User:Polygnotus/Scripts/NamespaceFilter.js

This is an old revision of this page, as edited by Polygnotus (talk | contribs) at 12:45, 24 August 2024. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>
// ==UserScript==
// @name         Wikipedia Namespace Filter
// @version      0.4
// @description  Filter special page results by namespace, including mainspace, with All/None options and storing prefs in localstorage
// @match        https://*.wikipedia.org/w/index.php?title=Special:LinkSearch*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const STORAGE_KEY = 'wikipediaNamespaceFilter';

    function addStyles() {
        const style = document.createElement('style');
        style.textContent = `
            #namespace-filter {
                margin: 10px 0;
                padding: 10px;
                border: 1px solid #a2a9b1;
                background-color: #f8f9fa;
            }
            #namespace-filter label {
                margin-right: 10px;
                display: inline-block;
            }
            #all-none-options {
                margin-bottom: 10px;
            }
            #all-none-options button {
                margin-right: 10px;
            }
        `;
        document.head.appendChild(style);
    }

    function getNamespaces() {
        const namespaces = new Set(['Main']);
        document.querySelectorAll('ol.special li a:nth-child(2)').forEach(link => {
            const text = link.textContent;
            const colonIndex = text.indexOf(':');
            if (colonIndex === -1) {
                namespaces.add('Main');
            } else {
                const namespace = text.substring(0, colonIndex);
                if (namespace) {
                    namespaces.add(namespace);
                }
            }
        });
        return Array.from(namespaces).sort((a, b) => a === 'Main' ? -1 : b === 'Main' ? 1 : a.localeCompare(b));
    }

    function createFilterUI(namespaces) {
        const filterDiv = document.createElement('div');
        filterDiv.id = 'namespace-filter';
        filterDiv.innerHTML = '<h4>Filter by namespace:</h4>';

        // Add All/None options
        const allNoneDiv = document.createElement('div');
        allNoneDiv.id = 'all-none-options';
        const allButton = document.createElement('button');
        allButton.textContent = 'Select All';
        allButton.addEventListener('click', () => setAllCheckboxes(true));
        const noneButton = document.createElement('button');
        noneButton.textContent = 'Select None';
        noneButton.addEventListener('click', () => setAllCheckboxes(false));
        allNoneDiv.appendChild(allButton);
        allNoneDiv.appendChild(noneButton);
        filterDiv.appendChild(allNoneDiv);

        const savedFilters = getSavedFilters();

        namespaces.forEach(namespace => {
            const label = document.createElement('label');
            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.value = namespace;
            checkbox.checked = savedFilters ? savedFilters.includes(namespace) : true;
            checkbox.addEventListener('change', () => {
                filterResults();
                saveFilters();
            });
            label.appendChild(checkbox);
            label.appendChild(document.createTextNode(namespace));
            filterDiv.appendChild(label);
        });

        const ol = document.querySelector('ol.special');
        ol.parentNode.insertBefore(filterDiv, ol);
    }

    function setAllCheckboxes(checked) {
        document.querySelectorAll('#namespace-filter input[type="checkbox"]').forEach(cb => {
            cb.checked = checked;
        });
        filterResults();
        saveFilters();
    }

    function filterResults() {
        const checkedNamespaces = Array.from(document.querySelectorAll('#namespace-filter input:checked')).map(cb => cb.value);
        document.querySelectorAll('ol.special li').forEach(li => {
            const link = li.querySelector('a:nth-child(2)');
            const text = link.textContent;
            const colonIndex = text.indexOf(':');
            const namespace = colonIndex === -1 ? 'Main' : text.substring(0, colonIndex);
            if (checkedNamespaces.includes(namespace)) {
                li.style.display = '';
            } else {
                li.style.display = 'none';
            }
        });
    }

    function saveFilters() {
        const checkedNamespaces = Array.from(document.querySelectorAll('#namespace-filter input:checked')).map(cb => cb.value);
        localStorage.setItem(STORAGE_KEY, JSON.stringify(checkedNamespaces));
    }

    function getSavedFilters() {
        const savedFilters = localStorage.getItem(STORAGE_KEY);
        return savedFilters ? JSON.parse(savedFilters) : null;
    }

    function init() {
        const namespaces = getNamespaces();
        if (namespaces.length > 0) {
            addStyles();
            createFilterUI(namespaces);
            filterResults(); // Apply filters on initial load
        }
    }

    // Run the script when the page is loaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
// </nowiki>