--- /dev/null
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+
+
+/**
+* @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 _DIV = "DIV",
+ _HD = "hd",
+ _BD = "bd",
+ _FT = "ft",
+ _LI = "LI",
+ _DISABLED = "disabled",
+ _MOUSEOVER = "mouseover",
+ _MOUSEOUT = "mouseout",
+ _MOUSEDOWN = "mousedown",
+ _MOUSEUP = "mouseup",
+ _FOCUS = YAHOO.env.ua.ie ? "focusin" : "focus",
+ _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",
+
+
+ Dom = YAHOO.util.Dom,
+ Event = YAHOO.util.Event,
+ Lang = YAHOO.lang;
+
+
+ /**
+ * 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"
+ },
+
+
+ // The element in the DOM that currently has focus
+
+ m_oFocusedElement = null,
+
+
+ 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),
+ 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[p_oEvent.type];
+
+
+ // Fire the Custom Event that corresponds the current DOM event
+
+ if (oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
+
+ oMenuItem[sCustomEventType].fire(p_oEvent);
+
+ }
+
+ oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
+
+ }
+ else if (p_oEvent.type == _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();
+
+ }
+ 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;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+ else if (p_oEvent.type == _FOCUS) {
+
+ m_oFocusedElement = oTarget;
+
+ }
+
+ }
+
+
+ /**
+ * @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 onMenuHide
+ * @description "hide" 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.
+ * @param <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+ * level-one-html.html#ID-58190037">p_oFocusedElement</a> The HTML element that had focus
+ * prior to the Menu being made visible
+ */
+ function onMenuHide(p_sType, p_aArgs, p_oFocusedElement) {
+
+ /*
+ Restore focus to the element in the DOM that had focus prior to the Menu
+ being made visible
+ */
+
+ if (p_oFocusedElement && p_oFocusedElement.focus) {
+
+ try {
+ p_oFocusedElement.focus();
+ }
+ catch(ex) {
+ }
+
+ }
+
+ this.hideEvent.unsubscribe(onMenuHide, p_oFocusedElement);
+
+ }
+
+
+ /**
+ * @method onMenuShow
+ * @description "show" 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 onMenuShow(p_sType, p_aArgs) {
+
+ /*
+ Dynamically positioned, root Menus focus themselves when visible, and will then,
+ when hidden, restore focus to the UI control that had focus before the Menu was
+ made visible
+ */
+
+ if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
+
+ this.hideEvent.subscribe(onMenuHide, m_oFocusedElement);
+ this.focus();
+
+ }
+
+ }
+
+
+ /**
+ * @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;
+
+
+ }
+ else if (m_oVisibleMenus[sId]) {
+
+ delete m_oVisibleMenus[sId];
+
+
+ }
+
+ }
+
+
+ /**
+ * @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);
+
+
+ }
+
+ }
+
+
+ /**
+ * @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);
+
+
+ }
+
+ }
+
+ }
+
+
+ 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;
+
+
+ }
+
+ 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);
+ p_oMenu.showEvent.subscribe(onMenuShow);
+
+
+ }
+
+ },
+
+
+ /**
+ * @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];
+
+
+
+ /*
+ Unregister the menu from the collection of
+ visible menus
+ */
+
+ if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
+
+ delete m_oVisibleMenus[sId];
+
+
+ }
+
+
+ // 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,
+ _WINDOWS = "windows",
+ _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,
+
+ 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
+ };
+
+
+
+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);
+
+
+ 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);
+
+
+ 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);
+
+
+ }
+
+
+ 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);
+
+
+ // 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;
+
+
+
+ if (sSrcElementTagName) {
+
+ switch (sSrcElementTagName) {
+
+ case _DIV_UPPERCASE:
+
+ aListElements = this._aListElements;
+ nListElements = aListElements.length;
+
+ if (nListElements > 0) {
+
+
+ i = nListElements - 1;
+
+ do {
+
+ oNode = aListElements[i].firstChild;
+
+ if (oNode) {
+
+
+ do {
+
+ if (oNode && oNode.tagName &&
+ oNode.tagName.toUpperCase() == _LI) {
+
+
+ this.addItem(new this.ITEM_TYPE(oNode,
+ { parent: this }), i);
+
+ }
+
+ }
+ while ((oNode = oNode.nextSibling));
+
+ }
+
+ }
+ while (i--);
+
+ }
+
+ break;
+
+ case _SELECT:
+
+
+ oNode = oSrcElement.firstChild;
+
+ do {
+
+ if (oNode && oNode.tagName) {
+
+ switch (oNode.tagName.toUpperCase()) {
+
+ case _OPTGROUP:
+ case _OPTION:
+
+
+ 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);
+
+
+ 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);
+
+ }
+
+
+
+ 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 () {
+
+ /*
+ There is an inconsistency between Firefox for Mac OS X and Firefox Windows
+ regarding the triggering of the display of the browser's context menu and the
+ subsequent firing of the "click" event. In Firefox for Windows, 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. 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 have an internal "click" event handler they
+ use to hide themselves when clicked. As a result, in Firefox for Windows a
+ Menu will hide when the user right clicks on a MenuItem to raise the browser's
+ default context menu, because its internal "click" event handler ends up
+ getting called. The following line fixes this bug.
+ */
+
+ if (!((UA.gecko && this.platform == _WINDOWS) && oEvent.button > 0)) {
+
+ 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;
+
+
+ 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 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
+* @description "mouseout" event handler for the menu's "header" and "footer"
+* elements. Used to stop scrolling 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.
+*/
+_onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
+
+ var oBodyScrollTimer = this._bodyScrollTimer;
+
+ if (oBodyScrollTimer) {
+
+ oBodyScrollTimer.cancel();
+
+ }
+
+ this._cancelHideDelay();
+
+},
+
+
+
+// Private methods
+
+
+/**
+* @method _onInit
+* @description "init" event handler for the 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.
+*/
+_onInit: function (p_sType, p_aArgs) {
+
+ this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
+
+ var bRootMenu = !this.parent,
+ bLazyLoad = this.lazyLoad;
+
+
+ /*
+ Automatically initialize a menu's subtree if:
+
+ 1) This is the root menu and lazyload is off
+
+ 2) This is the root menu, lazyload is on, but the menu is
+ already visible
+
+ 3) This menu is a submenu and lazyload is off
+ */
+
+
+
+ if (((bRootMenu && !bLazyLoad) ||
+ (bRootMenu && (this.cfg.getProperty(_VISIBLE) ||
+ this.cfg.getProperty(_POSITION) == _STATIC)) ||
+ (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
+
+ if (this.srcElement) {
+
+ this._initSubTree();
+
+ }
+
+
+ if (this.itemData) {
+
+ this.addItems(this.itemData);
+
+ }
+
+ }
+ else if (bLazyLoad) {
+
+ this.cfg.fireQueue();
+
+ }
+
+},
+
+
+/**
+* @method _onBeforeRender
+* @description "beforerender" event handler for the menu. Appends all of the
+* <code><ul></code>, <code><li></code> and their accompanying
+* title elements to the body element of the 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.
+*/
+_onBeforeRender: function (p_sType, p_aArgs) {
+
+ var oEl = this.element,
+ nListElements = this._aListElements.length,
+ bFirstList = true,
+ i = 0,
+ oUL,
+ oGroupTitle;
+
+ if (nListElements > 0) {
+
+ do {
+
+ oUL = this._aListElements[i];
+
+ if (oUL) {
+
+ if (bFirstList) {
+
+ Dom.addClass(oUL, _FIRST_OF_TYPE);
+ bFirstList = false;
+
+ }
+
+
+ if (!Dom.isAncestor(oEl, oUL)) {
+
+ this.appendToBody(oUL);
+
+ }
+
+
+ oGroupTitle = this._aGroupTitleElements[i];
+
+ if (oGroupTitle) {
+
+ if (!Dom.isAncestor(oEl, oGroupTitle)) {
+
+ oUL.parentNode.insertBefore(oGroupTitle, oUL);
+
+ }
+
+
+ Dom.addClass(oUL, _HAS_TITLE);
+
+ }
+
+ }
+
+ i++;
+
+ }
+ while (i < nListElements);
+
+ }
+
+},
+
+
+/**
+* @method _onRender
+* @description "render" event handler for the 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.
+*/
+_onRender: function (p_sType, p_aArgs) {
+
+ if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ if (!this.cfg.getProperty(_VISIBLE)) {
+
+ this.positionOffScreen();
+
+ }
+
+ }
+
+},
+
+
+
+
+
+/**
+* @method _onBeforeShow
+* @description "beforeshow" event handler for the 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.
+*/
+_onBeforeShow: function (p_sType, p_aArgs) {
+
+ var nOptions,
+ n,
+ oSrcElement,
+ oContainer = this.cfg.getProperty(_CONTAINER);
+
+
+ if (this.lazyLoad && this.getItemGroups().length === 0) {
+
+ if (this.srcElement) {
+
+ this._initSubTree();
+
+ }
+
+
+ if (this.itemData) {
+
+ if (this.parent && this.parent.parent &&
+ this.parent.parent.srcElement &&
+ this.parent.parent.srcElement.tagName.toUpperCase() ==
+ _SELECT) {
+
+ nOptions = this.itemData.length;
+
+ for(n=0; n<nOptions; n++) {
+
+ if (this.itemData[n].tagName) {
+
+ this.addItem((new this.ITEM_TYPE(this.itemData[n])));
+
+ }
+
+ }
+
+ }
+ else {
+
+ this.addItems(this.itemData);
+
+ }
+
+ }
+
+
+ oSrcElement = this.srcElement;
+
+ if (oSrcElement) {
+
+ if (oSrcElement.tagName.toUpperCase() == _SELECT) {
+
+ if (Dom.inDocument(oSrcElement)) {
+
+ this.render(oSrcElement.parentNode);
+
+ }
+ else {
+
+ this.render(oContainer);
+
+ }
+
+ }
+ else {
+
+ this.render();
+
+ }
+
+ }
+ else {
+
+ if (this.parent) {
+
+ this.render(this.parent.element);
+
+ }
+ else {
+
+ this.render(oContainer);
+
+ }
+
+ }
+
+ }
+
+
+
+ var oParent = this.parent,
+ aAlignment;
+
+
+ if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ this.cfg.refireEvent(_XY);
+
+ }
+
+
+ if (oParent) {
+
+ aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
+
+ this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
+ this.align();
+
+ }
+
+},
+
+
+getConstrainedY: function (y) {
+
+ var oMenu = this,
+
+ aContext = oMenu.cfg.getProperty(_CONTEXT),
+ nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
+
+ nMaxHeight,
+
+ oOverlapPositions = {
+
+ "trbr": true,
+ "tlbl": true,
+ "bltl": true,
+ "brtr": true
+
+ },
+
+ bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
+
+ oMenuEl = oMenu.element,
+ nMenuOffsetHeight = oMenuEl.offsetHeight,
+
+ nViewportOffset = Overlay.VIEWPORT_OFFSET,
+ viewPortHeight = Dom.getViewportHeight(),
+ scrollY = Dom.getDocumentScrollTop(),
+
+ bCanConstrain =
+ (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
+
+ nAvailableHeight,
+
+ oContextEl,
+ nContextElY,
+ nContextElHeight,
+
+ bFlipped = false,
+
+ nTopRegionHeight,
+ nBottomRegionHeight,
+
+ topConstraint = scrollY + nViewportOffset,
+ bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
+
+ yNew = y;
+
+
+ var flipVertical = function () {
+
+ var nNewY;
+
+ // The Menu is below the context element, flip it above
+ if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
+ nNewY = (nContextElY - nMenuOffsetHeight);
+ }
+ else { // The Menu is above the context element, flip it below
+ nNewY = (nContextElY + nContextElHeight);
+ }
+
+ oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
+
+ return nNewY;
+
+ };
+
+
+ /*
+ Uses the context element's position to calculate the availble height
+ above and below it to display its corresponding Menu.
+ */
+
+ var getDisplayRegionHeight = function () {
+
+ // The Menu is below the context element
+ if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
+ return (nBottomRegionHeight - nViewportOffset);
+ }
+ else { // The Menu is above the context element
+ return (nTopRegionHeight - nViewportOffset);
+ }
+
+ };
+
+
+ /*
+ Sets the Menu's "y" configuration property to the correct value based on its
+ current orientation.
+ */
+
+ var alignY = function () {
+
+ var nNewY;
+
+ if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
+ nNewY = (nContextElY + nContextElHeight);
+ }
+ else {
+ nNewY = (nContextElY - oMenuEl.offsetHeight);
+ }
+
+ oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
+
+ };
+
+
+ // Resets the maxheight of the Menu to the value set by the user
+
+ var resetMaxHeight = function () {
+
+ oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
+
+ oMenu.hideEvent.unsubscribe(resetMaxHeight);
+
+ };
+
+
+ /*
+ Trys to place the Menu in the best possible position (either above or
+ below its corresponding context element).
+ */
+
+ var setVerticalPosition = function () {
+
+ var nDisplayRegionHeight = getDisplayRegionHeight(),
+ bMenuHasItems = (oMenu.getItems().length > 0),
+ nMenuMinScrollHeight,
+ fnReturnVal;
+
+
+ if (nMenuOffsetHeight > nDisplayRegionHeight) {
+
+ nMenuMinScrollHeight =
+ bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
+
+
+ if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
+ nMaxHeight = nDisplayRegionHeight;
+ }
+ else {
+ nMaxHeight = nInitialMaxHeight;
+ }
+
+
+ oMenu._setScrollHeight(nMaxHeight);
+ oMenu.hideEvent.subscribe(resetMaxHeight);
+
+
+ // Re-align the Menu since its height has just changed
+ // as a result of the setting of the maxheight property.
+
+ alignY();
+
+
+ if (nDisplayRegionHeight < nMenuMinScrollHeight) {
+
+ if (bFlipped) {
+
+ /*
+ All possible positions and values for the "maxheight"
+ configuration property have been tried, but none were
+ successful, so fall back to the original size and position.
+ */
+
+ flipVertical();
+
+ }
+ else {
+
+ flipVertical();
+
+ bFlipped = true;
+
+ fnReturnVal = setVerticalPosition();
+
+ }
+
+ }
+
+ }
+ else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
+
+ oMenu._setScrollHeight(nInitialMaxHeight);
+ oMenu.hideEvent.subscribe(resetMaxHeight);
+
+ // Re-align the Menu since its height has just changed
+ // as a result of the setting of the maxheight property.
+
+ alignY();
+
+ }
+
+ return fnReturnVal;
+
+ };
+
+
+ // Determine if the current value for the Menu's "y" configuration property will
+ // result in the Menu being positioned outside the boundaries of the viewport
+
+ if (y < topConstraint || y > bottomConstraint) {
+
+ // The current value for the Menu's "y" configuration property WILL
+ // result in the Menu being positioned outside the boundaries of the viewport
+
+ if (bCanConstrain) {
+
+ if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
+
+ // SOLUTION #1:
+ // If the "preventcontextoverlap" configuration property is set to "true",
+ // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
+ // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
+
+ oContextEl = aContext[0];
+ nContextElHeight = oContextEl.offsetHeight;
+ nContextElY = (Dom.getY(oContextEl) - scrollY);
+
+ nTopRegionHeight = nContextElY;
+ nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
+
+ setVerticalPosition();
+
+ yNew = oMenu.cfg.getProperty(_Y);
+
+ }
+ else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
+ nMenuOffsetHeight >= viewPortHeight) {
+
+ // SOLUTION #2:
+ // If the Menu exceeds the height of the viewport, introduce scroll bars
+ // to keep the Menu inside the boundaries of the viewport
+
+ nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
+
+ if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
+
+ oMenu._setScrollHeight(nAvailableHeight);
+ oMenu.hideEvent.subscribe(resetMaxHeight);
+
+ alignY();
+
+ yNew = oMenu.cfg.getProperty(_Y);
+
+ }
+
+ }
+ else {
+
+ // SOLUTION #3:
+
+ if (y < topConstraint) {
+ yNew = topConstraint;
+ } else if (y > bottomConstraint) {
+ yNew = bottomConstraint;
+ }
+
+ }
+
+ }
+ else {
+ // The "y" configuration property cannot be set to a value that will keep
+ // entire Menu inside the boundary of the viewport. Therefore, set
+ // the "y" configuration property to scrollY to keep as much of the
+ // Menu inside the viewport as possible.
+ yNew = nViewportOffset + scrollY;
+ }
+
+ }
+
+ return yNew;
+
+},
+
+
+/**
+* @method _onHide
+* @description "hide" event handler for the 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.
+*/
+_onHide: function (p_sType, p_aArgs) {
+
+ if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
+
+ this.positionOffScreen();
+
+ }
+
+},
+
+
+/**
+* @method _onShow
+* @description "show" event handler for the 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.
+*/
+_onShow: function (p_sType, p_aArgs) {
+
+ var oParent = this.parent,
+ oParentMenu,
+ oElement,
+ nOffsetWidth,
+ sWidth;
+
+
+ function disableAutoSubmenuDisplay(p_oEvent) {
+
+ var oTarget;
+
+ if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
+
+ /*
+ Set the "autosubmenudisplay" to "false" if the user
+ clicks outside the menu bar.
+ */
+
+ oTarget = Event.getTarget(p_oEvent);
+
+ if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
+
+ oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
+
+ Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
+ Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
+
+ }
+
+ }
+
+ }
+
+
+ function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
+
+ this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
+ this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
+
+ }
+
+
+ if (oParent) {
+
+ oParentMenu = oParent.parent;
+
+
+ if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
+ (oParentMenu instanceof YAHOO.widget.MenuBar ||
+ oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
+
+ oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
+
+ Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
+ Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
+
+ }
+
+
+ // The following fixes an issue with the selected state of a MenuItem
+ // not rendering correctly when a submenu is aligned to the left of
+ // its parent Menu instance.
+
+ if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
+ (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
+
+ oElement = this.element;
+ nOffsetWidth = oElement.offsetWidth;
+
+ /*
+ Measuring the difference of the offsetWidth before and after
+ setting the "width" style attribute allows us to compute the
+ about of padding and borders applied to the element, which in
+ turn allows us to set the "width" property correctly.
+ */
+
+ oElement.style.width = nOffsetWidth + _PX;
+
+ sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
+
+ this.cfg.setProperty(_WIDTH, sWidth);
+
+ this.hideEvent.subscribe(onSubmenuHide, sWidth);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onBeforeHide
+* @description "beforehide" event handler for the 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.
+*/
+_onBeforeHide: function (p_sType, p_aArgs) {
+
+ var oActiveItem = this.activeItem,
+ oRoot = this.getRoot(),
+ oConfig,
+ oSubmenu;
+
+
+ if (oActiveItem) {
+
+ oConfig = oActiveItem.cfg;
+
+ oConfig.setProperty(_SELECTED, false);
+
+ oSubmenu = oConfig.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.hide();
+
+ }
+
+ }
+
+
+ /*
+ Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
+ For this reason, it is necessary to maintain the focused state in a private property
+ so that the _onMouseOver event handler is able to determined whether or not to set focus
+ to MenuItems as the user is moving the mouse.
+ */
+
+ if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
+
+ oRoot._hasFocus = this.hasFocus();
+
+ }
+
+
+ if (oRoot == this) {
+
+ oRoot.blur();
+
+ }
+
+},
+
+
+/**
+* @method _onParentMenuConfigChange
+* @description "configchange" event handler for a submenu.
+* @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_oSubmenu Object representing the submenu that
+* subscribed to the event.
+*/
+_onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
+
+ var sPropertyName = p_aArgs[0][0],
+ oPropertyValue = p_aArgs[0][1];
+
+ switch(sPropertyName) {
+
+ case _IFRAME:
+ case _CONSTRAIN_TO_VIEWPORT:
+ case _HIDE_DELAY:
+ case _SHOW_DELAY:
+ case _SUBMENU_HIDE_DELAY:
+ case _CLICK_TO_HIDE:
+ case _EFFECT:
+ case _CLASSNAME:
+ case _SCROLL_INCREMENT:
+ case _MAX_HEIGHT:
+ case _MIN_SCROLL_HEIGHT:
+ case _MONITOR_RESIZE:
+ case _SHADOW:
+ case _PREVENT_CONTEXT_OVERLAP:
+
+ p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
+
+ break;
+
+ case _SUBMENU_ALIGNMENT:
+
+ if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
+
+ p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
+
+ }
+
+ break;
+
+ }
+
+},
+
+
+/**
+* @method _onParentMenuRender
+* @description "render" event handler for a submenu. Renders a
+* submenu in response to the firing of its parent's "render" event.
+* @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_oSubmenu Object representing the submenu that
+* subscribed to the event.
+*/
+_onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
+
+ var oParentMenu = p_oSubmenu.parent.parent,
+ oParentCfg = oParentMenu.cfg,
+
+ oConfig = {
+
+ constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
+
+ xy: [0,0],
+
+ clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
+
+ effect: oParentCfg.getProperty(_EFFECT),
+
+ showdelay: oParentCfg.getProperty(_SHOW_DELAY),
+
+ hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
+
+ submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
+
+ classname: oParentCfg.getProperty(_CLASSNAME),
+
+ scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
+
+ maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
+
+ minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
+
+ iframe: oParentCfg.getProperty(_IFRAME),
+
+ shadow: oParentCfg.getProperty(_SHADOW),
+
+ preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
+
+ monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE)
+
+ },
+
+ oLI;
+
+
+
+ if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
+
+ oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
+
+ }
+
+
+ p_oSubmenu.cfg.applyConfig(oConfig);
+
+
+ if (!this.lazyLoad) {
+
+ oLI = this.parent.element;
+
+ if (this.element.parentNode == oLI) {
+
+ this.render();
+
+ }
+ else {
+
+ this.render(oLI);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _onMenuItemDestroy
+* @description "destroy" event handler for the menu's items.
+* @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.MenuItem} p_oItem Object representing the menu item
+* that fired the event.
+*/
+_onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
+
+ this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
+
+},
+
+
+/**
+* @method _onMenuItemConfigChange
+* @description "configchange" event handler for the menu's items.
+* @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.MenuItem} p_oItem Object representing the menu item
+* that fired the event.
+*/
+_onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
+
+ var sPropertyName = p_aArgs[0][0],
+ oPropertyValue = p_aArgs[0][1],
+ oSubmenu;
+
+
+ switch(sPropertyName) {
+
+ case _SELECTED:
+
+ if (oPropertyValue === true) {
+
+ this.activeItem = p_oItem;
+
+ }
+
+ break;
+
+ case _SUBMENU:
+
+ oSubmenu = p_aArgs[0][1];
+
+ if (oSubmenu) {
+
+ this._configureSubmenu(p_oItem);
+
+ }
+
+ break;
+
+ }
+
+},
+
+
+
+// Public event handlers for configuration properties
+
+
+/**
+* @method configVisible
+* @description Event handler for when the "visible" configuration property
+* the menu changes.
+* @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 Object representing the menu that
+* fired the event.
+*/
+configVisible: function (p_sType, p_aArgs, p_oMenu) {
+
+ var bVisible,
+ sDisplay;
+
+ if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
+
+ }
+ else {
+
+ bVisible = p_aArgs[0];
+ sDisplay = Dom.getStyle(this.element, _DISPLAY);
+
+ Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
+
+ if (bVisible) {
+
+ if (sDisplay != _BLOCK) {
+ this.beforeShowEvent.fire();
+ Dom.setStyle(this.element, _DISPLAY, _BLOCK);
+ this.showEvent.fire();
+ }
+
+ }
+ else {
+
+ if (sDisplay == _BLOCK) {
+ this.beforeHideEvent.fire();
+ Dom.setStyle(this.element, _DISPLAY, _NONE);
+ this.hideEvent.fire();
+ }
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method configPosition
+* @description Event handler for when the "position" configuration property
+* of the menu changes.
+* @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 Object representing the menu that
+* fired the event.
+*/
+configPosition: function (p_sType, p_aArgs, p_oMenu) {
+
+ var oElement = this.element,
+ sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
+ oCfg = this.cfg,
+ nZIndex;
+
+
+ Dom.setStyle(oElement, _POSITION, sCSSPosition);
+
+
+ if (sCSSPosition == _STATIC) {
+
+ // Statically positioned menus are visible by default
+
+ Dom.setStyle(oElement, _DISPLAY, _BLOCK);
+
+ oCfg.setProperty(_VISIBLE, true);
+
+ }
+ else {
+
+ /*
+ Even though the "visible" property is queued to
+ "false" by default, we need to set the "visibility" property to
+ "hidden" since Overlay's "configVisible" implementation checks the
+ element's "visibility" style property before deciding whether
+ or not to show an Overlay instance.
+ */
+
+ Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
+
+ }
+
+
+ if (sCSSPosition == _ABSOLUTE) {
+
+ nZIndex = oCfg.getProperty(_ZINDEX);
+
+ if (!nZIndex || nZIndex === 0) {
+
+ oCfg.setProperty(_ZINDEX, 1);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method configIframe
+* @description Event handler for when the "iframe" configuration property of
+* the menu changes.
+* @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 Object representing the menu that
+* fired the event.
+*/
+configIframe: function (p_sType, p_aArgs, p_oMenu) {
+
+ if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
+
+ }
+
+},
+
+
+/**
+* @method configHideDelay
+* @description Event handler for when the "hidedelay" configuration property
+* of the menu changes.
+* @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 Object representing the menu that
+* fired the event.
+*/
+configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
+
+ var nHideDelay = p_aArgs[0];
+
+ this._useHideDelay = (nHideDelay > 0);
+
+},
+
+
+/**
+* @method configContainer
+* @description Event handler for when the "container" configuration property
+* of the menu changes.
+* @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 Object representing the menu that
+* fired the event.
+*/
+configContainer: function (p_sType, p_aArgs, p_oMenu) {
+
+ var oElement = p_aArgs[0];
+
+ if (Lang.isString(oElement)) {
+
+ this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
+
+ }
+
+},
+
+
+/**
+* @method _clearSetWidthFlag
+* @description Change event listener for the "width" configuration property. This listener is
+* added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
+* is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
+* is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
+* property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
+* scrolling functionality, it will maintain the Menu's new width rather than reseting it.
+* @private
+*/
+_clearSetWidthFlag: function () {
+
+ this._widthSetForScroll = false;
+
+ this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
+
+},
+
+
+/**
+* @method _setScrollHeight
+* @description
+* @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
+* @private
+*/
+_setScrollHeight: function (p_nScrollHeight) {
+
+ var nScrollHeight = p_nScrollHeight,
+ bRefireIFrameAndShadow = false,
+ bSetWidth = false,
+ oElement,
+ oBody,
+ oHeader,
+ oFooter,
+ fnMouseOver,
+ fnMouseOut,
+ nMinScrollHeight,
+ nHeight,
+ nOffsetWidth,
+ sWidth;
+
+
+ if (this.getItems().length > 0) {
+
+ oElement = this.element;
+ oBody = this.body;
+ oHeader = this.header;
+ oFooter = this.footer;
+ fnMouseOver = this._onScrollTargetMouseOver;
+ fnMouseOut = this._onScrollTargetMouseOut;
+ nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
+
+
+ if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
+
+ nScrollHeight = nMinScrollHeight;
+
+ }
+
+
+ Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
+ Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
+ oBody.scrollTop = 0;
+
+
+ // Need to set a width for the Menu to fix the following problems in
+ // Firefox 2 and IE:
+
+ // #1) Scrolled Menus will render at 1px wide in Firefox 2
+
+ // #2) There is a bug in gecko-based browsers where an element whose
+ // "position" property is set to "absolute" and "overflow" property is
+ // set to "hidden" will not render at the correct width when its
+ // offsetParent's "position" property is also set to "absolute." It is
+ // possible to work around this bug by specifying a value for the width
+ // property in addition to overflow.
+
+ // #3) In IE it is necessary to give the Menu a width before the
+ // scrollbars are rendered to prevent the Menu from rendering with a
+ // width that is 100% of the browser viewport.
+
+ bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
+
+ if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
+
+ nOffsetWidth = oElement.offsetWidth;
+
+ /*
+ Measuring the difference of the offsetWidth before and after
+ setting the "width" style attribute allows us to compute the
+ about of padding and borders applied to the element, which in
+ turn allows us to set the "width" property correctly.
+ */
+
+ oElement.style.width = nOffsetWidth + _PX;
+
+ sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
+
+
+ this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
+
+
+ this.cfg.setProperty(_WIDTH, sWidth);
+
+
+ /*
+ Set a flag (_widthSetForScroll) to maintain some history regarding how the
+ "width" configuration property was set. If the "width" configuration property
+ is set by something other than the "_setScrollHeight" method, it will be
+ necessary to maintain that new value and not clear the width if scrolling
+ is turned off.
+ */
+
+ this._widthSetForScroll = true;
+
+ this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
+
+ }
+
+
+ if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
+
+
+ this.setHeader(_NON_BREAKING_SPACE);
+ this.setFooter(_NON_BREAKING_SPACE);
+
+ oHeader = this.header;
+ oFooter = this.footer;
+
+ Dom.addClass(oHeader, _TOP_SCROLLBAR);
+ Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
+
+ oElement.insertBefore(oHeader, oBody);
+ oElement.appendChild(oFooter);
+
+ }
+
+
+ nHeight = nScrollHeight;
+
+
+ if (oHeader && oFooter) {
+ nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
+ }
+
+
+ if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
+
+
+ Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
+ Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
+
+ if (!this._hasScrollEventHandlers) {
+
+ Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
+ Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
+ Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
+ Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
+
+ this._hasScrollEventHandlers = true;
+
+ }
+
+ this._disableScrollHeader();
+ this._enableScrollFooter();
+
+ bRefireIFrameAndShadow = true;
+
+ }
+ else if (oHeader && oFooter) {
+
+
+
+ /*
+ Only clear the the "width" configuration property if it was set the
+ "_setScrollHeight" method and wasn't changed by some other means after it was set.
+ */
+
+ if (this._widthSetForScroll) {
+
+
+ this._widthSetForScroll = false;
+
+ this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
+
+ this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
+
+ }
+
+
+ this._enableScrollHeader();
+ this._enableScrollFooter();
+
+ if (this._hasScrollEventHandlers) {
+
+ Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
+ Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
+ Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
+ Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
+
+ this._hasScrollEventHandlers = false;
+
+ }
+
+ oElement.removeChild(oHeader);
+ oElement.removeChild(oFooter);
+
+ this.header = null;
+ this.footer = null;
+
+ bRefireIFrameAndShadow = true;
+
+ }
+
+
+ if (bRefireIFrameAndShadow) {
+
+ this.cfg.refireEvent(_IFRAME);
+ this.cfg.refireEvent(_SHADOW);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method _setMaxHeight
+* @description "renderEvent" handler used to defer the setting of the
+* "maxheight" configuration property until the menu is rendered in lazy
+* load scenarios.
+* @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.
+* @param {Number} p_nMaxHeight Number representing the value to set for the
+* "maxheight" configuration property.
+* @private
+*/
+_setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
+
+ this._setScrollHeight(p_nMaxHeight);
+ this.renderEvent.unsubscribe(this._setMaxHeight);
+
+},
+
+
+/**
+* @method configMaxHeight
+* @description Event handler for when the "maxheight" configuration property of
+* a Menu changes.
+* @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.
+* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
+* the event.
+*/
+configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
+
+ var nMaxHeight = p_aArgs[0];
+
+ if (this.lazyLoad && !this.body && nMaxHeight > 0) {
+
+ this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
+
+ }
+ else {
+
+ this._setScrollHeight(nMaxHeight);
+
+ }
+
+},
+
+
+/**
+* @method configClassName
+* @description Event handler for when the "classname" configuration property of
+* a menu changes.
+* @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.
+* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
+*/
+configClassName: function (p_sType, p_aArgs, p_oMenu) {
+
+ var sClassName = p_aArgs[0];
+
+ if (this._sClassName) {
+
+ Dom.removeClass(this.element, this._sClassName);
+
+ }
+
+ Dom.addClass(this.element, sClassName);
+ this._sClassName = sClassName;
+
+},
+
+
+/**
+* @method _onItemAdded
+* @description "itemadded" event handler for a Menu instance.
+* @private
+* @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.
+*/
+_onItemAdded: function (p_sType, p_aArgs) {
+
+ var oItem = p_aArgs[0];
+
+ if (oItem) {
+
+ oItem.cfg.setProperty(_DISABLED, true);
+
+ }
+
+},
+
+
+/**
+* @method configDisabled
+* @description Event handler for when the "disabled" configuration property of
+* a menu changes.
+* @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.
+* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
+*/
+configDisabled: function (p_sType, p_aArgs, p_oMenu) {
+
+ var bDisabled = p_aArgs[0],
+ aItems = this.getItems(),
+ nItems,
+ i;
+
+ if (Lang.isArray(aItems)) {
+
+ nItems = aItems.length;
+
+ if (nItems > 0) {
+
+ i = nItems - 1;
+
+ do {
+
+ aItems[i].cfg.setProperty(_DISABLED, bDisabled);
+
+ }
+ while (i--);
+
+ }
+
+
+ if (bDisabled) {
+
+ this.clearActiveItem(true);
+
+ Dom.addClass(this.element, _DISABLED);
+
+ this.itemAddedEvent.subscribe(this._onItemAdded);
+
+ }
+ else {
+
+ Dom.removeClass(this.element, _DISABLED);
+
+ this.itemAddedEvent.unsubscribe(this._onItemAdded);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method configShadow
+* @description Event handler for when the "shadow" configuration property of
+* a menu changes.
+* @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.
+* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
+*/
+configShadow: function (p_sType, p_aArgs, p_oMenu) {
+
+ var sizeShadow = function () {
+
+ var oElement = this.element,
+ oShadow = this._shadow;
+
+ if (oShadow && oElement) {
+
+ // Clear the previous width
+
+ if (oShadow.style.width && oShadow.style.height) {
+
+ oShadow.style.width = _EMPTY_STRING;
+ oShadow.style.height = _EMPTY_STRING;
+
+ }
+
+ oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
+ oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
+
+ }
+
+ };
+
+
+ var replaceShadow = function () {
+
+ this.element.appendChild(this._shadow);
+
+ };
+
+
+ var addShadowVisibleClass = function () {
+
+ Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
+
+ };
+
+
+ var removeShadowVisibleClass = function () {
+
+ Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
+
+ };
+
+
+ var createShadow = function () {
+
+ var oShadow = this._shadow,
+ oElement;
+
+ if (!oShadow) {
+
+ oElement = this.element;
+
+
+ if (!m_oShadowTemplate) {
+
+ m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
+ m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
+
+ }
+
+ oShadow = m_oShadowTemplate.cloneNode(false);
+
+ oElement.appendChild(oShadow);
+
+ this._shadow = oShadow;
+
+ this.beforeShowEvent.subscribe(addShadowVisibleClass);
+ this.beforeHideEvent.subscribe(removeShadowVisibleClass);
+
+
+ if (UA.ie) {
+
+ /*
+ Need to call sizeShadow & syncIframe via setTimeout for
+ IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
+ or the shadow and iframe shim will not be sized and
+ positioned properly.
+ */
+
+ Lang.later(0, this, function () {
+
+ sizeShadow.call(this);
+ this.syncIframe();
+
+ });
+
+
+ this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
+ this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
+ this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
+ this.changeContentEvent.subscribe(sizeShadow);
+
+ Module.textResizeEvent.subscribe(sizeShadow, this, true);
+
+ this.destroyEvent.subscribe(function () {
+
+ Module.textResizeEvent.unsubscribe(sizeShadow, this);
+
+ });
+
+ }
+
+ this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
+
+ }
+
+ };
+
+
+ var onBeforeShow = function () {
+
+ if (this._shadow) {
+
+ // If called because the "shadow" event was refired - just append again and resize
+
+ replaceShadow.call(this);
+
+ if (UA.ie) {
+ sizeShadow.call(this);
+ }
+
+ }
+ else {
+
+ createShadow.call(this);
+
+ }
+
+ this.beforeShowEvent.unsubscribe(onBeforeShow);
+
+ };
+
+
+ var bShadow = p_aArgs[0];
+
+
+ if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
+
+ if (this.cfg.getProperty(_VISIBLE)) {
+
+ if (this._shadow) {
+
+ // If the "shadow" event was refired - just append again and resize
+
+ replaceShadow.call(this);
+
+ if (UA.ie) {
+ sizeShadow.call(this);
+ }
+
+ }
+ else {
+ createShadow.call(this);
+ }
+
+ }
+ else {
+
+ this.beforeShowEvent.subscribe(onBeforeShow);
+
+ }
+
+ }
+
+},
+
+
+
+// Public methods
+
+
+/**
+* @method initEvents
+* @description Initializes the custom events for the menu.
+*/
+initEvents: function () {
+
+ Menu.superclass.initEvents.call(this);
+
+ // Create custom events
+
+ var i = EVENT_TYPES.length - 1,
+ aEventData,
+ oCustomEvent;
+
+
+ do {
+
+ aEventData = EVENT_TYPES[i];
+
+ oCustomEvent = this.createEvent(aEventData[1]);
+ oCustomEvent.signature = CustomEvent.LIST;
+
+ this[aEventData[0]] = oCustomEvent;
+
+ }
+ while (i--);
+
+},
+
+
+/**
+* @method positionOffScreen
+* @description Positions the menu outside of the boundaries of the browser's
+* viewport. Called automatically when a menu is hidden to ensure that
+* it doesn't force the browser to render uncessary scrollbars.
+*/
+positionOffScreen: function () {
+
+ var oIFrame = this.iframe,
+ oElement = this.element,
+ sPos = this.OFF_SCREEN_POSITION;
+
+ oElement.style.top = _EMPTY_STRING;
+ oElement.style.left = _EMPTY_STRING;
+
+ if (oIFrame) {
+
+ oIFrame.style.top = sPos;
+ oIFrame.style.left = sPos;
+
+ }
+
+},
+
+
+/**
+* @method getRoot
+* @description Finds the menu's root menu.
+*/
+getRoot: function () {
+
+ var oItem = this.parent,
+ oParentMenu,
+ returnVal;
+
+ if (oItem) {
+
+ oParentMenu = oItem.parent;
+
+ returnVal = oParentMenu ? oParentMenu.getRoot() : this;
+
+ }
+ else {
+
+ returnVal = this;
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method toString
+* @description Returns a string representing the menu.
+* @return {String}
+*/
+toString: function () {
+
+ var sReturnVal = _MENU,
+ sId = this.id;
+
+ if (sId) {
+
+ sReturnVal += (_SPACE + sId);
+
+ }
+
+ return sReturnVal;
+
+},
+
+
+/**
+* @method setItemGroupTitle
+* @description Sets the title of a group of menu items.
+* @param {String} p_sGroupTitle String specifying the title of the group.
+* @param {Number} p_nGroupIndex Optional. Number specifying the group to which
+* the title belongs.
+*/
+setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
+
+ var nGroupIndex,
+ oTitle,
+ i,
+ nFirstIndex;
+
+ if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
+
+ nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
+ oTitle = this._aGroupTitleElements[nGroupIndex];
+
+
+ if (oTitle) {
+
+ oTitle.innerHTML = p_sGroupTitle;
+
+ }
+ else {
+
+ oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
+
+ oTitle.innerHTML = p_sGroupTitle;
+
+ this._aGroupTitleElements[nGroupIndex] = oTitle;
+
+ }
+
+
+ i = this._aGroupTitleElements.length - 1;
+
+ do {
+
+ if (this._aGroupTitleElements[i]) {
+
+ Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
+
+ nFirstIndex = i;
+
+ }
+
+ }
+ while (i--);
+
+
+ if (nFirstIndex !== null) {
+
+ Dom.addClass(this._aGroupTitleElements[nFirstIndex],
+ _FIRST_OF_TYPE);
+
+ }
+
+ this.changeContentEvent.fire();
+
+ }
+
+},
+
+
+
+/**
+* @method addItem
+* @description Appends an item to the menu.
+* @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_nGroupIndex Optional. Number indicating the group to
+* which the item belongs.
+* @return {YAHOO.widget.MenuItem}
+*/
+addItem: function (p_oItem, p_nGroupIndex) {
+
+ return this._addItemToGroup(p_nGroupIndex, p_oItem);
+
+},
+
+
+/**
+* @method addItems
+* @description Adds an array of items to the menu.
+* @param {Array} p_aItems Array of items to be added to the menu. The array
+* can contain strings specifying the text for each item to be created, object
+* literals specifying each of the menu item configuration properties,
+* or MenuItem instances.
+* @param {Number} p_nGroupIndex Optional. Number specifying the group to
+* which the items belongs.
+* @return {Array}
+*/
+addItems: function (p_aItems, p_nGroupIndex) {
+
+ var nItems,
+ aItems,
+ oItem,
+ i,
+ returnVal;
+
+
+ if (Lang.isArray(p_aItems)) {
+
+ nItems = p_aItems.length;
+ aItems = [];
+
+ for(i=0; i<nItems; i++) {
+
+ oItem = p_aItems[i];
+
+ if (oItem) {
+
+ if (Lang.isArray(oItem)) {
+
+ aItems[aItems.length] = this.addItems(oItem, i);
+
+ }
+ else {
+
+ aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
+
+ }
+
+ }
+
+ }
+
+
+ if (aItems.length) {
+
+ returnVal = aItems;
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method insertItem
+* @description Inserts an item into the menu at the specified index.
+* @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 Number indicating the ordinal position at which
+* the item should be added.
+* @param {Number} p_nGroupIndex Optional. Number indicating the group to which
+* the item belongs.
+* @return {YAHOO.widget.MenuItem}
+*/
+insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
+
+ return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
+
+},
+
+
+/**
+* @method removeItem
+* @description Removes the specified item from the menu.
+* @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
+* instance to be removed from the menu.
+* @param {Number} p_oObject Number specifying the index of the item
+* to be removed.
+* @param {Number} p_nGroupIndex Optional. Number specifying the group to
+* which the item belongs.
+* @return {YAHOO.widget.MenuItem}
+*/
+removeItem: function (p_oObject, p_nGroupIndex) {
+
+ var oItem,
+ returnVal;
+
+ if (!Lang.isUndefined(p_oObject)) {
+
+ if (p_oObject instanceof YAHOO.widget.MenuItem) {
+
+ oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
+
+ }
+ else if (Lang.isNumber(p_oObject)) {
+
+ oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
+
+ }
+
+ if (oItem) {
+
+ oItem.destroy();
+
+
+ returnVal = oItem;
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method getItems
+* @description Returns an array of all of the items in the menu.
+* @return {Array}
+*/
+getItems: function () {
+
+ var aGroups = this._aItemGroups,
+ nGroups,
+ returnVal,
+ aItems = [];
+
+
+ if (Lang.isArray(aGroups)) {
+
+ nGroups = aGroups.length;
+
+ returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method getItemGroups
+* @description Multi-dimensional Array representing the menu items as they
+* are grouped in the menu.
+* @return {Array}
+*/
+getItemGroups: function () {
+
+ return this._aItemGroups;
+
+},
+
+
+/**
+* @method getItem
+* @description Returns the item at the specified index.
+* @param {Number} p_nItemIndex Number indicating the ordinal position of the
+* item to be retrieved.
+* @param {Number} p_nGroupIndex Optional. Number indicating the group to which
+* the item belongs.
+* @return {YAHOO.widget.MenuItem}
+*/
+getItem: function (p_nItemIndex, p_nGroupIndex) {
+
+ var aGroup,
+ returnVal;
+
+ if (Lang.isNumber(p_nItemIndex)) {
+
+ aGroup = this._getItemGroup(p_nGroupIndex);
+
+ if (aGroup) {
+
+ returnVal = aGroup[p_nItemIndex];
+
+ }
+
+ }
+
+ return returnVal;
+
+},
+
+
+/**
+* @method getSubmenus
+* @description Returns an array of all of the submenus that are immediate
+* children of the menu.
+* @return {Array}
+*/
+getSubmenus: function () {
+
+ var aItems = this.getItems(),
+ nItems = aItems.length,
+ aSubmenus,
+ oSubmenu,
+ oItem,
+ i;
+
+
+ if (nItems > 0) {
+
+ aSubmenus = [];
+
+ for(i=0; i<nItems; i++) {
+
+ oItem = aItems[i];
+
+ if (oItem) {
+
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ aSubmenus[aSubmenus.length] = oSubmenu;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return aSubmenus;
+
+},
+
+
+/**
+* @method clearContent
+* @description Removes all of the content from the menu, including the menu
+* items, group titles, header and footer.
+*/
+clearContent: function () {
+
+ var aItems = this.getItems(),
+ nItems = aItems.length,
+ oElement = this.element,
+ oBody = this.body,
+ oHeader = this.header,
+ oFooter = this.footer,
+ oItem,
+ oSubmenu,
+ i;
+
+
+ if (nItems > 0) {
+
+ i = nItems - 1;
+
+ do {
+
+ oItem = aItems[i];
+
+ if (oItem) {
+
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ this.cfg.configChangedEvent.unsubscribe(
+ this._onParentMenuConfigChange, oSubmenu);
+
+ this.renderEvent.unsubscribe(this._onParentMenuRender,
+ oSubmenu);
+
+ }
+
+ this.removeItem(oItem, oItem.groupIndex);
+
+ }
+
+ }
+ while (i--);
+
+ }
+
+
+ if (oHeader) {
+
+ Event.purgeElement(oHeader);
+ oElement.removeChild(oHeader);
+
+ }
+
+
+ if (oFooter) {
+
+ Event.purgeElement(oFooter);
+ oElement.removeChild(oFooter);
+ }
+
+
+ if (oBody) {
+
+ Event.purgeElement(oBody);
+
+ oBody.innerHTML = _EMPTY_STRING;
+
+ }
+
+ this.activeItem = null;
+
+ this._aItemGroups = [];
+ this._aListElements = [];
+ this._aGroupTitleElements = [];
+
+ this.cfg.setProperty(_WIDTH, null);
+
+},
+
+
+/**
+* @method destroy
+* @description Removes the menu's <code><div></code> element
+* (and accompanying child nodes) from the document.
+*/
+destroy: function () {
+
+ // Remove all items
+
+ this.clearContent();
+
+ this._aItemGroups = null;
+ this._aListElements = null;
+ this._aGroupTitleElements = null;
+
+
+ // Continue with the superclass implementation of this method
+
+ Menu.superclass.destroy.call(this);
+
+
+},
+
+
+/**
+* @method setInitialFocus
+* @description Sets focus to the menu's first enabled item.
+*/
+setInitialFocus: function () {
+
+ var oItem = this._getFirstEnabledItem();
+
+ if (oItem) {
+
+ oItem.focus();
+
+ }
+
+},
+
+
+/**
+* @method setInitialSelection
+* @description Sets the "selected" configuration property of the menu's first
+* enabled item to "true."
+*/
+setInitialSelection: function () {
+
+ var oItem = this._getFirstEnabledItem();
+
+ if (oItem) {
+
+ oItem.cfg.setProperty(_SELECTED, true);
+ }
+
+},
+
+
+/**
+* @method clearActiveItem
+* @description Sets the "selected" configuration property of the menu's active
+* item to "false" and hides the item's submenu.
+* @param {Boolean} p_bBlur Boolean indicating if the menu's active item
+* should be blurred.
+*/
+clearActiveItem: function (p_bBlur) {
+
+ if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
+
+ this._cancelShowDelay();
+
+ }
+
+
+ var oActiveItem = this.activeItem,
+ oConfig,
+ oSubmenu;
+
+ if (oActiveItem) {
+
+ oConfig = oActiveItem.cfg;
+
+ if (p_bBlur) {
+
+ oActiveItem.blur();
+
+ this.getRoot()._hasFocus = true;
+
+ }
+
+ oConfig.setProperty(_SELECTED, false);
+
+ oSubmenu = oConfig.getProperty(_SUBMENU);
+
+
+ if (oSubmenu) {
+
+ oSubmenu.hide();
+
+ }
+
+ this.activeItem = null;
+
+ }
+
+},
+
+
+/**
+* @method focus
+* @description Causes the menu to receive focus and fires the "focus" event.
+*/
+focus: function () {
+
+ if (!this.hasFocus()) {
+
+ this.setInitialFocus();
+
+ }
+
+},
+
+
+/**
+* @method blur
+* @description Causes the menu to lose focus and fires the "blur" event.
+*/
+blur: function () {
+
+ var oItem;
+
+ if (this.hasFocus()) {
+
+ oItem = MenuManager.getFocusedMenuItem();
+
+ if (oItem) {
+
+ oItem.blur();
+
+ }
+
+ }
+
+},
+
+
+/**
+* @method hasFocus
+* @description Returns a boolean indicating whether or not the menu has focus.
+* @return {Boolean}
+*/
+hasFocus: function () {
+
+ return (MenuManager.getFocusedMenu() == this.getRoot());
+
+},
+
+
+/**
+* Adds the specified CustomEvent subscriber to the menu and each of
+* its submenus.
+* @method subscribe
+* @param p_type {string} the type, or name of the event
+* @param p_fn {function} the function to exectute when the event fires
+* @param p_obj {Object} An object to be passed along when the event
+* fires
+* @param p_override {boolean} If true, the obj passed in becomes the
+* execution scope of the listener
+*/
+subscribe: function () {
+
+ function onItemAdded(p_sType, p_aArgs, p_oObject) {
+
+ var oItem = p_aArgs[0],
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.subscribe.apply(oSubmenu, p_oObject);
+
+ }
+
+ }
+
+
+ function onSubmenuAdded(p_sType, p_aArgs, p_oObject) {
+
+ var oSubmenu = this.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.subscribe.apply(oSubmenu, p_oObject);
+
+ }
+
+ }
+
+
+ Menu.superclass.subscribe.apply(this, arguments);
+ Menu.superclass.subscribe.call(this, _ITEM_ADDED, onItemAdded, arguments);
+
+
+ var aItems = this.getItems(),
+ nItems,
+ oItem,
+ oSubmenu,
+ i;
+
+
+ if (aItems) {
+
+ nItems = aItems.length;
+
+ if (nItems > 0) {
+
+ i = nItems - 1;
+
+ do {
+
+ oItem = aItems[i];
+
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.subscribe.apply(oSubmenu, arguments);
+
+ }
+ else {
+
+ oItem.cfg.subscribeToConfigEvent(_SUBMENU, onSubmenuAdded, arguments);
+
+ }
+
+ }
+ while (i--);
+
+ }
+
+ }
+
+},
+
+
+/**
+* @description Initializes the class's configurable properties which can be
+* changed using the menu's Config object ("cfg").
+* @method initDefaultConfig
+*/
+initDefaultConfig: function () {
+
+ Menu.superclass.initDefaultConfig.call(this);
+
+ var oConfig = this.cfg;
+
+
+ // Module documentation overrides
+
+ /**
+ * @config effect
+ * @description Object or array of objects representing the ContainerEffect
+ * classes that are active for animating the container. When set this
+ * property is automatically applied to all submenus.
+ * @type Object
+ * @default null
+ */
+
+ // Overlay documentation overrides
+
+
+ /**
+ * @config x
+ * @description Number representing the absolute x-coordinate position of
+ * the Menu. This property is only applied when the "position"
+ * configuration property is set to dynamic.
+ * @type Number
+ * @default null
+ */
+
+
+ /**
+ * @config y
+ * @description Number representing the absolute y-coordinate position of
+ * the Menu. This property is only applied when the "position"
+ * configuration property is set to dynamic.
+ * @type Number
+ * @default null
+ */
+
+
+ /**
+ * @description Array of the absolute x and y positions of the Menu. This
+ * property is only applied when the "position" configuration property is
+ * set to dynamic.
+ * @config xy
+ * @type Number[]
+ * @default null
+ */
+
+
+ /**
+ * @config context
+ * @description Array of context arguments for context-sensitive positioning.
+ * The format is: [id or element, element corner, context corner].
+ * For example, setting this property to ["img1", "tl", "bl"] would
+ * align the Mnu's top left corner to the context element's
+ * bottom left corner. This property is only applied when the "position"
+ * configuration property is set to dynamic.
+ * @type Array
+ * @default null
+ */
+
+
+ /**
+ * @config fixedcenter
+ * @description Boolean indicating if the Menu should be anchored to the
+ * center of the viewport. This property is only applied when the
+ * "position" configuration property is set to dynamic.
+ * @type Boolean
+ * @default false
+ */
+
+
+ /**
+ * @config iframe
+ * @description Boolean indicating whether or not the Menu should
+ * have an IFRAME shim; used to prevent SELECT elements from
+ * poking through an Overlay instance in IE6. When set to "true",
+ * the iframe shim is created when the Menu instance is intially
+ * made visible. This property is only applied when the "position"
+ * configuration property is set to dynamic and is automatically applied
+ * to all submenus.
+ * @type Boolean
+ * @default true for IE6 and below, false for all other browsers.
+ */
+
+
+ // Add configuration attributes
+
+ /*
+ Change the default value for the "visible" configuration
+ property to "false" by re-adding the property.
+ */
+
+ /**
+ * @config visible
+ * @description Boolean indicating whether or not the menu is visible. If
+ * the menu's "position" configuration property is set to "dynamic" (the
+ * default), this property toggles the menu's <code><div></code>
+ * element's "visibility" style property between "visible" (true) or
+ * "hidden" (false). If the menu's "position" configuration property is
+ * set to "static" this property toggles the menu's
+ * <code><div></code> element's "display" style property
+ * between "block" (true) or "none" (false).
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ VISIBLE_CONFIG.key,
+ {
+ handler: this.configVisible,
+ value: VISIBLE_CONFIG.value,
+ validator: VISIBLE_CONFIG.validator
+ }
+ );
+
+
+ /*
+ Change the default value for the "constraintoviewport" configuration
+ property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
+ */
+
+ /**
+ * @config constraintoviewport
+ * @description Boolean indicating if the menu will try to remain inside
+ * the boundaries of the size of viewport. This property is only applied
+ * when the "position" configuration property is set to dynamic and is
+ * automatically applied to all submenus.
+ * @default true
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ CONSTRAIN_TO_VIEWPORT_CONFIG.key,
+ {
+ handler: this.configConstrainToViewport,
+ value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
+ validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
+ supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
+ }
+ );
+
+
+ /*
+ Change the default value for the "preventcontextoverlap" configuration
+ property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
+ */
+
+ /**
+ * @config preventcontextoverlap
+ * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
+ * when the "constraintoviewport" configuration property is set to "true".
+ * @type Boolean
+ * @default true
+ */
+ oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
+
+ value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
+ validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
+ supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
+
+ });
+
+
+ /**
+ * @config position
+ * @description String indicating how a menu should be positioned on the
+ * screen. Possible values are "static" and "dynamic." Static menus are
+ * visible by default and reside in the normal flow of the document
+ * (CSS position: static). Dynamic menus are hidden by default, reside
+ * out of the normal flow of the document (CSS position: absolute), and
+ * can overlay other elements on the screen.
+ * @default dynamic
+ * @type String
+ */
+ oConfig.addProperty(
+ POSITION_CONFIG.key,
+ {
+ handler: this.configPosition,
+ value: POSITION_CONFIG.value,
+ validator: POSITION_CONFIG.validator,
+ supercedes: POSITION_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config submenualignment
+ * @description Array defining how submenus should be aligned to their
+ * parent menu item. The format is: [itemCorner, submenuCorner]. By default
+ * a submenu's top left corner is aligned to its parent menu item's top
+ * right corner.
+ * @default ["tl","tr"]
+ * @type Array
+ */
+ oConfig.addProperty(
+ SUBMENU_ALIGNMENT_CONFIG.key,
+ {
+ value: SUBMENU_ALIGNMENT_CONFIG.value,
+ suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config autosubmenudisplay
+ * @description Boolean indicating if submenus are automatically made
+ * visible when the user mouses over the menu's items.
+ * @default true
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ AUTO_SUBMENU_DISPLAY_CONFIG.key,
+ {
+ value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
+ validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
+ suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config showdelay
+ * @description Number indicating the time (in milliseconds) that should
+ * expire before a submenu is made visible when the user mouses over
+ * the menu's items. This property is only applied when the "position"
+ * configuration property is set to dynamic and is automatically applied
+ * to all submenus.
+ * @default 250
+ * @type Number
+ */
+ oConfig.addProperty(
+ SHOW_DELAY_CONFIG.key,
+ {
+ value: SHOW_DELAY_CONFIG.value,
+ validator: SHOW_DELAY_CONFIG.validator,
+ suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config hidedelay
+ * @description Number indicating the time (in milliseconds) that should
+ * expire before the menu is hidden. This property is only applied when
+ * the "position" configuration property is set to dynamic and is
+ * automatically applied to all submenus.
+ * @default 0
+ * @type Number
+ */
+ oConfig.addProperty(
+ HIDE_DELAY_CONFIG.key,
+ {
+ handler: this.configHideDelay,
+ value: HIDE_DELAY_CONFIG.value,
+ validator: HIDE_DELAY_CONFIG.validator,
+ suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config submenuhidedelay
+ * @description Number indicating the time (in milliseconds) that should
+ * expire before a submenu is hidden when the user mouses out of a menu item
+ * heading in the direction of a submenu. The value must be greater than or
+ * equal to the value specified for the "showdelay" configuration property.
+ * This property is only applied when the "position" configuration property
+ * is set to dynamic and is automatically applied to all submenus.
+ * @default 250
+ * @type Number
+ */
+ oConfig.addProperty(
+ SUBMENU_HIDE_DELAY_CONFIG.key,
+ {
+ value: SUBMENU_HIDE_DELAY_CONFIG.value,
+ validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
+ suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config clicktohide
+ * @description Boolean indicating if the menu will automatically be
+ * hidden if the user clicks outside of it. This property is only
+ * applied when the "position" configuration property is set to dynamic
+ * and is automatically applied to all submenus.
+ * @default true
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ CLICK_TO_HIDE_CONFIG.key,
+ {
+ value: CLICK_TO_HIDE_CONFIG.value,
+ validator: CLICK_TO_HIDE_CONFIG.validator,
+ suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config container
+ * @description HTML element reference or string specifying the id
+ * attribute of the HTML element that the menu's markup should be
+ * rendered into.
+ * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+ * level-one-html.html#ID-58190037">HTMLElement</a>|String
+ * @default document.body
+ */
+ oConfig.addProperty(
+ CONTAINER_CONFIG.key,
+ {
+ handler: this.configContainer,
+ value: document.body,
+ suppressEvent: CONTAINER_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config scrollincrement
+ * @description Number used to control the scroll speed of a menu. Used to
+ * increment the "scrollTop" property of the menu's body by when a menu's
+ * content is scrolling. When set this property is automatically applied
+ * to all submenus.
+ * @default 1
+ * @type Number
+ */
+ oConfig.addProperty(
+ SCROLL_INCREMENT_CONFIG.key,
+ {
+ value: SCROLL_INCREMENT_CONFIG.value,
+ validator: SCROLL_INCREMENT_CONFIG.validator,
+ supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
+ suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config minscrollheight
+ * @description Number defining the minimum threshold for the "maxheight"
+ * configuration property. When set this property is automatically applied
+ * to all submenus.
+ * @default 90
+ * @type Number
+ */
+ oConfig.addProperty(
+ MIN_SCROLL_HEIGHT_CONFIG.key,
+ {
+ value: MIN_SCROLL_HEIGHT_CONFIG.value,
+ validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
+ supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
+ suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config maxheight
+ * @description Number defining the maximum height (in pixels) for a menu's
+ * body element (<code><div class="bd"<</code>). Once a menu's body
+ * exceeds this height, the contents of the body are scrolled to maintain
+ * this value. This value cannot be set lower than the value of the
+ * "minscrollheight" configuration property.
+ * @default 0
+ * @type Number
+ */
+ oConfig.addProperty(
+ MAX_HEIGHT_CONFIG.key,
+ {
+ handler: this.configMaxHeight,
+ value: MAX_HEIGHT_CONFIG.value,
+ validator: MAX_HEIGHT_CONFIG.validator,
+ suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
+ supercedes: MAX_HEIGHT_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config classname
+ * @description String representing the CSS class to be applied to the
+ * menu's root <code><div></code> element. The specified class(es)
+ * are appended in addition to the default class as specified by the menu's
+ * CSS_CLASS_NAME constant. When set this property is automatically
+ * applied to all submenus.
+ * @default null
+ * @type String
+ */
+ oConfig.addProperty(
+ CLASS_NAME_CONFIG.key,
+ {
+ handler: this.configClassName,
+ value: CLASS_NAME_CONFIG.value,
+ validator: CLASS_NAME_CONFIG.validator,
+ supercedes: CLASS_NAME_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config disabled
+ * @description Boolean indicating if the menu should be disabled.
+ * Disabling a menu disables each of its items. (Disabled menu items are
+ * dimmed and will not respond to user input or fire events.) Disabled
+ * menus have a corresponding "disabled" CSS class applied to their root
+ * <code><div></code> element.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ DISABLED_CONFIG.key,
+ {
+ handler: this.configDisabled,
+ value: DISABLED_CONFIG.value,
+ validator: DISABLED_CONFIG.validator,
+ suppressEvent: DISABLED_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config shadow
+ * @description Boolean indicating if the menu should have a shadow.
+ * @default true
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ SHADOW_CONFIG.key,
+ {
+ handler: this.configShadow,
+ value: SHADOW_CONFIG.value,
+ validator: SHADOW_CONFIG.validator
+ }
+ );
+
+
+ /**
+ * @config keepopen
+ * @description Boolean indicating if the menu should remain open when clicked.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ KEEP_OPEN_CONFIG.key,
+ {
+ value: KEEP_OPEN_CONFIG.value,
+ validator: KEEP_OPEN_CONFIG.validator
+ }
+ );
+
+}
+
+}); // END YAHOO.lang.extend
+
+})();
+
+
+
+(function () {
+
+/**
+* Creates an item for a menu.
+*
+* @param {String} p_oObject String specifying the text of the menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
+* the <code><li></code> element of the menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
+* specifying the <code><optgroup></code> element of the menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
+* specifying the <code><option></code> element of the menu item.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu item. See configuration class documentation
+* for more details.
+* @class MenuItem
+* @constructor
+*/
+YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
+
+ if (p_oObject) {
+
+ if (p_oConfig) {
+
+ this.parent = p_oConfig.parent;
+ this.value = p_oConfig.value;
+ this.id = p_oConfig.id;
+
+ }
+
+ this.init(p_oObject, p_oConfig);
+
+ }
+
+};
+
+
+var Dom = YAHOO.util.Dom,
+ Module = YAHOO.widget.Module,
+ Menu = YAHOO.widget.Menu,
+ MenuItem = YAHOO.widget.MenuItem,
+ CustomEvent = YAHOO.util.CustomEvent,
+ UA = YAHOO.env.ua,
+ Lang = YAHOO.lang,
+
+ // Private string constants
+
+ _TEXT = "text",
+ _HASH = "#",
+ _HYPHEN = "-",
+ _HELP_TEXT = "helptext",
+ _URL = "url",
+ _TARGET = "target",
+ _EMPHASIS = "emphasis",
+ _STRONG_EMPHASIS = "strongemphasis",
+ _CHECKED = "checked",
+ _SUBMENU = "submenu",
+ _DISABLED = "disabled",
+ _SELECTED = "selected",
+ _HAS_SUBMENU = "hassubmenu",
+ _CHECKED_DISABLED = "checked-disabled",
+ _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
+ _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
+ _CHECKED_SELECTED = "checked-selected",
+ _ONCLICK = "onclick",
+ _CLASSNAME = "classname",
+ _EMPTY_STRING = "",
+ _OPTION = "OPTION",
+ _OPTGROUP = "OPTGROUP",
+ _LI_UPPERCASE = "LI",
+ _HREF = "href",
+ _SELECT = "SELECT",
+ _DIV = "DIV",
+ _START_HELP_TEXT = "<em class=\"helptext\">",
+ _START_EM = "<em>",
+ _END_EM = "</em>",
+ _START_STRONG = "<strong>",
+ _END_STRONG = "</strong>",
+ _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
+ _OBJ = "obj",
+ _SCOPE = "scope",
+ _NONE = "none",
+ _VISIBLE = "visible",
+ _SPACE = " ",
+ _MENUITEM = "MenuItem",
+ _CLICK = "click",
+ _SHOW = "show",
+ _HIDE = "hide",
+ _LI_LOWERCASE = "li",
+ _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
+
+ EVENT_TYPES = [
+
+ ["mouseOverEvent", "mouseover"],
+ ["mouseOutEvent", "mouseout"],
+ ["mouseDownEvent", "mousedown"],
+ ["mouseUpEvent", "mouseup"],
+ ["clickEvent", _CLICK],
+ ["keyPressEvent", "keypress"],
+ ["keyDownEvent", "keydown"],
+ ["keyUpEvent", "keyup"],
+ ["focusEvent", "focus"],
+ ["blurEvent", "blur"],
+ ["destroyEvent", "destroy"]
+
+ ],
+
+ TEXT_CONFIG = {
+ key: _TEXT,
+ value: _EMPTY_STRING,
+ validator: Lang.isString,
+ suppressEvent: true
+ },
+
+ HELP_TEXT_CONFIG = {
+ key: _HELP_TEXT,
+ supercedes: [_TEXT],
+ suppressEvent: true
+ },
+
+ URL_CONFIG = {
+ key: _URL,
+ value: _HASH,
+ suppressEvent: true
+ },
+
+ TARGET_CONFIG = {
+ key: _TARGET,
+ suppressEvent: true
+ },
+
+ EMPHASIS_CONFIG = {
+ key: _EMPHASIS,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true,
+ supercedes: [_TEXT]
+ },
+
+ STRONG_EMPHASIS_CONFIG = {
+ key: _STRONG_EMPHASIS,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true,
+ supercedes: [_TEXT]
+ },
+
+ CHECKED_CONFIG = {
+ key: _CHECKED,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true,
+ supercedes: [_DISABLED, _SELECTED]
+ },
+
+ SUBMENU_CONFIG = {
+ key: _SUBMENU,
+ suppressEvent: true,
+ supercedes: [_DISABLED, _SELECTED]
+ },
+
+ DISABLED_CONFIG = {
+ key: _DISABLED,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true,
+ supercedes: [_TEXT, _SELECTED]
+ },
+
+ SELECTED_CONFIG = {
+ key: _SELECTED,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true
+ },
+
+ ONCLICK_CONFIG = {
+ key: _ONCLICK,
+ suppressEvent: true
+ },
+
+ CLASS_NAME_CONFIG = {
+ key: _CLASSNAME,
+ value: null,
+ validator: Lang.isString,
+ suppressEvent: true
+ },
+
+ KEY_LISTENER_CONFIG = {
+ key: "keylistener",
+ value: null,
+ suppressEvent: true
+ },
+
+ m_oMenuItemTemplate = null,
+
+ CLASS_NAMES = {};
+
+
+/**
+* @method getClassNameForState
+* @description Returns a class name for the specified prefix and state. If the class name does not
+* yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
+* @private
+* @param {String} prefix String representing the prefix for the class name
+* @param {String} state String representing a state - "disabled," "checked," etc.
+*/
+var getClassNameForState = function (prefix, state) {
+
+ var oClassNames = CLASS_NAMES[prefix];
+
+ if (!oClassNames) {
+ CLASS_NAMES[prefix] = {};
+ oClassNames = CLASS_NAMES[prefix];
+ }
+
+
+ var sClassName = oClassNames[state];
+
+ if (!sClassName) {
+ sClassName = prefix + _HYPHEN + state;
+ oClassNames[state] = sClassName;
+ }
+
+ return sClassName;
+
+};
+
+
+/**
+* @method addClassNameForState
+* @description Applies a class name to a MenuItem instance's <LI> and <A> elements
+* that represents a MenuItem's state - "disabled," "checked," etc.
+* @private
+* @param {String} state String representing a state - "disabled," "checked," etc.
+*/
+var addClassNameForState = function (state) {
+
+ Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
+ Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
+
+};
+
+/**
+* @method removeClassNameForState
+* @description Removes a class name from a MenuItem instance's <LI> and <A> elements
+* that represents a MenuItem's state - "disabled," "checked," etc.
+* @private
+* @param {String} state String representing a state - "disabled," "checked," etc.
+*/
+var removeClassNameForState = function (state) {
+
+ Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
+ Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
+
+};
+
+
+MenuItem.prototype = {
+
+ /**
+ * @property CSS_CLASS_NAME
+ * @description String representing the CSS class(es) to be applied to the
+ * <code><li></code> element of the menu item.
+ * @default "yuimenuitem"
+ * @final
+ * @type String
+ */
+ CSS_CLASS_NAME: "yuimenuitem",
+
+
+ /**
+ * @property CSS_LABEL_CLASS_NAME
+ * @description String representing the CSS class(es) to be applied to the
+ * menu item's <code><a></code> element.
+ * @default "yuimenuitemlabel"
+ * @final
+ * @type String
+ */
+ CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
+
+
+ /**
+ * @property SUBMENU_TYPE
+ * @description Object representing the type of menu to instantiate and
+ * add when parsing the child nodes of the menu item's source HTML element.
+ * @final
+ * @type YAHOO.widget.Menu
+ */
+ SUBMENU_TYPE: null,
+
+
+
+ // Private member variables
+
+
+ /**
+ * @property _oAnchor
+ * @description Object reference to the menu item's
+ * <code><a></code> element.
+ * @default null
+ * @private
+ * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-48250443">HTMLAnchorElement</a>
+ */
+ _oAnchor: null,
+
+
+ /**
+ * @property _oHelpTextEM
+ * @description Object reference to the menu item's help text
+ * <code><em></code> element.
+ * @default null
+ * @private
+ * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-58190037">HTMLElement</a>
+ */
+ _oHelpTextEM: null,
+
+
+ /**
+ * @property _oSubmenu
+ * @description Object reference to the menu item's submenu.
+ * @default null
+ * @private
+ * @type YAHOO.widget.Menu
+ */
+ _oSubmenu: null,
+
+
+ /**
+ * @property _oOnclickAttributeValue
+ * @description Object reference to the menu item's current value for the
+ * "onclick" configuration attribute.
+ * @default null
+ * @private
+ * @type Object
+ */
+ _oOnclickAttributeValue: null,
+
+
+ /**
+ * @property _sClassName
+ * @description The current value of the "classname" configuration attribute.
+ * @default null
+ * @private
+ * @type String
+ */
+ _sClassName: null,
+
+
+
+ // Public properties
+
+
+ /**
+ * @property constructor
+ * @description Object reference to the menu item's constructor function.
+ * @default YAHOO.widget.MenuItem
+ * @type YAHOO.widget.MenuItem
+ */
+ constructor: MenuItem,
+
+
+ /**
+ * @property index
+ * @description Number indicating the ordinal position of the menu item in
+ * its group.
+ * @default null
+ * @type Number
+ */
+ index: null,
+
+
+ /**
+ * @property groupIndex
+ * @description Number indicating the index of the group to which the menu
+ * item belongs.
+ * @default null
+ * @type Number
+ */
+ groupIndex: null,
+
+
+ /**
+ * @property parent
+ * @description Object reference to the menu item's parent menu.
+ * @default null
+ * @type YAHOO.widget.Menu
+ */
+ parent: null,
+
+
+ /**
+ * @property element
+ * @description Object reference to the menu item's
+ * <code><li></code> element.
+ * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
+ * -one-html.html#ID-74680021">HTMLLIElement</a>
+ * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-74680021">HTMLLIElement</a>
+ */
+ element: null,
+
+
+ /**
+ * @property srcElement
+ * @description Object reference to the HTML element (either
+ * <code><li></code>, <code><optgroup></code> or
+ * <code><option></code>) used create the menu item.
+ * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+ * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
+ * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
+ * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
+ * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
+ * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
+ * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
+ * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
+ * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
+ */
+ srcElement: null,
+
+
+ /**
+ * @property value
+ * @description Object reference to the menu item's value.
+ * @default null
+ * @type Object
+ */
+ value: null,
+
+
+ /**
+ * @property browser
+ * @deprecated Use YAHOO.env.ua
+ * @description String representing the browser.
+ * @type String
+ */
+ browser: Module.prototype.browser,
+
+
+ /**
+ * @property id
+ * @description Id of the menu item's root <code><li></code>
+ * element. This property should be set via the constructor using the
+ * configuration object literal. If an id is not specified, then one will
+ * be created using the "generateId" method of the Dom utility.
+ * @default null
+ * @type String
+ */
+ id: null,
+
+
+
+ // Events
+
+
+ /**
+ * @event destroyEvent
+ * @description Fires when the menu item's <code><li></code>
+ * element is removed from its parent <code><ul></code> element.
+ * @type YAHOO.util.CustomEvent
+ */
+
+
+ /**
+ * @event mouseOverEvent
+ * @description Fires when the mouse has entered the menu item. Passes
+ * back the DOM Event object as an argument.
+ * @type YAHOO.util.CustomEvent
+ */
+
+
+ /**
+ * @event mouseOutEvent
+ * @description Fires when the mouse has left the menu item. 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 item. 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 item. 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 item. 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 the
+ * menu item 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 the menu item 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 the menu item has
+ * focus. Passes back the DOM Event object as an argument.
+ * @type YAHOO.util.CustomEvent
+ */
+
+
+ /**
+ * @event focusEvent
+ * @description Fires when the menu item receives focus.
+ * @type YAHOO.util.CustomEvent
+ */
+
+
+ /**
+ * @event blurEvent
+ * @description Fires when the menu item loses the input focus.
+ * @type YAHOO.util.CustomEvent
+ */
+
+
+ /**
+ * @method init
+ * @description The MenuItem 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_oObject String specifying the text of the menu item.
+ * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
+ * the <code><li></code> element of the menu item.
+ * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
+ * specifying the <code><optgroup></code> element of the menu item.
+ * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+ * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
+ * specifying the <code><option></code> element of the menu item.
+ * @param {Object} p_oConfig Optional. Object literal specifying the
+ * configuration for the menu item. See configuration class documentation
+ * for more details.
+ */
+ init: function (p_oObject, p_oConfig) {
+
+
+ if (!this.SUBMENU_TYPE) {
+
+ this.SUBMENU_TYPE = Menu;
+
+ }
+
+
+ // Create the config object
+
+ this.cfg = new YAHOO.util.Config(this);
+
+ this.initDefaultConfig();
+
+ var oConfig = this.cfg,
+ sURL = _HASH,
+ oCustomEvent,
+ aEventData,
+ oAnchor,
+ sTarget,
+ sText,
+ sId,
+ i;
+
+
+ if (Lang.isString(p_oObject)) {
+
+ this._createRootNodeStructure();
+
+ oConfig.queueProperty(_TEXT, p_oObject);
+
+ }
+ else if (p_oObject && p_oObject.tagName) {
+
+ switch(p_oObject.tagName.toUpperCase()) {
+
+ case _OPTION:
+
+ this._createRootNodeStructure();
+
+ oConfig.queueProperty(_TEXT, p_oObject.text);
+ oConfig.queueProperty(_DISABLED, p_oObject.disabled);
+
+ this.value = p_oObject.value;
+
+ this.srcElement = p_oObject;
+
+ break;
+
+ case _OPTGROUP:
+
+ this._createRootNodeStructure();
+
+ oConfig.queueProperty(_TEXT, p_oObject.label);
+ oConfig.queueProperty(_DISABLED, p_oObject.disabled);
+
+ this.srcElement = p_oObject;
+
+ this._initSubTree();
+
+ break;
+
+ case _LI_UPPERCASE:
+
+ // Get the anchor node (if it exists)
+
+ oAnchor = Dom.getFirstChild(p_oObject);
+
+
+ // Capture the "text" and/or the "URL"
+
+ if (oAnchor) {
+
+ sURL = oAnchor.getAttribute(_HREF, 2);
+ sTarget = oAnchor.getAttribute(_TARGET);
+
+ sText = oAnchor.innerHTML;
+
+ }
+
+ this.srcElement = p_oObject;
+ this.element = p_oObject;
+ this._oAnchor = oAnchor;
+
+ /*
+ Set these properties silently to sync up the
+ configuration object without making changes to the
+ element's DOM
+ */
+
+ oConfig.setProperty(_TEXT, sText, true);
+ oConfig.setProperty(_URL, sURL, true);
+ oConfig.setProperty(_TARGET, sTarget, true);
+
+ this._initSubTree();
+
+ break;
+
+ }
+
+ }
+
+
+ if (this.element) {
+
+ sId = (this.srcElement || this.element).id;
+
+ if (!sId) {
+
+ sId = this.id || Dom.generateId();
+
+ this.element.id = sId;
+
+ }
+
+ this.id = sId;
+
+
+ Dom.addClass(this.element, this.CSS_CLASS_NAME);
+ Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
+
+
+ i = EVENT_TYPES.length - 1;
+
+ do {
+
+ aEventData = EVENT_TYPES[i];
+
+ oCustomEvent = this.createEvent(aEventData[1]);
+ oCustomEvent.signature = CustomEvent.LIST;
+
+ this[aEventData[0]] = oCustomEvent;
+
+ }
+ while (i--);
+
+
+ if (p_oConfig) {
+
+ oConfig.applyConfig(p_oConfig);
+
+ }
+
+ oConfig.fireQueue();
+
+ }
+
+ },
+
+
+
+ // Private methods
+
+ /**
+ * @method _createRootNodeStructure
+ * @description Creates the core DOM structure for the menu item.
+ * @private
+ */
+ _createRootNodeStructure: function () {
+
+ var oElement,
+ oAnchor;
+
+ if (!m_oMenuItemTemplate) {
+
+ m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
+ m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
+
+ }
+
+ oElement = m_oMenuItemTemplate.cloneNode(true);
+ oElement.className = this.CSS_CLASS_NAME;
+
+ oAnchor = oElement.firstChild;
+ oAnchor.className = this.CSS_LABEL_CLASS_NAME;
+
+ this.element = oElement;
+ this._oAnchor = oAnchor;
+
+ },
+
+
+ /**
+ * @method _initSubTree
+ * @description Iterates the source element's childNodes collection and uses
+ * the child nodes to instantiate other menus.
+ * @private
+ */
+ _initSubTree: function () {
+
+ var oSrcEl = this.srcElement,
+ oConfig = this.cfg,
+ oNode,
+ aOptions,
+ nOptions,
+ oMenu,
+ n;
+
+
+ if (oSrcEl.childNodes.length > 0) {
+
+ if (this.parent.lazyLoad && this.parent.srcElement &&
+ this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
+
+ oConfig.setProperty(
+ _SUBMENU,
+ { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
+ );
+
+ }
+ else {
+
+ oNode = oSrcEl.firstChild;
+ aOptions = [];
+
+ do {
+
+ if (oNode && oNode.tagName) {
+
+ switch(oNode.tagName.toUpperCase()) {
+
+ case _DIV:
+
+ oConfig.setProperty(_SUBMENU, oNode);
+
+ break;
+
+ case _OPTION:
+
+ aOptions[aOptions.length] = oNode;
+
+ break;
+
+ }
+
+ }
+
+ }
+ while((oNode = oNode.nextSibling));
+
+
+ nOptions = aOptions.length;
+
+ if (nOptions > 0) {
+
+ oMenu = new this.SUBMENU_TYPE(Dom.generateId());
+
+ oConfig.setProperty(_SUBMENU, oMenu);
+
+ for(n=0; n<nOptions; n++) {
+
+ oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
+
+ }
+
+ }
+
+ }
+
+ }
+
+ },
+
+
+
+ // Event handlers for configuration properties
+
+
+ /**
+ * @method configText
+ * @description Event handler for when the "text" configuration property of
+ * the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configText: function (p_sType, p_aArgs, p_oItem) {
+
+ var sText = p_aArgs[0],
+ oConfig = this.cfg,
+ oAnchor = this._oAnchor,
+ sHelpText = oConfig.getProperty(_HELP_TEXT),
+ sHelpTextHTML = _EMPTY_STRING,
+ sEmphasisStartTag = _EMPTY_STRING,
+ sEmphasisEndTag = _EMPTY_STRING;
+
+
+ if (sText) {
+
+
+ if (sHelpText) {
+
+ sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
+
+ }
+
+
+ if (oConfig.getProperty(_EMPHASIS)) {
+
+ sEmphasisStartTag = _START_EM;
+ sEmphasisEndTag = _END_EM;
+
+ }
+
+
+ if (oConfig.getProperty(_STRONG_EMPHASIS)) {
+
+ sEmphasisStartTag = _START_STRONG;
+ sEmphasisEndTag = _END_STRONG;
+
+ }
+
+
+ oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
+
+ }
+
+ },
+
+
+ /**
+ * @method configHelpText
+ * @description Event handler for when the "helptext" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configHelpText: function (p_sType, p_aArgs, p_oItem) {
+
+ this.cfg.refireEvent(_TEXT);
+
+ },
+
+
+ /**
+ * @method configURL
+ * @description Event handler for when the "url" configuration property of
+ * the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configURL: function (p_sType, p_aArgs, p_oItem) {
+
+ var sURL = p_aArgs[0];
+
+ if (!sURL) {
+
+ sURL = _HASH;
+
+ }
+
+ var oAnchor = this._oAnchor;
+
+ if (UA.opera) {
+
+ oAnchor.removeAttribute(_HREF);
+
+ }
+
+ oAnchor.setAttribute(_HREF, sURL);
+
+ },
+
+
+ /**
+ * @method configTarget
+ * @description Event handler for when the "target" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configTarget: function (p_sType, p_aArgs, p_oItem) {
+
+ var sTarget = p_aArgs[0],
+ oAnchor = this._oAnchor;
+
+ if (sTarget && sTarget.length > 0) {
+
+ oAnchor.setAttribute(_TARGET, sTarget);
+
+ }
+ else {
+
+ oAnchor.removeAttribute(_TARGET);
+
+ }
+
+ },
+
+
+ /**
+ * @method configEmphasis
+ * @description Event handler for when the "emphasis" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configEmphasis: function (p_sType, p_aArgs, p_oItem) {
+
+ var bEmphasis = p_aArgs[0],
+ oConfig = this.cfg;
+
+
+ if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
+
+ oConfig.setProperty(_STRONG_EMPHASIS, false);
+
+ }
+
+
+ oConfig.refireEvent(_TEXT);
+
+ },
+
+
+ /**
+ * @method configStrongEmphasis
+ * @description Event handler for when the "strongemphasis" configuration
+ * property of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
+
+ var bStrongEmphasis = p_aArgs[0],
+ oConfig = this.cfg;
+
+
+ if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
+
+ oConfig.setProperty(_EMPHASIS, false);
+
+ }
+
+ oConfig.refireEvent(_TEXT);
+
+ },
+
+
+ /**
+ * @method configChecked
+ * @description Event handler for when the "checked" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configChecked: function (p_sType, p_aArgs, p_oItem) {
+
+ var bChecked = p_aArgs[0],
+ oConfig = this.cfg;
+
+
+ if (bChecked) {
+
+ addClassNameForState.call(this, _CHECKED);
+
+ }
+ else {
+
+ removeClassNameForState.call(this, _CHECKED);
+ }
+
+
+ oConfig.refireEvent(_TEXT);
+
+
+ if (oConfig.getProperty(_DISABLED)) {
+
+ oConfig.refireEvent(_DISABLED);
+
+ }
+
+
+ if (oConfig.getProperty(_SELECTED)) {
+
+ oConfig.refireEvent(_SELECTED);
+
+ }
+
+ },
+
+
+
+ /**
+ * @method configDisabled
+ * @description Event handler for when the "disabled" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configDisabled: function (p_sType, p_aArgs, p_oItem) {
+
+ var bDisabled = p_aArgs[0],
+ oConfig = this.cfg,
+ oSubmenu = oConfig.getProperty(_SUBMENU),
+ bChecked = oConfig.getProperty(_CHECKED);
+
+
+ if (bDisabled) {
+
+ if (oConfig.getProperty(_SELECTED)) {
+
+ oConfig.setProperty(_SELECTED, false);
+
+ }
+
+
+ addClassNameForState.call(this, _DISABLED);
+
+
+ if (oSubmenu) {
+
+ addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
+
+ }
+
+
+ if (bChecked) {
+
+ addClassNameForState.call(this, _CHECKED_DISABLED);
+
+ }
+
+ }
+ else {
+
+ removeClassNameForState.call(this, _DISABLED);
+
+
+ if (oSubmenu) {
+
+ removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
+
+ }
+
+
+ if (bChecked) {
+
+ removeClassNameForState.call(this, _CHECKED_DISABLED);
+
+ }
+
+ }
+
+ },
+
+
+ /**
+ * @method configSelected
+ * @description Event handler for when the "selected" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configSelected: function (p_sType, p_aArgs, p_oItem) {
+
+ var oConfig = this.cfg,
+ oAnchor = this._oAnchor,
+
+ bSelected = p_aArgs[0],
+ bChecked = oConfig.getProperty(_CHECKED),
+ oSubmenu = oConfig.getProperty(_SUBMENU);
+
+
+ if (UA.opera) {
+
+ oAnchor.blur();
+
+ }
+
+
+ if (bSelected && !oConfig.getProperty(_DISABLED)) {
+
+ addClassNameForState.call(this, _SELECTED);
+
+
+ if (oSubmenu) {
+
+ addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
+
+ }
+
+
+ if (bChecked) {
+
+ addClassNameForState.call(this, _CHECKED_SELECTED);
+
+ }
+
+ }
+ else {
+
+ removeClassNameForState.call(this, _SELECTED);
+
+
+ if (oSubmenu) {
+
+ removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
+
+ }
+
+
+ if (bChecked) {
+
+ removeClassNameForState.call(this, _CHECKED_SELECTED);
+
+ }
+
+ }
+
+
+ if (this.hasFocus() && UA.opera) {
+
+ oAnchor.focus();
+
+ }
+
+ },
+
+
+ /**
+ * @method _onSubmenuBeforeHide
+ * @description "beforehide" Custom Event handler for a submenu.
+ * @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.
+ */
+ _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
+
+ var oItem = this.parent,
+ oMenu;
+
+ function onHide() {
+
+ oItem._oAnchor.blur();
+ oMenu.beforeHideEvent.unsubscribe(onHide);
+
+ }
+
+
+ if (oItem.hasFocus()) {
+
+ oMenu = oItem.parent;
+
+ oMenu.beforeHideEvent.subscribe(onHide);
+
+ }
+
+ },
+
+
+ /**
+ * @method configSubmenu
+ * @description Event handler for when the "submenu" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configSubmenu: function (p_sType, p_aArgs, p_oItem) {
+
+ var oSubmenu = p_aArgs[0],
+ oConfig = this.cfg,
+ bLazyLoad = this.parent && this.parent.lazyLoad,
+ oMenu,
+ sSubmenuId,
+ oSubmenuConfig;
+
+
+ if (oSubmenu) {
+
+ if (oSubmenu instanceof Menu) {
+
+ oMenu = oSubmenu;
+ oMenu.parent = this;
+ oMenu.lazyLoad = bLazyLoad;
+
+ }
+ else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
+
+ sSubmenuId = oSubmenu.id;
+ oSubmenuConfig = oSubmenu;
+
+ oSubmenuConfig.lazyload = bLazyLoad;
+ oSubmenuConfig.parent = this;
+
+ oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
+
+
+ // Set the value of the property to the Menu instance
+
+ oConfig.setProperty(_SUBMENU, oMenu, true);
+
+ }
+ else {
+
+ oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
+
+
+ // Set the value of the property to the Menu instance
+
+ oConfig.setProperty(_SUBMENU, oMenu, true);
+
+ }
+
+
+ if (oMenu) {
+
+ oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
+
+ addClassNameForState.call(this, _HAS_SUBMENU);
+
+
+ if (oConfig.getProperty(_URL) === _HASH) {
+
+ oConfig.setProperty(_URL, (_HASH + oMenu.id));
+
+ }
+
+
+ this._oSubmenu = oMenu;
+
+
+ if (UA.opera) {
+
+ oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
+
+ }
+
+ }
+
+ }
+ else {
+
+ removeClassNameForState.call(this, _HAS_SUBMENU);
+
+ if (this._oSubmenu) {
+
+ this._oSubmenu.destroy();
+
+ }
+
+ }
+
+
+ if (oConfig.getProperty(_DISABLED)) {
+
+ oConfig.refireEvent(_DISABLED);
+
+ }
+
+
+ if (oConfig.getProperty(_SELECTED)) {
+
+ oConfig.refireEvent(_SELECTED);
+
+ }
+
+ },
+
+
+ /**
+ * @method configOnClick
+ * @description Event handler for when the "onclick" configuration property
+ * of the menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configOnClick: function (p_sType, p_aArgs, p_oItem) {
+
+ var oObject = p_aArgs[0];
+
+ /*
+ Remove any existing listeners if a "click" event handler has
+ already been specified.
+ */
+
+ if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
+
+ this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
+ this._oOnclickAttributeValue.obj);
+
+ this._oOnclickAttributeValue = null;
+
+ }
+
+
+ if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
+ Lang.isFunction(oObject.fn)) {
+
+ this.clickEvent.subscribe(oObject.fn,
+ ((_OBJ in oObject) ? oObject.obj : this),
+ ((_SCOPE in oObject) ? oObject.scope : null) );
+
+ this._oOnclickAttributeValue = oObject;
+
+ }
+
+ },
+
+
+ /**
+ * @method configClassName
+ * @description Event handler for when the "classname" configuration
+ * property of a menu item changes.
+ * @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.MenuItem} p_oItem Object representing the menu item
+ * that fired the event.
+ */
+ configClassName: function (p_sType, p_aArgs, p_oItem) {
+
+ var sClassName = p_aArgs[0];
+
+ if (this._sClassName) {
+
+ Dom.removeClass(this.element, this._sClassName);
+
+ }
+
+ Dom.addClass(this.element, sClassName);
+ this._sClassName = sClassName;
+
+ },
+
+
+ /**
+ * @method _dispatchClickEvent
+ * @description Dispatches a DOM "click" event to the anchor element of a
+ * MenuItem instance.
+ * @private
+ */
+ _dispatchClickEvent: function () {
+
+ var oMenuItem = this,
+ oAnchor,
+ oEvent;
+
+ if (!oMenuItem.cfg.getProperty(_DISABLED)) {
+
+ oAnchor = Dom.getFirstChild(oMenuItem.element);
+
+ // Dispatch a "click" event to the MenuItem's anchor so that its
+ // "click" event handlers will get called in response to the user
+ // pressing the keyboard shortcut defined by the "keylistener"
+ // configuration property.
+
+ if (UA.ie) {
+ oAnchor.fireEvent(_ONCLICK);
+ }
+ else {
+
+ if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
+
+ oEvent = document.createEvent("HTMLEvents");
+ oEvent.initEvent(_CLICK, true, true);
+
+ }
+ else {
+
+ oEvent = document.createEvent("MouseEvents");
+ oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0,
+ 0, 0, false, false, false, false, 0, null);
+
+ }
+
+ oAnchor.dispatchEvent(oEvent);
+
+ }
+
+ }
+
+ },
+
+
+ /**
+ * @method _createKeyListener
+ * @description "show" event handler for a Menu instance - responsible for
+ * setting up the KeyListener instance for a MenuItem.
+ * @private
+ * @param {String} type String representing the name of the event that
+ * was fired.
+ * @param {Array} args Array of arguments sent when the event was fired.
+ * @param {Array} keyData Array of arguments sent when the event was fired.
+ */
+ _createKeyListener: function (type, args, keyData) {
+
+ var oMenuItem = this,
+ oMenu = oMenuItem.parent;
+
+ var oKeyListener = new YAHOO.util.KeyListener(
+ oMenu.element.ownerDocument,
+ keyData,
+ {
+ fn: oMenuItem._dispatchClickEvent,
+ scope: oMenuItem,
+ correctScope: true });
+
+
+ if (oMenu.cfg.getProperty(_VISIBLE)) {
+ oKeyListener.enable();
+ }
+
+
+ oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
+ oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
+
+ oMenuItem._keyListener = oKeyListener;
+
+ oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
+
+ },
+
+
+ /**
+ * @method configKeyListener
+ * @description Event handler for when the "keylistener" configuration
+ * property of a menu item changes.
+ * @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.
+ */
+ configKeyListener: function (p_sType, p_aArgs) {
+
+ var oKeyData = p_aArgs[0],
+ oMenuItem = this,
+ oMenu = oMenuItem.parent;
+
+ if (oMenuItem._keyData) {
+
+ // Unsubscribe from the "show" event in case the keylistener
+ // config was changed before the Menu was ever made visible.
+
+ oMenu.unsubscribe(_SHOW,
+ oMenuItem._createKeyListener, oMenuItem._keyData);
+
+ oMenuItem._keyData = null;
+
+ }
+
+
+ // Tear down for the previous value of the "keylistener" property
+
+ if (oMenuItem._keyListener) {
+
+ oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
+ oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
+
+ oMenuItem._keyListener.disable();
+ oMenuItem._keyListener = null;
+
+ }
+
+
+ if (oKeyData) {
+
+ oMenuItem._keyData = oKeyData;
+
+ // Defer the creation of the KeyListener instance until the
+ // parent Menu is visible. This is necessary since the
+ // KeyListener instance needs to be bound to the document the
+ // Menu has been rendered into. Deferring creation of the
+ // KeyListener instance also improves performance.
+
+ oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
+ oKeyData, oMenuItem);
+ }
+
+ },
+
+
+ // Public methods
+
+
+ /**
+ * @method initDefaultConfig
+ * @description Initializes an item's configurable properties.
+ */
+ initDefaultConfig : function () {
+
+ var oConfig = this.cfg;
+
+
+ // Define the configuration attributes
+
+ /**
+ * @config text
+ * @description String specifying the text label for the menu item.
+ * When building a menu from existing HTML the value of this property
+ * will be interpreted from the menu's markup.
+ * @default ""
+ * @type String
+ */
+ oConfig.addProperty(
+ TEXT_CONFIG.key,
+ {
+ handler: this.configText,
+ value: TEXT_CONFIG.value,
+ validator: TEXT_CONFIG.validator,
+ suppressEvent: TEXT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config helptext
+ * @description String specifying additional instructional text to
+ * accompany the text for the menu item.
+ * @deprecated Use "text" configuration property to add help text markup.
+ * For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em
+ * class=\"helptext\">Ctrl + C</em>");</code>
+ * @default null
+ * @type String|<a href="http://www.w3.org/TR/
+ * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
+ * HTMLElement</a>
+ */
+ oConfig.addProperty(
+ HELP_TEXT_CONFIG.key,
+ {
+ handler: this.configHelpText,
+ supercedes: HELP_TEXT_CONFIG.supercedes,
+ suppressEvent: HELP_TEXT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config url
+ * @description String specifying the URL for the menu item's anchor's
+ * "href" attribute. When building a menu from existing HTML the value
+ * of this property will be interpreted from the menu's markup.
+ * @default "#"
+ * @type String
+ */
+ oConfig.addProperty(
+ URL_CONFIG.key,
+ {
+ handler: this.configURL,
+ value: URL_CONFIG.value,
+ suppressEvent: URL_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config target
+ * @description String specifying the value for the "target" attribute
+ * of the menu item's anchor element. <strong>Specifying a target will
+ * require the user to click directly on the menu item's anchor node in
+ * order to cause the browser to navigate to the specified URL.</strong>
+ * When building a menu from existing HTML the value of this property
+ * will be interpreted from the menu's markup.
+ * @default null
+ * @type String
+ */
+ oConfig.addProperty(
+ TARGET_CONFIG.key,
+ {
+ handler: this.configTarget,
+ suppressEvent: TARGET_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config emphasis
+ * @description Boolean indicating if the text of the menu item will be
+ * rendered with emphasis.
+ * @deprecated Use the "text" configuration property to add emphasis.
+ * For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some
+ * Text</em>");</code>
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ EMPHASIS_CONFIG.key,
+ {
+ handler: this.configEmphasis,
+ value: EMPHASIS_CONFIG.value,
+ validator: EMPHASIS_CONFIG.validator,
+ suppressEvent: EMPHASIS_CONFIG.suppressEvent,
+ supercedes: EMPHASIS_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config strongemphasis
+ * @description Boolean indicating if the text of the menu item will be
+ * rendered with strong emphasis.
+ * @deprecated Use the "text" configuration property to add strong emphasis.
+ * For example: <code>oMenuItem.cfg.setProperty("text", "<strong>
+ * Some Text</strong>");</code>
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ STRONG_EMPHASIS_CONFIG.key,
+ {
+ handler: this.configStrongEmphasis,
+ value: STRONG_EMPHASIS_CONFIG.value,
+ validator: STRONG_EMPHASIS_CONFIG.validator,
+ suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
+ supercedes: STRONG_EMPHASIS_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config checked
+ * @description Boolean indicating if the menu item should be rendered
+ * with a checkmark.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ CHECKED_CONFIG.key,
+ {
+ handler: this.configChecked,
+ value: CHECKED_CONFIG.value,
+ validator: CHECKED_CONFIG.validator,
+ suppressEvent: CHECKED_CONFIG.suppressEvent,
+ supercedes: CHECKED_CONFIG.supercedes
+ }
+ );
+
+
+ /**
+ * @config disabled
+ * @description Boolean indicating if the menu item should be disabled.
+ * (Disabled menu items are dimmed and will not respond to user input
+ * or fire events.)
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ DISABLED_CONFIG.key,
+ {
+ handler: this.configDisabled,
+ value: DISABLED_CONFIG.value,
+ validator: DISABLED_CONFIG.validator,
+ suppressEvent: DISABLED_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config selected
+ * @description Boolean indicating if the menu item should
+ * be highlighted.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ SELECTED_CONFIG.key,
+ {
+ handler: this.configSelected,
+ value: SELECTED_CONFIG.value,
+ validator: SELECTED_CONFIG.validator,
+ suppressEvent: SELECTED_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config submenu
+ * @description Object specifying the submenu to be appended to the
+ * menu item. The value can be one of the following: <ul><li>Object
+ * specifying a Menu instance.</li><li>Object literal specifying the
+ * menu to be created. Format: <code>{ id: [menu id], itemdata:
+ * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
+ * items</a>] }</code>.</li><li>String specifying the id attribute
+ * of the <code><div></code> element of the menu.</li><li>
+ * Object specifying the <code><div></code> element of the
+ * menu.</li></ul>
+ * @default null
+ * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
+ * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
+ * HTMLElement</a>
+ */
+ oConfig.addProperty(
+ SUBMENU_CONFIG.key,
+ {
+ handler: this.configSubmenu,
+ supercedes: SUBMENU_CONFIG.supercedes,
+ suppressEvent: SUBMENU_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config onclick
+ * @description Object literal representing the code to be executed when
+ * the item is clicked. Format:<br> <code> {<br>
+ * <strong>fn:</strong> Function, // The handler to call when
+ * the event fires.<br> <strong>obj:</strong> Object, // An
+ * object to pass back to the handler.<br> <strong>scope:</strong>
+ * Object // The object to use for the scope of the handler.
+ * <br> } </code>
+ * @type Object
+ * @default null
+ */
+ oConfig.addProperty(
+ ONCLICK_CONFIG.key,
+ {
+ handler: this.configOnClick,
+ suppressEvent: ONCLICK_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config classname
+ * @description CSS class to be applied to the menu item's root
+ * <code><li></code> element. The specified class(es) are
+ * appended in addition to the default class as specified by the menu
+ * item's CSS_CLASS_NAME constant.
+ * @default null
+ * @type String
+ */
+ oConfig.addProperty(
+ CLASS_NAME_CONFIG.key,
+ {
+ handler: this.configClassName,
+ value: CLASS_NAME_CONFIG.value,
+ validator: CLASS_NAME_CONFIG.validator,
+ suppressEvent: CLASS_NAME_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config keylistener
+ * @description Object literal representing the key(s) that can be used
+ * to trigger the MenuItem's "click" event. Possible attributes are
+ * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
+ * or an array of ints representing keycodes).
+ * @default null
+ * @type Object
+ */
+ oConfig.addProperty(
+ KEY_LISTENER_CONFIG.key,
+ {
+ handler: this.configKeyListener,
+ value: KEY_LISTENER_CONFIG.value,
+ suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
+ }
+ );
+
+ },
+
+
+ /**
+ * @method getNextEnabledSibling
+ * @description Finds the menu item's next enabled sibling.
+ * @return YAHOO.widget.MenuItem
+ */
+ getNextEnabledSibling: function () {
+
+ var nGroupIndex,
+ aItemGroups,
+ oNextItem,
+ nNextGroupIndex,
+ aNextGroup,
+ returnVal;
+
+ function getNextArrayItem(p_aArray, p_nStartIndex) {
+
+ return p_aArray[p_nStartIndex] || getNextArrayItem(p_aArray, (p_nStartIndex+1));
+
+ }
+
+ if (this.parent instanceof Menu) {
+
+ nGroupIndex = this.groupIndex;
+
+ aItemGroups = this.parent.getItemGroups();
+
+ if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
+
+ oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
+ (this.index+1));
+
+ }
+ else {
+
+ if (nGroupIndex < (aItemGroups.length - 1)) {
+
+ nNextGroupIndex = nGroupIndex + 1;
+
+ }
+ else {
+
+ nNextGroupIndex = 0;
+
+ }
+
+ aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
+
+ // Retrieve the first menu item in the next group
+
+ oNextItem = getNextArrayItem(aNextGroup, 0);
+
+ }
+
+ returnVal = (oNextItem.cfg.getProperty(_DISABLED) ||
+ oNextItem.element.style.display == _NONE) ?
+ oNextItem.getNextEnabledSibling() : oNextItem;
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method getPreviousEnabledSibling
+ * @description Finds the menu item's previous enabled sibling.
+ * @return {YAHOO.widget.MenuItem}
+ */
+ getPreviousEnabledSibling: function () {
+
+ var nGroupIndex,
+ aItemGroups,
+ oPreviousItem,
+ nPreviousGroupIndex,
+ aPreviousGroup,
+ returnVal;
+
+ function getPreviousArrayItem(p_aArray, p_nStartIndex) {
+
+ return p_aArray[p_nStartIndex] || getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
+
+ }
+
+ function getFirstItemIndex(p_aArray, p_nStartIndex) {
+
+ return p_aArray[p_nStartIndex] ? p_nStartIndex :
+ getFirstItemIndex(p_aArray, (p_nStartIndex+1));
+
+ }
+
+ if (this.parent instanceof Menu) {
+
+ nGroupIndex = this.groupIndex;
+ aItemGroups = this.parent.getItemGroups();
+
+
+ if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
+
+ oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
+ (this.index-1));
+
+ }
+ else {
+
+ if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
+
+ nPreviousGroupIndex = nGroupIndex - 1;
+
+ }
+ else {
+
+ nPreviousGroupIndex = aItemGroups.length - 1;
+
+ }
+
+ aPreviousGroup = getPreviousArrayItem(aItemGroups,
+ nPreviousGroupIndex);
+
+ oPreviousItem = getPreviousArrayItem(aPreviousGroup,
+ (aPreviousGroup.length - 1));
+
+ }
+
+ returnVal = (oPreviousItem.cfg.getProperty(_DISABLED) ||
+ oPreviousItem.element.style.display == _NONE) ?
+ oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
+
+ }
+
+ return returnVal;
+
+ },
+
+
+ /**
+ * @method focus
+ * @description Causes the menu item to receive the focus and fires the
+ * focus event.
+ */
+ focus: function () {
+
+ var oParent = this.parent,
+ oAnchor = this._oAnchor,
+ oActiveItem = oParent.activeItem;
+
+
+ function setFocus() {
+
+ try {
+
+ if (!(UA.ie && !document.hasFocus())) {
+
+ if (oActiveItem) {
+
+ oActiveItem.blurEvent.fire();
+
+ }
+
+ oAnchor.focus();
+
+ this.focusEvent.fire();
+
+ }
+
+ }
+ catch(e) {
+
+ }
+
+ }
+
+
+ if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
+ this.element.style.display != _NONE) {
+
+
+ /*
+ Setting focus via a timer fixes a race condition in Firefox, IE
+ and Opera where the browser viewport jumps as it trys to
+ position and focus the menu.
+ */
+
+ Lang.later(0, this, setFocus);
+
+ }
+
+ },
+
+
+ /**
+ * @method blur
+ * @description Causes the menu item to lose focus and fires the
+ * blur event.
+ */
+ blur: function () {
+
+ var oParent = this.parent;
+
+ if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
+
+ Lang.later(0, this, function () {
+
+ try {
+
+ this._oAnchor.blur();
+ this.blurEvent.fire();
+
+ }
+ catch (e) {
+
+ }
+
+ }, 0);
+
+ }
+
+ },
+
+
+ /**
+ * @method hasFocus
+ * @description Returns a boolean indicating whether or not the menu item
+ * has focus.
+ * @return {Boolean}
+ */
+ hasFocus: function () {
+
+ return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
+
+ },
+
+
+ /**
+ * @method destroy
+ * @description Removes the menu item's <code><li></code> element
+ * from its parent <code><ul></code> element.
+ */
+ destroy: function () {
+
+ var oEl = this.element,
+ oSubmenu,
+ oParentNode,
+ aEventData,
+ i;
+
+
+ if (oEl) {
+
+
+ // If the item has a submenu, destroy it first
+
+ oSubmenu = this.cfg.getProperty(_SUBMENU);
+
+ if (oSubmenu) {
+
+ oSubmenu.destroy();
+
+ }
+
+
+ // Remove the element from the parent node
+
+ oParentNode = oEl.parentNode;
+
+ if (oParentNode) {
+
+ oParentNode.removeChild(oEl);
+
+ this.destroyEvent.fire();
+
+ }
+
+
+ // Remove CustomEvent listeners
+
+ i = EVENT_TYPES.length - 1;
+
+ do {
+
+ aEventData = EVENT_TYPES[i];
+
+ this[aEventData[0]].unsubscribeAll();
+
+ }
+ while (i--);
+
+
+ this.cfg.configChangedEvent.unsubscribeAll();
+
+ }
+
+ },
+
+
+ /**
+ * @method toString
+ * @description Returns a string representing the menu item.
+ * @return {String}
+ */
+ toString: function () {
+
+ var sReturnVal = _MENUITEM,
+ sId = this.id;
+
+ if (sId) {
+
+ sReturnVal += (_SPACE + sId);
+
+ }
+
+ return sReturnVal;
+
+ }
+
+};
+
+Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
+
+})();
+(function () {
+
+ var _XY = "xy",
+ _MOUSEDOWN = "mousedown",
+ _CONTEXTMENU = "ContextMenu",
+ _SPACE = " ";
+
+/**
+* Creates a list of options or commands which are made visible in response to
+* an HTML element's "contextmenu" event ("mousedown" for Opera).
+*
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><div></code> element of the context 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
+* context 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 context 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 context menu.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the context menu. See configuration class documentation
+* for more details.
+* @class ContextMenu
+* @constructor
+* @extends YAHOO.widget.Menu
+* @namespace YAHOO.widget
+*/
+YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
+
+ YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
+
+};
+
+
+var Event = YAHOO.util.Event,
+ UA = YAHOO.env.ua,
+ ContextMenu = YAHOO.widget.ContextMenu,
+
+
+
+ /**
+ * Constant representing the name of the ContextMenu's events
+ * @property EVENT_TYPES
+ * @private
+ * @final
+ * @type Object
+ */
+ EVENT_TYPES = {
+
+ "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
+ "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
+ "CLICK": "click"
+
+ },
+
+
+ /**
+ * Constant representing the ContextMenu's configuration properties
+ * @property DEFAULT_CONFIG
+ * @private
+ * @final
+ * @type Object
+ */
+ TRIGGER_CONFIG = {
+ key: "trigger",
+ suppressEvent: true
+ };
+
+
+/**
+* @method position
+* @description "beforeShow" event handler used to position the contextmenu.
+* @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 {Array} p_aPos Array representing the xy position for the context menu.
+*/
+function position(p_sType, p_aArgs, p_aPos) {
+
+ this.cfg.setProperty(_XY, p_aPos);
+
+ this.beforeShowEvent.unsubscribe(position, p_aPos);
+
+}
+
+
+YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
+
+
+
+// Private properties
+
+
+/**
+* @property _oTrigger
+* @description Object reference to the current value of the "trigger"
+* configuration property.
+* @default null
+* @private
+* @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
+* l-one-html.html#ID-58190037">HTMLElement</a>|Array
+*/
+_oTrigger: null,
+
+
+/**
+* @property _bCancelled
+* @description Boolean indicating if the display of the context menu should
+* be cancelled.
+* @default false
+* @private
+* @type Boolean
+*/
+_bCancelled: false,
+
+
+
+// Public properties
+
+
+/**
+* @property contextEventTarget
+* @description Object reference for the HTML element that was the target of the
+* "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
+* the context menu.
+* @default null
+* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
+* html.html#ID-58190037">HTMLElement</a>
+*/
+contextEventTarget: null,
+
+
+
+// Events
+
+
+/**
+* @event triggerContextMenuEvent
+* @description Custom Event wrapper for the "contextmenu" DOM event
+* ("mousedown" for Opera) fired by the element(s) that trigger the display of
+* the context menu.
+*/
+triggerContextMenuEvent: null,
+
+
+
+/**
+* @method init
+* @description The ContextMenu 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 context 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 context 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 context 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 context menu.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the context menu. See configuration class documentation
+* for more details.
+*/
+init: function(p_oElement, p_oConfig) {
+
+
+ // Call the init of the superclass (YAHOO.widget.Menu)
+
+ ContextMenu.superclass.init.call(this, p_oElement);
+
+
+ this.beforeInitEvent.fire(ContextMenu);
+
+
+ if (p_oConfig) {
+
+ this.cfg.applyConfig(p_oConfig, true);
+
+ }
+
+ this.initEvent.fire(ContextMenu);
+
+},
+
+
+/**
+* @method initEvents
+* @description Initializes the custom events for the context menu.
+*/
+initEvents: function() {
+
+ ContextMenu.superclass.initEvents.call(this);
+
+ // Create custom events
+
+ this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
+
+ this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
+
+},
+
+
+/**
+* @method cancel
+* @description Cancels the display of the context menu.
+*/
+cancel: function() {
+
+ this._bCancelled = true;
+
+},
+
+
+
+// Private methods
+
+
+/**
+* @method _removeEventHandlers
+* @description Removes all of the DOM event handlers from the HTML element(s)
+* whose "context menu" event ("click" for Opera) trigger the display of
+* the context menu.
+* @private
+*/
+_removeEventHandlers: function() {
+
+ var oTrigger = this._oTrigger;
+
+
+ // Remove the event handlers from the trigger(s)
+
+ if (oTrigger) {
+
+ Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
+
+ if (UA.opera) {
+
+ Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
+
+ }
+
+ }
+
+},
+
+
+
+// Private event handlers
+
+
+
+/**
+* @method _onTriggerClick
+* @description "click" event handler for the HTML element(s) identified as the
+* "trigger" for the context menu. Used to cancel default behaviors in Opera.
+* @private
+* @param {Event} p_oEvent Object representing the DOM event object passed back
+* by the event utility (YAHOO.util.Event).
+* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
+* menu that is handling the event.
+*/
+_onTriggerClick: function(p_oEvent, p_oMenu) {
+
+ if (p_oEvent.ctrlKey) {
+
+ Event.stopEvent(p_oEvent);
+
+ }
+
+},
+
+
+/**
+* @method _onTriggerContextMenu
+* @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
+* element(s) that trigger the display of the context menu.
+* @private
+* @param {Event} p_oEvent Object representing the DOM event object passed back
+* by the event utility (YAHOO.util.Event).
+* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
+* menu that is handling the event.
+*/
+_onTriggerContextMenu: function(p_oEvent, p_oMenu) {
+
+ var aXY;
+
+ if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
+
+ this.contextEventTarget = Event.getTarget(p_oEvent);
+
+ this.triggerContextMenuEvent.fire(p_oEvent);
+
+
+ if (!this._bCancelled) {
+
+ /*
+ Prevent the browser's default context menu from appearing and
+ stop the propagation of the "contextmenu" event so that
+ other ContextMenu instances are not displayed.
+ */
+
+ Event.stopEvent(p_oEvent);
+
+
+ // Hide any other Menu instances that might be visible
+
+ YAHOO.widget.MenuManager.hideVisible();
+
+
+
+ // Position and display the context menu
+
+ aXY = Event.getXY(p_oEvent);
+
+
+ if (!YAHOO.util.Dom.inDocument(this.element)) {
+
+ this.beforeShowEvent.subscribe(position, aXY);
+
+ }
+ else {
+
+ this.cfg.setProperty(_XY, aXY);
+
+ }
+
+
+ this.show();
+
+ }
+
+ this._bCancelled = false;
+
+ }
+
+},
+
+
+
+// Public methods
+
+
+/**
+* @method toString
+* @description Returns a string representing the context menu.
+* @return {String}
+*/
+toString: function() {
+
+ var sReturnVal = _CONTEXTMENU,
+ sId = this.id;
+
+ if (sId) {
+
+ sReturnVal += (_SPACE + sId);
+
+ }
+
+ return sReturnVal;
+
+},
+
+
+/**
+* @method initDefaultConfig
+* @description Initializes the class's configurable properties which can be
+* changed using the context menu's Config object ("cfg").
+*/
+initDefaultConfig: function() {
+
+ ContextMenu.superclass.initDefaultConfig.call(this);
+
+ /**
+ * @config trigger
+ * @description The HTML element(s) whose "contextmenu" event ("mousedown"
+ * for Opera) trigger the display of the context menu. Can be a string
+ * representing the id attribute of the HTML element, an object reference
+ * for the HTML element, or an array of strings or HTML element references.
+ * @default null
+ * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
+ * level-one-html.html#ID-58190037">HTMLElement</a>|Array
+ */
+ this.cfg.addProperty(TRIGGER_CONFIG.key,
+ {
+ handler: this.configTrigger,
+ suppressEvent: TRIGGER_CONFIG.suppressEvent
+ }
+ );
+
+},
+
+
+/**
+* @method destroy
+* @description Removes the context menu's <code><div></code> element
+* (and accompanying child nodes) from the document.
+*/
+destroy: function() {
+
+ // Remove the DOM event handlers from the current trigger(s)
+
+ this._removeEventHandlers();
+
+
+ // Continue with the superclass implementation of this method
+
+ ContextMenu.superclass.destroy.call(this);
+
+},
+
+
+
+// Public event handlers for configuration properties
+
+
+/**
+* @method configTrigger
+* @description Event handler for when the value of the "trigger" configuration
+* property changes.
+* @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.ContextMenu} p_oMenu Object representing the context
+* menu that fired the event.
+*/
+configTrigger: function(p_sType, p_aArgs, p_oMenu) {
+
+ var oTrigger = p_aArgs[0];
+
+ if (oTrigger) {
+
+ /*
+ If there is a current "trigger" - remove the event handlers
+ from that element(s) before assigning new ones
+ */
+
+ if (this._oTrigger) {
+
+ this._removeEventHandlers();
+
+ }
+
+ this._oTrigger = oTrigger;
+
+
+ /*
+ Listen for the "mousedown" event in Opera b/c it does not
+ support the "contextmenu" event
+ */
+
+ Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
+
+
+ /*
+ Assign a "click" event handler to the trigger element(s) for
+ Opera to prevent default browser behaviors.
+ */
+
+ if (UA.opera) {
+
+ Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
+
+ }
+
+ }
+ else {
+
+ this._removeEventHandlers();
+
+ }
+
+}
+
+}); // END YAHOO.lang.extend
+
+}());
+
+
+
+/**
+* Creates an item for a context menu.
+*
+* @param {String} p_oObject String specifying the text of the context menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
+* <code><li></code> element of the context menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
+* specifying the <code><optgroup></code> element of the context
+* menu item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
+* the <code><option></code> element of the context menu item.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the context menu item. See configuration class
+* documentation for more details.
+* @class ContextMenuItem
+* @constructor
+* @extends YAHOO.widget.MenuItem
+* @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
+* are of type YAHOO.widget.MenuItem.
+*/
+YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
+(function () {
+
+ var Lang = YAHOO.lang,
+
+ // String constants
+
+ _STATIC = "static",
+ _DYNAMIC_STATIC = "dynamic," + _STATIC,
+ _DISABLED = "disabled",
+ _SELECTED = "selected",
+ _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
+ _SUBMENU = "submenu",
+ _VISIBLE = "visible",
+ _SPACE = " ",
+ _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
+ _MENUBAR = "MenuBar";
+
+/**
+* Horizontal collection of items, each of which can contain a submenu.
+*
+* @param {String} p_oElement String specifying the id attribute of the
+* <code><div></code> element of the menu bar.
+* @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 bar.
+* @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 bar.
+* @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 bar.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu bar. See configuration class documentation for
+* more details.
+* @class MenuBar
+* @constructor
+* @extends YAHOO.widget.Menu
+* @namespace YAHOO.widget
+*/
+YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
+
+ YAHOO.widget.MenuBar.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 Event = YAHOO.util.Event,
+ MenuBar = YAHOO.widget.MenuBar,
+
+ POSITION_CONFIG = {
+ key: "position",
+ value: _STATIC,
+ validator: checkPosition,
+ supercedes: [_VISIBLE]
+ },
+
+ SUBMENU_ALIGNMENT_CONFIG = {
+ key: "submenualignment",
+ value: ["tl","bl"]
+ },
+
+ AUTO_SUBMENU_DISPLAY_CONFIG = {
+ key: _AUTO_SUBMENU_DISPLAY,
+ value: false,
+ validator: Lang.isBoolean,
+ suppressEvent: true
+ },
+
+ SUBMENU_TOGGLE_REGION_CONFIG = {
+ key: _SUBMENU_TOGGLE_REGION,
+ value: false,
+ validator: Lang.isBoolean
+ };
+
+
+
+Lang.extend(MenuBar, YAHOO.widget.Menu, {
+
+/**
+* @method init
+* @description The MenuBar 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 bar.
+* @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 bar.
+* @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 bar.
+* @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 bar.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu bar. See configuration class documentation for
+* more details.
+*/
+init: function(p_oElement, p_oConfig) {
+
+ if(!this.ITEM_TYPE) {
+
+ this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
+
+ }
+
+
+ // Call the init of the superclass (YAHOO.widget.Menu)
+
+ MenuBar.superclass.init.call(this, p_oElement);
+
+
+ this.beforeInitEvent.fire(MenuBar);
+
+
+ if(p_oConfig) {
+
+ this.cfg.applyConfig(p_oConfig, true);
+
+ }
+
+ this.initEvent.fire(MenuBar);
+
+},
+
+
+
+// Constants
+
+
+/**
+* @property CSS_CLASS_NAME
+* @description String representing the CSS class(es) to be applied to the menu
+* bar's <code><div></code> element.
+* @default "yuimenubar"
+* @final
+* @type String
+*/
+CSS_CLASS_NAME: "yuimenubar",
+
+
+/**
+* @property SUBMENU_TOGGLE_REGION_WIDTH
+* @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
+* display of the MenuBarItem's submenu.
+* @default 20
+* @final
+* @type Number
+*/
+SUBMENU_TOGGLE_REGION_WIDTH: 20,
+
+
+// Protected event handlers
+
+
+/**
+* @method _onKeyDown
+* @description "keydown" Custom Event handler for the menu bar.
+* @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.MenuBar} p_oMenuBar Object representing the menu bar
+* that fired the event.
+*/
+_onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
+
+ var oEvent = p_aArgs[0],
+ oItem = p_aArgs[1],
+ oSubmenu,
+ oItemCfg,
+ oNextItem;
+
+
+ if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
+
+ oItemCfg = oItem.cfg;
+
+ switch(oEvent.keyCode) {
+
+ case 37: // Left arrow
+ case 39: // Right arrow
+
+ if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
+
+ oItemCfg.setProperty(_SELECTED, true);
+
+ }
+ else {
+
+ oNextItem = (oEvent.keyCode == 37) ?
+ oItem.getPreviousEnabledSibling() :
+ oItem.getNextEnabledSibling();
+
+ if(oNextItem) {
+
+ this.clearActiveItem();
+
+ oNextItem.cfg.setProperty(_SELECTED, true);
+
+ oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
+
+ if(oSubmenu) {
+
+ oSubmenu.show();
+ oSubmenu.setInitialFocus();
+
+ }
+ else {
+ oNextItem.focus();
+ }
+
+ }
+
+ }
+
+ Event.preventDefault(oEvent);
+
+ break;
+
+ case 40: // Down arrow
+
+ if(this.activeItem != oItem) {
+
+ this.clearActiveItem();
+
+ oItemCfg.setProperty(_SELECTED, true);
+ oItem.focus();
+
+ }
+
+ oSubmenu = oItemCfg.getProperty(_SUBMENU);
+
+ if(oSubmenu) {
+
+ if(oSubmenu.cfg.getProperty(_VISIBLE)) {
+
+ oSubmenu.setInitialSelection();
+ oSubmenu.setInitialFocus();
+
+ }
+ else {
+
+ oSubmenu.show();
+ oSubmenu.setInitialFocus();
+
+ }
+
+ }
+
+ Event.preventDefault(oEvent);
+
+ break;
+
+ }
+
+ }
+
+
+ if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
+
+ oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
+
+ if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
+
+ oSubmenu.hide();
+ this.activeItem.focus();
+
+ }
+ else {
+
+ this.activeItem.cfg.setProperty(_SELECTED, false);
+ this.activeItem.blur();
+
+ }
+
+ Event.preventDefault(oEvent);
+
+ }
+
+},
+
+
+/**
+* @method _onClick
+* @description "click" event handler for the menu bar.
+* @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.
+* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
+* that fired the event.
+*/
+_onClick: function(p_sType, p_aArgs, p_oMenuBar) {
+
+ MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
+
+ var oItem = p_aArgs[1],
+ bReturnVal = true,
+ oItemEl,
+ oEvent,
+ oTarget,
+ oActiveItem,
+ oConfig,
+ oSubmenu,
+ nMenuItemX,
+ nToggleRegion;
+
+
+ var toggleSubmenuDisplay = function () {
+
+ if(oSubmenu.cfg.getProperty(_VISIBLE)) {
+
+ oSubmenu.hide();
+
+ }
+ else {
+
+ oSubmenu.show();
+
+ }
+
+ };
+
+
+ if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
+
+ oEvent = p_aArgs[0];
+ oTarget = Event.getTarget(oEvent);
+ oActiveItem = this.activeItem;
+ oConfig = this.cfg;
+
+
+ // Hide any other submenus that might be visible
+
+ if(oActiveItem && oActiveItem != oItem) {
+
+ this.clearActiveItem();
+
+ }
+
+
+ oItem.cfg.setProperty(_SELECTED, true);
+
+
+ // Show the submenu for the item
+
+ oSubmenu = oItem.cfg.getProperty(_SUBMENU);
+
+
+ if(oSubmenu) {
+
+ oItemEl = oItem.element;
+ nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
+ nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
+
+ if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
+
+ if (Event.getPageX(oEvent) > nToggleRegion) {
+
+ toggleSubmenuDisplay();
+
+ Event.preventDefault(oEvent);
+
+ /*
+ Return false so that other click event handlers are not called when the
+ user clicks inside the toggle region.
+ */
+ bReturnVal = false;
+
+ }
+
+ }
+ else {
+
+ toggleSubmenuDisplay();
+
+ }
+
+ }
+
+ }
+
+
+ return bReturnVal;
+
+},
+
+
+
+// Public methods
+
+/**
+* @method configSubmenuToggle
+* @description Event handler for when the "submenutoggleregion" configuration property of
+* a MenuBar changes.
+* @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.
+*/
+configSubmenuToggle: function (p_sType, p_aArgs) {
+
+ var bSubmenuToggle = p_aArgs[0];
+
+ if (bSubmenuToggle) {
+
+ this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
+
+ }
+
+},
+
+
+/**
+* @method toString
+* @description Returns a string representing the menu bar.
+* @return {String}
+*/
+toString: function() {
+
+ var sReturnVal = _MENUBAR,
+ sId = this.id;
+
+ if(sId) {
+
+ sReturnVal += (_SPACE + sId);
+
+ }
+
+ return sReturnVal;
+
+},
+
+
+/**
+* @description Initializes the class's configurable properties which can be
+* changed using the menu bar's Config object ("cfg").
+* @method initDefaultConfig
+*/
+initDefaultConfig: function() {
+
+ MenuBar.superclass.initDefaultConfig.call(this);
+
+ var oConfig = this.cfg;
+
+ // Add configuration properties
+
+
+ /*
+ Set the default value for the "position" configuration property
+ to "static" by re-adding the property.
+ */
+
+
+ /**
+ * @config position
+ * @description String indicating how a menu bar should be positioned on the
+ * screen. Possible values are "static" and "dynamic." Static menu bars
+ * are visible by default and reside in the normal flow of the document
+ * (CSS position: static). Dynamic menu bars are hidden by default, reside
+ * out of the normal flow of the document (CSS position: absolute), and can
+ * overlay other elements on the screen.
+ * @default static
+ * @type String
+ */
+ oConfig.addProperty(
+ POSITION_CONFIG.key,
+ {
+ handler: this.configPosition,
+ value: POSITION_CONFIG.value,
+ validator: POSITION_CONFIG.validator,
+ supercedes: POSITION_CONFIG.supercedes
+ }
+ );
+
+
+ /*
+ Set the default value for the "submenualignment" configuration property
+ to ["tl","bl"] by re-adding the property.
+ */
+
+ /**
+ * @config submenualignment
+ * @description Array defining how submenus should be aligned to their
+ * parent menu bar item. The format is: [itemCorner, submenuCorner].
+ * @default ["tl","bl"]
+ * @type Array
+ */
+ oConfig.addProperty(
+ SUBMENU_ALIGNMENT_CONFIG.key,
+ {
+ value: SUBMENU_ALIGNMENT_CONFIG.value,
+ suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
+ }
+ );
+
+
+ /*
+ Change the default value for the "autosubmenudisplay" configuration
+ property to "false" by re-adding the property.
+ */
+
+ /**
+ * @config autosubmenudisplay
+ * @description Boolean indicating if submenus are automatically made
+ * visible when the user mouses over the menu bar's items.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ AUTO_SUBMENU_DISPLAY_CONFIG.key,
+ {
+ value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
+ validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
+ suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
+ }
+ );
+
+
+ /**
+ * @config submenutoggleregion
+ * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
+ * display of a submenu. The default width of the region is determined by the value of the
+ * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
+ * configuration property will be set to false, and any click event listeners will not be
+ * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
+ * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
+ * standard behavior.
+ * @default false
+ * @type Boolean
+ */
+ oConfig.addProperty(
+ SUBMENU_TOGGLE_REGION_CONFIG.key,
+ {
+ value: SUBMENU_TOGGLE_REGION_CONFIG.value,
+ validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
+ handler: this.configSubmenuToggle
+ }
+ );
+
+}
+
+}); // END YAHOO.lang.extend
+
+}());
+
+
+
+/**
+* Creates an item for a menu bar.
+*
+* @param {String} p_oObject String specifying the text of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
+* <code><li></code> element of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
+* specifying the <code><optgroup></code> element of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
+* the <code><option></code> element of the menu bar item.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu bar item. See configuration class documentation
+* for more details.
+* @class MenuBarItem
+* @constructor
+* @extends YAHOO.widget.MenuItem
+*/
+YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
+
+ YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
+
+};
+
+YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
+
+
+
+/**
+* @method init
+* @description The MenuBarItem 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_oObject String specifying the text of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
+* <code><li></code> element of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
+* specifying the <code><optgroup></code> element of the menu bar item.
+* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
+* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
+* the <code><option></code> element of the menu bar item.
+* @param {Object} p_oConfig Optional. Object literal specifying the
+* configuration for the menu bar item. See configuration class documentation
+* for more details.
+*/
+init: function(p_oObject, p_oConfig) {
+
+ if(!this.SUBMENU_TYPE) {
+
+ this.SUBMENU_TYPE = YAHOO.widget.Menu;
+
+ }
+
+
+ /*
+ Call the init of the superclass (YAHOO.widget.MenuItem)
+ Note: We don't pass the user config in here yet
+ because we only want it executed once, at the lowest
+ subclass level.
+ */
+
+ YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
+
+
+ var oConfig = this.cfg;
+
+ if(p_oConfig) {
+
+ oConfig.applyConfig(p_oConfig, true);
+
+ }
+
+ oConfig.fireQueue();
+
+},
+
+
+
+// Constants
+
+
+/**
+* @property CSS_CLASS_NAME
+* @description String representing the CSS class(es) to be applied to the
+* <code><li></code> element of the menu bar item.
+* @default "yuimenubaritem"
+* @final
+* @type String
+*/
+CSS_CLASS_NAME: "yuimenubaritem",
+
+
+/**
+* @property CSS_LABEL_CLASS_NAME
+* @description String representing the CSS class(es) to be applied to the
+* menu bar item's <code><a></code> element.
+* @default "yuimenubaritemlabel"
+* @final
+* @type String
+*/
+CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
+
+
+
+// Public methods
+
+
+/**
+* @method toString
+* @description Returns a string representing the menu bar item.
+* @return {String}
+*/
+toString: function() {
+
+ var sReturnVal = "MenuBarItem";
+
+ if(this.cfg && this.cfg.getProperty("text")) {
+
+ sReturnVal += (": " + this.cfg.getProperty("text"));
+
+ }
+
+ return sReturnVal;
+
+}
+
+}); // END YAHOO.lang.extend
+YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.7.0", build: "1799"});