You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2009/09/28 04:57:47 UTC
svn commit: r819446 [21/28] - in /roller/trunk/apps/weblogger/web:
WEB-INF/jsps/editor/ WEB-INF/jsps/tiles/ roller-ui/yui/
roller-ui/yui/assets/ roller-ui/yui/assets/skins/
roller-ui/yui/assets/skins/sam/ roller-ui/yui/autocomplete/
roller-ui/yui/autoc...
Added: roller/trunk/apps/weblogger/web/roller-ui/yui/menu/menu-debug.js
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/web/roller-ui/yui/menu/menu-debug.js?rev=819446&view=auto
==============================================================================
--- roller/trunk/apps/weblogger/web/roller-ui/yui/menu/menu-debug.js (added)
+++ roller/trunk/apps/weblogger/web/roller-ui/yui/menu/menu-debug.js Mon Sep 28 02:57:43 2009
@@ -0,0 +1,9870 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.8.0r4
+*/
+
+
+/**
+* @module menu
+* @description <p>The Menu family of components features a collection of
+* controls that make it easy to add menus to your website or web application.
+* With the Menu Controls you can create website fly-out menus, customized
+* context menus, or application-style menu bars with just a small amount of
+* scripting.</p><p>The Menu family of controls features:</p>
+* <ul>
+* <li>Keyboard and mouse navigation.</li>
+* <li>A rich event model that provides access to all of a menu's
+* interesting moments.</li>
+* <li>Support for
+* <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
+* Enhancement</a>; Menus can be created from simple,
+* semantic markup on the page or purely through JavaScript.</li>
+* </ul>
+* @title Menu
+* @namespace YAHOO.widget
+* @requires Event, Dom, Container
+*/
+(function () {
+
+ var UA = YAHOO.env.ua,
+ Dom = YAHOO.util.Dom,
+ Event = YAHOO.util.Event,
+ Lang = YAHOO.lang,
+
+ _DIV = "DIV",
+ _HD = "hd",
+ _BD = "bd",
+ _FT = "ft",
+ _LI = "LI",
+ _DISABLED = "disabled",
+ _MOUSEOVER = "mouseover",
+ _MOUSEOUT = "mouseout",
+ _MOUSEDOWN = "mousedown",
+ _MOUSEUP = "mouseup",
+ _CLICK = "click",
+ _KEYDOWN = "keydown",
+ _KEYUP = "keyup",
+ _KEYPRESS = "keypress",
+ _CLICK_TO_HIDE = "clicktohide",
+ _POSITION = "position",
+ _DYNAMIC = "dynamic",
+ _SHOW_DELAY = "showdelay",
+ _SELECTED = "selected",
+ _VISIBLE = "visible",
+ _UL = "UL",
+ _MENUMANAGER = "MenuManager";
+
+
+ /**
+ * Singleton that manages a collection of all menus and menu items. Listens
+ * for DOM events at the document level and dispatches the events to the
+ * corresponding menu or menu item.
+ *
+ * @namespace YAHOO.widget
+ * @class MenuManager
+ * @static
+ */
+ YAHOO.widget.MenuManager = function () {
+
+ // Private member variables
+
+
+ // Flag indicating if the DOM event handlers have been attached
+
+ var m_bInitializedEventHandlers = false,
+
+
+ // Collection of menus
+
+ m_oMenus = {},
+
+
+ // Collection of visible menus
+
+ m_oVisibleMenus = {},
+
+
+ // Collection of menu items
+
+ m_oItems = {},
+
+
+ // Map of DOM event types to their equivalent CustomEvent types
+
+ m_oEventTypes = {
+ "click": "clickEvent",
+ "mousedown": "mouseDownEvent",
+ "mouseup": "mouseUpEvent",
+ "mouseover": "mouseOverEvent",
+ "mouseout": "mouseOutEvent",
+ "keydown": "keyDownEvent",
+ "keyup": "keyUpEvent",
+ "keypress": "keyPressEvent",
+ "focus": "focusEvent",
+ "focusin": "focusEvent",
+ "blur": "blurEvent",
+ "focusout": "blurEvent"
+ },
+
+
+ m_oFocusedMenuItem = null;
+
+
+
+ // Private methods
+
+
+ /**
+ * @method getMenuRootElement
+ * @description Finds the root DIV node of a menu or the root LI node of
+ * a menu item.
+ * @private
+ * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+ * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
+ * specifying an HTML element.
+ */
+ function getMenuRootElement(p_oElement) {
+
+ var oParentNode,
+ returnVal;
+
+ if (p_oElement && p_oElement.tagName) {
+
+ switch (p_oElement.tagName.toUpperCase()) {
+
+ case _DIV:
+
+ oParentNode = p_oElement.parentNode;
+
+ // Check if the DIV is the inner "body" node of a menu
+
+ if ((
+ Dom.hasClass(p_oElement, _HD) ||
+ Dom.hasClass(p_oElement, _BD) ||
+ Dom.hasClass(p_oElement, _FT)
+ ) &&
+ oParentNode &&
+ oParentNode.tagName &&
+ oParentNode.tagName.toUpperCase() == _DIV) {
+
+ returnVal = oParentNode;
+
+ }
+ else {
+
+ returnVal = p_oElement;
+
+ }
+
+ break;
+
+ case _LI:
+
+ returnVal = p_oElement;
+
+ break;
+
+ default:
+
+ oParentNode = p_oElement.parentNode;
+
+ if (oParentNode) {
+
+ returnVal = getMenuRootElement(oParentNode);
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ return returnVal;
+
+ }
+
+
+
+ // Private event handlers
+
+
+ /**
+ * @method onDOMEvent
+ * @description Generic, global event handler for all of a menu's
+ * DOM-based events. This listens for events against the document
+ * object. If the target of a given event is a member of a menu or
+ * menu item's DOM, the instance's corresponding Custom Event is fired.
+ * @private
+ * @param {Event} p_oEvent Object representing the DOM event object
+ * passed back by the event utility (YAHOO.util.Event).
+ */
+ function onDOMEvent(p_oEvent) {
+
+ // Get the target node of the DOM event
+
+ var oTarget = Event.getTarget(p_oEvent),
+
+ // See if the target of the event was a menu, or a menu item
+
+ oElement = getMenuRootElement(oTarget),
+ bFireEvent = true,
+ sEventType = p_oEvent.type,
+ sCustomEventType,
+ sTagName,
+ sId,
+ oMenuItem,
+ oMenu;
+
+
+ if (oElement) {
+
+ sTagName = oElement.tagName.toUpperCase();
+
+ if (sTagName == _LI) {
+
+ sId = oElement.id;
+
+ if (sId && m_oItems[sId]) {
+
+ oMenuItem = m_oItems[sId];
+ oMenu = oMenuItem.parent;
+
+ }
+
+ }
+ else if (sTagName == _DIV) {
+
+ if (oElement.id) {
+
+ oMenu = m_oMenus[oElement.id];
+
+ }
+
+ }
+
+ }
+
+
+ if (oMenu) {
+
+ sCustomEventType = m_oEventTypes[sEventType];
+
+ /*
+ There is an inconsistency between Firefox for Mac OS X and
+ Firefox Windows & Linux regarding the triggering of the
+ display of the browser's context menu and the subsequent
+ firing of the "click" event. In Firefox for Windows & Linux,
+ when the user triggers the display of the browser's context
+ menu the "click" event also fires for the document object,
+ even though the "click" event did not fire for the element
+ that was the original target of the "contextmenu" event.
+ This is unique to Firefox on Windows & Linux. For all
+ other A-Grade browsers, including Firefox for Mac OS X, the
+ "click" event doesn't fire for the document object.
+
+ This bug in Firefox for Windows affects Menu, as Menu
+ instances listen for events at the document level and
+ dispatches Custom Events of the same name. Therefore users
+ of Menu will get an unwanted firing of the "click"
+ custom event. The following line fixes this bug.
+ */
+
+
+
+ if (sEventType == "click" &&
+ (UA.gecko && oMenu.platform != "mac") &&
+ p_oEvent.button > 0) {
+
+ bFireEvent = false;
+
+ }
+
+ // Fire the Custom Event that corresponds the current DOM event
+
+ if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
+ oMenuItem[sCustomEventType].fire(p_oEvent);
+ }
+
+ if (bFireEvent) {
+ oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
+ }
+
+ }
+ else if (sEventType == _MOUSEDOWN) {
+
+ /*
+ If the target of the event wasn't a menu, hide all
+ dynamically positioned menus
+ */
+
+ for (var i in m_oVisibleMenus) {
+
+ if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
+
+ oMenu = m_oVisibleMenus[i];
+
+ if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) &&
+ !(oMenu instanceof YAHOO.widget.MenuBar) &&
+ oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ oMenu.hide();
+
+ // In IE when the user mouses down on a focusable
+ // element that element will be focused and become
+ // the "activeElement".
+ // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
+ // However, there is a bug in IE where if there is
+ // a positioned element with a focused descendant
+ // that is hidden in response to the mousedown
+ // event, the target of the mousedown event will
+ // appear to have focus, but will not be set as
+ // the activeElement. This will result in the
+ // element not firing key events, even though it
+ // appears to have focus. The following call to
+ // "setActive" fixes this bug.
+
+ if (UA.ie && oTarget.focus) {
+ oTarget.setActive();
+ }
+
+ }
+ else {
+
+ if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
+
+ oMenu._cancelShowDelay();
+
+ }
+
+
+ if (oMenu.activeItem) {
+
+ oMenu.activeItem.blur();
+ oMenu.activeItem.cfg.setProperty(_SELECTED, false);
+
+ oMenu.activeItem = null;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @method onMenuDestroy
+ * @description "destroy" event handler for a menu.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
+ */
+ function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
+
+ if (m_oMenus[p_oMenu.id]) {
+
+ this.removeMenu(p_oMenu);
+
+ }
+
+ }
+
+
+ /**
+ * @method onMenuFocus
+ * @description "focus" event handler for a MenuItem instance.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ */
+ function onMenuFocus(p_sType, p_aArgs) {
+
+ var oItem = p_aArgs[1];
+
+ if (oItem) {
+
+ m_oFocusedMenuItem = oItem;
+
+ }
+
+ }
+
+
+ /**
+ * @method onMenuBlur
+ * @description "blur" event handler for a MenuItem instance.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ */
+ function onMenuBlur(p_sType, p_aArgs) {
+
+ m_oFocusedMenuItem = null;
+
+ }
+
+
+ /**
+ * @method onMenuVisibleConfigChange
+ * @description Event handler for when the "visible" configuration
+ * property of a Menu instance changes.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ */
+ function onMenuVisibleConfigChange(p_sType, p_aArgs) {
+
+ var bVisible = p_aArgs[0],
+ sId = this.id;
+
+ if (bVisible) {
+
+ m_oVisibleMenus[sId] = this;
+
+ YAHOO.log(this + " added to the collection of visible menus.",
+ "info", _MENUMANAGER);
+
+ }
+ else if (m_oVisibleMenus[sId]) {
+
+ delete m_oVisibleMenus[sId];
+
+ YAHOO.log(this + " removed from the collection of visible menus.",
+ "info", _MENUMANAGER);
+
+ }
+
+ }
+
+
+ /**
+ * @method onItemDestroy
+ * @description "destroy" event handler for a MenuItem instance.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ */
+ function onItemDestroy(p_sType, p_aArgs) {
+
+ removeItem(this);
+
+ }
+
+
+ /**
+ * @method removeItem
+ * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
+ * @private
+ * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
+ */
+ function removeItem(p_oMenuItem) {
+
+ var sId = p_oMenuItem.id;
+
+ if (sId && m_oItems[sId]) {
+
+ if (m_oFocusedMenuItem == p_oMenuItem) {
+
+ m_oFocusedMenuItem = null;
+
+ }
+
+ delete m_oItems[sId];
+
+ p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
+
+ YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
+
+ }
+
+ }
+
+
+ /**
+ * @method onItemAdded
+ * @description "itemadded" event handler for a Menu instance.
+ * @private
+ * @param {String} p_sType String representing the name of the event
+ * that was fired.
+ * @param {Array} p_aArgs Array of arguments sent when the event
+ * was fired.
+ */
+ function onItemAdded(p_sType, p_aArgs) {
+
+ var oItem = p_aArgs[0],
+ sId;
+
+ if (oItem instanceof YAHOO.widget.MenuItem) {
+
+ sId = oItem.id;
+
+ if (!m_oItems[sId]) {
+
+ m_oItems[sId] = oItem;
+
+ oItem.destroyEvent.subscribe(onItemDestroy);
+
+ YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
+
+ }
+
+ }
+
+ }
+
+
+ return {
+
+ // Privileged methods
+
+
+ /**
+ * @method addMenu
+ * @description Adds a menu to the collection of known menus.
+ * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
+ * instance to be added.
+ */
+ addMenu: function (p_oMenu) {
+
+ var oDoc;
+
+ if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
+ !m_oMenus[p_oMenu.id]) {
+
+ m_oMenus[p_oMenu.id] = p_oMenu;
+
+
+ if (!m_bInitializedEventHandlers) {
+
+ oDoc = document;
+
+ Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
+ Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
+ Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
+ Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
+ Event.on(oDoc, _CLICK, onDOMEvent, this, true);
+ Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
+ Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
+ Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
+
+ Event.onFocus(oDoc, onDOMEvent, this, true);
+ Event.onBlur(oDoc, onDOMEvent, this, true);
+
+ m_bInitializedEventHandlers = true;
+
+ YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
+
+ }
+
+ p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
+ p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
+ p_oMenu.itemAddedEvent.subscribe(onItemAdded);
+ p_oMenu.focusEvent.subscribe(onMenuFocus);
+ p_oMenu.blurEvent.subscribe(onMenuBlur);
+
+ YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
+
+ }
+
+ },
+
+
+ /**
+ * @method removeMenu
+ * @description Removes a menu from the collection of known menus.
+ * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
+ * instance to be removed.
+ */
+ removeMenu: function (p_oMenu) {
+
+ var sId,
+ aItems,
+ i;
+
+ if (p_oMenu) {
+
+ sId = p_oMenu.id;
+
+ if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
+
+ // Unregister each menu item
+
+ aItems = p_oMenu.getItems();
+
+ if (aItems && aItems.length > 0) {
+
+ i = aItems.length - 1;
+
+ do {
+
+ removeItem(aItems[i]);
+
+ }
+ while (i--);
+
+ }
+
+
+ // Unregister the menu
+
+ delete m_oMenus[sId];
+
+ YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
+
+
+ /*
+ Unregister the menu from the collection of
+ visible menus
+ */
+
+ if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
+
+ delete m_oVisibleMenus[sId];
+
+ YAHOO.log(p_oMenu + " unregistered from the" +
+ " collection of visible menus.", "info", _MENUMANAGER);
+
+ }
+
+
+ // Unsubscribe event listeners
+
+ if (p_oMenu.cfg) {
+
+ p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE,
+ onMenuVisibleConfigChange);
+
+ }
+
+ p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
+ p_oMenu);
+
+ p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
+ p_oMenu.focusEvent.unsubscribe(onMenuFocus);
+ p_oMenu.blurEvent.unsubscribe(onMenuBlur);
+
+ }
+
+ }
+
+ },
+
+
+ /**
+ * @method hideVisible
+ * @description Hides all visible, dynamically positioned menus
+ * (excluding instances of YAHOO.widget.MenuBar).
+ */
+ hideVisible: function () {
+
+ var oMenu;
+
+ for (var i in m_oVisibleMenus) {
+
+ if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
+
+ oMenu = m_oVisibleMenus[i];
+
+ if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
+ oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ oMenu.hide();
+
+ }
+
+ }
+
+ }
+
+ },
+
+
+ /**
+ * @method getVisible
+ * @description Returns a collection of all visible menus registered
+ * with the menu manger.
+ * @return {Object}
+ */
+ getVisible: function () {
+
+ return m_oVisibleMenus;
+
+ },
+
+
+ /**
+ * @method getMenus
+ * @description Returns a collection of all menus registered with the
+ * menu manger.
+ * @return {Object}
+ */
+ getMenus: function () {
+
+ return m_oMenus;
+
+ },
+
+
+ /**
+ * @method getMenu
+ * @description Returns a menu with the specified id.
+ * @param {String} p_sId String specifying the id of the
+ * <code><div></code> element representing the menu to
+ * be retrieved.
+ * @return {YAHOO.widget.Menu}
+ */
+ getMenu: function (p_sId) {
+
+ var returnVal;
+
+ if (p_sId in m_oMenus) {
+
+ returnVal = m_oMenus[p_sId];
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method getMenuItem
+ * @description Returns a menu item with the specified id.
+ * @param {String} p_sId String specifying the id of the
+ * <code><li></code> element representing the menu item to
+ * be retrieved.
+ * @return {YAHOO.widget.MenuItem}
+ */
+ getMenuItem: function (p_sId) {
+
+ var returnVal;
+
+ if (p_sId in m_oItems) {
+
+ returnVal = m_oItems[p_sId];
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method getMenuItemGroup
+ * @description Returns an array of menu item instances whose
+ * corresponding <code><li></code> elements are child
+ * nodes of the <code><ul></code> element with the
+ * specified id.
+ * @param {String} p_sId String specifying the id of the
+ * <code><ul></code> element representing the group of
+ * menu items to be retrieved.
+ * @return {Array}
+ */
+ getMenuItemGroup: function (p_sId) {
+
+ var oUL = Dom.get(p_sId),
+ aItems,
+ oNode,
+ oItem,
+ sId,
+ returnVal;
+
+
+ if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
+
+ oNode = oUL.firstChild;
+
+ if (oNode) {
+
+ aItems = [];
+
+ do {
+
+ sId = oNode.id;
+
+ if (sId) {
+
+ oItem = this.getMenuItem(sId);
+
+ if (oItem) {
+
+ aItems[aItems.length] = oItem;
+
+ }
+
+ }
+
+ }
+ while ((oNode = oNode.nextSibling));
+
+
+ if (aItems.length > 0) {
+
+ returnVal = aItems;
+
+ }
+
+ }
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method getFocusedMenuItem
+ * @description Returns a reference to the menu item that currently
+ * has focus.
+ * @return {YAHOO.widget.MenuItem}
+ */
+ getFocusedMenuItem: function () {
+
+ return m_oFocusedMenuItem;
+
+ },
+
+
+ /**
+ * @method getFocusedMenu
+ * @description Returns a reference to the menu that currently
+ * has focus.
+ * @return {YAHOO.widget.Menu}
+ */
+ getFocusedMenu: function () {
+
+ var returnVal;
+
+ if (m_oFocusedMenuItem) {
+
+ returnVal = m_oFocusedMenuItem.parent.getRoot();
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method toString
+ * @description Returns a string representing the menu manager.
+ * @return {String}
+ */
+ toString: function () {
+
+ return _MENUMANAGER;
+
+ }
+
+ };
+
+ }();
+
+})();
+
+
+
+(function () {
+
+ var Lang = YAHOO.lang,
+
+ // String constants
+
+ _MENU = "Menu",
+ _DIV_UPPERCASE = "DIV",
+ _DIV_LOWERCASE = "div",
+ _ID = "id",
+ _SELECT = "SELECT",
+ _XY = "xy",
+ _Y = "y",
+ _UL_UPPERCASE = "UL",
+ _UL_LOWERCASE = "ul",
+ _FIRST_OF_TYPE = "first-of-type",
+ _LI = "LI",
+ _OPTGROUP = "OPTGROUP",
+ _OPTION = "OPTION",
+ _DISABLED = "disabled",
+ _NONE = "none",
+ _SELECTED = "selected",
+ _GROUP_INDEX = "groupindex",
+ _INDEX = "index",
+ _SUBMENU = "submenu",
+ _VISIBLE = "visible",
+ _HIDE_DELAY = "hidedelay",
+ _POSITION = "position",
+ _DYNAMIC = "dynamic",
+ _STATIC = "static",
+ _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
+ _URL = "url",
+ _HASH = "#",
+ _TARGET = "target",
+ _MAX_HEIGHT = "maxheight",
+ _TOP_SCROLLBAR = "topscrollbar",
+ _BOTTOM_SCROLLBAR = "bottomscrollbar",
+ _UNDERSCORE = "_",
+ _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
+ _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
+ _MOUSEMOVE = "mousemove",
+ _SHOW_DELAY = "showdelay",
+ _SUBMENU_HIDE_DELAY = "submenuhidedelay",
+ _IFRAME = "iframe",
+ _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
+ _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
+ _SUBMENU_ALIGNMENT = "submenualignment",
+ _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
+ _CLICK_TO_HIDE = "clicktohide",
+ _CONTAINER = "container",
+ _SCROLL_INCREMENT = "scrollincrement",
+ _MIN_SCROLL_HEIGHT = "minscrollheight",
+ _CLASSNAME = "classname",
+ _SHADOW = "shadow",
+ _KEEP_OPEN = "keepopen",
+ _HD = "hd",
+ _HAS_TITLE = "hastitle",
+ _CONTEXT = "context",
+ _EMPTY_STRING = "",
+ _MOUSEDOWN = "mousedown",
+ _KEYDOWN = "keydown",
+ _HEIGHT = "height",
+ _WIDTH = "width",
+ _PX = "px",
+ _EFFECT = "effect",
+ _MONITOR_RESIZE = "monitorresize",
+ _DISPLAY = "display",
+ _BLOCK = "block",
+ _VISIBILITY = "visibility",
+ _ABSOLUTE = "absolute",
+ _ZINDEX = "zindex",
+ _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
+ _NON_BREAKING_SPACE = " ",
+ _SPACE = " ",
+ _MOUSEOVER = "mouseover",
+ _MOUSEOUT = "mouseout",
+ _ITEM_ADDED = "itemAdded",
+ _ITEM_REMOVED = "itemRemoved",
+ _HIDDEN = "hidden",
+ _YUI_MENU_SHADOW = "yui-menu-shadow",
+ _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
+ _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
+
+
+/**
+* The Menu class creates a container that holds a vertical list representing
+* a set of options or commands. Menu is the base class for all
+* menu containers.
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><div></code> element of the menu.
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><select></code> element to be used as the data source
+* for the menu.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
+* specifying the <code><div></code> element of the menu.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
+* Object specifying the <code><select></code> element to be used as
+* the data source for the menu.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu. See configuration class documentation for
+* more details.
+* @namespace YAHOO.widget
+* @class Menu
+* @constructor
+* @extends YAHOO.widget.Overlay
+*/
+YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
+
+ if (p_oConfig) {
+
+ this.parent = p_oConfig.parent;
+ this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
+ this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
+
+ }
+
+
+ YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
+
+};
+
+
+
+/**
+* @method checkPosition
+* @description Checks to make sure that the value of the "position" property
+* is one of the supported strings. Returns true if the position is supported.
+* @private
+* @param {Object} p_sPosition String specifying the position of the menu.
+* @return {Boolean}
+*/
+function checkPosition(p_sPosition) {
+
+ var returnVal = false;
+
+ if (Lang.isString(p_sPosition)) {
+
+ returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
+
+ }
+
+ return returnVal;
+
+}
+
+
+var Dom = YAHOO.util.Dom,
+ Event = YAHOO.util.Event,
+ Module = YAHOO.widget.Module,
+ Overlay = YAHOO.widget.Overlay,
+ Menu = YAHOO.widget.Menu,
+ MenuManager = YAHOO.widget.MenuManager,
+ CustomEvent = YAHOO.util.CustomEvent,
+ UA = YAHOO.env.ua,
+
+ m_oShadowTemplate,
+
+ bFocusListenerInitialized = false,
+
+ oFocusedElement,
+
+ EVENT_TYPES = [
+
+ ["mouseOverEvent", _MOUSEOVER],
+ ["mouseOutEvent", _MOUSEOUT],
+ ["mouseDownEvent", _MOUSEDOWN],
+ ["mouseUpEvent", "mouseup"],
+ ["clickEvent", "click"],
+ ["keyPressEvent", "keypress"],
+ ["keyDownEvent", _KEYDOWN],
+ ["keyUpEvent", "keyup"],
+ ["focusEvent", "focus"],
+ ["blurEvent", "blur"],
+ ["itemAddedEvent", _ITEM_ADDED],
+ ["itemRemovedEvent", _ITEM_REMOVED]
+
+ ],
+
+ VISIBLE_CONFIG = {
+ key: _VISIBLE,
+ value: false,
+ validator: Lang.isBoolean
+ },
+
+ CONSTRAIN_TO_VIEWPORT_CONFIG = {
+ key: _CONSTRAIN_TO_VIEWPORT,
+ value: true,
+ validator: Lang.isBoolean,
+ supercedes: [_IFRAME,"x",_Y,_XY]
+ },
+
+ PREVENT_CONTEXT_OVERLAP_CONFIG = {
+ key: _PREVENT_CONTEXT_OVERLAP,
+ value: true,
+ validator: Lang.isBoolean,
+ supercedes: [_CONSTRAIN_TO_VIEWPORT]
+ },
+
+ POSITION_CONFIG = {
+ key: _POSITION,
+ value: _DYNAMIC,
+ validator: checkPosition,
+ supercedes: [_VISIBLE, _IFRAME]
+ },
+
+ SUBMENU_ALIGNMENT_CONFIG = {
+ key: _SUBMENU_ALIGNMENT,
+ value: ["tl","tr"]
+ },
+
+ AUTO_SUBMENU_DISPLAY_CONFIG = {
+ key: _AUTO_SUBMENU_DISPLAY,
+ value: true,
+ validator: Lang.isBoolean,
+ suppressEvent: true
+ },
+
+ SHOW_DELAY_CONFIG = {
+ key: _SHOW_DELAY,
+ value: 250,
+ validator: Lang.isNumber,
+ suppressEvent: true
+ },
+
+ HIDE_DELAY_CONFIG = {
+ key: _HIDE_DELAY,
+ value: 0,
+ validator: Lang.isNumber,
+ suppressEvent: true
+ },
+
+ SUBMENU_HIDE_DELAY_CONFIG = {
+ key: _SUBMENU_HIDE_DELAY,
+ value: 250,
+ validator: Lang.isNumber,
+ suppressEvent: true
+ },
+
+ CLICK_TO_HIDE_CONFIG = {
+ key: _CLICK_TO_HIDE,
+ value: true,
+ validator: Lang.isBoolean,
+ suppressEvent: true
+ },
+
+ CONTAINER_CONFIG = {
+ key: _CONTAINER,
+ suppressEvent: true
+ },
+
+ SCROLL_INCREMENT_CONFIG = {
+ key: _SCROLL_INCREMENT,
+ value: 1,
+ validator: Lang.isNumber,
+ supercedes: [_MAX_HEIGHT],
+ suppressEvent: true
+ },
+
+ MIN_SCROLL_HEIGHT_CONFIG = {
+ key: _MIN_SCROLL_HEIGHT,
+ value: 90,
+ validator: Lang.isNumber,
+ supercedes: [_MAX_HEIGHT],
+ suppressEvent: true
+ },
+
+ MAX_HEIGHT_CONFIG = {
+ key: _MAX_HEIGHT,
+ value: 0,
+ validator: Lang.isNumber,
+ supercedes: [_IFRAME],
+ suppressEvent: true
+ },
+
+ CLASS_NAME_CONFIG = {
+ key: _CLASSNAME,
+ value: null,
+ validator: Lang.isString,
+ suppressEvent: true
+ },
+
+ DISABLED_CONFIG = {
+ key: _DISABLED,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true
+ },
+
+ SHADOW_CONFIG = {
+ key: _SHADOW,
+ value: true,
+ validator: Lang.isBoolean,
+ suppressEvent: true,
+ supercedes: [_VISIBLE]
+ },
+
+ KEEP_OPEN_CONFIG = {
+ key: _KEEP_OPEN,
+ value: false,
+ validator: Lang.isBoolean
+ };
+
+
+function onDocFocus(event) {
+
+ oFocusedElement = Event.getTarget(event);
+
+}
+
+
+
+YAHOO.lang.extend(Menu, Overlay, {
+
+
+// Constants
+
+
+/**
+* @property CSS_CLASS_NAME
+* @description String representing the CSS class(es) to be applied to the
+* menu's <code><div></code> element.
+* @default "yuimenu"
+* @final
+* @type String
+*/
+CSS_CLASS_NAME: "yuimenu",
+
+
+/**
+* @property ITEM_TYPE
+* @description Object representing the type of menu item to instantiate and
+* add when parsing the child nodes (either <code><li></code> element,
+* <code><optgroup></code> element or <code><option></code>)
+* of the menu's source HTML element.
+* @default YAHOO.widget.MenuItem
+* @final
+* @type YAHOO.widget.MenuItem
+*/
+ITEM_TYPE: null,
+
+
+/**
+* @property GROUP_TITLE_TAG_NAME
+* @description String representing the tagname of the HTML element used to
+* title the menu's item groups.
+* @default H6
+* @final
+* @type String
+*/
+GROUP_TITLE_TAG_NAME: "h6",
+
+
+/**
+* @property OFF_SCREEN_POSITION
+* @description Array representing the default x and y position that a menu
+* should have when it is positioned outside the viewport by the
+* "poistionOffScreen" method.
+* @default "-999em"
+* @final
+* @type String
+*/
+OFF_SCREEN_POSITION: "-999em",
+
+
+// Private properties
+
+
+/**
+* @property _useHideDelay
+* @description Boolean indicating if the "mouseover" and "mouseout" event
+* handlers used for hiding the menu via a call to "YAHOO.lang.later" have
+* already been assigned.
+* @default false
+* @private
+* @type Boolean
+*/
+_useHideDelay: false,
+
+
+/**
+* @property _bHandledMouseOverEvent
+* @description Boolean indicating the current state of the menu's
+* "mouseover" event.
+* @default false
+* @private
+* @type Boolean
+*/
+_bHandledMouseOverEvent: false,
+
+
+/**
+* @property _bHandledMouseOutEvent
+* @description Boolean indicating the current state of the menu's
+* "mouseout" event.
+* @default false
+* @private
+* @type Boolean
+*/
+_bHandledMouseOutEvent: false,
+
+
+/**
+* @property _aGroupTitleElements
+* @description Array of HTML element used to title groups of menu items.
+* @default []
+* @private
+* @type Array
+*/
+_aGroupTitleElements: null,
+
+
+/**
+* @property _aItemGroups
+* @description Multi-dimensional Array representing the menu items as they
+* are grouped in the menu.
+* @default []
+* @private
+* @type Array
+*/
+_aItemGroups: null,
+
+
+/**
+* @property _aListElements
+* @description Array of <code><ul></code> elements, each of which is
+* the parent node for each item's <code><li></code> element.
+* @default []
+* @private
+* @type Array
+*/
+_aListElements: null,
+
+
+/**
+* @property _nCurrentMouseX
+* @description The current x coordinate of the mouse inside the area of
+* the menu.
+* @default 0
+* @private
+* @type Number
+*/
+_nCurrentMouseX: 0,
+
+
+/**
+* @property _bStopMouseEventHandlers
+* @description Stops "mouseover," "mouseout," and "mousemove" event handlers
+* from executing.
+* @default false
+* @private
+* @type Boolean
+*/
+_bStopMouseEventHandlers: false,
+
+
+/**
+* @property _sClassName
+* @description The current value of the "classname" configuration attribute.
+* @default null
+* @private
+* @type String
+*/
+_sClassName: null,
+
+
+
+// Public properties
+
+
+/**
+* @property lazyLoad
+* @description Boolean indicating if the menu's "lazy load" feature is
+* enabled. If set to "true," initialization and rendering of the menu's
+* items will be deferred until the first time it is made visible. This
+* property should be set via the constructor using the configuration
+* object literal.
+* @default false
+* @type Boolean
+*/
+lazyLoad: false,
+
+
+/**
+* @property itemData
+* @description Array of items to be added to the menu. The array can contain
+* strings representing the text for each item to be created, object literals
+* representing the menu item configuration properties, or MenuItem instances.
+* This property should be set via the constructor using the configuration
+* object literal.
+* @default null
+* @type Array
+*/
+itemData: null,
+
+
+/**
+* @property activeItem
+* @description Object reference to the item in the menu that has is selected.
+* @default null
+* @type YAHOO.widget.MenuItem
+*/
+activeItem: null,
+
+
+/**
+* @property parent
+* @description Object reference to the menu's parent menu or menu item.
+* This property can be set via the constructor using the configuration
+* object literal.
+* @default null
+* @type YAHOO.widget.MenuItem
+*/
+parent: null,
+
+
+/**
+* @property srcElement
+* @description Object reference to the HTML element (either
+* <code><select></code> or <code><div></code>) used to
+* create the menu.
+* @default null
+* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+* level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
+* href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
+* html#ID-22445964">HTMLDivElement</a>
+*/
+srcElement: null,
+
+
+
+// Events
+
+
+/**
+* @event mouseOverEvent
+* @description Fires when the mouse has entered the menu. Passes back
+* the DOM Event object as an argument.
+*/
+
+
+/**
+* @event mouseOutEvent
+* @description Fires when the mouse has left the menu. Passes back the DOM
+* Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event mouseDownEvent
+* @description Fires when the user mouses down on the menu. Passes back the
+* DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event mouseUpEvent
+* @description Fires when the user releases a mouse button while the mouse is
+* over the menu. Passes back the DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event clickEvent
+* @description Fires when the user clicks the on the menu. Passes back the
+* DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event keyPressEvent
+* @description Fires when the user presses an alphanumeric key when one of the
+* menu's items has focus. Passes back the DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event keyDownEvent
+* @description Fires when the user presses a key when one of the menu's items
+* has focus. Passes back the DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event keyUpEvent
+* @description Fires when the user releases a key when one of the menu's items
+* has focus. Passes back the DOM Event object as an argument.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event itemAddedEvent
+* @description Fires when an item is added to the menu.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @event itemRemovedEvent
+* @description Fires when an item is removed to the menu.
+* @type YAHOO.util.CustomEvent
+*/
+
+
+/**
+* @method init
+* @description The Menu class's initialization method. This method is
+* automatically called by the constructor, and sets up all DOM references
+* for pre-existing markup, and creates required markup if it is not
+* already present.
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><div></code> element of the menu.
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><select></code> element to be used as the data source
+* for the menu.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
+* specifying the <code><div></code> element of the menu.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
+* Object specifying the <code><select></code> element to be used as
+* the data source for the menu.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu. See configuration class documentation for
+* more details.
+*/
+init: function (p_oElement, p_oConfig) {
+
+ this._aItemGroups = [];
+ this._aListElements = [];
+ this._aGroupTitleElements = [];
+
+ if (!this.ITEM_TYPE) {
+
+ this.ITEM_TYPE = YAHOO.widget.MenuItem;
+
+ }
+
+
+ var oElement;
+
+ if (Lang.isString(p_oElement)) {
+
+ oElement = Dom.get(p_oElement);
+
+ }
+ else if (p_oElement.tagName) {
+
+ oElement = p_oElement;
+
+ }
+
+
+ if (oElement && oElement.tagName) {
+
+ switch(oElement.tagName.toUpperCase()) {
+
+ case _DIV_UPPERCASE:
+
+ this.srcElement = oElement;
+
+ if (!oElement.id) {
+
+ oElement.setAttribute(_ID, Dom.generateId());
+
+ }
+
+
+ /*
+ Note: we don't pass the user config in here yet
+ because we only want it executed once, at the lowest
+ subclass level.
+ */
+
+ Menu.superclass.init.call(this, oElement);
+
+ this.beforeInitEvent.fire(Menu);
+
+ YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
+
+ break;
+
+ case _SELECT:
+
+ this.srcElement = oElement;
+
+
+ /*
+ The source element is not something that we can use
+ outright, so we need to create a new Overlay
+
+ Note: we don't pass the user config in here yet
+ because we only want it executed once, at the lowest
+ subclass level.
+ */
+
+ Menu.superclass.init.call(this, Dom.generateId());
+
+ this.beforeInitEvent.fire(Menu);
+
+ YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
+
+ break;
+
+ }
+
+ }
+ else {
+
+ /*
+ Note: we don't pass the user config in here yet
+ because we only want it executed once, at the lowest
+ subclass level.
+ */
+
+ Menu.superclass.init.call(this, p_oElement);
+
+ this.beforeInitEvent.fire(Menu);
+
+ YAHOO.log("No source element found. Created element with id: " + this.id, "info", this.toString());
+
+ }
+
+
+ if (this.element) {
+
+ Dom.addClass(this.element, this.CSS_CLASS_NAME);
+
+
+ // Subscribe to Custom Events
+
+ this.initEvent.subscribe(this._onInit);
+ this.beforeRenderEvent.subscribe(this._onBeforeRender);
+ this.renderEvent.subscribe(this._onRender);
+ this.beforeShowEvent.subscribe(this._onBeforeShow);
+ this.hideEvent.subscribe(this._onHide);
+ this.showEvent.subscribe(this._onShow);
+ this.beforeHideEvent.subscribe(this._onBeforeHide);
+ this.mouseOverEvent.subscribe(this._onMouseOver);
+ this.mouseOutEvent.subscribe(this._onMouseOut);
+ this.clickEvent.subscribe(this._onClick);
+ this.keyDownEvent.subscribe(this._onKeyDown);
+ this.keyPressEvent.subscribe(this._onKeyPress);
+ this.blurEvent.subscribe(this._onBlur);
+
+
+ if (!bFocusListenerInitialized) {
+ Event.onFocus(document, onDocFocus);
+ bFocusListenerInitialized = true;
+ }
+
+
+ // Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY"
+ // methods return values that don't take scrollTop into consideration
+
+ if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) {
+
+ this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
+
+ }
+
+
+ if (p_oConfig) {
+
+ this.cfg.applyConfig(p_oConfig, true);
+
+ }
+
+
+ // Register the Menu instance with the MenuManager
+
+ MenuManager.addMenu(this);
+
+
+ this.initEvent.fire(Menu);
+
+ }
+
+},
+
+
+
+// Private methods
+
+
+/**
+* @method _initSubTree
+* @description Iterates the childNodes of the source element to find nodes
+* used to instantiate menu and menu items.
+* @private
+*/
+_initSubTree: function () {
+
+ var oSrcElement = this.srcElement,
+ sSrcElementTagName,
+ nGroup,
+ sGroupTitleTagName,
+ oNode,
+ aListElements,
+ nListElements,
+ i;
+
+
+ if (oSrcElement) {
+
+ sSrcElementTagName =
+ (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
+
+
+ if (sSrcElementTagName == _DIV_UPPERCASE) {
+
+ // Populate the collection of item groups and item group titles
+
+ oNode = this.body.firstChild;
+
+
+ if (oNode) {
+
+ nGroup = 0;
+ sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
+
+ do {
+
+
+ if (oNode && oNode.tagName) {
+
+ switch (oNode.tagName.toUpperCase()) {
+
+ case sGroupTitleTagName:
+
+ this._aGroupTitleElements[nGroup] = oNode;
+
+ break;
+
+ case _UL_UPPERCASE:
+
+ this._aListElements[nGroup] = oNode;
+ this._aItemGroups[nGroup] = [];
+ nGroup++;
+
+ break;
+
+ }
+
+ }
+
+ }
+ while ((oNode = oNode.nextSibling));
+
+
+ /*
+ Apply the "first-of-type" class to the first UL to mimic
+ the ":first-of-type" CSS3 psuedo class.
+ */
+
+ if (this._aListElements[0]) {
+
+ Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
+
+ }
+
+ }
+
+ }
+
+
+ oNode = null;
+
+ YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
+
+
+ if (sSrcElementTagName) {
+
+ switch (sSrcElementTagName) {
+
+ case _DIV_UPPERCASE:
+
+ aListElements = this._aListElements;
+ nListElements = aListElements.length;
+
+ if (nListElements > 0) {
+
+ YAHOO.log("Found " + nListElements + " item groups to initialize.",
+ "info", this.toString());
+
+ i = nListElements - 1;
+
+ do {
+
+ oNode = aListElements[i].firstChild;
+
+ if (oNode) {
+
+ YAHOO.log("Scanning " +
+ aListElements[i].childNodes.length +
+ " child nodes for items to initialize.", "info", this.toString());
+
+ do {
+
+ if (oNode && oNode.tagName &&
+ oNode.tagName.toUpperCase() == _LI) {
+
+ YAHOO.log("Initializing " +
+ oNode.tagName + " node.", "info", this.toString());
+
+ this.addItem(new this.ITEM_TYPE(oNode,
+ { parent: this }), i);
+
+ }
+
+ }
+ while ((oNode = oNode.nextSibling));
+
+ }
+
+ }
+ while (i--);
+
+ }
+
+ break;
+
+ case _SELECT:
+
+ YAHOO.log("Scanning " +
+ oSrcElement.childNodes.length +
+ " child nodes for items to initialize.", "info", this.toString());
+
+ oNode = oSrcElement.firstChild;
+
+ do {
+
+ if (oNode && oNode.tagName) {
+
+ switch (oNode.tagName.toUpperCase()) {
+
+ case _OPTGROUP:
+ case _OPTION:
+
+ YAHOO.log("Initializing " +
+ oNode.tagName + " node.", "info", this.toString());
+
+ this.addItem(
+ new this.ITEM_TYPE(
+ oNode,
+ { parent: this }
+ )
+ );
+
+ break;
+
+ }
+
+ }
+
+ }
+ while ((oNode = oNode.nextSibling));
+
+ break;
+
+ }
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _getFirstEnabledItem
+* @description Returns the first enabled item in the menu.
+* @return {YAHOO.widget.MenuItem}
+* @private
+*/
+_getFirstEnabledItem: function () {
+
+ var aItems = this.getItems(),
+ nItems = aItems.length,
+ oItem,
+ returnVal;
+
+
+ for(var i=0; i<nItems; i++) {
+
+ oItem = aItems[i];
+
+ if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
+
+ returnVal = oItem;
+ break;
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method _addItemToGroup
+* @description Adds a menu item to a group.
+* @private
+* @param {Number} p_nGroupIndex Number indicating the group to which the
+* item belongs.
+* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
+* instance to be added to the menu.
+* @param {String} p_oItem String specifying the text of the item to be added
+* to the menu.
+* @param {Object} p_oItem Object literal containing a set of menu item
+* configuration properties.
+* @param {Number} p_nItemIndex Optional. Number indicating the index at
+* which the menu item should be added.
+* @return {YAHOO.widget.MenuItem}
+*/
+_addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
+
+ var oItem,
+ nGroupIndex,
+ aGroup,
+ oGroupItem,
+ bAppend,
+ oNextItemSibling,
+ nItemIndex,
+ returnVal;
+
+
+ function getNextItemSibling(p_aArray, p_nStartIndex) {
+
+ return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
+
+ }
+
+
+ if (p_oItem instanceof this.ITEM_TYPE) {
+
+ oItem = p_oItem;
+ oItem.parent = this;
+
+ }
+ else if (Lang.isString(p_oItem)) {
+
+ oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
+
+ }
+ else if (Lang.isObject(p_oItem)) {
+
+ p_oItem.parent = this;
+
+ oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
+
+ }
+
+
+ if (oItem) {
+
+ if (oItem.cfg.getProperty(_SELECTED)) {
+
+ this.activeItem = oItem;
+
+ }
+
+
+ nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
+ aGroup = this._getItemGroup(nGroupIndex);
+
+
+
+ if (!aGroup) {
+
+ aGroup = this._createItemGroup(nGroupIndex);
+
+ }
+
+
+ if (Lang.isNumber(p_nItemIndex)) {
+
+ bAppend = (p_nItemIndex >= aGroup.length);
+
+
+ if (aGroup[p_nItemIndex]) {
+
+ aGroup.splice(p_nItemIndex, 0, oItem);
+
+ }
+ else {
+
+ aGroup[p_nItemIndex] = oItem;
+
+ }
+
+
+ oGroupItem = aGroup[p_nItemIndex];
+
+ if (oGroupItem) {
+
+ if (bAppend && (!oGroupItem.element.parentNode ||
+ oGroupItem.element.parentNode.nodeType == 11)) {
+
+ this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
+
+ }
+ else {
+
+ oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
+
+ if (oNextItemSibling && (!oGroupItem.element.parentNode ||
+ oGroupItem.element.parentNode.nodeType == 11)) {
+
+ this._aListElements[nGroupIndex].insertBefore(
+ oGroupItem.element, oNextItemSibling.element);
+
+ }
+
+ }
+
+
+ oGroupItem.parent = this;
+
+ this._subscribeToItemEvents(oGroupItem);
+
+ this._configureSubmenu(oGroupItem);
+
+ this._updateItemProperties(nGroupIndex);
+
+ YAHOO.log("Item inserted." +
+ " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
+ " Index: " + oGroupItem.index + ", " +
+ " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
+
+ this.itemAddedEvent.fire(oGroupItem);
+ this.changeContentEvent.fire();
+
+ returnVal = oGroupItem;
+
+ }
+
+ }
+ else {
+
+ nItemIndex = aGroup.length;
+
+ aGroup[nItemIndex] = oItem;
+
+ oGroupItem = aGroup[nItemIndex];
+
+
+ if (oGroupItem) {
+
+ if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
+
+ this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
+
+ }
+
+ oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
+ oGroupItem.element.setAttribute(_INDEX, nItemIndex);
+
+ oGroupItem.parent = this;
+
+ oGroupItem.index = nItemIndex;
+ oGroupItem.groupIndex = nGroupIndex;
+
+ this._subscribeToItemEvents(oGroupItem);
+
+ this._configureSubmenu(oGroupItem);
+
+ if (nItemIndex === 0) {
+
+ Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
+
+ }
+
+ YAHOO.log("Item added." +
+ " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
+ " Index: " + oGroupItem.index + ", " +
+ " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
+
+
+ this.itemAddedEvent.fire(oGroupItem);
+ this.changeContentEvent.fire();
+
+ returnVal = oGroupItem;
+
+ }
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method _removeItemFromGroupByIndex
+* @description Removes a menu item from a group by index. Returns the menu
+* item that was removed.
+* @private
+* @param {Number} p_nGroupIndex Number indicating the group to which the menu
+* item belongs.
+* @param {Number} p_nItemIndex Number indicating the index of the menu item
+* to be removed.
+* @return {YAHOO.widget.MenuItem}
+*/
+_removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
+
+ var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
+ aGroup = this._getItemGroup(nGroupIndex),
+ aArray,
+ oItem,
+ oUL;
+
+ if (aGroup) {
+
+ aArray = aGroup.splice(p_nItemIndex, 1);
+ oItem = aArray[0];
+
+ if (oItem) {
+
+ // Update the index and className properties of each member
+
+ this._updateItemProperties(nGroupIndex);
+
+ if (aGroup.length === 0) {
+
+ // Remove the UL
+
+ oUL = this._aListElements[nGroupIndex];
+
+ if (this.body && oUL) {
+
+ this.body.removeChild(oUL);
+
+ }
+
+ // Remove the group from the array of items
+
+ this._aItemGroups.splice(nGroupIndex, 1);
+
+
+ // Remove the UL from the array of ULs
+
+ this._aListElements.splice(nGroupIndex, 1);
+
+
+ /*
+ Assign the "first-of-type" class to the new first UL
+ in the collection
+ */
+
+ oUL = this._aListElements[0];
+
+ if (oUL) {
+
+ Dom.addClass(oUL, _FIRST_OF_TYPE);
+
+ }
+
+ }
+
+
+ this.itemRemovedEvent.fire(oItem);
+ this.changeContentEvent.fire();
+
+ }
+
+ }
+
+ // Return a reference to the item that was removed
+
+ return oItem;
+
+},
+
+
+/**
+* @method _removeItemFromGroupByValue
+* @description Removes a menu item from a group by reference. Returns the
+* menu item that was removed.
+* @private
+* @param {Number} p_nGroupIndex Number indicating the group to which the
+* menu item belongs.
+* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
+* instance to be removed.
+* @return {YAHOO.widget.MenuItem}
+*/
+_removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
+
+ var aGroup = this._getItemGroup(p_nGroupIndex),
+ nItems,
+ nItemIndex,
+ returnVal,
+ i;
+
+ if (aGroup) {
+
+ nItems = aGroup.length;
+ nItemIndex = -1;
+
+ if (nItems > 0) {
+
+ i = nItems-1;
+
+ do {
+
+ if (aGroup[i] == p_oItem) {
+
+ nItemIndex = i;
+ break;
+
+ }
+
+ }
+ while (i--);
+
+ if (nItemIndex > -1) {
+
+ returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
+
+ }
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method _updateItemProperties
+* @description Updates the "index," "groupindex," and "className" properties
+* of the menu items in the specified group.
+* @private
+* @param {Number} p_nGroupIndex Number indicating the group of items to update.
+*/
+_updateItemProperties: function (p_nGroupIndex) {
+
+ var aGroup = this._getItemGroup(p_nGroupIndex),
+ nItems = aGroup.length,
+ oItem,
+ oLI,
+ i;
+
+
+ if (nItems > 0) {
+
+ i = nItems - 1;
+
+ // Update the index and className properties of each member
+
+ do {
+
+ oItem = aGroup[i];
+
+ if (oItem) {
+
+ oLI = oItem.element;
+
+ oItem.index = i;
+ oItem.groupIndex = p_nGroupIndex;
+
+ oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
+ oLI.setAttribute(_INDEX, i);
+
+ Dom.removeClass(oLI, _FIRST_OF_TYPE);
+
+ }
+
+ }
+ while (i--);
+
+
+ if (oLI) {
+
+ Dom.addClass(oLI, _FIRST_OF_TYPE);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _createItemGroup
+* @description Creates a new menu item group (array) and its associated
+* <code><ul></code> element. Returns an aray of menu item groups.
+* @private
+* @param {Number} p_nIndex Number indicating the group to create.
+* @return {Array}
+*/
+_createItemGroup: function (p_nIndex) {
+
+ var oUL,
+ returnVal;
+
+ if (!this._aItemGroups[p_nIndex]) {
+
+ this._aItemGroups[p_nIndex] = [];
+
+ oUL = document.createElement(_UL_LOWERCASE);
+
+ this._aListElements[p_nIndex] = oUL;
+
+ returnVal = this._aItemGroups[p_nIndex];
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method _getItemGroup
+* @description Returns the menu item group at the specified index.
+* @private
+* @param {Number} p_nIndex Number indicating the index of the menu item group
+* to be retrieved.
+* @return {Array}
+*/
+_getItemGroup: function (p_nIndex) {
+
+ var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
+ aGroups = this._aItemGroups,
+ returnVal;
+
+ if (nIndex in aGroups) {
+
+ returnVal = aGroups[nIndex];
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method _configureSubmenu
+* @description Subscribes the menu item's submenu to its parent menu's events.
+* @private
+* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
+* instance with the submenu to be configured.
+*/
+_configureSubmenu: function (p_oItem) {
+
+ var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ /*
+ Listen for configuration changes to the parent menu
+ so they they can be applied to the submenu.
+ */
+
+ this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
+
+ this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
+
+ }
+
+},
+
+
+
+
+/**
+* @method _subscribeToItemEvents
+* @description Subscribes a menu to a menu item's event.
+* @private
+* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
+* instance whose events should be subscribed to.
+*/
+_subscribeToItemEvents: function (p_oItem) {
+
+ p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
+ p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
+
+},
+
+
+/**
+* @method _onVisibleChange
+* @description Change event handler for the the menu's "visible" configuration
+* property.
+* @private
+* @param {String} p_sType String representing the name of the event that
+* was fired.
+* @param {Array} p_aArgs Array of arguments sent when the event was fired.
+*/
+_onVisibleChange: function (p_sType, p_aArgs) {
+
+ var bVisible = p_aArgs[0];
+
+ if (bVisible) {
+
+ Dom.addClass(this.element, _VISIBLE);
+
+ }
+ else {
+
+ Dom.removeClass(this.element, _VISIBLE);
+
+ }
+
+},
+
+
+/**
+* @method _cancelHideDelay
+* @description Cancels the call to "hideMenu."
+* @private
+*/
+_cancelHideDelay: function () {
+
+ var oTimer = this.getRoot()._hideDelayTimer;
+
+ if (oTimer) {
+
+ oTimer.cancel();
+
+ }
+
+},
+
+
+/**
+* @method _execHideDelay
+* @description Hides the menu after the number of milliseconds specified by
+* the "hidedelay" configuration property.
+* @private
+*/
+_execHideDelay: function () {
+
+ this._cancelHideDelay();
+
+ var oRoot = this.getRoot();
+
+ oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
+
+ if (oRoot.activeItem) {
+
+ if (oRoot.hasFocus()) {
+
+ oRoot.activeItem.focus();
+
+ }
+
+ oRoot.clearActiveItem();
+
+ }
+
+ if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) &&
+ this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ this.hide();
+
+ }
+
+ });
+
+},
+
+
+/**
+* @method _cancelShowDelay
+* @description Cancels the call to the "showMenu."
+* @private
+*/
+_cancelShowDelay: function () {
+
+ var oTimer = this.getRoot()._showDelayTimer;
+
+ if (oTimer) {
+
+ oTimer.cancel();
+
+ }
+
+},
+
+
+/**
+* @method _execSubmenuHideDelay
+* @description Hides a submenu after the number of milliseconds specified by
+* the "submenuhidedelay" configuration property have ellapsed.
+* @private
+* @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
+* should be hidden.
+* @param {Number} p_nMouseX The x coordinate of the mouse when it left
+* the specified submenu's parent menu item.
+* @param {Number} p_nHideDelay The number of milliseconds that should ellapse
+* before the submenu is hidden.
+*/
+_execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
+
+ p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
+
+ if (this._nCurrentMouseX > (p_nMouseX + 10)) {
+
+ p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
+
+ this.hide();
+
+ });
+
+ }
+ else {
+
+ p_oSubmenu.hide();
+
+ }
+
+ });
+
+},
+
+
+
+// Protected methods
+
+
+/**
+* @method _disableScrollHeader
+* @description Disables the header used for scrolling the body of the menu.
+* @protected
+*/
+_disableScrollHeader: function () {
+
+ if (!this._bHeaderDisabled) {
+
+ Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
+ this._bHeaderDisabled = true;
+
+ }
+
+},
+
+
+/**
+* @method _disableScrollFooter
+* @description Disables the footer used for scrolling the body of the menu.
+* @protected
+*/
+_disableScrollFooter: function () {
+
+ if (!this._bFooterDisabled) {
+
+ Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
+ this._bFooterDisabled = true;
+
+ }
+
+},
+
+
+/**
+* @method _enableScrollHeader
+* @description Enables the header used for scrolling the body of the menu.
+* @protected
+*/
+_enableScrollHeader: function () {
+
+ if (this._bHeaderDisabled) {
+
+ Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
+ this._bHeaderDisabled = false;
+
+ }
+
+},
+
+
+/**
+* @method _enableScrollFooter
+* @description Enables the footer used for scrolling the body of the menu.
+* @protected
+*/
+_enableScrollFooter: function () {
+
+ if (this._bFooterDisabled) {
+
+ Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
+ this._bFooterDisabled = false;
+
+ }
+
+},
+
+
+/**
+* @method _onMouseOver
+* @description "mouseover" event handler for the menu.
+* @protected
+* @param {String} p_sType String representing the name of the event that
+* was fired.
+* @param {Array} p_aArgs Array of arguments sent when the event was fired.
+*/
+_onMouseOver: function (p_sType, p_aArgs) {
+
+ var oEvent = p_aArgs[0],
+ oItem = p_aArgs[1],
+ oTarget = Event.getTarget(oEvent),
+ oRoot = this.getRoot(),
+ oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
+ oParentMenu,
+ nShowDelay,
+ bShowDelay,
+ oActiveItem,
+ oItemCfg,
+ oSubmenu;
+
+
+ var showSubmenu = function () {
+
+ if (this.parent.cfg.getProperty(_SELECTED)) {
+
+ this.show();
+
+ }
+
+ };
+
+
+ if (!this._bStopMouseEventHandlers) {
+
+ if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
+ Dom.isAncestor(this.element, oTarget))) {
+
+ // Menu mouseover logic
+
+ if (this._useHideDelay) {
+ this._cancelHideDelay();
+ }
+
+ this._nCurrentMouseX = 0;
+
+ Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
+
+
+ /*
+ If the mouse is moving from the submenu back to its corresponding menu item,
+ don't hide the submenu or clear the active MenuItem.
+ */
+
+ if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
+
+ this.clearActiveItem();
+
+ }
+
+
+ if (this.parent && oSubmenuHideDelayTimer) {
+
+ oSubmenuHideDelayTimer.cancel();
+
+ this.parent.cfg.setProperty(_SELECTED, true);
+
+ oParentMenu = this.parent.parent;
+
+ oParentMenu._bHandledMouseOutEvent = true;
+ oParentMenu._bHandledMouseOverEvent = false;
+
+ }
+
+
+ this._bHandledMouseOverEvent = true;
+ this._bHandledMouseOutEvent = false;
+
+ }
+
+
+ if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) &&
+ (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
+
+ // Menu Item mouseover logic
+
+ nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
+ bShowDelay = (nShowDelay > 0);
+
+
+ if (bShowDelay) {
+
+ this._cancelShowDelay();
+
+ }
+
+
+ oActiveItem = this.activeItem;
+
+ if (oActiveItem) {
+
+ oActiveItem.cfg.setProperty(_SELECTED, false);
+
+ }
+
+
+ oItemCfg = oItem.cfg;
+
+ // Select and focus the current menu item
+
+ oItemCfg.setProperty(_SELECTED, true);
+
+
+ if (this.hasFocus() || oRoot._hasFocus) {
+
+ oItem.focus();
+
+ oRoot._hasFocus = false;
+
+ }
+
+
+ if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
+
+ // Show the submenu this menu item
+
+ oSubmenu = oItemCfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ if (bShowDelay) {
+
+ oRoot._showDelayTimer =
+ Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
+
+ }
+ else {
+
+ oSubmenu.show();
+
+ }
+
+ }
+
+ }
+
+ oItem.handledMouseOverEvent = true;
+ oItem.handledMouseOutEvent = false;
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onMouseOut
+* @description "mouseout" event handler for the menu.
+* @protected
+* @param {String} p_sType String representing the name of the event that
+* was fired.
+* @param {Array} p_aArgs Array of arguments sent when the event was fired.
+*/
+_onMouseOut: function (p_sType, p_aArgs) {
+
+ var oEvent = p_aArgs[0],
+ oItem = p_aArgs[1],
+ oRelatedTarget = Event.getRelatedTarget(oEvent),
+ bMovingToSubmenu = false,
+ oItemCfg,
+ oSubmenu,
+ nSubmenuHideDelay,
+ nShowDelay;
+
+
+ if (!this._bStopMouseEventHandlers) {
+
+ if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
+
+ oItemCfg = oItem.cfg;
+ oSubmenu = oItemCfg.getProperty(_SUBMENU);
+
+
+ if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
+ Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
+
+ bMovingToSubmenu = true;
+
+ }
+
+
+ if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
+ !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
+
+ // Menu Item mouseout logic
+
+ if (!bMovingToSubmenu) {
+
+ oItem.cfg.setProperty(_SELECTED, false);
+
+
+ if (oSubmenu) {
+
+ nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
+
+ nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
+
+ if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 &&
+ nShowDelay >= nSubmenuHideDelay) {
+
+ this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
+ nSubmenuHideDelay);
+
+ }
+ else {
+
+ oSubmenu.hide();
+
+ }
+
+ }
+
+ }
+
+
+ oItem.handledMouseOutEvent = true;
+ oItem.handledMouseOverEvent = false;
+
+ }
+
+ }
+
+
+ if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
+ !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
+
+ // Menu mouseout logic
+
+ if (this._useHideDelay) {
+ this._execHideDelay();
+ }
+
+ Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
+
+ this._nCurrentMouseX = Event.getPageX(oEvent);
+
+ this._bHandledMouseOutEvent = true;
+ this._bHandledMouseOverEvent = false;
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onMouseMove
+* @description "click" event handler for the menu.
+* @protected
+* @param {Event} p_oEvent Object representing the DOM event object passed
+* back by the event utility (YAHOO.util.Event).
+* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
+* fired the event.
+*/
+_onMouseMove: function (p_oEvent, p_oMenu) {
+
+ if (!this._bStopMouseEventHandlers) {
+
+ this._nCurrentMouseX = Event.getPageX(p_oEvent);
+
+ }
+
+},
+
+
+/**
+* @method _onClick
+* @description "click" event handler for the menu.
+* @protected
+* @param {String} p_sType String representing the name of the event that
+* was fired.
+* @param {Array} p_aArgs Array of arguments sent when the event was fired.
+*/
+_onClick: function (p_sType, p_aArgs) {
+
+ var oEvent = p_aArgs[0],
+ oItem = p_aArgs[1],
+ bInMenuAnchor = false,
+ oSubmenu,
+ oMenu,
+ oRoot,
+ sId,
+ sURL,
+ nHashPos,
+ nLen;
+
+
+ var hide = function () {
+
+ oRoot = this.getRoot();
+
+ if (oRoot instanceof YAHOO.widget.MenuBar ||
+ oRoot.cfg.getProperty(_POSITION) == _STATIC) {
+
+ oRoot.clearActiveItem();
+
+ }
+ else {
+
+ oRoot.hide();
+
+ }
+
+ };
+
+
+ if (oItem) {
+
+ if (oItem.cfg.getProperty(_DISABLED)) {
+
+ Event.preventDefault(oEvent);
+
+ hide.call(this);
+
+ }
+ else {
+
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+
+ /*
+ Check if the URL of the anchor is pointing to an element that is
+ a child of the menu.
+ */
+
+ sURL = oItem.cfg.getProperty(_URL);
+
+
+ if (sURL) {
+
+ nHashPos = sURL.indexOf(_HASH);
+
+ nLen = sURL.length;
+
+
+ if (nHashPos != -1) {
+
+ sURL = sURL.substr(nHashPos, nLen);
+
+ nLen = sURL.length;
+
+
+ if (nLen > 1) {
+
+ sId = sURL.substr(1, nLen);
+
+ oMenu = YAHOO.widget.MenuManager.getMenu(sId);
+
+ if (oMenu) {
+
+ bInMenuAnchor =
+ (this.getRoot() === oMenu.getRoot());
+
+ }
+
+ }
+ else if (nLen === 1) {
+
+ bInMenuAnchor = true;
+
+ }
+
+ }
+
+ }
+
+
+ if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
+
+ Event.preventDefault(oEvent);
+
+
+ if (UA.webkit) {
+
+ oItem.focus();
+
+ }
+ else {
+
+ oItem.focusEvent.fire();
+
+ }
+
+ }
+
+
+ if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
+
+ hide.call(this);
+
+ }
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onKeyDown
+* @description "keydown" event handler for the menu.
+* @protected
+* @param {String} p_sType String representing the name of the event that
+* was fired.
+* @param {Array} p_aArgs Array of arguments sent when the event was fired.
+*/
+_onKeyDown: function (p_sType, p_aArgs) {
+
+ var oEvent = p_aArgs[0],
+ oItem = p_aArgs[1],
+ oSubmenu,
+ oItemCfg,
+ oParentItem,
+ oRoot,
+ oNextItem,
+ oBody,
+ nBodyScrollTop,
+ nBodyOffsetHeight,
+ aItems,
+ nItems,
+ nNextItemOffsetTop,
+ nScrollTarget,
+ oParentMenu,
+ oFocusedEl;
+
+
+ if (this._useHideDelay) {
+ this._cancelHideDelay();
+ }
+
+
+ /*
+ This function is called to prevent a bug in Firefox. In Firefox,
+ moving a DOM element into a stationary mouse pointer will cause the
+ browser to fire mouse events. This can result in the menu mouse
+ event handlers being called uncessarily, especially when menus are
+ moved into a stationary mouse pointer as a result of a
+ key event handler.
+ */
+ function stopMouseEventHandlers() {
+
+ this._bStopMouseEventHandlers = true;
+
+ Lang.later(10, this, function () {
+
+ this._bStopMouseEventHandlers = false;
+
+ });
+
+ }
+
+
+ if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
+
+ oItemCfg = oItem.cfg;
+ oParentItem = this.parent;
+
+ switch(oEvent.keyCode) {
+
+ case 38: // Up arrow
+ case 40: // Down arrow
+
+ oNextItem = (oEvent.keyCode == 38) ?
+ oItem.getPreviousEnabledSibling() :
+ oItem.getNextEnabledSibling();
+
+ if (oNextItem) {
+
+ this.clearActiveItem();
+
+ oNextItem.cfg.setProperty(_SELECTED, true);
+ oNextItem.focus();
+
+
+ if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
+
+ oBody = this.body;
+ nBodyScrollTop = oBody.scrollTop;
+ nBodyOffsetHeight = oBody.offsetHeight;
+ aItems = this.getItems();
+ nItems = aItems.length - 1;
+ nNextItemOffsetTop = oNextItem.element.offsetTop;
+
+
+ if (oEvent.keyCode == 40 ) { // Down
+
+ if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
+
+ oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
+
+ }
+ else if (nNextItemOffsetTop <= nBodyScrollTop) {
+
+ oBody.scrollTop = 0;
+
+ }
+
+
+ if (oNextItem == aItems[nItems]) {
+
+ oBody.scrollTop = oNextItem.element.offsetTop;
+
+ }
+
+ }
+ else { // Up
+
+ if (nNextItemOffsetTop <= nBodyScrollTop) {
+
+ oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
+
+ }
+ else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
+
+ oBody.scrollTop = nNextItemOffsetTop;
+
+ }
+
+
+ if (oNextItem == aItems[0]) {
+
+ oBody.scrollTop = 0;
+
+ }
+
+ }
+
+
+ nBodyScrollTop = oBody.scrollTop;
+ nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
+
+ if (nBodyScrollTop === 0) {
+
+ this._disableScrollHeader();
+ this._enableScrollFooter();
+
+ }
+ else if (nBodyScrollTop == nScrollTarget) {
+
+ this._enableScrollHeader();
+ this._disableScrollFooter();
+
+ }
+ else {
+
+ this._enableScrollHeader();
+ this._enableScrollFooter();
+
+ }
+
+ }
+
+ }
+
+
+ Event.preventDefault(oEvent);
+
+ stopMouseEventHandlers();
+
+ break;
+
+
+ case 39: // Right arrow
+
+ oSubmenu = oItemCfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ if (!oItemCfg.getProperty(_SELECTED)) {
+
+ oItemCfg.setProperty(_SELECTED, true);
+
+ }
+
+ oSubmenu.show();
+ oSubmenu.setInitialFocus();
+ oSubmenu.setInitialSelection();
+
+ }
+ else {
+
+ oRoot = this.getRoot();
+
+ if (oRoot instanceof YAHOO.widget.MenuBar) {
+
+ oNextItem = oRoot.activeItem.getNextEnabledSibling();
+
+ if (oNextItem) {
+
+ oRoot.clearActiveItem();
+
+ oNextItem.cfg.setProperty(_SELECTED, true);
+
+ oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.show();
+ oSubmenu.setInitialFocus();
+
+ }
+ else {
+
+ oNextItem.focus();
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ Event.preventDefault(oEvent);
+
+ stopMouseEventHandlers();
+
+ break;
+
+
+ case 37: // Left arrow
+
+ if (oParentItem) {
+
+ oParentMenu = oParentItem.parent;
+
+ if (oParentMenu instanceof YAHOO.widget.MenuBar) {
+
+ oNextItem =
+ oParentMenu.activeItem.getPreviousEnabledSibling();
+
+ if (oNextItem) {
+
+ oParentMenu.clearActiveItem();
+
+ oNextItem.cfg.setProperty(_SELECTED, true);
+
+ oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.show();
+ oSubmenu.setInitialFocus();
+
+ }
+ else {
+
+ oNextItem.focus();
+
+ }
+
+ }
+
+ }
+ else {
+
+ this.hide();
+
+ oParentItem.focus();
+
+ }
+
+ }
+
+ Event.preventDefault(oEvent);
+
+ stopMouseEventHandlers();
+
+ break;
+
+ }
+
+
+ }
+
+
+ if (oEvent.keyCode == 27) { // Esc key
+
+ if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ this.hide();
+
+ if (this.parent) {
+
+ this.parent.focus();
+
+ }
+ else {
+ // Focus the element that previously had focus
+
+ oFocusedEl = this._focusedElement;
+
+ if (oFocusedEl && oFocusedEl.focus) {
+
+ try {
+ oFocusedEl.focus();
+ }
+ catch(ex) {
+ }
+
+ }
+
+ }
+
+ }
+ else if (this.activeItem) {
+
+ oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
+
+ oSubmenu.hide();
+ this.activeItem.focus();
+
+ }
+ else {
+
+ this.activeItem.blur();
+ this.activeItem.cfg.setProperty(_SELECTED, false);
+
+ }
+
+ }
+
+
+ Event.preventDefault(oEvent);
+
+ }
+
+},
+
+
+/**
+* @method _onKeyPress
+* @description "keypress" event handler for a Menu instance.
+* @protected
+* @param {String} p_sType The name of the event that was fired.
+* @param {Array} p_aArgs Collection of arguments sent when the event
+* was fired.
+*/
+_onKeyPress: function (p_sType, p_aArgs) {
+
+ var oEvent = p_aArgs[0];
+
+
+ if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
+
+ Event.preventDefault(oEvent);
+
+ }
+
+},
+
+
+/**
+* @method _onBlur
+* @description "blur" event handler for a Menu instance.
+* @protected
+* @param {String} p_sType The name of the event that was fired.
+* @param {Array} p_aArgs Collection of arguments sent when the event
+* was fired.
+*/
+_onBlur: function (p_sType, p_aArgs) {
+
+ if (this._hasFocus) {
+ this._hasFocus = false;
+ }
+
+},
+
+/**
+* @method _onYChange
+* @description "y" event handler for a Menu instance.
+* @protected
+* @param {String} p_sType The name of the event that was fired.
+* @param {Array} p_aArgs Collection of arguments sent when the event
+* was fired.
+*/
+_onYChange: function (p_sType, p_aArgs) {
+
+ var oParent = this.parent,
+ nScrollTop,
+ oIFrame,
+ nY;
+
+
+ if (oParent) {
+
+ nScrollTop = oParent.parent.body.scrollTop;
+
+
+ if (nScrollTop > 0) {
+
+ nY = (this.cfg.getProperty(_Y) - nScrollTop);
+
+ Dom.setY(this.element, nY);
+
+ oIFrame = this.iframe;
+
+
+ if (oIFrame) {
+
+ Dom.setY(oIFrame, nY);
+
+ }
+
+ this.cfg.setProperty(_Y, nY, true);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onScrollTargetMouseOver
+* @description "mouseover" event handler for the menu's "header" and "footer"
+* elements. Used to scroll the body of the menu up and down when the
+* menu's "maxheight" configuration property is set to a value greater than 0.
+* @protected
+* @param {Event} p_oEvent Object representing the DOM event object passed
+* back by the event utility (YAHOO.util.Event).
+* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
+* fired the event.
+*/
+_onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
+
+ var oBodyScrollTimer = this._bodyScrollTimer;
+
+
+ if (oBodyScrollTimer) {
+
+ oBodyScrollTimer.cancel();
+
+ }
+
+
+ this._cancelHideDelay();
+
+
+ var oTarget = Event.getTarget(p_oEvent),
+ oBody = this.body,
+ nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
+ nScrollTarget,
+ fnScrollFunction;
+
+
+ function scrollBodyDown() {
+
+ var nScrollTop = oBody.scrollTop;
+
+
+ if (nScrollTop < nScrollTarget) {
+
+ oBody.scrollTop = (nScrollTop + nScrollIncrement);
+
+ this._enableScrollHeader();
+
+ }
+ else {
+
+ oBody.scrollTop = nScrollTarget;
+
+ this._bodyScrollTimer.cancel();
+
+ this._disableScrollFooter();
+
+ }
+
+ }
+
+
+ function scrollBodyUp() {
+
+ var nScrollTop = oBody.scrollTop;
+
+
+ if (nScrollTop > 0) {
+
+ oBody.scrollTop = (nScrollTop - nScrollIncrement);
+
+ this._enableScrollFooter();
+
+ }
+ else {
+
+ oBody.scrollTop = 0;
+
+ this._bodyScrollTimer.cancel();
+
+ this._disableScrollHeader();
+
+ }
+
+ }
+
+
+ if (Dom.hasClass(oTarget, _HD)) {
+
+ fnScrollFunction = scrollBodyUp;
+
+ }
+ else {
+
+ nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
+
+ fnScrollFunction = scrollBodyDown;
+
+ }
+
+
+ this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
+
+},
+
+
+/**
+* @method _onScrollTargetMouseOut
[... 6343 lines stripped ...]