Skip to content

Commit d163b23

Browse files
author
Steven G. Harms
committed
Menubar: Bug: Arrow right w/ open submenu error
1. Load page 1. Tab to first bar 1. Right cursor 1. Down cursor 1. Right cursor 1. Error Test the object that is tested for an `active` for definition before querying that property. Create new method for assessing whether or not a new submenu should be opened. The testing here is a smell. This logic should be simplified.
1 parent 4a2d393 commit d163b23

File tree

1 file changed

+55
-37
lines changed

1 file changed

+55
-37
lines changed

ui/jquery.ui.menubar.js

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ $.widget( "ui.menubar", {
6464
active.prev().focus();
6565
}
6666
},
67-
focusin: function( event ) {
67+
focusin: function() {
6868
clearTimeout( menubar.closeTimer );
6969
},
7070
focusout: function( event ) {
7171
menubar.closeTimer = setTimeout (function() {
7272
menubar._close( event );
73+
menubar._reenableTabIndexOnFirstMenuItem();
7374
}, 150 );
7475
},
7576
"mouseleave .ui-menubar-item": function( event ) {
@@ -79,15 +80,14 @@ $.widget( "ui.menubar", {
7980
}, 150 );
8081
}
8182
},
82-
"mouseenter .ui-menubar-item": function( event ) {
83+
"mouseenter .ui-menubar-item": function() {
8384
clearTimeout( menubar.closeTimer );
8485
}
8586
});
8687
},
8788

8889
_initializeMenuItems: function() {
89-
var $item,
90-
menubar = this;
90+
var menubar = this;
9191

9292
this.menuItems
9393
.addClass("ui-menubar-item")
@@ -122,6 +122,8 @@ $.widget( "ui.menubar", {
122122
menubar._determineSubmenuStatus( $menuItem, menubar );
123123
menubar._styleMenuItem( $menuItem, menubar );
124124

125+
$menuItem.data( "name", $item.text() );
126+
125127
if ( $menuItem.data("hasSubMenu") ) {
126128
menubar._initializeSubMenu( $menuItem, menubar );
127129
}
@@ -137,7 +139,7 @@ $.widget( "ui.menubar", {
137139
$menuItem.data( "hasSubMenu", hasSubMenu );
138140
},
139141

140-
_styleMenuItem: function( $menuItem, menubar ) {
142+
_styleMenuItem: function( $menuItem ) {
141143
$menuItem.css({
142144
"border-width" : "1px",
143145
"border-style" : "hidden"
@@ -178,7 +180,9 @@ $.widget( "ui.menubar", {
178180
case $.ui.keyCode.LEFT:
179181
parentButton = menubar.active.prev(".ui-button");
180182

181-
if ( parentButton.parent().prev().data('hasSubMenu') ) {
183+
if ( this.openSubmenus ) {
184+
this.openSubmenus--;
185+
} else if ( parentButton.parent().prev().data("hasSubMenu") ) {
182186
menubar.active.blur();
183187
menubar._open( event, parentButton.parent().prev().find(".ui-menu") );
184188
} else {
@@ -196,7 +200,7 @@ $.widget( "ui.menubar", {
196200
}
197201
},
198202
focusout: function( event ) {
199-
event.stopImmediatePropagation();
203+
$(event.target).removeClass("ui-state-focus");
200204
}
201205
});
202206
},
@@ -235,10 +239,10 @@ $.widget( "ui.menubar", {
235239

236240
__applyMouseAndKeyboardBehaviorForMenuItem: function( $anItem, menubar ) {
237241
menubar._on( $anItem, {
238-
focus: function( event ){
242+
focus: function(){
239243
$anItem.addClass("ui-state-focus");
240244
},
241-
focusout: function( event ){
245+
focusout: function(){
242246
$anItem.removeClass("ui-state-focus");
243247
}
244248
} );
@@ -320,15 +324,15 @@ $.widget( "ui.menubar", {
320324
menubar._off( $anItem, "click mouseenter" );
321325
menubar._hoverable( $anItem );
322326
menubar._on( $anItem, {
323-
click: function( event ) {
327+
click: function() {
324328
if ( this.active ) {
325329
this._close();
326330
} else {
327331
this.open = true;
328332
this.active = $( $anItem ).parent();
329333
}
330334
},
331-
mouseenter: function( event ) {
335+
mouseenter: function() {
332336
if ( this.open ) {
333337
this.stashedOpenMenu = this.active;
334338
this._close();
@@ -367,7 +371,7 @@ $.widget( "ui.menubar", {
367371
.removeAttr("role")
368372
.removeAttr("aria-haspopup")
369373
// TODO unwrap?
370-
.children("span.ui-button-text").each(function( i, e ) {
374+
.children("span.ui-button-text").each(function() {
371375
var item = $( this );
372376
item.parent().html( item.html() );
373377
})
@@ -445,25 +449,30 @@ $.widget( "ui.menubar", {
445449
.removeAttr("aria-hidden")
446450
.attr("aria-expanded", "true")
447451
.menu("focus", event, menu.children(".ui-menu-item").first() )
448-
// TODO need a comment here why both events are triggered
449-
.focus()
450-
.focusin();
452+
.focus() // Establish focus on the submenu item
453+
.focusin(); // Move focus within the containing submenu
454+
451455

452456
this.open = true;
453457
},
454458

459+
_shouldOpenNestedSubMenu: function() {
460+
return this.open &&
461+
this.active &&
462+
this.active.closest( this.options.items ).data("hasSubMenu") &&
463+
this.active.data("uiMenu") &&
464+
this.active.data("uiMenu").active &&
465+
this.active.data("uiMenu").active.has(".ui-menu").length;
466+
},
467+
455468
next: function( event ) {
456-
if ( this.open && this.active &&
457-
this.active.closest( this.options.items ).data("hasSubMenu") &&
458-
this.active.data("menu").active &&
459-
this.active.data("menu").active.has(".ui-menu").length ) {
469+
if ( this._shouldOpenNestedSubMenu() ) {
460470
// Track number of open submenus and prevent moving to next menubar item
461471
this.openSubmenus++;
462472
return;
463473
}
464474
this.openSubmenus = 0;
465475
this._move( "next", "first", event );
466-
467476
},
468477

469478
previous: function( event ) {
@@ -481,9 +490,6 @@ $.widget( "ui.menubar", {
481490
},
482491

483492
_move: function( direction, filter, event ) {
484-
var next,
485-
wrapItem;
486-
487493
var closestMenuItem = $( event.target ).closest(".ui-menubar-item"),
488494
nextMenuItem = closestMenuItem.data( direction + "MenuItem" ),
489495
focusableTarget = this._findNextFocusableTarget( nextMenuItem );
@@ -494,35 +500,47 @@ $.widget( "ui.menubar", {
494500
} else {
495501
this._submenuless_open( event, nextMenuItem );
496502
}
503+
} else {
504+
closestMenuItem.find(".ui-button").attr( "tabindex", -1 );
505+
focusableTarget.focus();
497506
}
498-
499-
focusableTarget.focus();
500507
},
501508

502-
_submenuless_open: function( event, next ) {
503-
var button,
504-
menuItem = next.closest(".ui-menubar-item");
509+
_submenuless_open: function( event, nextMenuItem) {
510+
var menuItem = $(event.target).closest(".ui-menubar-item");
505511

506-
if ( this.active && this.active.length ) {
507-
// TODO refactor, almost the same as _close above, but don't remove tabIndex
508-
if ( this.active.closest( this.options.items ) ) {
512+
if ( this.active && this.active.length && menuItem.data("hasSubMenu") ) {
509513
this.active
510514
.menu("collapseAll")
511515
.hide()
512516
.attr({
513517
"aria-hidden": "true",
514518
"aria-expanded": "false"
515519
});
516-
}
517-
this.active.closest(this.options.items)
518-
.removeClass("ui-state-active");
520+
menuItem.removeClass("ui-state-active");
519521
}
520522

521-
// set tabIndex -1 to have the button skipped on shift-tab when menu is open (it gets focus)
522-
button = menuItem.attr( "tabIndex", -1 );
523+
nextMenuItem.find(".ui-button").focus();
523524

524525
this.open = true;
525-
this.active = menuItem;
526+
},
527+
528+
_closeOpenMenu: function( menu ) {
529+
menu
530+
.menu("collapseAll")
531+
.hide()
532+
.attr({
533+
"aria-hidden": "true",
534+
"aria-expanded": "false"
535+
});
536+
},
537+
538+
_deactivateMenusParentButton: function( menu ) {
539+
menu.parent(".ui-menubar-item").removeClass("ui-state-active");
540+
},
541+
542+
_reenableTabIndexOnFirstMenuItem: function() {
543+
$(this.menuItems[0]).find(".ui-widget").attr( "tabindex", 1 );
526544
}
527545

528546
});

0 commit comments

Comments
 (0)