MediaWiki:Gadget-FastRollback.js
Jump to navigation
Jump to search
Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.
- Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
- Konqueror and Chrome: click Reload or press F5;
- Opera: clear the cache in Tools → Preferences;
- Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.
- The following documentation is located at MediaWiki:Gadget-FastRollback.js/documentation. [edit]
- This script is a part of the
FastRollback
gadget (edit definitions)- Description (edit): FastRollback: use the API to rollback changes without reloading the page, while allowing to input an edit summary
- Useful links: subpage list • links • redirects
See also: Special:Gadgets.
// {{documentation}}
/*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 [[Special:Contributions/' + user + '|' + user + ']]. If you think this rollback is in error, please leave a message on my [[User talk:' + mw.config.get('wgUserName') + '|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 [[Special:Permalink/' + oldid + '|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);
}
});
})();