Torn Market Item Locker

Add lockable quantity controls to market items

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