Torn Item Sorter

Sort items by total value, single value or quantity

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Torn Item Sorter
// @namespace    torn.item.sorter
// @version      1.1
// @description  Sort items by total value, single value or quantity
// @author       KOKOT
// @match        https://www.torn.com/item.php*
// @grant        GM_getValue
// @grant        GM_setValue
 // @license MIT
// ==/UserScript==


(function () {
    'use strict';


    const STORAGE_KEY = 'sortMode';

    function getVisibleContainer() {
        return document.querySelector('ul.itemsList[aria-hidden="false"]');
    }

    function getAllContainers() {
        return [...document.querySelectorAll('ul.itemsList')];
    }

    function getTotalValue(item) {

        const price = item.querySelector('.tt-item-price');

        if (!price) return 0;

        const spans = price.querySelectorAll('span');

        const text = spans.length
            ? spans[spans.length - 1].textContent
            : price.textContent;

        return parseInt(text.replace(/[^\d]/g, ''), 10) || 0;
    }

    function getSingleItemValue(item) {

        const price = item.querySelector('.tt-item-price');

        if (!price) return 0;

        const spans = price.querySelectorAll('span');

        if (!spans.length) return 0;

        return parseInt(
            spans[0].textContent.replace(/[^\d]/g, ''),
            10
        ) || 0;
    }

    function sortItems(mode) {

        if (document.querySelector('[class*="itemInfo"]')) {
            return;
        }

        const containers = getAllContainers();

        containers.forEach(container => {

            const items = [...container.children];

            if (!items.length) return;

            if (mode === 'value') {

                items.sort((a, b) =>
                    getTotalValue(b) - getTotalValue(a)
                );

            } else if (mode === 'singleValue') {

                items.sort((a, b) =>
                    getSingleItemValue(b) - getSingleItemValue(a)
                );

            } else if (mode === 'qty') {

                items.sort((a, b) =>
                    Number(b.dataset.qty || 0) -
                    Number(a.dataset.qty || 0)
                );

            } else {
                return;
            }

            items.forEach(item => container.appendChild(item));
        });
    }

    function createControls() {

        if (document.querySelector('#tt-item-sorter')) {
            return;
        }

        const container = getVisibleContainer();

        if (!container) return;

        const wrapper = document.createElement('div');
        wrapper.id = 'tt-item-sorter';

        wrapper.innerHTML = `
            <select id="tt-sort-select">
                <option value="none">Default</option>
                <option value="value">Total value ↓</option>
                <option value="singleValue">Single value ↓</option>
                <option value="qty">Qty ↓</option>
            </select>
        `;

        if (!document.querySelector('#tt-sort-style')) {

            const style = document.createElement('style');
            style.id = 'tt-sort-style';

            style.textContent = `
                #tt-sort-select {
                    height:24px;
                    width:110px;
                    background:#2b2b2b;
                    color:#ddd;
                    border:1px solid #555;
                    border-radius:4px;
                    padding:0 6px;
                    font-size:11px;
                    cursor:pointer;
                }

                #tt-sort-select:hover {
                    border-color:#777;
                }

                #tt-sort-select:focus {
                    outline:none;
                    border-color:#999;
                }
            `;

            document.head.appendChild(style);
        }

        const titleBar = document.querySelector(
            '.title-black.hospital-dark.top-round.scroll-dark'
        );

        const searchForm = titleBar?.querySelector('form.isAcSearch');

        if (titleBar && searchForm) {

            titleBar.style.position = 'relative';

            wrapper.style.cssText = `
                position:absolute;
                right:170px;
                top:50%;
    transform:translateY(-50%);
                z-index:100;
            `;

            titleBar.appendChild(wrapper);

        } else {

            container.parentElement.prepend(wrapper);
        }

        const select = document.querySelector('#tt-sort-select');

        const savedMode = GM_getValue(STORAGE_KEY, 'none');

        select.value = savedMode;

        select.addEventListener('change', () => {

            const mode = select.value;

            GM_setValue(STORAGE_KEY, mode);

            if (mode === 'none') {
                location.reload();
                return;
            }

            sortItems(mode);
        });
    }

   let lastMode = '';

    setInterval(() => {

        createControls();

         if (document.querySelector('[class*="itemInfo"]')) {
        return;
    }

    const mode = GM_getValue(STORAGE_KEY, 'none');

    if (mode !== 'none') {
        sortItems(mode);
    }

}, 2000);
})();