Greasy Fork is available in English.

[GC] - TP Enhancements

Tp

// ==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;
  }
}