Filter Items by Price on Dead Frontier

Filter items on the Dead Frontier market page by user-defined price range and category

// ==UserScript==
// @name         Filter Items by Price on Dead Frontier
// @namespace    http://tampermonkey.net/
// @version      0.9.1
// @description  Filter items on the Dead Frontier market page by user-defined price range and category
// @author       Diabetus
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=35
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Function to validate price input
    function validatePriceInput(price) {
        const priceRegex = /^\$\d{1,3}(,\d{3})*$/; // Matches $ and commas in the correct format
        return priceRegex.test(price);
    }

    // Function to parse price string into a number
    function parsePrice(priceString) {
        return parseInt(priceString.replace(/[^0-9]/g, ''), 10);
    }

    // Function to filter items by price range
    function filterByPriceRange(minPrice, maxPrice) {
        const items = document.querySelectorAll('.fakeItem');

        items.forEach(item => {
            const salePriceElement = item.querySelector('.salePrice');

            if (salePriceElement) {
                const priceText = salePriceElement.textContent.trim();

                if (validatePriceInput(priceText)) {
                    const price = parsePrice(priceText);

                    if (price < minPrice || price > maxPrice) {
                        item.style.display = 'none';
                    } else {
                        item.style.display = '';
                    }
                }
            }
        });
    }

    // Function to filter items by food type
    function filterByFoodType(type) {
        const items = document.querySelectorAll('.fakeItem');

        items.forEach(item => {
            const itemType = item.getAttribute('data-type');

            if (itemType) {
                if (type === 'cooked' && !itemType.includes('_cooked')) {
                    item.style.display = 'none';
                } else if (type === 'uncooked' && itemType.includes('_cooked')) {
                    item.style.display = 'none';
                } else {
                    item.style.display = '';
                }
            }
        });
    }

    // Function to reset visibility for all food items
    function resetAllFoodItems() {
        const items = document.querySelectorAll('.fakeItem');

        items.forEach(item => {
            const itemType = item.getAttribute('data-type');

            if (itemType && itemType.includes('food')) {
                item.style.display = '';
            }
        });
    }

 // Function to filter items by affordability
    function filterByAffordability() {
        const cashElement = document.querySelector('.heldCash');
        const heldCash = parsePrice(cashElement.getAttribute('data-cash'));

        const items = document.querySelectorAll('.fakeItem');
        items.forEach(item => {
            const salePriceElement = item.querySelector('.salePrice');

            if (salePriceElement) {
                const priceText = salePriceElement.textContent.trim();
                const price = validatePriceInput(priceText) ? parsePrice(priceText) : Infinity;

                if (price > heldCash) {
                    item.style.display = 'none';
                } else {
                    item.style.display = '';
                }
            }
        });
    }

    // Function to toggle food options visibility based on category
    function toggleFoodOptionsVisibility() {
        const foodOptions = document.querySelectorAll('[name="foodType"], label[for="cookedFood"], label[for="uncookedFood"], label[for="bothFood"]');
        const currentCategory = document.querySelector('#categoryChoice')?.getAttribute('data-catname');

        if (currentCategory === 'food') {
            foodOptions.forEach(option => {
                option.style.display = '';
            });
        } else {
            foodOptions.forEach(option => {
                option.style.display = 'none';
            });
        }
    }

 // Function to create and display the UI
    function createFilterUI() {
        const uiContainer = document.createElement('div');
        uiContainer.style.position = 'fixed';
        uiContainer.style.top = '10px';
        uiContainer.style.right = '10px';
        uiContainer.style.backgroundColor = 'grey';
        uiContainer.style.border = '1px solid #ccc';
        uiContainer.style.padding = '10px';
        uiContainer.style.zIndex = '9999';

        uiContainer.innerHTML = `
            <label for="minPrice" style="color: red;">Min Price:</label>
            <input id="minPrice" type="text" placeholder="$0">
            <br>
            <label for="maxPrice" style="color: red;">Max Price:</label>
            <input id="maxPrice" type="text" placeholder="$1,000,000">
            <br>
            <input type="checkbox" id="hideUnaffordable" name="hideUnaffordable"> <label for="hideUnaffordable" style="color: red;">Hide Items You Can't Afford</label>
            <button id="applyFilter">Apply Filter</button>
            <p id="errorMessage" style="color: red; display: none;">Invalid price format. Use "$1,000" format.</p>
            <br>
            <label name="foodType" style="color: red;">Food Type:</label><br>
            <input type="radio" id="cookedFood" name="foodType" value="cooked"> <label for="cookedFood">Cooked Food</label><br>
            <input type="radio" id="uncookedFood" name="foodType" value="uncooked"> <label for="uncookedFood">Uncooked Food</label><br>
            <input type="radio" id="bothFood" name="foodType" value="both" checked> <label for="bothFood">Both</label><br>
        `;

        document.body.appendChild(uiContainer);

        const minPriceInput = document.getElementById('minPrice');
        const maxPriceInput = document.getElementById('maxPrice');
        const applyFilterButton = document.getElementById('applyFilter');
        const errorMessage = document.getElementById('errorMessage');
        const cookedFoodRadio = document.getElementById('cookedFood');
        const uncookedFoodRadio = document.getElementById('uncookedFood');
        const bothFoodRadio = document.getElementById('bothFood');
        const hideUnaffordableCheckbox = document.getElementById('hideUnaffordable');

        // Automatically filter food type when radio buttons are clicked
        cookedFoodRadio.addEventListener('change', () => {
            if (cookedFoodRadio.checked) filterByFoodType('cooked');
        });

        uncookedFoodRadio.addEventListener('change', () => {
            if (uncookedFoodRadio.checked) filterByFoodType('uncooked');
        });

        bothFoodRadio.addEventListener('change', () => {
            if (bothFoodRadio.checked) resetAllFoodItems();
        });


        applyFilterButton.addEventListener('click', () => {
            const minPriceText = minPriceInput.value.trim();
            const maxPriceText = maxPriceInput.value.trim();

            if ((minPriceText && validatePriceInput(minPriceText)) || (maxPriceText && validatePriceInput(maxPriceText)) || hideUnaffordableCheckbox.checked) {
                errorMessage.style.display = 'none';

                const minPrice = minPriceText && validatePriceInput(minPriceText) ? parsePrice(minPriceText) : 0;
                const maxPrice = maxPriceText && validatePriceInput(maxPriceText) ? parsePrice(maxPriceText) : Infinity;

                filterByPriceRange(minPrice, maxPrice);

            } else {
                errorMessage.style.display = 'block';
            }
        });

        hideUnaffordableCheckbox.addEventListener('change', () => {
            if (hideUnaffordableCheckbox.checked) {
                filterByAffordability();
            } else {
                filterByPriceRange(0, Infinity); // Reset to show all items within the current range
            }
        });

        // Toggle food options visibility based on category
        toggleFoodOptionsVisibility();

        // Observe category changes
        const observer = new MutationObserver(toggleFoodOptionsVisibility);
        observer.observe(document.querySelector('#categoryChoice'), { attributes: true });
    }

    // Initialize the script
    window.addEventListener('load', () => {
        createFilterUI();
    });
})();