4 * Create an object like mw.Api, but automatically handling everything required to communicate
5 * with another MediaWiki wiki via cross-origin requests (CORS).
7 * The foreign wiki must be configured to accept requests from the current wiki. See
8 * <https://www.mediawiki.org/wiki/Manual:$wgCrossSiteAJAXdomains> for details.
10 * var api = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
14 * } ).done( function ( data ) {
15 * console.log( data );
18 * To ensure that the user at the foreign wiki is logged in, pass the `assert: 'user'` parameter
19 * to #get/#post (since MW 1.23): if they are not, the API request will fail. (Note that this
20 * doesn't guarantee that it's the same user.)
22 * Authentication-related MediaWiki extensions may extend this class to ensure that the user
23 * authenticated on the current wiki will be automatically authenticated on the foreign one. These
24 * extension modules should be registered using the ResourceLoaderForeignApiModules hook. See
25 * CentralAuth for a practical example. The general pattern to extend and override the name is:
27 * function MyForeignApi() {};
28 * OO.inheritClass( MyForeignApi, mw.ForeignApi );
29 * mw.ForeignApi = MyForeignApi;
31 * @class mw.ForeignApi
36 * @param {string|mw.Uri} url URL pointing to another wiki's `api.php` endpoint.
37 * @param {Object} [options] See mw.Api.
38 * @param {Object} [options.anonymous=false] Perform all requests anonymously. Use this option if
39 * the target wiki may otherwise not accept cross-origin requests, or if you don't need to
40 * perform write actions or read restricted information and want to avoid the overhead.
42 * @author Bartosz DziewoĆski
45 function CoreForeignApi( url
, options
) {
46 if ( !url
|| $.isPlainObject( url
) ) {
47 throw new Error( 'mw.ForeignApi() requires a `url` parameter' );
50 this.apiUrl
= String( url
);
51 this.anonymous
= options
&& options
.anonymous
;
53 options
= $.extend( /* deep=*/ true,
58 withCredentials
: !this.anonymous
62 // Add 'origin' query parameter to all requests.
63 origin
: this.getOrigin()
69 // Call parent constructor
70 CoreForeignApi
.parent
.call( this, options
);
73 OO
.inheritClass( CoreForeignApi
, mw
.Api
);
76 * Return the origin to use for API requests, in the required format (protocol, host and port, if
82 CoreForeignApi
.prototype.getOrigin = function () {
84 if ( this.anonymous
) {
87 origin
= location
.protocol
+ '//' + location
.hostname
;
88 if ( location
.port
) {
89 origin
+= ':' + location
.port
;
97 CoreForeignApi
.prototype.ajax = function ( parameters
, ajaxOptions
) {
98 var url
, origin
, newAjaxOptions
;
100 // 'origin' query parameter must be part of the request URI, and not just POST request body
101 if ( ajaxOptions
.type
=== 'POST' ) {
102 url
= ( ajaxOptions
&& ajaxOptions
.url
) || this.defaults
.ajax
.url
;
103 origin
= ( parameters
&& parameters
.origin
) || this.defaults
.parameters
.origin
;
104 url
+= ( url
.indexOf( '?' ) !== -1 ? '&' : '?' ) +
105 // Depending on server configuration, MediaWiki may forbid periods in URLs, due to an IE 6
106 // XSS bug. So let's escape them here. See WebRequest::checkUrlExtension() and T30235.
107 'origin=' + encodeURIComponent( origin
).replace( /\./g, '%2E' );
108 newAjaxOptions
= $.extend( {}, ajaxOptions
, { url
: url
} );
110 newAjaxOptions
= ajaxOptions
;
113 return CoreForeignApi
.parent
.prototype.ajax
.call( this, parameters
, newAjaxOptions
);
117 mw
.ForeignApi
= CoreForeignApi
;
119 }( mediaWiki
, jQuery
) );