Torn Market Item Locker

Add lockable quantity controls to market items

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Torn Market Item Locker
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Add lockable quantity controls to market items
// @author       Your name
// @match        https://www.torn.com/page.php?sid=ItemMarket*
// ==/UserScript==

(function() {
    'use strict';

    // Create and inject CSS
    const style = document.createElement('style');
    style.textContent = `
        .input-locked {
            pointer-events: none !important;
            opacity: 0.5;
        }
        .lock-icon {
            cursor: pointer;
            margin-left: 5px;
            color: #777;
            position: relative;
            z-index: 1000;
            padding: 5px;
        }
        .lock-icon.locked {
            color: #ff4444;
        }
    `;
    document.head.appendChild(style);

    const STORAGE_KEY = 'torn_market_locked_items';
    let lockedItems = new Set(JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'));

    function saveLockedItems() {
        localStorage.setItem(STORAGE_KEY, JSON.stringify([...lockedItems]));
    }

    function getItemIdentifier(titleElement) {
        const nameElement = titleElement.querySelector('.name___XmQWk');
        return nameElement ? nameElement.textContent.trim() : '';
    }

    function simulateInput(input, value) {
        input.focus();
        input.value = value;
        input.dispatchEvent(new Event('input', { bubbles: true }));
        input.dispatchEvent(new Event('change', { bubbles: true }));
        input.blur();
    }

    function setRowLockState(itemRow, locked) {
        // Handle quantity input
        const quantityWrapper = itemRow.querySelector('.amountInputWrapper___USwSs');
        if (quantityWrapper) {
            const quantityInput = quantityWrapper.querySelector('input.input-money:not([type="hidden"])');
            quantityWrapper.classList.toggle('input-locked', locked);
            if (locked && quantityInput) {
                simulateInput(quantityInput, '0');
            }
        }

        // Handle price input
        const priceWrapper = itemRow.querySelector('.priceInputWrapper___TBFHl');
        if (priceWrapper) {
            const priceInput = priceWrapper.querySelector('input.input-money:not([type="hidden"])');
            priceWrapper.classList.toggle('input-locked', locked);
            if (locked && priceInput) {
                simulateInput(priceInput, '0');
            }
        }
    }

    function startLockedItemsCheck() {
        setInterval(() => {
            document.querySelectorAll('.lock-icon.locked').forEach(lockIcon => {
                const itemRow = lockIcon.closest('.itemRow___Mf7bO');
                if (itemRow) {
                    // Check and reset quantity
                    const quantityWrapper = itemRow.querySelector('.amountInputWrapper___USwSs');
                    if (quantityWrapper) {
                        const quantityInput = quantityWrapper.querySelector('input.input-money:not([type="hidden"])');
                        if (quantityInput && quantityInput.value !== '0') {
                            simulateInput(quantityInput, '0');
                        }
                    }

                    // Check and reset price
                    const priceWrapper = itemRow.querySelector('.priceInputWrapper___TBFHl');
                    if (priceWrapper) {
                        const priceInput = priceWrapper.querySelector('input.input-money:not([type="hidden"])');
                        if (priceInput && priceInput.value !== '0') {
                            simulateInput(priceInput, '0');
                        }
                    }
                }
            });
        }, 100);
    }

    function processTitle(titleElement) {
        if (titleElement.querySelector('.lock-icon')) return;

        const lockIcon = document.createElement('span');
        lockIcon.innerHTML = '🔓';
        lockIcon.className = 'lock-icon';
        titleElement.appendChild(lockIcon);

        const itemRow = titleElement.closest('.itemRow___Mf7bO');
        const itemId = getItemIdentifier(titleElement);

        if (lockedItems.has(itemId)) {
            lockIcon.innerHTML = '🔒';
            lockIcon.classList.add('locked');
            setRowLockState(itemRow, true);
        }

        lockIcon.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();

            const isLocked = lockIcon.classList.contains('locked');

            if (isLocked) {
                lockIcon.innerHTML = '🔓';
                lockIcon.classList.remove('locked');
                setRowLockState(itemRow, false);
                lockedItems.delete(itemId);
            } else {
                lockIcon.innerHTML = '🔒';
                lockIcon.classList.add('locked');
                setRowLockState(itemRow, true);
                lockedItems.add(itemId);
            }

            saveLockedItems();
            return false;
        }, true);
    }

    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            mutation.addedNodes.forEach((node) => {
                if (node.nodeType === 1) {
                    const titles = node.matches('.title___Xo6Pm') ?
                        [node] :
                        node.querySelectorAll('.title___Xo6Pm');

                    titles.forEach(processTitle);
                }
            });
        });
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    document.querySelectorAll('.title___Xo6Pm').forEach(processTitle);
    startLockedItemsCheck();
})();