// ==UserScript==
// @name [GC] - TP Enhancements
// @namespace https://greasyfork.org/en/users/1225524-kaitlin
// @match https://www.grundos.cafe/island/tradingpost/*
// @version 1.3.1
// @license MIT
// @description
// @author Cupkait
// @icon https://i.imgur.com/4Hm2e6z.png
// @description Tp
// ==/UserScript==
function pageCheck() {
const headerCheck = document.querySelector('.trading_post > div.header').textContent.trim();
if (headerCheck === 'Create a New Lot') {
initiateNewTrade();
} else if (headerCheck === 'Your Lots') {
generateCancelButtons();
generateSortElement();
} else if (headerCheck === 'Select Your Search Criteria') {
generateUserDropdown();
} else if (headerCheck === 'Offers You Have Made') {
} else if (headerCheck === 'Offers on Lot') {
} else if (headerCheck.startsWith('Make an Offer on Lot')) {
} else {
error();
}
}
pageCheck();
function addGlobalStyles(){
const tradeStyles = document.createElement('style');
//Insert any CSS styling that applies to newly created elements, etc.
tradeStyles.innerHTML = `
.user-dropdown {
display: block;
position: absolute;
top: 100%;
left: 100%;
background-color: var(--bgcolor);
box-shadow: 0 8px 16px 0 rgba(0,0,0,.2);
z-index: 2;
min-width: 150px;
padding: 0;
border: 1px solid var(--color);
border-radius: 5px;
overflow: hidden;
}
.user-icon {
cursor: pointer;
}
.user-dropdown p {
font-size: 12px;
padding-left: 10px;}
.cancelbtn, #sortSelect {
margin:5px;
width:47%;
box-sizing: border-box;
font-family: inherit;
font-size: inherit;
font-weight: normal;
line-height: 1.5em;
min-height: 1.5em;
}
.createbtn {
margin:5px;
width:75%;
box-sizing: border-box;
font-family: inherit;
font-size: inherit;
font-weight: normal;
line-height: 1.5em;
min-height: 1.5em;
}
.trade-lot {
border-top: 2px solid black;
}
#tradeSettings {
text-align:center !important;
padding: 10px;
}
#exitSettings {
height:auto;
width:75%;
margin:auto;}
#newContainer {
text-align:center;
}
#createFilter {
width: 70%;
margin-right:5px;
}
#submitBtn, #createBtn {
width: 45%;
margin:5px;
height:auto;
}
#checkedCounter {
text-transform:uppercase;
font-weight:bold;
margin:5px;
color:blue;
}
#selectFirst, #selectMax, #selectNone {
margin:5px;
height:auto;
width:31%;
}
.quick {
margin-bottom:5px;
}
input.quick {
width: 60% !important;
}
button.quick {
margin-right:5px !important;
}
#wishlist {
width: 100%;
height: 1.5em;
}
#quicksale-neopoints {
width: 230px;
height: 1.5em;
margin-left: 10px;
}
.tp_header {
text-align:center;
margin: auto;
margin-bottom:10px;
width: 75%;
overflow-wrap: break-word;
padding: 4px;
}
.tp_header button {
height:auto;
width: auto;
margin-left:10px;
margin-right:10px;
padding-left:10px;
padding-right:10px;
}
.tp_header a {
font-size:10px;
margin:5px;
font-style:italic;
}
`;
document.head.appendChild(tradeStyles);
}
addGlobalStyles();
function addGlobalSettings() {
const tpHeader = document.querySelector('main h1').textContent
if (tpHeader === 'The Mystery Island Trading Post') {
const navBar = document.querySelector('main nav');
navBar.innerHTML += `| <a href="#settings" id="tpSettings">Trading Post Settings</a>`
var tpSettings = document.getElementById('tpSettings');
tpSettings.addEventListener('click', function () {
var tradeDetails = document.querySelector('.trading_post');
if (tradeDetails.style.display != 'none') {
openTradeSettings();}
})}
}
addGlobalSettings();
function addGlobalHeader() {
const mainTP = document.querySelector('.trading_post');
let mainHeader = document.createElement('div');
mainHeader.classList.add('tp_header');
mainTP.parentNode.insertBefore(mainHeader, mainTP);
let headerButton = document.createElement('button');
headerButton.id = 'createHeader';
headerButton.textContent = 'Create a new trade!';
let linkLots = document.createElement('a');
let user = document.querySelector("#user-info-username").text;
linkLots.href = `https://www.grundos.cafe/island/tradingpost/lot/user/${user}/`;
linkLots.textContent = 'Link to your Lots';
let clipboardIcon = document.createElement('span');
clipboardIcon.classList.add('clipboard-icon');
clipboardIcon.textContent = '📋';
clipboardIcon.style.cursor = 'pointer';
clipboardIcon.title = 'Copy Link to Clipboard';
let quickSearch = document.createElement('input');
quickSearch.placeholder = 'Enter TP Search Term Here';
quickSearch.classList.add('quick');
// Add an event listener for the 'Enter' key on the quickSearch input
quickSearch.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && quickSearch.value.trim() !== '') {
event.preventDefault(); // Prevent form submission if inside a form
tpQuickSearch(); // Call the quick search function
}
});
let qsButton = document.createElement('button');
qsButton.textContent = "Quick Search";
qsButton.onclick = function() { tpQuickSearch(); };
qsButton.classList.add('quick');
const headerCheck = document.querySelector('.trading_post > div.header').textContent;
if (headerCheck !== '\nSelect Your Search Criteria\n') {
mainHeader.append(quickSearch);
mainHeader.append(qsButton);
}
mainHeader.append(headerButton);
mainHeader.append(linkLots);
mainHeader.append(clipboardIcon);
document.getElementById('createHeader').addEventListener('click', function() {
window.location.href = '/island/tradingpost/createtrade/';
});
clipboardIcon.addEventListener('click', function() {
const tempInput = document.createElement('input');
tempInput.value = linkLots.href;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
clipboardIcon.textContent = '✓ Copied!';
setTimeout(function() {
clipboardIcon.textContent = '📋';
}, 1500);
});
}
addGlobalHeader();
function openTradeSettings() {
const tradeDetails = document.querySelector('.trading_post'),
tradeSettings = Object.assign(document.createElement('div'), {
id: 'tradeSettings',
className: 'trading_post bg-dm-gray flex-column margin-auto',
style: { display: 'none' },
innerHTML: `<div class="header"><strong>Trading Post Script Settings</strong></div><div></div>`
}),
wishContainer = Object.assign(document.createElement('div'), {
id: 'wishContainer',
innerHTML: `<p><strong>Default Wishlists</strong></p>`
}),
hiddenContainer = Object.assign(document.createElement('div'), {
id: 'hiddenContainer',
innerHTML: `<p><strong>Trade-Blocked Users</strong></p>`
}),
exitSettingsBtn = Object.assign(document.createElement('button'), {
id: 'exitSettings',
textContent: "Save and Exit Settings"
});
tradeDetails.insertAdjacentElement('afterend', tradeSettings);
tradeSettings.append(wishContainer, hiddenContainer, exitSettingsBtn);
exitSettingsBtn.addEventListener('click', function() {
tradeSettings.remove();
tradeDetails.style.display = "";
})
}
async function initiateNewTrade() {
const inventItems = document.querySelectorAll('.trade-item');
const itemDetails = await getItemDetails(inventItems);
const lotCount = await fetchLotCount();
const lotsLeft = 20 - lotCount;
const heading = document.querySelector('.trading_post > div.header > strong');
heading.textContent = `${heading.textContent} (${lotsLeft} lots left)`;
let checkedCount = 0;
const counterDisplay = createCounterDisplay(checkedCount);
const itemButtons = document.querySelector('#tp-buttons');
const filterInput = createFilterInput();
const autoSelect = createSelectButtons();
const createBtn = document.querySelector('.center input.form-control');
createBtn.value = "Submit and View Trades";
const submitBtn = createSubmitButton();
const wishList = document.querySelector('#wishlist');
wishlist.placeholder = "WISHLIST: Optionally, list what you are seeking."
const slotsData = document.querySelector('.flex-column.med-gap > span');
const [slotsOpen, slotsAvail] = slotsData.textContent.match(/\d+/g).map(Number);
const quickSale = document.querySelector('#quicksale-neopoints');
const container = document.createElement('div');
container.id = "newContainer";
document.querySelector('#tp-buttons').insertAdjacentElement('afterend', container);
container.append(filterInput);
container.append(counterDisplay);
container.append(autoSelect);
if (slotsOpen != 0) {
quickSale.placeholder = "Name an auto sale price."
container.append(slotsData);
container.append(quickSale);}
container.append(wishList);
container.append(submitBtn);
container.append(createBtn);
document.querySelector('.med-gap').replaceWith(itemButtons)
document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
checkbox.addEventListener('change', event => handleCheckboxChange(event, counterDisplay));
});
filterInput.addEventListener('input', () => filterShownItems(itemDetails, filterInput.value));
filterInput.dispatchEvent(new Event('input'));
filterInput.addEventListener('input', () => filterShownItems(itemDetails, filterInput.value));
submitBtn.addEventListener('click', event => submitTradeForm(itemDetails));
}
function submitTradeForm(itemDetails){
event.preventDefault();
const tokenVal = document.querySelector('form [name="csrfmiddlewaretoken"]').value;
const wishList = document.querySelector('textarea#wishlist').value;
const checkedItems = Array.from(document.querySelectorAll('.trade-item input')).filter(item => item.checked);
const quickSale = document.querySelector('input#quicksale-neopoints') ? document.querySelector('input#quicksale-neopoints').value : '';
var formData = new FormData();
formData.append('csrfmiddlewaretoken', tokenVal);
formData.append('quicksale-neopoints', quickSale)
formData.append('wishlist', wishList);
checkedItems.forEach(item => {
formData.append('checks', item.value);
});
fetch('/island/tradingpost/processcreation/', {
method: 'POST',
body: formData
})
.then(response => {
if (response.redirected) {
window.location.reload();
} else {
console.log('Form submitted successfully');
}
})
.catch(error => {
console.error('Error submitting form:', error);
});
}
function createSubmitButton() {
const submitBtn = document.createElement('button');
submitBtn.id = "submitBtn";
submitBtn.textContent = "Submit and Create Next"
return submitBtn;
}
async function getItemDetails(inventItems) {
return Array.from(inventItems).map(item => {
let itemName = item.querySelector('.item-info > span').textContent;
let itemRarity = parseInt(item.querySelector('.item-info > span:nth-child(2)').textContent.replace(/\D/g, ''), 10) || 0;
let itemID = item.querySelector('input').value;
return { item, itemName, itemRarity, itemID };
});
}
function createSelectButtons() {
const selectFirst = document.createElement('button');
const selectMax = document.createElement('button');
const selectNone = document.createElement('button');
const buttonCont = document.createElement('span');
selectFirst.id = 'selectFirst';
selectMax.id = 'selectMax';
selectNone.id = 'selectNone';
buttonCont.append(selectFirst, selectMax, selectNone);
selectFirst.textContent = "Select First";
selectMax.textContent = "Select 15";
selectNone.textContent = "Clear All";
selectFirst.addEventListener('click', (event) => {
event.preventDefault();
selectFirstAction();
});
selectMax.addEventListener('click', (event) => {
event.preventDefault();
selectMaxAction();
});
selectNone.addEventListener('click', (event) => {
event.preventDefault();
selectNoneAction();
});
return buttonCont;
}
function selectFirstAction() {
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
let index = 0;
checkboxes.forEach(checkbox => {
let parent = checkbox.parentElement;
while (parent) {
const style = window.getComputedStyle(parent);
if (style.display === 'none') {
return;
}
parent = parent.parentElement;
}
checkbox.checked = (index === 0);
index++;
});
updateCheckedCount();
}
function selectMaxAction() {
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
let selectedCount = 0;
checkboxes.forEach(checkbox => {
if (selectedCount >= 15) {
return;
}
let parent = checkbox.parentElement;
let hidden = false;
while (parent) {
const style = window.getComputedStyle(parent);
if (style.display === 'none') {
hidden = true;
break;
}
parent = parent.parentElement;
}
if (!hidden) {
checkbox.checked = true;
selectedCount++;
}
});
updateCheckedCount();
}
function selectNoneAction() {
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
updateCheckedCount();
}
function updateCheckedCount() {
const counterDisplay = document.getElementById('checkedCounter');
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const checkedCount = Array.from(checkboxes).filter(checkbox => checkbox.checked).length;
counterDisplay.textContent = `Selected: ${checkedCount}`;
}
function createCounterDisplay(initialCount) {
const counterDisplay = document.createElement('span');
counterDisplay.id = 'checkedCounter';
counterDisplay.textContent = `Selected: ${initialCount}`;
return counterDisplay;
}
function createFilterInput() {
const filterInput = document.createElement('input');
filterInput.placeholder = "Filter by Name or Rarity";
filterInput.id = "createFilter";
filterInput.value = sessionStorage.getItem('filterValue') || '';
return filterInput;
}
function filterShownItems(itemDetails) {
let filterValue = document.querySelector('#createFilter').value;
sessionStorage.setItem('filterValue', filterValue);
const lowerCaseFilterValue = filterValue.toLowerCase();
itemDetails.forEach(({ item, itemName, itemRarity }) => {
item.style.display = itemName.toLowerCase().includes(lowerCaseFilterValue) || itemRarity.toString().includes(lowerCaseFilterValue) ? '' : 'none';
});
}
function handleCheckboxChange(event, counterDisplay) {
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
let checkedCount = Array.from(checkboxes).filter(checkbox => checkbox.checked).length;
if (checkedCount > 15) {
alert(`You can only select up to 15 items.`);
event.target.checked = false;
checkedCount--;
}
counterDisplay.textContent = `Selected: ${checkedCount}`;
}
async function capturelotDetails() {
const tradeLots = document.querySelectorAll('.trade-lot');
let tokenVal = document.querySelector('.button-group [type="hidden"][name="csrfmiddlewaretoken"]').value;
document.querySelectorAll('.flex-column [action="/island/tradingpost/createtrade/"]')
.forEach(element => element.style.display = "none");
document.querySelector('.trading_post .small-gap').style.display="none";
let lotDetails = [];
tradeLots.forEach(lot => {
let lotNum = lot.querySelector('.button-group input[type="hidden"][name="lotno"]').value;
let offerCt = parseInt(lot.querySelector('span').textContent.replace(/\D/g, ''), 10) || 0;
let lotDate = new Date(lot.querySelector('span:nth-of-type(3)').textContent.split(':').slice(1).join(':').replace('NST', '').trim().replace(' at ', ` ${new Date().getFullYear()} `));
let autoSale = parseInt(lot.querySelector(`span#quicksale-text-${lotNum}`).textContent.replace(/\D/g, ''), 10) || null;
let entry = { lotNum: lotNum, offerCt: offerCt, element: lot , autoSale: autoSale, lotDate: lotDate};
lotDetails.push(entry);
});
return { tokenVal, lotDetails, tradeLots };
}
function generateCancelButtons() {
const createLotBtn = document.querySelector('form.center [type="submit"]');
const cancelContainer = document.createElement('div');
const cancelAllBtn = document.createElement('span');
cancelContainer.id = "cancelContainer";
cancelAllBtn.classList = "cancelbtn";
cancelAllBtn.id = "cancelBtn";
cancelAllBtn.textContent = "Sort Options:";
cancelAllBtn.onclick = function() {
const confirmed = confirm('Are you sure you wish to cancel ALL trades at once? This may take a moment and will not include any trades with pending offers.');
if (confirmed) {
cancelAllBtn.disabled = true;
cancelAllBtn.textContent = "Cancellation in progress...";
cancelAllTrades();
} else {
//Do Nothing
}
};
createLotBtn.parentNode.insertAdjacentElement('afterend', cancelContainer);
cancelContainer.append(cancelAllBtn);
}
function generateSortElement() {
const sortSelect = document.createElement('select');
sortSelect.id = "sortSelect";
var options = ['Sort by Newest', 'Sort by Oldest', 'Show Offers First', 'Show Offers Only', 'Show Autosale Only'];
for (var i = 0; i < options.length; i++) {
var option = document.createElement('option');
option.value = [i + 1];
option.text = options[i];
sortSelect.appendChild(option);
}
var selectedOption = localStorage.getItem('selectedOption');
if (selectedOption) {
sortSelect.value = selectedOption;
}
applySelectedOption();
document.querySelector('#cancelContainer').append(sortSelect);
sortSelect.addEventListener('change', function () {
applySelectedOption();
localStorage.setItem('selectedOption', sortSelect.value);
});
}
async function applySelectedOption() {
const { tokenVal, lotDetails, tradeLots } = await capturelotDetails();
const linehr = document.querySelectorAll('hr');
linehr.forEach(line => {line.remove();})
const sortSelect = document.getElementById('sortSelect');
const selectedValue = parseInt(sortSelect.value);
if (selectedValue === 1) { //newest
lotDetails.sort((a, b) => b.lotDate - a.lotDate);
} else if (selectedValue === 2) { //oldest
lotDetails.sort((a, b) => a.lotDate - b.lotDate);
} else if (selectedValue === 3) { //offers first
lotDetails.sort((a, b) => b.offerCt - a.offerCt);
} else if (selectedValue === 4) { //offers only
lotDetails.forEach(lot => {
lot.element.style.display = '';
if (lot.offerCt === 0) {
lot.element.style.display = 'none';
} else {
lot.element.style.display = 'visible';
}
});
} else if (selectedValue === 5) { //autosale only
lotDetails.forEach(lot => {
lot.element.style.display = '';
if (lot.autoSale === null) {
lot.element.style.display = 'none';
} else {
lot.element.style.display = 'visible';
}
}); }
if (selectedValue !== 4 && selectedValue !== 5) {
const parent = tradeLots[0].parentElement;
lotDetails.forEach(lot => {
parent.appendChild(lot.element);
lot.element.style.display = ''; // Ensure all elements are displayed for sorting options 1 and 2
});
}
}
async function tpQuickSearch() {
const tokenVal = document.querySelector('form [name="csrfmiddlewaretoken"]').value;
function submitForm() {
const searchVal = document.querySelector('input.quick').value;
var form = document.createElement('form');
form.method = 'POST';
form.action = '/island/tradingpost/browse/';
var input1 = document.createElement('input');
input1.type = 'hidden';
input1.name = 'csrfmiddlewaretoken';
input1.value = tokenVal;
var input2 = document.createElement('input');
input2.type = 'hidden';
input2.name = 'qty';
input2.value = '0';
var input3 = document.createElement('input');
input3.type = 'hidden';
input3.name = 'category';
input3.value = '1';
var input4 = document.createElement('input');
input4.type = 'hidden';
input4.name = 'query';
input4.value = searchVal;
var input5 = document.createElement('input');
input5.type = 'hidden';
input5.name = 'type';
input5.value = '-1';
var input6 = document.createElement('input');
input6.type = 'hidden';
input6.name = 'sort';
input6.value = 'newest';
form.appendChild(input1);
form.appendChild(input2);
form.appendChild(input3);
form.appendChild(input4);
form.appendChild(input5);
form.appendChild(input6);
document.body.appendChild(form);
form.submit();
}
submitForm();
}
async function cancelAllTrades() {
// Submit the form to cancel all trades on the page.
const { tokenVal, lotDetails, tradeLots } = await capturelotDetails();
const cancelAllBtn = document.getElementById('cancelAllBtn');
if (cancelAllBtn) {
cancelAllBtn.disabled = true}
function submitForm(lotNum) {
var form = document.createElement('form');
form.method = 'POST';
form.action = '/island/tradingpost/canceltrade/';
var input1 = document.createElement('input');
input1.type = 'hidden';
input1.name = 'csrfmiddlewaretoken';
input1.value = tokenVal;
var input2 = document.createElement('input');
input2.type = 'hidden';
input2.name = 'lotno';
input2.value = lotNum.lotNum;
form.appendChild(input1);
form.appendChild(input2);
document.body.appendChild(form);
form.submit();
}
lotDetails.forEach((lotNum, index) => {
if (lotNum.offerCt === 0) {
setTimeout(() => {
submitForm(lotNum);
}, index * 500);
} else {
}
});
}
function generateUserDropdown() {
const tradeLots = document.querySelectorAll('.trade-lot');
tradeLots.forEach(lot => {
const user = lot.querySelector('span');
var lotNumber = parseInt(lot.querySelector('strong').textContent.match(/\d+/)[0], 10);
var lotlink = `https://www.grundos.cafe/island/tradingpost/lot/${lotNumber}`;
const username = user.querySelector('a').textContent;
const icon = document.createElement('span');
const dropdown = document.createElement('div');
dropdown.classList.add('user-dropdown');
icon.classList.add('user-icon');
dropdown.innerHTML = `
<p><a href="https://www.grundos.cafe/neomessages/sendmessage/?username=${username}">Send Neomail</a></p>
<p><a href="https://www.grundos.cafe/island/tradingpost/lot/user/${username}">View All Trades</a></p>
<p><a href="https://www.grundos.cafe/userlookup/?user=${username}">Visit Userlookup</a></p>
<p><a href="https://www.grundos.cafe/wishlist/?user=${username}">View Wishlist</a></p>
<p class="copy-link">Copy Link to Lot 📋</p>
`;
dropdown.style.display = 'none';
icon.innerText = ' ⤵️';
user.style.position = 'relative';
user.append(icon);
icon.appendChild(dropdown);
icon.addEventListener('click', (event) => {
event.stopPropagation();
if (dropdown.style.display === 'none') {
dropdown.style.display = 'block';
} else {
dropdown.style.display = 'none';
}
});
dropdown.addEventListener('click', (event) => {
event.stopPropagation();
});
const copyLink = dropdown.querySelector('.copy-link');
copyLink.addEventListener('click', () => {
navigator.clipboard.writeText(lotlink).then(() => {
copyLink.textContent = 'Copied!';
setTimeout(() => {
copyLink.textContent = 'Copy Link to Lot 📋';
}, 5000);
}).catch(err => {
console.error('Failed to copy: ', err);
});
});
});
}
async function fetchLotCount() {
try {
const response = await fetch('https://www.grundos.cafe/island/tradingpost/');
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'text/html');
const tradeLots = doc.querySelectorAll('.trade-lot');
const lotCount = tradeLots.length;
return lotCount;
} catch (error) {
console.error('Error fetching lot count:', error);
return 0;
}
}