User:JJPMaster/rollback.js
Appearance
Note: After saving, changes may not occur immediately. Click here to learn how to bypass your browser's cache.
- Mozilla / Firefox / Safari: hold down Shift while clicking Reload, or press Ctrl-Shift-R (Cmd-Shift-R on Apple Mac);
- Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5;
- Konqueror: simply click the Reload button, or press F5;
- Opera users may need to completely clear their cache in Tools→Preferences.
Warning: Malicious code can compromise your account. Page preview will cause your web browser to execute this page's content as code under some skins, including Monobook. If you have any questions about any code you plan to add, you can ask at the appropriate reading room. |
Documentation for this user script can be added at User:JJPMaster/rollback. |
async function getNonRolledBackEdit(page) {
try {
var params = {
action: 'query',
prop: 'revisions',
rvprop: "user|ids|comment",
titles: page,
rvlimit: 'max',
format: 'json'
},
api = new mw.Api();
const data = await api.get( params );
var pages = data.query.pages,
p;
for ( p in pages ) {
var lastEditor = Object.values(pages)[0].revisions[0].user;
var otherIndex = pages[ p ].revisions.findIndex(i => i.user != lastEditor) - 1;
var lastEditByOther = pages[ p ].revisions[otherIndex + 1] ? pages[ p ].revisions[otherIndex + 1].revid : undefined;
var lastEdits = pages[ p ].revisions.slice(0, otherIndex + 1);
var numberOfEdits = lastEdits.length;
var lastEdit = Object.values(pages)[0].revisions[0].revid;
return [lastEditor, lastEditByOther, lastEdit, numberOfEdits];
}
}
catch {
alert("Luna: It appears that only one user has edited this page. Rollback cannot be applied.");
return;
}
}
async function doUndo(reason, from, to, page = mw.config.get("wgPageName")) {
var anyOtherEdits = (await getNonRolledBackEdit(page))[1];
var lastEdit = await getNonRolledBackEdit(page);
if (typeof anyOtherEdits != "undefined") {
var params = {
action: 'edit',
title: page,
undo: from,
undoafter: to,
summary: `Reverting ${lastEdit[3]} edit${lastEdit[3] == 1 ? "" : "s"} by [[Special:Contributions/${lastEdit[0]}|${lastEdit[0]}]]${reason ? ": " + reason : ""}`,
tags: "Luna",
format: 'json'
},
api = new mw.Api();
const data = await api.postWithToken( "csrf", params );
console.log(data);
}
}
async function doRollback(reason, page = mw.config.get("wgPageName")) {
var lastEdit = await getNonRolledBackEdit(page);
if(myRights.indexOf("rollback") < 0) {
try {
await doUndo(reason, lastEdit[2], lastEdit[1], page);
mw.notify("Luna: Rollback complete.");
}
catch (e) {
mw.notify("Luna: Rollback failed. See the console for details.");
console.error(e);
}
}
else {
try {
params = {
action: 'rollback',
title: page,
user: lastEdit[0],
summary: `Rollback ${lastEdit[3]} edit${lastEdit[3] == 1 ? "" : "s"} by [[Special:Contributions/${lastEdit[0]}|${lastEdit[0]}]]${reason ? ": " + reason : ""}`,
tags: "Luna",
format: 'json'
},
api = new mw.Api();
const data = await api.postWithToken( "rollback", params );
mw.notify("Luna: Rollback complete.");
console.log(data);
}
catch {
try {
await doUndo(reason, lastEdit[2], lastEdit[1], page);
mw.notify("Luna: Rollback complete.");
}
catch (e) {
mw.notify("Luna: Rollback failed. See the console for details.");
console.error(e);
}
}
}
}
async function doRestore(reason, revid, page = mw.config.get("wgPageName")) {
var cur = (await getNonRolledBackEdit(page))[2];
var params, api;
params = {
action: 'edit',
title: page,
undo: cur,
undoafter: revid,
summary: `Restoring revision ${revid}${reason ? ": " + reason : ""}`,
tags: "Luna",
format: 'json'
},
api = new mw.Api();
try {
const data = await api.postWithToken( "csrf", params );
mw.notify("Luna: Reversion complete.");
console.log(data);
}
catch (e) {
mw.notify("Luna: Reversion failed. See the console for details.");
console.error(e);
}
}
var spanTag = function( myClass, content ) {
var span = document.createElement( 'span' );
$(span).addClass(myClass);
span.appendChild( document.createTextNode( content ) );
return span;
};
function addRollbackLinks(selector) {
var list = $("#bodyContent").find(selector);
var revNode = document.createElement('strong');
var revLink = document.createElement('a');
revLink.style.textDecoration = "none";
revLink.appendChild( spanTag( "luna-rollback-link", 'rollback' ) );
revNode.appendChild(revLink);
var revVandNode = document.createElement('strong');
var revVandLink = document.createElement('a');
revVandLink.style.textDecoration = "none";
revVandLink.appendChild( spanTag( "luna-vand-link", 'vandalism' ) );
revVandNode.appendChild(revVandLink);
list.each(function(key, current) {
var href = $(current).find('.mw-changeslist-diff').attr('href') ? $(current).find('.mw-changeslist-diff').attr('href') : `${mw.config.get("wgScript")}?title=${mw.config.get("wgPageName")}`;
current.appendChild(document.createTextNode(' '));
var tmpNode = revNode.cloneNode(true);
var pageTitle = new URLSearchParams(new URL("http:" + mw.config.get("wgServer") + href).search).get("title");
$(tmpNode).click(() => {
var rzn = prompt("Why would you like to revert this edit?");
if (rzn != null) {
doRollback(prompt("Why would you like to revert this edit?"), pageTitle);
}
});
current.appendChild(tmpNode);
current.appendChild(document.createTextNode(' '));
tmpNode = revVandNode.cloneNode(true);
$(tmpNode).click(() => doRollback("Vandalism", pageTitle));
current.appendChild(tmpNode);
});
}
function addRestoreLinks(selector) {
var list = $("#bodyContent").find(selector);
var resNode = document.createElement('strong');
var resLink = document.createElement('a');
resLink.style.textDecoration = "none";
resLink.appendChild( spanTag( "luna-restore-link", 'restore' ) );
resNode.appendChild(resLink);
list.each(function(key, current) {
var href = $(current).find('.mw-changeslist-diff').attr('href') ? $(current).find('.mw-changeslist-diff').attr('href') : `${mw.config.get("wgScript")}?title=${mw.config.get("wgPageName")}`;
var oldid = !!$(current).data('mw-revid') ? $(current).data('mw-revid') : $(current).find('[data-mw-revid]').data('mw-revid');
current.appendChild(document.createTextNode(' '));
var tmpNode = resNode.cloneNode(true);
var pageTitle = new URLSearchParams(new URL("http:" + mw.config.get("wgServer") + href).search).get("title");
$(tmpNode).click(() => {
var rzn = prompt("Why would you like to restore this version?");
if (rzn != null) {
doRestore(rzn, oldid, pageTitle);
}
});
current.appendChild(tmpNode);
});
}
function addAppropriateLinks() {
switch (mw.config.get('wgCanonicalSpecialPageName')) {
case "Contributions":
addRollbackLinks("ul li:has(span.mw-uctop)");
addRestoreLinks("ul.mw-contributions-list li:not(:has(span.mw-uctop))");
break;
case "Recentchanges":
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
addRestoreLinks(".mw-changeslist :not(.mw-changeslist-last).mw-changeslist-src-mw-edit");
break;
case "Recentchangeslinked":
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
addRestoreLinks(".mw-changeslist :not(.mw-changeslist-last).mw-changeslist-src-mw-edit");
break;
case "Watchlist":
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
addRestoreLinks(".mw-changeslist :not(.mw-changeslist-last).mw-changeslist-src-mw-edit");
break;
default:
if (mw.config.get("wgIsProbablyEditable")) {
if (mw.config.get("wgAction") == "history") {
addRollbackLinks("#pagehistory li:first");
addRestoreLinks("#pagehistory li:not(:first)");
}
else if (mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId'))) {
addRollbackLinks("#mw-diff-ntitle2");
addRestoreLinks("#mw-diff-otitle2");
}
else if ($("#mw-revision-info")) {
addRestoreLinks("#mw-revision-info");
}
}
}
}
if (mw.config.get("wgCanonicalSpecialPageName") == "Recentchanges" || mw.config.get("wgCanonicalSpecialPageName") == "Relatedchanges" || mw.config.get("wgCanonicalSpecialPageName") == "Watchlist") {
mw.hook('wikipage.content').add((item) => {
if (item.is('div')) {
addAppropriateLinks();
}
});
}
else if (mw.config.get('wgDiffNewId') || mw.config.get('wgDiffOldId')) {
mw.hook('wikipage.diff').add(() => {
addAppropriateLinks();
});
}
else {
addAppropriateLinks();
}
if (mw.config.get('wgIsProbablyEditable') && mw.config.get('wgArticleId') > 0) {
$(mw.util.addPortletLink('luna-actions', '#', 'Quick rollback', 'luna-qrb', 'Quickly revert all edits made by the last editor')).click(() => {
doRollback(prompt("Why would you like to revert this edit?"), mw.config.get("wgPageName"));
});
}