From 94317d7aa4ed439cb825d006fb461145a6d2aa5d Mon Sep 17 00:00:00 2001 From: kborchers Date: Mon, 12 Sep 2011 08:43:49 -0500 Subject: Menu: Added autoCollapse as the default and added a unit test --- ui/jquery.ui.menu.js | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'ui/jquery.ui.menu.js') diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js index 27e76d909..549eb5fae 100644 --- a/ui/jquery.ui.menu.js +++ b/ui/jquery.ui.menu.js @@ -62,6 +62,8 @@ $.widget( "ui.menu", { target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); this.focus( event, target ); }, + "mouseleave": "_mouseleave", + "mouseleave .ui-menu": "_mouseleave", "mouseout .ui-menu-item": "blur", "focus": function( event ) { this.focus( event, $( event.target ).children( ".ui-menu-item:first" ) ); @@ -346,21 +348,30 @@ $.widget( "ui.menu", { }, collapseAll: function( event ) { - this.element - .find( "ul" ) - .hide() - .attr( "aria-hidden", "true" ) - .attr( "aria-expanded", "false" ) - .end() - .find( "a.ui-state-active" ) - .removeClass( "ui-state-active" ); + var currentMenu = false; + if ( event ) { + var target = $( event.target ); + if ( target.is( "ui.menu" ) ) { + currentMenu = target; + } else if ( target.closest( ".ui-menu" ).length ) { + currentMenu = target.closest( ".ui-menu" ); + } + } - this.blur( event ); - this.activeMenu = this.element; + this._close( currentMenu ); + + if( !currentMenu ) { + this.blur( event ); + this.activeMenu = this.element; + } }, - _close: function() { - this.active.parent() + _close: function( startMenu ) { + if( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; + } + + startMenu .find( "ul" ) .hide() .attr( "aria-hidden", "true" ) @@ -373,10 +384,7 @@ $.widget( "ui.menu", { collapse: function( event ) { var newItem = this.active && this.active.parents("li:not(.ui-menubar-item)").first(); if ( newItem && newItem.length ) { - this.active.parent() - .attr("aria-hidden", "true") - .attr("aria-expanded", "false") - .hide(); + this._close(); this.focus( event, newItem ); return true; } @@ -486,6 +494,11 @@ $.widget( "ui.menu", { return this.element.height() < this.element.prop( "scrollHeight" ); }, + _mouseleave: function( event ) { + this.collapseAll( event ); + this.blur(); + }, + select: function( event ) { // save active reference before collapseAll triggers blur var ui = { -- cgit v1.2.3 From 609e1f87f4b242b1f30ccff75d72a863cb1fdb8e Mon Sep 17 00:00:00 2001 From: Jörn Zaefferer Date: Mon, 12 Sep 2011 23:19:19 +0200 Subject: Menu: Replace regular bind call with _bind --- ui/jquery.ui.menu.js | 188 +++++++++++++++++++++++++-------------------------- 1 file changed, 94 insertions(+), 94 deletions(-) (limited to 'ui/jquery.ui.menu.js') diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js index 27e76d909..c900f4218 100644 --- a/ui/jquery.ui.menu.js +++ b/ui/jquery.ui.menu.js @@ -71,111 +71,111 @@ $.widget( "ui.menu", { this.refresh(); - this.element.attr( "tabIndex", 0 ).bind( "keydown.menu", function( event ) { - if ( self.options.disabled ) { - return; - } - switch ( event.keyCode ) { - case $.ui.keyCode.PAGE_UP: - self.previousPage( event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.PAGE_DOWN: - self.nextPage( event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.HOME: - self._move( "first", "first", event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.END: - self._move( "last", "last", event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.UP: - self.previous( event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.DOWN: - self.next( event ); - event.preventDefault(); - event.stopImmediatePropagation(); - break; - case $.ui.keyCode.LEFT: - if (self.collapse( event )) { + this.element.attr( "tabIndex", 0 ); + this._bind({ + "keydown": function( event ) { + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + self.previousPage( event ); + event.preventDefault(); event.stopImmediatePropagation(); - } - event.preventDefault(); - break; - case $.ui.keyCode.RIGHT: - if (self.expand( event )) { + break; + case $.ui.keyCode.PAGE_DOWN: + self.nextPage( event ); + event.preventDefault(); event.stopImmediatePropagation(); - } - event.preventDefault(); - break; - case $.ui.keyCode.ENTER: - if ( self.active.children( "a[aria-haspopup='true']" ).length ) { - if ( self.expand( event ) ) { - event.stopImmediatePropagation(); - } - } - else { - self.select( event ); + break; + case $.ui.keyCode.HOME: + self._move( "first", "first", event ); + event.preventDefault(); event.stopImmediatePropagation(); - } - event.preventDefault(); - break; - case $.ui.keyCode.ESCAPE: - if ( self.collapse( event ) ) { + break; + case $.ui.keyCode.END: + self._move( "last", "last", event ); + event.preventDefault(); event.stopImmediatePropagation(); - } - event.preventDefault(); - break; - default: - event.stopPropagation(); - clearTimeout( self.filterTimer ); - var match, - prev = self.previousFilter || "", - character = String.fromCharCode( event.keyCode ), - skip = false; - - if (character == prev) { - skip = true; - } else { - character = prev + character; - } - function escape( value ) { - return value.replace( /[-[\]{}()*+?.,\\^$|#\s]/g , "\\$&" ); - } - match = self.activeMenu.children( ".ui-menu-item" ).filter( function() { - return new RegExp("^" + escape(character), "i") - .test( $( this ).children( "a" ).text() ); - }); - match = skip && match.index(self.active.next()) != -1 ? self.active.nextAll(".ui-menu-item") : match; - if ( !match.length ) { - character = String.fromCharCode(event.keyCode); - match = self.activeMenu.children(".ui-menu-item").filter( function() { + break; + case $.ui.keyCode.UP: + self.previous( event ); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.DOWN: + self.next( event ); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.LEFT: + if (self.collapse( event )) { + event.stopImmediatePropagation(); + } + event.preventDefault(); + break; + case $.ui.keyCode.RIGHT: + if (self.expand( event )) { + event.stopImmediatePropagation(); + } + event.preventDefault(); + break; + case $.ui.keyCode.ENTER: + if ( self.active.children( "a[aria-haspopup='true']" ).length ) { + if ( self.expand( event ) ) { + event.stopImmediatePropagation(); + } + } + else { + self.select( event ); + event.stopImmediatePropagation(); + } + event.preventDefault(); + break; + case $.ui.keyCode.ESCAPE: + if ( self.collapse( event ) ) { + event.stopImmediatePropagation(); + } + event.preventDefault(); + break; + default: + event.stopPropagation(); + clearTimeout( self.filterTimer ); + var match, + prev = self.previousFilter || "", + character = String.fromCharCode( event.keyCode ), + skip = false; + + if (character == prev) { + skip = true; + } else { + character = prev + character; + } + function escape( value ) { + return value.replace( /[-[\]{}()*+?.,\\^$|#\s]/g , "\\$&" ); + } + match = self.activeMenu.children( ".ui-menu-item" ).filter( function() { return new RegExp("^" + escape(character), "i") .test( $( this ).children( "a" ).text() ); }); - } - if ( match.length ) { - self.focus( event, match ); - if (match.length > 1) { - self.previousFilter = character; - self.filterTimer = setTimeout( function() { + match = skip && match.index(self.active.next()) != -1 ? self.active.nextAll(".ui-menu-item") : match; + if ( !match.length ) { + character = String.fromCharCode(event.keyCode); + match = self.activeMenu.children(".ui-menu-item").filter( function() { + return new RegExp("^" + escape(character), "i") + .test( $( this ).children( "a" ).text() ); + }); + } + if ( match.length ) { + self.focus( event, match ); + if (match.length > 1) { + self.previousFilter = character; + self.filterTimer = setTimeout( function() { + delete self.previousFilter; + }, 1000 ); + } else { delete self.previousFilter; - }, 1000 ); + } } else { delete self.previousFilter; } - } else { - delete self.previousFilter; } } }); -- cgit v1.2.3 From bf26bf1ac4b2be791c2f283a60453fc59ee389bb Mon Sep 17 00:00:00 2001 From: Jörn Zaefferer Date: Mon, 12 Sep 2011 23:52:17 +0200 Subject: Menu: Get rid of `var self`, replacing with `that` or calls to _delay --- ui/jquery.ui.menu.js | 88 ++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 47 deletions(-) (limited to 'ui/jquery.ui.menu.js') diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js index c900f4218..050112db5 100644 --- a/ui/jquery.ui.menu.js +++ b/ui/jquery.ui.menu.js @@ -26,7 +26,6 @@ $.widget( "ui.menu", { } }, _create: function() { - var self = this; this.activeMenu = this.element; this.menuId = this.element.attr( "id" ) || "ui-menu-" + idIncrement++; if ( this.element.find( ".ui-icon" ).length ) { @@ -40,11 +39,11 @@ $.widget( "ui.menu", { }) // need to catch all clicks on disabled menu // not possible through _bind - .bind( "click.menu", function( event ) { - if ( self.options.disabled ) { + .bind( "click.menu", $.proxy( function( event ) { + if ( this.options.disabled ) { event.preventDefault(); } - }); + }, this)); this._bind({ "click .ui-menu-item:has(a)": function( event ) { event.stopImmediatePropagation(); @@ -76,70 +75,70 @@ $.widget( "ui.menu", { "keydown": function( event ) { switch ( event.keyCode ) { case $.ui.keyCode.PAGE_UP: - self.previousPage( event ); + this.previousPage( event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.PAGE_DOWN: - self.nextPage( event ); + this.nextPage( event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.HOME: - self._move( "first", "first", event ); + this._move( "first", "first", event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.END: - self._move( "last", "last", event ); + this._move( "last", "last", event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.UP: - self.previous( event ); + this.previous( event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.DOWN: - self.next( event ); + this.next( event ); event.preventDefault(); event.stopImmediatePropagation(); break; case $.ui.keyCode.LEFT: - if (self.collapse( event )) { + if (this.collapse( event )) { event.stopImmediatePropagation(); } event.preventDefault(); break; case $.ui.keyCode.RIGHT: - if (self.expand( event )) { + if (this.expand( event )) { event.stopImmediatePropagation(); } event.preventDefault(); break; case $.ui.keyCode.ENTER: - if ( self.active.children( "a[aria-haspopup='true']" ).length ) { - if ( self.expand( event ) ) { + if ( this.active.children( "a[aria-haspopup='true']" ).length ) { + if ( this.expand( event ) ) { event.stopImmediatePropagation(); } } else { - self.select( event ); + this.select( event ); event.stopImmediatePropagation(); } event.preventDefault(); break; case $.ui.keyCode.ESCAPE: - if ( self.collapse( event ) ) { + if ( this.collapse( event ) ) { event.stopImmediatePropagation(); } event.preventDefault(); break; default: event.stopPropagation(); - clearTimeout( self.filterTimer ); + clearTimeout( this.filterTimer ); var match, - prev = self.previousFilter || "", + prev = this.previousFilter || "", character = String.fromCharCode( event.keyCode ), skip = false; @@ -151,30 +150,30 @@ $.widget( "ui.menu", { function escape( value ) { return value.replace( /[-[\]{}()*+?.,\\^$|#\s]/g , "\\$&" ); } - match = self.activeMenu.children( ".ui-menu-item" ).filter( function() { + match = this.activeMenu.children( ".ui-menu-item" ).filter( function() { return new RegExp("^" + escape(character), "i") .test( $( this ).children( "a" ).text() ); }); - match = skip && match.index(self.active.next()) != -1 ? self.active.nextAll(".ui-menu-item") : match; + match = skip && match.index(this.active.next()) != -1 ? this.active.nextAll(".ui-menu-item") : match; if ( !match.length ) { character = String.fromCharCode(event.keyCode); - match = self.activeMenu.children(".ui-menu-item").filter( function() { + match = this.activeMenu.children(".ui-menu-item").filter( function() { return new RegExp("^" + escape(character), "i") .test( $( this ).children( "a" ).text() ); }); } if ( match.length ) { - self.focus( event, match ); + this.focus( event, match ); if (match.length > 1) { - self.previousFilter = character; - self.filterTimer = setTimeout( function() { - delete self.previousFilter; + this.previousFilter = character; + this.filterTimer = this._delay( function() { + delete this.previousFilter; }, 1000 ); } else { - delete self.previousFilter; + delete this.previousFilter; } } else { - delete self.previousFilter; + delete this.previousFilter; } } } @@ -219,7 +218,7 @@ $.widget( "ui.menu", { }, refresh: function() { - var self = this, + var that = this, // initialize nested menus submenus = this.element.find( "ul:not(.ui-menu)" ) @@ -239,7 +238,7 @@ $.widget( "ui.menu", { .attr( "tabIndex", -1 ) .attr( "role", "menuitem" ) .attr( "id", function( i ) { - return self.element.attr( "id" ) + "-" + i; + return that.element.attr( "id" ) + "-" + i; }); submenus.each( function() { @@ -253,9 +252,6 @@ $.widget( "ui.menu", { }, focus: function( event, item ) { - var nested, - self = this; - this.blur( event ); if ( this._hasScroll() ) { @@ -277,18 +273,18 @@ $.widget( "ui.menu", { .children( "a" ) .addClass( "ui-state-focus" ) .end(); - self.element.attr( "aria-activedescendant", self.active.children("a").attr("id") ); + this.element.attr( "aria-activedescendant", this.active.children("a").attr("id") ); // highlight active parent menu item, if any this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"); - self.timer = setTimeout( function() { - self._close(); - }, self.delay ); + this.timer = this._delay( function() { + this._close(); + }, this.delay ); - nested = $( ">ul", item ); + var nested = $( ">ul", item ); if ( nested.length && ( /^mouse/.test( event.type ) ) ) { - self._startOpening(nested); + this._startOpening(nested); } this.activeMenu = item.parent(); @@ -317,11 +313,10 @@ $.widget( "ui.menu", { return; } - var self = this; - self.timer = setTimeout( function() { - self._close(); - self._open( submenu ); - }, self.delay ); + this.timer = this._delay( function() { + this._close(); + this._open( submenu ); + }, this.delay ); }, _open: function( submenu ) { @@ -383,15 +378,14 @@ $.widget( "ui.menu", { }, expand: function( event ) { - var self = this, - newItem = this.active && this.active.children("ul").children("li").first(); + var newItem = this.active && this.active.children("ul").children("li").first(); if ( newItem && newItem.length ) { this._open( newItem.parent() ); //timeout so Firefox will not hide activedescendant change in expanding submenu from AT - setTimeout( function() { - self.focus( event, newItem ); + this._delay( function() { + this.focus( event, newItem ); }, 20 ); return true; } -- cgit v1.2.3 From e1ec6f8ebb509b636840dfad11aa062c9877beac Mon Sep 17 00:00:00 2001 From: Jörn Zaefferer Date: Tue, 13 Sep 2011 00:24:43 +0200 Subject: Menu: Refactor to get rid of var that. Cleanup some odd formattings and unneeded temp vars --- tests/visual/menu/menu.html | 12 ++++++------ ui/jquery.ui.menu.js | 40 +++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 27 deletions(-) (limited to 'ui/jquery.ui.menu.js') diff --git a/tests/visual/menu/menu.html b/tests/visual/menu/menu.html index 5720d04d9..195488184 100644 --- a/tests/visual/menu/menu.html +++ b/tests/visual/menu/menu.html @@ -16,7 +16,7 @@ right: 10, top: 10 }).appendTo(document.body).themeswitcher(); - + function create() { menus.menu({ select: function(event, ui) { @@ -24,8 +24,8 @@ } }); } - - var menus = $("#menu1, #menu2, #menu3, #menu4"); + + var menus = $("#menu1, #menu2, #menu3, .menu4"); create(); $("#toggle-destroy").toggle(function() { @@ -41,11 +41,11 @@ - + - + + + +
Log:
@@ -182,4 +280,4 @@ - + \ No newline at end of file diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js index 9cb6afe32..455a12184 100644 --- a/ui/jquery.ui.menu.js +++ b/ui/jquery.ui.menu.js @@ -20,6 +20,7 @@ $.widget( "ui.menu", { defaultElement: "
    ", delay: 150, options: { + items: "ul", position: { my: "left top", at: "right top" @@ -194,7 +195,7 @@ $.widget( "ui.menu", { //destroy (sub)menus this.element .removeAttr( "aria-activedescendant" ) - .find( "ul" ) + .find( ".ui-menu" ) .andSelf() .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) .removeAttr( "role" ) @@ -221,7 +222,7 @@ $.widget( "ui.menu", { refresh: function() { // initialize nested menus - var submenus = this.element.find( "ul:not(.ui-menu)" ) + var submenus = this.element.find( this.options.items + ":not( .ui-menu )" ) .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) .attr( "role", "menu" ) .hide() @@ -230,7 +231,7 @@ $.widget( "ui.menu", { // don't refresh list items that are already adapted var menuId = this.menuId; - submenus.add( this.element ).children( "li:not(.ui-menu-item):has(a)" ) + submenus.add( this.element ).children( ":not( .ui-menu-item ):has( a )" ) .addClass( "ui-menu-item" ) .attr( "role", "presentation" ) .children( "a" ) @@ -273,16 +274,16 @@ $.widget( "ui.menu", { .children( "a" ) .addClass( "ui-state-focus" ) .end(); - this.element.attr( "aria-activedescendant", this.active.children("a").attr("id") ); + this.element.attr( "aria-activedescendant", this.active.children( "a" ).attr( "id" ) ); // highlight active parent menu item, if any - this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"); + this.active.parent().closest( ".ui-menu-item" ).children( "a:first" ).addClass( "ui-state-active" ); this.timer = this._delay( function() { this._close(); }, this.delay ); - var nested = $( ">ul", item ); + var nested = $( "> .ui-menu", item ); if ( nested.length && ( /^mouse/.test( event.type ) ) ) { this._startOpening(nested); } @@ -353,19 +354,19 @@ $.widget( "ui.menu", { this._close( currentMenu ); - if( !currentMenu ) { + if ( !currentMenu ) { this.blur( event ); this.activeMenu = this.element; } }, _close: function( startMenu ) { - if( !startMenu ) { + if ( !startMenu ) { startMenu = this.active ? this.active.parent() : this.element; } startMenu - .find( "ul" ) + .find( ".ui-menu" ) .hide() .attr( "aria-hidden", "true" ) .attr( "aria-expanded", "false" ) @@ -375,7 +376,7 @@ $.widget( "ui.menu", { }, collapse: function( event ) { - var newItem = this.active && this.active.parents("li:not(.ui-menubar-item)").first(); + var newItem = this.active && this.active.parent().closest( ".ui-menu-item", this.element ); if ( newItem && newItem.length ) { this._close(); this.focus( event, newItem ); @@ -384,7 +385,7 @@ $.widget( "ui.menu", { }, expand: function( event ) { - var newItem = this.active && this.active.children("ul").children("li").first(); + var newItem = this.active && this.active.children( ".ui-menu " ).children( ".ui-menu-item" ).first(); if ( newItem && newItem.length ) { this._open( newItem.parent() ); -- cgit v1.2.3 From 34a0479d1cbb0acf5d86818506deec78bfbb373b Mon Sep 17 00:00:00 2001 From: Corey Frang Date: Thu, 22 Sep 2011 13:56:53 -0500 Subject: Menu: Refactoring the collapseAll to deal with some issues selecting - Updating unit tests. Thanks @kborchers --- tests/unit/menu/menu_events.js | 8 ++++++- tests/unit/menu/menu_test_helpers.js | 2 +- ui/jquery.ui.menu.js | 46 +++++++++++++++++++----------------- 3 files changed, 32 insertions(+), 24 deletions(-) (limited to 'ui/jquery.ui.menu.js') diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js index 6d1b02b87..55ec1e2ff 100644 --- a/tests/unit/menu/menu_events.js +++ b/tests/unit/menu/menu_events.js @@ -99,7 +99,7 @@ asyncTest( "handle submenu auto collapse: mouseleave", function() { }); asyncTest( "handle custom menu item submenu auto collapse: mouseleave", function() { - expect( 4 ); + expect( 5 ); var $menu = $( "#menu5" ).menu( { items: "div" } ); $menu.children( ":nth-child(7)" ).trigger( "mouseover" ); @@ -110,6 +110,11 @@ asyncTest( "handle custom menu item submenu auto collapse: mouseleave", function equal( $menu.find( "div[aria-expanded='true']" ).length, 2, "second submenu expanded" ); $menu.find( "div[aria-expanded='true']:first" ).trigger( "mouseleave" ); equal( $menu.find( "div[aria-expanded='true']" ).length, 1, "second submenu collapsed" ); + + $menu.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN }); + ok( $menu.find( ".ui-state-active" ).is( "#menu5 :nth-child(7) a" ), + "down keypress selected an item from the first submenu" ); + $menu.trigger( "mouseleave" ); equal( $menu.find( "div[aria-expanded='true']" ).length, 0, "first submenu collapsed" ); start(); @@ -117,6 +122,7 @@ asyncTest( "handle custom menu item submenu auto collapse: mouseleave", function }, 200); }); + test("handle keyboard navigation on menu without scroll and without submenus", function() { expect(12); var element = $('#menu1').menu({ diff --git a/tests/unit/menu/menu_test_helpers.js b/tests/unit/menu/menu_test_helpers.js index 052c9226b..e83795e5a 100644 --- a/tests/unit/menu/menu_test_helpers.js +++ b/tests/unit/menu/menu_test_helpers.js @@ -5,7 +5,7 @@ function menu_log( message, clear ) { if ( message === undefined ) { message = $( "#log" ).data( "lastItem" ); } - $( "#log" ).prepend( message + "," ); + $( "#log" ).prepend( $.trim( message ) + "," ); } function menu_click( menu, item ) { diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js index 455a12184..6d9db8879 100644 --- a/ui/jquery.ui.menu.js +++ b/ui/jquery.ui.menu.js @@ -62,13 +62,19 @@ $.widget( "ui.menu", { target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); this.focus( event, target ); }, - "mouseleave": "_mouseleave", - "mouseleave .ui-menu": "_mouseleave", + "mouseleave": "collapseAll", + "mouseleave .ui-menu": "collapseAll", "mouseout .ui-menu-item": "blur", "focus": function( event ) { this.focus( event, $( event.target ).children( ".ui-menu-item:first" ) ); }, - "blur": "collapseAll" + blur: function( event ) { + this._delay( function() { + if ( ! $.contains( this.element[0], document.activeElement ) ) { + this.collapseAll( event ); + } + }, 0); + } }); this.refresh(); @@ -341,25 +347,25 @@ $.widget( "ui.menu", { .position( position ); }, - collapseAll: function( event ) { - var currentMenu = false; - if ( event ) { - var target = $( event.target ); - if ( target.is( "ui.menu" ) ) { - currentMenu = target; - } else if ( target.closest( ".ui-menu" ).length ) { - currentMenu = target.closest( ".ui-menu" ); - } + collapseAll: function( event, all ) { + + // if we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); + + // if we found no valid submenu ancestor, use the main menu to close all sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; } this._close( currentMenu ); - if ( !currentMenu ) { - this.blur( event ); - this.activeMenu = this.element; - } + this.blur( event ); + this.activeMenu = currentMenu; }, + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW _close: function( startMenu ) { if ( !startMenu ) { startMenu = this.active ? this.active.parent() : this.element; @@ -487,17 +493,13 @@ $.widget( "ui.menu", { return this.element.height() < this.element.prop( "scrollHeight" ); }, - _mouseleave: function( event ) { - this.collapseAll( event ); - this.blur(); - }, - select: function( event ) { + // save active reference before collapseAll triggers blur var ui = { item: this.active }; - this.collapseAll( event ); + this.collapseAll( event, true ); this._trigger( "select", event, ui ); } }); -- cgit v1.2.3