Skip to content
Permalink
Browse files

Menu: Overhauled nested menu via flyoutmenu.js backported from Michael

Lang's fork. Changed key input handling by setting focus to menu,
getting rid of input option.
  • Loading branch information...
jzaefferer committed Feb 22, 2011
1 parent a1eaac8 commit 355705878a22c6d00f242f0d8d93d03a097935e1
Showing with 176 additions and 146 deletions.
  1. +7 −6 tests/visual/menu/contextmenu.html
  2. +149 −0 tests/visual/menu/flyoutmenu.js
  3. +19 −136 tests/visual/menu/nested.html
  4. +1 −4 ui/jquery.ui.menu.js
@@ -9,7 +9,9 @@
<script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script>
<script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script>
<script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script>
<!--
<script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
-->
<script type="text/javascript">
$(function() {
$.fn.themeswitcher && $('<div/>').css({
@@ -21,10 +23,9 @@
$("button").each(function() {
$(this).next().menu({
select: function(event, ui) {
$(this).hide();
$(this).hide().prev().focus();
$("#log").append("<div>Selected " + ui.item.text() + "</div>");
},
input: $(this)
}
}).hide();
}).click(function(event) {
// TODO required to prevent the click handler below from handling this event
@@ -33,12 +34,12 @@
my: "left top",
at: "right top",
of: event.pageX > 0 ? event : this
});
}).focus();
$(document).one("click", function() {
menu.hide();
})
}).keydown(function(event) {
var menu = $("#menu" + this.id).data("menu");
}).next().keydown(function(event) {
var menu = $(this).data("menu");
if (menu.widget().is(":hidden"))
return;
event.stopPropagation();
@@ -0,0 +1,149 @@
/*
* jQuery UI flyout menu
* - written for jQuery UI 1.9 milestone 2 using the widget factory
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* modified from: http://view.jqueryui.com/menu/tests/visual/menu/nested.html
* by: Michael Lang, http://nexul.com/
*
*/
(function($) {

$.widget("ui.flyoutmenu", {
_create: function() {
var self = this;
this.active = this.element;
this.activeItem = this.element.children("li").first();
// hide submenus and create indicator icons
this.element.find("ul").addClass("ui-menu-flyout").hide().prev("a").prepend('<span class="ui-icon ui-icon-carat-1-e"></span>');

this.element.find("ul").andSelf().menu({
select: function(event) {
self._select(event);
},
focus: function(event, ui) {
self.active = ui.item.parent();
self.activeItem = ui.item;
ui.item.parent().find("ul").hide();
var nested = $(">ul", ui.item);
if (nested.length && event.originalEvent && /^mouse/.test(event.originalEvent.type)) {
self._open(nested);
}
}
}).keydown(function(event) {
if (self.element.is(":hidden"))
return;
event.stopPropagation();
switch (event.keyCode) {
case $.ui.keyCode.LEFT:
self.left(event);
event.preventDefault();
break;
case $.ui.keyCode.RIGHT:
self.right(event);
event.preventDefault();
break;
case $.ui.keyCode.ESCAPE:
self.hide();
break;
default:
clearTimeout(self.filterTimer);
var prev = self.previousFilter || "";
var character = String.fromCharCode(event.keyCode);
var skip = false;
if (character == prev) {
skip = true;
} else {
character = prev + character;
}

var match = self.activeItem.parent("ul").children("li").filter(function() {
return new RegExp("^" + character, "i").test($("a", this).text());
});
var match = skip && match.index(self.active.next()) != -1 ? match.next() : match;
if (!match.length) {
character = String.fromCharCode(event.keyCode);
match = self.widget().children("li").filter(function() {
return new RegExp("^" + character, "i").test($(this).text());
});
}
if (match.length) {
self.activate(event, match);
if (match.length > 1) {
self.previousFilter = character;
self.filterTimer = setTimeout(function() {
delete self.previousFilter;
}, 1000);
} else {
delete self.previousFilter;
}
} else {
delete self.previousFilter;
}
}
});
},
_open: function(submenu) {
// TODO restrict to widget
//only one menu can have items open at a time.
$(document).find(".ui-menu-flyout").not(submenu.parents()).hide();
submenu.show().css({
top: 0,
left: 0
}).position({
my: "left top",
at: "right top",
of: this.activeItem
});
$(document).one("click", function() {
//clicking outside menu flyouts should close all flyouts
//$(document).find(".ui-menu-flyout").hide();
})
},
_select: function(event) {
event.stopPropagation();
// TODO make _select cancelable?
this._trigger( "select", event, { item: this.activeItem } );
//this.activate(event, this.element.children("li").first());
this.hide();
},
left: function(event) {
var newItem = this.activeItem.parents("li").first();
if (newItem.length) {
this.activate(event, newItem);
}
},
right: function(event) {
var newItem = this.activeItem.children("ul").children("li").first();
if (newItem.length) {
this._open(newItem.parent());
this.activate(event, newItem);
}
},
activate: function(event, item) {
if (item) {
item.parent().data("menu").widget().show();
item.parent().data("menu").activate(event, item);
}
this.activeItem = item;
this.active = item.parent("ul")
this.active.focus();
},
show: function() {
this.active = this.element;
this.element.show();
if (this.element.hasClass("ui-menu-flyout")) {
$(document).one("click", function() {
//clicking outside menu flyouts should close all flyouts
//$(document).find(".ui-menu-flyout").hide();
})
}
},
hide: function() {
this.activeItem = this.element.children("li").first();
this.element.find("ul").andSelf().menu("deactivate").hide();
}
});

}(jQuery));
@@ -9,8 +9,11 @@
<script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script>
<script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script>
<script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script>
<script type="text/javascript" src="../../../external/jquery.bgiframe-2.1.1.js"></script>
<script type="text/javascript" src="../../../external/jquery.bgiframe-2.1.2.js"></script>
<script type="text/javascript" src="flyoutmenu.js"></script>
<!--
<script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
-->
<script type="text/javascript">
$(function() {
$.fn.themeswitcher && $('<div/>').css({
@@ -19,73 +22,14 @@
top: 10
}).appendTo(document.body).themeswitcher();
$.widget("ui.nestedmenu", {
_init: function() {
var self = this;
this.active = this.element;
// hide submenus and create indicator icons
this.element.find("ul").hide().prev("a").prepend('<span class="ui-icon ui-icon-carat-1-e"></span>');
this.element.find("ul").andSelf().menu({
// disable built-in key handling
input: $(),
select: this.options.select,
focus: function(event, ui) {
self.active = ui.item.parent();
self.activeItem = ui.item;
ui.item.parent().find("ul").hide();
var nested = $(">ul", ui.item);
if (nested.length && /^mouse/.test(event.originalEvent.type)) {
self._open(nested);
}
}
})
},
_open: function(submenu) {
submenu.show().css({
top: 0,
left: 0
}).position({
my: "left top",
at: "right top",
of: this.activeItem
});
},
up: function(event) {
this.active = this.active.menu("deactivate").hide().parent().parent();
this.activeItem = this.active.data("menu").active;
},
down: function(event) {
var submenu = $(">ul", this.activeItem);
this._open(submenu, this.activeItem);
submenu.menu("activate", event, submenu.children(":first"));
},
show: function() {
this.active = this.element;
this.element.show();
},
hide: function() {
this.element.find("ul").andSelf().menu("deactivate").hide();
}
});
var menu = $("#menu");
var nestedmenu = $("#menu").nestedmenu({
select: function(event, ui) {
$("#log").append("<div>Selected " + ui.item.text() + "</div>");
}
}).hide();
$("button").click(function(event) {
var button = $("button").click(function(event) {
// TODO required to prevent the click handler below from handling this event
event.stopPropagation();
nestedmenu.nestedmenu("show")
menu.flyoutmenu("show")
//.attr("tabIndex", 0)
.focus()
.css({
top: 0,
left: 0
@@ -96,78 +40,17 @@
of: this
});
$(document).one("click", function() {
nestedmenu.nestedmenu("hide");
})
}).keydown(function(event) {
var menu = nestedmenu.data("nestedmenu").active.data("menu");
if (menu.widget().is(":hidden"))
return;
event.stopPropagation();
switch (event.keyCode) {
case $.ui.keyCode.PAGE_UP:
menu.previousPage(event);
break;
case $.ui.keyCode.PAGE_DOWN:
menu.nextPage(event);
break;
case $.ui.keyCode.UP:
menu.previous(event);
break;
case $.ui.keyCode.LEFT:
nestedmenu.nestedmenu("up", event);
break;
case $.ui.keyCode.RIGHT:
nestedmenu.nestedmenu("down", event);
break;
case $.ui.keyCode.DOWN:
menu.next(event);
event.preventDefault();
break;
case $.ui.keyCode.ENTER:
case $.ui.keyCode.TAB:
menu.select();
nestedmenu.nestedmenu("hide");
event.preventDefault();
break;
case $.ui.keyCode.ESCAPE:
nestedmenu.nestedmenu("hide");
break;
default:
clearTimeout(menu.filterTimer);
var prev = menu.previousFilter || "";
var character = String.fromCharCode(event.keyCode);
var skip = false;
if (character == prev) {
skip = true;
} else {
character = prev + character;
}
var match = menu.widget().children("li").filter(function() {
return new RegExp("^" + character, "i").test($("a", this).text());
});
var match = skip && match.index(menu.active.next()) != -1 ? match.next() : match;
if (!match.length) {
character = String.fromCharCode(event.keyCode);
match = menu.widget().children("li").filter(function() {
return new RegExp("^" + character, "i").test($(this).text());
});
}
if (match.length) {
menu.activate(event, match);
if (match.length > 1) {
menu.previousFilter = character;
menu.filterTimer = setTimeout(function() {
delete menu.previousFilter;
}, 1000);
} else {
delete menu.previousFilter;
}
} else {
delete menu.previousFilter;
}
}
menu.flyoutmenu("hide");
});
});
menu.flyoutmenu({
//input: button,
select: function(event, ui) {
$("#log").append("<div>Selected " + ui.item.children("a").text() + "</div>");
button.focus();
}
}).hide();
});
</script>
<style>
@@ -57,10 +57,7 @@ $.widget("ui.menu", {
});
this.refresh();

if ( !this.options.input ) {
this.options.input = this.element.attr( "tabIndex", 0 );
}
this.options.input.bind( "keydown.menu", function( event ) {
this.element.attr( "tabIndex", 0 ).bind( "keydown.menu", function( event ) {
if ( self.options.disabled ) {
return;
}

0 comments on commit 3557058

Please sign in to comment.
You can’t perform that action at this time.