]> source.dussan.org Git - jquery-ui.git/commitdiff
Autocomplete: Close the menu on any outside interactions
authorScott González <scott.gonzalez@gmail.com>
Thu, 15 Oct 2015 14:11:14 +0000 (10:11 -0400)
committerScott González <scott.gonzalez@gmail.com>
Fri, 16 Oct 2015 18:09:05 +0000 (14:09 -0400)
This ensures that the menu will close if the user interacts with a
draggable, resizable, etc. element since those interactions don't
change focus.

Ref #6642
Closes gh-1614

tests/unit/autocomplete/core.js
ui/widgets/autocomplete.js

index 41be5ae6a0a8f9a45a51cf9b20c43d06a6a72549..9cfac39172d313c9aabb1ee19822bc3916c0a3ac 100644 (file)
@@ -398,4 +398,28 @@ asyncTest( "Search if the user retypes the same value (#7434)", function() {
        } );
 } );
 
+asyncTest( "Close on click outside when focus remains", function() {
+       expect( 2 );
+
+       var element = $( "#autocomplete" ).autocomplete( {
+               source: [ "java", "javascript" ],
+               delay: 0
+       } );
+       var menu = element.autocomplete( "widget" );
+
+       $( "body" ).on( "mousedown", function( event ) {
+               event.preventDefault();
+       } );
+
+       element.val( "j" ).autocomplete( "search", "j" );
+       setTimeout(function() {
+               ok( menu.is( ":visible" ), "menu displays initially" );
+               $( "body" ).simulate( "mousedown" );
+               setTimeout(function() {
+                       ok( menu.is( ":hidden" ), "menu closes after clicking elsewhere" );
+                       start();
+               } );
+       } );
+} );
+
 } );
index 4067f871fdef969baf34ca0c702e5e25e9902869..20d6d2fdd235bb1af66d37719213e13b3884ac52 100644 (file)
@@ -245,24 +245,6 @@ $.widget( "ui.autocomplete", {
                                                this.element.trigger( "focus" );
                                        }
                                } );
-
-                               // Clicking on the scrollbar causes focus to shift to the body
-                               // but we can't detect a mouseup or a click immediately afterward
-                               // so we have to track the next mousedown and close the menu if
-                               // the user clicks somewhere outside of the autocomplete
-                               var menuElement = this.menu.element[ 0 ];
-                               if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
-                                       this._delay( function() {
-                                               var that = this;
-                                               this.document.one( "mousedown", function( event ) {
-                                                       if ( event.target !== that.element[ 0 ] &&
-                                                                       event.target !== menuElement &&
-                                                                       !$.contains( menuElement, event.target ) ) {
-                                                               that.close();
-                                                       }
-                                               } );
-                                       } );
-                               }
                        },
                        menufocus: function( event, ui ) {
                                var label, item;
@@ -368,6 +350,20 @@ $.widget( "ui.autocomplete", {
                }
        },
 
+       _isEventTargetInWidget: function( event ) {
+               var menuElement = this.menu.element[ 0 ];
+
+               return event.target === this.element[ 0 ] ||
+                       event.target === menuElement ||
+                       $.contains( menuElement, event.target );
+       },
+
+       _closeOnClickOutside: function( event ) {
+               if ( !this._isEventTargetInWidget( event ) ) {
+                       this.close();
+               }
+       },
+
        _appendTo: function() {
                var element = this.options.appendTo;
 
@@ -496,6 +492,10 @@ $.widget( "ui.autocomplete", {
        },
 
        _close: function( event ) {
+
+               // Remove the handler that closes the menu on outside clicks
+               this._off( this.document, "mousedown" );
+
                if ( this.menu.element.is( ":visible" ) ) {
                        this.menu.element.hide();
                        this.menu.blur();
@@ -546,6 +546,11 @@ $.widget( "ui.autocomplete", {
                if ( this.options.autoFocus ) {
                        this.menu.next();
                }
+
+               // Listen for interactions outside of the widget (#6642)
+               this._on( this.document, {
+                       mousedown: "_closeOnClickOutside"
+               } );
        },
 
        _resizeMenu: function() {