User:Nihiltres/nothingthree.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:Nihiltres/nothingthree and an accompanying .css page at User:Nihiltres/nothingthree.css. |
/*
This nothingthree library is a collection of functions that are probably useful. They're created
or collected (as noted) by Nihiltres for his use on Wikipedia, and you can use them as you see fit.
There is no guarantee that they work; Nihiltres only tests them under Safari on Mac OS, though will
occasionally correct or minimize bugs that occur on other browsers. Enjoy! Note the importScript
activator at the bottom. You'll need a user nothingthree-config.js file as well as importing this.
*/
/*global nothingthree: true, importScript, importStylesheetURI, jQuery, mw */
mw.loader.using(["mediawiki.util", "oojs-ui.styles.icons-editing-list"], function () {
window.nothingthree = {
settings: { //Holds nothingthree globals and defaults
topsHidden: false, //Tops start out shown, so this has to be false to start.
pageRCloaded: false, //Are revisions loaded? Has to be false to start.
specificAutoWatchNamespaces: [1, 2, 3, 8, 9], //Default auto-watch namespaces
monthlist: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], //default names for months, allows for basic i18n
dateOrder: mw.user.options.get("date") //Default date order. Iff "mdy", nothingthree.util.stringifyDate's output changes slightly.
}, //end settings
util: {
linkFix: function (targetId, replacementText) { // Tab name fixer; drills down to bottom first-child of targeted ID, then replaces its text.
var drilldown = jQuery("#".concat(targetId));
while (drilldown.children().length > 0) {
drilldown = drilldown.children().first();
}
drilldown.text(replacementText); //jQuery.text() natively escapes HTML, AFAICT
}, //end linkfix
isMobile: function () { //really rather basic mobile-device detection here, but can be improved as needed. Mostly useful for tidy code.
return !!(navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || (navigator.userAgent.match(/Android/i)));
}, //end isMobile
parseDate: function (dateString) { //Turns the date strings that the MW API likes to use (e.g. "2011-04-06T22:24:52Z") into JS dates. It assumes everything's in UTC, and expects a string for input.
var dateParts = /^\s*(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z\s*$/.exec(dateString);
if (dateParts) {
return new Date(Date.UTC(+dateParts[1], +dateParts[2] - 1, +dateParts[3], +dateParts[4], +dateParts[5], +dateParts[6]));
}
return new Date(NaN); //In case dateString isn't what we're expecting…
}, //end parseDate
stringifyDate: function (theDate) { //Turns a date object into a pretty UTC output string.
var dateParts, timeParts;
timeParts = ("0" + theDate.getUTCHours()).slice(-2) + ":" + ("0" + theDate.getUTCMinutes()).slice(-2);
if (nothingthree.settings.dateOrder === "mdy") {
dateParts = nothingthree.settings.monthlist[theDate.getUTCMonth()] + " " + theDate.getUTCDate() + ", " + theDate.getUTCFullYear();
} else {
dateParts = theDate.getUTCDate() + " " + nothingthree.settings.monthlist[theDate.getUTCMonth()] + " " + theDate.getUTCFullYear();
}
return (timeParts + ", " + dateParts + " (UTC)");
}, //end stringifyDate
formatInt: function (num) { //Formats integers with commas
var numString = num.toString();
while (/(\d+)(\d{3})/.test(numString)) {
numString = numString.replace(/(\d+)(\d{3})/, "$1,$2");
}
return numString;
}, //end formatInt
addPortletLink: function (obj) {
var $item, $portlet, $list;
if (!obj || !obj.portlet || !obj.portlet.jquery || !obj.portlet.length || !obj.text || (!obj.href && !obj.function)) {
return null;
}
$item = jQuery("<li><a></li>").attr("id", (obj.id || null));
$item.addClass("mw-list-item");
$item.children().text(obj.text).attr({
href: (obj.href || "#"),
title: (obj.tooltip || null),
accesskey: (obj.accesskey || null)
}).updateTooltipAccessKeys();
$portlet = obj.portlet.first();
//if ($portlet.hasClass("vectorTabs")) {
$item.find("a").wrapInner("<span>");
//}
if ($portlet.hasClass("vector-menu-tabs")) {
$item.addClass("vector-tab-noicon");
}
$list = $portlet.find("ul").first();
if ($list.length === 0) {
$list = jQuery("<ul>");
if ($portlet.find('div:first').length === 0) {
$portlet.append($list);
} else {
$portlet.find('div').last().append($list);
}
if ($portlet.find("ul") === 0) {
return null;
}
}
$portlet.removeClass("emptyPortlet");
if (obj.next && obj.next.jquery && $list.find(obj.next.first()).length !== 0) {
$item.insertBefore(obj.next.first());
} else if (obj.prev && obj.prev.jquery && $list.find(obj.prev.first()).length !== 0) {
$item.insertAfter(obj.prev.first());
} else {
$item.appendTo($list);
}
return $item.click((typeof obj.function === "function") ? obj.function : null);
} //end addPortletLink
}, //end util
tabAdd: { //Collection of independent tab-addition routines.
log: function () { //Adds a link to the log of actions performed by the user. Mainly useful for administrators.
if (jQuery("#pt-log").length > 0) {
return;
}
nothingthree.util.addPortletLink({
portlet: jQuery("#p-personal"),
href: mw.util.getUrl("Special:Log", {user: mw.config.get("wgUserName")}),
text: "Log",
id: "pt-log",
tooltip: "Log of your non-edit actions",
next: jQuery("#pt-mycontris")
});
if (jQuery("#p-personal .mw-ui-icon").length > 0) {
jQuery("#pt-log a").prepend($("<span class=\"mw-ui-icon mw-ui-icon-listBullet\">"))
//userContributions is closer to what we want, but to differentiate
//the icons a bit, we'll use listBullet
}
//jQuery("#pt-log").addClass("collapsible"); not necessary on p-personal links
if (mw.config.get("wgPageName") === "Special:Log" && jQuery("#mw-input-user input").val() === mw.config.get("wgUserName")) {
jQuery("#pt-log").addClass("active");
}
}, //end log
sandbox: function () { //Used to add a sandbox link; now that that's present by default, this function normalizes the link to reflect the function's old target.
jQuery("#pt-sandbox a").first().attr("href", mw.util.getUrl("User:".concat(mw.config.get("wgUserName"), "/Sandbox")));
}, //end sandbox
purge: function () { //Adds a link to purge the current page.
if (jQuery("#ca-purge").length > 0 || mw.config.get("wgCanonicalNamespace") === "Special") {
return;
}
nothingthree.util.addPortletLink({
portlet: jQuery("#p-cactions"),
href: mw.util.getUrl(mw.config.get("wgPageName"), {"action": "purge"}),
text: "Purge",
id: "ca-purge",
tooltip: "Purge the server cache of this page",
next: jQuery("#p-cactions #ca-unwatch, #p-cactions #ca-watch")
});
} //end purge
}, //end tabAdd
specificAutoWatch: function () { //Automatically checks the "Watch this page" button when editing MediaWiki-namespace pages.
if (mw.config.get("wgAction") === "edit" && nothingthree.settings.specificAutoWatchNamespaces.indexOf(mw.config.get("wgNamespaceNumber")) !== -1) {
jQuery("#wpWatchthis").prop("checked", true);
}
}, //end watchMediawikiSpaceEdits
tabMove: { //Tab-moving routines, and custom bits that make use of them.
core: function (obj) { //Now slightly less ugly! Does the actual moving part. Takes an object loaded like so: {id: "foo", followingElement: "bar", targetParent: "baz"}. The latter two arguments within that object are optional.
var $id, $followingElement, $targetParent;
$id = (obj.id ? jQuery("#".concat(obj.id)) : []);
$followingElement = (obj.followingElement ? jQuery("#".concat(obj.followingElement)) : []);
$targetParent = (obj.targetParent ? jQuery("#".concat(obj.targetParent)) : jQuery((obj.followingElement ? $followingElement.parent() : [])));
if ($id.length !== 1 || $targetParent.length !== 1) {
return;
}
if ($id.closest("ul").children().length === 1) {
$id.closest("div:not(.menu)").addClass("emptyPortlet");
}
$targetParent.removeClass("emptyPortlet");
//if (!$id.children().first().is("span")) {
// $id.wrapInner("<span></span>");
//}
if ($targetParent.hasClass("vector-menu-tabs")) {
$id.addClass("vector-tab-noicon");
}
if ($targetParent.attr("id") === "p-views") { //Necessary until better collapsibleTabs support is implemented
$id.addClass("collapsible");
}
if ($followingElement.length > 0) {
$id.detach().insertBefore($followingElement.first());
} else {
$id.detach().appendTo($targetParent.find("ul").first());
}
//It'd be nice to properly update the collapsibleTabs data RIGHT HERE, but for now, that's not implemented.
//jQuery.collapsibleTabs.handleResize(); //Force an update regardless
}, //end core
protection: function () { //if the page is protected, show the unprotect button; serves also as an indicator for protection, indicating the value in the title.
var restrictionStringArray = [];
if (jQuery("#ca-unprotect").length === 0) { //There are more thorough checks, but this seems stable enough…
return;
}
nothingthree.tabMove.core({"id": "ca-unprotect", "followingElement": "ca-history", "targetParent": "p-views"});
if (mw.config.get("wgRestrictionEdit")) {
restrictionStringArray.push("edit: [".concat(mw.config.get("wgRestrictionEdit").join(", "), "]"));
}
if (mw.config.get("wgRestrictionMove")) {
restrictionStringArray.push("move: [".concat(mw.config.get("wgRestrictionMove").join(", "), "]"));
}
if (mw.config.get("wgRestrictionCreate")) {
restrictionStringArray.push("create: [".concat(mw.config.get("wgRestrictionCreate").join(", "), "]"));
}
jQuery("#ca-unprotect a").attr("title", "Change protection of this page (".concat(restrictionStringArray.join(", "), ")"));
}, //end protection
deletion: function () { //If the page contains a deletion template or a redlinked redirect, or is an empty proposed deletion category, move out the delete tab. In the redirect or category cases, give an automatic, useful deletion summary.
var cada = jQuery("#ca-delete a"),
moveObj = {id: "ca-delete", followingElement: "ca-history", targetParent: "p-views"};
if (jQuery("[class*=mbox-speedy], [class*=mbox-delete]").length >= 1) { //if there's a deletion template present…
nothingthree.tabMove.core(moveObj);
}
if ((mw.config.get("wgPageName").indexOf("Category:Proposed_deletion_as_of") !== -1) && (jQuery("#mw-category-empty").length !== 0)) { //if it's an empty proposed deletion category…
nothingthree.tabMove.core(moveObj);
if (cada.length !== 0) {
cada.first().attr("href", cada.first().attr("href").concat("&wpReason=%5B%5BWP%3ACSD%23G6%7CG6%5D%5D%3A%20Empty%20proposed%20deletion%20category"));
}
}
if (jQuery(".redirectText a[href*='redlink=1']").length > 0) { //if it's a redlink redirect…
nothingthree.tabMove.core(moveObj);
if (cada.length !== 0) {
cada.first().attr("href", cada.first().attr("href").concat("&wpReason=%5B%5BWP%3ACSD%23G8%7CG8%5D%5D%3A%20Redirect%20to%20a%20deleted%20page"));
}
}
}, //end deletion
watch: function () { //This bit moves the watch tab back into the menu after removing its icon status.
jQuery("#ca-watch, #ca-unwatch").removeClass("icon");
nothingthree.tabMove.core({"id": jQuery("#ca-watch, #ca-unwatch").first().attr("id"), "targetParent": "p-cactions"});
}, //end watch
contribs: function () {
var user;
if (mw.config.get("wgCanonicalSpecialPageName") == "Contributions") {
user = mw.config.get("wgPageName").split("/")[1] || mw.util.getParamValue("target");
nothingthree.util.addPortletLink({
portlet: jQuery("#p-associated-pages"),
href: mw.util.getUrl("User:" + user),
text: "User page",
id: "ca-nstab-user",
tooltip: "View the user page",
next: jQuery("#ca-nstab-special")
});
nothingthree.util.addPortletLink({
portlet: jQuery("#p-associated-pages"),
href: mw.util.getUrl("User_talk:" + user),
text: "Talk",
id: "ca-talk",
tooltip: "Discussion about the content page",
next: jQuery("#ca-nstab-special")
});
nothingthree.util.linkFix("ca-nstab-special", "Contributions");
jQuery("#t-contributions").addClass("selected");
}
if (jQuery("#t-contributions").length === 1) {
nothingthree.tabMove.core({id: "t-contributions", targetParent: "p-associated-pages"});
jQuery("#t-contributions").attr("id", "ca-contributions");
nothingthree.util.linkFix("ca-contributions", "Contributions");
}
}
}, //end tabMove
sidebar: { //A collection of functions for playing with the sidebar, mostly to collapse or expand it.
toggle: function () { //Toggles between collapsed and expanded
jQuery("#mw-panel, #content, #head-base, #footer, #mw-head-base, #left-navigation").toggleClass("n3-sidebar-collapsed");
if (jQuery.cookie("sideBarCollapsed") === "collapsed") {
jQuery.cookie("sideBarCollapsed", "expanded", {path: "/"});
} else {
jQuery.cookie("sideBarCollapsed", "collapsed", {path: "/"}); //This isn't error-tolerant enough for my taste, but the likelihood that something else will change this value is low, so I haven't bothered to write more.
} //end if
}, //end toggle
toggleTab: function () { //Adds a tab to the menu to allow the collapsed status to be easily toggled.
if (jQuery("#ca-sidebar").length > 0) {
return;
}
nothingthree.util.addPortletLink({
portlet: jQuery("#p-cactions"),
function: nothingthree.sidebar.toggle,
text: "Toggle sidebar",
id: "ca-sidebar",
tooltip: "Hide or show the sidebar",
next: jQuery("#p-cactions #ca-purge, #p-cactions #ca-unwatch, #p-cactions #ca-watch")
});
if (mw.config.get("wgCanonicalNamespace") === "Special") {
nothingthree.tabMove.core({"id": "ca-sidebar", "targetParent": "p-views"});
} //end if
}, //end toggleTab
remember: function () { //Collapses the sidebar if it was previously collapsed.
if (jQuery.cookie("sideBarCollapsed") === "collapsed") {
nothingthree.sidebar.toggle();
} //end if
} //end remember
}, //end sidebar
tops: { //A collection of functions designed to allow the visibility of (top) edits on contribution pages to be toggled. Also included are edits where a later edit to the same page is (top).
hide: function () { //Hides (top) edits.
var title, topElsewhere;
topElsewhere = [];
jQuery(".mw-contributions-list li").each(function () {
title = jQuery(this).find(".mw-contributions-title").first().text();
if (jQuery(this).find(".mw-uctop").length > 0) {
topElsewhere.push(title);
}
if (topElsewhere.indexOf(title) !== -1) {
jQuery(this).addClass("n3-tops-faded");
}
});
nothingthree.settings.topsHidden = true;
}, //end hide
show: function () { //Shows (top) edits.
jQuery(".n3-tops-faded").removeClass("n3-tops-faded");
nothingthree.settings.topsHidden = false;
}, //end show
toggle: function () { //Toggles between hidden and shown based on the current value.
if (nothingthree.settings.topsHidden === true) {
nothingthree.tops.show();
} else {
nothingthree.tops.hide();
}
}, //end toggle
toggleTab: function () { //Adds a tab to the menu allowing the visibility of (top) edits to be toggled.
if (jQuery("body").hasClass("mw-special-Contributions") && jQuery("#ca-tops").length === 0) {
nothingthree.util.addPortletLink({
portlet: jQuery("#p-views"),
function: nothingthree.tops.toggle,
text: "Toggle (top) entries",
id: "ca-tops",
tooltip: "Hide or show the (top) entries",
next: jQuery("#ca-sidebar")
});
jQuery("#ca-tops").addClass("collapsible");
} //end if
} //end toggleTab
}, //end tops
monoedit: {
toggle: function () {
if ((mw.config.get("wgAction") === "edit" || mw.config.get("wgAction") === "submit") && jQuery("#wpTextbox1").length === 1) {
jQuery("#wpTextbox1").toggleClass("n3-monoedit");
} //end if
}, //end toggle
toggleButton: function () {
if ((mw.config.get("wgAction") === "edit" || mw.config.get("wgAction") === "submit") && jQuery("#wpTextbox1").length === 1) {
mw.loader.using("ext.wikiEditor.toolbar", function () {
jQuery("#wpTextbox1").wikiEditor("addToToolbar", { //Add a custom group for the button
"section": "main",
"groups": {
"views": {}
}
});
jQuery("#wpTextbox1").wikiEditor("addToToolbar", { //add the button itself, to the group
"section": "main",
"group": "views",
"tools": {
"monospace": {
"label": "Toggle monospace",
"type": "button",
"icon": "//upload.wikimedia.org/wikipedia/commons/c/c2/Toolbaricon_regular_M.png", //Compromise, no base64 image support AFAICT
"action": {
"type": "callback",
"execute": function () {
nothingthree.monoedit.toggle();
} //end execute
} //end action
} //end monospace
} //end tools
}); //end add button
jQuery(".group-views").insertBefore(".section-main .group-format"); //Move the group where I want it.
});
} //end if
} //end toggleButton
}, //end monoedit
customRevs: {
getHistory: function (obj) { //Makes the main AJAX call, retrieving the core data and passing along the callback
var historyCall;
historyCall = new mw.Api();
if (nothingthree.customRevs.gettingHistory) {
return;
}
nothingthree.customRevs.gettingHistory = true;
historyCall.get({ //Eventually this item should have something dangling from it for attaching filters
action: "query",
prop: "revisions",
pageids: mw.config.get("wgArticleId"),
continue: (obj ? obj.continueString || "" : ""),
rvprop: "ids|timestamp|flags|user|parsedcomment|size|tags",
rvdir: "older",
rvlimit: (obj ? obj.limit || 50 : 50),
rvtoken: "rollback"
})
.done(function (data) {
if (data.continue && data.continue.rvcontinue) { //This should probably have "else" code if continuation is impossible
nothingthree.customRevs.historyContinue = data.continue.rvcontinue;
}
nothingthree.customRevs.revisionCleanQueue = data.query.pages[mw.config.get("wgArticleId").toString()].revisions;
nothingthree.customRevs.revisionCleanQueue[0].canRollback = true; //This is ugly; I need a better way to resolve rollback-ability
nothingthree.customRevs.resolveRevisions();
nothingthree.customRevs.gettingHistory = false;
});
}, //end getHistory
resolveRevisions: function () { //Makes any further calls to preprocess the data, then renders the revisions to the page
var revsToGet, historyCall, queryMax, cleaningList;
revsToGet = [];
if (mw.config.get("wgUserGroups").indexOf("sysop") !== -1) { //This isn't good, but fair enough for now…
queryMax = 500;
} else {
queryMax = 50;
}
historyCall = new mw.Api();
cleaningList = nothingthree.customRevs.revisionCleanQueue.splice(0, Math.max(nothingthree.customRevs.revisionCleanQueue.length, queryMax));
jQuery.each(cleaningList, function () {
revsToGet.push(this.parentid);
}); //end jQuery.each
historyCall.get({
action: "query",
prop: "revisions",
revids: revsToGet.join("|"),
rvprop: "size"
})
.done(function (data) {
var retrievedRevisions = data.query.pages[mw.config.get("wgArticleId").toString()].revisions.reverse();
jQuery.each(cleaningList, function (index) {
this.sizediff = (this.size - retrievedRevisions[index].size);
this.timestamp = nothingthree.util.parseDate(this.timestamp);
if (!this.canRollback) { //Second part of the ugly bit
delete this.rollbacktoken;
}
nothingthree.customRevs.revisionData.push(this);
nothingthree.customRevs.renderHistoryItem(this, jQuery("#n3-pagehistory").first());
}); //end jQuery.each
if (nothingthree.customRevs.revisionCleanQueue.length > 0) {
nothingthree.customRevs.resolveRevisions();
} else {
jQuery("input[type=checkbox]:not(.noshiftselect)").checkboxShiftClick(); //Reinitialize shift-clicking now that new elements have been created
} //end if/else
}); //end historyCall & done;
}, //end getCleanHistory
gettingHistory: false,
revisionData: [], //Stores cleaned list, starts empty
revisionCleanQueue: [],
historyContinue: "", //Stores latest rvcontinue; this code needs better structure
renderHistoryItem: function (revObject, $historylist) {
var renderedItem, byteLabels;
//Permanent structures
//---- init THE BIG BLOB
renderedItem = jQuery("<li class=\"n3-revision\"></li>");
renderedItem.append("<div class=\"n3-rev-main\"><div class=\"n3-rev-diff\"><a class=\"n3-rev-timestamp\"></a></div></div><div class=\"n3-rev-summary\"><span><span class=\"n3-rev-comment\"></span></span></div><div class=\"n3-rev-meta\"><span class=\"n3-rev-compares\"><span>Compare:</span><ul></ul></span><span class=\"n3-rev-actions\"><span>Actions:</span><ul></ul></span><div class=\"n3-rev-bytediff\"></div></div>");
//---- n3-rev-timestamp
renderedItem.find(".n3-rev-timestamp")
.attr("href", mw.util.getUrl(mw.config.get("wgPageName"), {oldid: revObject.revid}))
.text(nothingthree.util.stringifyDate(revObject.timestamp));
//---- n3-rev-compares
jQuery.each(nothingthree.customRevs.compares, function () {
if (typeof this === "function") {
renderedItem.find(".n3-rev-compares ul").append(nothingthree.customRevs.newLia(this(revObject)));
}
});
//----n3-rev-comment
if (revObject.parsedcomment !== "") {
renderedItem.find(".n3-rev-comment").html(revObject.parsedcomment);
} else {
renderedItem.find(".n3-rev-comment").addClass("n3-rev-nocomment").text("(no edit summary)");
}
//----n3-rev-actions
jQuery.each(nothingthree.customRevs.actions, function () {
if (typeof this === "function") {
renderedItem.find(".n3-rev-actions ul").append(nothingthree.customRevs.newLia(this(revObject)));
}
});
//----n3-rev-bytes & n3-rev-bytebar
if (revObject.sizediff < 0) {
byteLabels = ["n3-rev-bytesremoved", "−"];
} else if (revObject.sizediff > 0) {
byteLabels = ["n3-rev-bytesadded", "+"];
} else {
byteLabels = ["n3-rev-bytesnull", "±"];
}
renderedItem.find(".n3-rev-bytediff").html("<span class=\"".concat(byteLabels[0], "\">", byteLabels[1], nothingthree.util.formatInt(Math.abs(revObject.sizediff)), "</span> → ", nothingthree.util.formatInt(revObject.size), " bytes"));
//Structures which ought to eventually be optional:
//---- n3-rev-form in n3-rev-diff, would be conditional on revision list type; revdel name attr is placeholder
renderedItem.find(".n3-rev-diff").prepend("<div class=\"n3-rev-form\"><input name=\"oldid\" type=\"radio\"><input name=\"diff\" type=\"radio\"><input name=\"revdel\" type=\"checkbox\"></div>");
renderedItem.find("input[name=\"oldid\"], input[name=\"diff\"]").attr("value", revObject.revid);
renderedItem.find("input[name=\"revdel\"]").attr("name", "ids[" + revObject.revid.toString() + "]");
//---- n3-rev-user in n3-rev-main, would be conditional on revision list type
renderedItem.find(".n3-rev-main").append("<div class=\"n3-rev-user vectorMenu\"><h3 class=\"n3-rev-username\"></h3><div class=\"n3-rev-userlinks menu\"><ul></ul></div></div>");
renderedItem.find(".n3-rev-username").text(revObject.user);
jQuery.each(nothingthree.customRevs.userlinks, function () {
if (typeof this === "function") {
renderedItem.find(".n3-rev-userlinks ul").append(nothingthree.customRevs.newLia(this(revObject)));
}
});
//---- n3-rev-flagtags in n3-rev-summary, would be conditional on presence
renderedItem.find(".n3-rev-summary > span").append("<span class=\"n3-rev-flagtags\"><ul></ul></span>");
if (revObject.minor !== undefined) {
renderedItem.find(".n3-rev-flagtags ul").append("<li>Minor edit</li>");
}
jQuery.each(revObject.tags, function () {
renderedItem.find(".n3-rev-flagtags ul")
.append(nothingthree.customRevs.newLia({text: "Tag", href: mw.util.getUrl("Special:Tags"), title: "Special:Tags"}).append(": ", jQuery("<span></span>").text(this)));
});
//Initialize rendered revision item
$historylist.append(renderedItem);
$historylist.children().last().find(".n3-rev-user").click(function () {
jQuery(this).toggleClass("menuForceShow");
});
}, //end renderHistoryItem
newLia: function (obj) { //Simplifies making all of the individual listy items
var newItem = jQuery("<li><a></a></li>");
if (!obj) {
return null;
}
if (obj.text) {
newItem.children().text(obj.text);
}
if (obj.href) {
newItem.children().attr("href", obj.href);
}
if (obj.title) {
newItem.children().attr("title", obj.title);
}
return newItem;
}, //end newLia
compares: {
diff: function (revObject) {
return {
text: "Previous",
href: mw.util.getUrl(mw.config.get("wgPageName"), {diff: revObject.revid, oldid: revObject.parentid})
};
}, //end diff
cur: function (revObject) {
return {
text: "Current",
href: mw.util.getUrl(mw.config.get("wgPageName"), {oldid: revObject.revid, diff: "cur"})
};
} //end cur
}, //end compares
userlinks: {
page: function (revObject) {
return {
text: "User page",
href: mw.util.getUrl("User:" + revObject.user)
};
}, //end page
talk: function (revObject) {
return {
text: "Talk",
href: mw.util.getUrl("User talk:" + revObject.user)
};
}, //end talk
contribs: function (revObject) {
return {
text: "Contributions",
href: mw.util.getUrl("Special:Contributions/" + revObject.user)
};
}, //end contribs
block: function (revObject) {
if (mw.config.get("wgUserGroups").indexOf("sysop") === -1) {
return null;
}
return {
text: "Block",
href: mw.util.getUrl("Special:Block/" + revObject.user)
};
} //end block
}, //end userlinks
actions: {
rollback: function (revObject) {
if (revObject.rollbacktoken === undefined) {
return null;
}
return {
text: "Rollback",
href: mw.util.getUrl(mw.config.get("wgPageName"), {action: "rollback", from: revObject.user, token: revObject.rollbacktoken})
};
}, //end rollback
undo: function (revObject) {
return {
text: "Undo",
href: mw.util.getUrl(mw.config.get("wgPageName"), {action: "edit", undo: revObject.revid, undoafter: revObject.parentid})
};
}, //end undo
thank: function (revObject) {
return {
text: "Thank",
href: mw.util.getUrl("Special:Thanks/" + revObject.revid)
};
}, //end thank
revdel: function (revObject) {
if (mw.config.get("wgUserGroups").indexOf("sysop") === -1) {
return null;
}
return {
text: "Delete",
href: mw.util.getUrl(mw.config.get("wgPageName"), {action: "revisiondelete", from: revObject.user}) + "&" + mw.util.rawurlencode("ids[" + revObject.revid + "]")
};
} //end revdel
}, //end actions
renderHistoryList: function (limit) {
var maxlimit = 500; //default API max; this is a bit of an unhealthy assumption…
if (mw.config.get("wgUserGroups").indexOf("sysop") !== -1) { //Same bad assumption, and hackish to boot
maxlimit = 5000;
}
nothingthree.customRevs.getHistory({
limit: (Math.min(parseInt(limit, 10), maxlimit) || Math.min(parseInt(mw.user.options.get("rclimit"), 10), maxlimit) || 50) //parseInt necessary to force some values to NaN for Math.min
}); //end gethistory & its input object
}, //end renderHistoryList
testRun: function () {
if (mw.config.get("wgAction") === "history") {
jQuery("#pagehistory").attr("id", "n3-pagehistory").html("");
nothingthree.customRevs.renderHistoryList(50);
}
} //end testRun
} //end customRevs
}; //end nothingthree
mw.loader.load("//en.wikipedia.org/w/index.php?title=User:Nihiltres/nothingthree.css&action=raw&ctype=text/css", "text/css");
mw.loader.load("//en.wikipedia.org/w/index.php?title=User:" + mw.util.wikiUrlencode(mw.config.get("wgUserName")) + "/nothingthree-config.js&action=raw&ctype=text/javascript"); //call the activator :)
});