User:Bawolff/mwapilib
Mwapilib2 (User:Bawolff/mwapilib2.js)
[edit]This does function chaining api access goodness. The main issues with it is it doesn't handle errors very gracefully. This library depends on User:Bawolff/mwapilib.js and will load it automatically. (If you're wondering, this was written before jQuery was available on wikimedia wikis, there might be better ways to do some of this with jquery).
Quick intro
[edit]This does api requests as a bunch of chained functions. They give context for how to do the request. Each chained function passes its output to the next one's input, kind of like unix pipes. To start off, you do api('initial input'). Chains end with a exec() call. No requests are done until exec() is reached.
Example
[edit]To Append foo to the end of Wikinews:Sandbox page:
api('Wikinews:Sandbox').getPage().lift(function( pageText ) {return pageText + '\nTesting API';}).savePage().exec();
Equivalently you can also do:
api().inject('Wikinews:Sandbox').getPage().lift(function( pageText ) {return pageText + '\nTesting API';}).savePage().exec();
or
api().getPage('Wikinews:Sandbox').lift(function( pageText ) {return pageText + '\nTesting API';}).savePage().exec();
To change the default edit summary:
api('Wikinews:Sandbox').setDefaultSummary('My edit summary').getPage().lift(function( pageText ) {return pageText + '\nTesting API';}).savePage().exec();
the different functions in detail
[edit]All chains start with api(). Note, you cannot do api().api(). If api is already defined as something else, you can use Bawolff.APIC.api()
instead.
.exec() is also special as it denotes an end of a chain. Chains do not start executing until exec() happens.
execute a function in the context
[edit]- func
- lift
This is used to lift a function into the context of the chain. Example:
api('foo').lift(function(input) { return 'a' + input; }).alert().exec()
Pops up with a message afoo
.
Any other arguments fed to lift are given to function.
api('foo').lift(function(a, b) { return a + b; }, 'baz').alert().exec() // returns 'foobaz'
- lift2
Same as lift, except argument 2 that is fed to function is taken from stack. Any other arguments given to lift2 come as arg 3, 4, ...
- alert
Pop up an alert box with current input. Useful for debugging.
Changing input/output
[edit]- All the function ones like
lift
- replace
api('foo').replace(/o/g, 'd').alert().exec(); // Outputs "fdd"
- inject
Change the input variable.
api('foo').inject('bar').alert().exec() // outputs 'bar'
- not
Negate input. Note that types are converted using standard js rules.
Stack stuff
[edit]The function chain also has a stack of other variables. The following mess around with putting input on stack, taking stack onto input, etc.
- pop
- push
- swap
- dup
Additionally lift2
uses the stuff on the stack.
Control stuff
[edit]splitting chain
[edit]If you want to split chain into two parts that are run asynchronously.
- runAsync
- fork
- doQuick
other control stuff
[edit]- abortIfFalse
Stop doing chain if current input is false. often used with .not()
.
Actual api requests
[edit]Configure how to make the request
[edit]- setDefaultSummary
Set the default edit summary. If summary given as first arg, leaves input alone, otherwise takes it from input
- setFollowRedirect
Should the script follow input.
Actual making the request
[edit]- getPage
Get a page
api('Wikinews:Sandbox').getPage().alert().exec();
Note this also sets the default save page target to the last gotten page.
- savePage
Save page. takes content from input, page name from last page requested with getPage, or first argument.
api('Wikinews:Sandbox').getPage().replace(/sand/g, 'Island').savePage().exec(); api('I Want food').savePage('Wikinews:Sandbox').exec()
- sightByRev
(for use with flagged revision). Sight a revision. First argument is revision id, second is sight level (Default to 1). If first argument is undefined, uses revision saved in the chain.
- parse
Parse wikitext (Taken from input), outputting html. First arg (if specified) is title to use for {{PAGENAME}}. Second argument is to supress pre-save transform if set to true.
api('test').parse().alert().exec(); //outputs <a href....
- parsePage (synonym
renderPage
)
Get wikitext for a page.
- expandTemplates
Expand wikitext, giving wikitext without templates.
- pagesInCat
Return number of pages in a category.
- makeRequest
Make a custom api request. Uses mwapilib1 (see below)
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.
- checkPageExists
Returns true if page exists. can be used with abortIfFalse().
Mwapilib1 (User:Bawolff/mwapilib.js)
[edit]User:Bawolff/mwapilib.js Is a javascript library i made in order to make it easier for user javascript (special:gadgets and what not) to use the mediawiki api. So far its really only used by me, but feel free to use it, copy it, modify it, whatever (but if you do please link back to the original).
To use
[edit]If you are on the english Wikinews, add importScript('User:Bawolff/mwapilib.js');
to the top of your js file. If your on a different wiki (say wikipedia) and you want to use it, use importScriptURI('http://en.wikinews.org/w/index.php?title=User%3ABawolff%2Fmwapilib.js&action=raw&ctype=text/javascript');
(if your not on a wikimedia wiki you should probably copy it to a local page and use that instead).
Basics
[edit]
A short example
[edit]
This library is meant to assist using the api. to demonstrate how it works, first lets consider a simple example where we want to get the length of Main Page and Wikinews:Water cooler/technical. (Note: you might want to skip past the example if your just interested in the details about what functions the library defines)
First we create a request object, lets call it req
:
var req = new Bawolff.mwapi.Request({action:'query', prop: "info", titles: 'Main Page|Wikinews:Water cooler/technical'});
This will send a request to the api using the query module, with a prop type of info, and for the pages Main Page and Wikinews:Water cooler/technical. The API uses |
to seperate multiple pages. See mw:Manual:API and http://en.wikinews.org/w/api.php for help on the api itself. When this request is sent (note: creating the request object itself does not send the request), it will return a page roughly equivalent to http://en.wikinews.org/w/api.php?action=query&prop=info&titles=Main%20Page%7CWikinews:Water%20cooler/technical&format=xmlfm (specificly it will do [1]) Which gives us:
<?xml version="1.0"?>
<api>
<query>
<pages>
<page pageid="3" ns="0" title="Main Page" touched="2009-07-10T08:46:20Z" lastrevid="838733" counter="0" length="5734" />
<page pageid="30617" ns="4" title="Wikinews:Water cooler/technical" touched="2009-07-10T03:33:52Z" lastrevid="846342" counter="0" length="42700" />
</pages>
</query>
</api>
Now before we actually send the request, we must first make a callback to handle the above data that we receive back from the server. Since the request is asynchronous, we must decide what to do with the data, before we actually send the request. The callback we make will be passed two arguments, the first being an XMLDocument
representing the response to the request, the second being the actual underlying XMLHttpRequest
object used. In most cases (including this case) we only need the first argument.
In this example, our callback is going to find the lengths of the two pages, and tell it to us in an alert()
box.
function length_callback(doc) {
var pages = doc.getElementsByTagName('page');
var out = 'Page Length Report:';
var title, length;
for (var i = 0; i < pages.length; i++) {
title = pages[i].getAttribute('title');
length = pages[i].getAttribute('length');
out += '\n' + title + ': ' + length;
}
alert(out);
}
Now we're ready to send the request.
req.send(length_callback);
Which should pop up a box that looks like this:
Page Length Report:
Main Page: 5734
Wikinews:Water cooler/technical: 42700
(Numbers were real as of 10:10, 10 July 2009 (UTC). They will obviously change as people edit those pages)
Of course we didn't really check if the api sent us garbage. If there was an explicit error, such as an HTTP error, or an <error>
tag in the api's response, a different callback is called (which by default puts an error message near the site notice (via jsMsg()
. it can be overridden by passing a error callback as the second argument to req.send()
. The error callback also takes two objects, the exception (an Error
object), and the original ajax. for example we could instead do:
req.send(length_callback, function (error) {alert("A bad thing happened: " + error);});
Which will alert us if an error happened (for example if we spelt query quey when originally creating our req
object.
However if we made a non-blatant mistake on our end, such as trying to find the length of a non-existent page, or a page with an invalid title (for example f{oo, our callback will see a <page ns="0" title="Some missing page" missing="" />
or a <page title="f{oo" invalid="" />
respectivly. It will see the title
attribute, but will fail finding the length
attribute, returning null as the length. If we pass it an interwiki link, such as w:Main Page, our callback won't see it at all, as interwiki pagenames return <i title="w:Main Page" iw="w" />
. In a real script you'd probably want to account for these possibilities.
Helper functions
[edit]
The library also defines a series of helper functions, that make it easier to do certain common tasks. For example, if you wanted to add a new section of Wikinews:Sandbox you could do:
var edit_cb = function(doc) {
var edit = doc.getElementsByTagName('edit');
if (edit && edit[0] && edit[0].hasAttribute('result')) {
alert('Result of edit' + edit[0].getAttribute('result'));
return;
}
alert('edit failed');
}
Bawolff.mwapi.edit ({content:'Wohoo! I made a new section, again', summary: 'test', page: 'Wikinews:Sandbox', section: 'new'}, edit_cb)
Chaining requests together
[edit]
Sometimes you need to chain requests together [to be continued]