User:Bawolff/mwapilib2.js
Appearance
Note: After saving, you may have to bypass your browser's cache to see the changes. Mozilla / Firefox / Safari: hold down Shift while clicking Reload, or press Ctrl-Shift-R (Cmd-Shift-R on Apple Mac); IE: 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. — More skins
//this is a better version of [[user:Bawolff/mwapilib2.js]]. It is not fully documented. Ask me (bawolff) if you have questions.
/*global window, wgDBname */
/*jslint bitwise: true, browser: true, eqeqeq: true, immed: true, newcap: true, nomen: false, plusplus: false, regexp: true, undef: true */
/*members APIC, Bawolff, _setNext, _startExec, api, apply, content,
cur_val, edit, exec, func, getPage, inject, last_get, length, lift,
mwapi, next, page, prototype, replace, savePage, section, start,
summary, toString, setFollowRedirect
*/
if (!window.Bawolff) {
var Bawolff = {};
}
if (mw.config.get( 'wgDBname' ) === "enwikinews") {
mw.loader.load( '/w/index.php?title=' + 'User:Bawolff/mwapilib.js' + '&action=raw&ctype=text/javascript' ); //this does low level stuff
} else {
//in case not loaded on en wikinews
mw.loader.load('//en.wikinews.org/w/index.php?title=User:Bawolff/mwapilib.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400');
}
Bawolff.APIC = function (start, prev, cur_func) {
//start, prev is APIC objects
//cur_func is a function.
this.start = start;
if (!start) {
this.start = this;
}
if(prev) {
prev._setNext(this);
}
this.func = cur_func;
}
Bawolff.APIC.prototype.toString = function() {
return "mediawiki api ajax request";
}
Bawolff.APIC.prototype._setNext = function(next) {
this.next = next;
}
//can manually be passed a state value
Bawolff.APIC.prototype.exec = function (optionalState) {
this.next = {"_startExec": function () {return true;}}; //FIXME: ugly
this.start._startExec(optionalState);
return true;
}
Bawolff.APIC.prototype._startExec = function(cur_val) {
this.func(this.next, cur_val);
}
Bawolff.APIC.api = function(initial, opts) {
var state = {cur_val: initial,
last_get: null,
lastSaveRev: 0,
summary: 'Editing using [[user:Bawolff/mwapilib.js]]',
follow_redirect: true,
stack: []}; //perhaps add last_put later?
//note its intentional initial could be undefined.
var func = function ( next, state2 ) {
if (next) {
if(state2 instanceof Object) {
state = state2;
state.cur_val = (initial !== undefined ? initial : state.cur_val)
}
next._startExec(state);
}
}
return new Bawolff.APIC(undefined, undefined, func);
}
if (!window.api) {
var api = Bawolff.APIC.api;
}
/*
this runs its arguments asynchronously, then goes to next thing in its chain
essentially forks the chain.
*/
Bawolff.APIC.prototype.split = function() {
var outerArgList = arguments;
var wrapper = function (next, state) {
for (var i = 0; i < outerArgList.length; i++) {
if (outerArgList[i] instanceof Bawolff.APIC) {
outerArgList[i].exec(state);
}
}
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.runAsync = Bawolff.APIC.prototype.split;
Bawolff.APIC.prototype.fork = Bawolff.APIC.prototype.split;
Bawolff.APIC.prototype.doQuick = Bawolff.APIC.prototype.split;
Bawolff.APIC.prototype.lift = function(func) {
var outerArgList = arguments;
var wrapper = function (next, state) {
var newArgList = [state.cur_val];
for (var i = 1; i < outerArgList.length; i++) {
newArgList[i] = outerArgList[i];
}
var res = func.apply(window, newArgList);
state.cur_val = res;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
//Takes second arg from stack
Bawolff.APIC.prototype.lift2 = function(func) {
var outerArgList = arguments;
var wrapper = function (next, state) {
var newArgList = [state.cur_val, state.stack.pop()];
for (var i = 2; i < outerArgList.length; i++) {
newArgList[i] = outerArgList[i];
}
var res = func.apply(window, newArgList);
state.cur_val = res;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.abortIfFalse = function() {
var wrapper = function (next, state) {
if (state.cur_val) {
next._startExec(state);
}
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.not = function() {
var wrapper = function (next, state) {
state.cur_val = !state.cur_val;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
/*lift(alert) dies in IE. */
Bawolff.APIC.prototype.alert = function(mesg) {
var wrapper = function (next, state) {
if (mesg === undefined) mesg = state.cur_val;
alert(mesg);
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.replace = function(regex, repl) {
var wrapper = function (next, state) {
var res = state.cur_val.replace(regex, repl);
state.cur_val = res;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.pop = function(defau) {
//default seems to be reserved word or something
var wrapper = function (next, state) {
var res = state.stack.pop();
if (res === undefined) res = defau;
state.cur_val = res;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.push = function(val) {
var wrapper = function (next, state) {
if (val !== undefined) {
state.stack.push(val);
} else {
state.stack.push(state.cur_val);
}
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.swap = function() {
var wrapper = function (next, state) {
var hold = state.stack.pop();
state.stack.push(state.cur_val)
state.cur_val = hold;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
/*Duplicate top item on stack*/
Bawolff.APIC.prototype.dup = function() {
var wrapper = function (next, state) {
var hold = state.stack.pop();
state.stack.push(hold);
state.stack.push(hold);
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.inject = function(val) {
var wrapper = function (next, state) {
state.cur_val = val;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, wrapper);
}
Bawolff.APIC.prototype.setDefaultSummary = function(summary) {
var outerWrapper = function (next, state) {
state.summary = (summary ? summary : state.cur_val);
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.setFollowRedirect = function(follow) {
//only affect parse page.
var outerWrapper = function (next, state) {
state.follow_redirect = follow;
next._startExec(state);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.getPage = function(pageName) {
var outerWrapper = function (next, state) {
if (!pageName) {
pageName = state.cur_val;
}
state.last_get = pageName;
var innerWrapper = function (p) {
state.cur_val = p[0];
next._startExec(state);
}
Bawolff.mwapi.getPage(pageName, innerWrapper, undefined, state.follow_redirect);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.savePage = function(pageName, opt) {
if (!opt) {
opt = {}; //stop reference errors for undef object
}
var outerWrapper = function (next, state) {
if (!pageName) {
pageName = state.last_get;
}
var editArg = {page: pageName, content: state.cur_val, summary: (opt.summary ? opt.summary : state.summary ), section: (opt.section ? opt.section : '')};
state.cur_val = pageName; //note we update this after we use it.
//at some point add timestamp for editconflict.
var innerWrapper = function (ok, doc) {
if (!ok) throw new Error('Error editing (CAPTCHA?; revcoverable)');
var edit = doc.getElementsByTagName('edit');
if (edit) edit = edit[0];
var newrevid = edit.getAttribute('newrevid');
if (newrevid) state.lastSaveRev = newrevid;
next._startExec(state);
}
Bawolff.mwapi.edit(editArg, innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
/** Sight a paticular revision
* takes revision from result of last save or first arg.
* 2nd arg is level. 1 for sight, 0 for unsight (default 1).
*/
Bawolff.APIC.prototype.sightByRev = function(revision, level) {
if (level == undefined) level = 1;
var outerWrapper = function (next, state) {
if (!revision) {
revision = state.lastSaveRev;
}
if (!revision) {
throw new Error('Could not determine which revision to sight');
}
//at some point add timestamp for editconflict.
var innerWrapper = function (p) {
next._startExec(state);
}
Bawolff.mwapi.sight({revid: revision, level: level, comment: state.summary}, innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
//http://en.wikinews.org/w/api.php?action=parse&text={{template:Lead_article_3}}&prop=text&title=Main_Page
//takes wikitext. optional context title (for {{PAGENAME}}) and boolean noPST to stop post save transform.
Bawolff.APIC.prototype.parse = function(title, noPST) {
var outerWrapper = function (next, state) {
var reqObj = {action: 'parse', prop: 'text'};
reqObj.text = state.cur_val;
if (title !== undefined) {
reqObj.title = title;
}
if (!noPST) { //<nowiki>pre-save transform. aka [[w:Foo|]] -> [[w:Foo|Foo]]</nowiki>
reqObj.pst = 'true';
}
var req = new Bawolff.mwapi.Request(reqObj, 'POST'); //to avoid 414 error, (from long uri) this is post
var innerWrapper = function (doc) {
var parseTextsArray = doc.getElementsByTagName('text');
if (!parseTextsArray || parseTextsArray.length < 1) {
throw new Error('Could not retrieve input. (on parse)');
}
if (parseTextsArray[0].normalize) parseTextsArray[0].normalize();
var parseText = parseTextsArray[0].firstChild.data;
state.cur_val = parseText;
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
//1 arg, name of page. optional, defaults to prev func value.
Bawolff.APIC.prototype.parsePage = function(pageName) {
var outerWrapper = function (next, state) {
var reqObj = {action: 'parse', prop: 'text'};
if (state.follow_redirect) {
reqObj.redirects = 'true';
}
reqObj.page = (pageName ? pageName : state.cur_val);
var req = new Bawolff.mwapi.Request(reqObj);
var innerWrapper = function (doc) {
var parseTextsArray = doc.getElementsByTagName('text');
if (!parseTextsArray) {
throw new Error('Could not retrieve input. (on parse)');
}
if (parseTextsArray[0].normalize) parseTextsArray[0].normalize();
var parseText = parseTextsArray[0].firstChild.data;
state.cur_val = parseText;
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.renderPage = Bawolff.APIC.prototype.parsePage;
Bawolff.APIC.prototype.expandTemplates = function(text) {
var outerWrapper = function (next, state) {
var reqObj = {action: 'expandtemplates', prop: 'wikitext'};
reqObj.text = state.cur_val;
if (title !== undefined) {
reqObj.title = title;
}
var req = new Bawolff.mwapi.Request(reqObj, 'POST'); //to avoid 414 error, (from long uri) this is post
var innerWrapper = function (doc) {
var parseTextsArray = doc.getElementsByTagName('wikitext');
if (!parseTextsArray) {
throw new Error('Could not retrieve input. (on expandTemplates)');
}
if (parseTextsArray[0].normalize) parseTextsArray[0].normalize();
var parseText = parseTextsArray[0].firstChild.data;
state.cur_val = parseText;
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.pagesInCat = function(arg) {
var outerWrapper = function (next, state) {
var reqObj = {action: 'expandtemplates', prop: 'wikitext'};
var cat = state.cur_val
if (arg !== undefined) {
cat = arg; //override prev value
}
reqObj.text = '{{PAGESINCAT:' + cat.replace(/\}\|/g, '') + '|R}}';
var req = new Bawolff.mwapi.Request(reqObj, 'POST'); //to avoid 414 error, (from long uri) this is post
var innerWrapper = function (doc) {
var parseTextsArray = doc.getElementsByTagName('wikitext');
if (!parseTextsArray) {
throw new Error('Could not retrieve input. (on expandTemplates - pagesincat)');
}
if (parseTextsArray[0].normalize) parseTextsArray[0].normalize();
var parseText = parseTextsArray[0].firstChild.data;
state.cur_val = parseText;
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
/*
Takes two arguments, both functions.
first function is passed the return of the last func in chain, and should return a req object. or could be a req object
(aka a associative array of args to pass to api: {action: 'query', meta: 'siteinfo'...)
2nd function takes the xmlDocument returned from the ajax, and does something with it.
*/
Bawolff.APIC.prototype.makeRequest = function(reqFormatter, callback) {
var outerWrapper = function (next, state) {
var reqObj;
if (typeof reqObj === "function") {
reqObj = reqFormatter(state.cur_val);
}
else if (typeof reqFormatter === "object") {
reqObj = reqFormatter;
}
else {
throw new Error("Inapropriate argument to makeRequest. should be either function or associative array specifying args to api");
}
var req = new Bawolff.mwapi.Request(reqObj, 'POST');
//always use post, since it works for everything.
var innerWrapper = function (doc) {
state.cur_val = callback(doc);
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}
Bawolff.APIC.prototype.checkPageExists = function(page) {
var outerWrapper = function (next, state) {
if (!page) page = state.cur_val;
var reqObj = {'titles': page, 'action': 'query'}
var req = new Bawolff.mwapi.Request(reqObj);
var innerWrapper = function (doc) {
//this will throw all kinds of errors in case of bad resp...
var foo = doc.getElementsByTagName('query')[0].getElementsByTagName('pages')[0].getElementsByTagName('page')[0];
state.cur_val = !_hasAttribute(foo, 'missing');
next._startExec(state);
}
req.send(innerWrapper);
}
return new Bawolff.APIC(this.start /*start*/, this, outerWrapper);
}