- /**
- * <p>The MenuNav Node Plugin makes it easy to transform existing list-based
- * markup into traditional, drop down navigational menus that are both accessible
- * and easy to customize, and only require a small set of dependencies.</p>
- *
- *
- * <p>To use the MenuNav Node Plugin, simply pass a reference to the plugin to a
- * Node instance's <code>plug</code> method.</p>
- *
- * <p>
- * <code>
- * <script type="text/javascript"> <br>
- * <br>
- * // Call the "use" method, passing in "node-menunav". This will <br>
- * // load the script and CSS for the MenuNav Node Plugin and all of <br>
- * // the required dependencies. <br>
- * <br>
- * YUI().use("node-menunav", function(Y) { <br>
- * <br>
- * // Use the "contentready" event to initialize the menu when <br>
- * // the subtree of element representing the root menu <br>
- * // (<div id="menu-1">) is ready to be scripted. <br>
- * <br>
- * Y.on("contentready", function () { <br>
- * <br>
- * // The scope of the callback will be a Node instance <br>
- * // representing the root menu (<div id="menu-1">). <br>
- * // Therefore, since "this" represents a Node instance, it <br>
- * // is possible to just call "this.plug" passing in a <br>
- * // reference to the MenuNav Node Plugin. <br>
- * <br>
- * this.plug(Y.Plugin.NodeMenuNav); <br>
- * <br>
- * }, "#menu-1"); <br>
- * <br>
- * }); <br>
- * <br>
- * </script> <br>
- * </code>
- * </p>
- *
- * <p>The MenuNav Node Plugin has several configuration properties that can be
- * set via an object literal that is passed as a second argument to a Node
- * instance's <code>plug</code> method.
- * </p>
- *
- * <p>
- * <code>
- * <script type="text/javascript"> <br>
- * <br>
- * // Call the "use" method, passing in "node-menunav". This will <br>
- * // load the script and CSS for the MenuNav Node Plugin and all of <br>
- * // the required dependencies. <br>
- * <br>
- * YUI().use("node-menunav", function(Y) { <br>
- * <br>
- * // Use the "contentready" event to initialize the menu when <br>
- * // the subtree of element representing the root menu <br>
- * // (<div id="menu-1">) is ready to be scripted. <br>
- * <br>
- * Y.on("contentready", function () { <br>
- * <br>
- * // The scope of the callback will be a Node instance <br>
- * // representing the root menu (<div id="menu-1">). <br>
- * // Therefore, since "this" represents a Node instance, it <br>
- * // is possible to just call "this.plug" passing in a <br>
- * // reference to the MenuNav Node Plugin. <br>
- * <br>
- * this.plug(Y.Plugin.NodeMenuNav, { mouseOutHideDelay: 1000 });
- * <br><br>
- * }, "#menu-1"); <br>
- * <br>
- * }); <br>
- * <br>
- * </script> <br>
- * </code>
- * </p>
- *
- DEPRECATED. The MenuNav Node Plugin has been deprecated as of YUI 3.9.0. This module will be removed from the library in a future version. If you require functionality similar to the one provided by this module, consider taking a look at the various modules in the YUI Gallery <http://yuilibrary.com/gallery/>.
-
- @module node-menunav
- @deprecated 3.9.0
- */
-
-
- // Util shortcuts
-
- var UA = Y.UA,
- later = Y.later,
- getClassName = Y.ClassNameManager.getClassName,
-
-
-
- // Frequently used strings
-
- MENU = "menu",
- MENUITEM = "menuitem",
- HIDDEN = "hidden",
- PARENT_NODE = "parentNode",
- CHILDREN = "children",
- OFFSET_HEIGHT = "offsetHeight",
- OFFSET_WIDTH = "offsetWidth",
- PX = "px",
- ID = "id",
- PERIOD = ".",
- HANDLED_MOUSEOUT = "handledMouseOut",
- HANDLED_MOUSEOVER = "handledMouseOver",
- ACTIVE = "active",
- LABEL = "label",
- LOWERCASE_A = "a",
- MOUSEDOWN = "mousedown",
- KEYDOWN = "keydown",
- CLICK = "click",
- EMPTY_STRING = "",
- FIRST_OF_TYPE = "first-of-type",
- ROLE = "role",
- PRESENTATION = "presentation",
- DESCENDANTS = "descendants",
- UI = "UI",
- ACTIVE_DESCENDANT = "activeDescendant",
- USE_ARIA = "useARIA",
- ARIA_HIDDEN = "aria-hidden",
- CONTENT = "content",
- HOST = "host",
- ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
-
-
- // Attribute keys
-
- AUTO_SUBMENU_DISPLAY = "autoSubmenuDisplay",
- MOUSEOUT_HIDE_DELAY = "mouseOutHideDelay",
-
-
- // CSS class names
-
- CSS_MENU = getClassName(MENU),
- CSS_MENU_HIDDEN = getClassName(MENU, HIDDEN),
- CSS_MENU_HORIZONTAL = getClassName(MENU, "horizontal"),
- CSS_MENU_LABEL = getClassName(MENU, LABEL),
- CSS_MENU_LABEL_ACTIVE = getClassName(MENU, LABEL, ACTIVE),
- CSS_MENU_LABEL_MENUVISIBLE = getClassName(MENU, LABEL, (MENU + "visible")),
- CSS_MENUITEM = getClassName(MENUITEM),
- CSS_MENUITEM_ACTIVE = getClassName(MENUITEM, ACTIVE),
-
-
- // CSS selectors
-
- MENU_SELECTOR = PERIOD + CSS_MENU,
- MENU_TOGGLE_SELECTOR = (PERIOD + getClassName(MENU, "toggle")),
- MENU_CONTENT_SELECTOR = PERIOD + getClassName(MENU, CONTENT),
- MENU_LABEL_SELECTOR = PERIOD + CSS_MENU_LABEL,
-
- STANDARD_QUERY = ">" + MENU_CONTENT_SELECTOR + ">ul>li>a",
- EXTENDED_QUERY = ">" + MENU_CONTENT_SELECTOR + ">ul>li>" + MENU_LABEL_SELECTOR + ">a:first-child";
-
- // Utility functions
-
-
- var getPreviousSibling = function (node) {
-
- var oPrevious = node.previous(),
- oChildren;
-
- if (!oPrevious) {
- oChildren = node.get(PARENT_NODE).get(CHILDREN);
- oPrevious = oChildren.item(oChildren.size() - 1);
- }
-
-
- return oPrevious;
-
- };
-
-
- var getNextSibling = function (node) {
-
- var oNext = node.next();
-
- if (!oNext) {
- oNext = node.get(PARENT_NODE).get(CHILDREN).item(0);
- }
-
- return oNext;
-
- };
-
-
- var isAnchor = function (node) {
-
- var bReturnVal = false;
-
- if (node) {
- bReturnVal = node.get("nodeName").toLowerCase() === LOWERCASE_A;
- }
-
- return bReturnVal;
-
- };
-
-
- var isMenuItem = function (node) {
-
- return node.hasClass(CSS_MENUITEM);
-
- };
-
-
- var isMenuLabel = function (node) {
-
- return node.hasClass(CSS_MENU_LABEL);
-
- };
-
-
- var isHorizontalMenu = function (menu) {
-
- return menu.hasClass(CSS_MENU_HORIZONTAL);
-
- };
-
-
- var hasVisibleSubmenu = function (menuLabel) {
-
- return menuLabel.hasClass(CSS_MENU_LABEL_MENUVISIBLE);
-
- };
-
-
- var getItemAnchor = function (node) {
-
- return isAnchor(node) ? node : node.one(LOWERCASE_A);
-
- };
-
-
- var getNodeWithClass = function (node, className, searchAncestors) {
-
- var oItem;
-
- if (node) {
-
- if (node.hasClass(className)) {
- oItem = node;
- }
-
- if (!oItem && searchAncestors) {
- oItem = node.ancestor((PERIOD + className));
- }
-
- }
-
- return oItem;
-
- };
-
-
- var getParentMenu = function (node) {
-
- return node.ancestor(MENU_SELECTOR);
-
- };
-
-
- var getMenu = function (node, searchAncestors) {
-
- return getNodeWithClass(node, CSS_MENU, searchAncestors);
-
- };
-
-
- var getMenuItem = function (node, searchAncestors) {
-
- var oItem;
-
- if (node) {
- oItem = getNodeWithClass(node, CSS_MENUITEM, searchAncestors);
- }
-
- return oItem;
-
- };
-
-
- var getMenuLabel = function (node, searchAncestors) {
-
- var oItem;
-
- if (node) {
-
- if (searchAncestors) {
- oItem = getNodeWithClass(node, CSS_MENU_LABEL, searchAncestors);
- }
- else {
- oItem = getNodeWithClass(node, CSS_MENU_LABEL) ||
- node.one((PERIOD + CSS_MENU_LABEL));
- }
-
- }
-
- return oItem;
-
- };
-
-
- var getItem = function (node, searchAncestors) {
-
- var oItem;
-
- if (node) {
- oItem = getMenuItem(node, searchAncestors) ||
- getMenuLabel(node, searchAncestors);
- }
-
- return oItem;
-
- };
-
-
- var getFirstItem = function (menu) {
-
- return getItem(menu.one("li"));
-
- };
-
-
- var getActiveClass = function (node) {
-
- return isMenuItem(node) ? CSS_MENUITEM_ACTIVE : CSS_MENU_LABEL_ACTIVE;
-
- };
-
-
- var handleMouseOverForNode = function (node, target) {
-
- return node && !node[HANDLED_MOUSEOVER] &&
- (node.compareTo(target) || node.contains(target));
-
- };
-
-
- var handleMouseOutForNode = function (node, relatedTarget) {
-
- return node && !node[HANDLED_MOUSEOUT] &&
- (!node.compareTo(relatedTarget) && !node.contains(relatedTarget));
-
- };
-
- /**
- * The NodeMenuNav class is a plugin for a Node instance. The class is used via
- * the <a href="Node.html#method_plug"><code>plug</code></a> method of Node and
- * should not be instantiated directly.
- * @namespace plugin
- * @class NodeMenuNav
- */
- var NodeMenuNav = function () {
-
- NodeMenuNav.superclass.constructor.apply(this, arguments);
-
- };
-
- NodeMenuNav.NAME = "nodeMenuNav";
- NodeMenuNav.NS = "menuNav";
-
-
- /**
- * @property SHIM_TEMPLATE_TITLE
- * @description String representing the value for the <code>title</code>
- * attribute for the shim used to prevent <code><select></code> elements
- * from poking through menus in IE 6.
- * @default "Menu Stacking Shim"
- * @type String
- */
- NodeMenuNav.SHIM_TEMPLATE_TITLE = "Menu Stacking Shim";
-
-
- /**
- * @property SHIM_TEMPLATE
- * @description String representing the HTML used to create the
- * <code><iframe></code> shim used to prevent
- * <code><select></code> elements from poking through menus in IE 6.
- * @default "<iframe frameborder="0" tabindex="-1"
- * class="yui-shim" title="Menu Stacking Shim"
- * src="javascript:false;"></iframe>"
- * @type String
- */
-
- // <iframe> shim notes:
- //
- // 1) Need to set the "frameBorder" property to 0 to suppress the default
- // <iframe> border in IE. (Setting the CSS "border" property alone doesn't
- // suppress it.)
- //
- // 2) The "src" attribute of the <iframe> is set to "javascript:false;" so
- // that it won't load a page inside it, preventing the secure/nonsecure
- // warning in IE when using HTTPS.
- //
- // 3) Since the role of the <iframe> shim is completely presentational, its
- // "tabindex" attribute is set to "-1" and its title attribute is set to
- // "Menu Stacking Shim". Both strategies help users of screen readers to
- // avoid mistakenly interacting with the <iframe> shim.
-
- NodeMenuNav.SHIM_TEMPLATE = '<iframe frameborder="0" tabindex="-1" class="' +
- getClassName("shim") +
- '" title="' + NodeMenuNav.SHIM_TEMPLATE_TITLE +
- '" src="javascript:false;"></iframe>';
-
-
- NodeMenuNav.ATTRS = {
-
- /**
- * Boolean indicating if use of the WAI-ARIA Roles and States should be
- * enabled for the menu.
- *
- * @attribute useARIA
- * @readOnly
- * @writeOnce
- * @default true
- * @type boolean
- */
- useARIA: {
-
- value: true,
- writeOnce: true,
- lazyAdd: false,
- setter: function (value) {
-
- var oMenu = this.get(HOST),
- oMenuLabel,
- oMenuToggle,
- oSubmenu,
- sID;
-
- if (value) {
-
- oMenu.set(ROLE, MENU);
-
- oMenu.all("ul,li," + MENU_CONTENT_SELECTOR).set(ROLE, PRESENTATION);
-
- oMenu.all((PERIOD + getClassName(MENUITEM, CONTENT))).set(ROLE, MENUITEM);
-
- oMenu.all((PERIOD + CSS_MENU_LABEL)).each(function (node) {
-
- oMenuLabel = node;
- oMenuToggle = node.one(MENU_TOGGLE_SELECTOR);
-
- if (oMenuToggle) {
- oMenuToggle.set(ROLE, PRESENTATION);
- oMenuLabel = oMenuToggle.previous();
- }
-
- oMenuLabel.set(ROLE, MENUITEM);
- oMenuLabel.set("aria-haspopup", true);
-
- oSubmenu = node.next();
-
- if (oSubmenu) {
-
- oSubmenu.set(ROLE, MENU);
-
- oMenuLabel = oSubmenu.previous();
- oMenuToggle = oMenuLabel.one(MENU_TOGGLE_SELECTOR);
-
- if (oMenuToggle) {
- oMenuLabel = oMenuToggle;
- }
-
- sID = Y.stamp(oMenuLabel);
-
- if (!oMenuLabel.get(ID)) {
- oMenuLabel.set(ID, sID);
- }
-
- oSubmenu.set("aria-labelledby", sID);
- oSubmenu.set(ARIA_HIDDEN, true);
-
- }
-
- });
-
- }
-
- }
-
- },
-
-
- /**
- * Boolean indicating if submenus are automatically made visible when the
- * user mouses over the menu's items.
- *
- * @attribute autoSubmenuDisplay
- * @readOnly
- * @writeOnce
- * @default true
- * @type boolean
- */
- autoSubmenuDisplay: {
-
- value: true,
- writeOnce: true
-
- },
-
-
- /**
- * Number indicating the time (in milliseconds) that should expire before a
- * submenu is made visible when the user mouses over the menu's label.
- *
- * @attribute submenuShowDelay
- * @readOnly
- * @writeOnce
- * @default 250
- * @type Number
- */
- submenuShowDelay: {
-
- value: 250,
- writeOnce: true
-
- },
-
-
- /**
- * Number indicating the time (in milliseconds) that should expire before a
- * submenu is hidden when the user mouses out of a menu label heading in the
- * direction of a submenu.
- *
- * @attribute submenuHideDelay
- * @readOnly
- * @writeOnce
- * @default 250
- * @type Number
- */
- submenuHideDelay: {
-
- value: 250,
- writeOnce: true
-
- },
-
-
- /**
- * Number indicating the time (in milliseconds) that should expire before a
- * submenu is hidden when the user mouses out of it.
- *
- * @attribute mouseOutHideDelay
- * @readOnly
- * @writeOnce
- * @default 750
- * @type Number
- */
- mouseOutHideDelay: {
-
- value: 750,
- writeOnce: true
-
- }
-
- };
-
-
- Y.extend(NodeMenuNav, Y.Plugin.Base, {
-
- // Protected properties
-
- /**
- * @property _rootMenu
- * @description Node instance representing the root menu in the menu.
- * @default null
- * @protected
- * @type Node
- */
- _rootMenu: null,
-
-
- /**
- * @property _activeItem
- * @description Node instance representing the menu's active descendent:
- * the menuitem or menu label the user is currently interacting with.
- * @default null
- * @protected
- * @type Node
- */
- _activeItem: null,
-
-
- /**
- * @property _activeMenu
- * @description Node instance representing the menu that is the parent of
- * the menu's active descendent.
- * @default null
- * @protected
- * @type Node
- */
- _activeMenu: null,
-
-
- /**
- * @property _hasFocus
- * @description Boolean indicating if the menu has focus.
- * @default false
- * @protected
- * @type Boolean
- */
- _hasFocus: false,
-
-
- // In gecko-based browsers a mouseover and mouseout event will fire even
- // if a DOM element moves out from under the mouse without the user
- // actually moving the mouse. This bug affects NodeMenuNav because the
- // user can hit the Esc key to hide a menu, and if the mouse is over the
- // menu when the user presses Esc, the _onMenuMouseOut handler will be
- // called. To fix this bug the following flag (_blockMouseEvent) is used
- // to block the code in the _onMenuMouseOut handler from executing.
-
- /**
- * @property _blockMouseEvent
- * @description Boolean indicating whether or not to handle the
- * "mouseover" event.
- * @default false
- * @protected
- * @type Boolean
- */
- _blockMouseEvent: false,
-
-
- /**
- * @property _currentMouseX
- * @description Number representing the current x coordinate of the mouse
- * inside the menu.
- * @default 0
- * @protected
- * @type Number
- */
- _currentMouseX: 0,
-
-
- /**
- * @property _movingToSubmenu
- * @description Boolean indicating if the mouse is moving from a menu
- * label to its corresponding submenu.
- * @default false
- * @protected
- * @type Boolean
- */
- _movingToSubmenu: false,
-
-
- /**
- * @property _showSubmenuTimer
- * @description Timer used to show a submenu.
- * @default null
- * @protected
- * @type Object
- */
- _showSubmenuTimer: null,
-
-
- /**
- * @property _hideSubmenuTimer
- * @description Timer used to hide a submenu.
- * @default null
- * @protected
- * @type Object
- */
- _hideSubmenuTimer: null,
-
-
- /**
- * @property _hideAllSubmenusTimer
- * @description Timer used to hide a all submenus.
- * @default null
- * @protected
- * @type Object
- */
- _hideAllSubmenusTimer: null,
-
-
- /**
- * @property _firstItem
- * @description Node instance representing the first item (menuitem or menu
- * label) in the root menu of a menu.
- * @default null
- * @protected
- * @type Node
- */
- _firstItem: null,
-
-
- // Public methods
-
-
- initializer: function (config) {
-
- var menuNav = this,
- oRootMenu = this.get(HOST),
- aHandlers = [],
- oDoc;
-
- Y.log("WARNING: Node-MenuNav is a deprecated module as of YUI 3.9.0. This module will be removed from a later version of the library.", "warn");
-
- if (oRootMenu) {
-
- menuNav._rootMenu = oRootMenu;
-
- oRootMenu.all("ul:first-child").addClass(FIRST_OF_TYPE);
-
- // Hide all visible submenus
-
- oRootMenu.all(MENU_SELECTOR).addClass(CSS_MENU_HIDDEN);
-
-
- // Wire up all event handlers
-
- aHandlers.push(oRootMenu.on("mouseover", menuNav._onMouseOver, menuNav));
- aHandlers.push(oRootMenu.on("mouseout", menuNav._onMouseOut, menuNav));
- aHandlers.push(oRootMenu.on("mousemove", menuNav._onMouseMove, menuNav));
- aHandlers.push(oRootMenu.on(MOUSEDOWN, menuNav._toggleSubmenuDisplay, menuNav));
- aHandlers.push(Y.on("key", menuNav._toggleSubmenuDisplay, oRootMenu, "down:13", menuNav));
- aHandlers.push(oRootMenu.on(CLICK, menuNav._toggleSubmenuDisplay, menuNav));
- aHandlers.push(oRootMenu.on("keypress", menuNav._onKeyPress, menuNav));
- aHandlers.push(oRootMenu.on(KEYDOWN, menuNav._onKeyDown, menuNav));
-
- oDoc = oRootMenu.get("ownerDocument");
-
- aHandlers.push(oDoc.on(MOUSEDOWN, menuNav._onDocMouseDown, menuNav));
- aHandlers.push(oDoc.on("focus", menuNav._onDocFocus, menuNav));
-
- this._eventHandlers = aHandlers;
-
- menuNav._initFocusManager();
-
- }
-
-
- },
-
- destructor: function () {
-
- var aHandlers = this._eventHandlers;
-
- if (aHandlers) {
-
- Y.Array.each(aHandlers, function (handle) {
- handle.detach();
- });
-
- this._eventHandlers = null;
-
- }
-
- this.get(HOST).unplug("focusManager");
-
- },
-
-
-
- // Protected methods
-
- /**
- * @method _isRoot
- * @description Returns a boolean indicating if the specified menu is the
- * root menu in the menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- * @return {Boolean} Boolean indicating if the specified menu is the root
- * menu in the menu.
- */
- _isRoot: function (menu) {
-
- return this._rootMenu.compareTo(menu);
-
- },
-
-
- /**
- * @method _getTopmostSubmenu
- * @description Returns the topmost submenu of a submenu hierarchy.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- * @return {Node} Node instance representing a menu.
- */
- _getTopmostSubmenu: function (menu) {
-
- var menuNav = this,
- oMenu = getParentMenu(menu),
- returnVal;
-
-
- if (!oMenu) {
- returnVal = menu;
- }
- else if (menuNav._isRoot(oMenu)) {
- returnVal = menu;
- }
- else {
- returnVal = menuNav._getTopmostSubmenu(oMenu);
- }
-
- return returnVal;
-
- },
-
-
- /**
- * @method _clearActiveItem
- * @description Clears the menu's active descendent.
- * @protected
- */
- _clearActiveItem: function () {
-
- var menuNav = this,
- oActiveItem = menuNav._activeItem;
-
- if (oActiveItem) {
- oActiveItem.removeClass(getActiveClass(oActiveItem));
- }
-
- menuNav._activeItem = null;
-
- },
-
-
- /**
- * @method _setActiveItem
- * @description Sets the specified menuitem or menu label as the menu's
- * active descendent.
- * @protected
- * @param {Node} item Node instance representing a menuitem or menu label.
- */
- _setActiveItem: function (item) {
-
- var menuNav = this;
-
- if (item) {
-
- menuNav._clearActiveItem();
-
- item.addClass(getActiveClass(item));
-
- menuNav._activeItem = item;
-
- }
-
- },
-
-
- /**
- * @method _focusItem
- * @description Focuses the specified menuitem or menu label.
- * @protected
- * @param {Node} item Node instance representing a menuitem or menu label.
- */
- _focusItem: function (item) {
-
- var menuNav = this,
- oMenu,
- oItem;
-
- if (item && menuNav._hasFocus) {
-
- oMenu = getParentMenu(item);
- oItem = getItemAnchor(item);
-
- if (oMenu && !oMenu.compareTo(menuNav._activeMenu)) {
- menuNav._activeMenu = oMenu;
- menuNav._initFocusManager();
- }
-
- menuNav._focusManager.focus(oItem);
-
- }
-
- },
-
-
- /**
- * @method _showMenu
- * @description Shows the specified menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- */
- _showMenu: function (menu) {
-
- var oParentMenu = getParentMenu(menu),
- oLI = menu.get(PARENT_NODE),
- aXY = oLI.getXY();
-
-
- if (this.get(USE_ARIA)) {
- menu.set(ARIA_HIDDEN, false);
- }
-
-
- if (isHorizontalMenu(oParentMenu)) {
- aXY[1] = aXY[1] + oLI.get(OFFSET_HEIGHT);
- }
- else {
- aXY[0] = aXY[0] + oLI.get(OFFSET_WIDTH);
- }
-
- menu.setXY(aXY);
-
- if (UA.ie && UA.ie < 8) {
-
- if (UA.ie === 6 && !menu.hasIFrameShim) {
-
- menu.appendChild(Y.Node.create(NodeMenuNav.SHIM_TEMPLATE));
- menu.hasIFrameShim = true;
-
- }
-
- // Clear previous values for height and width
-
- menu.setStyles({ height: EMPTY_STRING, width: EMPTY_STRING });
-
- // Set the width and height of the menu's bounding box - this is
- // necessary for IE 6 so that the CSS for the <iframe> shim can
- // simply set the <iframe>'s width and height to 100% to ensure
- // that dimensions of an <iframe> shim are always sync'd to the
- // that of its parent menu. Specifying a width and height also
- // helps when positioning decorator elements (for creating effects
- // like rounded corners) inside a menu's bounding box in IE 7.
-
- menu.setStyles({
- height: (menu.get(OFFSET_HEIGHT) + PX),
- width: (menu.get(OFFSET_WIDTH) + PX) });
-
- }
-
- menu.previous().addClass(CSS_MENU_LABEL_MENUVISIBLE);
- menu.removeClass(CSS_MENU_HIDDEN);
-
- },
-
-
- /**
- * @method _hideMenu
- * @description Hides the specified menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- * @param {Boolean} activateAndFocusLabel Boolean indicating if the label
- * for the specified
- * menu should be focused and set as active.
- */
- _hideMenu: function (menu, activateAndFocusLabel) {
-
- var menuNav = this,
- oLabel = menu.previous(),
- oActiveItem;
-
- oLabel.removeClass(CSS_MENU_LABEL_MENUVISIBLE);
-
-
- if (activateAndFocusLabel) {
- menuNav._focusItem(oLabel);
- menuNav._setActiveItem(oLabel);
- }
-
- oActiveItem = menu.one((PERIOD + CSS_MENUITEM_ACTIVE));
-
- if (oActiveItem) {
- oActiveItem.removeClass(CSS_MENUITEM_ACTIVE);
- }
-
- // Clear the values for top and left that were set by the call to
- // "setXY" when the menu was shown so that the hidden position
- // specified in the core CSS file will take affect.
-
- menu.setStyles({ left: EMPTY_STRING, top: EMPTY_STRING });
-
- menu.addClass(CSS_MENU_HIDDEN);
-
- if (menuNav.get(USE_ARIA)) {
- menu.set(ARIA_HIDDEN, true);
- }
-
- },
-
-
- /**
- * @method _hideAllSubmenus
- * @description Hides all submenus of the specified menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- */
- _hideAllSubmenus: function (menu) {
-
- var menuNav = this;
-
- menu.all(MENU_SELECTOR).each(Y.bind(function (submenuNode) {
-
- menuNav._hideMenu(submenuNode);
-
- }, menuNav));
-
- },
-
-
- /**
- * @method _cancelShowSubmenuTimer
- * @description Cancels the timer used to show a submenu.
- * @protected
- */
- _cancelShowSubmenuTimer: function () {
-
- var menuNav = this,
- oShowSubmenuTimer = menuNav._showSubmenuTimer;
-
- if (oShowSubmenuTimer) {
- oShowSubmenuTimer.cancel();
- menuNav._showSubmenuTimer = null;
- }
-
- },
-
-
- /**
- * @method _cancelHideSubmenuTimer
- * @description Cancels the timer used to hide a submenu.
- * @protected
- */
- _cancelHideSubmenuTimer: function () {
-
- var menuNav = this,
- oHideSubmenuTimer = menuNav._hideSubmenuTimer;
-
-
- if (oHideSubmenuTimer) {
- oHideSubmenuTimer.cancel();
- menuNav._hideSubmenuTimer = null;
- }
-
- },
-
-
- /**
- * @method _initFocusManager
- * @description Initializes and updates the Focus Manager so that is is
- * always managing descendants of the active menu.
- * @protected
- */
- _initFocusManager: function () {
-
- var menuNav = this,
- oRootMenu = menuNav._rootMenu,
- oMenu = menuNav._activeMenu || oRootMenu,
- sSelectorBase =
- menuNav._isRoot(oMenu) ? EMPTY_STRING : ("#" + oMenu.get("id")),
- oFocusManager = menuNav._focusManager,
- sKeysVal,
- sDescendantSelector,
- sQuery;
-
- if (isHorizontalMenu(oMenu)) {
-
- sDescendantSelector = sSelectorBase + STANDARD_QUERY + "," +
- sSelectorBase + EXTENDED_QUERY;
-
- sKeysVal = { next: "down:39", previous: "down:37" };
-
- }
- else {
-
- sDescendantSelector = sSelectorBase + STANDARD_QUERY;
- sKeysVal = { next: "down:40", previous: "down:38" };
-
- }
-
-
- if (!oFocusManager) {
-
- oRootMenu.plug(Y.Plugin.NodeFocusManager, {
- descendants: sDescendantSelector,
- keys: sKeysVal,
- circular: true
- });
-
- oFocusManager = oRootMenu.focusManager;
-
- sQuery = "#" + oRootMenu.get("id") + MENU_SELECTOR + " a," +
- MENU_TOGGLE_SELECTOR;
-
- oRootMenu.all(sQuery).set("tabIndex", -1);
-
- oFocusManager.on(ACTIVE_DESCENDANT_CHANGE,
- this._onActiveDescendantChange, oFocusManager, this);
-
- oFocusManager.after(ACTIVE_DESCENDANT_CHANGE,
- this._afterActiveDescendantChange, oFocusManager, this);
-
- menuNav._focusManager = oFocusManager;
-
- }
- else {
-
- oFocusManager.set(ACTIVE_DESCENDANT, -1);
- oFocusManager.set(DESCENDANTS, sDescendantSelector);
- oFocusManager.set("keys", sKeysVal);
-
- }
-
- },
-
-
- // Event handlers for discrete pieces of pieces of the menu
-
-
- /**
- * @method _onActiveDescendantChange
- * @description "activeDescendantChange" event handler for menu's
- * Focus Manager.
- * @protected
- * @param {Object} event Object representing the Attribute change event.
- * @param {NodeMenuNav} menuNav Object representing the NodeMenuNav instance.
- */
- _onActiveDescendantChange: function (event, menuNav) {
-
- if (event.src === UI && menuNav._activeMenu &&
- !menuNav._movingToSubmenu) {
-
- menuNav._hideAllSubmenus(menuNav._activeMenu);
-
- }
-
- },
-
-
- /**
- * @method _afterActiveDescendantChange
- * @description "activeDescendantChange" event handler for menu's
- * Focus Manager.
- * @protected
- * @param {Object} event Object representing the Attribute change event.
- * @param {NodeMenuNav} menuNav Object representing the NodeMenuNav instance.
- */
- _afterActiveDescendantChange: function (event, menuNav) {
-
- var oItem;
-
- if (event.src === UI) {
- oItem = getItem(this.get(DESCENDANTS).item(event.newVal), true);
- menuNav._setActiveItem(oItem);
- }
-
- },
-
-
- /**
- * @method _onDocFocus
- * @description "focus" event handler for the owner document of the MenuNav.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onDocFocus: function (event) {
-
- var menuNav = this,
- oActiveItem = menuNav._activeItem,
- oTarget = event.target,
- oMenu;
-
-
- if (menuNav._rootMenu.contains(oTarget)) { // The menu has focus
-
- if (menuNav._hasFocus) {
-
- oMenu = getParentMenu(oTarget);
-
- // If the element that was focused is a descendant of the
- // root menu, but is in a submenu not currently being
- // managed by the Focus Manager, update the Focus Manager so
- // that it is now managing the submenu that is the parent of
- // the element that was focused.
-
- if (!menuNav._activeMenu.compareTo(oMenu)) {
-
- menuNav._activeMenu = oMenu;
- menuNav._initFocusManager();
- menuNav._focusManager.set(ACTIVE_DESCENDANT, oTarget);
- menuNav._setActiveItem(getItem(oTarget, true));
-
- }
-
- }
- else { // Initial focus
-
- // First time the menu has been focused, need to setup focused
- // state and established active active descendant
-
- menuNav._hasFocus = true;
-
- oActiveItem = getItem(oTarget, true);
-
- if (oActiveItem) {
- menuNav._setActiveItem(oActiveItem);
- }
-
- }
-
- }
- else { // The menu has lost focus
-
- menuNav._clearActiveItem();
-
- menuNav._cancelShowSubmenuTimer();
- menuNav._hideAllSubmenus(menuNav._rootMenu);
-
- menuNav._activeMenu = menuNav._rootMenu;
- menuNav._initFocusManager();
-
- menuNav._focusManager.set(ACTIVE_DESCENDANT, 0);
-
- menuNav._hasFocus = false;
-
- }
-
- },
-
-
- /**
- * @method _onMenuMouseOver
- * @description "mouseover" event handler for a menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuMouseOver: function (menu, event) {
-
- var menuNav = this,
- oHideAllSubmenusTimer = menuNav._hideAllSubmenusTimer;
-
- if (oHideAllSubmenusTimer) {
- oHideAllSubmenusTimer.cancel();
- menuNav._hideAllSubmenusTimer = null;
- }
-
- menuNav._cancelHideSubmenuTimer();
-
- // Need to update the FocusManager in advance of focus a new
- // Menu in order to avoid the FocusManager thinking that
- // it has lost focus
-
- if (menu && !menu.compareTo(menuNav._activeMenu)) {
- menuNav._activeMenu = menu;
-
- if (menuNav._hasFocus) {
- menuNav._initFocusManager();
- }
-
- }
-
- if (menuNav._movingToSubmenu && isHorizontalMenu(menu)) {
- menuNav._movingToSubmenu = false;
- }
-
- },
-
-
- /**
- * @method _hideAndFocusLabel
- * @description Hides all of the submenus of the root menu and focuses the
- * label of the topmost submenu
- * @protected
- */
- _hideAndFocusLabel: function () {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- oSubmenu;
-
- menuNav._hideAllSubmenus(menuNav._rootMenu);
-
- if (oActiveMenu) {
-
- // Focus the label element for the topmost submenu
- oSubmenu = menuNav._getTopmostSubmenu(oActiveMenu);
- menuNav._focusItem(oSubmenu.previous());
-
- }
-
- },
-
-
- /**
- * @method _onMenuMouseOut
- * @description "mouseout" event handler for a menu.
- * @protected
- * @param {Node} menu Node instance representing a menu.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuMouseOut: function (menu, event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- oRelatedTarget = event.relatedTarget,
- oActiveItem = menuNav._activeItem,
- oParentMenu,
- oMenu;
-
-
- if (oActiveMenu && !oActiveMenu.contains(oRelatedTarget)) {
-
- oParentMenu = getParentMenu(oActiveMenu);
-
-
- if (oParentMenu && !oParentMenu.contains(oRelatedTarget)) {
-
- if (menuNav.get(MOUSEOUT_HIDE_DELAY) > 0) {
-
- menuNav._cancelShowSubmenuTimer();
-
- menuNav._hideAllSubmenusTimer =
-
- later(menuNav.get(MOUSEOUT_HIDE_DELAY),
- menuNav, menuNav._hideAndFocusLabel);
-
- }
-
- }
- else {
-
- if (oActiveItem) {
-
- oMenu = getParentMenu(oActiveItem);
-
- if (!menuNav._isRoot(oMenu)) {
- menuNav._focusItem(oMenu.previous());
- }
-
- }
-
- }
-
- }
-
- },
-
-
- /**
- * @method _onMenuLabelMouseOver
- * @description "mouseover" event handler for a menu label.
- * @protected
- * @param {Node} menuLabel Node instance representing a menu label.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuLabelMouseOver: function (menuLabel, event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- bIsRoot = menuNav._isRoot(oActiveMenu),
- bUseAutoSubmenuDisplay =
- (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot),
- submenuShowDelay = menuNav.get("submenuShowDelay"),
- oSubmenu;
-
-
- var showSubmenu = function (delay) {
-
- menuNav._cancelHideSubmenuTimer();
- menuNav._cancelShowSubmenuTimer();
-
- if (!hasVisibleSubmenu(menuLabel)) {
-
- oSubmenu = menuLabel.next();
-
- if (oSubmenu) {
- menuNav._hideAllSubmenus(oActiveMenu);
- menuNav._showSubmenuTimer = later(delay, menuNav, menuNav._showMenu, oSubmenu);
- }
-
- }
-
- };
-
-
- menuNav._focusItem(menuLabel);
- menuNav._setActiveItem(menuLabel);
-
-
- if (bUseAutoSubmenuDisplay) {
-
- if (menuNav._movingToSubmenu) {
-
- // If the user is moving diagonally from a submenu to
- // another submenu and they then stop and pause on a
- // menu label for an amount of time equal to the amount of
- // time defined for the display of a submenu then show the
- // submenu immediately.
- // http://yuilibrary.com/projects/yui3/ticket/2528316
-
- //Y.message("Pause path");
-
- menuNav._hoverTimer = later(submenuShowDelay, menuNav, function () {
- showSubmenu(0);
- });
-
- }
- else {
- showSubmenu(submenuShowDelay);
- }
-
- }
-
- },
-
-
- /**
- * @method _onMenuLabelMouseOut
- * @description "mouseout" event handler for a menu label.
- * @protected
- * @param {Node} menuLabel Node instance representing a menu label.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuLabelMouseOut: function (menuLabel, event) {
-
- var menuNav = this,
- bIsRoot = menuNav._isRoot(menuNav._activeMenu),
- bUseAutoSubmenuDisplay =
- (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot),
-
- oRelatedTarget = event.relatedTarget,
- oSubmenu = menuLabel.next(),
- hoverTimer = menuNav._hoverTimer;
-
- if (hoverTimer) {
- hoverTimer.cancel();
- }
-
- menuNav._clearActiveItem();
-
- if (bUseAutoSubmenuDisplay) {
-
- if (menuNav._movingToSubmenu &&
- !menuNav._showSubmenuTimer && oSubmenu) {
-
- // If the mouse is moving diagonally toward the submenu and
- // another submenu isn't in the process of being displayed
- // (via a timer), then hide the submenu via a timer to give
- // the user some time to reach the submenu.
-
- menuNav._hideSubmenuTimer =
- later(menuNav.get("submenuHideDelay"), menuNav,
- menuNav._hideMenu, oSubmenu);
-
- }
- else if (!menuNav._movingToSubmenu && oSubmenu && (!oRelatedTarget ||
- (oRelatedTarget &&
- !oSubmenu.contains(oRelatedTarget) &&
- !oRelatedTarget.compareTo(oSubmenu)))) {
-
- // If the mouse is not moving toward the submenu, cancel any
- // submenus that might be in the process of being displayed
- // (via a timer) and hide this submenu immediately.
-
- menuNav._cancelShowSubmenuTimer();
-
- menuNav._hideMenu(oSubmenu);
-
- }
-
- }
-
- },
-
-
- /**
- * @method _onMenuItemMouseOver
- * @description "mouseover" event handler for a menuitem.
- * @protected
- * @param {Node} menuItem Node instance representing a menuitem.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuItemMouseOver: function (menuItem, event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- bIsRoot = menuNav._isRoot(oActiveMenu),
- bUseAutoSubmenuDisplay =
- (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot);
-
-
- menuNav._focusItem(menuItem);
- menuNav._setActiveItem(menuItem);
-
-
- if (bUseAutoSubmenuDisplay && !menuNav._movingToSubmenu) {
-
- menuNav._hideAllSubmenus(oActiveMenu);
-
- }
-
- },
-
-
- /**
- * @method _onMenuItemMouseOut
- * @description "mouseout" event handler for a menuitem.
- * @protected
- * @param {Node} menuItem Node instance representing a menuitem.
- * @param {Object} event Object representing the DOM event.
- */
- _onMenuItemMouseOut: function (menuItem, event) {
-
- this._clearActiveItem();
-
- },
-
-
- /**
- * @method _onVerticalMenuKeyDown
- * @description "keydown" event handler for vertical menus.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onVerticalMenuKeyDown: function (event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- oRootMenu = menuNav._rootMenu,
- oTarget = event.target,
- bPreventDefault = false,
- nKeyCode = event.keyCode,
- oSubmenu,
- oParentMenu,
- oLI,
- oItem;
-
-
- switch (nKeyCode) {
-
- case 37: // left arrow
-
- oParentMenu = getParentMenu(oActiveMenu);
-
- if (oParentMenu && isHorizontalMenu(oParentMenu)) {
-
- menuNav._hideMenu(oActiveMenu);
- oLI = getPreviousSibling(oActiveMenu.get(PARENT_NODE));
- oItem = getItem(oLI);
-
- if (oItem) {
-
- if (isMenuLabel(oItem)) { // Menu label
-
- oSubmenu = oItem.next();
-
-
- if (oSubmenu) {
-
- menuNav._showMenu(oSubmenu);
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
- else {
-
- menuNav._focusItem(oItem);
- menuNav._setActiveItem(oItem);
-
- }
-
- }
- else { // MenuItem
-
- menuNav._focusItem(oItem);
- menuNav._setActiveItem(oItem);
-
- }
-
- }
-
- }
- else if (!menuNav._isRoot(oActiveMenu)) {
- menuNav._hideMenu(oActiveMenu, true);
- }
-
-
- bPreventDefault = true;
-
- break;
-
- case 39: // right arrow
-
- if (isMenuLabel(oTarget)) {
-
- oSubmenu = oTarget.next();
-
- if (oSubmenu) {
-
- menuNav._showMenu(oSubmenu);
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
-
- }
- else if (isHorizontalMenu(oRootMenu)) {
-
- oSubmenu = menuNav._getTopmostSubmenu(oActiveMenu);
- oLI = getNextSibling(oSubmenu.get(PARENT_NODE));
- oItem = getItem(oLI);
-
- menuNav._hideAllSubmenus(oRootMenu);
-
- if (oItem) {
-
- if (isMenuLabel(oItem)) { // Menu label
-
- oSubmenu = oItem.next();
-
- if (oSubmenu) {
-
- menuNav._showMenu(oSubmenu);
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
- else {
-
- menuNav._focusItem(oItem);
- menuNav._setActiveItem(oItem);
-
- }
-
- }
- else { // MenuItem
-
- menuNav._focusItem(oItem);
- menuNav._setActiveItem(oItem);
-
- }
-
- }
-
- }
-
- bPreventDefault = true;
-
- break;
-
- }
-
-
- if (bPreventDefault) {
-
- // Prevent the browser from scrolling the window
-
- event.preventDefault();
-
- }
-
- },
-
-
- /**
- * @method _onHorizontalMenuKeyDown
- * @description "keydown" event handler for horizontal menus.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onHorizontalMenuKeyDown: function (event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- oTarget = event.target,
- oFocusedItem = getItem(oTarget, true),
- bPreventDefault = false,
- nKeyCode = event.keyCode,
- oSubmenu;
-
-
- if (nKeyCode === 40) {
-
- menuNav._hideAllSubmenus(oActiveMenu);
-
- if (isMenuLabel(oFocusedItem)) {
-
- oSubmenu = oFocusedItem.next();
-
- if (oSubmenu) {
-
- menuNav._showMenu(oSubmenu);
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
-
- bPreventDefault = true;
-
- }
-
- }
-
-
- if (bPreventDefault) {
-
- // Prevent the browser from scrolling the window
-
- event.preventDefault();
-
- }
-
- },
-
-
- // Generic DOM Event handlers
-
-
- /**
- * @method _onMouseMove
- * @description "mousemove" event handler for the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onMouseMove: function (event) {
-
- var menuNav = this;
-
- // Using a timer to set the value of the "_currentMouseX" property
- // helps improve the reliability of the calculation used to set the
- // value of the "_movingToSubmenu" property - especially in Opera.
-
- later(10, menuNav, function () {
-
- menuNav._currentMouseX = event.pageX;
-
- });
-
- },
-
-
- /**
- * @method _onMouseOver
- * @description "mouseover" event handler for the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onMouseOver: function (event) {
-
- var menuNav = this,
- oTarget,
- oMenu,
- oMenuLabel,
- oParentMenu,
- oMenuItem;
-
-
- if (menuNav._blockMouseEvent) {
- menuNav._blockMouseEvent = false;
- }
- else {
-
- oTarget = event.target;
- oMenu = getMenu(oTarget, true);
- oMenuLabel = getMenuLabel(oTarget, true);
- oMenuItem = getMenuItem(oTarget, true);
-
-
- if (handleMouseOverForNode(oMenu, oTarget)) {
-
- menuNav._onMenuMouseOver(oMenu, event);
-
- oMenu[HANDLED_MOUSEOVER] = true;
- oMenu[HANDLED_MOUSEOUT] = false;
-
- oParentMenu = getParentMenu(oMenu);
-
- if (oParentMenu) {
-
- oParentMenu[HANDLED_MOUSEOUT] = true;
- oParentMenu[HANDLED_MOUSEOVER] = false;
-
- }
-
- }
-
- if (handleMouseOverForNode(oMenuLabel, oTarget)) {
-
- menuNav._onMenuLabelMouseOver(oMenuLabel, event);
-
- oMenuLabel[HANDLED_MOUSEOVER] = true;
- oMenuLabel[HANDLED_MOUSEOUT] = false;
-
- }
-
- if (handleMouseOverForNode(oMenuItem, oTarget)) {
-
- menuNav._onMenuItemMouseOver(oMenuItem, event);
-
- oMenuItem[HANDLED_MOUSEOVER] = true;
- oMenuItem[HANDLED_MOUSEOUT] = false;
-
- }
-
- }
-
- },
-
-
- /**
- * @method _onMouseOut
- * @description "mouseout" event handler for the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onMouseOut: function (event) {
-
- var menuNav = this,
- oActiveMenu = menuNav._activeMenu,
- bMovingToSubmenu = false,
- oTarget,
- oRelatedTarget,
- oMenu,
- oMenuLabel,
- oSubmenu,
- oMenuItem;
-
-
- menuNav._movingToSubmenu =
- (oActiveMenu && !isHorizontalMenu(oActiveMenu) &&
- ((event.pageX - 5) > menuNav._currentMouseX));
-
- oTarget = event.target;
- oRelatedTarget = event.relatedTarget;
- oMenu = getMenu(oTarget, true);
- oMenuLabel = getMenuLabel(oTarget, true);
- oMenuItem = getMenuItem(oTarget, true);
-
-
- if (handleMouseOutForNode(oMenuLabel, oRelatedTarget)) {
-
- menuNav._onMenuLabelMouseOut(oMenuLabel, event);
-
- oMenuLabel[HANDLED_MOUSEOUT] = true;
- oMenuLabel[HANDLED_MOUSEOVER] = false;
-
- }
-
- if (handleMouseOutForNode(oMenuItem, oRelatedTarget)) {
-
- menuNav._onMenuItemMouseOut(oMenuItem, event);
-
- oMenuItem[HANDLED_MOUSEOUT] = true;
- oMenuItem[HANDLED_MOUSEOVER] = false;
-
- }
-
-
- if (oMenuLabel) {
-
- oSubmenu = oMenuLabel.next();
-
- if (oSubmenu && oRelatedTarget &&
- (oRelatedTarget.compareTo(oSubmenu) ||
- oSubmenu.contains(oRelatedTarget))) {
-
- bMovingToSubmenu = true;
-
- }
-
- }
-
-
- if (handleMouseOutForNode(oMenu, oRelatedTarget) || bMovingToSubmenu) {
-
- menuNav._onMenuMouseOut(oMenu, event);
-
- oMenu[HANDLED_MOUSEOUT] = true;
- oMenu[HANDLED_MOUSEOVER] = false;
-
- }
-
- },
-
-
- /**
- * @method _toggleSubmenuDisplay
- * @description "mousedown," "keydown," and "click" event handler for the
- * menu used to toggle the display of a submenu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _toggleSubmenuDisplay: function (event) {
-
- var menuNav = this,
- oTarget = event.target,
- oMenuLabel = getMenuLabel(oTarget, true),
- sType = event.type,
- oAnchor,
- oSubmenu,
- sHref,
- nHashPos,
- nLen,
- sId;
-
-
- if (oMenuLabel) {
-
- oAnchor = isAnchor(oTarget) ? oTarget : oTarget.ancestor(isAnchor);
-
-
- if (oAnchor) {
-
- // Need to pass "2" as a second argument to "getAttribute" for
- // IE otherwise IE will return a fully qualified URL for the
- // value of the "href" attribute.
- // http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
-
- sHref = oAnchor.getAttribute("href", 2);
- nHashPos = sHref.indexOf("#");
- nLen = sHref.length;
-
- if (nHashPos === 0 && nLen > 1) {
-
- sId = sHref.substr(1, nLen);
- oSubmenu = oMenuLabel.next();
-
- if (oSubmenu && (oSubmenu.get(ID) === sId)) {
-
- if (sType === MOUSEDOWN || sType === KEYDOWN) {
-
- if ((UA.opera || UA.gecko || UA.ie) && sType === KEYDOWN && !menuNav._preventClickHandle) {
-
- // Prevent the browser from following the URL of
- // the anchor element
-
- menuNav._preventClickHandle = menuNav._rootMenu.on("click", function (event) {
-
- event.preventDefault();
-
- menuNav._preventClickHandle.detach();
- menuNav._preventClickHandle = null;
-
- });
-
- }
-
- if (sType == MOUSEDOWN) {
-
- // Prevent the target from getting focused by
- // default, since the element to be focused will
- // be determined by weather or not the submenu
- // is visible.
- event.preventDefault();
-
- // FocusManager will attempt to focus any
- // descendant that is the target of the mousedown
- // event. Since we want to explicitly control
- // where focus is going, we need to call
- // "stopImmediatePropagation" to stop the
- // FocusManager from doing its thing.
- event.stopImmediatePropagation();
-
- // The "_focusItem" method relies on the
- // "_hasFocus" property being set to true. The
- // "_hasFocus" property is normally set via a
- // "focus" event listener, but since we've
- // blocked focus from happening, we need to set
- // this property manually.
- menuNav._hasFocus = true;
-
- }
-
-
- if (menuNav._isRoot(getParentMenu(oTarget))) { // Event target is a submenu label in the root menu
-
- // Menu label toggle functionality
-
- if (hasVisibleSubmenu(oMenuLabel)) {
-
- menuNav._hideMenu(oSubmenu);
- menuNav._focusItem(oMenuLabel);
- menuNav._setActiveItem(oMenuLabel);
-
- }
- else {
-
- menuNav._hideAllSubmenus(menuNav._rootMenu);
- menuNav._showMenu(oSubmenu);
-
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
-
- }
- else { // Event target is a submenu label within a submenu
-
- if (menuNav._activeItem == oMenuLabel) {
-
- menuNav._showMenu(oSubmenu);
- menuNav._focusItem(getFirstItem(oSubmenu));
- menuNav._setActiveItem(getFirstItem(oSubmenu));
-
- }
- else {
-
- if (!oMenuLabel._clickHandle) {
-
- oMenuLabel._clickHandle = oMenuLabel.on("click", function () {
-
- menuNav._hideAllSubmenus(menuNav._rootMenu);
-
- menuNav._hasFocus = false;
- menuNav._clearActiveItem();
-
-
- oMenuLabel._clickHandle.detach();
-
- oMenuLabel._clickHandle = null;
-
- });
-
- }
-
- }
-
- }
-
- }
-
-
- if (sType === CLICK) {
-
- // Prevent the browser from following the URL of
- // the anchor element
-
- event.preventDefault();
-
- }
-
- }
-
- }
-
-
- }
-
- }
-
- },
-
-
- /**
- * @method _onKeyPress
- * @description "keypress" event handler for the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onKeyPress: function (event) {
-
- switch (event.keyCode) {
-
- case 37: // left arrow
- case 38: // up arrow
- case 39: // right arrow
- case 40: // down arrow
-
- // Prevent the browser from scrolling the window
-
- event.preventDefault();
-
- break;
-
- }
-
- },
-
-
- /**
- * @method _onKeyDown
- * @description "keydown" event handler for the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onKeyDown: function (event) {
-
- var menuNav = this,
- oActiveItem = menuNav._activeItem,
- oTarget = event.target,
- oActiveMenu = getParentMenu(oTarget),
- oSubmenu;
-
- if (oActiveMenu) {
-
- menuNav._activeMenu = oActiveMenu;
-
- if (isHorizontalMenu(oActiveMenu)) {
- menuNav._onHorizontalMenuKeyDown(event);
- }
- else {
- menuNav._onVerticalMenuKeyDown(event);
- }
-
-
- if (event.keyCode === 27) {
-
- if (!menuNav._isRoot(oActiveMenu)) {
-
- if (UA.opera) {
- later(0, menuNav, function () {
- menuNav._hideMenu(oActiveMenu, true);
- });
- }
- else {
- menuNav._hideMenu(oActiveMenu, true);
- }
-
- event.stopPropagation();
- menuNav._blockMouseEvent = UA.gecko ? true : false;
-
- }
- else if (oActiveItem) {
-
- if (isMenuLabel(oActiveItem) &&
- hasVisibleSubmenu(oActiveItem)) {
-
- oSubmenu = oActiveItem.next();
-
- if (oSubmenu) {
- menuNav._hideMenu(oSubmenu);
- }
-
- }
- else {
-
- menuNav._focusManager.blur();
-
- // This is necessary for Webkit since blurring the
- // active menuitem won't result in the document
- // gaining focus, meaning the that _onDocFocus
- // listener won't clear the active menuitem.
-
- menuNav._clearActiveItem();
-
- menuNav._hasFocus = false;
-
- }
-
- }
-
- }
-
- }
-
- },
-
- /**
- * @method _onDocMouseDown
- * @description "mousedown" event handler for the owner document of
- * the menu.
- * @protected
- * @param {Object} event Object representing the DOM event.
- */
- _onDocMouseDown: function (event) {
-
- var menuNav = this,
- oRoot = menuNav._rootMenu,
- oTarget = event.target;
-
-
- if (!(oRoot.compareTo(oTarget) || oRoot.contains(oTarget))) {
-
- menuNav._hideAllSubmenus(oRoot);
-
- // Document doesn't receive focus in Webkit when the user mouses
- // down on it, so the "_hasFocus" property won't get set to the
- // correct value. The following line corrects the problem.
-
- if (UA.webkit) {
- menuNav._hasFocus = false;
- menuNav._clearActiveItem();
- }
-
- }
-
- }
-
- });
-
-
- Y.namespace('Plugin');
-
- Y.Plugin.NodeMenuNav = NodeMenuNav;
-
-