User:Bawolff/mwapilib2.js

From Wikinews, the free news source you can write!
Jump to navigation Jump to search

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);
}