Torn Quick Sell Weapons to Game

Quickly sell weapons to the game

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

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Torn Quick Sell Weapons to Game
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Quickly sell weapons to the game
// @author       PedroXimenez
// @match        https://*.torn.com/item.php*
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Class name cache and lookup for CSS modules compatibility
    const classCache = {};

    function findClass(prefix) {
        if (classCache[prefix]) return classCache[prefix];

        // Plain class fallback (for classes not yet using CSS modules)
        if (document.querySelector(`.${prefix}`)) {
            classCache[prefix] = prefix;
            return prefix;
        }

        // Search through all elements for a matching hashed class
        const el = document.querySelector(`[class*="${prefix}___"]`);
        if (el) {
            const match = el.className.match(new RegExp(`${prefix}___\\w+`));
            if (match) {
                classCache[prefix] = match[0];
                return match[0];
            }
        }

        // Fallback: search stylesheets
        for (const sheet of document.styleSheets) {
            try {
                for (const rule of sheet.cssRules || []) {
                    if (rule.selectorText && rule.selectorText.includes(`${prefix}___`)) {
                        const match = rule.selectorText.match(new RegExp(`${prefix}___\\w+`));
                        if (match) {
                            classCache[prefix] = match[0];
                            return match[0];
                        }
                    }
                }
            } catch (e) {
                // Cross-origin stylesheets will throw
            }
        }

        return null;
    }

    // Inject styles once we can resolve the option-sell class
    let stylesInjected = false;

    function injectStyles() {
        if (stylesInjected) return;
        const optionSellClass = findClass('option-sell');
        if (!optionSellClass) return;

        stylesInjected = true;
        GM_addStyle(`
            button.${optionSellClass}.quick-sell-confirm::after {
                content: "?";
                position: absolute;
                inset: 0;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 20px;
                font-weight: bold;
                color: white;
                background: rgba(0, 0, 0, 0.7);
                border-radius: 4px;
            }
            button.${optionSellClass}.quick-sell-close::after {
                content: "\\2715";
                position: absolute;
                inset: 0;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 16px;
                font-weight: bold;
                color: white;
                background: rgba(0, 0, 0, 0.7);
                border-radius: 4px;
            }
            button.${optionSellClass} {
                position: relative;
            }
        `);
    }

    // Track the currently modified button
    let activeButton = null;

    // Two-layer protection against mutation cycles
    const enqueueUpdate = typeof window.requestAnimationFrame === 'function'
        ? (cb) => window.requestAnimationFrame(cb)
        : (cb) => setTimeout(cb, 50);
    let isUpdating = false;
    let updateScheduled = false;

    function scheduleUpdate() {
        if (updateScheduled) {
            return;
        }
        updateScheduled = true;
        enqueueUpdate(() => {
            updateScheduled = false;
            doUpdate();
        });
    }

    function doUpdate() {
        if (isUpdating) return;
        isUpdating = true;
        try {
            injectStyles();

            // Clear previous state
            if (activeButton) {
                activeButton.classList.remove('quick-sell-confirm', 'quick-sell-close');
                activeButton = null;
            }

            const sellActClass = findClass('sell-act');
            const actClass = findClass('act');
            const optionSellClass = findClass('option-sell');
            const nextActClass = findClass('next-act');
            const closeActClass = findClass('close-act');

            if (!sellActClass || !actClass || !optionSellClass) return;

            const sellAct = document.querySelector(`.${sellActClass}`);
            if (sellAct) {
                // Find the active item's sell button
                const activeLi = document.querySelector(`li.${actClass}[data-item]`);
                if (activeLi) {
                    const sellButton = activeLi.querySelector(`button.${optionSellClass}`);
                    if (sellButton) {
                        activeButton = sellButton;

                        // Determine which state we're in
                        if (nextActClass && sellAct.querySelector(`a.${nextActClass}`)) {
                            // Confirmation dialog - show question mark
                            sellButton.classList.add('quick-sell-confirm');
                        } else if (closeActClass && sellAct.querySelector(`a.${closeActClass}`)) {
                            // Success dialog - show close icon
                            sellButton.classList.add('quick-sell-close');
                        }
                    }
                }
            }
        } finally {
            isUpdating = false;
        }
    }

    // Watch for DOM changes to detect dialog state
    const observer = new MutationObserver(() => scheduleUpdate());

    function startObserver() {
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['style', 'class']
        });
        scheduleUpdate();
    }

    if (document.body) {
        startObserver();
    } else {
        document.addEventListener('DOMContentLoaded', startObserver);
    }

    // Click handler for sell button
    document.addEventListener('click', function(e) {
        const optionSellClass = findClass('option-sell');
        if (!optionSellClass) return;

        const sellButton = e.target.closest(`button.${optionSellClass}`);
        if (!sellButton) {
            return;
        }

        const sellActClass = findClass('sell-act');
        const nextActClass = findClass('next-act');
        const closeActClass = findClass('close-act');

        if (!sellActClass) return;

        // Check if sell confirmation dialog is visible (Yes/No prompt)
        if (nextActClass) {
            const yesLink = document.querySelector(`.${sellActClass} a.${nextActClass}`);
            if (yesLink) {
                e.preventDefault();
                e.stopPropagation();
                yesLink.click();
                return;
            }
        }

        // Check if sell success dialog is visible (Close prompt)
        if (closeActClass) {
            const closeLink = document.querySelector(`.${sellActClass} a.${closeActClass}`);
            if (closeLink) {
                e.preventDefault();
                e.stopPropagation();
                closeLink.click();
                return;
            }
        }

        // No dialog visible, let the click proceed normally
    }, true);
})();