User:Hoo man/smartUndo.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/*
* [[m:user:Hoo man]]; Version 1.2.0; 2012-06-10;
* Provides smart undo (automatic undo of many changes)
* Requires rollback permissions (the script needs it to find pages which have undoable edits)
* Tested in IE and FF with vector and monobook, uses my (Hoo man) wiki tools (functions.js)
*
* DO NOT COPY AND PASTE, instead use:
 
//Smart undo, by [[m:user:Hoo man]]
mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:Hoo_man/smartUndo.js&action=raw&ctype=text/javascript');
 
*/

if(typeof(hoo) === 'undefined') {
	hoo = {};
}

/*global hoo, mw, smartUndoConfig, disable_smart_undo */
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, loopfunc:true, bitwise:true, undef:true, browser:true, jquery:true, indent:4, maxerr:50, white:false */

hoo.smartUndo = function() {
	this.init = function() {
		//edit summaries
		if(typeof(smartUndoConfig) === 'undefined' || typeof(smartUndoConfig.editSummaries) === 'undefined') {
			//smartUndoConfig.editSummaries isn't set, so we take the default out of the lang file
			this.config.editSummaries = mw.messages.get('hoo-smartUndo-editSummaries');
		}else{
			this.config.editSummaries = smartUndoConfig.editSummaries;
		}
		hoo.addToolLink(mw.message('hoo-smartUndo-toolbarText').escaped(), (function (self) { return function() { self.openWindow(); }; })(this), '', this.config.toolLinkMethod);
	};
	this.openWindow = function() {
		if(!this.window) {
			this.window = new hoo.popup('smartUndoWindow', 460, 155, mw.message('hoo-smartUndo-windowTitle').escaped());
			this.window.addButton(mw.message('hoo-smartUndo-windowMassButton').escaped(), (function (self) { return function() { self.performAction(); }; })(this));
		}else{
			this.window.reOpen();
		}
		var tmp = '<form name="smartUndoForm">';
		tmp += mw.message('hoo-smartUndo-editSummary').escaped() + '<br /><select name="editSummarySelect" style="width: 97%;">';
		tmp += '<option value="useDefault">' +  mw.message('hoo-smartUndo-useDefault').escaped() + '</option>';
		for(var i in this.config.editSummaries) {
			if(typeof(this.config.editSummaries[i]) === 'string' && i !== 'other' && i !== 'useDefault') { //to filter out stupid prototype functions and deprecated strings
				tmp += '<option value="' + this.config.editSummaries[i] + '">' + this.config.editSummaries[i] + '</option>';
			}
		}
		tmp += '<option value="otherSummary" id="smartUndoUseCustomEditSummary">' + mw.message('hoo-smartUndo-other').escaped() + '</option>';
		tmp += '</select><br />';
		tmp += '<small>' + mw.message('hoo-smartUndo-editSummaryInfo').escaped() + '</small><br /><br />';
		tmp += mw.message('hoo-smartUndo-customEditSummary').escaped() + '<br /><input name="editSummaryOther" id="smartUndoEditSummaryOther" type="text" style="width: 97%;" onClick="document.getElementById(\'smartUndoUseCustomEditSummary\').selected = \'true\'"><br /><br />';
		if(this.config.enableBotEdits !== false && (hoo.isInGlobalGroup('Global_bot') || hoo.isInGroup('bot') || hoo.isInGroup('flood') || this.config.enableBotEdits === true)) {
			tmp += mw.message('hoo-smartUndo-markbotedits').escaped() + '<br /><label for="hoo-smartUndo-yes">' + mw.message('hoo-smartUndo-yes').escaped() + ':</label><input type="radio" name="bot" value="true" id="hoo-smartUndo-yes">';
			tmp += '<label for="hoo-smartUndo-yes">' + mw.message('hoo-smartUndo-no').escaped() + ':</label><input type="radio" name="bot" value="false" id="hoo-smartUndo-no" checked>';
		}
		tmp += '</form>';
		this.window.containerHTML(tmp);
	};
	this.performAction = function() {
		var titles, lastRev, params, i, y, tmp, temp, page;
		this.window.close();
		hoo.showProcess();
		//new edit summary
		var summary = document.smartUndoForm.editSummarySelect.value;
		if(summary === 'otherSummary') {
			summary = document.smartUndoForm.editSummaryOther.value;
		}
		if(summary === 'useDefault') {
			summary = hoo.api.sync.getPage({title : 'MediaWiki:Undo-summary', usemsgcache : true});
		}
		//mark as bot edits?
		var bot = 'false';
		if(document.smartUndoForm.bot) {
			for(i=0; i<document.smartUndoForm.bot.length; i++) {
				if(document.smartUndoForm.bot[i].checked) {
					bot = document.smartUndoForm.bot[i].value;
				}
			}
		}
		//get all rollback links on page
		var links = document.getElementsByTagName('a');
		var pageList = {};
		for(i = 0; i<links.length; i++) {
			if(links[i].parentNode.className === 'mw-rollback-link') {
				//it is a rollback link, so we auto undo
				tmp = mw.util.getParamValue('title', links[i].href).replace(/_/g, ' ');
				pageList[ tmp ] = {};
				pageList[ tmp ].from = mw.util.getParamValue('from', links[i].href);
				
			}
		}
		y = i = 0;
		titles = [];
		for(page in pageList) {
			if(typeof(page) === 'string') {
				if(i === 0) {
					titles[y] = page;
				}else if(i < 500) {
					titles[y] += '|' + page;
				}else{
					//500 filed, starting next list
					y++;
					i = -1;
				}
				i++;
			}
		}
		for(i = 0; i<titles.length; i++) {
			tmp = hoo.api.sync.getToken('edit', titles[i], true);
			for(y = 0; y<tmp.pageids.length; y++) {
				temp = pageList[ tmp.pages[ tmp.pageids[y] ].title ].from;
				pageList[ tmp.pages[ tmp.pageids[y] ].title ] = tmp.pages[ tmp.pageids[y] ];
				pageList[ tmp.pages[ tmp.pageids[y] ].title ].from = temp;
			}
		}
		for(page in pageList) {
			if(typeof(page) === 'string') {
				try {
					lastRev = pageList[page].revisions[0];
					if(lastRev.user !== pageList[page].from) {
						continue;
					}
					params = {'summary' : summary.replace(/\$1/g, lastRev.revid).replace(/\$2/g, lastRev.user), 'minor' : true, 'basetimestamp' : lastRev.timestamp, 'undo' : lastRev.revid};
					if(bot !== 'false') {
						params.bot = true;
					}
					hoo.api.sync.edit(page, params);
				}catch(e) {
					// mhm :/
				}
			}
		}
		window.location.reload();
	};
	var lang;
	if(typeof(disable_smart_undo) !== 'undefined' && disable_smart_undo) {
		return false;
	}
	if(typeof(smartUndoConfig) === 'undefined') {
		this.config = hoo.objectDiff(hoo.smartUndoDefaultConfig, null);
	}else{
		this.config = hoo.objectDiff(smartUndoConfig, hoo.smartUndoDefaultConfig);
	}
	if(typeof(this.config.toolLinkMethod) === 'undefined') {
		this.config.toolLinkMethod = hoo.config.toolLinkMethod;
	}
	//is there at least one rollback link on the page, so that there is smth. to undo?
	var spans = mw.util.$content[0].getElementsByTagName('span');
	for(var i = 0; i<spans.length; i++) {
		if(spans[i].className === 'mw-rollback-link') {
			//localization
			if(this.config.lang) {
				lang = this.config.lang;
			}else{
				lang = hoo.config.lang;
			}
			hoo.loadLocalization(lang, '//meta.wikimedia.org/w/index.php?title=User:Hoo_man/lang/$1/smartUndo.js&action=raw&ctype=text/javascript', (function (self) { return function() { self.init(); }; })(this), this.config.availableLangs, 'en');
			break;
		}
	}
};

//default config
if(typeof(hoo.smartUndoDefaultConfig) === 'undefined') hoo.smartUndoDefaultConfig = {};

//to change anything just add one of the following lines to your own .js and replace 'hoo.smartUndoDefaultConfig' with 'smartUndoConfig'
hoo.smartUndoDefaultConfig.lang = null;
hoo.smartUndoDefaultConfig.enableBotEdits = null;
hoo.smartUndoDefaultConfig.availableLangs = ['en'];

//(default) lang
mw.messages.set({
	'hoo-smartUndo-toolbarText' : 'Smart undo',
	'hoo-smartUndo-windowTitle' : 'Smart undo',
	'hoo-smartUndo-windowMassButton' : 'Undo everything',
	'hoo-smartUndo-editSummary' : 'Edit summary:',
	'hoo-smartUndo-editSummaryInfo' : '($1 will be replaced with the revision id and $2 with the user)',
	'hoo-smartUndo-customEditSummary' : 'Custom edit summary:',
	'hoo-smartUndo-useDefault' : 'Use the default edit summary',
	'hoo-smartUndo-markbotedits' : 'Mark edits as bot edits:',
	'hoo-smartUndo-yes' : 'Yes',
	'hoo-smartUndo-no' : 'No',
	'hoo-smartUndo-other' : 'Other ->',
	'hoo-smartUndo-editSummaries' : [
		'Undo revision $1',
		'Undo revision $1, vandalism'
	]
});

if(typeof(hoo) === 'undefined' || typeof(hoo.objectDiff) === 'undefined') {
	if(typeof(hoo_callbacks) === 'undefined') {
		var hoo_callbacks = [ function() { hoo.instances.smartUndo = new hoo.smartUndo(); } ];
		mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:Hoo_man/functions2.js&action=raw&ctype=text/javascript');		
	}else{
		hoo_callbacks = hoo_callbacks.concat([ function() { hoo.instances.smartUndo = new hoo.smartUndo(); } ]);   
	}
}else{
	hoo.instances.smartUndo = new hoo.smartUndo();
}