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 getRevisionAuthor(revid) {
var params = {
action: 'query',
prop: 'revisions',
titles: mw.config.get("wgPageName"),
rvprop: "user",
rvstartid: revid,
rvlimit: '1',
format: 'json'
},
api = new mw.Api();
const data = await api.get(params);
return Object.values(data.query.pages)[0].revisions[0].user;
}
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 author = await getRevisionAuthor(revid);
var params, api;
params = {
action: 'edit',
title: page,
undo: cur,
undoafter: revid,
summary: `Restoring revision ${revid} by [[Special:Contributions/${author}|${author}]]${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);
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(rzn, pageTitle);
}
});
current.appendChild(tmpNode);
});
}
function addVandalLinks(selector) {
var list = $("#bodyContent").find(selector);
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(' '));
tmpNode = revVandNode.cloneNode(true);
var pageTitle = new URLSearchParams(new URL("http:" + mw.config.get("wgServer") + href).search).get("title");
$(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() {
(async () => {
if(await waitForPreferences()) {
switch (mw.config.get('wgCanonicalSpecialPageName')) {
case "Contributions":
if(!Luna.getPref("luna-hide-rb-ct"))
addRollbackLinks("ul li:has(span.mw-uctop)");
if(!Luna.getPref("luna-hide-vand-ct"))
addVandalLinks("ul li:has(span.mw-uctop)");
if(!Luna.getPref("luna-hide-res-ct"))
addRestoreLinks("ul.mw-contributions-list li:not(:has(span.mw-uctop))");
break;
case "Recentchanges":
if(!Luna.getPref("luna-hide-rb-rc"))
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-vand-rc"))
addVandalLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-res-rc"))
addRestoreLinks(".mw-changeslist :not(.mw-changeslist-last).mw-changeslist-src-mw-edit");
break;
case "Recentchangeslinked":
if(!Luna.getPref("luna-hide-rb-rcl"))
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-vand-rcl"))
addVandalLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-res-rcl"))
addRestoreLinks(".mw-changeslist :not(.mw-changeslist-last).mw-changeslist-src-mw-edit");
break;
case "Watchlist":
if(!Luna.getPref("luna-hide-rb-wl"))
addRollbackLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-vand-wl"))
addVandalLinks(".mw-changeslist .mw-changeslist-last.mw-changeslist-src-mw-edit");
if(!Luna.getPref("luna-hide-res-wl"))
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") {
if(!Luna.getPref("luna-hide-rb-ht"))
addRollbackLinks("#pagehistory li:first");
if(!Luna.getPref("luna-hide-vand-ht"))
addVandalLinks("#pagehistory li:first");
if(!Luna.getPref("luna-hide-res-ht"))
addRestoreLinks("#pagehistory li:not(:first)");
}
else if (mw.config.get('wgDiffOldId') && (mw.config.get('wgDiffOldId') !== mw.config.get('wgDiffNewId'))) {
if(!Luna.getPref("luna-hide-rb-df"))
addRollbackLinks("#mw-diff-ntitle2");
if(!Luna.getPref("luna-hide-vand-df"))
addVandalLinks("#mw-diff-ntitle2");
if(!Luna.getPref("luna-hide-res-df"))
addRestoreLinks("#mw-diff-otitle2");
}
else if ($("#mw-revision-info")) {
if(!Luna.getPref("luna-hide-res-oi"))
addRestoreLinks("#mw-revision-info");
}
}
}
}
else {
console.error("Luna: Preferences never fully loaded.");
}
})();
}
if (mw.config.get("wgCanonicalSpecialPageName") == "Recentchanges" || mw.config.get("wgCanonicalSpecialPageName") == "Recentchangeslinked" || 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"));
});
}