User:Bawolff/mwapilib2.js

//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 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'); }
 * takes revision from result of last save or first arg.
 * 2nd arg is level. 1 for sight, 0 for unsight (default 1).

//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=&prop=text&title=Main_Page //takes wikitext. optional context title (for ) 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) { // pre-save transform. aka Foo -> Foo 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); }