MediaWiki:Gadget-FastRollback.js

// /*jshint undef:true, latedef:true, undef:true, shadow:true, scripturl:true */ /*global mw, jQuery */ (function { var api = new mw.Api; function processLink(link, title, token, user, markbot) {	var wrapper = link.parentNode;	var bracketed = (wrapper.textContent[0] === '[');	link.addEventListener('click', function (ev) { ev.preventDefault;

var summary = prompt('About to rollback edits by User:' + user + ' to ' + title + '.\n\nEdit summary (empty for default):',			'Reverted edits by ' + user + '. If you think this rollback is in error, please leave a message on my talk page.'); if (summary === null) return; wrapper.textContent = bracketed ? '[wait]' : 'wait'; api.post({			action: 'rollback',			title: title,			user: user,			token: token,			markbot: markbot ? '1' : void(0),			summary: summary ? summary : void(0)		}).then(function (result) {			var diffLink = document.createElement('a');			diffLink.href = mw.config.get('wgScript') + '?diff=' + result.rollback.revid + '&diffonly=1';			diffLink.textContent = 'diff';			var reloadLink = document.createElement('a');			reloadLink.href = 'javascript:location.reload;';			reloadLink.textContent = 'reload';			wrapper.textContent = '';			if (bracketed) wrapper.appendChild(document.createTextNode('['));			wrapper.appendChild(document.createTextNode('done: '));			wrapper.appendChild(diffLink);			wrapper.appendChild(document.createTextNode(' | '));			wrapper.appendChild(reloadLink);			if (bracketed) wrapper.appendChild(document.createTextNode(']'));		}, function (code, result, xhr) {			link.textContent = 'retry'; var cnode = document.createElement('code'); cnode.style.borderBottom = '1px dotted black'; cnode.style.cursor = 'help'; cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; default: cnode.title = result.error.info; }

wrapper.textContent = ''; if (bracketed) wrapper.appendChild(document.createTextNode('[')); wrapper.appendChild(document.createTextNode('error: ')); wrapper.appendChild(cnode); wrapper.appendChild(document.createTextNode(' ('));			wrapper.appendChild(link);			wrapper.appendChild(document.createTextNode(')')); if (bracketed) wrapper.appendChild(document.createTextNode(']'));

console.error(result); });	}, false); } jQuery(document).ready(function {

var rolllinks = document.getElementsByClassName('mw-rollback-link');

for (var i = 0; i < rolllinks.length; ++i) { var links = rolllinks[i].getElementsByTagName('a'); if (links.length !== 1) continue; var link = links[0]; try { var uri = new mw.Uri(link.href); if (uri.query.action === 'rollback') processLink(link, uri.query.title, uri.query.token, uri.query.from, uri.query.bot && true); } catch (e) { /* swallow */ } }

function makeRestoreLink(oldid, uname) { var link = document.createElement('a'); var span = document.createElement('span'); link.href = mw.config.get('wgScript') + '?action=edit&oldid=' + oldid;

function doRestore { function showError(action, code, result) { var cnode = document.createElement('code'); cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; case 'edit-failure': cnode.textContent = result.edit.code; cnode.title = 'Edit error: ' + result.edit.info; break; default: cnode.title = result.error.info; }

var retryLink = document.createElement('a'); retryLink.href = link.href; retryLink.textContent = 'retry'; retryLink.addEventListener('click', function (ev) {				ev.preventDefault;				doRestore;			}, false);

span.textContent = ''; span.appendChild(document.createTextNode('error: ')); span.appendChild(cnode); span.appendChild(document.createTextNode(' ('));			span.appendChild(retryLink);			span.appendChild(document.createTextNode(')')); }

var summary = prompt('Edit summary for this reversion:', 'Restored revision ' + oldid + ' by User:' + uname + ''); if (summary === null) return;

span.textContent = 'grabbing oldid'; if (link.parentNode) { link.parentNode.insertBefore(span, link); link.parentNode.removeChild(link); }

api.get({			action: 'query',			pageids: mw.config.get('wgArticleId'),			prop: 'revisions',			rvstartid: oldid,			rvlimit: 1,			rvprop: 'content'		}).then(function (result, xhr) {			console.info(result);			var starttimestamp = (new Date(xhr.getResponseHeader('Date'))).toISOString; // XXX: acceptable?			var content = result.query.pages[mw.config.get('wgArticleId')].revisions[0]['*'];

span.textContent = 'grabbing latest revision'; api.get({				action: 'query',				pageids: mw.config.get('wgArticleId'),				prop: 'revisions',				rvlimit: 1,				rvprop: 'ids|timestamp'			}).then(function (result) {				console.info(result);				var basetimestamp = result.query.pages[mw.config.get('wgArticleId')].revisions[0].timestamp;				if (result.query.pages[mw.config.get('wgArticleId')].revisions[0].revid === Number(oldid)) {					span.textContent = 'this is already the latest revision';					return;				}

span.textContent = 'reverting'; api.post({					action: 'edit',					pageid: mw.config.get('wgArticleId'),					token: mw.user.tokens.get('csrfToken'),					basetimestamp: basetimestamp,					starttimestamp: starttimestamp,					nocreate: '1',					text: content,					summary: summary				}).then(function (result) {					if (result.edit.result === 'Success') {						span.textContent = 'done';					} else {						showError('saving', 'edit-failure', result);					}				}, function (code, result) {					showError('saving', code, result);				}); }, function (code, result) { showError('grabbing latest revision data', code, result); });		}, function (code, result) {			showError('grabbing old revision text', code, result);		}); }

link.addEventListener('click', function (ev) {		ev.preventDefault;		doRestore;	}, false);

return link; }

// are we viewing an old revision? var revnav = document.getElementById('mw-revision-nav'); if (revnav) { var uname = document.getElementById('mw-revision-info').getElementsByClassName('mw-userlink')[0].textContent; var oldid = mw.config.get('wgRevisionId'); // XXX: suppress if this is the latest revid

var link = makeRestoreLink(oldid, uname); link.textContent = 'restore this version';

revnav.appendChild(document.createTextNode(' ('));	revnav.appendChild(link);	revnav.appendChild(document.createTextNode(')')); return; }

// intentionally not enabled on history pages; // I want the user to see to what version they are reverting // either directly or at least a diff // may be changed on request, though

function addRestoreLink(titlenode) { if (!titlenode) return;

var titlelinks = titlenode.getElementsByTagName('a'); var userlink = titlenode.parentNode.getElementsByClassName('mw-userlink')[0]; var uname = userlink.textContent; var uri = new mw.Uri(titlelinks[0].href); // XXX: suppress for latest revid var rlink = makeRestoreLink(uri.query.oldid, userlink.textContent); rlink.textContent = 'restore'; titlelinks[1].parentNode.insertBefore(rlink, titlelinks[1].nextSibling); titlelinks[1].parentNode.insertBefore(document.createTextNode(' | '), titlelinks[1].nextSibling); }

// are we viewing a diff? var ot = document.getElementById('mw-diff-otitle1'); var nt = document.getElementById('mw-diff-ntitle1'); var ri = document.getElementById('mw-revision-info'); if ((nt || ot) && mw.config.get('wgArticleId')) { addRestoreLink(ot); addRestoreLink(nt); } else if (ri && (mw.config.get('wgRevisionId') !== mw.config.get('wgCurRevisionId'))) { var userlink = ri.getElementsByClassName('mw-userlink')[0]; var rlink = makeRestoreLink(mw.config.get('wgRevisionId'), userlink.textContent); rlink.textContent = 'restore'; var fh = document.getElementById('firstHeading'); var span = document.createElement('span'); span.className = 'mw-editsection'; span.appendChild(document.createTextNode('[')); span.appendChild(rlink); span.appendChild(document.createTextNode(']')); fh.appendChild(span); }

});

});