Modified:
/branches/dev/tests/visual/menu/nested.html
=======================================
--- /branches/dev/tests/visual/menu/nested.html Mon Nov 9 03:10:32 2009
+++ /branches/dev/tests/visual/menu/nested.html Mon Nov 9 05:11:21 2009
@@ -9,67 +9,98 @@
<script type="text/javascript"
src="../../../ui/jquery.ui.core.js"></script>
<script type="text/javascript"
src="../../../ui/jquery.ui.menu.js"></script>
<script type="text/javascript"
src="../../../ui/jquery.ui.position.js"></script>
- <script type="text/javascript"
src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
<script type="text/javascript">
$(function() {
- $.fn.themeswitcher && $('<div/>').css({
- position: "absolute",
- right: 10,
- top: 10
- }).appendTo(document.body).themeswitcher();
-
-
- var submenu;
- var menu = $("#menu").menu({
+ $.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({
+ selected: this.options.selected,
+ focus: function(event, ui) {
+ self.active = ui.item.parent();
+ // put a previous submenu back into its place and hide it
+ self.hideDown();
+ var nested = $(">ul", ui.item);
+ if (nested.length) {
+ // append to body in order to display the submenu above the parent
menu, instead of inside of it
+ nested.appendTo(document.body).menu("deactivate").show().position({
+ my: "left top",
+ at: "right top",
+ of: ui.item
+ // store the current submenu
+ }).data("menuparent", ui.item);
+
+ self.active.data("submenu", nested);
+ }
+ }
+ })
+ },
+
+ up: function() {
+ if (!this.active.data("menuparent"))
+ return;
+ this.active.menu("deactivate");
+ this.active = this.active.data("menuparent").parent();
+ },
+
+ down: function() {
+ var submenu = this.active.data("submenu");
+ if (!submenu)
+ return;
+ submenu.data("menu").activate(submenu.children(":first"))
+ this.active = submenu;
+ },
+
+ show: function() {
+ this.element.menu("deactivate").show();
+ this.active = this.element;
+ },
+
+ hide: function() {
+ this.hideDown();
+ var child = this.active.hide(), parent;
+ while(child.data("menuparent")) {
+ parent = child.data("menuparent");
+ child.appendTo(parent).removeData("menuparent");
+ child = parent.parent().removeData("submenu").hide();
+ }
+ },
+
+ hideDown: function() {
+ var submenu = this.active.data("submenu");
+ while(submenu) {
+ var parent = submenu.data("menuparent");
+ submenu.appendTo(parent).hide().removeData("menuparent");
+ parent.parent().removeData("submenu");
+ submenu = submenu.data("submenu");
+ };
+ }
+ });
+
+ var nestedmenu = $("#menu").nestedmenu({
selected: function(event, ui) {
$("#log").append("<div>Selected " + ui.item.text() + "</div>");
- },
- focus: function(event, ui) {
- // put a previous submenu back into its place and hide it
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent")).hide();
- submenu = null;
- }
- var nested = $("ul", ui.item);
- if (nested.length) {
- nested.menu({
- selected: function(event, ui) {
- $("#log").append("<div>Selected " + ui.item.text() + "</div>");
- }
- // append to body in order to display the submenu above the parent
menu, instead of inside of it
- }).appendTo(document.body).menu("deactivate").show().position({
- my: "left top",
- at: "right top",
- of: ui.item
- });
- // store the current submenu
- submenu = nested;
- submenu.data("menuparent", ui.item);
- }
}
}).hide();
- // hide submenus and create indicator icons
- menu.find("ul").hide().prev("a").prepend('<span class="ui-icon
ui-icon-carat-1-e"></span>');
-
-
$("button").click(function(event) {
// TODO required to prevent the click handler below from handling this
event
event.stopPropagation();
- $("#menu").menu("deactivate").show().position({
+ nestedmenu.nestedmenu("show").position({
my: "left top",
at: "right top",
of: event.pageX > 0 ? event : this
});
$().one("click", function() {
- menu.hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent")).hide();
- submenu = null;
- }
+ nestedmenu.nestedmenu("hide");
})
}).keydown(function(event) {
- var menu = submenu && submenu.data("menufocussed") &&
submenu.data("menu") || $("#menu" + this.id).data("menu");
+ var menu = nestedmenu.data("nestedmenu").active.data("menu");
if (menu.widget().is(":hidden"))
return;
event.stopPropagation();
@@ -84,17 +115,10 @@
menu.previous();
break;
case $.ui.keyCode.LEFT:
- if (submenu && submenu.data("menufocussed")) {
- submenu.data("menufocussed", false);
- menu.deactivate();
- }
+ nestedmenu.nestedmenu("up");
break;
case $.ui.keyCode.RIGHT:
- if (submenu) {
- submenu.data("menufocussed", true);
- menu = submenu.data("menu");
- menu.activate(menu.element.children(":first"));
- }
+ nestedmenu.nestedmenu("down");
break;
case $.ui.keyCode.DOWN:
menu.next();
@@ -103,25 +127,11 @@
case $.ui.keyCode.ENTER:
case $.ui.keyCode.TAB:
menu.select();
- menu.widget().hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent"));
- submenu.removeData("menuparent");
- submenu = null;
- // also hide parent
- $("#menu" + this.id).hide();
- }
+ nestedmenu.nestedmenu("hide");
event.preventDefault();
break;
case $.ui.keyCode.ESCAPE:
- menu.widget().hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent"));
- submenu.removeData("menuparent");
- submenu = null;
- // also hide parent
- $("#menu" + this.id).hide();
- }
+ nestedmenu.nestedmenu("hide");
break;
default:
clearTimeout(menu.filterTimer);
@@ -177,7 +187,23 @@
<ul>
<li><a href="#">Aberdeen</a></li>
<li><a href="#">Ada</a></li>
- <li><a href="#">Adamsville</a></li>
+ <li>
+ <a href="#">Adamsville</a>
+ <ul>
+ <li><a href="#">Anaheim</a></li>
+ <li>
+ <a href="#">Cologne</a>
+ <ul>
+ <li><a href="#">Mberdeen</a></li>
+ <li><a href="#">Mda</a></li>
+ <li><a href="#">Mdamsville</a></li>
+ <li><a href="#">Mddyston</a></li>
+ <li><a href="#">Mmesville</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Frankfurt</a></li>
+ </ul>
+ </li>
<li><a href="#">Addyston</a></li>
<li><a href="#">Amesville</a></li>
</ul>
aria-owns attribute indicates that the div with id "external_listitem" should be considered a child of the ul element with the property, even though it is not a child in the DOM."Dunno what an "embedded hierachy" is supposed to be, just plain nested lists? What are alternative workarounds for the scrolling issue?
BTW, it would be nice if code in the core and in all jQuery libraries
followed the convention of prefixing jQuery objects with "$". This
would make it easier to follow because "elem" would always be the DOM-
element and $elem the elem wrapped in a jQuery object. This would
avoid the different syntax in each area, like "curElem", which still
doesn't make clear whether it is a DOM or jQuery reference. (though
the setOffset method is so small that it's not a problem)
The same '$name' standard should apply to UI widgets. It makes object
pointers crystal clear. It also creates a clear relationship between
the DOM and jQuery objects, eg: $(menu) = $menu
Just my 2-cents.