Abort promises before sending new ones in MediaSearchWidget

Before sending new searches to the API, abort the previous ones if
they were not resolved. This will assure that the result presented
on the screen is valid to the latest search that was done even if
the user types quickly and sends many async requests simultaneously.

Bug: 67438
Change-Id: If88123019bfa972520e9db7c627a7f4cd8fc2526
This commit is contained in:
Moriel Schottlender 2014-09-05 01:21:12 -04:00
parent ae4511a02b
commit 2e03a8276e

View file

@ -30,8 +30,7 @@ ve.ui.MWMediaSearchWidget = function VeUiMWMediaSearchWidget( config ) {
this.queryTimeout = null;
this.titles = {};
this.queryMediaSourcesCallback = this.queryMediaSources.bind( this );
this.sourceCounter = 0;
this.promises = [];
this.$noItemsMessage = this.$( '<div>' )
.addClass( 've-ui-mwMediaSearchWidget-noresults' )
@ -102,7 +101,6 @@ ve.ui.MWMediaSearchWidget.prototype.onResultsScroll = function () {
*/
ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
var i, len, source, request,
promises = [],
ajaxOptions = {},
value = this.query.getValue();
@ -110,18 +108,17 @@ ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
return;
}
// Reset counter
this.sourceCounter = 0;
// Reset message
this.$noItemsMessage.hide();
// Abort previous promises if they are pending
this.resetPromises();
for ( i = 0, len = this.sources.length; i < len; i++ ) {
source = this.sources[i];
// If we don't have either 'apiurl' or 'scriptDirUrl'
// the source is invalid, and we will skip it
if ( source.apiurl || source.scriptDirUrl !== undefined ) {
if ( source.request ) {
source.request.abort();
}
if ( !source.gsroffset ) {
source.gsroffset = 0;
}
@ -159,22 +156,36 @@ ve.ui.MWMediaSearchWidget.prototype.queryMediaSources = function () {
}, ajaxOptions )
.done( this.onMediaQueryDone.bind( this, source ) );
source.value = value;
promises.push( request );
this.promises.push( request );
}
// When all sources are done, check to see if there are results
$.when.apply( $, promises ).done( this.onAllMediaQueriesDone.bind( this ) );
$.when.apply( $, this.promises ).done( this.onAllMediaQueriesDone.bind( this ) );
}
};
/**
* Abort all api search query promises
*/
ve.ui.MWMediaSearchWidget.prototype.resetPromises = function () {
var i;
for ( i = 0; i < this.promises.length; i++ ) {
this.promises[i].abort();
this.query.popPending();
}
// Empty the promise array
this.promises = [];
};
/**
* Handle media query response events.
*
* @method
* @param {Object} source Media query source
*/
ve.ui.MWMediaSearchWidget.prototype.onAllMediaQueriesDone = function ( source ) {
source.request = null;
ve.ui.MWMediaSearchWidget.prototype.onAllMediaQueriesDone = function () {
this.query.popPending();
if ( this.results.getItems().length === 0 ) {