summaryrefslogtreecommitdiff
path: root/www/wiki/resources/src/mediawiki.widgets/MediaSearch/mw.widgets.APIResultsQueue.js
blob: 3bc1d51bac5648516fc74eb9d84d3581058d5a75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*!
 * MediaWiki Widgets - APIResultsQueue class.
 *
 * @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org
 */
( function ( $, mw ) {

	/**
	 * API Results Queue object.
	 *
	 * @class
	 * @mixins OO.EventEmitter
	 *
	 * @constructor
	 * @param {Object} [config] Configuration options
	 * @cfg {number} limit The default number of results to fetch
	 * @cfg {number} 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: $.noop } );
	};

	/**
	 * 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 ) {
		var fetchingPromise = null,
			me = this;

		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( function ( items ) {
					// Add to the queue
					me.queue = me.queue.concat.apply( me.queue, items );
				} );
		}

		return $.when( fetchingPromise )
			.then( function () {
				return me.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 ) {
		var i, len,
			queue = this;

		// Make sure there are resources set up
		return this.setup()
			.then( function () {
				// Abort previous requests
				for ( i = 0, len = queue.providerPromises.length; i < len; i++ ) {
					queue.providerPromises[ i ].abort();
				}
				queue.providerPromises = [];
				// Set up the query to all providers
				for ( i = 0, len = queue.providers.length; i < len; i++ ) {
					if ( !queue.providers[ i ].isDepleted() ) {
						queue.providerPromises.push(
							queue.providers[ i ].getResults( howMany )
						);
					}
				}

				return $.when.apply( $, queue.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 ) {
		var i, len;
		if ( !OO.compare( params, this.params, true ) ) {
			this.reset();
			this.params = $.extend( this.params, params );
			// Reset queue
			this.queue = [];
			// Reset promises
			for ( i = 0, len = this.providerPromises.length; i < len; i++ ) {
				this.providerPromises[ i ].abort();
			}
			// Change queries
			for ( i = 0, len = this.providers.length; i < len; i++ ) {
				this.providers[ i ].setUserParams( this.params );
			}
		}
	};

	/**
	 * Reset the queue and all its providers
	 */
	mw.widgets.APIResultsQueue.prototype.reset = function () {
		var i, len;
		// Reset queue
		this.queue = [];
		// Reset promises
		for ( i = 0, len = this.providerPromises.length; i < len; i++ ) {
			this.providerPromises[ i ].abort();
		}
		// Change queries
		for ( i = 0, len = this.providers.length; i < len; i++ ) {
			this.providers[ i ].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;
	};

	/**
	 * 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 );
	};

	/**
	 * 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;
	};
}( jQuery, mediaWiki ) );