Widget:Editing robot

Description
This widget facilitates the automation of repetitive edits. If you are doing lots of edits, make sure to login to a bot account before using this page.

/* CSS for bulk edit tool */ width: 100%; clear: both; } width: 100%; } border: 1px solid #555; background-color: #777; padding: 3px 0px; width: 100%; color: #EEE; text-align: center; font-size: 12pt; } .contentwrapper { border: 1px solid #555; margin-top: 2px; background-color: #DDD; width: 100%; } .contentwrapper > table { width: 100%; border-spacing: 5px; } .contentwrapper td { border: 1px solid #555; background-color: #EEE; padding: 5px; font-family: consolas; vertical-align: top; } min-width: 222px; width: 30%; } width: 99%; padding: 3px 2px; } width: 70px; margin: 0px 2px; } display: inline-block; height: 27px; } overflow-y: scroll; height: 515px; } background-color: #9F9; white-space: nowrap; } height: 500px; overflow-y: scroll; } background-color: #F99; white-space: nowrap; } max-height: 100px; overflow-y: scroll; } /* WIDGET: EDITING ROBOT */ function mwBulkScript {
 * 1) listwrapper {
 * 1) listwrapper > table {
 * 1) titlebar {
 * 1) listoperators {
 * 1) fullwrapper input[type=text] {
 * 1) fullwrapper input[type=button] {
 * 1) fullwrapper select {
 * 1) listinput textarea {
 * 1) listsucceed {
 * 1) listsucceed div {
 * 1) listfailed {
 * 1) listfailed div {

// Make the GUI. function makeTaskGUI { // Initialise frame with required options. var UIframe = $(' '                           +' AJAX purge/move/delete/restore/upload script '                            +' '                                +' '                            +' '                        +' '); $('#widgettarget').html(UIframe); // Update text list if files are provided. $('#filelist').change(function {           $('#listinput textarea').val( $.map($(this)[0].files, function(v) { return 'File:' + v['name']; }).join('\n') );        }); }   // Extract information from the GUI. function getCurrentTaskFromGUI (files) { // Define variables var mode = $('#listmode').val; var summary = ''; var content = ''; // no idea how we'd do this bit. Maybe only apply regex rules to old content? (GET required) var sourcepagetitle = ''; var targetpagetitle = ''; // Obtain the list of potential pages var allpages = []; allpages = $('#listinput textarea').val.split('\n'); // Take the first line away from the potential pages and add to the processing box. var currentline = allpages.shift; $('#listprogress').text(currentline); // Return allpages back to the form without the top line $('#listinput textarea').val(allpages.join('\n')); // Check list entry isn't blank var currentpages = currentline.split('>'); if (currentpages.length > 0) { sourcepagetitle = currentpages[0].trim; }       // Check if the mode is move, if so, we need to have a target. if (mode === 'move' && currentpages.length > 1) { targetpagetitle = currentpages[1].trim; } else if (mode === 'move') { // If no target, reject everything and shut down. return; }       // Get summary summary = $('#listsummary').val; // Verify inprogress isn't blank if ( $('#listprogress').text == '' ) { return; }       // Need to pass a different set of options for each operation var options = {}; switch (mode) { case "move": // Move source page to target page - this works by separating lists with '>' // FIXME: Use a tab instead? options = { action: 'move', reason: summary, from: sourcepagetitle, to: targetpagetitle, noredirect: true, movetalk: true, movesubpages: true, ignorewarnings: true, bot: true };               tokenOperation(options); break; case "delete": // Delete source page options = { action: 'delete', reason: summary, title: sourcepagetitle, bot: true };               tokenOperation(options); break; case "restore": // Restore source page with last revision options = { action: 'undelete', reason: summary, title: sourcepagetitle, bot: true };               tokenOperation(options); break; case "purge": // Purge current page content cache options = { action: 'purge', titles: sourcepagetitle, forcelinkupdate: true };               noTokenOperation(options); break; case "upload": // Upload selected files options = { action: 'upload', comment: summary, ignorewarnings: true }               var file = files.shift; fileOperation(options, file, files); break; default: // Do nothing and abort. return; break; }   }    // Perform an operation using the currently active account with a token. function tokenOperation (options) { // console.log(options); var pagetitle = options.title || options.from || options.titles; api.postWithToken( "csrf", options ) .done( function( result, jqXHR ) {           $('#listsucceed div').html( $('#listprogress').text + ' ' + $('#listsucceed div').html);            $('#listprogress').text();            if ( $('#listinput textarea').val !==  ) {                getCurrentTaskFromGUI;            }        }) .fail( function(code, result) {           $('#listfailed div').html( $('#listprogress').text + ' ' + $('#listfailed div').html);            $('#listprogress').text('');            if ( code === "http" ) {                console.log( pagetitle + ": HTTP error: " + result.textStatus );            } else if ( code === "ok-but-empty" ) {                console.log( pagetitle + ": Got an empty response from the server" );            } else {                console.log( pagetitle + ": API error: " + code );            }        }); }   // Perform an operation using the currently active account without a token. function noTokenOperation (options) { // console.log(options); var pagetitle = options.title || options.from || options.titles; api.post(options ) .done( function( result, jqXHR ) {           $('#listsucceed div').html( $('#listprogress').text + ' ' + $('#listsucceed div').html);            $('#listprogress').text();            if ( $('#listinput textarea').val !==  ) {                getCurrentTaskFromGUI;            }        }) .fail( function(code, result) {           $('#listfailed div').html( $('#listprogress').text + ' ' + $('#listfailed div').html);            $('#listprogress').text('');            if ( code === "http" ) {                console.log( pagetitle + ": HTTP error: " + result.textStatus );            } else if ( code === "ok-but-empty" ) {                console.log( pagetitle + ": Got an empty response from the server" );            } else {                console.log( pagetitle + ": API error: " + code );            }        }); }   // Perform a file upload operation using the currently active account. function fileOperation (options, file, files) { // We can't transmit files using the standard api functions like we used above. formdata = new FormData; // Add options from previous GUI function $.each(options, function(k, v) {           formdata.append(k, v);        }); // Supplement with editing token and the file formdata.append('token', mw.user.tokens.get( 'editToken' ) ); formdata.append('file', file); formdata.append('filename', file.name); // Upload the file $.ajax({           url: mw.util.wikiScript( 'api' ),            contentType: false,            processData: false,            type: 'POST',            data: formdata,            success: function(data) {                $('#listsucceed div').html( $('#listprogress').text + ' ' + $('#listsucceed div').html);                $('#listprogress').text();                if (files.length > 0) {                    getCurrentTaskFromGUI(files);                }            },            error: function(code, result) {                $('#listfailed div').html( $('#listprogress').text + ' ' + $('#listfailed div').html);                $('#listprogress').text();                if ( code === "http" ) {                    console.log( file.name + ": HTTP error: " + result.textStatus );                } else if ( code === "ok-but-empty" ) {                    console.log( file.name + ": Got an empty response from the server" ); } else { console.log( file.name + ": API error: " + code ); }           }        });    }    // Make the API connection, set up the GUI, respond to button pushes, loop through elements    function mainTaskFunction  {        // When user clicks run, pick up the current function and cycle through the list        $('input[name="run"]').click(function { console.log('user clicked run.'); if ( $('#listmode').val == 'blank' ) { console.log('User did not select a mode. Abort!'); return; }           var files = []; Array.prototype.push.apply( files, $('#filelist')[0].files ); if ( files.length > 0 ) { getCurrentTaskFromGUI(files); } else { getCurrentTaskFromGUI; }       });        // When user clicks reset, blank all fields        $('input[name="reset"]').click(function { console.log('user clicked reset.'); $('#listmode').val('blank'); $('#listsucceed div').html(''); $('#listfailed').html(''); $('#listinput textarea').text(''); $('#listprogress').text(''); $('#listprogress').text(''); $('#listsummary').val(''); });   }    // Prepare MediaWiki API functions    var api = new mw.Api;    // Create the user interface    makeTaskGUI;    // Add functions to the interface    mainTaskFunction;    // Make sure only admins get delete/restore options    var userrights = mw.config.get('wgUserGroups');    if (userrights.indexOf('sysop') == -1) {        $("#listmode option[value='delete']").remove;        $("#listmode option[value='restore']").remove;        $("#titlebar").val('AJAX purge/move/upload script');    } }

RLQ.push(['jquery', function {    mw.loader.using('mediawiki.api', function  { var userrights = mw.config.get('wgUserGroups'); var pageurl = window.location.href; if (userrights.indexOf('sysop') > -1 || userrights.indexOf('bot') > -1 || userrights.indexOf('patrol') > -1 || (pageurl.indexOf('#yesiknowwhatiamdoing') > -1) ) { mwBulkScript; } else { console.log('Insufficient user rights: '+JSON.stringify(userrights)); }   }); }]);