From 150c3df7b61b87ca4cc251625df987290f3866b0 Mon Sep 17 00:00:00 2001 From: Rolux Date: Fri, 5 Feb 2010 14:43:03 +0530 Subject: [PATCH] some more menu and keyboard navigation --- build/js/ox.ui.js | 217 ++++++++++++++++++++++++++++++++++----------- demos/test/menu.js | 41 +++++++-- 2 files changed, 198 insertions(+), 60 deletions(-) diff --git a/build/js/ox.ui.js b/build/js/ox.ui.js index 154ff97c..6cba1500 100644 --- a/build/js/ox.ui.js +++ b/build/js/ox.ui.js @@ -47,7 +47,6 @@ requires }(), path: $("script[src*=ox.ui.js]").attr("src") .replace("js/ox.ui.js", ""), - stack: [], // fixme: used? symbols: { // fixme: make lowercase alt: "\u2325", apple: "\uF8FF", @@ -203,21 +202,52 @@ requires // use dom elements / jquery instead + Ox.Event = function() { - var $eventHandler = $("
"); + var keyboardEvents = {}; + $eventHandler = $("
"); + function isKeyboardEvent(event) { + return event.substr(0, 4) == "key_"; + } return { - bind: function(event, callback) { - $eventHandler.bind(event, callback); + bind: function(id, event, callback) { + if (isKeyboardEvent(event)) { + keyboardEvents[id] = keyboardEvents[id] || []; + keyboardEvents[id].push({ + event: event, + callback: callback + }); + } + if (!isKeyboardEvent(event) || Ox.Focus.focused() == id) { + $eventHandler.bind(event, callback); + } }, - one: function(event, callback) { - $eventHandler.one(event, callback); + bindKeyboard: function(id) { + $.each(keyboardEvents[id] || [], function(i, event) { + Ox.Event.bind(id, event.event, event.callback); + }); }, trigger: function(event, data) { Ox.print("trigger", event, data || {}); $eventHandler.trigger(event, data || {}); }, - unbind: function(event, callback) { + unbind: function(id, event, callback) { + if (isKeyboardEvent(event)) { + $.each(keyboardEvents[id] || [], function(i, e) { + if (e.event == event) { + keyboardEvents[id].splice(i, 1); + return false; + } + }); + } $eventHandler.unbind(event, callback); + }, + unbindKeyboard: function(id) { + //Ox.print(keyboardEvents) + //Ox.print("unbindKeyboard", id, keyboardEvents[id]) + $.each(keyboardEvents[id] || [], function(i, e) { + $eventHandler.unbind(e.event, e.callback); + }); } } }(); @@ -265,14 +295,31 @@ requires var stack = []; return { focus: function(id) { + /* + if (stack.length) { + Ox.Event.unbindKeyboard(stack[stack.length - 1]); + } + */ var index = stack.indexOf(id); if (index > -1) { - oxui.stack.splice(i, 1); + stack.splice(index, 1); } - oxui.stack.push(id); + stack.push(id); + Ox.Event.bindKeyboard(id); + console.log("focus", stack); + }, + focused: function() { + return stack[stack.length - 1]; }, blur: function(id) { - oxui.stack.pop(); + if (stack.indexOf(id) > -1) { + stack.splice(stack.length - 2, 0, stack.pop()); + } + Ox.Event.unbindKeyboard(id); + /* + Ox.Event.bindKeyboard(stack[stack.length - 1]); + */ + console.log("blur", stack); } }; }(); @@ -438,7 +485,7 @@ requires buffer += key == "SPACE" ? " " : key; bufferTime = time; } - Ox.Event.trigger("key." + key); + Ox.Event.trigger("key_" + key); /* $.each(stack, function(i, v) { // fixme: we dont get the return value! @@ -656,7 +703,6 @@ requires }; }(); - /* ---------------------------------------------------------------------------- Ox.URL @@ -771,20 +817,35 @@ requires }; // public + that.bindEvent = function() { + /* + bindEvent(event, fn) or bindEvent({event0: fn0, event1: fn1, ...}) + */ + if (arguments.length == 1) { + $.each(arguments[0], function(event, fn) { + Ox.Event.bind(that.id, event, fn); + }) + } else { + Ox.Event.bind(that.id, arguments[0], arguments[1]); + } + }; that.defaults = function(defaults) { /* that.defaults({foo: x}) sets self.defaults */ self.defaults = defaults; return that; - } - that.gain = function() { - Ox.Focus.gain(that.id); - } - that.lose = function() { - Ox.Focus.lose(that.id); - } - that.options = function() { + }; + that.gainFocus = function() { + Ox.Focus.focus(that.id); + }; + that.hasFocus = function() { + return Ox.Focus.focused() == that.id; + }; + that.loseFocus = function() { + Ox.Focus.blur(that.id); + }; + that.options = function() { // fixme: use Ox.getset /* that.options() returns self.options that.options("foo") returns self.options.foo @@ -817,26 +878,21 @@ requires } return ret; } - that.publish = function() { - arguments[0] = arguments[0] + "." + that.id; - Ox.Event.publish.apply(that, arguments); - // or, maybe better: - $(".OxWidget").trigger.apply(that, arguments); - return that; - } that.remove = function() { that.$element.remove(); delete elements[that.ox]; } - that.subscribe = function() { - Ox.Event.subscribe.apply(that, arguments); - // or - that.$element.bind.apply(that, arguments); - return that; - } - that.unsubscribe = function() { - Ox.Event.unsubscribe.apply(that, arguments); - return that; + that.unbindEvent = function() { + /* + unbindEvent(event, fn) or unbindEvent({event0: fn0, event1: fn1, ...}) + */ + if (arguments.length == 1) { + $.each(arguments[0], function(event, fn) { + Ox.Event.unbind(that.id, event, fn); + }) + } else { + Ox.Event.unbind(that.id, arguments[0], arguments[1]); + } } // return @@ -1694,9 +1750,10 @@ requires left: 0, top: 0 }, + parent: null, selected: -1, side: "bottom", - size: "medium" + size: "medium", }) .options(options) .addClass( @@ -1740,8 +1797,9 @@ requires left: 0, top: -4 }, + parent: that, side: "right", - size: self.options.size + size: self.options.size, }); } } else { @@ -1756,6 +1814,12 @@ requires .addClass("OxBottom") .appendTo(that.$element); + function click(event) { + if (!$(event.target).is(".OxCell")) { + that.hideMenu(); + } + } + function clickItem() { if (self.options.selected > -1) { that.items[self.options.selected].trigger("click"); @@ -1823,6 +1887,7 @@ requires } function getElement(id) { + // fixme: needed? return $("#" + Ox.toCamelCase(options.id + "/" + id)); } @@ -1898,6 +1963,37 @@ requires } } + function selectSubmenu() { + var submenu = that.submenus[that.items[self.options.selected].options("id")]; + if (submenu && submenu.hasEnabledItems()) { + that.loseFocus(); + submenu.gainFocus(); + submenu.selectFirstItem(); + } + } + + function selectSupermenu() { + if (self.options.parent) { + that.items[self.options.selected].trigger("mouseleave"); + that.loseFocus(); + self.options.parent.gainFocus(); + } + } + + self.onChange = function(key, value) { + + } + + that.hasEnabledItems = function() { + var ret = false; + $.each(that.items, function(i, item) { + if (!item.options("disabled")) { + return ret = true; + } + }); + return ret; + }; + that.hideMenu = function() { Ox.print("hideMenu") $.each(that.submenus, function(i, submenu) { @@ -1911,11 +2007,20 @@ requires if (self.options.selected > -1) { that.items[self.options.selected].trigger("mouseleave"); } - Ox.Event.unbind("key down", selectNextItem); - Ox.Event.unbind("key up", selectPreviousItem); - Ox.Event.unbind("key.escape", that.hideMenu); - Ox.Event.unbind("key.enter", clickItem); - $document.unbind("click", that.hideMenu); + that.loseFocus(); + that.unbindEvent({ + key_up: selectPreviousItem, + key_down: selectNextItem, + key_left: selectSupermenu, + key_right: selectSubmenu, + key_escape: that.hideMenu, + key_enter: clickItem + }); + $document.unbind("click", click); + }; + + that.selectFirstItem = function() { + selectNextItem(); }; that.showMenu = function() { @@ -1935,13 +2040,19 @@ requires that.$container.height(maxHeight - itemHeight); that.$scrollbars.down.show(); } - Ox.print("binding..."); - Ox.Event.bind("key.down", selectNextItem); - Ox.Event.bind("key.up", selectPreviousItem); - Ox.Event.bind("key.escape", that.hideMenu); - Ox.Event.bind("key.enter", clickItem); + if (!self.options.parent) { + that.gainFocus(); + } + that.bindEvent({ + key_up: selectPreviousItem, + key_down: selectNextItem, + key_left: selectSupermenu, + key_right: selectSubmenu, + key_escape: that.hideMenu, + key_enter: clickItem + }); setTimeout(function() { - $document.bind("click", that.hideMenu); + $document.bind("click", click); }, 100); }; @@ -2025,7 +2136,7 @@ requires ); function click() { - if (!that.hasClass("OxDisabled") && !self.options.submenu) { + if (!that.hasClass("OxDisabled") && !self.options.items.length) { self.options.menu.hideMenu(); if (self.options.checked !== null && (!self.options.group || !self.options.checked)) { that.options({ @@ -2039,7 +2150,6 @@ requires id: self.options.id, value: self.options.title // fixme: value or title? }); - return false; } } @@ -2050,7 +2160,10 @@ requires function mouseenter() { if (!self.options.disabled && !isSelected()) { $.each(self.options.menu.submenus, function(id, submenu) { - submenu.hideMenu(); + if (!submenu.is(":hidden")) { + submenu.hideMenu(); + return false; + } }); if (self.options.menu.options("selected") > -1) { self.options.menu.items[self.options.menu.options("selected")].trigger("mouseleave"); diff --git a/demos/test/menu.js b/demos/test/menu.js index 271070e7..823e6e07 100644 --- a/demos/test/menu.js +++ b/demos/test/menu.js @@ -74,18 +74,43 @@ $(function() { }, ], title: "More", + }, + { + id: "even_more", + items: [ + { + checked: true, + group: "101112", + id: "tenth", + title: "Tenth" + }, + { + checked: false, + group: "101112", + id: "eleventh", + title: "Eleventh" + }, + { + checked: false, + group: "101112", + id: "twelfth", + title: "Twelfth" + }, + ], + title: "Even More", } ] }); - button.click(function() { - $(this).blur(); // fix for firefox - menu.toggleMenu(); - }); - Ox.Event.bind("OxClickMenu", function(event, data) { - button.options({ - value: data.value + button + .click(function() { + $(this).blur(); // fix for firefox + menu.toggleMenu(); + }) + .bindEvent("OxClickMenu", function(event, data) { + button.options({ + value: data.value + }); }); - }); $select = $("