Neopets: Shop Condenser

Condenses your shop's view. Removes useless elements.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Neopets: Shop Condenser
// @namespace    https://github.com/saahphire/NeopetsUserscripts
// @version      1.0.0
// @description  Condenses your shop's view. Removes useless elements.
// @author       saahphire
// @homepageURL  https://github.com/saahphire/NeopetsUserscripts
// @homepage     https://github.com/saahphire/NeopetsUserscripts
// @match        *://*.neopets.com/market.phtml?*type=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=neopets.com
// @run-at       document-idle
// @license      Unlicense
// ==/UserScript==

/*
•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•:•:•:•:•:•:•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•.•:•:•:•:•:•:•:•:•.•:•:•.•:•.••:•.•:•.••:
........................................................................................................................
☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦
    This script does the following:
    - Removes:
        - The big image at the top
        - The Marketplace is where you can...
        - Land : Neopia Central (or whatever you chose)
        - Cleaner Code, Better Browsing and A Safer Neopia!
        - (please do not use rude words or IFRAMES!)
        - (it costs 150 NP to open a shop)
        - Items that cost 0 Neopoints...
        - Shopkeeper's picture and greeting in the stock page
        - Item descriptions
        - Note: shops are strictly a place for selling...
        - Please clear your Sales History regularly to save space on the Neopets servers! :)
        - Only purchases of 1000 NP or greater will be displayed here.
        - Need some extra security? Add a PIN for use in this area!
        - (max 999,999)
    - Changes:
        - Moves "Jump to" links to their own div
        - Makes item images smaller
        - Item quantity and removal are now the same column

    You may also like (use GreasyFork or GitHub for each, not both):
        - No Top Links (removes the cluster of redundant links on top of every old layour page)
            https://github.com/saahphire/NeopetsUserscripts/tree/main
            https://greatest.deepsurf.us/en/scripts/565351-neopets-no-top-links

    ✦ ⌇ saahphire
☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦
........................................................................................................................
•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•:•:•:•:•:•:•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•.•:•:•:•:•:•:•:•:•.•:•:•.•:•.••:•.•:•.••:
*/

const jumpToLinks = [
    ['https://www.neopets.com/browseshop.phtml?owner=saahphire', 'Shop Front'],
    ['https://www.neopets.com/market.phtml?type=edit', 'Edit Shop'],
    ['https://www.neopets.com/market.phtml?type=your', 'Stock'],
    ['https://www.neopets.com/market.phtml?type=till', 'Till'],
    ['https://www.neopets.com/market.phtml?type=sales', 'Sales History'],
    ['https://www.neopets.com/quickstock.phtml', 'Quick Stock'],
    ['https://www.neopets.com/gallery/index.phtml', 'Gallery']
];

const remove = [
    'br + b + p:has(br)',
    'table table:has(.contentModule)',
    'center + p',
    'center:has([name="keeperimage"])',
    '.saahphire-stocked + b',
    'form + table:has(a[href="/pin_prefs.phtml"])',
    'font[size="1"]'
];

const shopLetters = [
    ['a', 'n', '0'],
    ['b', 'o', '1'],
    ['c', 'p', '2'],
    ['d', 'q', '3'],
    ['e', 'r', '4'],
    ['f', 's', '5'],
    ['g', 't', '6'],
    ['h', 'u', '7'],
    ['i', 'v', '8'],
    ['j', 'w', '9'],
    ['k', 'x', '_'],
    ['l', 'y'],
    ['m', 'z']
];

const usernameLetter = document.querySelector('.user a').textContent.charAt(0);
const swLetters = shopLetters.find(letterCluster => letterCluster.find(letter => letter === usernameLetter));

const buildJumpTo = () => {
    const ul = document.createElement('ul');
    ul.classList.add('saahphire-jump-to');
    ul.ariaLabel = 'Shop Navigation';
    document.querySelector('table table:has(.contentModule)').insertAdjacentElement('beforeBegin', ul);
    jumpToLinks.forEach(link => {
        const li = document.createElement('li');
        ul.appendChild(li);
        const a = document.createElement('a');
        li.appendChild(a);
        a.href = link[0];
        a.textContent = link[1];
    });
}

const buildStock = () => {
    const siblings = document.getElementsByName('subbyprev');
    if(!siblings.length) return;
    const bs = document.querySelectorAll('center:has([name="keeperimage"]) b');
    siblings.forEach(sibling => sibling.insertAdjacentHTML('afterend', `<p class="saahphire-stocked">Items Stocked: <strong>${bs[1].textContent}</strong> | Free Space: <strong>${bs[2].textContent}</strong>`));
}

const unanchorPage = () => {
    const currentPageStart = document.querySelector('input + b')?.textContent.match(/Viewing items (\d+)/)?.[1];
    if(!currentPageStart) return;
    ['.saahphire-jump-to ~ p a', 'form[action="process_market.phtml"] + center a'].forEach(anchorQuery => {
        const currentPageAnchor = [...document.querySelectorAll(anchorQuery)].find(a => a.textContent.startsWith(`[${currentPageStart}-`));
        currentPageAnchor.insertAdjacentHTML('afterend', `<span class="saahphire-page">${currentPageAnchor.textContent}</span>`);
        currentPageAnchor.remove();
    });
}

const moveStockInputs = form => {
    [...form.childNodes].filter(node => node.nodeType === 3).forEach(node => node.remove());
    const centerDiv = document.createElement('div');
    const rightDiv = document.createElement('div');
    const invisibleDiv = document.createElement('div');
    if(form.querySelector('input[value="Find"]')) {
        rightDiv.appendChild(document.getElementsByName('obj_name')[0]);
        rightDiv.appendChild(form.querySelector('input[value="Find"]'));
    }
    [...form.children].forEach(child => centerDiv.appendChild(child));
    [invisibleDiv, centerDiv, rightDiv].forEach(div => form.appendChild(div));
}

const removeDescriptions = () => {
    const column = [...document.querySelectorAll('[name="view"] + table > tbody > tr:first-child td')].findIndex(child => child.textContent === 'Description');
    document.querySelectorAll(`[name="view"] + table > tbody > tr td:nth-of-type(${column + 1})`).forEach(description => description.style.display = 'none');
}

const addMaxToRemove = () => {
    document.querySelectorAll('[name="view"] + table > tbody > tr').forEach(row => {
        const quantity = row.querySelector('td[width="50"]');
        if(!quantity) return;
        [...row.getElementsByTagName('option')].forEach(option => option.textContent += `/${quantity.textContent}`);
        row.querySelector('td[width="50"]').style.display = 'none';
    });
    [...document.querySelectorAll('[name="view"] + table > tbody > tr:first-child td')].find(td => td.textContent === 'Stock')?.remove();
    document.querySelector('[value="Update"]')?.addEventListener('click', () => document.querySelectorAll('[name="view"] + table > tbody > tr').forEach(row => [...row.getElementsByTagName('option')].forEach(option => option.textContent = option.value)));
}

const addPinToLastRow = () => {
    const parent = document.querySelector('[name="view"] + table > tbody > tr:last-child td');
    if(!parent) return;
    const div = document.createElement('div');
    parent.appendChild(div);
    const pinRow = document.querySelector('[name="view"] + table tr:has(table)');
    div.insertAdjacentHTML('beforeend', '<span class="saahphire-pin">Enter your <a href="https://www.neopets.com/pin_prefs.phtml">PIN</a>:</span>');
    div.appendChild(pinRow.querySelector('input'));
    pinRow.remove();
}

const css = `<style>
p, ul {
    margin: 0.25em;
}

#search-form, #ssw-tabs-1 {
    height: auto;
}

#search-form p {
    margin: 0;
}

#results_table tr:not(:first-child, :nth-child(2), :has(a[href*="owner=${swLetters.join('"], a[href*="owner=')}"])) {
    display: none;
}

.saahphire-jump-to {
    padding: 0;
    text-align: center;
}

.saahphire-jump-to li {
    display: inline;

    &:not(:last-child)::after {
        content: "|";
        margin: 0.25em;
        cursor: auto;
        pointer-events: none;
    }
}

.saahphire-stocked {
    text-align: center;
    display: inline;
    margin: 0 1em;
}

.saahphire-page {
    font-weight: 600;
    margin: 0.3em;
}

form[action="market.phtml"] {
    display: grid;
    grid-template-columns: 1fr 3fr 1fr;

    & div {
        text-align: center;

        &:last-child {
            text-align: right;
        }
    }
}

[name="view"] + table .search-helper, [name="view"] + table, [name="shopform"] table, textarea {
    width: 100%;
}

[name="view"] + table > tbody {
    display: grid;
    grid-template-columns: subgrid;
}

[name="view"] + table td {
    align-items: center;
    justify-content: center;
    display: flex;
    padding: 0.25em;
    flex-wrap: wrap;
    text-align: center;
    height: 100%;
    width: auto!important;
    background-color: transparent!important;
    box-sizing: border-box;
}

[name="view"] + table :not(.search-helper) img {
    width: 40px;
    height: 40px;
}

[name="view"] + table tr {
    display: grid;
    grid-template-columns: 3fr repeat(var(--columns), 1fr);
    padding: 0;
    background-color: #ffffcc;
}

[name="view"] + table tr:nth-child(2n) {
    background-color: white;
}

[name="view"] + table tr:is(:first-child, :last-child) {
    background-color: #dddd77;
    font-weight: 600;
}

[name="view"] + table td:first-child {
    justify-content: left;
    text-align: left;
}

[name="view"] + table tr:first-child td:first-child {
    text-align: center;
}

[name="view"] + table tr:last-child td {
    grid-column: 1 / -1;
}

[name="view"] + table tr:last-child td div {
    margin-left: auto;
}

br, tr:has(> td[bgcolor="#cccccc"]), .sf {
    display: none;
}
</style>`;

(function() {
    'use strict';
    document.head.insertAdjacentHTML('beforeend', css);
    buildJumpTo();
    unanchorPage();
    buildStock();
    document.querySelectorAll('form[action="market.phtml"]').forEach(form => moveStockInputs(form));
    removeDescriptions();
    addMaxToRemove();
    document.querySelector('[name="view"] + table')?.style.setProperty('--columns', document.querySelectorAll('[name="view"] + table > tbody > tr:first-child td').length - 2);
    addPinToLastRow();
    document.querySelectorAll(remove.join(', ')).forEach(rm => rm.remove());
    [...document.querySelectorAll('b + p[align="center"]')].find(p => p.textContent.startsWith('Only purchases'))?.remove();
})();