mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-12-03 18:36:20 +00:00
aa9eb95455
Change the media search widget to work with resource queues and providers. Create providers based on the user's filerepo settings and aggregate their responses with the media queue. Stop asking for more results from providers that are depleted. Also fixes a rather nasty infinite-loop bug where the API returns only very few images, and the UI keeps asking for more. Bug: T78161 Bug: T88764 Change-Id: I65aed3446cd1f056476c56e6e04522c70e49e595
175 lines
4.1 KiB
JavaScript
175 lines
4.1 KiB
JavaScript
/*!
|
|
* VisualEditor DataModel MWMediaResourceQueue class.
|
|
*
|
|
* @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* MediaWiki media resource queue.
|
|
*
|
|
* @class
|
|
* @mixins OO.EventEmitter
|
|
*
|
|
* @constructor
|
|
* @param {Object} [config] Configuration options
|
|
*/
|
|
ve.dm.MWMediaResourceQueue = function VeDmMWMediaResourceQueue( config ) {
|
|
config = config || {};
|
|
|
|
this.fileRepoPromise = null;
|
|
this.providers = [];
|
|
this.providerPromises = [];
|
|
|
|
this.queue = [];
|
|
|
|
this.limit = config.limit || 20;
|
|
this.threshhold = config.threshhold || 10;
|
|
|
|
// Mixin constructors
|
|
OO.EventEmitter.call( this );
|
|
};
|
|
|
|
/* Setup */
|
|
OO.initClass( ve.dm.MWMediaResourceQueue );
|
|
OO.mixinClass( ve.dm.MWMediaResourceQueue, OO.EventEmitter );
|
|
|
|
/**
|
|
* Get items from the queue
|
|
*
|
|
* @param {number} [howMany] How many items to retrieve
|
|
* @return {jQuery.Promise} Promise that resolves into an array of items
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.get = function ( howMany ) {
|
|
var me = this,
|
|
prepared = [];
|
|
|
|
howMany = howMany || this.limit;
|
|
|
|
// Check if the queue has enough items
|
|
if ( this.queue.length < howMany + this.threshhold ) {
|
|
// Call for more results
|
|
prepared.push(
|
|
this.getResults( howMany + this.threshhold )
|
|
.then( function ( items ) {
|
|
// Add to the queue
|
|
me.queue = me.queue.concat.apply( me.queue, items );
|
|
} )
|
|
);
|
|
}
|
|
|
|
return $.when.apply( $, prepared )
|
|
.then( function () {
|
|
return me.queue.splice( 0, howMany );
|
|
} );
|
|
|
|
};
|
|
|
|
/**
|
|
* Get results from all providers
|
|
* @return {jQuery.Promise} Promise that is resolved into an array of fetched items.
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.getResults = function ( howMany ) {
|
|
var i, len,
|
|
queue = this;
|
|
|
|
// Make sure there are resources set up
|
|
return this.setup()
|
|
.then( function () {
|
|
queue.providerPromises = [];
|
|
// Set up the query to all providers
|
|
for ( i = 0, len = queue.providers.length; i < len; i++ ) {
|
|
queue.providers[i].setQuery( queue.getQuery() );
|
|
if ( !queue.providers[i].isDepleted() ) {
|
|
queue.providerPromises.push(
|
|
queue.providers[i].getResults( howMany )
|
|
);
|
|
}
|
|
}
|
|
|
|
return $.when.apply( $, queue.providerPromises )
|
|
.then( Array.prototype.concat.bind( [] ) );
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* Set up the queue and its resources
|
|
*
|
|
* @return {jQuery.Promise} Promise that resolves when the resources are set up
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.setup = function () {
|
|
var i, len,
|
|
queue = this;
|
|
|
|
return this.getFileRepos().then( function ( sources ) {
|
|
if ( queue.providers.length === 0 ) {
|
|
// Set up the providers
|
|
for ( i = 0, len = sources.length; i < len; i++ ) {
|
|
queue.providers.push( new ve.dm.MWMediaResourceProvider( {
|
|
apiurl: sources[i].apiurl,
|
|
name: sources[i].name,
|
|
local: sources[i].local,
|
|
scriptDirUrl: sources[i].scriptDirUrl
|
|
} ) );
|
|
}
|
|
}
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* Fetch the file repos.
|
|
*
|
|
* @return {jQuery.Promise} Promise that resolves when the resources are set up
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.getFileRepos = function () {
|
|
var defaultSource = [ {
|
|
url: mw.util.wikiScript( 'api' ),
|
|
local: true
|
|
} ];
|
|
|
|
if ( !this.fileRepoPromise ) {
|
|
this.fileRepoPromise = ve.init.target.constructor.static.apiRequest( {
|
|
action: 'query',
|
|
meta: 'filerepoinfo'
|
|
} ).then(
|
|
function ( resp ) {
|
|
return resp.query && resp.query.repos || defaultSource;
|
|
},
|
|
function () {
|
|
return $.Deferred().resolve( defaultSource );
|
|
}
|
|
);
|
|
}
|
|
|
|
return this.fileRepoPromise;
|
|
};
|
|
|
|
/**
|
|
* Set the search query for all the providers.
|
|
*
|
|
* This also makes sure to abort any previous promises.
|
|
*
|
|
* @param {string} query Search query
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.setQuery = function ( query ) {
|
|
var i, len;
|
|
if ( query !== this.query ) {
|
|
this.query = query;
|
|
// Reset queue
|
|
this.queue = [];
|
|
// Reset promises
|
|
for ( i = 0, len = this.providerPromises.length; i < len; i++ ) {
|
|
this.providerPromises[i].abort();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get the current search query.
|
|
*
|
|
* @param {string} query Search query
|
|
*/
|
|
ve.dm.MWMediaResourceQueue.prototype.getQuery = function () {
|
|
return this.query;
|
|
};
|