From 4ac9fa081a7c045f6a9f1cfc529d82423f485b2e Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sun, 8 Dec 2013 09:55:49 +0100 Subject: Update to MediaWiki 1.22.0 --- resources/mediawiki.api/mediawiki.api.category.js | 35 ++++----- resources/mediawiki.api/mediawiki.api.edit.js | 65 +---------------- resources/mediawiki.api/mediawiki.api.js | 88 +++++++++++++++++++++-- resources/mediawiki.api/mediawiki.api.login.js | 54 ++++++++++++++ resources/mediawiki.api/mediawiki.api.parse.js | 12 ++-- resources/mediawiki.api/mediawiki.api.watch.js | 12 ++-- 6 files changed, 172 insertions(+), 94 deletions(-) create mode 100644 resources/mediawiki.api/mediawiki.api.login.js (limited to 'resources/mediawiki.api') diff --git a/resources/mediawiki.api/mediawiki.api.category.js b/resources/mediawiki.api/mediawiki.api.category.js index 4de52911..98a9c54b 100644 --- a/resources/mediawiki.api/mediawiki.api.category.js +++ b/resources/mediawiki.api/mediawiki.api.category.js @@ -14,12 +14,13 @@ * @return {boolean} return.done.isCategory Whether the category exists. */ isCategory: function ( title, ok, err ) { - var d = $.Deferred(); + var d = $.Deferred(), + apiPromise; + // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); + d.done( ok ).fail( err ); - this.get( { + apiPromise = this.get( { prop: 'categoryinfo', titles: title.toString() } ) @@ -36,7 +37,7 @@ }) .fail( d.reject ); - return d.promise(); + return d.promise( { abort: apiPromise.abort } ); }, /** @@ -50,13 +51,14 @@ * @return {String[]} return.done.categories Matched categories */ getCategoriesByPrefix: function ( prefix, ok, err ) { - var d = $.Deferred(); + var d = $.Deferred(), + apiPromise; + // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); + d.done( ok ).fail( err ); // Fetch with allpages to only get categories that have a corresponding description page. - this.get( { + apiPromise = this.get( { list: 'allpages', apprefix: prefix, apnamespace: mw.config.get('wgNamespaceIds').category @@ -72,7 +74,7 @@ }) .fail( d.reject ); - return d.promise(); + return d.promise( { abort: apiPromise.abort } ); }, @@ -88,12 +90,13 @@ * if title was not found. */ getCategories: function ( title, ok, err, async ) { - var d = $.Deferred(); + var d = $.Deferred(), + apiPromise; + // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); + d.done( ok ).fail( err ); - this.get( { + apiPromise = this.get( { prop: 'categories', titles: title.toString() }, { @@ -114,10 +117,10 @@ } ); } d.resolve( ret ); - }) + } ) .fail( d.reject ); - return d.promise(); + return d.promise( { abort: apiPromise.abort } ); } } ); diff --git a/resources/mediawiki.api/mediawiki.api.edit.js b/resources/mediawiki.api/mediawiki.api.edit.js index 3c775ad0..cc83a4b8 100644 --- a/resources/mediawiki.api/mediawiki.api.edit.js +++ b/resources/mediawiki.api/mediawiki.api.edit.js @@ -3,9 +3,6 @@ */ ( function ( mw, $ ) { - // Cache token so we don't have to keep fetching new ones for every single request. - var cachedToken = null; - $.extend( mw.Api.prototype, { /** @@ -19,32 +16,7 @@ * @return {jQuery.Promise} See #post */ postWithEditToken: function ( params, ok, err ) { - var useTokenToPost, getTokenIfBad, - api = this; - if ( cachedToken === null ) { - // We don't have a valid cached token, so get a fresh one and try posting. - // We do not trap any 'badtoken' or 'notoken' errors, because we don't want - // an infinite loop. If this fresh token is bad, something else is very wrong. - useTokenToPost = function ( token ) { - params.token = token; - api.post( params, ok, err ); - }; - return api.getEditToken( useTokenToPost, err ); - } else { - // We do have a token, but it might be expired. So if it is 'bad' then - // start over with a new token. - params.token = cachedToken; - getTokenIfBad = function ( code, result ) { - if ( code === 'badtoken' ) { - // force a new token, clear any old one - cachedToken = null; - api.postWithEditToken( params, ok, err ); - } else { - err( code, result ); - } - }; - return api.post( params, { ok : ok, err : getTokenIfBad }); - } + return this.postWithToken( 'edit', params ).done( ok ).fail( err ); }, /** @@ -57,37 +29,7 @@ * @return {string} return.done.token Received token. */ getEditToken: function ( ok, err ) { - var d = $.Deferred(); - // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); - - this.get( { - action: 'tokens', - type: 'edit' - }, { - // Due to the API assuming we're logged out if we pass the callback-parameter, - // we have to disable jQuery's callback system, and instead parse JSON string, - // by setting 'jsonp' to false. - // TODO: This concern seems genuine but no other module has it. Is it still - // needed and/or should we pass this by default? - jsonp: false - } ) - .done( function ( data ) { - var token; - // If token type is not available for this user, - // key 'edittoken' is missing or can contain Boolean false - if ( data.tokens && data.tokens.edittoken ) { - token = data.tokens.edittoken; - cachedToken = token; - d.resolve( token ); - } else { - d.reject( 'token-missing', data ); - } - }) - .fail( d.reject ); - - return d.promise(); + return this.getToken( 'edit' ).done( ok ).fail( err ); }, /** @@ -110,8 +52,7 @@ text: message }, ok, err ); } - - } ); + } ); /** * @class mw.Api diff --git a/resources/mediawiki.api/mediawiki.api.js b/resources/mediawiki.api/mediawiki.api.js index cf7443f3..cdc67679 100644 --- a/resources/mediawiki.api/mediawiki.api.js +++ b/resources/mediawiki.api/mediawiki.api.js @@ -20,7 +20,8 @@ dataType: 'json' } - }; + }, + tokenCache = {}; /** * Constructor to create an object to interact with the API of a particular MediaWiki server. @@ -115,7 +116,8 @@ */ ajax: function ( parameters, ajaxOptions ) { var token, - apiDeferred = $.Deferred(); + apiDeferred = $.Deferred(), + xhr; parameters = $.extend( {}, this.defaults.parameters, parameters ); ajaxOptions = $.extend( {}, this.defaults.ajax, ajaxOptions ); @@ -147,7 +149,7 @@ } // Make the AJAX request - $.ajax( ajaxOptions ) + xhr = $.ajax( ajaxOptions ) // If AJAX fails, reject API call with error code 'http' // and details in second argument. .fail( function ( xhr, textStatus, exception ) { @@ -172,11 +174,85 @@ } ); // Return the Promise - return apiDeferred.promise().fail( function ( code, details ) { + return apiDeferred.promise( { abort: xhr.abort } ).fail( function ( code, details ) { mw.log( 'mw.Api error: ', code, details ); - }); - } + } ); + }, + + /** + * Post to API with specified type of token. If we have no token, get one and try to post. + * If we have a cached token try using that, and if it fails, blank out the + * cached token and start over. For example to change an user option you could do: + * + * new mw.Api().postWithToken( 'options', { + * action: 'options', + * optionname: 'gender', + * optionvalue: 'female' + * } ); + * + * @param {string} tokenType The name of the token, like options or edit. + * @param {Object} params API parameters + * @return {jQuery.Promise} See #post + */ + postWithToken: function ( tokenType, params ) { + var api = this, hasOwn = tokenCache.hasOwnProperty; + if ( hasOwn.call( tokenCache, tokenType ) && tokenCache[tokenType] !== undefined ) { + params.token = tokenCache[tokenType]; + return api.post( params ).then( + null, + function ( code ) { + if ( code === 'badtoken' ) { + // force a new token, clear any old one + tokenCache[tokenType] = params.token = undefined; + return api.post( params ); + } + // Pass the promise forward, so the caller gets error codes + return this; + } + ); + } else { + return api.getToken( tokenType ).then( function ( token ) { + tokenCache[tokenType] = params.token = token; + return api.post( params ); + } ); + } + }, + /** + * Api helper to grab any token. + * + * @param {string} type Token type. + * @return {jQuery.Promise} + * @return {Function} return.done + * @return {string} return.done.token Received token. + */ + getToken: function ( type ) { + var apiPromise, + d = $.Deferred(); + + apiPromise = this.get( { + action: 'tokens', + type: type + }, { + // Due to the API assuming we're logged out if we pass the callback-parameter, + // we have to disable jQuery's callback system, and instead parse JSON string, + // by setting 'jsonp' to false. + // TODO: This concern seems genuine but no other module has it. Is it still + // needed and/or should we pass this by default? + } ) + .done( function ( data ) { + // If token type is not available for this user, + // key '...token' is missing or can contain Boolean false + if ( data.tokens && data.tokens[type + 'token'] ) { + d.resolve( data.tokens[type + 'token'] ); + } else { + d.reject( 'token-missing', data ); + } + } ) + .fail( d.reject ); + + return d.promise( { abort: apiPromise.abort } ); + } }; /** diff --git a/resources/mediawiki.api/mediawiki.api.login.js b/resources/mediawiki.api/mediawiki.api.login.js new file mode 100644 index 00000000..ccbae06c --- /dev/null +++ b/resources/mediawiki.api/mediawiki.api.login.js @@ -0,0 +1,54 @@ +/** + * Make the two-step login easier. + * @author Niklas Laxström + * @class mw.Api.plugin.login + * @since 1.22 + */ +( function ( mw, $ ) { + 'use strict'; + + $.extend( mw.Api.prototype, { + /** + * @param {string} username + * @param {string} password + * @return {jQuery.Promise} See mw.Api#post + */ + login: function ( username, password ) { + var params, request, + deferred = $.Deferred(), + api = this; + + params = { + action: 'login', + lgname: username, + lgpassword: password + }; + + request = api.post( params ); + request.fail( deferred.reject ); + request.done( function ( data ) { + params.lgtoken = data.login.token; + api.post( params ) + .fail( deferred.reject ) + .done( function ( data ) { + var code; + if ( data.login && data.login.result === 'Success' ) { + deferred.resolve( data ); + } else { + // Set proper error code whenever possible + code = data.error && data.error.code || 'unknown'; + deferred.reject( code, data ); + } + } ); + } ); + + return deferred.promise( { abort: request.abort } ); + } + } ); + + /** + * @class mw.Api + * @mixins mw.Api.plugin.login + */ + +}( mediaWiki, jQuery ) ); diff --git a/resources/mediawiki.api/mediawiki.api.parse.js b/resources/mediawiki.api/mediawiki.api.parse.js index ea0388c1..c4d23b82 100644 --- a/resources/mediawiki.api/mediawiki.api.parse.js +++ b/resources/mediawiki.api/mediawiki.api.parse.js @@ -15,13 +15,15 @@ * @return {string} return.done.data Parsed HTML of `wikitext`. */ parse: function ( wikitext, ok, err ) { - var d = $.Deferred(); + var d = $.Deferred(), + apiPromise; + // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); + d.done( ok ).fail( err ); - this.get( { + apiPromise = this.get( { action: 'parse', + contentmodel: 'wikitext', text: wikitext } ) .done( function ( data ) { @@ -31,7 +33,7 @@ } ) .fail( d.reject ); - return d.promise(); + return d.promise( { abort: apiPromise.abort } ); } } ); diff --git a/resources/mediawiki.api/mediawiki.api.watch.js b/resources/mediawiki.api/mediawiki.api.watch.js index c86a90a7..49a4c622 100644 --- a/resources/mediawiki.api/mediawiki.api.watch.js +++ b/resources/mediawiki.api/mediawiki.api.watch.js @@ -19,10 +19,12 @@ * @return {string} return.done.watch.message Parsed HTML of the confirmational interface message */ function doWatchInternal( page, ok, err, addParams ) { - var params, d = $.Deferred(); + var params, + d = $.Deferred(), + apiPromise; + // Backwards compatibility (< MW 1.20) - d.done( ok ); - d.fail( err ); + d.done( ok ).fail( err ); params = { action: 'watch', @@ -35,13 +37,13 @@ $.extend( params, addParams ); } - this.post( params ) + apiPromise = this.post( params ) .done( function ( data ) { d.resolve( data.watch ); } ) .fail( d.reject ); - return d.promise(); + return d.promise( { abort: apiPromise.abort } ); } $.extend( mw.Api.prototype, { -- cgit v1.2.2