Autocomplete: Move race condition logic from ajax requests to general response handler. Fixes #8234 - Autocomplete: Automatic race-condition handling for custom sources.

(cherry picked from commit 96f9c84b7b)

Conflicts:

	tests/unit/autocomplete/autocomplete_core.js
	ui/jquery.ui.autocomplete.js
This commit is contained in:
Scott González 2012-04-03 16:51:22 -04:00
parent fc6e72bf73
commit d040b8f42c
2 changed files with 50 additions and 19 deletions

View File

@ -69,4 +69,33 @@ test( "allow form submit on enter when menu is not active", function() {
ok( !event.isDefaultPrevented(), "default action is prevented" ); ok( !event.isDefaultPrevented(), "default action is prevented" );
}); });
})(jQuery); asyncTest( "handle race condition", function() {
expect( 3 );
var count = 0,
element = $( "#autocomplete" ).autocomplete({
source: function( request, response ) {
count++;
if ( request.term.length === 1 ) {
equal( count, 1, "request with 1 character is first" );
setTimeout(function() {
response([ "one" ]);
setTimeout( checkResults, 1 );
}, 1 );
return;
}
equal( count, 2, "request with 2 characters is second" );
response([ "two" ]);
}
});
element.autocomplete( "search", "a" );
element.autocomplete( "search", "ab" );
function checkResults() {
equal( element.autocomplete( "widget" ).find( ".ui-menu-item" ).text(), "two",
"correct results displayed" );
start();
}
});
}( jQuery ) );

View File

@ -131,9 +131,6 @@ $.widget( "ui.autocomplete", {
}, 150 ); }, 150 );
}); });
this._initSource(); this._initSource();
this.response = function() {
return self._response.apply( self, arguments );
};
this.menu = $( "<ul></ul>" ) this.menu = $( "<ul></ul>" )
.addClass( "ui-autocomplete" ) .addClass( "ui-autocomplete" )
.appendTo( $( this.options.appendTo || "body", doc )[0] ) .appendTo( $( this.options.appendTo || "body", doc )[0] )
@ -268,19 +265,12 @@ $.widget( "ui.autocomplete", {
url: url, url: url,
data: request, data: request,
dataType: "json", dataType: "json",
context: {
autocompleteRequest: ++requestIndex
},
success: function( data, status ) { success: function( data, status ) {
if ( this.autocompleteRequest === requestIndex ) {
response( data ); response( data );
}
}, },
error: function() { error: function() {
if ( this.autocompleteRequest === requestIndex ) {
response( [] ); response( [] );
} }
}
}); });
}; };
} else { } else {
@ -310,10 +300,26 @@ $.widget( "ui.autocomplete", {
this.pending++; this.pending++;
this.element.addClass( "ui-autocomplete-loading" ); this.element.addClass( "ui-autocomplete-loading" );
this.source( { term: value }, this.response ); this.source( { term: value }, this._response() );
}, },
_response: function( content ) { _response: function() {
var that = this,
index = ++requestIndex;
return function( content ) {
if ( index === requestIndex ) {
that.__response( content );
}
that.pending--;
if ( !that.pending ) {
that.element.removeClass( "ui-autocomplete-loading" );
}
};
},
__response: function( content ) {
if ( !this.options.disabled && content && content.length ) { if ( !this.options.disabled && content && content.length ) {
content = this._normalize( content ); content = this._normalize( content );
this._suggest( content ); this._suggest( content );
@ -321,10 +327,6 @@ $.widget( "ui.autocomplete", {
} else { } else {
this.close(); this.close();
} }
this.pending--;
if ( !this.pending ) {
this.element.removeClass( "ui-autocomplete-loading" );
}
}, },
close: function( event ) { close: function( event ) {