MediaWiki:Common.js: Difference between revisions

From MDrivenWiki
No edit summary
No edit summary
Line 48: Line 48:
         showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
         showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
             decisions.deletion = true;
             decisions.deletion = true;
             showLoadingDialog('Performing Cleanup', function (updateLoadingText) {
             showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText) {
                 executeAllActions(pageTitle, decisions, function () {
                 executeAllActions(pageTitle, decisions, function () {
                     location.reload();
                     loadingDialog.close().closed.then(function() {
                        location.reload();
                    });
                 }, updateLoadingText);
                 }, updateLoadingText);
             });
             });
Line 100: Line 102:
                         '<div class="modal-body">' +
                         '<div class="modal-body">' +
                             '<p id="loading-text">' + message + '</p>' +
                             '<p id="loading-text">' + message + '</p>' +
                            '<ul id="loading-log"></ul>' +
                         '</div>' +
                         '</div>' +
                     '</div>' +
                     '</div>' +
Line 109: Line 112:
         modal.modal('show');
         modal.modal('show');


         callback(function (text) {
         callback({
            $('#loading-text').text(text);
            dialog: modal,
            console.log(text); // Log progress
            updateLoadingText: function (text) {
                $('#loading-text').text(text);
                console.log(text); // Log progress
                $('#loading-log').append('<li>' + text + '</li>');
            }
         });
         });
     }
     }
Line 119: Line 126:


         function handleLinksAndRedirects(action, newTarget, next) {
         function handleLinksAndRedirects(action, newTarget, next) {
             updateLoadingText(action === 'update' ? 'Updating all links and redirects...' : 'Removing all links and redirects...');
             updateLoadingText('Fetching backlinks...');
             api.get({
             api.get({
                 action: 'query',
                 action: 'query',
Line 129: Line 136:
                     var promises = $.map(data.query.backlinks, function (link) {
                     var promises = $.map(data.query.backlinks, function (link) {
                         return new $.Deferred(function (defer) {
                         return new $.Deferred(function (defer) {
                            updateLoadingText('Processing backlink: ' + link.title);
                             if (action === 'update') {
                             if (action === 'update') {
                                 updateLink(link.title, newTarget, api).then(defer.resolve);
                                 updateLinkInPage(link.title, pageTitle, newTarget, api).then(defer.resolve);
                             } else {
                             } else {
                                 removeLinkFromPage(link.title, pageTitle, api, action === 'update' ? newTarget : null).then(defer.resolve);
                                 removeLinkFromPage(link.title, pageTitle, api).then(defer.resolve);
                             }
                             }
                         }).promise();
                         }).promise();
                     });
                     });
                     $.when.apply($, promises).then(function () {
                     $.when.apply($, promises).then(function () {
                         updateLoadingText(action === 'update' ? 'All links and redirects updated.' : 'All links and redirects removed.');
                         updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
                         next();
                         next();
                     });
                     });
Line 150: Line 158:
         }
         }


         function updateLink(pageTitle, newTarget, api) {
         function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api) {
             return api.postWithToken('csrf', {
             return api.get({
                 action: 'edit',
                 action: 'parse',
                 title: pageTitle,
                 page: linkedPageTitle,
                 text: '#REDIRECT [[' + newTarget + ']]',
                 prop: 'wikitext'
                summary: 'Updated redirect to new target [[' + newTarget + ']]'
            }).then(function (data) {
                var wikitext = data.parse.wikitext['*'];
                var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]');
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Updated link to [[' + newTarget + ']]'
                });
             }).fail(function (error) {
             }).fail(function (error) {
                 console.error('Error updating link:', error);
                 console.error('Error updating link in page:', error);
             });
             });
         }
         }


         function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, newTarget) {
         function removeLinkFromPage(linkedPageTitle, originalPageTitle, api) {
             return api.get({
             return api.get({
                 action: 'parse',
                 action: 'parse',
Line 169: Line 186:
                 var wikitext = data.parse.wikitext['*'];
                 var wikitext = data.parse.wikitext['*'];
                 var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                 var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
                 var newWikitext = newTarget ?
                 var newWikitext = wikitext.replace(regex, function(match, p1) {
                    wikitext.replace(regex, '[[' + newTarget + '$1]]') :
                     return p1 ? p1.substring(1) : originalPageTitle;
                     wikitext.replace(regex, originalPageTitle);
                });
                 return api.postWithToken('csrf', {
                 return api.postWithToken('csrf', {
                     action: 'edit',
                     action: 'edit',
                     title: linkedPageTitle,
                     title: linkedPageTitle,
                     text: newWikitext,
                     text: newWikitext,
                     summary: newTarget ? 'Updated link to [[' + newTarget + ']]' : 'Removed link to [[' + originalPageTitle + ']]'
                     summary: 'Removed link to [[' + originalPageTitle + ']]'
                 });
                 });
             }).fail(function (error) {
             }).fail(function (error) {
                 console.error('Error removing link:', error);
                 console.error('Error removing link from page:', error);
             });
             });
         }
         }


         function handleRedirects(next) {
         function handleRedirects(next) {
            updateLoadingText('Fetching redirects...');
             api.get({
             api.get({
                 action: 'query',
                 action: 'query',
Line 193: Line 211:
                     var promises = $.map(redirects, function (redirect) {
                     var promises = $.map(redirects, function (redirect) {
                         return new $.Deferred(function (defer) {
                         return new $.Deferred(function (defer) {
                            updateLoadingText('Deleting redirect: ' + redirect.title);
                             performDeletion(redirect.title, defer.resolve);
                             performDeletion(redirect.title, defer.resolve);
                         }).promise();
                         }).promise();
Line 210: Line 229:


         function performDeletion(pageTitle, next) {
         function performDeletion(pageTitle, next) {
             updateLoadingText('Deleting the page...');
             updateLoadingText('Deleting the page: ' + pageTitle);
             api.postWithToken('csrf', {
             api.postWithToken('csrf', {
                 action: 'delete',
                 action: 'delete',
Line 216: Line 235:
                 reason: 'Automated clean delete by admin'
                 reason: 'Automated clean delete by admin'
             }).done(function () {
             }).done(function () {
                 updateLoadingText('Page deleted.');
                 updateLoadingText('Page deleted: ' + pageTitle);
                 next();
                 next();
             }).fail(function (error) {
             }).fail(function (error) {

Revision as of 09:10, 8 July 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) {
                executeAllActions(pageTitle, decisions, function () {
                    loadingDialog.close().closed.then(function() {
                        location.reload();
                    });
                }, updateLoadingText);
            });
        });
    }

    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({
            dialog: modal,
            updateLoadingText: function (text) {
                $('#loading-text').text(text);
                console.log(text); // Log progress
                $('#loading-log').append('<li>' + text + '</li>');
            }
        });
    }

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

        function handleLinksAndRedirects(action, newTarget, next) {
            updateLoadingText('Fetching backlinks...');
            api.get({
                action: 'query',
                list: 'backlinks',
                bltitle: pageTitle,
                bllimit: 'max'
            }).done(function (data) {
                if (data.query.backlinks) {
                    var promises = $.map(data.query.backlinks, function (link) {
                        return new $.Deferred(function (defer) {
                            updateLoadingText('Processing backlink: ' + link.title);
                            if (action === 'update') {
                                updateLinkInPage(link.title, pageTitle, newTarget, api).then(defer.resolve);
                            } else {
                                removeLinkFromPage(link.title, pageTitle, api).then(defer.resolve);
                            }
                        }).promise();
                    });
                    $.when.apply($, promises).then(function () {
                        updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
                        next();
                    });
                } else {
                    next();
                }
            }).fail(function (error) {
                console.error('Error fetching backlinks:', error);
                updateLoadingText('Error fetching backlinks: ' + error);
                next();
            });
        }

        function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api) {
            return 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]]');
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Updated link to [[' + newTarget + ']]'
                });
            }).fail(function (error) {
                console.error('Error updating link in page:', error);
            });
        }

        function removeLinkFromPage(linkedPageTitle, originalPageTitle, api) {
            return 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;
                });
                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: linkedPageTitle,
                    text: newWikitext,
                    summary: 'Removed link to [[' + originalPageTitle + ']]'
                });
            }).fail(function (error) {
                console.error('Error removing link from page:', error);
            });
        }

        function handleRedirects(next) {
            updateLoadingText('Fetching redirects...');
            api.get({
                action: 'query',
                titles: pageTitle,
                redirects: true
            }).done(function (data) {
                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) {
                            updateLoadingText('Deleting redirect: ' + redirect.title);
                            performDeletion(redirect.title, defer.resolve);
                        }).promise();
                    });
                    $.when.apply($, promises).then(function () {
                        next();
                    });
                } else {
                    next();
                }
            }).fail(function (error) {
                console.error('Error fetching redirects:', error);
                updateLoadingText('Error fetching redirects: ' + error);
                next();
            });
        }

        function performDeletion(pageTitle, next) {
            updateLoadingText('Deleting the page: ' + pageTitle);
            api.postWithToken('csrf', {
                action: 'delete',
                title: pageTitle,
                reason: 'Automated clean delete by admin'
            }).done(function () {
                updateLoadingText('Page deleted: ' + pageTitle);
                next();
            }).fail(function (error) {
                console.error('Error during clean deletion:', error);
                updateLoadingText('Error during clean deletion: ' + error);
                next();
            });
        }

        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);
                } else {
                    resolve();
                }
            }
        ];

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

    mw.hook('wikipage.content').add(addCleanDeleteLink);
});
This page was edited 146 days ago on 08/26/2024. What links here