您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Tp
// ==UserScript== // @name [GC] - TP Enhancements // @namespace https://greasyfork.org/en/users/1225524-kaitlin // @match https://www.grundos.cafe/island/tradingpost/* // @version 1.3.2 // @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.parentElement.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; } }