Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/resources/src/mediawiki.api/index.js
Ðазад
( function () { /** * @typedef {Object} mw.Api.Options * @property {Object} [parameters = { action: 'query', format: 'json' }] Default query * parameters for API requests * @property {Object} [ajax = { url: mw.util.wikiScript( 'api' ), timeout: 30 * 1000, dataType: 'json' }] * Default options for jQuery#ajax * @property {boolean} [useUS] Whether to use U+001F when joining multi-valued * parameters (since 1.28). Default is true if ajax.url is not set, false otherwise for * compatibility. */ /** * @private * @type {mw.Api.Options} */ let defaultOptions = null; /** * @classdesc Interact with the MediaWiki API. `mw.Api` is a client library for * the [action API](https://www.mediawiki.org/wiki/Special:MyLanguage/API:Main_page). * An `mw.Api` object represents the API of a MediaWiki site. For the REST API, * see {@link mw.Rest}. * * ``` * var api = new mw.Api(); * api.get( { * action: 'query', * meta: 'userinfo' * } ).then( function ( data ) { * console.log( data ); * } ); * ``` * * Since MW 1.25, multiple values for a parameter can be specified using an array: * * ``` * var api = new mw.Api(); * api.get( { * action: 'query', * meta: [ 'userinfo', 'siteinfo' ] // same effect as 'userinfo|siteinfo' * } ).then( function ( data ) { * console.log( data ); * } ); * ``` * * Since MW 1.26, boolean values for API parameters can be specified natively. Parameter * values set to `false` or `undefined` will be omitted from the request, as required by * the API. * * @class mw.Api * @constructor * @description Create an instance of `mw.Api`. * @param {mw.Api.Options} [options] See {@link mw.Api.Options}. This can also be overridden for * each request by passing them to [get()]{@link mw.Api#get} or [post()]{@link mw.Api#post} (or directly to * [ajax()]{@link mw.Api#ajax}) later on. */ mw.Api = function ( options ) { const defaults = Object.assign( {}, options ), setsUrl = options && options.ajax && options.ajax.url !== undefined; defaults.parameters = Object.assign( {}, defaultOptions.parameters, defaults.parameters ); defaults.ajax = Object.assign( {}, defaultOptions.ajax, defaults.ajax ); // Force a string if we got a mw.Uri object if ( setsUrl ) { defaults.ajax.url = String( defaults.ajax.url ); } if ( defaults.useUS === undefined ) { defaults.useUS = !setsUrl; } this.defaults = defaults; this.requests = []; }; /** * @private * @type {mw.Api.Options} */ defaultOptions = { parameters: { action: 'query', format: 'json' }, ajax: { url: mw.util.wikiScript( 'api' ), timeout: 30 * 1000, // 30 seconds dataType: 'json' } }; function mapLegacyToken( action ) { // Legacy types for backward-compatibility with API action=tokens. const csrfActions = [ 'edit', 'delete', 'protect', 'move', 'block', 'unblock', 'email', 'import', 'options' ]; if ( csrfActions.indexOf( action ) !== -1 ) { mw.track( 'mw.deprecate', 'apitoken_' + action ); mw.log.warn( 'Use of the "' + action + '" token is deprecated. Use "csrf" instead.' ); return 'csrf'; } return action; } function createTokenCache() { const tokenPromises = {}; // Pre-populate with fake ajax promises to avoid HTTP requests for tokens that // we already have on the page from the embedded user.options module (T36733). tokenPromises[ defaultOptions.ajax.url ] = {}; const tokens = mw.user.tokens.get(); for ( const tokenKey in tokens ) { const value = tokens[ tokenKey ]; // This requires #getToken to use the same key as mw.user.tokens. // Format: token-type + "Token" (eg. csrfToken, patrolToken, watchToken). tokenPromises[ defaultOptions.ajax.url ][ tokenKey ] = $.Deferred() .resolve( value ) .promise( { abort: function () {} } ); } return tokenPromises; } // Keyed by ajax url and symbolic name for the individual request let promises = createTokenCache(); mw.Api.prototype = { /** * Abort all unfinished requests issued by this Api object. * * @method */ abort: function () { this.requests.forEach( ( request ) => { if ( request ) { request.abort(); } } ); }, /** * Perform API get request. See [ajax()]{@link mw.Api#ajax} for details. * * @param {Object} parameters * @param {Object} [ajaxOptions] * @return {jQuery.Promise} */ get: function ( parameters, ajaxOptions ) { ajaxOptions = ajaxOptions || {}; ajaxOptions.type = 'GET'; return this.ajax( parameters, ajaxOptions ); }, /** * Perform API post request. See [ajax()]{@link mw.Api#ajax} for details. * * @param {Object} parameters * @param {Object} [ajaxOptions] * @return {jQuery.Promise} */ post: function ( parameters, ajaxOptions ) { ajaxOptions = ajaxOptions || {}; ajaxOptions.type = 'POST'; return this.ajax( parameters, ajaxOptions ); }, /** * Massage parameters from the nice format we accept into a format suitable for the API. * * NOTE: A value of undefined/null in an array will be represented by Array#join() * as the empty string. Should we filter silently? Warn? Leave as-is? * * @private * @param {Object} parameters (modified in-place) * @param {boolean} useUS Whether to use U+001F when joining multivalued parameters. */ preprocessParameters: function ( parameters, useUS ) { let key; // Handle common MediaWiki API idioms for passing parameters for ( key in parameters ) { // Multiple values are pipe-separated if ( Array.isArray( parameters[ key ] ) ) { if ( !useUS || parameters[ key ].join( '' ).indexOf( '|' ) === -1 ) { parameters[ key ] = parameters[ key ].join( '|' ); } else { parameters[ key ] = '\x1f' + parameters[ key ].join( '\x1f' ); } } else if ( parameters[ key ] === false || parameters[ key ] === undefined ) { // Boolean values are only false when not given at all delete parameters[ key ]; } } }, /** * Perform the API call. * * @param {Object} parameters Parameters to the API. See also {@link mw.Api.Options} * @param {Object} [ajaxOptions] Parameters to pass to jQuery.ajax. See also * {@link mw.Api.Options} * @return {jQuery.Promise} A promise that settles when the API response is processed. * Has an 'abort' method which can be used to abort the request. * * - On success, resolves to `( result, jqXHR )` where `result` is the parsed API response. * - On an API error, rejects with `( code, result, result, jqXHR )` where `code` is the * [API error code](https://www.mediawiki.org/wiki/API:Errors_and_warnings), and `result` * is as above. When there are multiple errors, the code from the first one will be used. * If there is no error code, "unknown" is used. * - On other types of errors, rejects with `( 'http', details )` where `details` is an object * with three fields: `xhr` (the jqXHR object), `textStatus`, and `exception`. * The meaning of the last two fields is as follows: * - When the request is aborted (the abort method of the promise is called), textStatus * and exception are both set to "abort". * - On a network timeout, textStatus and exception are both set to "timeout". * - On a network error, textStatus is "error" and exception is the empty string. * - When the HTTP response code is anything other than 2xx or 304 (the API does not * use such response codes but some intermediate layer might), textStatus is "error" * and exception is the HTTP status text (the text following the status code in the * first line of the server response). For HTTP/2, `exception` is always an empty string. * - When the response is not valid JSON but the previous error conditions aren't met, * textStatus is "parsererror" and exception is the exception object thrown by * {@link JSON.parse}. */ ajax: function ( parameters, ajaxOptions ) { const api = this, apiDeferred = $.Deferred(); parameters = Object.assign( {}, this.defaults.parameters, parameters ); ajaxOptions = Object.assign( {}, this.defaults.ajax, ajaxOptions ); let token; // Ensure that token parameter is last (per [[mw:API:Edit#Token]]). if ( parameters.token ) { token = parameters.token; delete parameters.token; } this.preprocessParameters( parameters, this.defaults.useUS ); // If multipart/form-data has been requested and emulation is possible, emulate it if ( ajaxOptions.type === 'POST' && window.FormData && ajaxOptions.contentType === 'multipart/form-data' ) { const formData = new FormData(); for ( const key in parameters ) { formData.append( key, parameters[ key ] ); } // If we extracted a token parameter, add it back in. if ( token ) { formData.append( 'token', token ); } ajaxOptions.data = formData; // Prevent jQuery from mangling our FormData object ajaxOptions.processData = false; // Prevent jQuery from overriding the Content-Type header ajaxOptions.contentType = false; } else { // This works because jQuery accepts data as a query string or as an Object ajaxOptions.data = $.param( parameters ); // If we extracted a token parameter, add it back in. if ( token ) { ajaxOptions.data += '&token=' + encodeURIComponent( token ); } if ( ajaxOptions.contentType === 'multipart/form-data' ) { // We were asked to emulate but can't, so drop the Content-Type header, otherwise // it'll be wrong and the server will fail to decode the POST body delete ajaxOptions.contentType; } } // Make the AJAX request const xhr = $.ajax( ajaxOptions ) // If AJAX fails, reject API call with error code 'http' // and the details in the second argument. .fail( ( jqXHR, textStatus, exception ) => { apiDeferred.reject( 'http', { xhr: jqXHR, textStatus: textStatus, exception: exception } ); } ) // AJAX success just means "200 OK" response, also check API error codes .done( ( result, textStatus, jqXHR ) => { let code; if ( result === undefined || result === null || result === '' ) { apiDeferred.reject( 'ok-but-empty', 'OK response but empty result (check HTTP headers?)', result, jqXHR ); } else if ( result.error ) { // errorformat=bc code = result.error.code === undefined ? 'unknown' : result.error.code; apiDeferred.reject( code, result, result, jqXHR ); } else if ( result.errors ) { // errorformat!=bc code = result.errors[ 0 ].code === undefined ? 'unknown' : result.errors[ 0 ].code; apiDeferred.reject( code, result, result, jqXHR ); } else { apiDeferred.resolve( result, jqXHR ); } } ); const requestIndex = this.requests.length; this.requests.push( xhr ); xhr.always( () => { api.requests[ requestIndex ] = null; } ); // Return the Promise return apiDeferred.promise( { abort: xhr.abort } ).fail( ( code, details ) => { if ( !( code === 'http' && details && details.textStatus === 'abort' ) ) { mw.log( 'mw.Api error: ', code, details ); } } ); }, /** * Post to API with the specified type of token. If we have no token, get one and try to post. * If we already have a cached token, try using that, and if the request fails using the cached token, * blank it out and start over. * * @example <caption>For example, to change a user option, you could do:</caption> * new mw.Api().postWithToken( 'csrf', { * action: 'options', * optionname: 'gender', * optionvalue: 'female' * } ); * * @param {string} tokenType The name of the token, like options or edit. * @param {Object} params API parameters * @param {Object} [ajaxOptions] * @return {jQuery.Promise} See [post()]{@link mw.Api#post} * @since 1.22 */ postWithToken: function ( tokenType, params, ajaxOptions ) { const api = this, assertParams = { assert: params.assert, assertuser: params.assertuser }, abortedPromise = $.Deferred().reject( 'http', { textStatus: 'abort', exception: 'abort' } ).promise(); let abortable, aborted; return api.getToken( tokenType, assertParams ).then( ( token ) => { params.token = token; // Request was aborted while token request was running, but we // don't want to unnecessarily abort token requests, so abort // a fake request instead if ( aborted ) { return abortedPromise; } return ( abortable = api.post( params, ajaxOptions ) ).catch( // Error handler function ( code ) { if ( code === 'badtoken' ) { api.badToken( tokenType ); // Try again, once params.token = undefined; abortable = null; return api.getToken( tokenType, assertParams ).then( ( t ) => { params.token = t; if ( aborted ) { return abortedPromise; } return ( abortable = api.post( params, ajaxOptions ) ); } ); } // Let caller handle the error code return $.Deferred().rejectWith( this, arguments ); } ); } ).promise( { abort: function () { if ( abortable ) { abortable.abort(); } else { aborted = true; } } } ); }, /** * Get a token for a certain action from the API. * * @since 1.22 * @param {string} type Token type * @param {Object|string} [additionalParams] Additional parameters for the API (since 1.35). * When given a string, it's treated as the 'assert' parameter (since 1.25). * @return {jQuery.Promise<string>} Received token. */ getToken: function ( type, additionalParams ) { type = mapLegacyToken( type ); if ( typeof additionalParams === 'string' ) { additionalParams = { assert: additionalParams }; } const cacheKey = type + 'Token'; let promiseGroup = promises[ this.defaults.ajax.url ]; if ( !promiseGroup ) { promiseGroup = promises[ this.defaults.ajax.url ] = {}; } let promise = promiseGroup && promiseGroup[ cacheKey ]; function reject() { // Clear cache. Do not cache errors. delete promiseGroup[ cacheKey ]; // Let caller handle the error code return $.Deferred().rejectWith( this, arguments ); } if ( !promise ) { const apiPromise = this.get( Object.assign( { action: 'query', meta: 'tokens', type: type }, additionalParams ) ); promise = apiPromise .then( ( res ) => { if ( !res.query ) { return reject( 'query-missing', res ); } // If the token type is unknown, it is omitted from the response if ( !res.query.tokens[ type + 'token' ] ) { return $.Deferred().reject( 'token-missing', res ); } return res.query.tokens[ type + 'token' ]; }, reject ) // Preserve abort handler .promise( { abort: apiPromise.abort } ); // Optimization: Store the promise so we can reuse it immediately, even when // other async code requests before this one finishes. promiseGroup[ cacheKey ] = promise; } return promise; }, /** * Indicate that the cached token for a certain action of the API is bad. * * Call this if you get a 'badtoken' error when using the token returned by [getToken()]{@link mw.Api#getToken}. * You may also want to use [postWithToken()]{@link mw.Api#postWithToken} instead, which invalidates bad cached tokens * automatically. * * @param {string} type Token type * @since 1.26 */ badToken: function ( type ) { const promiseGroup = promises[ this.defaults.ajax.url ]; type = mapLegacyToken( type ); if ( promiseGroup ) { delete promiseGroup[ type + 'Token' ]; } }, /** * Given an API response indicating an error, get a jQuery object containing a human-readable * error message that you can display somewhere on the page. * * For better quality of error messages, it's recommended to use the following options in your * API queries: * * ``` * errorformat: 'html', * errorlang: mw.config.get( 'wgUserLanguage' ), * errorsuselocal: true, * ``` * * Error messages, particularly for editing pages, may consist of multiple paragraphs of text. * Your user interface should have enough space for that. * * @example * var api = new mw.Api(); * // var title = 'Test valid title'; * var title = 'Test invalid title <>'; * api.postWithToken( 'watch', { * action: 'watch', * title: title * } ).then( function ( data ) { * mw.notify( 'Success!' ); * }, function ( code, data ) { * mw.notify( api.getErrorMessage( data ), { type: 'error' } ); * } ); * * @param {Object} data API response indicating an error * @return {jQuery} Error messages, each wrapped in a `<div>` */ getErrorMessage: function ( data ) { if ( data === undefined || data === null || data === '' || // The #ajax method returns the data like this, it's not my fault... data === 'OK response but empty result (check HTTP headers?)' ) { // The server failed so horribly that it did not set a HTTP error status return $( '<div>' ).append( mw.message( 'api-clientside-error-invalidresponse' ).parseDom() ); } else if ( data.xhr ) { if ( data.textStatus === 'timeout' ) { // Hit the timeout (as defined above in defaultOptions) return $( '<div>' ).append( mw.message( 'api-clientside-error-timeout' ).parseDom() ); } else if ( data.textStatus === 'abort' ) { // The request was cancelled by calling the abort() method on the promise return $( '<div>' ).append( mw.message( 'api-clientside-error-aborted' ).parseDom() ); } else if ( data.textStatus === 'parsererror' ) { // Server returned invalid JSON // data.exception is probably a SyntaxError exception return $( '<div>' ).append( mw.message( 'api-clientside-error-invalidresponse' ).parseDom() ); } else if ( data.xhr.status ) { // Server HTTP error // data.exception is probably the HTTP "reason phrase", e.g. "Internal Server Error" return $( '<div>' ).append( mw.message( 'api-clientside-error-http', data.xhr.status ).parseDom() ); } else { // We don't know the status of the HTTP request. Common causes include (we have no way // to distinguish these): user losing their network connection (request wasn't even sent), // misconfigured CORS for cross-wiki queries. return $( '<div>' ).append( mw.message( 'api-clientside-error-noconnect' ).parseDom() ); } } else if ( data.error ) { // errorformat: 'bc' (or not specified) return $( '<div>' ).text( data.error.info ); } else if ( data.errors ) { // errorformat: 'html' return $( data.errors.map( ( err ) => { // formatversion: 1 / 2 const $node = $( '<div>' ).html( err[ '*' ] || err.html ); return $node[ 0 ]; } ) ); } else { // The server returned some valid but bogus JSON that probably doesn't even come from our API, // or this method was called incorrectly (e.g. with a successful response) mw.log.warn( 'mw.Api#getErrorMessage could not handle the response:', data ); return $( '<div>' ).append( mw.message( 'api-clientside-error-invalidresponse' ).parseDom() ); } } }; if ( window.QUnit ) { mw.Api.resetTokenCacheForTest = function () { promises = createTokenCache(); }; } }() );
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка