Current File : /home/jvzmxxx/wiki/extensions/VisualEditor/modules/ve-mw/dm/models/ve.dm.MWMediaResourceProvider.js
/*!
 * VisualEditor DataModel MWMediaResourceProvider class.
 *
 * @copyright 2011-2016 VisualEditor Team and others; see AUTHORS.txt
 * @license The MIT License (MIT); see LICENSE.txt
 */

/**
 * MediaWiki media resource provider.
 *
 * @class
 * @extends ve.dm.APIResultsProvider
 *
 * @constructor
 * @param {string} apiurl The API url
 * @param {Object} [config] Configuration options
 * @cfg {string} [scriptDirUrl] The url of the API script
 */
ve.dm.MWMediaResourceProvider = function VeDmMWMediaResourceProvider( apiurl, config ) {
	config = config || {};

	// Parent constructor
	ve.dm.MWMediaResourceProvider.super.call( this, apiurl, config );

	// Fetching configuration
	this.scriptDirUrl = config.scriptDirUrl;
	this.isLocal = config.local !== undefined;

	if ( this.isLocal ) {
		this.setAjaxSettings( {
			url: mw.util.wikiScript( 'api' ),
			// If the url is local use json
			dataType: 'json'
		} );
	} else {
		this.setAjaxSettings( {
			// If 'apiurl' is set, use that. Otherwise, build the url
			// from scriptDirUrl and /api.php suffix
			url: this.getAPIurl() || ( this.scriptDirUrl + '/api.php' ),
			// If the url is not the same origin use jsonp
			dataType: 'jsonp',
			// JSON-P requests are not cached by default and get a &_=random trail.
			// While setting cache=true will still bypass cache in most case due to the
			// callback parameter, at least drop the &_=random trail which triggers
			// an API warning (invalid parameter).
			cache: true
		} );
	}
	this.siteInfoPromise = null;
	this.thumbSizes = [];
	this.imageSizes = [];
};

/* Inheritance */
OO.inheritClass( ve.dm.MWMediaResourceProvider, ve.dm.APIResultsProvider );

/* Methods */

/**
 * @inheritdoc
 */
ve.dm.MWMediaResourceProvider.prototype.getStaticParams = function () {
	return $.extend(
		{},
		// Parent method
		ve.dm.MWMediaResourceProvider.super.prototype.getStaticParams.call( this ),
		{
			action: 'query',
			iiprop: 'dimensions|url|mediatype|extmetadata|timestamp|user',
			iiextmetadatalanguage: this.getLang(),
			prop: 'imageinfo'
		}
	);
};

/**
 * Initialize the source and get the site info.
 *
 * Connect to the api url and retrieve the siteinfo parameters
 * that are required for fetching results.
 *
 * @return {jQuery.Promise} Promise that resolves when the class
 * properties are set.
 */
ve.dm.MWMediaResourceProvider.prototype.loadSiteInfo = function () {
	var provider = this;

	if ( !this.siteInfoPromise ) {
		this.siteInfoPromise = new mw.Api().get( {
			action: 'query',
			meta: 'siteinfo'
		} )
			.then( function ( data ) {
				provider.setImageSizes( data.query.general.imagelimits || [] );
				provider.setThumbSizes( data.query.general.thumblimits || [] );
				provider.setUserParams( {
					// Standard width per resource
					iiurlwidth: provider.getStandardWidth()
				} );
			} );
	}
	return this.siteInfoPromise;
};

/**
 * Override parent method and get results from the source
 *
 * @param {number} [howMany] The number of items to pull from the API
 * @return {jQuery.Promise} Promise that is resolved into an array
 * of available results, or is rejected if no results are available.
 */
ve.dm.MWMediaResourceProvider.prototype.getResults = function ( howMany ) {
	var xhr,
		aborted = false,
		provider = this;

	return this.loadSiteInfo()
		.then( function () {
			if ( aborted ) {
				return $.Deferred().reject();
			}
			xhr = provider.fetchAPIresults( howMany );
			return xhr;
		} )
		.then(
			function ( results ) {
				if ( !results || results.length === 0 ) {
					provider.toggleDepleted( true );
					return [];
				}
				return results;
			},
			// Process failed, return an empty promise
			function () {
				provider.toggleDepleted( true );
				return $.Deferred().resolve( [] );
			}
		)
		.promise( { abort: function () {
			aborted = true;
			if ( xhr ) {
				xhr.abort();
			}
		} } );
};

/**
 * Get continuation API data
 *
 * @param {number} howMany The number of results to retrieve
 * @return {Object} API request data
 */
ve.dm.MWMediaResourceProvider.prototype.getContinueData = function () {
	return {};
};

/**
 * Set continuation data for the next page
 *
 * @param {Object} continueData Continuation data
 */
ve.dm.MWMediaResourceProvider.prototype.setContinue = function () {
};

/**
 * Sort the results
 *
 * @param {Object[]} results API results
 * @return {Object[]} Sorted results
 */
ve.dm.MWMediaResourceProvider.prototype.sort = function ( results ) {
	return results;
};

/**
 * Call the API for search results.
 *
 * @param {number} howMany The number of results to retrieve
 * @return {jQuery.Promise} Promise that resolves with an array of objects that contain
 *  the fetched data.
 */
ve.dm.MWMediaResourceProvider.prototype.fetchAPIresults = function ( howMany ) {
	var xhr,
		ajaxOptions = {},
		provider = this;

	if ( !this.isValid() ) {
		return $.Deferred().reject().promise( { abort: $.noop } );
	}

	ajaxOptions = this.getAjaxSettings();

	xhr = new mw.Api().get( $.extend( {}, this.getStaticParams(), this.getUserParams(), this.getContinueData( howMany ) ), ajaxOptions );
	return xhr
		.then( function ( data ) {
			var page, newObj, raw,
				results = [];

			if ( data.error ) {
				provider.toggleDepleted( true );
				return [];
			}

			if ( data.continue ) {
				// Update the offset for next time
				provider.setContinue( data.continue );
			} else {
				// This is the last available set of results. Mark as depleted!
				provider.toggleDepleted( true );
			}

			// If the source returned no results, it will not have a
			// query property
			if ( data.query ) {
				raw = data.query.pages;
				if ( raw ) {
					// Strip away the page ids
					for ( page in raw ) {
						if ( !raw[ page ].imageinfo ) {
							// The search may give us pages that belong to the File:
							// namespace but have no files in them, either because
							// they were deleted or imported wrongly, or just started
							// as pages. In that case, the response will not include
							// imageinfo. Skip those files.
							continue;
						}
						newObj = raw[ page ].imageinfo[ 0 ];
						newObj.title = raw[ page ].title;
						newObj.index = raw[ page ].index;
						results.push( newObj );
					}
				}
			}
			return provider.sort( results );
		} )
		.promise( { abort: xhr.abort } );
};

/**
 * Set name
 *
 * @param {string} name
 */
ve.dm.MWMediaResourceProvider.prototype.setName = function ( name ) {
	this.name = name;
};

/**
 * Get name
 *
 * @return {string} name
 */
ve.dm.MWMediaResourceProvider.prototype.getName = function () {
	return this.name;
};

/**
 * Get standard width, based on the provider source's thumb sizes.
 *
 * @return {number|undefined} fetchWidth
 */
ve.dm.MWMediaResourceProvider.prototype.getStandardWidth = function () {
	return ( this.thumbSizes && this.thumbSizes[ this.thumbSizes.length - 1 ] ) ||
		( this.imageSizes && this.imageSizes[ 0 ] ) ||
		// Fall back on a number
		300;
};

/**
 * Get prop
 *
 * @return {string} prop
 */
ve.dm.MWMediaResourceProvider.prototype.getFetchProp = function () {
	return this.fetchProp;
};

/**
 * Set prop
 *
 * @param {string} prop
 */
ve.dm.MWMediaResourceProvider.prototype.setFetchProp = function ( prop ) {
	this.fetchProp = prop;
};

/**
 * Set thumb sizes
 *
 * @param {number[]} sizes Available thumbnail sizes
 */
ve.dm.MWMediaResourceProvider.prototype.setThumbSizes = function ( sizes ) {
	this.thumbSizes = sizes;
};

/**
 * Set image sizes
 *
 * @param {number[]} sizes Available image sizes
 */
ve.dm.MWMediaResourceProvider.prototype.setImageSizes = function ( sizes ) {
	this.imageSizes = sizes;
};

/**
 * Get thumb sizes
 *
 * @return {number[]} sizes Available thumbnail sizes
 */
ve.dm.MWMediaResourceProvider.prototype.getThumbSizes = function () {
	return this.thumbSizes;
};

/**
 * Get image sizes
 *
 * @return {number[]} sizes Available image sizes
 */
ve.dm.MWMediaResourceProvider.prototype.getImageSizes = function () {
	return this.imageSizes;
};

/**
 * Check if this source is valid.
 *
 * @return {boolean} Source is valid
 */
ve.dm.MWMediaResourceProvider.prototype.isValid = function () {
	return this.isLocal ||
		// If we don't have either 'apiurl' or 'scriptDirUrl'
		// the source is invalid, and we will skip it
		this.apiurl !== undefined ||
		this.scriptDirUrl !== undefined;
};