// This, that and the other's mass tagging script
// July 2011
// To make it work, use a JavaScript console to call masstag() or massremove()
// Script depends on the following lines having been included in skin.js previously:
// importStylesheet("MediaWiki:Gadget-morebits.css");
// importScript("MediaWiki:Gadget-morebits.js");
function masstag() {
if (mw.config.get("wgUserName") !== "TTObot") {
alert("The masstag script may only be run under the User:TTObot account. If you wish to use this script to perform mass tagging tasks, please contact User:This, that and the other.");
return;
}
mw.loader.using(['jquery.ui'], function() {
var dialog = new Morebits.simpleWindow(500, 400);
dialog.setTitle("Mass tagging");
var form = new Morebits.quickForm(masstag.callback.initialTag);
form.append({ type: 'div', label: [ Morebits.htmlNode("strong", "Notice: BAG approval applies to mass XfD tagging operations only.", "red") ]});
form.append({ type: 'textarea', name: 'list', label: 'List of pages (one per line)' });
form.append({ type: 'input', name: 'tag', label: 'Text to prepend: ', size: 60 });
form.append({ type: 'input', name: 'summary', label: 'Edit summary: ', size: 60 });
form.append({ type: 'checkbox', list: [
{ name: 'skipMissing', label: 'Skip non-existent pages', checked: true },
{ name: 'skipCsd', label: 'Skip speedy deletion candidates', checked: true },
{ name: 'skipEdited', label: 'Skip pages with more than one revision' },
{ name: 'skipBig', label: 'Skip pages bigger than the size threshold below' }
]});
form.append({ type: 'input', name: 'bigThreshold', label: 'Size threshold (bytes): ', size: 5 });
form.append({ type: 'submit' });
dialog.setContent(form.render());
dialog.display();
});
}
function massremove() {
if (mw.config.get("wgUserName") !== "TTObot") {
alert("The masstag script may only be run under the User:TTObot account. If you wish to use this script to perform mass tagging tasks, please contact User:This, that and the other.");
return;
}
mw.loader.using(['jquery.ui'], function() {
var dialog = new Morebits.simpleWindow(500, 400);
dialog.setTitle("Mass tag removal");
var form = new Morebits.quickForm(masstag.callback.initialRemove);
form.append({ type: 'div', label: [ Morebits.htmlNode("strong", "Notice: BAG approval applies to mass removal of XfD tags only.", "red") ]});
form.append({ type: 'textarea', name: 'list', label: 'List of pages (one per line)' });
form.append({ type: 'input', name: 'regex', label: 'Regex to remove (case insens.): ', size: 60 });
form.append({ type: 'div', label: "^(<noinclude>)?\\s*\\{\\{tfd[^\\}]*\\}\\}\\s*(</noinclude>)?\\s*" });
form.append({ type: 'input', name: 'summary', label: 'Edit summary: ', size: 60 });
form.append({ type: 'checkbox', list: [
{ name: 'skipCsd', label: 'Skip speedy deletion candidates', checked: true }
]});
form.append({ type: 'submit' });
dialog.setContent(form.render());
dialog.display();
});
}
masstag.callback = {};
masstag.callback.initialTag = function(e) {
var form = e.target;
if (!form.tag.value || !form.summary.value) {
alert("Tag text and edit summary are compulsory");
return;
}
var params = {
massremove: false,
tag: form.tag.value,
list: form.list.value.trimRight().split("\n"),
summary: form.summary.value,
skipMissing: form.skipMissing.checked,
skipCsd: form.skipCsd.checked,
skipEdited: form.skipEdited.checked,
skipBig: form.skipBig.checked,
bigThreshold: parseInt(form.bigThreshold.value, 10),
resultPages: [],
resultInitialContributors: [],
form: form
};
Morebits.simpleWindow.setButtonsEnabled(false);
form.textContent = "";
var div = document.createElement("div");
div.style.height = "8em";
div.style.overflow = "auto";
div.style.padding = "4px";
div.style.border = "1px black solid";
div.style.background = "white";
form.appendChild(div);
Morebits.status.init(div);
masstag.callback.beginTag(params);
};
masstag.callback.initialRemove = function(e) {
var form = e.target;
if (!form.regex.value || !form.summary.value) {
alert("Removal regex and edit summary are compulsory");
return;
}
var params = {
massremove: true,
regex: form.regex.value,
list: form.list.value.trimRight().split("\n"),
summary: form.summary.value,
skipMissing: true,
skipCsd: form.skipCsd.checked,
skipEdited: false,
skipBig: false,
resultPages: [],
resultInitialContributors: [],
form: form
};
Morebits.simpleWindow.setButtonsEnabled(false);
form.textContent = "";
var div = document.createElement("div");
div.style.height = "8em";
div.style.overflow = "auto";
div.style.padding = "4px";
div.style.border = "1px black solid";
div.style.background = "white";
form.appendChild(div);
Morebits.status.init(div);
masstag.callback.beginTag(params);
};
masstag.callback.beginTag = function(params) {
if (params.list.length === 0) {
masstag.callback.finishUp(params);
return;
}
var query = {
action: 'query',
prop: 'info|revisions',
rvprop: 'user|timestamp|flags|content',
titles: params.list[0]
};
var api = new Morebits.wiki.api("Fetching page data", query, masstag.callback.processTag, new Status("Loading " + params.list[0]));
api.params = params;
window.setTimeout(function() { api.post(); }, 6000); // throttling to prevent overly frequent editing
};
masstag.callback.processTag = function(apiobj) {
var params = apiobj.params;
var $xml = $(apiobj.responseXML);
var $page = $xml.find("page");
if ($page.attr("missing") === "" && params.skipMissing) {
params.resultPages.push({ title: params.list[0], result: "Page does not exist", red: true });
} else {
if ($page.attr("redirect") === "") {
params.resultPages.push({ title: params.list[0], result: "Page is a redirect", red: true });
} else {
if ($xml.find("rev").text().indexOf("{{db") !== -1 && params.skipCsd) {
params.resultPages.push({ title: params.list[0], result: "Page may be a speedy deletion candidate", red: true });
} else {
if ($page.attr("new") !== "" && params.skipEdited) {
params.resultPages.push({ title: params.list[0], result: "Page has more than one revision", red: true });
} else {
if (params.skipBig && $page.attr("length") > params.bigThreshold) {
params.resultPages.push({ title: params.list[0], result: "Page is too long (" + $page.attr("length") + " bytes)", red: true });
} else {
// do it
var page = new Morebits.wiki.page(params.list[0]);
var editsuccess = function(apiresult) {
page.getStatusElement().info("Done");
params.resultPages.push({ title: params.oldtitle, result: "Success" });
masstag.callback.beginTag(params);
};
var editerror = function(apiresult) {
page.getStatusElement().error(apiresult.errorText);
params.resultPages.push({ title: params.oldtitle, result: "API error (" + apiresult.errorText + ")", red: true });
masstag.callback.beginTag(params);
};
if (params.massremove) {
page.load(function(pageresult) {
var text = pageresult.getPageText();
var newText = text.replace(new RegExp(params.regex, "i"), "");
if (text === newText) {
page.getStatusElement().warn("Regex did not match");
params.resultPages.push({ title: params.list[0], result: "Regex did not match; page skipped" });
params.list = params.list.slice(1);
masstag.callback.beginTag(params);
return;
}
page.setPageText(newText);
page.setEditSummary(params.summary);
page.setCreateOption("nocreate");
params.oldtitle = params.list[0];
params.list = params.list.slice(1);
page.save(editsuccess, editerror);
});
} else {
page.setPrependText(params.tag);
page.setEditSummary(params.summary);
page.setCreateOption(params.skipMissing ? "nocreate" : "recreate");
params.oldtitle = params.list[0];
params.list = params.list.slice(1);
page.prepend(editsuccess, editerror);
if ($page.attr("missing") !== "") {
page.lookupCreator(function(pageobj) {
if (params.resultInitialContributors.indexOf(pageobj.getCreator()) === -1) {
params.resultInitialContributors.push(pageobj.getCreator());
}
});
}
}
return;
}
}
}
}
}
params.list = params.list.slice(1);
masstag.callback.beginTag(apiobj.params);
};
masstag.callback.finishUp = function(params) {
var success = [], failed = [];
params.form.appendChild(Morebits.htmlNode("h3", "1. Results"));
$.each(params.resultPages, function(k, v) {
var div = Morebits.htmlNode("div", "", v.red ? "red" : null);
var a = Morebits.htmlNode("a", v.title);
a.href = "/wiki/" + v.title;
div.appendChild(a);
div.appendChild(document.createTextNode(": " + v.result));
params.form.appendChild(div);
(v.red ? failed : success).push(v.title);
});
if (!params.massremove) {
params.form.appendChild(Morebits.htmlNode("h3", "2. Initial contributors"));
$.each(params.resultInitialContributors, function(k, v) {
params.form.appendChild(Morebits.htmlNode("div", v));
});
}
params.form.appendChild(Morebits.htmlNode("h3", (params.massremove ? "2" : "3") + "a. Summary: successful pages (" + success.length + " total)"));
$.each(success, function(k, v) {
params.form.appendChild(Morebits.htmlNode("div", v));
});
params.form.appendChild(Morebits.htmlNode("h3", (params.massremove ? "2" : "3") + "b. Summary: failed pages (" + failed.length + " total)"));
$.each(failed, function(k, v) {
params.form.appendChild(Morebits.htmlNode("div", v));
});
};