2 * @class mw.Api.plugin.options
6 var saveOptionsRequests
= {};
8 $.extend( mw
.Api
.prototype, {
11 * Asynchronously save the value of a single user option using the API. See #saveOptions.
13 * @param {string} name
14 * @param {string|null} value
15 * @return {jQuery.Promise}
17 saveOption: function ( name
, value
) {
19 param
[ name
] = value
;
20 return this.saveOptions( param
);
24 * Asynchronously save the values of user options using the API.
26 * If a value of `null` is provided, the given option will be reset to the default value.
28 * Any warnings returned by the API, including warnings about invalid option names or values,
29 * are ignored. However, do not rely on this behavior.
31 * If necessary, the options will be saved using several sequential API requests. Only one promise
32 * is always returned that will be resolved when all requests complete.
34 * If a request from a previous #saveOptions call is still pending, this will wait for it to be
35 * completed, otherwise MediaWiki gets sad. No requests are sent for anonymous users, as they
36 * would fail anyway. See T214963.
38 * @param {Object} options Options as a `{ name: value, … }` object
39 * @return {jQuery.Promise}
41 saveOptions: function ( options
) {
42 var name
, value
, bundleable
,
46 // Logged-out users can't have user options; we can't depend on mw.user, that'd be circular
47 if ( mw
.config
.get( 'wgUserName' ) === null ) {
48 return $.Deferred().reject( 'notloggedin' ).promise();
51 // If another options request to this API is pending, wait for it first
53 saveOptionsRequests
[ this.defaults
.ajax
.url
] &&
54 // Avoid long chains of promises, they may cause memory leaks
55 saveOptionsRequests
[ this.defaults
.ajax
.url
].state() === 'pending'
57 promise
= saveOptionsRequests
[ this.defaults
.ajax
.url
].then( function () {
58 // Don't expose the old promise's result, it would be confusing
59 return $.Deferred().resolve();
61 return $.Deferred().resolve();
64 promise
= $.Deferred().resolve();
67 for ( name
in options
) {
68 value
= options
[ name
] === null ? null : String( options
[ name
] );
70 // Can we bundle this option, or does it need a separate request?
71 if ( this.defaults
.useUS
) {
72 bundleable
= name
.indexOf( '=' ) === -1;
75 ( value
=== null || value
.indexOf( '|' ) === -1 ) &&
76 ( name
.indexOf( '|' ) === -1 && name
.indexOf( '=' ) === -1 );
80 if ( value
!== null ) {
81 grouped
.push( name
+ '=' + value
);
83 // Omitting value resets the option
87 if ( value
!== null ) {
88 promise
= promise
.then( function ( name
, value
) {
89 return this.postWithToken( 'csrf', {
95 }.bind( this, name
, value
) );
97 // Omitting value resets the option
98 promise
= promise
.then( function ( name
) {
99 return this.postWithToken( 'csrf', {
104 }.bind( this, name
) );
109 if ( grouped
.length
) {
110 promise
= promise
.then( function () {
111 return this.postWithToken( 'csrf', {
119 saveOptionsRequests
[ this.defaults
.ajax
.url
] = promise
;
128 * @mixins mw.Api.plugin.options