Aller au contenu

MediaWiki:Gadget-BatchPurge.js

De Wiki Undertale FR

Note : après avoir publié vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

  • Firefox / Safari : maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou appuyez sur Ctrl + F5 ou Ctrl + R (⌘ + R sur un Mac).
  • Google Chrome : appuyez sur Ctrl + Maj + R (⌘ + Shift + R sur un Mac).
  •  Edge : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl + F5.
/* Copied from https://dev.fandom.com/wiki/MediaWiki:MassNullEdit/code.js */
/* MassNullEdit originally by OneTwoThreeFall and Ozuzanna */

const apiModeData = {
    backlinks: {
        name: 'backlinks',
        limit: 'bllimit',
        value: 'bltitle'
    },
    transclusions: {
        name: 'embeddedin',
        limit: 'eilimit',
        value: 'eititle'
    },
    fileusage: {
        name: 'imageusage',
        limit: 'iulimit',
        value: 'iutitle'
    },
    prefix: {
        name: 'prefixsearch',
        limit: 'pslimit',
        value: 'pssearch'
    },
    category: {
        name: 'categorymembers',
        limit: 'cmlimit',
        value: 'cmtitle'
    },
    namespace: {
        name: 'allpages',
        limit: 'aplimit',
        value: 'apnamespace'
    }
};
const namespaces = mw.config.get('wgFormattedNamespaces');


let i18n;
const editApi = new mw.Api();
let failedPages = [];
let input;
const modalMain = new mw.libs.QDmodal('mne-main');
const modalAddPages = new mw.libs.QDmodal('mne-addpages');
let paused = true;
let rateLimited = false;
let rateLimitTimeoutId;
let stopAddPages = null;

modalMain.$element.addClass("mne-modal");
modalAddPages.$element.addClass("mne-modal");

function log(i18nMsg) {
    $('#mne-output').prepend(i18nMsg.parse(), '<br>');
}

function addToInput(pages) {
    var currentPages = input.value.split('\n');

    pages = pages.filter(function (page) {
        return currentPages.indexOf(page) === -1;
    });

    if (pages.length) {
        input.value += pages.join('\n') + '\n';
    }

    return pages.length;
}

function nullEdit(titles) {
    var editReq = editApi.post({
        action: 'purge',
        titles,
        forcerecursivelinkupdate: true
    });
    editReq.always(function (result, resultIfRejected) {
        if (editReq.state() === 'rejected') {
            result = resultIfRejected;
        }
        var error = result.error && result.error.code;
        if (error === 'ratelimited') {
            rateLimited = true;
            input.value = `${titles.join('\n')}\n${input.value}`;
        } else if (error) {
            failedPages.push(...titles);
            log(i18n('fail', titles, error));
        }
        process();
    });
}

function pause() {
    paused = true;
    rateLimited = false;
    modalMain.$element.removeClass("processing");
}

function start() {
    paused = false;
    modalMain.$element.addClass("processing");
    process();
}

function process() {
    if (rateLimited) {
        log(i18n('notice-ratelimit'));
        pause();
        rateLimitTimeoutId = setTimeout(start, 30000);
    }
    if (paused || input === null) {
        return;
    }
    const pages = input.value
        .trim()
        .split('\n')
        .map(p => p.trim())
        .filter(Boolean);
    const batch = pages.splice(0, 50);
    input.value = pages.join('\n');
    if (batch.length) {
        nullEdit(batch);
    } else {
        log(i18n('notice-finished'));
        addToInput(failedPages);
        failedPages = [];
        pause();
    }
}

function addPages(query, mode, displayValue) {
    var pages = [];
    var queryApi = new mw.Api({parameters: query});

    function complete(error) {
        if (error) {
            log(i18n('notice-error-' + mode, displayValue, error));
        }

        // show success message if either no error (a successful result may be 0 pages)
        // or error (in which case a multi-request query might still have some results)
        if (!error || pages.length) {
            var addedCount = addToInput(pages);
            log(i18n('notice-success-' + mode, displayValue, addedCount));
        }

        // reset "add pages" modal if it was used
        modalAddPages.$element.removeClass("processing");
        modalAddPages.hide();
    }

    function collect(more) {
        var queryReq = queryApi.get(more);
        queryReq.always(function (result, resultIfRejected) {
            if (queryReq.state() === 'rejected') {
                result = resultIfRejected;
            }

            var error = (result.error && result.error.code) || 'unknown';
            var data = result.query && result.query[query.list];
            var continueData = result['query-continue'];

            if (data) {
                data.forEach(function (entry) {
                    pages.push(entry.title);
                });
            } else {
                complete(error);
                return;
            }

            if (continueData && stopAddPages === null) {
                stopAddPages = !confirm(i18n('confirm-big-request', result.limits[query.list]).parse());
            }

            if (continueData && !stopAddPages) {
                collect(continueData[query.list]);
            } else {
                complete();
            }
        });
    }

    modalAddPages.$element.addClass("processing");
    collect();
}

function addPagesProcess(mode, value) {
    var modeData = apiModeData[mode];
    var query = {rawcontinue: ''};
    const nsCategory = `${namespaces[14]}:`;
    const nsFile = namespaces[6] + ':';

    // cancel if unknown mode or empty/undefined value
    if (!modeData || !value) {
        return;
    }
    let displayValue = value;

    // mode-specific adjustments
    switch (mode) {
    case 'namespace':
        // use namespace name for displaying namespace requests
        displayValue = value === '0'
            ? i18n('namespace-main').escape()
            : namespaces[value];
        break;
    case 'category':
        // add namespace to category value if not included,
        // else remove it from display for brevity
        if (value.indexOf(nsCategory) !== 0) {
            value = nsCategory + value;
        } else {
            displayValue = displayValue.slice(nsCategory.length);
        }
        break;
    case 'fileusage':
        // add namespace to file value if not included,
        // else remove it from display for brevity
        if (value.indexOf(nsFile) !== 0) {
            value = nsFile + value;
        } else {
            displayValue = displayValue.slice(nsFile.length);
        }
        break;
    case 'prefix':
        // separate namespace id
        var nsAndTitle = new mw.Title(value);
        query.apnamespace = nsAndTitle.namespace;
        value = nsAndTitle.title;
        break;
    }

    query.list = modeData.name;
    query[modeData.value] = value;
    query[modeData.limit] = 'max';

    addPages(query, mode, displayValue);
}

function addPagesCreateModalRow(mode) {
    var $row = $('<p>').attr('class', 'mne-addpages-row');
    var $radio = $('<input>').attr({
        type: 'radio',
        name: 'mode',
        value: mode
    });
    var $input = $('<input>').attr({
        type: 'text',
        name: mode
    });

    if (mode === 'namespace') {
        $input = $('<select>').attr('name', mode);

        Object.keys(namespaces).forEach(function (ns) {
            if (Number(ns) < 0) {
                return;
            }

            var opt = document.createElement('option');
            opt.value = ns;
            opt.textContent = ns === '0'
                ? i18n('namespace-main').plain()
                : namespaces[ns];

            $input.append(opt);
        });
    }

    // select a mode if its value is changed
    $input.on('change', function () {
        $radio.prop('checked', true);
    });

    $row.append(
        $('<label>').append(
            $radio,
            document.createTextNode(i18n('addpages-' + mode).plain())
        ),
        $input
    );

    return $row;
}

function addPagesOpenModal() {
    var formData;
    var $modalContent = $('<form>').attr('id', 'mne-mode');

    Object.keys(apiModeData).forEach(function (mode) {
        $modalContent.append(addPagesCreateModalRow(mode));
    });

    modalAddPages.show({
        title: i18n('addpages').plain(),
        content: $modalContent,
        onShow: function () {
            stopAddPages = null;
            formData = document.forms['mne-mode'].elements;
            modalAddPages.$footer.append(
                $('<span>').attr('id', 'mne-processing-msg').text(i18n('processing').plain()),
                mw.libs.QDmodal.getSpinner()
            );
        },
        onHide: function () {
            stopAddPages = true;
        },
        buttons: [{
            text: i18n('addpages').plain(),
            attr: {id: 'mne-addpages-start'},
            handler: function () {
                // formData.mode.value would be better, but not available in IE 11
                var mode = modalAddPages.$content.find('[name=mode]:checked').val();
                var value = formData[mode] && formData[mode].value;
                addPagesProcess(mode, value);
            }
        }, {
            text: i18n('cancel').plain(),
            handler: modalAddPages.hide.bind(modalAddPages)
        }]
    });
}

function autoFillPages() {
    const relevantPage = new mw.Title(mw.config.get('wgRelevantPageName'));
    if (mw.config.get('wgCanonicalNamespace') === 'Category') {
        addPagesProcess('category', relevantPage.getPrefixedText());
    }
    switch (mw.config.get('wgCanonicalSpecialPageName')) {
        case 'Whatlinkshere':
            addPagesProcess('backlinks', relevantPage.getPrefixedText());
            addPagesProcess('transclusions', relevantPage.getPrefixedText());
            if (relevantPage.namespace === 6) {
                addPagesProcess('fileusage', relevantPage.getPrefixedText());
            }
            break;
        case 'Allpages':
            addPagesProcess(
                'namespace',
                $('form [name="namespace"]').val()
            );
            break;
        case 'Prefixindex':
            var prefix = $('form [name="prefix"]').val();
            var prefixNs = $('form [name="namespace"]').val();
            var page = '';
    
            if (prefixNs !== '0') {
                page += namespaces[prefixNs] + ':';
            }
    
            page += prefix;
            addPagesProcess('prefix', page);
            break;
    }
}

function openModal(ev) {
    ev.preventDefault();

    var modalContents = (
        '<p>' + i18n('instructions').escape() + '</p>' +
        '<textarea id="mne-input"></textarea>' +
        '<div id="mne-output">' +
            '<i>' + i18n('notice-output').escape() + '</i>' +
        '</div>'
    );

    modalMain.show({
        title: i18n('title').plain(),
        content: modalContents,
        onShow: function () {
            input = document.getElementById('mne-input');
            pause();
            modalMain.$footer.append(
                $('<span>').attr('id', 'mne-processing-msg').text(i18n('processing').plain()),
                mw.libs.QDmodal.getSpinner()
            );
        },
        onHide: function () {
            pause();
            input = null;
            clearTimeout(rateLimitTimeoutId);
        },
        buttons: [{
            text: i18n('initiate').plain(),
            attr: {id: 'mne-main-start'},
            handler: start
        }, {
            text: i18n('pause').plain(),
            attr: {id: 'mne-main-pause'},
            handler: pause
        }, {
            text: i18n('addpages').plain(),
            handler: addPagesOpenModal
        }, {
            text: i18n('cancel').plain(),
            handler: modalMain.hide.bind(modalMain)
        }]
    });
    autoFillPages();
}

window.dev.i18n.loadMessages('MassNullEdit').done(function (i18nData) {
    i18n = i18nData.msg;
    const link = mw.util.addPortletLink('p-tb', '#', i18n('title').plain(), 't-mne');
    if (link) {
        link.addEventListener('click', openModal);
    }
});