/*! * MediaWiki Widgets - APIResultsQueue class. * * @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org */ ( function () { /** * @classdesc API results queue. * * @class * @mixes OO.EventEmitter * * @constructor * @param {Object} [config] Configuration options * @param {number} config.limit The default number of results to fetch * @param {number} config.threshold The default number of extra results * that the queue should always strive to have on top of the * individual requests for items. */ mw.widgets.APIResultsQueue = function MwWidgetsAPIResultsQueue( config ) { config = config || {}; this.fileRepoPromise = null; this.providers = []; this.providerPromises = []; this.queue = []; this.params = {}; this.limit = config.limit || 20; this.setThreshold( config.threshold || 10 ); // Mixin constructors OO.EventEmitter.call( this ); }; /* Setup */ OO.mixinClass( mw.widgets.APIResultsQueue, OO.EventEmitter ); /* Methods */ /** * Set up the queue and its resources. * This should be overridden if there are any setup steps to perform. * * @return {jQuery.Promise} Promise that resolves when the resources * are set up. Note: The promise must have an .abort() functionality. */ mw.widgets.APIResultsQueue.prototype.setup = function () { return $.Deferred().resolve().promise( { abort: function () {} } ); }; /** * Get items from the queue. * * @param {number} [howMany] How many items to retrieve. Defaults to the * default limit supplied on initialization. * @return {jQuery.Promise} Promise that resolves into an array of items. */ mw.widgets.APIResultsQueue.prototype.get = function ( howMany ) { let fetchingPromise = null; howMany = howMany || this.limit; // Check if the queue has enough items if ( this.queue.length < howMany + this.threshold ) { // Call for more results fetchingPromise = this.queryProviders( howMany + this.threshold ) .then( ( items ) => { // Add to the queue this.queue = this.queue.concat.apply( this.queue, items ); } ); } return $.when( fetchingPromise ) .then( () => this.queue.splice( 0, howMany ) ); }; /** * Get results from all providers. * * @param {number} [howMany] How many items to retrieve. Defaults to the * default limit supplied on initialization. * @return {jQuery.Promise} Promise that is resolved into an array * of fetched items. Note: The promise must have an .abort() functionality. */ mw.widgets.APIResultsQueue.prototype.queryProviders = function ( howMany ) { // Make sure there are resources set up return this.setup() .then( () => { // Abort previous requests for ( let i = 0, iLen = this.providerPromises.length; i < iLen; i++ ) { this.providerPromises[ i ].abort(); } this.providerPromises = []; // Set up the query to all providers for ( let j = 0, jLen = this.providers.length; j < jLen; j++ ) { if ( !this.providers[ j ].isDepleted() ) { this.providerPromises.push( this.providers[ j ].getResults( howMany ) ); } } return $.when( ...this.providerPromises ) .then( Array.prototype.concat.bind( [] ) ); } ); }; /** * Set the search query for all the providers. * * This also makes sure to abort any previous promises. * * @param {Object} params API search parameters */ mw.widgets.APIResultsQueue.prototype.setParams = function ( params ) { if ( !OO.compare( params, this.params, true ) ) { this.reset(); this.params = Object.assign( this.params, params ); // Reset queue this.queue = []; // Reset promises for ( let i = 0, iLen = this.providerPromises.length; i < iLen; i++ ) { this.providerPromises[ i ].abort(); } // Change queries for ( let j = 0, jLen = this.providers.length; j < jLen; j++ ) { this.providers[ j ].setUserParams( this.params ); } } }; /** * Reset the queue and all its providers. */ mw.widgets.APIResultsQueue.prototype.reset = function () { // Reset queue this.queue = []; // Reset promises for ( let i = 0, iLen = this.providerPromises.length; i < iLen; i++ ) { this.providerPromises[ i ].abort(); } // Reset options for ( let j = 0, jLen = this.providers.length; j < jLen; j++ ) { this.providers[ j ].reset(); } }; /** * Get the data parameters sent to the API. * * @return {Object} params API search parameters */ mw.widgets.APIResultsQueue.prototype.getParams = function () { return this.params; }; /** * Set the providers. * * @param {mw.widgets.APIResultsProvider[]} providers An array of providers */ mw.widgets.APIResultsQueue.prototype.setProviders = function ( providers ) { this.providers = providers; for ( let i = 0, len = this.providers.length; i < len; i++ ) { this.providers[ i ].setUserParams( this.params ); this.providers[ i ].setLang( this.lang ); } }; /** * Add a provider to the group. * * @param {mw.widgets.APIResultsProvider} provider A provider object */ mw.widgets.APIResultsQueue.prototype.addProvider = function ( provider ) { this.providers.push( provider ); provider.setUserParams( this.params ); provider.setLang( this.lang ); }; /** * Set the providers. * * @return {mw.widgets.APIResultsProvider[]} providers An array of providers */ mw.widgets.APIResultsQueue.prototype.getProviders = function () { return this.providers; }; /** * Get the queue size. * * @return {number} Queue size */ mw.widgets.APIResultsQueue.prototype.getQueueSize = function () { return this.queue.length; }; /** * Set queue threshold. * * @param {number} threshold Queue threshold, below which we will * request more items */ mw.widgets.APIResultsQueue.prototype.setThreshold = function ( threshold ) { this.threshold = threshold; }; /** * Get queue threshold. * * @return {number} threshold Queue threshold, below which we will * request more items */ mw.widgets.APIResultsQueue.prototype.getThreshold = function () { return this.threshold; }; /** * Set language for the query results. * * @param {string|undefined} lang Language */ mw.widgets.APIResultsQueue.prototype.setLang = function ( lang ) { this.lang = lang; for ( let i = 0, len = this.providers.length; i < len; i++ ) { this.providers[ i ].setLang( this.lang ); } }; /** * Get language for the query results. * * @return {string|undefined} lang Language */ mw.widgets.APIResultsQueue.prototype.getLang = function () { return this.lang; }; }() );