Bikarhêner:Balyozxane/skrîpt/js/addSortKey.js

Ji Wîkîpediya, ensîklopediya azad.

Zanibe: Piştî weşandinê, ji bo dîtina guhartinan dibe ku hewce be "cache"ya geroka xwe paqij bikî.

  • Firefox / Safari: Pê li Shift û Reload bike an jî Ctrl-F5 an Ctrl-R bike (ji bo Mac: ⌘-R)
  • Google Chrome: Pê li Ctrl-Shift-R (ji bo Mac: ⌘-Shift-R) bike
  • Internet Explorer / Edge: Pê li Ctrl û Refresh bike, an jî Ctrl-F5 bike
  • Opera: Pê li Ctrl-F5 bike.
$(document).ready(function() {
    mw.loader.using(["mediawiki.api", "jquery.ui"]).done(function() {

        function getCategoriesAndPagesInCategory(categoryName, callback) {
            // Construct the API URL
            const apiUrl = "https://ku.wikipedia.org/w/api.php";
            const params = {
                action: "query",
                list: "categorymembers",
                cmtitle: encodeURIComponent(categoryName),
                cmlimit: "max", // To retrieve all members
                format: "json"
            };

            const queryString = Object.keys(params).map(key => key + '=' + params[key]).join('&');
            const fullUrl = apiUrl + '?' + queryString;

            // Make a request to the API
            fetch(fullUrl)
                .then(response => response.json())
                .then(data => {
                    // Extract category and page members from the response
                    if (data.query && data.query.categorymembers) {
                        const members = data.query.categorymembers.reduce((acc, member) => {
                            if (!acc[member.ns]) {
                                acc[member.ns] = [];
                            }
                            acc[member.ns].push(member.title);
                            return acc;
                        }, {});
                        callback(members);
                    } else {
                        callback({
                            0: [],
                            14: []
                        });
                    }
                })
                .catch(error => {
                    console.error("Error fetching categories and pages:", error);
                    callback({
                        0: [],
                        14: []
                    });
                });
        }

        function displayModal(categoriesAndPages) {
            const pageTitle = mw.config.get('wgPageName');
            let sereke = pageTitle.replace(/_/g, " ").replace(/^Kategorî:/, "");

            const firstPart = sereke.split(" ")[0];
            let pattern = "^" + firstPart + " (.*?)$";
            
            const categoryItems = categoriesAndPages[14] ? categoriesAndPages[14].map(category => `<div class="category-item">${category}</div>`).join('') : '';
            const pageItems = categoriesAndPages[0] ? categoriesAndPages[0].map(page => `<div class="page-item">${page}</div>`).join('') : '';
            
            const modalContent = `
                <style>
                    .category-item.selected, .page-item.selected {
                        font-weight: bold;
                        background-color: #ffcc80; /* Orange highlight color */
                    }
                </style>
                <div>
                    <label for="pattern">Pattern:</label>
                    <input type="text" id="pattern" value="${pattern}">
                </div>
                <div>
                    <input type="radio" id="categoryRadio" name="content" value="category" checked>
                    <label for="categoryRadio">Categories</label>
                    <input type="radio" id="pageRadio" name="content" value="page">
                    <label for="pageRadio">Pages</label>
                </div>
                <div id="content-list">
                    ${categoryItems}
                </div>
                <button id="selectAllButton">Select All</button>
                <button id="invertSelectionButton">Invert</button>
                <button id="saveButton">Save Changes</button>
            `;

            $('#modal-content').html(modalContent);
            openModal();

            $('#selectAllButton').on('click', function() {
                $('.category-item, .page-item').addClass('selected');
            });

            $('#invertSelectionButton').on('click', function() {
                $('.category-item, .page-item').toggleClass('selected');
            });

            $('#saveButton').on('click', function() {
                const editedPattern = $('#pattern').val();
                const editedItems = $('.category-item.selected, .page-item.selected').map(function() {
                    return $(this).text();
                }).get();

                // Update the pages with edited data
                editPages(sereke, editedPattern, editedItems);
            });

            // Event listener for selecting items
            $('#content-list').on('click', '.category-item, .page-item', function() {
                $(this).toggleClass('selected');
            });

            // Event listener for radio button change
            $('input[name="content"]').on('change', function() {
                const contentType = $(this).val();
                if (contentType === 'category') {
                    $('#content-list').html(categoryItems);
                } else if (contentType === 'page') {
                    $('#content-list').html(pageItems);
                }
            });
        }

        // Ji [[:commons:MediaWiki:Gadget-Cat-a-lot.js#L-600]] hat girtin
        function regexCatBuilder(category) {
            var catname = "Kategorî";

            // Build a regexp string for matching the given category:
            // trim leading/trailing whitespace and underscores
            category = category.replace(/^[\s_]+|[\s_]+$/g, '');

            // escape regexp metacharacters (= any ASCII punctuation except _)
            category = mw.util.escapeRegExp(category);

            // any sequence of spaces and underscores should match any other
            category = category.replace(/[\s_]+/g, '[\\s_]+');

            // Make the first character case-insensitive:
            var first = category.substr(0, 1);
            if (first.toUpperCase() !== first.toLowerCase()) {
                category = '[' + first.toUpperCase() + first.toLowerCase() + ']' + category.substr(1);
            }

            // Compile it into a RegExp that matches MediaWiki category syntax (yeah, it looks ugly):
            // XXX: the first capturing parens are assumed to match the sortkey, if present, including the | but excluding the ]]
            return new RegExp('\\[\\[[\\s_]*' + catname + '[\\s_]*:[\\s_]*' + category + '[\\s_]*(\\|[^\\]]*(?:\\][^\\]]+)*)?\\]\\]\\s*', 'g');
        }

        function editPages(sereke, editedPattern, editedItems) {
            const promises = editedItems.map(item => {
                const patterns_arr = [" ", "!", "+", "*"];
                let sort_key;

                if (patterns_arr.includes(editedPattern)) {
                    console.log("Using editedPattern as sort_key:", editedPattern);
                    sort_key = editedPattern;
                } else {
                    console.log("Checking if editedPattern is a valid regex and matches sereke...");
                    const regexPattern = new RegExp(editedPattern);
                    const item_kat_removed = item.replace(/^Kategorî:/, "");
                    if (regexPattern.test(item_kat_removed)) {
                        console.log("Edited pattern is a valid regex and matches item:", editedPattern);
                        const match = item_kat_removed.match(regexPattern);
                        if (match && match[1]) {
                            sort_key = match[1]; // Extract the matching part of item
                            console.log("Extracted sort_key:", sort_key);
                        } else {
                            console.log("No match found for sort_key, skipping to the next item");
                            // If no match found for sort_key, skip to the next item
                            return Promise.resolve();
                        }
                    } else {
                        console.log("Edited pattern is not a valid regex or doesn't match item, skipping to the next item");
                        // If editedPattern is not a valid regex or doesn't match item, skip to the next item
                        return Promise.resolve();
                    }
                }

                // Fetch current content of the page
                console.log("Fetching current content of the page:", item);
                return fetch(`https://ku.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(item)}&prop=revisions&rvprop=content&format=json`)
                    .then(response => response.json())
                    .then(data => {
                        const pages = data.query.pages;
                        const pageId = Object.keys(pages)[0];
                        let currentPageContent = pages[pageId].revisions[0]['*'];

                        // Build a RegExp to match sereke with sort_key
                        console.log("Building RegExp to match sereke with sort_key:", sereke, sort_key);
                        const regexBuilder = new RegExp(regexCatBuilder(sereke));

                        // Update the page content with the edited data
                        console.log("Replacing content in currentPageContent with sort_key:", sort_key);
                        const updatedContent = currentPageContent.replace(regexBuilder, `[[Kategorî:${sereke}|${sort_key}]]\n`);

                        // Get CSRF token
                        console.log("Fetching CSRF token...");
                        return fetch("https://ku.wikipedia.org/w/api.php?action=query&meta=tokens&type=csrf&format=json")
                            .then(response => response.json())
                            .then(data => {
                                const editToken = data.query.tokens.csrftoken;

                                // Construct edit parameters
                                console.log("Constructing edit parameters...");
                                const apiUrl = "https://ku.wikipedia.org/w/api.php";
                                const editParams = new URLSearchParams({
                                    action: "edit",
                                    title: item,
                                    token: editToken,
                                    summary: `Kilîda rêzkirinê li [[Kategorî:${sereke}]] hat zêdekirin ([[Bikarhêner:Balyozxane/skrîpt/js/addSortKey.js|addSortKey.js]])`,
                                    text: updatedContent,
                                    format: "json"
                                });

                                // Send POST request to edit the page
                                console.log("Sending POST request to edit the page...");
                                return fetch(apiUrl, {
                                    method: "POST",
                                    body: editParams
                                });
                            });
                    });
            });

            // Wait for all edit requests to complete
            console.log("Waiting for all edit requests to complete...");
            Promise.all(promises)
                .then(responses => {
                    responses.forEach(response => {
                        if (response.ok) {
                            console.log("Content edited successfully");
                            mw.notify("Content edited successfully");
                        } else {
                            console.error("Failed to edit content:", response);
                            mw.notify("Failed to edit content", {
                                type: "error"
                            });
                        }
                    });
                    closeModal(); // Close the modal after content is edited
                })
                .catch(error => {
                    console.error("Error editing content:", error);
                    mw.notify("Error editing content", {
                        type: "error"
                    });
                });
        }


        // Function to open the modal
        function openModal() {
            $('#myModal').dialog('open');
        }

        // Function to close the modal
        function closeModal() {
            $('#myModal').dialog('close');
        }

        // Create the modal dialog
        const modal = $('<div>', {
            id: 'myModal',
            title: 'AddSortKey',
            style: 'display: none;'
        });

        // Modal content area
        const modalContent = $('<div>', {
            id: 'modal-content'
        });
        modal.append(modalContent);

        // Append modal to the document body
        $(document.body).append(modal);

        // Initialize the modal as a jQuery UI dialog
        modal.dialog({
            autoOpen: false,
            modal: true,
            width: 'auto', // Adjusted for responsiveness
            close: function() {
                // Remove the modal from the DOM when closed
                $(this).dialog('destroy');
                $(this).remove();
            }
        });
        // Define the function to handle the click event
        function handleTemplateDataClick(event) {
            event.preventDefault(); // Prevent the default action of following the link

            const categoryName = mw.config.get('wgPageName');
            getCategoriesAndPagesInCategory(categoryName, function(categoriesAndPages) {
                displayModal(categoriesAndPages);
            });
        }

        if (mw.config.get('wgNamespaceNumber') === 14) {
            // Create the link using mw.util.addPortletLink
            var targetContainer = mw.config.get('skin') === 'vector-2022' ? 'p-cactions' : 'p-tb';
            var link = mw.util.addPortletLink(targetContainer, '#', 'AddSortKey', 't-AddSortKey', 'AddSortKey');

            // Attach an event listener to the link
            link.addEventListener('click', handleTemplateDataClick);
        }
    });
});