Merge "Block.php: replace '*' with explicit fields in selects"
[mediawiki.git] / resources / mediawiki.api / mediawiki.api.js
blob225093b36b19309e0bf3d176a7e6d7a67314cb36
1 /* mw.Api objects represent the API of a particular MediaWiki server. */
3 ( function( $, mw, undefined ) {
5         /**
6          * @var defaultOptions {Object}
7          * We allow people to omit these default parameters from API requests
8          * there is very customizable error handling here, on a per-call basis
9          * wondering, would it be simpler to make it easy to clone the api object,
10          * change error handling, and use that instead?
11          */
12         var defaultOptions = {
14                         // Query parameters for API requests
15                         parameters: {
16                                 action: 'query',
17                                 format: 'json'
18                         },
20                         // Ajax options for jQuery.ajax()
21                         ajax: {
22                                 url: mw.util.wikiScript( 'api' ),
24                                 ok: function() {},
26                                 // caller can supply handlers for http transport error or api errors
27                                 err: function( code, result ) {
28                                         mw.log( 'mw.Api error: ' + code, 'debug' );
29                                 },
31                                 timeout: 30000, // 30 seconds
33                                 dataType: 'json'
34                         }
35                 };
37         /**
38          * Constructor to create an object to interact with the API of a particular MediaWiki server.
39          *
40          * @todo Share API objects with exact same config.
41          * @example
42          * <code>
43          * var api = new mw.Api();
44          * api.get( {
45          *     action: 'query',
46          *     meta: 'userinfo'
47          * }, {
48          *     ok: function () { console.log( arguments ); }
49          * } );
50          * </code>
51          *
52          * @constructor
53          * @param options {Object} See defaultOptions documentation above. Ajax options can also be
54          * overridden for each individual request to jQuery.ajax() later on.
55          */
56         mw.Api = function( options ) {
58                 if ( options === undefined ) {
59                         options = {};
60                 }
62                 // Force toString if we got a mw.Uri object
63                 if ( options.ajax && options.ajax.url !== undefined ) {
64                         options.ajax.url = String( options.ajax.url );
65                 }
67                 options.parameters = $.extend( {}, defaultOptions.parameters, options.parameters );
68                 options.ajax = $.extend( {}, defaultOptions.ajax, options.ajax );
70                 this.defaults = options;
71         };
73         mw.Api.prototype = {
75                 /**
76                  * For api queries, in simple cases the caller just passes a success callback.
77                  * In complex cases they pass an object with a success property as callback and
78                  * probably other options.
79                  * Normalize the argument so that it's always the latter case.
80                  *
81                  * @param {Object|Function} An object contaning one or more of options.ajax,
82                  * or just a success function (options.ajax.ok).
83                  * @return {Object} Normalized ajax options.
84                  */
85                 normalizeAjaxOptions: function( arg ) {
86                         var opt = arg;
87                         if ( typeof arg === 'function' ) {
88                                 opt = { 'ok': arg };
89                         }
90                         if ( !opt.ok ) {
91                                 throw new Error( 'ajax options must include ok callback' );
92                         }
93                         return opt;
94                 },
96                 /**
97                  * Perform API get request
98                  *
99                  * @param {Object} request parameters
100                  * @param {Object|Function} ajax options, or just a success function
101                  * @return {jqXHR}
102                  */
103                 get: function( parameters, ajaxOptions ) {
104                         ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
105                         ajaxOptions.type = 'GET';
106                         return this.ajax( parameters, ajaxOptions );
107                 },
109                 /**
110                  * Perform API post request
111                  * @todo Post actions for nonlocal will need proxy
112                  *
113                  * @param {Object} request parameters
114                  * @param {Object|Function} ajax options, or just a success function
115                  * @return {jqXHR}
116                  */
117                 post: function( parameters, ajaxOptions ) {
118                         ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
119                         ajaxOptions.type = 'POST';
120                         return this.ajax( parameters, ajaxOptions );
121                 },
123                 /**
124                  * Perform the API call.
125                  *
126                  * @param {Object} request parameters
127                  * @param {Object} ajax options
128                  * @return {jqXHR}
129                  */
130                 ajax: function( parameters, ajaxOptions ) {
131                         parameters = $.extend( {}, this.defaults.parameters, parameters );
132                         ajaxOptions = $.extend( {}, this.defaults.ajax, ajaxOptions );
134                         // Some deployed MediaWiki >= 1.17 forbid periods in URLs, due to an IE XSS bug
135                         // So let's escape them here. See bug #28235
136                         // This works because jQuery accepts data as a query string or as an Object
137                         ajaxOptions.data = $.param( parameters ).replace( /\./g, '%2E' );
139                         ajaxOptions.error = function( xhr, textStatus, exception ) {
140                                 ajaxOptions.err( 'http', {
141                                         xhr: xhr,
142                                         textStatus: textStatus,
143                                         exception: exception
144                                 } );
145                         };
147                         // Success just means 200 OK; also check for output and API errors
148                         ajaxOptions.success = function( result ) {
149                                 if ( result === undefined || result === null || result === '' ) {
150                                         ajaxOptions.err( 'ok-but-empty',
151                                                 'OK response but empty result (check HTTP headers?)' );
152                                 } else if ( result.error ) {
153                                         var code = result.error.code === undefined ? 'unknown' : result.error.code;
154                                         ajaxOptions.err( code, result );
155                                 } else {
156                                         ajaxOptions.ok( result );
157                                 }
158                         };
160                         return $.ajax( ajaxOptions );
161                 }
163         };
165         /**
166          * @var {Array} List of errors we might receive from the API.
167          * For now, this just documents our expectation that there should be similar messages
168          * available.
169          */
170         mw.Api.errors = [
171                 // occurs when POST aborted
172                 // jQuery 1.4 can't distinguish abort or lost connection from 200 OK + empty result
173                 'ok-but-empty',
175                 // timeout
176                 'timeout',
178                 // really a warning, but we treat it like an error
179                 'duplicate',
180                 'duplicate-archive',
182                 // upload succeeded, but no image info.
183                 // this is probably impossible, but might as well check for it
184                 'noimageinfo',
185                 // remote errors, defined in API
186                 'uploaddisabled',
187                 'nomodule',
188                 'mustbeposted',
189                 'badaccess-groups',
190                 'stashfailed',
191                 'missingresult',
192                 'missingparam',
193                 'invalid-file-key',
194                 'copyuploaddisabled',
195                 'mustbeloggedin',
196                 'empty-file',
197                 'file-too-large',
198                 'filetype-missing',
199                 'filetype-banned',
200                 'filename-tooshort',
201                 'illegal-filename',
202                 'verification-error',
203                 'hookaborted',
204                 'unknown-error',
205                 'internal-error',
206                 'overwrite',
207                 'badtoken',
208                 'fetchfileerror',
209                 'fileexists-shared-forbidden',
210                 'invalidtitle',
211                 'notloggedin'
212         ];
214         /**
215          * @var {Array} List of warnings we might receive from the API.
216          * For now, this just documents our expectation that there should be similar messages
217          * available.
218          */
219         mw.Api.warnings = [
220                 'duplicate',
221                 'exists'
222         ];
224 })( jQuery, mediaWiki );