-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Menubar #829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Menubar #829
Changes from 3 commits
0f33062
82d0056
15bd67f
d4ca89b
f30c853
ec67b65
c57319c
36b5135
1a9f136
ab98a00
2fe73a1
baf9882
0700982
2500c96
bb87639
b74695a
706d882
8237fb2
1af1f8c
908fea5
bb8e2e0
0efe66e
fdc200d
aafdc17
1e8089b
09d51e8
a4a95cc
b2a3814
bab98f2
79b06b2
480de7f
56f6469
100f552
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ $.widget( "ui.menubar", { | |
} | ||
}, | ||
_create: function() { | ||
var that = this; | ||
var that = this, subMenus; | ||
this.menuItems = this.element.children( this.options.items ); | ||
this.items = this.menuItems.children( "button, a" ); | ||
|
||
|
@@ -46,7 +46,7 @@ $.widget( "ui.menubar", { | |
.attr( "role", "menubar" ); | ||
this._focusable( this.items ); | ||
this._hoverable( this.items ); | ||
this.items.siblings( this.options.menuElement ) | ||
subMenus = this.items.siblings( this.options.menuElement ) | ||
.menu({ | ||
position: { | ||
within: this.options.position.within | ||
|
@@ -58,89 +58,105 @@ $.widget( "ui.menubar", { | |
$(event.target).prev().focus(); | ||
that._trigger( "select", event, ui ); | ||
}, | ||
menus: that.options.menuElement | ||
menus: this.options.menuElement | ||
}) | ||
.hide() | ||
.attr({ | ||
"aria-hidden": "true", | ||
"aria-expanded": "false" | ||
}) | ||
// TODO use _on | ||
.bind( "keydown.menubar", function( event ) { | ||
}); | ||
this._on( subMenus, { | ||
"keydown.menubar": function(event) { | ||
var menu = $( this ); | ||
if ( menu.is( ":hidden" ) ) { | ||
return; | ||
} | ||
switch ( event.keyCode ) { | ||
case $.ui.keyCode.LEFT: | ||
that.previous( event ); | ||
this.previous( event ); | ||
event.preventDefault(); | ||
break; | ||
case $.ui.keyCode.RIGHT: | ||
that.next( event ); | ||
this.next( event ); | ||
event.preventDefault(); | ||
break; | ||
} | ||
}); | ||
} | ||
}); | ||
if ( this.items.length > 0 ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this conditional empty? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mikesherov Good catch. It's vestigial. Will rm. |
||
} | ||
this.items.each(function() { | ||
var input = $(this), | ||
// TODO menu var is only used on two places, doesn't quite justify the .each | ||
menu = input.next( that.options.menuElement ); | ||
menu = input.next( that.options.menuElement ), | ||
mouseBehaviorCallback, keyboardBehaviorCallback; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uninitialized vars at the top. |
||
|
||
// might be a non-menu button | ||
if ( menu.length ) { | ||
// TODO use _on | ||
input.bind( "click.menubar focus.menubar mouseenter.menubar", function( event ) { | ||
// ignore triggered focus event | ||
if ( event.type === "focus" && !event.originalEvent ) { | ||
return; | ||
mouseBehaviorCallback = function( event ) { | ||
// ignore triggered focus event | ||
if ( event.type === "focus" && !event.originalEvent ) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
// TODO can we simplify or extractthis check? especially the last two expressions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extractthis typo |
||
// there's a similar active[0] == menu[0] check in _open | ||
if ( event.type === "click" && menu.is( ":visible" ) && this.active && this.active[0] === menu[0] ) { | ||
this._close(); | ||
return; | ||
} | ||
if ( ( this.open && event.type === "mouseenter" ) || event.type === "click" || this.options.autoExpand ) { | ||
if( this.options.autoExpand ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't want spacing around As such:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, you're missing a space after the |
||
clearTimeout( this.closeTimer ); | ||
} | ||
|
||
this._open( event, menu ); | ||
} | ||
}; | ||
|
||
keyboardBehaviorCallback = function( event ) { | ||
switch ( event.keyCode ) { | ||
case $.ui.keyCode.SPACE: | ||
case $.ui.keyCode.UP: | ||
case $.ui.keyCode.DOWN: | ||
this._open( event, $( this ).next() ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using The focus handling is broken, also in the menubar branch, maybe something you could look into later as well? Moving focus to the first submenu-free item should also bind cursor left/right to move focus inside the menubar, and the tabindex accordingly. Currently you have to activate with the mouse first, before being able to use the keyboard, and even then there's two items that can be focused, not just one. |
||
event.preventDefault(); | ||
// TODO can we simplify or extractthis check? especially the last two expressions | ||
// there's a similar active[0] == menu[0] check in _open | ||
if ( event.type === "click" && menu.is( ":visible" ) && that.active && that.active[0] === menu[0] ) { | ||
that._close(); | ||
return; | ||
} | ||
if ( ( that.open && event.type === "mouseenter" ) || event.type === "click" || that.options.autoExpand ) { | ||
if( that.options.autoExpand ) { | ||
clearTimeout( that.closeTimer ); | ||
} | ||
break; | ||
case $.ui.keyCode.LEFT: | ||
this.previous( event ); | ||
event.preventDefault(); | ||
break; | ||
case $.ui.keyCode.RIGHT: | ||
this.next( event ); | ||
event.preventDefault(); | ||
break; | ||
} | ||
}; | ||
|
||
that._open( event, menu ); | ||
} | ||
}) | ||
// TODO use _on | ||
.bind( "keydown", function( event ) { | ||
switch ( event.keyCode ) { | ||
case $.ui.keyCode.SPACE: | ||
case $.ui.keyCode.UP: | ||
case $.ui.keyCode.DOWN: | ||
that._open( event, $( this ).next() ); | ||
event.preventDefault(); | ||
break; | ||
case $.ui.keyCode.LEFT: | ||
that.previous( event ); | ||
event.preventDefault(); | ||
break; | ||
case $.ui.keyCode.RIGHT: | ||
that.next( event ); | ||
event.preventDefault(); | ||
break; | ||
} | ||
}) | ||
.attr( "aria-haspopup", "true" ); | ||
// might be a non-menu button | ||
if ( menu.length ) { | ||
that._on(input, { | ||
"click.menubar": mouseBehaviorCallback, | ||
"focus.menubar": mouseBehaviorCallback, | ||
"mouseenter.menubar": mouseBehaviorCallback, | ||
"keydown": keyboardBehaviorCallback | ||
}); | ||
|
||
input.attr( "aria-haspopup", "true" ); | ||
|
||
// TODO review if these options (menuIcon and buttons) are a good choice, maybe they can be merged | ||
if ( that.options.menuIcon ) { | ||
input.addClass( "ui-state-default" ).append( "<span class='ui-button-icon-secondary ui-icon ui-icon-triangle-1-s'></span>" ); | ||
input.removeClass( "ui-button-text-only" ).addClass( "ui-button-text-icon-secondary" ); | ||
} | ||
} else { | ||
// TODO use _on | ||
input.bind( "click.menubar mouseenter.menubar", function( event ) { | ||
if ( ( that.open && event.type === "mouseenter" ) || event.type === "click" ) { | ||
that._close(); | ||
that._on(input, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always spaces. There's an exception for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also needs a keydown handler, see above. Not necessarily as part of this PR. |
||
click: function(event) { | ||
this._close(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spacing |
||
}, | ||
|
||
mouseenter: function(event) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spacing |
||
if (this.open){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. spacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the spacing is to be: if (this.open) {
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
this._close(); | ||
} | ||
} | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scottgonzalez @jzaefferer When I look at this
_create()
method, it seems there's a lot of initializing sub-tasks going on.menuItems
$.ui.menu
s underneath all of thesemenuItems
menuItems
and on the sub-menu itemsCombine with the jQuery 'dot-chaining' syntax, the method seems to strain easy readability (in my book). This makes the contribution bar higher (IMNSHO) and makes testing / debugging harder. Maybe this isn't so for jQuery gurus such as yourselves, but I think the code would be more approachable if the long methods used intention-revealing sub-methods. I don't see this done elsewhere in the jQuery UI plugin set, but I wanted to get your thoughts on why this is or if this is just my relative unfamiliarity with plugin design.
Questions:
_create()
-homed activities into intention-revealing sub-methods?var
declaration in the sub-method and thus chaining becomes less attractive (given the "only onevar
" statement) style ruleThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine to split up
_create()
if the split makes sense. I don't see how the one-var rule has any impact on chaining method calls.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that in another request, then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uninitialized vars at the top, on their own line: