2 * MediaWiki Widgets - MediaResourceProvider class.
4 * @copyright 2011-2016 VisualEditor Team and others; see AUTHORS.txt
5 * @license The MIT License (MIT); see LICENSE.txt
10 * @classdesc Media resource provider.
13 * @extends mw.widgets.APIResultsProvider
16 * @description Create an instance of `mw.widgets.MediaResourceProvider`.
17 * @param {string} apiurl The API url
18 * @param {Object} [config] Configuration options
19 * @param {string} [config.scriptDirUrl] The url of the API script
21 mw.widgets.MediaResourceProvider = function MwWidgetsMediaResourceProvider( apiurl, config ) {
22 config = config || {};
25 mw.widgets.MediaResourceProvider.super.call( this, apiurl, config );
27 // Fetching configuration
28 this.scriptDirUrl = config.scriptDirUrl;
29 this.isLocal = config.local !== undefined;
32 this.setAPIurl( mw.util.wikiScript( 'api' ) );
34 // If 'apiurl' is set, use that. Otherwise, build the url
35 // from scriptDirUrl and /api.php suffix
36 this.setAPIurl( this.getAPIurl() || ( this.scriptDirUrl + '/api.php' ) );
39 this.siteInfoPromise = null;
45 OO.inheritClass( mw.widgets.MediaResourceProvider, mw.widgets.APIResultsProvider );
52 mw.widgets.MediaResourceProvider.prototype.getStaticParams = function () {
56 mw.widgets.MediaResourceProvider.super.prototype.getStaticParams.call( this ),
59 iiprop: 'dimensions|url|mediatype|extmetadata|timestamp|user',
60 iiextmetadatalanguage: this.getLang(),
67 * Initialize the source and get the site info.
69 * Connect to the api url and retrieve the siteinfo parameters
70 * that are required for fetching results.
72 * @return {jQuery.Promise} Promise that resolves when the class
75 mw.widgets.MediaResourceProvider.prototype.loadSiteInfo = function () {
77 if ( !this.siteInfoPromise ) {
78 this.siteInfoPromise = new mw.Api().get( {
83 this.setImageSizes( data.query.general.imagelimits || [] );
84 this.setThumbSizes( data.query.general.thumblimits || [] );
86 // Standard width per resource
87 iiurlwidth: this.getStandardWidth()
91 return this.siteInfoPromise;
95 * Override parent method and get results from the source.
97 * @param {number} [howMany] The number of items to pull from the API
98 * @return {jQuery.Promise} Promise that is resolved into an array
99 * of available results, or is rejected if no results are available.
101 mw.widgets.MediaResourceProvider.prototype.getResults = function ( howMany ) {
105 return this.loadSiteInfo()
108 return $.Deferred().reject();
110 xhr = this.fetchAPIresults( howMany );
115 if ( !results || results.length === 0 ) {
116 this.toggleDepleted( true );
121 // Process failed, return an empty promise
123 this.toggleDepleted( true );
124 return $.Deferred().resolve( [] );
127 .promise( { abort: function () {
136 * Get continuation API data.
138 * @param {number} howMany The number of results to retrieve
139 * @return {Object} API request data
141 mw.widgets.MediaResourceProvider.prototype.getContinueData = function () {
146 * Set continuation data for the next page.
148 * @param {Object} continueData Continuation data
150 mw.widgets.MediaResourceProvider.prototype.setContinue = function () {
156 * @param {Object[]} results API results
157 * @return {Object[]} Sorted results
159 mw.widgets.MediaResourceProvider.prototype.sort = function ( results ) {
164 * Call the API for search results.
166 * @param {number} howMany The number of results to retrieve
167 * @return {jQuery.Promise} Promise that resolves with an array of objects that contain
170 mw.widgets.MediaResourceProvider.prototype.fetchAPIresults = function ( howMany ) {
171 if ( !this.isValid() ) {
172 return $.Deferred().reject().promise( { abort: function () {} } );
175 const api = this.isLocal ? new mw.Api() : new mw.ForeignApi( this.getAPIurl(), { anonymous: true } );
176 const xhr = api.get( Object.assign( {}, this.getStaticParams(), this.getUserParams(), this.getContinueData( howMany ) ) );
182 this.toggleDepleted( true );
186 if ( data.continue ) {
187 // Update the offset for next time
188 this.setContinue( data.continue );
190 // This is the last available set of results. Mark as depleted!
191 this.toggleDepleted( true );
194 // If the source returned no results, it will not have a
197 const raw = data.query.pages;
199 // Strip away the page ids
200 for ( const page in raw ) {
201 if ( !raw[ page ].imageinfo ) {
202 // The search may give us pages that belong to the File:
203 // namespace but have no files in them, either because
204 // they were deleted or imported wrongly, or just started
205 // as pages. In that case, the response will not include
206 // imageinfo. Skip those files.
209 const newObj = raw[ page ].imageinfo[ 0 ];
210 newObj.title = raw[ page ].title;
211 newObj.index = raw[ page ].index;
212 results.push( newObj );
216 return this.sort( results );
218 .promise( { abort: xhr.abort } );
224 * @param {string} name
226 mw.widgets.MediaResourceProvider.prototype.setName = function ( name ) {
233 * @return {string} name
235 mw.widgets.MediaResourceProvider.prototype.getName = function () {
240 * Get standard width, based on the provider source's thumb sizes.
242 * @return {number|undefined} fetchWidth
244 mw.widgets.MediaResourceProvider.prototype.getStandardWidth = function () {
245 return ( this.thumbSizes && this.thumbSizes[ this.thumbSizes.length - 1 ] ) ||
246 ( this.imageSizes && this.imageSizes[ 0 ] ) ||
247 // Fall back on a number
254 * @return {string} prop
256 mw.widgets.MediaResourceProvider.prototype.getFetchProp = function () {
257 return this.fetchProp;
263 * @param {string} prop
265 mw.widgets.MediaResourceProvider.prototype.setFetchProp = function ( prop ) {
266 this.fetchProp = prop;
272 * @param {number[]} sizes Available thumbnail sizes
274 mw.widgets.MediaResourceProvider.prototype.setThumbSizes = function ( sizes ) {
275 this.thumbSizes = sizes;
281 * @param {number[]} sizes Available image sizes
283 mw.widgets.MediaResourceProvider.prototype.setImageSizes = function ( sizes ) {
284 this.imageSizes = sizes;
290 * @return {number[]} sizes Available thumbnail sizes
292 mw.widgets.MediaResourceProvider.prototype.getThumbSizes = function () {
293 return this.thumbSizes;
299 * @return {number[]} sizes Available image sizes
301 mw.widgets.MediaResourceProvider.prototype.getImageSizes = function () {
302 return this.imageSizes;
306 * Check if this source is valid.
308 * @return {boolean} Source is valid
310 mw.widgets.MediaResourceProvider.prototype.isValid = function () {
311 return this.isLocal ||
312 // If we don't have either 'apiurl' or 'scriptDirUrl'
313 // the source is invalid, and we will skip it
314 this.apiurl !== undefined ||
315 this.scriptDirUrl !== undefined;