MediaWiki:Common.js: Difference between revisions

From MDrivenWiki
No edit summary
Tag: Manual revert
No edit summary
 
(47 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Any JavaScript here will be loaded for all users on every page load. */
// ==UserScript==
$(document).ready(function () {
// @name        MediaWiki Clean Delete
    $.get(mw.util.wikiScript('api'), {
// @namespace  MediaWikiScripts
        action: 'query',
// @description Adds a 'Clean Delete' action link to pages for admins to delete pages and clean up incoming links and redirects.
        meta: 'userinfo',
// ==/UserScript==
        format: 'json'
 
     }).done(function (data) {
mw.loader.using(['mediawiki.api', 'mediawiki.util', 'jquery'], function () {
         if (data.query.userinfo.id !== 0) {  
     function addCleanDeleteLink() {
             var username = data.query.userinfo.name;
         if (mw.config.get('wgUserGroups').indexOf('sysop') !== -1) {
            var userLink = mw.util.getUrl('User:' + username);
             if ($('#ca-cleandelete').length === 0) {
            var logoutLink = mw.util.getUrl('Special:Logout');
                var $link = $('<div>').attr('id', 'ca-cleandelete').attr('class', 'mw-list-item').append(
            $('#user-info').html('<a href="' + userLink + '" class="text-white">' + username + '</a>' +
                    $('<a>').attr('href', '#').attr('class', 'ca-cleandelete').text('Clean Delete').click(function (e) {
                                ' &nbsp;|&nbsp; <a href="' + logoutLink + '" class="text-white">Logout</a>');
                        e.preventDefault();
                        gatherAllDecisions(mw.config.get('wgPageName'));
                    })
                );
                $('#p-actions .tab-group').append($link);
            }
         }
         }
     });
     }
});


    function gatherAllDecisions(pageTitle) {
        var decisions = {};
        showModal('Handle Links and Redirects', '<div class="form-group">' +
            '<label>Specify how you would like to handle all incoming links and redirects:</label>' +
            '<select id="link-handling-select" class="form-control">' +
                '<option value="delete">Delete Links and Redirects</option>' +
                '<option value="change">Change Target of Links and Redirects</option>' +
            '</select>' +
        '</div>', function () {
            var choice = $('#link-handling-select').val();
            if (choice === 'change') {
                showModal('Specify New Target', '<div class="form-group">' +
                    '<label>Enter the new target page name to update all links and redirects:</label>' +
                    '<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' +
                '</div>', function () {
                    decisions.links = $('#new-target-input').val();
                    confirmDeletion(pageTitle, decisions);
                });
            } else {
                decisions.links = '';
                confirmDeletion(pageTitle, decisions);
            }
        });
    }


document.getElementById('offcanvas-toggler').addEventListener('click', function() {
    function confirmDeletion(pageTitle, decisions) {
    var sidebar = document.getElementById('offcanvas-menu');
        showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
    if (sidebar.classList.contains('show')) {
            decisions.deletion = true;
        sidebar.classList.remove('show');
            showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) {
    } else {
                executeAllActions(pageTitle, decisions, function () {
         sidebar.classList.add('show');
                    loadingDialog.close().closed.then(function() {
                        location.reload();
                    });
                }, updateLoadingText, logDetail);
            });
         });
     }
     }
});


    function showModal(title, body, onConfirm) {
        var modal = $(
            '<div class="modal fade" tabindex="-1" role="dialog">' +
                '<div class="modal-dialog" role="document">' +
                    '<div class="modal-content">' +
                        '<div class="modal-header">' +
                            '<h5 class="modal-title">' + title + '</h5>' +
                            '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
                                '<span aria-hidden="true">&times;</span>' +
                            '</button>' +
                        '</div>' +
                        '<div class="modal-body">' + body + '</div>' +
                        '<div class="modal-footer">' +
                            '<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' +
                            '<button type="button" class="btn btn-primary">Confirm</button>' +
                        '</div>' +
                    '</div>' +
                '</div>' +
            '</div>'
        );
        modal.find('.btn-primary').click(function () {
            onConfirm();
            modal.modal('hide');
        });
        modal.on('hidden.bs.modal', function () {
            modal.remove();
        });


        $('body').append(modal);
        modal.modal('show');
    }


    function showLoadingDialog(message, callback) {
        var modal = $(
            '<div class="modal fade" tabindex="-1" role="dialog">' +
                '<div class="modal-dialog" role="document">' +
                    '<div class="modal-content">' +
                        '<div class="modal-header">' +
                            '<h5 class="modal-title">Performing Cleanup</h5>' +
                        '</div>' +
                        '<div class="modal-body">' +
                            '<p id="loading-text">' + message + '</p>' +
                            '<ul id="loading-log"></ul>' +
                        '</div>' +
                    '</div>' +
                '</div>' +
            '</div>'
        );


$(document).ready(function() {
        $('body').append(modal);
    $('#offcanvas-close').on('click', function() {
         modal.modal('show');
         $('#offcanvas-menu').removeClass('show');
    });
});


document.addEventListener('DOMContentLoaded', function() {
        callback(modal, function (text) {
    var form = document.querySelector('.namespace-search-form');
            $('#loading-text').text(text);
    if (form) {
            $('#loading-log').append('<li>' + text + '</li>');
        form.addEventListener('submit', function(e) {
        }, function (detail) {
             var input = form.querySelector('#bs-extendedsearch-input');
             $('#loading-log').append('<li>' + detail + '</li>');
            if (input) {
                var namespace = mw.config.get('wgCanonicalNamespace');
                if (namespace && namespace.length > 0) {
                    input.value = namespace + ": " + input.value;
                }
            }
         });
         });
     }
     }
});


(function($) {
    function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) {
    'use strict';
        var api = new mw.Api();


    var css = [
         function handleLinksAndRedirects(action, newTarget, next) {
         '#suggestion-container {',
            updateLoadingText('Fetching backlinks...');
        '   position: relative;',
            api.get({
        '    width: 100%;',
                action: 'query',
        '}',
                list: 'backlinks',
        '#suggestion-box {',
                bltitle: pageTitle,
        '    position: absolute;',
                bllimit: 'max',
        '   top: 100%;',  
                blfilterredir: 'all' // Include both redirects and non-redirects
        '    left: 0;',  
            }).done(function (data) {
        '    width: 100%;',
                logDetail('Backlinks fetched.');
        '    margin-top: 5px;',  
                if (data.query.backlinks) {
        '    background-color: #fff;',
                    var promises = $.map(data.query.backlinks, function (link) {
        '   z-index: 1000;',
                        return new $.Deferred(function (defer) {
        '}',
                            api.get({
        '.suggestion-item {',
                                action: 'parse',
        '   padding: 8px;',
                                page: link.title,
        '    cursor: pointer;',
                                prop: 'wikitext'
        '}',
                            }).done(function (linkData) {
        '.suggestion-item:hover {',
                                var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT');
        '    background-color: #e0e0e0;',
                                if (isRedirect) {
        '}'
                                    if (action === 'update') {
    ].join('\n');
                                        updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail);
    $('head').append('<style type="text/css">' + css + '</style>');
                                    } else {
 
                                        logDetail('Backlink ' + link.title + ' is a redirect. Deleting...');
    $('#suggestion-container').append('<div id="suggestion-box"></div>');
                                        performDeletion(link.title, defer.resolve, logDetail);
 
                                    }
    function showSuggestions() {
                                } else {
        var query = $(this).val();
                                    if (action === 'update') {
        if (query.length > 0) {  
                                        updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail);
            var apiUrl = "https://wiki.mdriven.net/api.php";
                                     } else {
            var requestData = {
                                         removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail);
                action: "bs-extendedsearch-autocomplete",
                format: "json",
                q: JSON.stringify({
                    query: {
                        bool: {
                            must: {
                                match: {
                                     ac_ngram: {
                                         query: query
                                     }
                                     }
                                 }
                                 }
                             }
                             }).fail(function (error) {
                        }
                                logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error);
                    },
                                defer.resolve();
                    size: 8
                            });
                }),
                        }).promise();
                searchData: JSON.stringify({
                     });
                    namespace: 0,
                     $.when.apply($, promises).then(function () {
                    value: query,
                         updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
                    mainpage: ""
                         next();
                })
            };
            $.ajax({
                url: apiUrl,
                data: requestData,
                dataType: "json",
                method: "GET",
                success: function(data) {
                     var suggestions = data.suggestions || [];
                     $('#suggestion-box').empty();
                    $.each(suggestions, function(index, suggestion) {
                         var item = $('<div class="suggestion-item"></div>').text(suggestion.basename);
                         $('#suggestion-box').append(item);
                     });
                     });
                 },
                 } else {
                error: function(jqxhr, textStatus, error) {
                     next();
                     console.error('Error fetching suggestions:', error);
                 }
                 }
            }).fail(function (error) {
                updateLoadingText('Error fetching backlinks: ' + error);
                next();
             });
             });
         }
         }
    }


  function hideSuggestions(event) {
        function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) {
    if (!$(event.target).closest('#suggestion-container').length) {
            api.get({
        $('#suggestion-box').empty();
                action: 'parse',
    }
                page: linkedPageTitle,
}
                prop: 'wikitext'
            }).then(function (data) {
                var wikitext = data.parse.wikitext['*'];
                var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]');
                if (wikitext !== newWikitext) {
                    logDetail('Updating link in ' + linkedPageTitle);
                } else {
                    logDetail('No link found in ' + linkedPageTitle);
                }
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Updated link to [[' + newTarget + ']]'
                }).then(function (response) {
                    console.log('API response from updating link: ', response);
                    if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                        logDetail('Successfully updated link in ' + linkedPageTitle);
                    } else {
                        logDetail('No changes made to link in ' + linkedPageTitle);
                    }
                    resolve();
                }).fail(function (error) {
                    logDetail('Error updating link in ' + linkedPageTitle + ': ' + error);
                    resolve();
                });
            }).fail(function (error) {
                logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
                resolve();
            });
        }


function selectSuggestion(event) {
        function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) {
    event.preventDefault(); // Prevent the mousedown event from triggering blur on the search input
            logDetail('Updating redirect target in ' + redirectPageTitle);
    var selectedText = $(this).text();
            return api.postWithToken('csrf', {
    window.location.href = '/index.php?title=' + encodeURIComponent(selectedText);
                action: 'edit',
}
                title: redirectPageTitle,
                text: '#REDIRECT [[' + newTarget + ']]',
                summary: 'Updated redirect to [[' + newTarget + ']]'
            }).then(function (response) {
                console.log('API response from updating redirect: ', response);
                if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                    logDetail('Successfully updated redirect in ' + redirectPageTitle);
                } else {
                    logDetail('No changes made to redirect in ' + redirectPageTitle);
                }
                resolve();
            }).fail(function (error) {
                logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error);
                resolve();
            });
        }


        function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) {
            api.get({
                action: 'parse',
                page: linkedPageTitle,
                prop: 'wikitext'
            }).then(function (data) {
                var wikitext = data.parse.wikitext['*'];
                var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                var newWikitext = wikitext.replace(regex, function(match, p1) {
                    return p1 ? p1.substring(1) : originalPageTitle;
                });
                if (wikitext !== newWikitext) {
                    logDetail('Removing link from ' + linkedPageTitle);
                } else {
                    logDetail('No link found in ' + linkedPageTitle);
                }
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Removed link to [[' + originalPageTitle + ']]'
                }).then(function (response) {
                    console.log('API response from removing link: ', response);
                    if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                        logDetail('Successfully removed link from ' + linkedPageTitle);
                    } else {
                        logDetail('No changes made to link in ' + linkedPageTitle);
                    }
                    resolve();
                }).fail(function (error) {
                    logDetail('Error removing link from ' + linkedPageTitle + ': ' + error);
                    resolve();
                });
            }).fail(function (error) {
                logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
                resolve();
            });
        }


  $('.search-input').on('input', showSuggestions);
        function handleRedirects(next) {
$(document).on('click', hideSuggestions);
            updateLoadingText('Fetching redirects...');
$('#suggestion-box').on('mousedown', '.suggestion-item', selectSuggestion);  
            api.get({
                action: 'query',
                titles: pageTitle,
                redirects: true
            }).done(function (data) {
                logDetail('Redirects fetched.');
                var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects;
                if (redirects) {
                    var promises = $.map(redirects, function (redirect) {
                        return new $.Deferred(function (defer) {
                            logDetail('Found redirect: ' + redirect.title);
                            performDeletion(redirect.title, defer.resolve, logDetail);
                        }).promise();
                    });
                    $.when.apply($, promises).then(function () {
                        next();
                    });
                } else {
                    next();
                }
            }).fail(function (error) {
                updateLoadingText('Error fetching redirects: ' + error);
                next();
            });
        }


 
        function performDeletion(pageTitle, resolve, logDetail) {
})(jQuery);
            updateLoadingText('Deleting the page: ' + pageTitle);
 
            api.postWithToken('csrf', {
$(document).ready(function() {
                action: 'delete',
    // Function to toggle a section open or closed
                title: pageTitle,
    function toggleSection(element) {
                reason: 'Automated clean delete by admin'
        var submenu = $(element).next('.submenu');
            }).done(function (response) {
        submenu.toggle();
                console.log('API response from deleting page: ', response);
    }
                if (response.delete && response.delete.title) {
 
                    logDetail('Successfully deleted page: ' + response.delete.title);
    // Function to open the submenu containing the current page link and scroll to it
                } else {
    function openCurrentPageSubmenuAndScroll() {
                    logDetail('No deletion performed for ' + pageTitle);
        var currentPageLink = $('#navMenu .current-page');
                }
        if (currentPageLink.length) {
                resolve();
            // Open the parent submenu(s) of the current page link
             }).fail(function (error) {
            currentPageLink.parents('.submenu').show();
                 logDetail('Error during clean deletion of ' + pageTitle + ': ' + error);
 
                 resolve();
             // Delay the scrolling to allow for any dynamic layout changes
             });
            setTimeout(function() {
                 // Calculate the position of the current page link
                var position = currentPageLink.offset().top - $('#navMenu').offset().top + $('#navMenu').scrollTop();
 
                 // Scroll the menu to the active item
                $('#navMenu').animate({
                    scrollTop: position
                }, 500);
             }, 100); // Delay of 100 milliseconds
         }
         }
    }


    // Event delegation for dynamically loaded content
        var tasks = [
    $('#navMenu').on('click', '.menu-header', function() {
            function (resolve) {
        toggleSection(this);
                if (decisions.links === '') {
    });
                    handleLinksAndRedirects('remove', '', resolve);
                } else {
                    handleLinksAndRedirects('update', decisions.links, resolve);
                }
            },
            function (resolve) {
                if (decisions.deletion) {
                    handleRedirects(resolve);
                } else {
                    resolve();
                }
            },
            function (resolve) {
                if (decisions.deletion) {
                    performDeletion(pageTitle, resolve, logDetail);
                } else {
                    resolve();
                }
            }
        ];


    // Open the submenu containing the current page link and scroll to it
        (function executeTasks(i) {
    openCurrentPageSubmenuAndScroll();
            if (i < tasks.length) {
});
                tasks[i](function () {
 
                    executeTasks(i + 1);
document.getElementById('menu-toggle').addEventListener('click', function() {
                });
    var navMenu = document.getElementById('navMenu');
            } else {
    var bodyContent = document.getElementById('bodyContent');
                callback();
 
            }
    if (navMenu.style.display === 'none' || navMenu.style.display === '') {
         })(0);
        navMenu.style.display = 'block';
        bodyContent.style.display = 'none'; // Hide body content when nav menu is displayed
    } else {
         navMenu.style.display = 'none';
        bodyContent.style.display = 'block'; // Show body content when nav menu is hidden
     }
     }
});


$(document).ready(function() {
     mw.hook('wikipage.content').add(addCleanDeleteLink);
     $('.video__navigation .navigation-item').click(function() {
        var videoID = $(this).data('video');
        var startTime = $(this).data('start');
        var newSrc = 'https://www.youtube.com/embed/' + videoID + '?start=' + startTime + '&autoplay=1';
       
        $('.video__wrapper iframe').attr('src', newSrc);
    });
});
 
$(document).ready(function() {
        $('.bs-extendedsearch-filter-button-button').each(function() {
            $(this).append('<span class="fa fa-chevron-down"></span>');
        });
});
});


document.addEventListener("scroll", function() {
    var sidebar = document.getElementById("navMenu");
    var footerHeight = 100;
    var windowHeight = window.innerHeight;
    var scrollBottomPosition = window.scrollY + windowHeight;
    var footerTopPosition = document.documentElement.offsetHeight - footerHeight;


    if (scrollBottomPosition <= footerTopPosition) {
(function() {
        sidebar.style.height = "100vh";
    // Function to remove special characters from the search term
     } else {
     function sanitizeSearchTerm(term) {
         sidebar.style.height = "calc(100vh - 110px)";
         return term.replace(/[^a-zA-Z0-9\s]/g, ''); // Keep only alphanumeric characters and spaces
     }
     }
});


mw.loader.using('jquery', function() {
    // Save the original fetch function
     $(document).ready(function() {
     var originalFetch = window.fetch;
        var $toc = $('#toc').clone();
        $('#toc').remove();
        $('#tocContainer').html($toc);


 
    // Override the fetch function
        $('#tocContainer').css({
    window.fetch = function() {
            position: '-webkit-sticky',
        var url = arguments[0];
            position: 'sticky',
         var options = arguments[1] || {};
            top: '0',
            padding: '15px',
            margin: '0 auto',
            borderRadius: '5px',
            maxWidth: '280px',
            maxHeight: 'max-content',
            overflowY: 'auto',
            height: '90vh',
            zIndex: 1000
         });


         $('#tocContainer .toctitle').css({
         // Check if the URL is the target API endpoint
            fontSize: '16px',
        if (typeof url === 'string' && url.indexOf('action=bs-extendedsearch-query') !== -1) {
             fontWeight: '600',
             // Decode the URL to manipulate it
             color: '#555',
             var decodedUrl = decodeURIComponent(url);
            borderBottom: '1px solid #ccc',
            paddingBottom: '10px',
            marginBottom: '10px'
        });


        $('#tocContainer ul').css({
             // Find the search term in the URL
             margin: 0,
             var searchTermMatch = decodedUrl.match(/searchTerm=([^&]*)/);
             padding: '0 0 0 20px',
             if (searchTermMatch && searchTermMatch[1]) {
             listStyleType: 'none',
                var originalSearchTerm = searchTermMatch[1];
            fontSize: '14px',
            lineHeight: '1.6'
        });


        $('#tocContainer li').css({
                // Sanitize the search term
            marginBottom: '5px',
                var sanitizedSearchTerm = sanitizeSearchTerm(originalSearchTerm);
        });


        $('#tocContainer a').css({
                // Replace the original search term with the sanitized one
            color: '#555',
                decodedUrl = decodedUrl.replace(originalSearchTerm, sanitizedSearchTerm);
            textDecoration: 'none',
        }).hover(
            function() { $(this).css({textDecoration: 'underline', color: '#000'}); },
            function() { $(this).css({textDecoration: 'none', color: '#555'}); }
        );
    });
});


$(document).ready(function() {
                // Re-encode the URL
    var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input');
                url = encodeURI(decodedUrl);
    if ($inputElement.length) {
        $inputElement.on('keydown', function(event) {
            if (event.key === 'Enter') {
                event.preventDefault();
                $inputElement.addClass('search-input');
             }
             }
         });
         }
    }
});


$(document).ready(function() {
        // Call the original fetch function with the modified URL
    var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input');
         return originalFetch.apply(this, [url, options]);
    if ($inputElement.length) {
     };
        $inputElement.addClass('search-input');
})();
         console.log('Class "search-input" added to the input element.');
     } else {
        console.log('Input element not found.');
    }
});

Latest revision as of 23:50, 25 August 2024

// ==UserScript==
// @name        MediaWiki Clean Delete
// @namespace   MediaWikiScripts
// @description Adds a 'Clean Delete' action link to pages for admins to delete pages and clean up incoming links and redirects.
// ==/UserScript==

mw.loader.using(['mediawiki.api', 'mediawiki.util', 'jquery'], function () {
    function addCleanDeleteLink() {
        if (mw.config.get('wgUserGroups').indexOf('sysop') !== -1) {
            if ($('#ca-cleandelete').length === 0) {
                var $link = $('<div>').attr('id', 'ca-cleandelete').attr('class', 'mw-list-item').append(
                    $('<a>').attr('href', '#').attr('class', 'ca-cleandelete').text('Clean Delete').click(function (e) {
                        e.preventDefault();
                        gatherAllDecisions(mw.config.get('wgPageName'));
                    })
                );
                $('#p-actions .tab-group').append($link);
            }
        }
    }

    function gatherAllDecisions(pageTitle) {
        var decisions = {};
        showModal('Handle Links and Redirects', '<div class="form-group">' +
            '<label>Specify how you would like to handle all incoming links and redirects:</label>' +
            '<select id="link-handling-select" class="form-control">' +
                '<option value="delete">Delete Links and Redirects</option>' +
                '<option value="change">Change Target of Links and Redirects</option>' +
            '</select>' +
        '</div>', function () {
            var choice = $('#link-handling-select').val();
            if (choice === 'change') {
                showModal('Specify New Target', '<div class="form-group">' +
                    '<label>Enter the new target page name to update all links and redirects:</label>' +
                    '<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' +
                '</div>', function () {
                    decisions.links = $('#new-target-input').val();
                    confirmDeletion(pageTitle, decisions);
                });
            } else {
                decisions.links = '';
                confirmDeletion(pageTitle, decisions);
            }
        });
    }

    function confirmDeletion(pageTitle, decisions) {
        showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
            decisions.deletion = true;
            showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) {
                executeAllActions(pageTitle, decisions, function () {
                    loadingDialog.close().closed.then(function() {
                        location.reload();
                    });
                }, updateLoadingText, logDetail);
            });
        });
    }

    function showModal(title, body, onConfirm) {
        var modal = $(
            '<div class="modal fade" tabindex="-1" role="dialog">' +
                '<div class="modal-dialog" role="document">' +
                    '<div class="modal-content">' +
                        '<div class="modal-header">' +
                            '<h5 class="modal-title">' + title + '</h5>' +
                            '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
                                '<span aria-hidden="true">&times;</span>' +
                            '</button>' +
                        '</div>' +
                        '<div class="modal-body">' + body + '</div>' +
                        '<div class="modal-footer">' +
                            '<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' +
                            '<button type="button" class="btn btn-primary">Confirm</button>' +
                        '</div>' +
                    '</div>' +
                '</div>' +
            '</div>'
        );

        modal.find('.btn-primary').click(function () {
            onConfirm();
            modal.modal('hide');
        });

        modal.on('hidden.bs.modal', function () {
            modal.remove();
        });

        $('body').append(modal);
        modal.modal('show');
    }

    function showLoadingDialog(message, callback) {
        var modal = $(
            '<div class="modal fade" tabindex="-1" role="dialog">' +
                '<div class="modal-dialog" role="document">' +
                    '<div class="modal-content">' +
                        '<div class="modal-header">' +
                            '<h5 class="modal-title">Performing Cleanup</h5>' +
                        '</div>' +
                        '<div class="modal-body">' +
                            '<p id="loading-text">' + message + '</p>' +
                            '<ul id="loading-log"></ul>' +
                        '</div>' +
                    '</div>' +
                '</div>' +
            '</div>'
        );

        $('body').append(modal);
        modal.modal('show');

        callback(modal, function (text) {
            $('#loading-text').text(text);
            $('#loading-log').append('<li>' + text + '</li>');
        }, function (detail) {
            $('#loading-log').append('<li>' + detail + '</li>');
        });
    }

    function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) {
        var api = new mw.Api();

        function handleLinksAndRedirects(action, newTarget, next) {
            updateLoadingText('Fetching backlinks...');
            api.get({
                action: 'query',
                list: 'backlinks',
                bltitle: pageTitle,
                bllimit: 'max',
                blfilterredir: 'all' // Include both redirects and non-redirects
            }).done(function (data) {
                logDetail('Backlinks fetched.');
                if (data.query.backlinks) {
                    var promises = $.map(data.query.backlinks, function (link) {
                        return new $.Deferred(function (defer) {
                            api.get({
                                action: 'parse',
                                page: link.title,
                                prop: 'wikitext'
                            }).done(function (linkData) {
                                var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT');
                                if (isRedirect) {
                                    if (action === 'update') {
                                        updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail);
                                    } else {
                                        logDetail('Backlink ' + link.title + ' is a redirect. Deleting...');
                                        performDeletion(link.title, defer.resolve, logDetail);
                                    }
                                } else {
                                    if (action === 'update') {
                                        updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail);
                                    } else {
                                        removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail);
                                    }
                                }
                            }).fail(function (error) {
                                logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error);
                                defer.resolve();
                            });
                        }).promise();
                    });
                    $.when.apply($, promises).then(function () {
                        updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
                        next();
                    });
                } else {
                    next();
                }
            }).fail(function (error) {
                updateLoadingText('Error fetching backlinks: ' + error);
                next();
            });
        }

        function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) {
            api.get({
                action: 'parse',
                page: linkedPageTitle,
                prop: 'wikitext'
            }).then(function (data) {
                var wikitext = data.parse.wikitext['*'];
                var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]');
                if (wikitext !== newWikitext) {
                    logDetail('Updating link in ' + linkedPageTitle);
                } else {
                    logDetail('No link found in ' + linkedPageTitle);
                }
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Updated link to [[' + newTarget + ']]'
                }).then(function (response) {
                    console.log('API response from updating link: ', response);
                    if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                        logDetail('Successfully updated link in ' + linkedPageTitle);
                    } else {
                        logDetail('No changes made to link in ' + linkedPageTitle);
                    }
                    resolve();
                }).fail(function (error) {
                    logDetail('Error updating link in ' + linkedPageTitle + ': ' + error);
                    resolve();
                });
            }).fail(function (error) {
                logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
                resolve();
            });
        }

        function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) {
            logDetail('Updating redirect target in ' + redirectPageTitle);
            return api.postWithToken('csrf', {
                action: 'edit',
                title: redirectPageTitle,
                text: '#REDIRECT [[' + newTarget + ']]',
                summary: 'Updated redirect to [[' + newTarget + ']]'
            }).then(function (response) {
                console.log('API response from updating redirect: ', response);
                if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                    logDetail('Successfully updated redirect in ' + redirectPageTitle);
                } else {
                    logDetail('No changes made to redirect in ' + redirectPageTitle);
                }
                resolve();
            }).fail(function (error) {
                logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error);
                resolve();
            });
        }

        function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) {
            api.get({
                action: 'parse',
                page: linkedPageTitle,
                prop: 'wikitext'
            }).then(function (data) {
                var wikitext = data.parse.wikitext['*'];
                var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                var newWikitext = wikitext.replace(regex, function(match, p1) {
                    return p1 ? p1.substring(1) : originalPageTitle;
                });
                if (wikitext !== newWikitext) {
                    logDetail('Removing link from ' + linkedPageTitle);
                } else {
                    logDetail('No link found in ' + linkedPageTitle);
                }
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Removed link to [[' + originalPageTitle + ']]'
                }).then(function (response) {
                    console.log('API response from removing link: ', response);
                    if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
                        logDetail('Successfully removed link from ' + linkedPageTitle);
                    } else {
                        logDetail('No changes made to link in ' + linkedPageTitle);
                    }
                    resolve();
                }).fail(function (error) {
                    logDetail('Error removing link from ' + linkedPageTitle + ': ' + error);
                    resolve();
                });
            }).fail(function (error) {
                logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
                resolve();
            });
        }

        function handleRedirects(next) {
            updateLoadingText('Fetching redirects...');
            api.get({
                action: 'query',
                titles: pageTitle,
                redirects: true
            }).done(function (data) {
                logDetail('Redirects fetched.');
                var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects;
                if (redirects) {
                    var promises = $.map(redirects, function (redirect) {
                        return new $.Deferred(function (defer) {
                            logDetail('Found redirect: ' + redirect.title);
                            performDeletion(redirect.title, defer.resolve, logDetail);
                        }).promise();
                    });
                    $.when.apply($, promises).then(function () {
                        next();
                    });
                } else {
                    next();
                }
            }).fail(function (error) {
                updateLoadingText('Error fetching redirects: ' + error);
                next();
            });
        }

        function performDeletion(pageTitle, resolve, logDetail) {
            updateLoadingText('Deleting the page: ' + pageTitle);
            api.postWithToken('csrf', {
                action: 'delete',
                title: pageTitle,
                reason: 'Automated clean delete by admin'
            }).done(function (response) {
                console.log('API response from deleting page: ', response);
                if (response.delete && response.delete.title) {
                    logDetail('Successfully deleted page: ' + response.delete.title);
                } else {
                    logDetail('No deletion performed for ' + pageTitle);
                }
                resolve();
            }).fail(function (error) {
                logDetail('Error during clean deletion of ' + pageTitle + ': ' + error);
                resolve();
            });
        }

        var tasks = [
            function (resolve) {
                if (decisions.links === '') {
                    handleLinksAndRedirects('remove', '', resolve);
                } else {
                    handleLinksAndRedirects('update', decisions.links, resolve);
                }
            },
            function (resolve) {
                if (decisions.deletion) {
                    handleRedirects(resolve);
                } else {
                    resolve();
                }
            },
            function (resolve) {
                if (decisions.deletion) {
                    performDeletion(pageTitle, resolve, logDetail);
                } else {
                    resolve();
                }
            }
        ];

        (function executeTasks(i) {
            if (i < tasks.length) {
                tasks[i](function () {
                    executeTasks(i + 1);
                });
            } else {
                callback();
            }
        })(0);
    }

    mw.hook('wikipage.content').add(addCleanDeleteLink);
});


(function() {
    // Function to remove special characters from the search term
    function sanitizeSearchTerm(term) {
        return term.replace(/[^a-zA-Z0-9\s]/g, ''); // Keep only alphanumeric characters and spaces
    }

    // Save the original fetch function
    var originalFetch = window.fetch;

    // Override the fetch function
    window.fetch = function() {
        var url = arguments[0];
        var options = arguments[1] || {};

        // Check if the URL is the target API endpoint
        if (typeof url === 'string' && url.indexOf('action=bs-extendedsearch-query') !== -1) {
            // Decode the URL to manipulate it
            var decodedUrl = decodeURIComponent(url);

            // Find the search term in the URL
            var searchTermMatch = decodedUrl.match(/searchTerm=([^&]*)/);
            if (searchTermMatch && searchTermMatch[1]) {
                var originalSearchTerm = searchTermMatch[1];

                // Sanitize the search term
                var sanitizedSearchTerm = sanitizeSearchTerm(originalSearchTerm);

                // Replace the original search term with the sanitized one
                decodedUrl = decodedUrl.replace(originalSearchTerm, sanitizedSearchTerm);

                // Re-encode the URL
                url = encodeURI(decodedUrl);
            }
        }

        // Call the original fetch function with the modified URL
        return originalFetch.apply(this, [url, options]);
    };
})();
This page was edited 146 days ago on 08/26/2024. What links here