From d040b8f42cc28932deedddebe95473a9fd13d742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Scott=20Gonz=C3=A1lez?= Date: Tue, 3 Apr 2012 16:51:22 -0400 Subject: [PATCH] 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 96f9c84b7b2149c6b93ac226a52065652f218e1e) Conflicts: tests/unit/autocomplete/autocomplete_core.js ui/jquery.ui.autocomplete.js --- tests/unit/autocomplete/autocomplete_core.js | 31 +++++++++++++++- ui/jquery.ui.autocomplete.js | 38 ++++++++++---------- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/tests/unit/autocomplete/autocomplete_core.js b/tests/unit/autocomplete/autocomplete_core.js index fcd835d1a..84f26980f 100644 --- a/tests/unit/autocomplete/autocomplete_core.js +++ b/tests/unit/autocomplete/autocomplete_core.js @@ -69,4 +69,33 @@ test( "allow form submit on enter when menu is not active", function() { 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 ) ); diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 72a69fb0e..5352c3432 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -131,9 +131,6 @@ $.widget( "ui.autocomplete", { }, 150 ); }); this._initSource(); - this.response = function() { - return self._response.apply( self, arguments ); - }; this.menu = $( "" ) .addClass( "ui-autocomplete" ) .appendTo( $( this.options.appendTo || "body", doc )[0] ) @@ -268,18 +265,11 @@ $.widget( "ui.autocomplete", { url: url, data: request, dataType: "json", - context: { - autocompleteRequest: ++requestIndex - }, success: function( data, status ) { - if ( this.autocompleteRequest === requestIndex ) { - response( data ); - } + response( data ); }, error: function() { - if ( this.autocompleteRequest === requestIndex ) { - response( [] ); - } + response( [] ); } }); }; @@ -310,10 +300,26 @@ $.widget( "ui.autocomplete", { this.pending++; 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 ) { content = this._normalize( content ); this._suggest( content ); @@ -321,10 +327,6 @@ $.widget( "ui.autocomplete", { } else { this.close(); } - this.pending--; - if ( !this.pending ) { - this.element.removeClass( "ui-autocomplete-loading" ); - } }, close: function( event ) {