Skip to content
Permalink
Browse files

Autocomplete: Close the menu on any outside interactions

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
  • Loading branch information...
scottgonzalez committed Oct 15, 2015
1 parent 7df2f19 commit 548fbf570caa5fdee973bbbe8ac2d36b0338c2b9
Showing with 47 additions and 18 deletions.
  1. +24 −0 tests/unit/autocomplete/core.js
  2. +23 −18 ui/widgets/autocomplete.js
@@ -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();
} );
} );
} );

} );
@@ -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() {

0 comments on commit 548fbf5

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.