User:The Herald/amelvand.js

// //Ameliorating vandalism. Naught to do with the Belgian municipality. //TODO: combine addRollback and addRestore into one function //     use WikiTitle throughout the script //     add history visualization to get around IE prompt "security" issue AmelPrefs = { data: {}, set: function(name, value) { return this.data[name] = value; },	get: function(name, alternate) { return this.contains(name) ? this.data[name] : alternate; },	contains: function(name) { return (typeof this.data[name] != "undefined"); } }; if(typeof(AmelPrefs.data["summarySuffix"]) == "undefined") AmelPrefs.set("summarySuffix", ""); if(typeof(AmelPrefs.data["watchReversion"]) == "undefined") AmelPrefs.set("watchReversion", false); //combine these into one function. function addRollback { if(document.getElementById("mw-diff-ntitle1").getElementsByTagName("a")[0].firstChild.nodeValue.indexOf("Current revision") == -1) return; var roll = document.createElement("input"); roll.type = "button"; roll.onclick = AmelUtil.diffRollback(document); roll.value = "Rollback"; getElementsByClassName(document, "td", "diff-otitle")[0].appendChild(roll); } function addRestore { var rest = document.createElement("input") rest.type = "button"; rest.onclick = AmelUtil.diffRestore(document); rest.value = "Restore revision"; getElementsByClassName(document, "td", "diff-otitle")[0].appendChild(rest); } function AdminRollback(url) { if (!url || this == window) return; //no title given, or "new" keyword not used this.url = url; try { this.userFrom = decodeURIComponent(url.match(/[&?]from=([^&]*)/)[1]).replace(/_/g, " "); this.title = url.match(/[&?]title=([^&]*)/)[1]; } catch (e) { return; //error in parsing link; not correct }	this.init; } AdminRollback.prototype.init = function { var me = this; AmelUtil.colorStatus("#EFE"); var req = new XMLHttpRequest; req.open("HEAD", this.url, true); req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { AmelUtil.colorStatus("#EEF"); new WikiEdit(me.title).getHistory(function(obj){showHistory(me.title, obj)}); }	};	req.send(null); new Warning(this.title, this.userFrom); } function Rollback(title, revFrom, userFrom) { if (!title || this == window) return; //no title given, or "new" keyword not used this.title = title; //in encoded form this.from = { "revid" : revFrom || undefined, "user" : userFrom || undefined }; this.revTo = undefined; this.revnum = 0; this.editor = new WikiEdit(title, this); this.init; } Rollback.prototype.init = function { AmelUtil.colorStatus("#FEE"); this.editor.downloadEditFormData; this.editor.getHistory(this.parseHistory); } Rollback.prototype.parseHistory = function(history) { AmelUtil.colorStatus("#FFE"); if (!history || !history[0]) { alert("Error retriving page history"); //go modal boxes! return; }   this.editor.setTimes(AmelUtil.isoToNumerical(history[0]["timestamp"])); //some situations the reverter should check out var cautionMode = undefined; if (this.from.revid) { if (history[0]["revid"] == this.from.revid) this.from.user = history[0]["user"]; //just in case it's not defined else cautionMode = "The revision amelvand was told to revert from is not the most recent one."; }   else if (this.from.user && this.from.user != history[0]["user"]) cautionMode = "The user amelvand was told to revert from is not the most recent editor of the article."; else cautionMode = "Neither a revision nor a user was received, so just making sure that we really want to revert."; i = 0; if (cautionMode) { j = []; var min = Math.min(history.length, 8); for (i = 0; i < min; i++) //add summary? j[i] = i + ". " + history[i]["user"] + (history[i]["revid"] == this.from.revid ? " (original)" : ""); i = prompt(j.join("\n") + "\n\nCaution mode enabled. Reason: " + cautionMode + "\n\nFrom which revision do you wish to revert?", "0"); //moar options! if (isNaN(parseInt(i))) return; this.revid = history[i][0]; this.user = history[i][1]; }  //cautionModeBox(cautionMode, history); } else { this.revnum = i;  while (this.revnum < history.length && history[this.revnum]["user"] == this.from.user) { this.revnum++; }   if (this.revnum - i != 1) { if(!confirm("Rollback " + (this.revnum - i) + " edits by " + this.from.user + "?")) { j = prompt("Then rollback how many edits?", "1") if (isNaN(parseInt(j))) return; else this.revnum = j;     } }   if (this.revnum < history.length) { this.revTo = history[this.revnum]["revid"]; this.commit; }	else alert("Last revision not by user not found."); } Rollback.prototype.commit = function { new Warning(this.title, this.from.user); var editSum = "Reverted " + AmelUtil.plural(this.revnum, "edit", "edits") + " by $2 (talk)".replace(/\$2/g, this.from.user) + " to last revision by $1"; //$1 is assigned by RestoreRevision new RestoreRevision(this.title, this.revTo, this.editor, editSum) }; function RestoreRevision(title, revTo, editor, editSum) { if (!title || !revTo || this == window) return; AmelUtil.colorStatus("#EFE"); this.title = title; this.revTo = revTo; this.editSum = editSum || "Restored revision " + this.revTo + " by $1"; //$1 is assigned by commit(obj) if (!editor) { editor = new WikiEdit(title); editor.downloadEditFormData; editor.getHistory(function(obj) {			editor.setTimes(AmelUtil.isoToNumerical(obj["timestamp"]));		}, 1); }	editor.setParent(this); this.editor = editor; this.init; } RestoreRevision.prototype.init = function { this.editor.getText(this.commit, this.revTo); } RestoreRevision.prototype.commit = function(obj) { if (!obj) return; var text = obj["*"]; if (!text && text != "") return; this.editSum = this.editSum.replace(/\$1/g, obj["user"]) + AmelPrefs.get("summarySuffix", ""); var editor = this.editor; //short-hand reference var title = this.title; editor.setMinor(false); editor.setWatch(AmelPrefs.get("watchReversion", false)); editor.setCallback(function {		AmelUtil.colorStatus("#EEF");		editor.getHistory(function(obj){showHistory(title, obj)});	}); editor.setText(text); editor.setSummary(this.editSum); editor.submit; } //- //@Private function WikiTitle(displayTitle, urlTitle) { this.displayTitle = displayTitle; this.urlTitle = urlTitle; } WikiTitle.fromURL = function(url, param) { var urlmatch = (!param && /\/wiki\/(.*)/.exec(url)) || new RegExp("[?&]" + (param || "title") + "=([^&]*)").exec(url); if (urlmatch) return WikiEdit.fromEncoded(urlmatch[1]); } WikiTitle.fromEncoded = function(encoded) { return new WikiTitle(decodeURIComponent(encoded).replace(/_/g, " "),                        encoded); } WikiTitle.fromDisplay = function(display) { return new WikiTitle(display,	                    encodeURIComponent(display.replace(/ /g, "_"))); } //accessors WikiTitle.prototype = { toEncoded : function { return this.urlTitle; },	toIndexUrl : function { return mw.config.get('wgServer') + mw.config.get('wgScript') + "?title=" + this.urlTitle; },	toApiUrl : function { return mw.config.get('wgServer') + mw.config.get('wgScriptPath') + "/api.php?titles=" + this.urlTitle; },	toString : function { return this.displayTitle; } }; function Warning(title, user) { if (!title || !user || this == window) return; var me = this; this.user = user; title = WikiTitle.fromEncoded(title); this.title = title; var warnTitle = WikiTitle.fromDisplay("User talk:" + user), aivTitle = WikiTitle.fromDisplay("Wikipedia:Administrator intervention against vandalism"); this.data = new Object; this.data[Warning.WARN] = { "title": warnTitle, "editor": new WikiEdit(warnTitle, me), "summary": "Note: edits on " + title + "", "savedtext": undefined, "addtext": undefined, "infotext": "", "button": "Report to AIV", "init": Warning.warnInit, "editpage": title };	this.data[Warning.AIV] = { "title": aivTitle, "editor": new WikiEdit(aivTitle, me), "summary": "Reporting $1".replace(/\$1/g, user), "savedtext": undefined, "addtext": "* vandalism past last warning " + "", "infotext": "Reporting " + user + ". ", "button": "Warn User", "init": Warning.aivInit, "regex": new RegExp(user + "\\}\\}") //basic sensing mechanism };	this.mode = Warning.NONE; //initialize GUI. no "live" elements have innerHTML changed. var warnDiv = document.createElement("div"); warnDiv.innerHTML = '    '; var jumpToNav = document.getElementById("jump-to-nav"); if (!jumpToNav) return false; jumpToNav.parentNode.insertBefore(warnDiv, jumpToNav); this.gui = { "warnBox": document.getElementById("warnBox"), "warnPage": document.getElementById("warnPage"), "warnInfo": document.getElementById("warnInfo"), "warnSwitch": document.getElementById("warnSwitch"), "warnSubmit": document.getElementById("warnSubmit"), "warnSum": document.getElementById("warnSum") }	this.gui["warnBox"].value = ""; this.gui["warnPage"].appendChild(document.createTextNode("")); this.gui["warnInfo"].appendChild(document.createTextNode("")); this.gui["warnSwitch"].onclick = function {me.setNextMode;}; this.gui["warnSubmit"].onclick = function {me.submit;}; this.setNextMode; } Warning.NONE = ["NONE"]; Warning.WARN = ["WARN"]; Warning.AIV = ["AIV"]; Warning.warnInit = function(text) { this.savedtext = text; var parser = new WarningsParser(text); if (parser.report) this.infotext += "NOTE! User is past last warning. "; var now = new Date; var warnDate = parser.previousDate; var secElapsed = Math.ceil((now.getTime - warnDate.getTime) / 1000); if (secElapsed < 0) secElapsed += 3600; //an hour. voodoo programming! if (secElapsed < 600) { //ten minutes var minElapsed = Math.floor(secElapsed / 60); this.infotext += "Latest warning was left " + (minElapsed == 0 ? "" : AmelUtil.plural(minElapsed, "minute", "minutes") + " and ") + AmelUtil.plural(secElapsed % 60, "second", "seconds") + " ago. "; }//12	var headers = parser.getHeaders, prefixHeader = ""; if (!headers.warning || (headers.warning && headers.page) || (headers.warning && (now.getMonth != warnDate.getMonth || now.getFullYear != warnDate.getFullYear))) prefixHeader = "== " + AmelUtil.monthNames[now.getUTCMonth] + " " + now.getUTCFullYear + " ==\n"; this.savedtext += (/^\s*$/.test(this.savedtext) ? "" : "\n\n") + (this.addtext = prefixHeader + "" + this.editpage + " " + ""); } Warning.aivInit = function(text) { if (this.regex.test(text)) this.infotext += "NOTE! \"" + this.user + "\" found on page. "; this.savedtext = text + "\n" + this.addtext; } Warning.nextMode = function(mode) { switch (mode) { case Warning.NONE: return Warning.WARN; case Warning.WARN: return Warning.AIV; case Warning.AIV: return Warning.WARN; default: return Warning.NONE; } } Warning.prototype.getDownloadCallback = function(mode) { var me = this; return function(obj) { me.set(obj, mode); } } Warning.prototype.setNextMode = function { this.set(null, Warning.nextMode(this.mode)); } Warning.prototype.set = function(obj, newMode) { var mData = this.data[newMode]; var text = obj && obj["*"]; if (!mData) return; if (!mData.savedtext || mData.savedtext == "") { if (text || text == "") { mData.init(text); mData.editor.setTimes(AmelUtil.isoToNumerical(obj["timestamp"])); this.gui["warnSwitch"].value += "..."; this.showMode(newMode); } else { var func = this.getDownloadCallback(newMode); mData.editor.getText(func); mData.editor.downloadEditFormData; }	} else { if (text) { if (confirm("The page \"" + mData.title + "\" is already initialized. Overwrite displayed text?")) mData.init(text); else return; }		this.showMode(newMode); } } Warning.prototype.showMode = function(newMode) { var thisData = this.data[this.mode]; var newData = this.data[newMode]; var gui = this.gui; if (thisData) { thisData.savedtext = gui["warnBox"].value; thisData.summary = gui["warnSum"].value; }	gui["warnBox"].value = newData.savedtext; gui["warnSum"].value = newData.summary; gui["warnPage"].firstChild.nodeValue = newData.title; gui["warnInfo"].firstChild.nodeValue = newData.infotext; gui["warnSwitch"].value = newData.button; this.mode = newMode; } Warning.prototype.submit = function { var summary = this.gui["warnSum"].value; var text = this.gui["warnBox"].value; if (this.mode == Warning.WARN) { var re = /\{\{subst:uw-(.*?)(?:\|.*?)?\}\}/gi; if (summary.charAt(summary.length - 1) == "*") //shorthand for "no template plz" summary = summary.substring(0, summary.length - 1); else { var templateMatch, templateName; while (templateMatch = re.exec(text)) templateName = templateMatch[1]; if (templateName) summary += " (" + templateName + ")"; }	} else if (this.mode != Warning.AIV) { return; //only Warning.WARN and Warning.AIV allowed at the moment }	var button = this.gui["warnSubmit"]; button.disabled = true; var editor = this.data[this.mode].editor; editor.setText(text); editor.setSummary(summary); editor.setMinor(false); editor.setWatch(false); editor.setCallback(function { button.disabled = false; }); editor.submit; } //- //construct object: get in, get out. No need for state. function showHistory(title, historyObj, showButtons, limit) { limit = Math.min(historyObj.length, limit || 5); if (!limit) return; var pageURL = WikiTitle.fromEncoded(title).toIndexUrl; var currentId = historyObj[0]["revid"]; var newLink = function(url, title) { var link = document.createElement("a"); link.href = url; link.title = title; link.appendChild(document.createTextNode(title)); return link; }	var historyItem = function(item, nextItem) { //more pretty list under construction var liItem = document.createElement("li"); if (nextItem) { liItem.appendChild(document.createTextNode("("));			liItem.appendChild(newLink(pageURL + "&diff=" + currentId + "&oldid=" + item["revid"], "cur"));			liItem.appendChild(document.createTextNode(") ("));		} else {			liItem.appendChild(document.createTextNode("(cur) (")); }		liItem.appendChild(newLink(pageURL + "&diff=" + item["revid"] + "&dir=prev", "last")); liItem.appendChild(document.createTextNode(") "));		liItem.appendChild(newLink(pageURL + "&oldid=" + item["revid"], AmelUtil.isoToStandard(item.timestamp)));		liItem.appendChild(document.createTextNode(" "));		liItem.appendChild(newLink(WikiTitle.fromDisplay("Special:Contributions/" + item.user).toIndexUrl, item.user));		if (item["comment"]) {			var summary = item["comment"].replace(/\[\[([^\|\]]+)\|?(.*?)\]\]/g, function (ignore, link, display) { return "" + (display || link) + ""});			summary = summary.replace(/\/\*\s+(.+?)\s+\*\//g, function(ignore, anchor) { return "→" + anchor + " - "});			var summaryElem = document.createElement("span"); summaryElem.innerHTML = " | " + summary;			liItem.appendChild(summaryElem);		}		return liItem; }	var historyDiv = document.getElementById("historyDiv"); if (historyDiv && historyDiv.firstChild) { historyDiv.removeChild(historyDiv.firstChild); } else { historyDiv = document.createElement("div"); historyDiv.id = "historyDiv"; var jumpToNav = document.getElementById("jump-to-nav"); if (!jumpToNav) return false; jumpToNav.parentNode.insertBefore(historyDiv, jumpToNav); historyDiv = document.getElementById("historyDiv"); }	var historyList = document.createElement("ol"); var currentItem, nextItem; for (var i = 0; i < limit; i++) { currentItem = historyObj[i]; historyList.appendChild(historyItem(currentItem, nextItem)); nextItem = currentItem; }	historyDiv.appendChild(historyList); } //- function WarningsParser(text) { var state = { header: false, hasWarnings: false }; //if the latest header contains the most recent warning, if warnings can be found var recent = { header: undefined, text: undefined, date: new Date(0), level: 0 }; //the header under which the latest warning appears, the warning's text, //the date of the warning, its level. var warningMatch = 0, warning; var dayAgo = new Date; dayAgo.setTime(dayAgo.getTime - (24*60*60*1000)); var re = /.*?(\d{2}:\d{2}, \d+ \w+ \d{4}) \(UTC\)/gi; var warning; while (warning = re.exec(text)) { if (!warning) break; recent.date = new Date(warning[2] + " UTC"); //UTC can't be in parentheses :| if (recent.date > dayAgo) recent.text = warning[1]; state.hasWarnings = true; warningMatch = re.lastIndex; }	//find the header the warning is under var headerRe = /^(={2,6}).+?\1\s*?$/mg; var warningH = text.substring(0, warningMatch).match(headerRe); var pageH = text.substring(warningMatch).match(headerRe); recent.header = warningH && warningH.pop; state.header = !!pageH; if (recent.text) { var levels = recent.text.match(/^.*?(\d)(im)?$/); if (levels && levels[1]) recent.level = parseInt(levels[1]); else if (/first/i.test(recent.text)) recent.level = 1; else if (/second/i.test(recent.text)) recent.level = 2; else if (/third/i.test(recent.text)) recent.level = 3; else if (/fourth/i.test(recent.text)) recent.level = 4; } else if (state.hasWarnings) { recent.level = 1; //if there are warnings there, use a level 2. put this in prefs? }	this.pageData = state; this.warningData = recent; } //encapsulate state WarningsParser.prototype = { report : function { return this.warningData.level == 4; },	hasWarnings: function { return this.pageData.hasWarnings; },	nextWarning: function { var recent = this.warningData; if (recent.level < 4) return recent.level + 1; else if (recent.level == 4) return 4; else //not sure what we have; stick with level 1. return 1; },	previousDate: function { return this.warningData.date; },	getHeaders: function { return { page: this.pageData.header, warning: this.warningData.header }; } } AmelUtil = new Object; AmelUtil.plural = function(num, singular, plural) { return num + " " + (num == 1 ? singular : plural); } //previously named AmelUtil.yetAnotherJsMonthNameArray. too long, though :P AmelUtil.monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; AmelUtil.isIP = function(str) { var rangeCheck = function(num) { return (!/\D/.test(num) && parseInt(num) >> 8 == 0); }	var nums = str.split("."), index = nums.length; if (index != 4 && index != 6) return false; while (--index >= 0) if (!rangeCheck(nums[index])) return false; return true; } AmelUtil.numericalTsNow = function { var now = new Date; var padDD = function(num) { //double-digit pad return ("0" + num).slice(-2); }	return now.getUTCFullYear + padDD(now.getUTCMonth + 1) + padDD(now.getUTCDate) + padDD(now.getUTCHours) + padDD(now.getUTCMinutes) + padDD(now.getUTCSeconds); } AmelUtil.isoToNumerical = function(timestamp) { return timestamp && timestamp.replace( /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/, "$1$2$3$4$5$6") } AmelUtil.isoToStandard = function(timestamp) { return timestamp && timestamp.replace( /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/, function(ignore, year, month, date, hour, minute) { return hour + ":" + minute + ", " + date + " " + AmelUtil.monthNames[month - 1] + " " + year}); } AmelUtil.getPageObj = function(jsonObj) { try { jsonObj = jsonObj.query.pages; for (var pageObj in jsonObj) return jsonObj[pageObj]; } catch (e) { } } AmelUtil.colorStatus = function(color) { document.getElementById("content").style.background = color; } AmelUtil.rollbackPerm = function { if (wgUserGroups.indexOf) return wgUserGroups.indexOf("sysop") != -1 || wgUserGroups.indexOf("rollbacker") != -1; for (var i = 0, length = wgUserGroups.length; i < length; i++) if (wgUserGroups[i] == "sysop" || wgUserGroups[i] == "rollbacker") return true; return false; } AmelUtil.diffRollback = function { var checkExist = document.getElementById("mw-diff-ntitle1"); if (!checkExist) return null; if (AmelUtil.rollbackPerm) { var rb = document.getElementById("mw-diff-ntitle2").getElementsByTagName("span"); if (rb.length > 1) { var rbUrl = rb[1].getElementsByTagName("a")[0].href return function { new AdminRollback(rbUrl); };		} //else, continue along with normal revert }	var link = checkExist.getElementsByTagName("a"); link = link[link.length - 1].href; var revFrom = link.match(/[&?]undo=([^&]*)/); var pageName = link.match(/[&?]title=([^&]*)/); var userFrom = document.getElementById("mw-diff-ntitle2") .getElementsByTagName("a")[0].title.match(/(?:User:|Special:Contributions\/)(.*$)/); if (pageName) return function { new Rollback(pageName[1], (revFrom ? revFrom[1] : undefined), (userFrom ? userFrom[1] : undefined)); } }; AmelUtil.diffRestore = function(container) { var checkExist = container.getElementById("mw-diff-otitle1"); if (!checkExist) return null; var link = checkExist.getElementsByTagName("a")[0].href; var pageName = link.match(/[&?]title=([^&]*)/); var revTo = link.match(/[&?]oldid=([^&]*)/); var userTo = container.getElementById("mw-diff-otitle2") .getElementsByTagName('a')[0].title.match(/(?:User:|Special:Contributions\/)(.*$)/); if (pageName && revTo) return function { latest = new RestoreRevision(pageName[1], revTo[1]); } }; //- //Mode: press spacebar to revert AmelKeyFuncs = {}; AmelKeyFuncs.enabled = document.cookie.indexOf("amelKeys=true") != -1; AmelKeyFuncs.formatOnLoad = function { mw.util.addPortletLink("p-tb", "javascript:AmelKeyFuncs.toggleUse", (AmelKeyFuncs.enabled ? "Don't use" : "Use") + " spacebar reversion", "t-amelkeys", "Enable reversion on diffs using the spacebar"); window.onkeypress = AmelKeyFuncs.checkToRevert; window.focus; } AmelKeyFuncs.pageEnabled = true; AmelKeyFuncs.checkToRevert = function(e) { if (!AmelKeyFuncs.enabled || !AmelKeyFuncs.pageEnabled) return true; e = e || window.event; if (e.charCode == 32) { var func = AmelUtil.diffRollback; AmelKeyFuncs.pageEnabled = false; if (func) { func.call(this); return false; }	}	return true; } AmelKeyFuncs.toggleUse = function { var now = new Date; if (!AmelKeyFuncs.enabled) now.setTime(now.getTime + 365*24*60*60*1000); AmelKeyFuncs.enabled = !AmelKeyFuncs.enabled; document.cookie = "amelKeys=" + AmelKeyFuncs.enabled + "; expires=" + now.toGMTString + "; path=/" document.getElementById("t-amelkeys").firstChild.firstChild.nodeValue = (AmelKeyFuncs.enabled ? "Don't use" : "Use") + " spacebar reversion"; } //- var WikiEdit = function(title, parent, autosubmit) { if (!title) throw new Error("title needed for WikiEdit"); this.title = title; this.autosubmit = autosubmit; this.submitCallback = function{}; this.closed = false; this.editMonitor = false; this.submitData = {}; //the form fields this.onSubmitHooks = []; //to be processed immediately before submitting this.submitXHR = null; this.parent = parent; } WikiEdit.needToSubmit = ["wpTextbox1", "wpSummary", "wpEditToken", "wpStarttime", "wpEdittime"]; WikiEdit.prototype.setCallback = function(callback) { this.submitCallback = callback; } WikiEdit.prototype.cancel = function { this.closed = true; if (this.submitXHR) this.submitXHR.abort; } WikiEdit.prototype.addSubmitHook = function(func) { if (this.closed) return false; this.onSubmitHooks.push(func); return true; } WikiEdit.prototype.doPreSubmitHook = function(func) { if (this.closed) return false; this.editMonitor = true; func.call(this); this.editMonitor = false; this.addSubmitData({}); return true; } WikiEdit.prototype.downloadEditFormData = function { if (this.closed) return; var me = this; var req = new XMLHttpRequest; req.open("GET", mw.config.get('wgServer') + mw.config.get('wgScriptPath') + "/api.php?action=query&prop=info&intoken=edit&format=json&titles=" + this.title, true); req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { var pageObj = AmelUtil.getPageObj(eval("(" + req.responseText + ")")); if (pageObj) { me.addSubmitData({"wpEditToken" : pageObj["edittoken"]}); }			else alert("Could not retrieve edit form data"); }	}	req.send(null); } WikiEdit.prototype.setParent = function(parent) { this.parent = parent; } WikiEdit.prototype.setText = function(wikitext) { this.addSubmitData({"wpTextbox1" : wikitext}); } WikiEdit.prototype.setTimes = function(edittime) { var tsNow = AmelUtil.numericalTsNow; this.addSubmitData({"wpEdittime" : edittime || tsNow,		      	    "wpStarttime" : tsNow}); } WikiEdit.prototype.setSummary = function(text) { this.addSubmitData({"wpSummary" : text}); } WikiEdit.prototype.setMinor = function(boole) { if (boole) this.addSubmitData({"wpMinoredit" : "1"}); } WikiEdit.prototype.setWatch = function(boole) { if (boole) this.addSubmitData({"wpWatchthis" : "1"}); } WikiEdit.prototype.getHistory = function(callback, limit) { this.getRevInformation(callback, ["user", "ids", "comment", "timestamp"], limit || 20, undefined); } WikiEdit.prototype.getText = function(callback, oldid) { this.getRevInformation(callback, ["content", "user", "timestamp"], 1, oldid); } //Private. precondition: props are properly encoded WikiEdit.prototype.getRevInformation = function(callback, props, limit, revid) { if (!callback) return; var me = this; var req = new XMLHttpRequest; req.open("GET", wgServer + wgScriptPath + 	         "/api.php?action=query&prop=revisions&format=json&rvprop=" + props.join("|") +			 (revid ? "&rvstartid=" + revid : "") + (limit ? "&rvlimit=" + limit : "") +			 "&titles=" + this.title, true); req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { var pageObj = AmelUtil.getPageObj(eval("(" + req.responseText + ")")); if (!pageObj) return; if (pageObj.revisions) { var returnObj = pageObj["revisions"]; if (limit == 1) returnObj = returnObj[0]; returnObj.title = pageObj.title; callback.call(me.parent, returnObj); } else if (pageObj.missing == "") { callback.call(me.parent, {"user":"", "*":""}); }					}	}	req.send(null); } WikiEdit.prototype.submit = function { this.autosubmit = true; if (this.closed || this.editMonitor) return false; var submitData = this.submitData, onSubmitHooks = this.onSubmitHooks; for (var i = 0, nts = WikiEdit.needToSubmit; i < nts.length; i++) if (!(nts[i] in submitData)) return false; this.closed = true; while (onSubmitHooks.length > 0) onSubmitHooks.shift.call(this); var parameters = []; for (var property in submitData) parameters.push(encodeURIComponent(property) + "=" + encodeURIComponent(submitData[property])); var me = this; var req = this.submitXHR = new XMLHttpRequest; req.open("POST", mw.config.get('wgServer') + mw.config.get('wgScript') + "?title=" + this.title + "&action=submit", true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { me.submitCallback.call(me.parent); }	};	req.send(parameters.join("&")); return true; } //@Private. Adds data; submits to index.php if has all information WikiEdit.prototype.addSubmitData = function(obj) { var submitData = this.submitData; if (this.closed) return; for (var property in obj) //merge into submitData submitData[property] = obj[property]; if (this.autosubmit) this.submit; } //- var isDiff = /[?&]diff=/.test(document.location.href); if (isDiff) { addOnloadHook(addRollback); addOnloadHook(addRestore); if (AmelKeyFuncs.enabled) addOnloadHook(AmelKeyFuncs.formatOnLoad); } //