Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Menu: Added Home moves to first item and End moves to last item in currently active menu or submenu. Also fixed PageUp and PageDown so that they don't wrap back around to other end of menu. Also fixed scrolling to use activeMenu rather than element to all #397

Merged
merged 1 commit into from

3 participants

@kborchers
Owner

Menu: Added Home moves to first item and End moves to last item in currently active menu or submenu. Also fixed PageUp and PageDown so that they don't wrap back around to other end of menu. Also fixed scrolling to use activeMenu rather than element to allow scrollable submenus.

ui/jquery.ui.menu.js
@@ -409,7 +419,11 @@ $.widget( "ui.menu", {
this.focus( event, this.activeMenu.children( edge )[ filter ]() );
return;
}
- var next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
+ var next = direction === "first"
@gnarf Owner
gnarf added a note

I think that 423-426 are one too many tabs out...

Also, the double conditional expression seems a little confusing, perhaps an if would be more readable:

 var next;

 if ( direction === "first" || direction === "last" ) {
      next = this.active[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ).eq( -1 );
 } else {
      next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
 }

Other opinions?

@kborchers Owner

I think the if is more readable. I will make that change and rebase and resubmit. That's what I get for trying to get fancy. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@gnarf
Owner

It would be great if we could see some unit tests simulating these key events and verifying they do what is expected.

@kborchers
Owner

Updated the commit with those changes. Still working on unit tests

@jzaefferer jzaefferer commented on the diff
ui/jquery.ui.menu.js
@@ -252,17 +262,17 @@ $.widget( "ui.menu", {
this.blur();
if ( this._hasScroll() ) {
- var borderTop = parseFloat( $.curCSS( this.element[0], "borderTopWidth", true ) ) || 0,
- paddingTop = parseFloat( $.curCSS( this.element[0], "paddingTop", true ) ) || 0,
- offset = item.offset().top - this.element.offset().top - borderTop - paddingTop,
- scroll = this.element.scrollTop(),
- elementHeight = this.element.height(),
+ var borderTop = parseFloat( $.curCSS( this.activeMenu[0], "borderTopWidth", true ) ) || 0,
+ paddingTop = parseFloat( $.curCSS( this.activeMenu[0], "paddingTop", true ) ) || 0,
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop,
+ scroll = this.activeMenu.scrollTop(),
+ elementHeight = this.activeMenu.height(),
@jzaefferer Owner

What changed here?

@kborchers Owner

References to this.element changed to this.activeMenu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
ui/jquery.ui.menu.js
@@ -409,7 +419,14 @@ $.widget( "ui.menu", {
this.focus( event, this.activeMenu.children( edge )[ filter ]() );
return;
}
- var next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
+
+ var next;
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ).eq( -1 );
+ } else {
+ next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
@jzaefferer Owner

Whitespace messy? both 'next' should on the same level. Consider getting an editor that shows whitespace as some icon or autoformats properly...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
ui/jquery.ui.menu.js
@@ -89,6 +89,16 @@ $.widget( "ui.menu", {
event.preventDefault();
event.stopImmediatePropagation();
break;
+ case $.ui.keyCode.HOME:
+ self._move( "first", ".ui-menu-item", "first", event );
@jzaefferer Owner

Not a new issue, but the second argument seems to be pretty useless. Always has the same value, could as well get rid of that and inline it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jzaefferer
Owner

Lemme know when you've got the unit tests ready. Left a few code comments, rest looks solid.

@kborchers
Owner

Fixed white space, inlined the second argument to _move, still working on unit tests

@kborchers
Owner

Added first set of unit tests. Still need to test scrolling menu and scrolling submenu.

@kborchers
Owner

I went ahead and added the tests for scrolling menus. Hopefully they look ok.

@jzaefferer
Owner

Now this conflicts with the blur-event-test we landed earlier.

@kborchers kborchers Menu: Added Home moves to first item and End moves to last item in cu…
…rrently active menu or submenu. Also fixed PageUp and PageDown so that they don't wrap back around to other end of menu. Also fixed scrolling to use activeMenu rather than element to all. Also added unit tests for keyboard nav
23340f1
@kborchers
Owner

Fixed the blur-event-test conflict. Otherwise, do those tests look good?

@jzaefferer jzaefferer merged commit 23340f1 into from
@jzaefferer
Owner

Thanks, landed! The tests aren't pretty, but that was the case before adding these anyway. Nothing obvious to refactor, so something to get back to later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 25, 2011
  1. @kborchers

    Menu: Added Home moves to first item and End moves to last item in cu…

    kborchers authored
    …rrently active menu or submenu. Also fixed PageUp and PageDown so that they don't wrap back around to other end of menu. Also fixed scrolling to use activeMenu rather than element to all. Also added unit tests for keyboard nav
This page is out of date. Refresh to see the latest.
View
159 tests/unit/menu/menu.html
@@ -31,7 +31,7 @@
$("#log").data("lastItem",item);
$('li:eq(' + item + ') a',menu).trigger("click");
}
-
+
</script>
<script type="text/javascript" src="menu_core.js"></script>
@@ -41,10 +41,12 @@
<script type="text/javascript" src="menu_options.js"></script>
<script type="text/javascript" src="../swarminject.js"></script>
-
+
<style>
#qunit-fixture { font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; }
#list, #list1 *, #navigation, #navigation * { margin: 0; padding: 0; font-size: 12px; }
+ #menu3 { height: 250px; overflow: auto; }
+ #menu4, #menu4 ul { height: 250px; overflow: auto; }
</style>
</head>
<body>
@@ -66,6 +68,159 @@ <h2 id="qunit-userAgent"></h2>
<li class="foo"><a class="foo" href="#">Addyston</a></li>
<li class="foo"><a class="foo" href="#">Adelphi</a></li>
</ul>
+
+<ul id="menu2">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li>
+ <a href="#">Salzburg</a>
+ <ul>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Saarland</a></li>
+ <li class="foo"><a class="foo" href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Perch</a></li>
+ </ul>
+ </li>
+</ul>
+
+<ul class="foo" id="menu3">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+</ul>
+
+<ul class="foo" id="menu4">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo">
+ <a class="foo" href="#">Ada</a>
+ <ul class="foo">
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ </ul>
+ </li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+ <li class="foo"><a class="foo" href="#">Aberdeen</a></li>
+ <li class="foo"><a class="foo" href="#">Ada</a></li>
+ <li class="foo"><a class="foo" href="#">Adamsville</a></li>
+ <li class="foo"><a class="foo" href="#">Addyston</a></li>
+ <li class="foo"><a class="foo" href="#">Adelphi</a></li>
+ <li class="foo"><a class="foo" href="#">Adena</a></li>
+ <li class="foo"><a class="foo" href="#">Adrian</a></li>
+ <li class="foo"><a class="foo" href="#">Akron</a></li>
+ <li class="foo"><a class="foo" href="#">Albany</a></li>
+ <li class="foo"><a class="foo" href="#">Alexandria</a></li>
+ <li class="foo"><a class="foo" href="#">Alger</a></li>
+ <li class="foo"><a class="foo" href="#">Alledonia</a></li>
+ <li class="foo"><a class="foo" href="#">Alliance</a></li>
+ <li class="foo"><a class="foo" href="#">Alpha</a></li>
+ <li class="foo"><a class="foo" href="#">Alvada</a></li>
+ <li class="foo"><a class="foo" href="#">Alvordton</a></li>
+ <li class="foo"><a class="foo" href="#">Amanda</a></li>
+ <li class="foo"><a class="foo" href="#">Amelia</a></li>
+ <li class="foo"><a class="foo" href="#">Amesville</a></li>
+</ul>
+
<div id="log"></div>
</div>
View
305 tests/unit/menu/menu_events.js
@@ -42,4 +42,309 @@ test( "handle blur: click", function() {
$("#remove").remove();
});
+test("handle keyboard navigation on menu without scroll and without submenus", function() {
+ expect(12);
+ var element = $('#menu1').menu({
+ select: function(event, ui) {
+ log($(ui.item[0]).text());
+ },
+ focus: function( event, ui ) {
+ log($(event.target).find(".ui-state-focus").parent().index());
+ }
+ });
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equals( $("#log").html(), "keydown,", "Keydown RIGHT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "4,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equals( $("#log").html(), "4,keydown,", "Keydown END");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equals( $("#log").html(), "0,keydown,", "Keydown HOME");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equals( $("#log").html(), "keydown,", "Keydown ESCAPE (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER");
+});
+
+asyncTest("handle keyboard navigation on menu without scroll and with submenus", function() {
+ expect(14);
+ var element = $('#menu2').menu({
+ select: function(event, ui) {
+ log($(ui.item[0]).text());
+ },
+ focus: function( event, ui ) {
+ log($(event.target).find(".ui-state-focus").parent().index());
+ }
+ });
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ equals( $("#log").html(), "0,4,3,2,1,keydown,", "Keydown RIGHT (open submenu)");
+ }, 50);
+
+ setTimeout( function() {
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "4,keydown,", "Keydown LEFT (close submenu)");
+
+ //re-open submenu
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "2,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equals( $("#log").html(), "2,keydown,", "Keydown END");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equals( $("#log").html(), "0,keydown,", "Keydown HOME");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equals( $("#log").html(), "4,keydown,", "Keydown ESCAPE (close submenu)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+
+ setTimeout( function() {
+ equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equals( $("#log").html(), "Ada,keydown,", "Keydown ENTER (select item)");
+
+ start();
+ }, 200);
+ }, 150);
+ }, 100);
+
+});
+
+test("handle keyboard navigation on menu with scroll and without submenus", function() {
+ expect(14);
+ var element = $('#menu3').menu({
+ select: function(event, ui) {
+ log($(ui.item[0]).text());
+ },
+ focus: function( event, ui ) {
+ log($(event.target).find(".ui-state-focus").parent().index());
+ }
+ });
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+ equals( $("#log").html(), "keydown,", "Keydown RIGHT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equals( $("#log").html(), "37,keydown,", "Keydown END");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equals( $("#log").html(), "0,keydown,", "Keydown HOME");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equals( $("#log").html(), "keydown,", "Keydown ESCAPE (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER");
+});
+
+asyncTest("handle keyboard navigation on menu with scroll and with submenus", function() {
+ expect(14);
+ var element = $('#menu4').menu({
+ select: function(event, ui) {
+ log($(ui.item[0]).text());
+ },
+ focus: function( event, ui ) {
+ log($(event.target).find(".ui-state-focus").parent().index());
+ }
+ });
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ equals( $("#log").html(), "0,1,keydown,", "Keydown RIGHT (open submenu)");
+ }, 50);
+
+ setTimeout( function() {
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } );
+ equals( $("#log").html(), "1,keydown,", "Keydown LEFT (close submenu)");
+
+ //re-open submenu
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } );
+
+ setTimeout( function() {
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } );
+ equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } );
+ equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.END } );
+ equals( $("#log").html(), "27,keydown,", "Keydown END");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } );
+ equals( $("#log").html(), "0,keydown,", "Keydown HOME");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } );
+ equals( $("#log").html(), "1,keydown,", "Keydown ESCAPE (close submenu)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+
+ setTimeout( function() {
+ equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)");
+
+ log("keydown",true);
+ element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } );
+ equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER (select item)");
+
+ start();
+ }, 200);
+ }, 150);
+ }, 100);
+
+});
+
})(jQuery);
View
61 ui/jquery.ui.menu.js
@@ -89,6 +89,16 @@ $.widget( "ui.menu", {
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();
@@ -252,17 +262,17 @@ $.widget( "ui.menu", {
this.blur( event );
if ( this._hasScroll() ) {
- var borderTop = parseFloat( $.curCSS( this.element[0], "borderTopWidth", true ) ) || 0,
- paddingTop = parseFloat( $.curCSS( this.element[0], "paddingTop", true ) ) || 0,
- offset = item.offset().top - this.element.offset().top - borderTop - paddingTop,
- scroll = this.element.scrollTop(),
- elementHeight = this.element.height(),
+ var borderTop = parseFloat( $.curCSS( this.activeMenu[0], "borderTopWidth", true ) ) || 0,
+ paddingTop = parseFloat( $.curCSS( this.activeMenu[0], "paddingTop", true ) ) || 0,
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop,
+ scroll = this.activeMenu.scrollTop(),
+ elementHeight = this.activeMenu.height(),
@jzaefferer Owner

What changed here?

@kborchers Owner

References to this.element changed to this.activeMenu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
itemHeight = item.height();
if ( offset < 0 ) {
- this.element.scrollTop( scroll + offset );
+ this.activeMenu.scrollTop( scroll + offset );
} else if ( offset + itemHeight > elementHeight ) {
- this.element.scrollTop( scroll + offset - elementHeight + itemHeight );
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
}
}
@@ -391,11 +401,11 @@ $.widget( "ui.menu", {
},
next: function(event) {
- this._move( "next", ".ui-menu-item", "first", event );
+ this._move( "next", "first", event );
},
previous: function(event) {
- this._move( "prev", ".ui-menu-item", "last", event );
+ this._move( "prev", "last", event );
},
first: function() {
@@ -406,25 +416,36 @@ $.widget( "ui.menu", {
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
},
- _move: function( direction, edge, filter, event ) {
+ _move: function( direction, filter, event ) {
if ( !this.active ) {
- this.focus( event, this.activeMenu.children( edge )[ filter ]() );
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )[ filter ]() );
return;
}
- var next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
+
+ var next;
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ).eq( -1 );
+ } else {
+ next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 );
+ }
+
if ( next.length ) {
this.focus( event, next );
} else {
- this.focus( event, this.activeMenu.children( edge )[ filter ]() );
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )[ filter ]() );
}
},
nextPage: function( event ) {
if ( this._hasScroll() ) {
- if ( !this.active || this.last() ) {
+ if ( !this.active ) {
this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
return;
}
+ if ( this.last() ) {
+ return;
+ }
+
var base = this.active.offset().top,
height = this.element.height(),
result;
@@ -436,14 +457,17 @@ $.widget( "ui.menu", {
this.focus( event, result );
} else {
this.focus( event, this.activeMenu.children( ".ui-menu-item" )
- [ !this.active || this.last() ? "first" : "last" ]() );
+ [ !this.active ? "first" : "last" ]() );
}
},
previousPage: function( event ) {
if ( this._hasScroll() ) {
- if ( !this.active || this.first() ) {
- this.focus( event, this.activeMenu.children( ".ui-menu-item" ).last() );
+ if ( !this.active ) {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ return;
+ }
+ if ( this.first() ) {
return;
}
@@ -457,8 +481,7 @@ $.widget( "ui.menu", {
this.focus( event, result );
} else {
- this.focus( event, this.activeMenu.children( ".ui-menu-item" )
- [ !this.active || this.first() ? ":last" : ":first" ]() );
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
}
},
Something went wrong with that request. Please try again.