change args for feedback and api -- all optional, in array.
[lhc/web/wiklou.git] / resources / mediawiki / mediawiki.api.js
1 /* mw.Api objects represent the API of a particular MediaWiki server. */
2
3 ( function( mw, $j, undefined ) {
4
5 /**
6 * Represents the API of a particular MediaWiki server.
7 *
8 * Required options:
9 * url - complete URL to API endpoint. Usually equivalent to wgServer + wgScriptPath + '/api.php'
10 *
11 * Other options:
12 * can override the parameter defaults and ajax default options.
13 * XXX document!
14 *
15 * TODO share api objects with exact same config.
16 *
17 * ajax options can also be overriden on every get() or post()
18 *
19 * @param options {Mixed} can take many options, but must include at minimum the API url.
20 */
21 mw.Api = function( options ) {
22
23 if ( options === undefined ) {
24 options = {};
25 }
26
27 // make sure we at least have a URL endpoint for the API
28 if ( options.url === undefined ) {
29 options.url = mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/api' + mw.config.get( 'wgScriptExtension' );
30 }
31
32 this.url = options.url;
33
34 /* We allow people to omit these default parameters from API requests */
35 // there is very customizable error handling here, on a per-call basis
36 // wondering, would it be simpler to make it easy to clone the api object, change error handling, and use that instead?
37 this.defaults = {
38 parameters: {
39 action: 'query',
40 format: 'json'
41 },
42
43 ajax: {
44 // force toString if we got a mw.Uri object
45 url: new String( this.url ),
46
47 /* default function for success and no API error */
48 ok: function() {},
49
50 // caller can supply handlers for http transport error or api errors
51 err: function( code, result ) {
52 mw.log( "mw.Api error: " + code, 'debug' );
53 },
54
55 timeout: 30000, /* 30 seconds */
56
57 dataType: 'json'
58
59 }
60 };
61
62
63 if ( options.parameters ) {
64 $j.extend( this.defaults.parameters, options.parameters );
65 }
66
67 if ( options.ajax ) {
68 $j.extend( this.defaults.ajax, options.ajax );
69 }
70 };
71
72 mw.Api.prototype = {
73
74 /**
75 * For api queries, in simple cases the caller just passes a success callback.
76 * In complex cases they pass an object with a success property as callback and probably other options.
77 * Normalize the argument so that it's always the latter case.
78 *
79 * @param {Object|Function} ajax properties, or just a success function
80 * @return Function
81 */
82 normalizeAjaxOptions: function( arg ) {
83 if ( typeof arg === 'function' ) {
84 var ok = arg;
85 arg = { 'ok': ok };
86 }
87 if (! arg.ok ) {
88 throw Error( "ajax options must include ok callback" );
89 }
90 return arg;
91 },
92
93 /**
94 * Perform API get request
95 *
96 * @param {Object} request parameters
97 * @param {Object|Function} ajax properties, or just a success function
98 */
99 get: function( parameters, ajaxOptions ) {
100 ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
101 ajaxOptions.type = 'GET';
102 this.ajax( parameters, ajaxOptions );
103 },
104
105 /**
106 * Perform API post request
107 * TODO post actions for nonlocal will need proxy
108 *
109 * @param {Object} request parameters
110 * @param {Object|Function} ajax properties, or just a success function
111 */
112 post: function( parameters, ajaxOptions ) {
113 ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
114 ajaxOptions.type = 'POST';
115 this.ajax( parameters, ajaxOptions );
116 },
117
118 /**
119 * Perform the API call.
120 *
121 * @param {Object} request parameters
122 * @param {Object} ajax properties
123 */
124 ajax: function( parameters, ajaxOptions ) {
125 parameters = $j.extend( {}, this.defaults.parameters, parameters );
126 ajaxOptions = $j.extend( {}, this.defaults.ajax, ajaxOptions );
127
128 // Some deployed MediaWiki >= 1.17 forbid periods in URLs, due to an IE XSS bug
129 // So let's escape them here. See bug #28235
130 // This works because jQuery accepts data as a query string or as an Object
131 ajaxOptions.data = $j.param( parameters ).replace( /\./g, '%2E' );
132
133 ajaxOptions.error = function( xhr, textStatus, exception ) {
134 ajaxOptions.err( 'http', { xhr: xhr, textStatus: textStatus, exception: exception } );
135 };
136
137
138 /* success just means 200 OK; also check for output and API errors */
139 ajaxOptions.success = function( result ) {
140 if ( result === undefined || result === null || result === '' ) {
141 ajaxOptions.err( "ok-but-empty", "OK response but empty result (check HTTP headers?)" );
142 } else if ( result.error ) {
143 var code = result.error.code === undefined ? 'unknown' : result.error.code;
144 ajaxOptions.err( code, result );
145 } else {
146 ajaxOptions.ok( result );
147 }
148 };
149
150 $j.ajax( ajaxOptions );
151
152 }
153
154 };
155
156 /**
157 * This is a list of errors we might receive from the API.
158 * For now, this just documents our expectation that there should be similar messages
159 * available.
160 */
161 mw.Api.errors = [
162 /* occurs when POST aborted - jQuery 1.4 can't distinguish abort or lost connection from 200 OK + empty result */
163 'ok-but-empty',
164
165 // timeout
166 'timeout',
167
168 /* really a warning, but we treat it like an error */
169 'duplicate',
170 'duplicate-archive',
171
172 /* upload succeeded, but no image info.
173 this is probably impossible, but might as well check for it */
174 'noimageinfo',
175
176 /* remote errors, defined in API */
177 'uploaddisabled',
178 'nomodule',
179 'mustbeposted',
180 'badaccess-groups',
181 'stashfailed',
182 'missingresult',
183 'missingparam',
184 'invalid-file-key',
185 'copyuploaddisabled',
186 'mustbeloggedin',
187 'empty-file',
188 'file-too-large',
189 'filetype-missing',
190 'filetype-banned',
191 'filename-tooshort',
192 'illegal-filename',
193 'verification-error',
194 'hookaborted',
195 'unknown-error',
196 'internal-error',
197 'overwrite',
198 'badtoken',
199 'fetchfileerror',
200 'fileexists-shared-forbidden'
201 ];
202
203 /**
204 * This is a list of warnings we might receive from the API.
205 * For now, this just documents our expectation that there should be similar messages
206 * available.
207 */
208
209 mw.Api.warnings = [
210 'duplicate',
211 'exists'
212 ];
213
214 }) ( window.mediaWiki, jQuery );