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. Also added unit tests for keyboard nav

This commit is contained in:
kborchers 2011-07-25 09:13:13 -05:00
parent 51ee3be398
commit 23340f1162
3 changed files with 504 additions and 21 deletions

View File

@ -45,6 +45,8 @@
<style> <style>
#qunit-fixture { font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; } #qunit-fixture { font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; }
#list, #list1 *, #navigation, #navigation * { margin: 0; padding: 0; font-size: 12px; } #list, #list1 *, #navigation, #navigation * { margin: 0; padding: 0; font-size: 12px; }
#menu3 { height: 250px; overflow: auto; }
#menu4, #menu4 ul { height: 250px; overflow: auto; }
</style> </style>
</head> </head>
<body> <body>
@ -66,6 +68,159 @@
<li class="foo"><a class="foo" href="#">Addyston</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="#">Adelphi</a></li>
</ul> </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 id="log"></div>
</div> </div>

View File

@ -42,4 +42,309 @@ test( "handle blur: click", function() {
$("#remove").remove(); $("#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); })(jQuery);

61
ui/jquery.ui.menu.js vendored
View File

@ -89,6 +89,16 @@ $.widget( "ui.menu", {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
break; 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: case $.ui.keyCode.UP:
self.previous( event ); self.previous( event );
event.preventDefault(); event.preventDefault();
@ -252,17 +262,17 @@ $.widget( "ui.menu", {
this.blur( event ); this.blur( event );
if ( this._hasScroll() ) { if ( this._hasScroll() ) {
var borderTop = parseFloat( $.curCSS( this.element[0], "borderTopWidth", true ) ) || 0, var borderTop = parseFloat( $.curCSS( this.activeMenu[0], "borderTopWidth", true ) ) || 0,
paddingTop = parseFloat( $.curCSS( this.element[0], "paddingTop", true ) ) || 0, paddingTop = parseFloat( $.curCSS( this.activeMenu[0], "paddingTop", true ) ) || 0,
offset = item.offset().top - this.element.offset().top - borderTop - paddingTop, offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop,
scroll = this.element.scrollTop(), scroll = this.activeMenu.scrollTop(),
elementHeight = this.element.height(), elementHeight = this.activeMenu.height(),
itemHeight = item.height(); itemHeight = item.height();
if ( offset < 0 ) { if ( offset < 0 ) {
this.element.scrollTop( scroll + offset ); this.activeMenu.scrollTop( scroll + offset );
} else if ( offset + itemHeight > elementHeight ) { } 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) { next: function(event) {
this._move( "next", ".ui-menu-item", "first", event ); this._move( "next", "first", event );
}, },
previous: function(event) { previous: function(event) {
this._move( "prev", ".ui-menu-item", "last", event ); this._move( "prev", "last", event );
}, },
first: function() { first: function() {
@ -406,25 +416,36 @@ $.widget( "ui.menu", {
return this.active && !this.active.nextAll( ".ui-menu-item" ).length; return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
}, },
_move: function( direction, edge, filter, event ) { _move: function( direction, filter, event ) {
if ( !this.active ) { if ( !this.active ) {
this.focus( event, this.activeMenu.children( edge )[ filter ]() ); this.focus( event, this.activeMenu.children( ".ui-menu-item" )[ filter ]() );
return; 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 ) { if ( next.length ) {
this.focus( event, next ); this.focus( event, next );
} else { } else {
this.focus( event, this.activeMenu.children( edge )[ filter ]() ); this.focus( event, this.activeMenu.children( ".ui-menu-item" )[ filter ]() );
} }
}, },
nextPage: function( event ) { nextPage: function( event ) {
if ( this._hasScroll() ) { if ( this._hasScroll() ) {
if ( !this.active || this.last() ) { if ( !this.active ) {
this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
return; return;
} }
if ( this.last() ) {
return;
}
var base = this.active.offset().top, var base = this.active.offset().top,
height = this.element.height(), height = this.element.height(),
result; result;
@ -436,14 +457,17 @@ $.widget( "ui.menu", {
this.focus( event, result ); this.focus( event, result );
} else { } else {
this.focus( event, this.activeMenu.children( ".ui-menu-item" ) this.focus( event, this.activeMenu.children( ".ui-menu-item" )
[ !this.active || this.last() ? "first" : "last" ]() ); [ !this.active ? "first" : "last" ]() );
} }
}, },
previousPage: function( event ) { previousPage: function( event ) {
if ( this._hasScroll() ) { if ( this._hasScroll() ) {
if ( !this.active || this.first() ) { if ( !this.active ) {
this.focus( event, this.activeMenu.children( ".ui-menu-item" ).last() ); this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
return;
}
if ( this.first() ) {
return; return;
} }
@ -457,8 +481,7 @@ $.widget( "ui.menu", {
this.focus( event, result ); this.focus( event, result );
} else { } else {
this.focus( event, this.activeMenu.children( ".ui-menu-item" ) this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
[ !this.active || this.first() ? ":last" : ":first" ]() );
} }
}, },