r3424 committed - menu: nested menu refactoring, for now as its own widget

r3424 committed - menu: nested menu refactoring, for now as its own widget


Revision: 3424
Author: joern.zaefferer
Date: Mon Nov 9 05:11:21 2009
Log: menu: nested menu refactoring, for now as its own widget
http://code.google.com/p/jquery-ui/source/detail?r=3424
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>