Index: openacs-4/packages/ajaxhelper/www/resources/yui/menu/menu-debug.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ajaxhelper/www/resources/yui/menu/menu-debug.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/ajaxhelper/www/resources/yui/menu/menu-debug.js 25 Dec 2006 16:40:03 -0000 1.2 +++ openacs-4/packages/ajaxhelper/www/resources/yui/menu/menu-debug.js 8 Sep 2007 14:22:07 -0000 1.3 @@ -1,10807 +1,8824 @@ -/* -Copyright (c) 2006, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.com/yui/license.txt -version: 0.12.1 -*/ - - - -/** -* @module menu -* @description

The Menu Library features a collection of widgets that make -* it easy to add menus to your website or web application. With the Menu -* Library you can create website fly-out menus, customized context menus, or -* application-style menu bars with just a small amount of scripting.

-* -* @title Menu Library -* @namespace YAHOO.widget -* @requires Event, Dom, Container -*/ -(function() { - -var Dom = YAHOO.util.Dom, - Event = YAHOO.util.Event; - -/** -* 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 menu items - - m_oItems = {}, - - - // Collection of visible menus - - m_oVisibleMenus = {}, - - - // Logger - - m_oLogger = new YAHOO.widget.LogWriter(this.toString()), - - - me = this; - - - // Private methods - - - /** - * @method addItem - * @description Adds an item to the collection of known menu items. - * @private - * @param {YAHOO.widget.MenuItem} p_oItem Object specifying the MenuItem - * instance to be added. - */ - function addItem(p_oItem) { - - var sYUIId = Dom.generateId(); - - if(p_oItem && m_oItems[sYUIId] != p_oItem) { - - p_oItem.element.setAttribute("yuiid", sYUIId); - - m_oItems[sYUIId] = p_oItem; - - p_oItem.destroyEvent.subscribe(onItemDestroy, p_oItem); - - m_oLogger.log("Item: " + - p_oItem.toString() + " successfully registered."); - - } - - } - - - /** - * @method removeItem - * @description Removes an item from the collection of known menu items. - * @private - * @param {YAHOO.widget.MenuItem} p_oItem Object specifying the MenuItem - * instance to be removed. - */ - function removeItem(p_oItem) { - - var sYUIId = p_oItem.element.getAttribute("yuiid"); - - if(sYUIId && m_oItems[sYUIId]) { - - delete m_oItems[sYUIId]; - - m_oLogger.log("Item: " + - p_oItem.toString() + " successfully unregistered."); - - } - - } - - - /** - * @method getMenuRootElement - * @description Finds the root DIV node of a menu or the root LI node of a - * menu item. - * @private - * @param {HTMLElement} p_oElement Object specifying - * an HTML element. - */ - function getMenuRootElement(p_oElement) { - - var oParentNode; - - 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, "bd") && - oParentNode && - oParentNode.tagName && - oParentNode.tagName.toUpperCase() == "DIV" - ) { - - return oParentNode; - - } - else { - - return p_oElement; - - } - - break; - - case "LI": - - return p_oElement; - - default: - - oParentNode = p_oElement.parentNode; - - if(oParentNode) { - - return getMenuRootElement(oParentNode); - - } - - break; - - } - - } - - } - - - - // 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), - oMenuItem, - oMenu; - - - if(oElement) { - - var sTagName = oElement.tagName.toUpperCase(); - - if(sTagName == "LI") { - - var sYUIId = oElement.getAttribute("yuiid"); - - if(sYUIId) { - - oMenuItem = m_oItems[sYUIId]; - oMenu = oMenuItem.parent; - - } - - } - else if(sTagName == "DIV") { - - if(oElement.id) { - - oMenu = m_oMenus[oElement.id]; - - } - - } - - } - - if(oMenu) { - - // Map of DOM event names to CustomEvent names - - var oEventTypes = { - "click": "clickEvent", - "mousedown": "mouseDownEvent", - "mouseup": "mouseUpEvent", - "mouseover": "mouseOverEvent", - "mouseout": "mouseOutEvent", - "keydown": "keyDownEvent", - "keyup": "keyUpEvent", - "keypress": "keyPressEvent" - }, - - sCustomEventType = oEventTypes[p_oEvent.type]; - - - // Fire the Custom Even 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 - */ - - var oActiveItem; - - for(var i in m_oMenus) { - - if(m_oMenus.hasOwnProperty(i)) { - - oMenu = m_oMenus[i]; - - if( - oMenu.cfg.getProperty("clicktohide") && - oMenu.cfg.getProperty("position") == "dynamic" - ) { - - oMenu.hide(); - - } - else { - - oMenu.clearActiveItem(true); - - } - - } - - } - - } - - } - - - /** - * @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 Object representing the menu that - * fired the event. - */ - function onMenuDestroy(p_sType, p_aArgs, p_oMenu) { - - if(p_oMenu && m_oMenus[p_oMenu.id]) { - - delete m_oMenus[p_oMenu.id]; - - m_oLogger.log("Menu: " + - p_oMenu.toString() + " successfully unregistered."); - - } - - } - - - /** - * @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. - * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item - * that fired the event. - */ - function onItemDestroy(p_sType, p_aArgs, p_oItem) { - - var sYUIId = p_oItem.element.getAttribute("yuiid"); - - if(sYUIId) { - - delete m_oItems[sYUIId]; - - } - - } - - - /** - * @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. - * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - * fired the event. - */ - function onMenuVisibleConfigChange(p_sType, p_aArgs, p_oMenu) { - - var bVisible = p_aArgs[0]; - - if(bVisible) { - - m_oVisibleMenus[p_oMenu.id] = p_oMenu; - - m_oLogger.log("Menu: " + - p_oMenu.toString() + - " registered with the collection of visible menus."); - - } - else if(m_oVisibleMenus[p_oMenu.id]) { - - delete m_oVisibleMenus[p_oMenu.id]; - - m_oLogger.log("Menu: " + - p_oMenu.toString() + - " unregistered from the collection of visible menus."); - - } - - } - - - /** - * @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) { - - addItem(p_aArgs[0]); - - } - - - /** - * @method onItemRemoved - * @description "itemremoved" 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 onItemRemoved(p_sType, p_aArgs) { - - removeItem(p_aArgs[0]); - - } - - - - 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) { - - if(p_oMenu && p_oMenu.id && !m_oMenus[p_oMenu.id]) { - - m_oMenus[p_oMenu.id] = p_oMenu; - - - if(!m_bInitializedEventHandlers) { - - var oDoc = document; - - Event.addListener(oDoc, "mouseover", onDOMEvent, me, true); - Event.addListener(oDoc, "mouseout", onDOMEvent, me, true); - Event.addListener(oDoc, "mousedown", onDOMEvent, me, true); - Event.addListener(oDoc, "mouseup", onDOMEvent, me, true); - Event.addListener(oDoc, "click", onDOMEvent, me, true); - Event.addListener(oDoc, "keydown", onDOMEvent, me, true); - Event.addListener(oDoc, "keyup", onDOMEvent, me, true); - Event.addListener(oDoc, "keypress", onDOMEvent, me, true); - - m_bInitializedEventHandlers = true; - - m_oLogger.log("DOM event handlers initialized."); - - } - - p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, me); - - p_oMenu.cfg.subscribeToConfigEvent( - "visible", - onMenuVisibleConfigChange, - p_oMenu - ); - - p_oMenu.itemAddedEvent.subscribe(onItemAdded); - p_oMenu.itemRemovedEvent.subscribe(onItemRemoved); - - m_oLogger.log("Menu: " + - p_oMenu.toString() + " successfully registered."); - - } - - }, - - - /** - * @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) { - - if(p_oMenu && m_oMenus[p_oMenu.id]) { - - delete m_oMenus[p_oMenu.id]; - - m_oLogger.log("Menu: " + - p_oMenu.toString() + " successfully unregistered."); - - } - - }, - - - /** - * @method hideVisible - * @description Hides all visible, dynamically positioned menus. - */ - hideVisible: function() { - - var oMenu; - - for(var i in m_oVisibleMenus) { - - if(m_oVisibleMenus.hasOwnProperty(i)) { - - oMenu = m_oVisibleMenus[i]; - - if(oMenu.cfg.getProperty("position") == "dynamic") { - - oMenu.hide(); - - } - - } - - } - - }, - - - /** - * @method getMenus - * @description Returns an array of all menus registered with the - * menu manger. - * @return {Array} - */ - 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 menu to - * be retrieved. - * @return {YAHOO.widget.Menu} - */ - getMenu: function(p_sId) { - - if(m_oMenus[p_sId]) { - - return m_oMenus[p_sId]; - - } - - }, - - - /** - * @method toString - * @description Returns a string representing the menu manager. - * @return {String} - */ - toString: function() { - - return ("MenuManager"); - - } - - }; - -}(); - -})(); - - - - - -(function() { - - - -var Dom = YAHOO.util.Dom, - - Event = YAHOO.util.Event; - - - - - -/** - -* 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 - -* <div> element of the menu. - -* @param {String} p_oElement String specifying the id attribute of the - -* <select> element to be used as the data source - -* for the menu. - -* @param {HTMLDivElement} p_oElement Object - -* specifying the <div> element of the menu. - -* @param {HTMLSelectElement} p_oElement - -* Object specifying the <select> 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 - - ); - - - -}; - - - -YAHOO.extend(YAHOO.widget.Menu, YAHOO.widget.Overlay, { - - - - - - - -// Constants - - - - - -/** - -* @property CSS_CLASS_NAME - -* @description String representing the CSS class(es) to be applied to the - -* menu's <div> 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 <li> element, - -* <optgroup> element or <option>) - -* 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", - - - - - - - -// Private properties - - - - - -/** - -* @property _nHideDelayId - -* @description Number representing the time-out setting used to cancel the - -* hiding of a menu. - -* @default null - -* @private - -* @type Number - -*/ - -_nHideDelayId: null, - - - - - -/** - -* @property _nShowDelayId - -* @description Number representing the time-out setting used to cancel the - -* showing of a menu. - -* @default null - -* @private - -* @type Number - -*/ - -_nShowDelayId: null, - - - - - -/** - -* @property _hideDelayEventHandlersAssigned - -* @description Boolean indicating if the "mouseover" and "mouseout" event - -* handlers used for hiding the menu via a call to "window.setTimeout" have - -* already been assigned. - -* @default false - -* @private - -* @type Boolean - -*/ - -_hideDelayEventHandlersAssigned: 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 Array of menu items. - -* @default [] - -* @private - -* @type Array - -*/ - -_aItemGroups: null, - - - - - -/** - -* @property _aListElements - -* @description Array of <ul> elements, each of which is - -* the parent node for each item's <li> element. - -* @default [] - -* @private - -* @type Array - -*/ - -_aListElements: 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 focus. - -* @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 - -* <select> or <div>) used to - -* create the menu. - -* @default null - -* @type HTMLSelectElement|HTMLDivElement - -*/ - -srcElement: null, - - - - - - - -// Events - - - - - -/** - -* @event mouseOverEvent - -* @description Fires when the mouse has entered the menu. Passes back - -* the DOM Event object as an argument. - -*/ - -mouseOverEvent: null, - - - - - -/** - -* @event mouseOutEvent - -* @description Fires when the mouse has left the menu. Passes back the DOM - -* Event object as an argument. - -* @type YAHOO.util.CustomEvent - -*/ - -mouseOutEvent: null, - - - - - -/** - -* @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 - -*/ - -mouseDownEvent: null, - - - - - -/** - -* @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 - -*/ - -mouseUpEvent: null, - - - - - -/** - -* @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 - -*/ - -clickEvent: null, - - - - - -/** - -* @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 - -*/ - -keyPressEvent: null, - - - - - -/** - -* @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 - -*/ - -keyDownEvent: null, - - - - - -/** - -* @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 - -*/ - -keyUpEvent: null, - - - - - -/** - -* @event itemAddedEvent - -* @description Fires when an item is added to the menu. - -* @type YAHOO.util.CustomEvent - -*/ - -itemAddedEvent: null, - - - - - -/** - -* @event itemRemovedEvent - -* @description Fires when an item is removed to the menu. - -* @type YAHOO.util.CustomEvent - -*/ - -itemRemovedEvent: null, - - - - - -/** - -* @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 - -* <div> element of the menu. - -* @param {String} p_oElement String specifying the id attribute of the - -* <select> element to be used as the data source - -* for the menu. - -* @param {HTMLDivElement} p_oElement Object - -* specifying the <div> element of the menu. - -* @param {HTMLSelectElement} p_oElement - -* Object specifying the <select> 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(typeof p_oElement == "string") { - - - - oElement = document.getElementById(p_oElement); - - - - } - - else if(p_oElement.tagName) { - - - - oElement = p_oElement; - - - - } - - - - - - if(oElement && oElement.tagName) { - - - - switch(oElement.tagName.toUpperCase()) { - - - - case "DIV": - - - - 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. - - */ - - - - YAHOO.widget.Menu.superclass.init.call(this, oElement); - - - - this.beforeInitEvent.fire(YAHOO.widget.Menu); - - - - this.logger = new YAHOO.widget.LogWriter(this.toString()); - - - - this.logger.log("Source element: " + this.srcElement.tagName); - - - - 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. - - */ - - - - YAHOO.widget.Menu.superclass.init.call(this, Dom.generateId()); - - - - this.beforeInitEvent.fire(YAHOO.widget.Menu); - - - - this.logger = new YAHOO.widget.LogWriter(this.toString()); - - - - this.logger.log("Source element: " + this.srcElement.tagName); - - - - 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. - - */ - - - - YAHOO.widget.Menu.superclass.init.call(this, p_oElement); - - - - this.beforeInitEvent.fire(YAHOO.widget.Menu); - - - - this.logger = new YAHOO.widget.LogWriter(this.toString()); - - - - this.logger.log("No source element found. " + - - "Created element with id: " + this.id); - - - - } - - - - - - if(this.element) { - - - - var oEl = this.element; - - - - Dom.addClass(oEl, this.CSS_CLASS_NAME); - - - - - - // Subscribe to Custom Events - - - - this.initEvent.subscribe(this._onInit, this, true); - - this.beforeRenderEvent.subscribe(this._onBeforeRender, this, true); - - this.renderEvent.subscribe(this._onRender, this, true); - - this.beforeShowEvent.subscribe(this._onBeforeShow, this, true); - - this.showEvent.subscribe(this._onShow, this, true); - - this.beforeHideEvent.subscribe(this._onBeforeHide, this, true); - - this.mouseOverEvent.subscribe(this._onMouseOver, this, true); - - this.mouseOutEvent.subscribe(this._onMouseOut, this, true); - - this.clickEvent.subscribe(this._onClick, this, true); - - this.keyDownEvent.subscribe(this._onKeyDown, this, true); - - - - YAHOO.widget.Module.textResizeEvent.subscribe( - - this._onTextResize, - - this, - - true - - ); - - - - - - if(p_oConfig) { - - - - this.cfg.applyConfig(p_oConfig, true); - - - - } - - - - - - // Register the Menu instance with the MenuManager - - - - YAHOO.widget.MenuManager.addMenu(this); - - - - - - this.initEvent.fire(YAHOO.widget.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 oNode; - - - - if(this.srcElement.tagName == "DIV") { - - - - /* - - Populate the collection of item groups and item - - group titles - - */ - - - - oNode = this.body.firstChild; - - - - var 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": - - - - 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; - - - - this.logger.log("Searching DOM for items to initialize."); - - - - if(this.srcElement.tagName) { - - - - var sSrcElementTagName = this.srcElement.tagName.toUpperCase(); - - - - - - switch(sSrcElementTagName) { - - - - case "DIV": - - - - if(this._aListElements.length > 0) { - - - - this.logger.log("Found " + - - this._aListElements.length + - - " item groups to initialize."); - - - - var i = this._aListElements.length - 1; - - - - do { - - - - oNode = this._aListElements[i].firstChild; - - - - this.logger.log("Scanning " + - - this._aListElements[i].childNodes.length + - - " child nodes for items to initialize."); - - - - do { - - - - if( - - oNode && - - oNode.tagName && - - oNode.tagName.toUpperCase() == "LI" - - ) { - - - - this.logger.log("Initializing " + - - oNode.tagName + " node."); - - - - this.addItem( - - new this.ITEM_TYPE( - - oNode, - - { parent: this } - - ), - - i - - ); - - - - } - - - - } - - while((oNode = oNode.nextSibling)); - - - - } - - while(i--); - - - - } - - - - break; - - - - case "SELECT": - - - - this.logger.log("Scanning " + - - this.srcElement.childNodes.length + - - " child nodes for items to initialize."); - - - - oNode = this.srcElement.firstChild; - - - - do { - - - - if(oNode && oNode.tagName) { - - - - switch(oNode.tagName.toUpperCase()) { - - - - case "OPTGROUP": - - case "OPTION": - - - - this.logger.log("Initializing " + - - oNode.tagName + " node."); - - - - 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 nGroups = this._aItemGroups.length, - - oItem, - - aItemGroup; - - - - for(var i=0; i= 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 { - - - - - - /** - - * Returns the next sibling of an item in an array. - - * @private - - * @param {p_aArray} Array to search. - - * @param {p_nStartIndex} Number indicating the index to - - * start searching the array. - - * @return {Object} - - */ - - function getNextItemSibling(p_aArray, p_nStartIndex) { - - - - return ( - - p_aArray[p_nStartIndex] || - - getNextItemSibling( - - p_aArray, - - (p_nStartIndex+1) - - ) - - ); - - - - } - - - - - - var 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.logger.log("Item inserted." + - - " Text: " + oGroupItem.cfg.getProperty("text") + ", " + - - " Index: " + oGroupItem.index + ", " + - - " Group Index: " + oGroupItem.groupIndex); - - - - this.itemAddedEvent.fire(oGroupItem); - - - - return oGroupItem; - - - - } - - - - } - - else { - - - - var 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("groupindex", 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.logger.log("Item added." + - - " Text: " + oGroupItem.cfg.getProperty("text") + ", " + - - " Index: " + oGroupItem.index + ", " + - - " Group Index: " + oGroupItem.groupIndex); - - - - - - this.itemAddedEvent.fire(oGroupItem); - - - - return oGroupItem; - - - - } - - - - } - - - - } - - - -}, - - - - - -/** - -* @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 = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0, - - aGroup = this._getItemGroup(nGroupIndex); - - - - if(aGroup) { - - - - var 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 - - - - var 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); - - - - - - // 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); - - - - if(aGroup) { - - - - var nItems = aGroup.length, - - nItemIndex = -1; - - - - if(nItems > 0) { - - - - var i = nItems-1; - - - - do { - - - - if(aGroup[i] == p_oItem) { - - - - nItemIndex = i; - - break; - - - - } - - - - } - - while(i--); - - - - if(nItemIndex > -1) { - - - - return this._removeItemFromGroupByIndex( - - p_nGroupIndex, - - nItemIndex - - ); - - - - } - - - - } - - - - } - - - -}, - - - - - -/** - -* @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; - - - - if(nItems > 0) { - - - - var i = nItems - 1, - - oItem, - - oLI; - - - - // 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("groupindex", 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 - -* <ul> 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) { - - - - if(!this._aItemGroups[p_nIndex]) { - - - - this._aItemGroups[p_nIndex] = []; - - - - var oUL = document.createElement("ul"); - - - - this._aListElements[p_nIndex] = oUL; - - - - return this._aItemGroups[p_nIndex]; - - - - } - - - -}, - - - - - -/** - -* @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 = ((typeof p_nIndex == "number") ? p_nIndex : 0); - - - - return this._aItemGroups[nIndex]; - - - -}, - - - - - -/** - -* @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 - - ); - - - - oSubmenu.beforeShowEvent.subscribe( - - this._onSubmenuBeforeShow, - - oSubmenu, - - true - - ); - - - - oSubmenu.showEvent.subscribe( - - this._onSubmenuShow, - - oSubmenu, - - true - - ); - - - - oSubmenu.hideEvent.subscribe( - - this._onSubmenuHide, - - 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.focusEvent.subscribe(this._onMenuItemFocus, p_oItem, this); - - - - p_oItem.blurEvent.subscribe(this._onMenuItemBlur, this, true); - - - - p_oItem.cfg.configChangedEvent.subscribe( - - this._onMenuItemConfigChange, - - p_oItem, - - this - - ); - - - -}, - - - - - -/** - -* @method _getOffsetWidth - -* @description Returns the offset width of the menu's - -* <div> element. - -* @private - -*/ - -_getOffsetWidth: function() { - - - - var oClone = this.element.cloneNode(true); - - - - Dom.setStyle(oClone, "width", ""); - - - - document.body.appendChild(oClone); - - - - var sWidth = oClone.offsetWidth; - - - - document.body.removeChild(oClone); - - - - return sWidth; - - - -}, - - - - - -/** - -* @method _cancelHideDelay - -* @description Cancels the call to "hideMenu." - -* @private - -*/ - -_cancelHideDelay: function() { - - - - var oRoot = this.getRoot(); - - - - if(oRoot._nHideDelayId) { - - - - window.clearTimeout(oRoot._nHideDelayId); - - - - } - - - -}, - - - - - -/** - -* @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(), - - me = this; - - - - function hideMenu() { - - - - if(oRoot.activeItem) { - - - - oRoot.clearActiveItem(); - - - - } - - - - if(oRoot == me && me.cfg.getProperty("position") == "dynamic") { - - - - me.hide(); - - - - } - - - - } - - - - - - oRoot._nHideDelayId = - - window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay")); - - - -}, - - - - - -/** - -* @method _cancelShowDelay - -* @description Cancels the call to the "showMenu." - -* @private - -*/ - -_cancelShowDelay: function() { - - - - var oRoot = this.getRoot(); - - - - if(oRoot._nShowDelayId) { - - - - window.clearTimeout(oRoot._nShowDelayId); - - - - } - - - -}, - - - - - -/** - -* @method _execShowDelay - -* @description Shows the menu after the number of milliseconds specified by - -* the "showdelay" configuration property have ellapsed. - -* @private - -* @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should - -* be made visible. - -*/ - -_execShowDelay: function(p_oMenu) { - - - - var oRoot = this.getRoot(); - - - - function showMenu() { - - - - p_oMenu.show(); - - - - } - - - - - - oRoot._nShowDelayId = - - window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay")); - - - -}, - - - - - - - -// Protected methods - - - - - -/** - -* @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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onMouseOver: function(p_sType, p_aArgs, p_oMenu) { - - - - var oEvent = p_aArgs[0], - - oItem = p_aArgs[1], - - oTarget = Event.getTarget(oEvent); - - - - - - if( - - !this._bHandledMouseOverEvent && - - (oTarget == this.element || Dom.isAncestor(this.element, oTarget)) - - ) { - - - - this.clearActiveItem(); - - - - this._bHandledMouseOverEvent = true; - - this._bHandledMouseOutEvent = false; - - - - } - - - - - - if( - - oItem && !oItem.handledMouseOverEvent && - - !oItem.cfg.getProperty("disabled") && - - (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget)) - - ) { - - - - var nShowDelay = this.cfg.getProperty("showdelay"), - - bShowDelay = (nShowDelay > 0); - - - - - - if(bShowDelay) { - - - - this._cancelShowDelay(); - - - - } - - - - - - var oActiveItem = this.activeItem; - - - - if(oActiveItem) { - - - - oActiveItem.cfg.setProperty("selected", false); - - - - var oActiveSubmenu = oActiveItem.cfg.getProperty("submenu"); - - - - if(oActiveSubmenu) { - - - - oActiveSubmenu.hide(); - - - - } - - - - } - - - - - - var oItemCfg = oItem.cfg; - - - - // Select and focus the current menu item - - - - oItemCfg.setProperty("selected", true); - - oItem.focus(); - - - - - - if(this.cfg.getProperty("autosubmenudisplay")) { - - - - // Show the submenu this menu item - - - - var oSubmenu = oItemCfg.getProperty("submenu"); - - - - if(oSubmenu) { - - - - if(bShowDelay) { - - - - this._execShowDelay(oSubmenu); - - - - } - - 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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onMouseOut: function(p_sType, p_aArgs, p_oMenu) { - - - - var oEvent = p_aArgs[0], - - oItem = p_aArgs[1], - - oRelatedTarget = Event.getRelatedTarget(oEvent), - - bMovingToSubmenu = false; - - - - - - if(oItem && !oItem.cfg.getProperty("disabled")) { - - - - var 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 - - ) - - ) { - - - - if( - - !oSubmenu || - - (oSubmenu && !oSubmenu.cfg.getProperty("visible")) - - ) { - - - - oItem.cfg.setProperty("selected", false); - - - - if( - - oSubmenu && - - oSubmenu.cfg.getProperty("showdelay") && - - !oSubmenu.cfg.getProperty("visible") - - ) { - - - - this._cancelShowDelay(); - - - - } - - - - } - - - - - - oItem.handledMouseOutEvent = true; - - oItem.handledMouseOverEvent = false; - - - - } - - - - } - - - - - - if( - - !this._bHandledMouseOutEvent && - - ( - - ( - - oRelatedTarget != this.element && - - !Dom.isAncestor(this.element, oRelatedTarget) - - ) - - || bMovingToSubmenu - - ) - - ) { - - - - this._bHandledMouseOutEvent = true; - - this._bHandledMouseOverEvent = false; - - - - } - - - -}, - - - - - -/** - -* @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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onClick: function(p_sType, p_aArgs, p_oMenu) { - - - - var oEvent = p_aArgs[0], - - oItem = p_aArgs[1], - - oTarget = Event.getTarget(oEvent); - - - - if(oItem && !oItem.cfg.getProperty("disabled")) { - - - - var oItemCfg = oItem.cfg, - - oSubmenu = oItemCfg.getProperty("submenu"); - - - - - - /* - - ACCESSIBILITY FEATURE FOR SCREEN READERS: - - Expand/collapse the submenu when the user clicks - - on the submenu indicator image. - - */ - - - - if(oTarget == oItem.submenuIndicator && oSubmenu) { - - - - if(oSubmenu.cfg.getProperty("visible")) { - - - - oSubmenu.hide(); - - - - } - - else { - - - - this.clearActiveItem(); - - - - this.activeItem = oItem; - - - - oItem.cfg.setProperty("selected", true); - - - - oSubmenu.show(); - - - - } - - - - } - - else { - - - - var sURL = oItemCfg.getProperty("url"), - - bCurrentPageURL = (sURL.substr((sURL.length-1),1) == "#"), - - sTarget = oItemCfg.getProperty("target"), - - bHasTarget = (sTarget && sTarget.length > 0); - - - - /* - - Prevent the browser from following links - - equal to "#" - - */ - - - - if( - - oTarget.tagName.toUpperCase() == "A" && - - bCurrentPageURL && !bHasTarget - - ) { - - - - Event.preventDefault(oEvent); - - - - } - - - - if( - - oTarget.tagName.toUpperCase() != "A" && - - !bCurrentPageURL && !bHasTarget - - ) { - - - - /* - - Follow the URL of the item regardless of - - whether or not the user clicked specifically - - on the anchor element. - - */ - - - - document.location = sURL; - - - - } - - - - - - /* - - If the item doesn't navigate to a URL and it doesn't have - - a submenu, then collapse the menu tree. - - */ - - - - if(bCurrentPageURL && !oSubmenu) { - - - - var oRoot = this.getRoot(); - - - - if(oRoot.cfg.getProperty("position") == "static") { - - - - oRoot.clearActiveItem(); - - - - } - - else { - - - - oRoot.hide(); - - - - } - - - - } - - - - } - - - - } - - - -}, - - - - - -/** - -* @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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onKeyDown: function(p_sType, p_aArgs, p_oMenu) { - - - - var oEvent = p_aArgs[0], - - oItem = p_aArgs[1], - - oSubmenu; - - - - if(oItem && !oItem.cfg.getProperty("disabled")) { - - - - var oItemCfg = oItem.cfg, - - oParentItem = this.parent, - - oRoot, - - oNextItem; - - - - - - switch(oEvent.keyCode) { - - - - case 38: // Up arrow - - case 40: // Down arrow - - - - if( - - oItem == this.activeItem && - - !oItemCfg.getProperty("selected") - - ) { - - - - oItemCfg.setProperty("selected", true); - - - - } - - else { - - - - oNextItem = (oEvent.keyCode == 38) ? - - oItem.getPreviousEnabledSibling() : - - oItem.getNextEnabledSibling(); - - - - if(oNextItem) { - - - - this.clearActiveItem(); - - - - oNextItem.cfg.setProperty("selected", true); - - oNextItem.focus(); - - - - } - - - - } - - - - Event.preventDefault(oEvent); - - - - break; - - - - - - case 39: // Right arrow - - - - oSubmenu = oItemCfg.getProperty("submenu"); - - - - if(oSubmenu) { - - - - if(!oItemCfg.getProperty("selected")) { - - - - oItemCfg.setProperty("selected", true); - - - - } - - - - oSubmenu.show(); - - - - 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(); - - - - } - - - - oNextItem.focus(); - - - - } - - - - } - - - - } - - - - - - Event.preventDefault(oEvent); - - - - break; - - - - - - case 37: // Left arrow - - - - if(oParentItem) { - - - - var 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(); - - - - } - - - - oNextItem.focus(); - - - - } - - - - } - - else { - - - - this.hide(); - - - - oParentItem.focus(); - - - - } - - - - } - - - - Event.preventDefault(oEvent); - - - - 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.cfg.setProperty("selected", false); - - this.activeItem.blur(); - - - - } - - - - } - - - - - - Event.preventDefault(oEvent); - - - - } - - - -}, - - - - - -/** - -* @method _onTextResize - -* @description "textresize" 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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onTextResize: function(p_sType, p_aArgs, p_oMenu) { - - - - if(this.browser == "gecko" && !this._handleResize) { - - - - this._handleResize = true; - - return; - - - - } - - - - - - var oConfig = this.cfg; - - - - if(oConfig.getProperty("position") == "dynamic") { - - - - oConfig.setProperty("width", (this._getOffsetWidth() + "px")); - - - - } - - - -}, - - - - - - - -// 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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onInit: function(p_sType, p_aArgs, p_oMenu) { - - - - if( - - ( - - (this.parent && !this.lazyLoad) || - - (!this.parent && this.cfg.getProperty("position") == "static") || - - ( - - !this.parent && - - !this.lazyLoad && - - this.cfg.getProperty("position") == "dynamic" - - ) - - ) && - - this.getItemGroups().length === 0 - - ) { - - - - if(this.srcElement) { - - - - this._initSubTree(); - - - - } - - - - - - if(this.itemData) { - - - - this.addItems(this.itemData); - - - - } - - - - } - - else if(this.lazyLoad) { - - - - this.cfg.fireQueue(); - - - - } - - - -}, - - - - - -/** - -* @method _onBeforeRender - -* @description "beforerender" event handler for the menu. Appends all of the - -* <ul>, <li> 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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onBeforeRender: function(p_sType, p_aArgs, p_oMenu) { - - - - var oConfig = this.cfg, - - oEl = this.element, - - nListElements = this._aListElements.length; - - - - - - if(nListElements > 0) { - - - - var i = 0, - - bFirstList = true, - - oUL, - - oGroupTitle; - - - - - - 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, "hastitle"); - - - - } - - - - } - - - - 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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onRender: function(p_sType, p_aArgs, p_oMenu) { - - - - if(this.cfg.getProperty("position") == "dynamic") { - - - - var sWidth = - - this.element.parentNode.tagName.toUpperCase() == "BODY" ? - - this.element.offsetWidth : this._getOffsetWidth(); - - - - this.cfg.setProperty("width", (sWidth + "px")); - - - - } - - - -}, - - - - - -/** - -* @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. - -* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that - -* fired the event. - -*/ - -_onBeforeShow: function(p_sType, p_aArgs, p_oMenu) { - - - - 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" - - ) { - - - - var nOptions = this.itemData.length; - - - - for(var n=0; n viewPortWidth) { - - - - if( - - oContextElement && - - ((x - oContextElement.offsetWidth) > offsetWidth) - - ) { - - - - x = (x - (oContextElement.offsetWidth + offsetWidth)); - - - - } - - else { - - - - x = rightConstraint; - - - - } - - - - } - - - - if (y < 10) { - - - - y = topConstraint; - - - - } else if (y > bottomConstraint) { - - - - if(oContextElement && (y > offsetHeight)) { - - - - y = ((y + oContextElement.offsetHeight) - offsetHeight); - - - - } - - else { - - - - y = bottomConstraint; - - - - } - - - - } - - - - oConfig.setProperty("x", x, true); - - oConfig.setProperty("y", y, true); - - oConfig.setProperty("xy", [x,y], true); - - - -}, - - - - - -/** - -* @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) { - - - - if(this.cfg.getProperty("position") == "dynamic") { - - - - YAHOO.widget.Menu.superclass.configVisible.call( - - this, - - p_sType, - - p_aArgs, - - p_oMenu - - ); - - - - } - - else { - - - - var bVisible = p_aArgs[0], - - sDisplay = Dom.getStyle(this.element, "display"); - - - - 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 sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute", - - oCfg = this.cfg; - - - - Dom.setStyle(this.element, "position", sCSSPosition); - - - - - - if(sCSSPosition == "static") { - - - - /* - - Remove the iframe for statically positioned menus since it will - - intercept mouse events. - - */ - - - - oCfg.setProperty("iframe", false); - - - - - - // Statically positioned menus are visible by default - - - - Dom.setStyle(this.element, "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(this.element, "visibility", "hidden"); - - - - } - - - - - - if(sCSSPosition == "absolute") { - - - - var nZIndex = oCfg.getProperty("zindex"); - - - - if(!nZIndex || nZIndex === 0) { - - - - nZIndex = this.parent ? - - (this.parent.parent.cfg.getProperty("zindex") + 1) : 1; - - - - oCfg.setProperty("zindex", nZIndex); - - - - } - - - - } - - - -}, - - - - - -/** - -* @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") { - - - - YAHOO.widget.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], - - oMouseOutEvent = this.mouseOutEvent, - - oMouseOverEvent = this.mouseOverEvent, - - oKeyDownEvent = this.keyDownEvent; - - - - if(nHideDelay > 0) { - - - - /* - - Only assign event handlers once. This way the user change - - the value for the hidedelay as many times as they want. - - */ - - - - if(!this._hideDelayEventHandlersAssigned) { - - - - oMouseOutEvent.subscribe(this._execHideDelay, true); - - oMouseOverEvent.subscribe(this._cancelHideDelay, this, true); - - oKeyDownEvent.subscribe(this._cancelHideDelay, this, true); - - - - this._hideDelayEventHandlersAssigned = true; - - - - } - - - - } - - else { - - - - oMouseOutEvent.unsubscribe(this._execHideDelay, this); - - oMouseOverEvent.unsubscribe(this._cancelHideDelay, this); - - oKeyDownEvent.unsubscribe(this._cancelHideDelay, this); - - - - this._hideDelayEventHandlersAssigned = false; - - - - } - - - -}, - - - - - -/** - -* @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(typeof oElement == 'string') { - - - - this.cfg.setProperty( - - "container", - - document.getElementById(oElement), - - true - - ); - - - - } - - - -}, - - - - - - - -// Public methods - - - - - -/** - -* @method initEvents - -* @description Initializes the custom events for the menu. - -*/ - -initEvents: function() { - - - - YAHOO.widget.Menu.superclass.initEvents.call(this); - - - - // Create custom events - - - - var CustomEvent = YAHOO.util.CustomEvent; - - - - this.mouseOverEvent = new CustomEvent("mouseOverEvent", this); - - this.mouseOutEvent = new CustomEvent("mouseOutEvent", this); - - this.mouseDownEvent = new CustomEvent("mouseDownEvent", this); - - this.mouseUpEvent = new CustomEvent("mouseUpEvent", this); - - this.clickEvent = new CustomEvent("clickEvent", this); - - this.keyPressEvent = new CustomEvent("keyPressEvent", this); - - this.keyDownEvent = new CustomEvent("keyDownEvent", this); - - this.keyUpEvent = new CustomEvent("keyUpEvent", this); - - this.itemAddedEvent = new CustomEvent("itemAddedEvent", this); - - this.itemRemovedEvent = new CustomEvent("itemRemovedEvent", this); - - - -}, - - - - - -/** - -* @method getRoot - -* @description Finds the menu's root menu. - -*/ - -getRoot: function() { - - - - var oItem = this.parent; - - - - if(oItem) { - - - - var oParentMenu = oItem.parent; - - - - return oParentMenu ? oParentMenu.getRoot() : this; - - - - } - - else { - - - - return this; - - - - } - - - -}, - - - - - -/** - -* @method toString - -* @description Returns a string representing the menu. - -* @return {String} - -*/ - -toString: function() { - - - - return ("Menu " + this.id); - - - -}, - - - - - -/** - -* @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) { - - - - if(typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) { - - - - var nGroupIndex = typeof p_nGroupIndex == "number" ? 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; - - - - } - - - - - - var i = this._aGroupTitleElements.length - 1, - - nFirstIndex; - - - - 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" - - ); - - - - } - - - - } - - - -}, - - - - - - - -/** - -* @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) { - - - - if(p_oItem) { - - - - 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) { - - - - function isArray(p_oValue) { - - - - return (typeof p_oValue == "object" && p_oValue.constructor == Array); - - - - } - - - - - - if(isArray(p_aItems)) { - - - - var nItems = p_aItems.length, - - aItems = [], - - oItem; - - - - - - for(var i=0; i<div> element - -* (and accompanying child nodes) from the document. - -*/ - -destroy: function() { - - - - // Remove Custom Event listeners - - - - this.mouseOverEvent.unsubscribeAll(); - - this.mouseOutEvent.unsubscribeAll(); - - this.mouseDownEvent.unsubscribeAll(); - - this.mouseUpEvent.unsubscribeAll(); - - this.clickEvent.unsubscribeAll(); - - this.keyPressEvent.unsubscribeAll(); - - this.keyDownEvent.unsubscribeAll(); - - this.keyUpEvent.unsubscribeAll(); - - this.itemAddedEvent.unsubscribeAll(); - - this.itemRemovedEvent.unsubscribeAll(); - - - - var nItemGroups = this._aItemGroups.length, - - nItems, - - oItemGroup, - - oItem, - - i, - - n; - - - - - - // Remove all items - - - - if(nItemGroups > 0) { - - - - i = nItemGroups - 1; - - - - do { - - - - oItemGroup = this._aItemGroups[i]; - - - - if(oItemGroup) { - - - - nItems = oItemGroup.length; - - - - if(nItems > 0) { - - - - n = nItems - 1; - - - - do { - - - - oItem = this._aItemGroups[i][n]; - - - - if(oItem) { - - - - oItem.destroy(); - - } - - - - } - - while(n--); - - - - } - - - - } - - - - } - - while(i--); - - - - } - - - - - - // Continue with the superclass implementation of this method - - - - YAHOO.widget.Menu.superclass.destroy.call(this); - - - - this.logger.log("Destroyed."); - - - -}, - - - - - -/** - -* @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("showdelay") > 0) { - - - - this._cancelShowDelay(); - - - - } - - - - - - var oActiveItem = this.activeItem; - - - - if(oActiveItem) { - - - - var oConfig = oActiveItem.cfg; - - - - oConfig.setProperty("selected", false); - - - - var oSubmenu = oConfig.getProperty("submenu"); - - - - if(oSubmenu) { - - - - oSubmenu.hide(); - - - - } - - - - if(p_bBlur) { - - - - oActiveItem.blur(); - - - - } - - - - } - - - -}, - - - - - -/** - -* @description Initializes the class's configurable properties which can be - -* changed using the menu's Config object ("cfg"). - -* @method initDefaultConfig - -*/ - -initDefaultConfig: function() { - - - - YAHOO.widget.Menu.superclass.initDefaultConfig.call(this); - - - - var oConfig = this.cfg; - - - - // Add configuration properties - - - - /* - - 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 <div> - - * 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 - - * <div> element's "display" style property - - * between "block" (true) or "none" (false). - - * @default false - - * @type Boolean - - */ - - oConfig.addProperty( - - "visible", - - { - - value:false, - - handler:this.configVisible, - - validator:this.cfg.checkBoolean - - } - - ); - - - - - - /* - - Change the default value for the "constraintoviewport" configuration - - property 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. - - * @default true - - * @type Boolean - - */ - - oConfig.addProperty( - - "constraintoviewport", - - { - - value:true, - - handler:this.configConstrainToViewport, - - validator:this.cfg.checkBoolean, - - supercedes:["iframe","x","y","xy"] - - } - - ); - - - - - - /** - - * @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", - - { - - value: "dynamic", - - handler: this.configPosition, - - validator: this._checkPosition, - - supercedes: ["visible"] - - } - - ); - - - - - - /** - - * @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("submenualignment", { value: ["tl","tr"] } ); - - - - - - /** - - * @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( - - "autosubmenudisplay", - - { - - value: true, - - validator: oConfig.checkBoolean - - } - - ); - - - - - - /** - - * @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. - - * @default 0 - - * @type Number - - */ - - oConfig.addProperty( - - "showdelay", - - { - - value: 0, - - validator: oConfig.checkNumber - - } - - ); - - - - - - /** - - * @config hidedelay - - * @description Number indicating the time (in milliseconds) that should - - * expire before the menu is hidden. - - * @default 0 - - * @type Number - - */ - - oConfig.addProperty( - - "hidedelay", - - { - - value: 0, - - validator: oConfig.checkNumber, - - handler: this.configHideDelay, - - suppressEvent: true - - } - - ); - - - - - - /** - - * @config clicktohide - - * @description Boolean indicating if the menu will automatically be - - * hidden if the user clicks outside of it. - - * @default true - - * @type Boolean - - */ - - oConfig.addProperty( - - "clicktohide", - - { - - value: true, - - validator: oConfig.checkBoolean - - } - - ); - - - - - - /** - - * @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 HTMLElement|String - - * @default document.body - - */ - - this.cfg.addProperty( - - "container", - - { value:document.body, handler:this.configContainer } - - ); - - - -} - - - -}); // END YAHOO.extend - - - -})(); - - -/** -* The base class for all menuing containers. -* -* @param {String} p_oElement String specifying the id attribute of the -* <div> element of the menu module. -* @param {String} p_oElement String specifying the id attribute of the -* <select> element to be used as the data source for the -* menu module. -* @param {HTMLDivElement} p_oElement Object -* specifying the <div> element of the menu module. -* @param {HTMLSelectElement} p_oElement Object -* specifying the <select> element to be used as the data -* source for the menu module. -* @param {Object} p_oConfig Optional. Object literal specifying the -* configuration for the menu module. See configuration class documentation for -* more details. -* @class MenuModule -* @constructor -* @extends YAHOO.widget.Overlay -* @deprecated As of version 0.12, all MenuModule functionality has been -* implemented directly in YAHOO.widget.Menu, making YAHOO.widget.Menu the base -* class for all menuing containers. -*/ -YAHOO.widget.MenuModule = YAHOO.widget.Menu; - - -(function() { - -var Dom = YAHOO.util.Dom, - Module = YAHOO.widget.Module, - Menu = YAHOO.widget.Menu; - - -/** -* Creates an item for a menu. -* -* @param {String} p_oObject String specifying the text of the menu item. -* @param {HTMLLIElement} p_oObject Object specifying -* the <li> element of the menu item. -* @param {HTMLOptGroupElement} p_oObject Object -* specifying the <optgroup> element of the menu item. -* @param {HTMLOptionElement} p_oObject Object -* specifying the <option> 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.init(p_oObject, p_oConfig); - - } - -}; - -YAHOO.widget.MenuItem.prototype = { - - // Constants - - /** - * @property SUBMENU_INDICATOR_IMAGE_PATH - * @description String representing the path to the image to be used for the - * menu item's submenu arrow indicator. - * @default "nt/ic/ut/alt1/menuarorght8_nrm_1.gif" - * @final - * @type String - */ - SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarorght8_nrm_1.gif", - - - /** - * @property SELECTED_SUBMENU_INDICATOR_IMAGE_PATH - * @description String representing the path to the image to be used for the - * submenu arrow indicator when the menu item is selected. - * @default "nt/ic/ut/alt1/menuarorght8_hov_1.gif" - * @final - * @type String - */ - SELECTED_SUBMENU_INDICATOR_IMAGE_PATH: - "nt/ic/ut/alt1/menuarorght8_hov_1.gif", - - - /** - * @property DISABLED_SUBMENU_INDICATOR_IMAGE_PATH - * @description String representing the path to the image to be used for the - * submenu arrow indicator when the menu item is disabled. - * @default "nt/ic/ut/alt1/menuarorght8_dim_1.gif" - * @final - * @type String - */ - DISABLED_SUBMENU_INDICATOR_IMAGE_PATH: - "nt/ic/ut/alt1/menuarorght8_dim_1.gif", - - - /** - * @property COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT - * @description String representing the alt text for the image to be used - * for the submenu arrow indicator. - * @default "Collapsed. Click to expand." - * @final - * @type String - */ - COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT: "Collapsed. Click to expand.", - - - /** - * @property EXPANDED_SUBMENU_INDICATOR_ALT_TEXT - * @description String representing the alt text for the image to be used - * for the submenu arrow indicator when the submenu is visible. - * @default "Expanded. Click to collapse." - * @final - * @type String - */ - EXPANDED_SUBMENU_INDICATOR_ALT_TEXT: "Expanded. Click to collapse.", - - - /** - * @property DISABLED_SUBMENU_INDICATOR_ALT_TEXT - * @description String representing the alt text for the image to be used - * for the submenu arrow indicator when the menu item is disabled. - * @default "Disabled." - * @final - * @type String - */ - DISABLED_SUBMENU_INDICATOR_ALT_TEXT: "Disabled.", - - - /** - * @property CHECKED_IMAGE_PATH - * @description String representing the path to the image to be used for - * the checked state. - * @default "nt/ic/ut/bsc/menuchk8_nrm_1.gif" - * @final - * @type String - */ - CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_nrm_1.gif", - - - /** - * @property SELECTED_CHECKED_IMAGE_PATH - * @description String representing the path to the image to be used for - * the selected checked state. - * @default "nt/ic/ut/bsc/menuchk8_hov_1.gif" - * @final - * @type String - */ - SELECTED_CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_hov_1.gif", - - - /** - * @property DISABLED_CHECKED_IMAGE_PATH - * @description String representing the path to the image to be used for - * the disabled checked state. - * @default "nt/ic/ut/bsc/menuchk8_dim_1.gif" - * @final - * @type String - */ - DISABLED_CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_dim_1.gif", - - - /** - * @property CHECKED_IMAGE_ALT_TEXT - * @description String representing the alt text for the image to be used - * for the checked image. - * @default "Checked." - * @final - * @type String - */ - CHECKED_IMAGE_ALT_TEXT: "Checked.", - - - /** - * @property DISABLED_CHECKED_IMAGE_ALT_TEXT - * @description String representing the alt text for the image to be used - * for the checked image when the item is disabled. - * @default "Checked. (Item disabled.)" - * @final - * @type String - */ - DISABLED_CHECKED_IMAGE_ALT_TEXT: "Checked. (Item disabled.)", - - - /** - * @property CSS_CLASS_NAME - * @description String representing the CSS class(es) to be applied to the - * <li> element of the menu item. - * @default "yuimenuitem" - * @final - * @type String - */ - CSS_CLASS_NAME: "yuimenuitem", - - - /** - * @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, - - - /** - * @property IMG_ROOT - * @description String representing the prefix path to use for - * non-secure images. - * @default "http://us.i1.yimg.com/us.yimg.com/i/" - * @type String - */ - IMG_ROOT: "http://us.i1.yimg.com/us.yimg.com/i/", - - - /** - * @property IMG_ROOT_SSL - * @description String representing the prefix path to use for securely - * served images. - * @default "https://a248.e.akamai.net/sec.yimg.com/i/" - * @type String - */ - IMG_ROOT_SSL: "https://a248.e.akamai.net/sec.yimg.com/i/", - - - - // Private member variables - - /** - * @property _oAnchor - * @description Object reference to the menu item's - * <a> element. - * @default null - * @private - * @type HTMLAnchorElement - */ - _oAnchor: null, - - - /** - * @property _oText - * @description Object reference to the menu item's text node. - * @default null - * @private - * @type TextNode - */ - _oText: null, - - - /** - * @property _oHelpTextEM - * @description Object reference to the menu item's help text - * <em> element. - * @default null - * @private - * @type HTMLElement - */ - _oHelpTextEM: null, - - - /** - * @property _oSubmenu - * @description Object reference to the menu item's submenu. - * @default null - * @private - * @type YAHOO.widget.Menu - */ - _oSubmenu: null, - - - /** - * @property _checkImage - * @description Object reference to the menu item's checkmark image. - * @default null - * @private - * @type HTMLImageElement - */ - _checkImage: null, - - - - // Public properties - - /** - * @property constructor - * @description Object reference to the menu item's constructor function. - * @default YAHOO.widget.MenuItem - * @type YAHOO.widget.MenuItem - */ - constructor: YAHOO.widget.MenuItem, - - - /** - * @property imageRoot - * @description String representing the root path for all of the menu - * item's images. - * @type String - */ - imageRoot: null, - - - /** - * @property isSecure - * @description Boolean representing whether or not the current browsing - * context is secure (HTTPS). - * @type Boolean - */ - isSecure: Module.prototype.isSecure, - - - /** - * @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 - * <li> element. - * @default HTMLLIElement - * @type HTMLLIElement - */ - element: null, - - - /** - * @property srcElement - * @description Object reference to the HTML element (either - * <li>, <optgroup> or - * <option>) used create the menu item. - * @default HTMLLIElement|HTMLOptGroupElement|HTMLOptionElement - * @type HTMLLIElement| - * HTMLOptGroupElement|HTMLOptionElement - */ - srcElement: null, - - - /** - * @property value - * @description Object reference to the menu item's value. - * @default null - * @type Object - */ - value: null, - - - /** - * @property submenuIndicator - * @description Object reference to the <img> element - * used to create the submenu indicator for the menu item. - * @default HTMLImageElement - * @type HTMLImageElement - */ - submenuIndicator: null, - - - /** - * @property browser - * @description String representing the browser. - * @type String - */ - browser: Module.prototype.browser, - - - - // Events - - - /** - * @event destroyEvent - * @description Fires when the menu item's <li> - * element is removed from its parent <ul> element. - * @type YAHOO.util.CustomEvent - */ - destroyEvent: null, - - - /** - * @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 - */ - mouseOverEvent: null, - - - /** - * @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 - */ - mouseOutEvent: null, - - - /** - * @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 - */ - mouseDownEvent: null, - - - /** - * @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 - */ - mouseUpEvent: null, - - - /** - * @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 - */ - clickEvent: null, - - - /** - * @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 - */ - keyPressEvent: null, - - - /** - * @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 - */ - keyDownEvent: null, - - - /** - * @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 - */ - keyUpEvent: null, - - - /** - * @event focusEvent - * @description Fires when the menu item receives focus. - * @type YAHOO.util.CustomEvent - */ - focusEvent: null, - - - /** - * @event blurEvent - * @description Fires when the menu item loses the input focus. - * @type YAHOO.util.CustomEvent - */ - blurEvent: null, - - - /** - * @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 {HTMLLIElement} p_oObject Object specifying - * the <li> element of the menu item. - * @param {HTMLOptGroupElement} p_oObject Object - * specifying the <optgroup> element of the menu item. - * @param {HTMLOptionElement} p_oObject Object - * specifying the <option> 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) { - - this.imageRoot = (this.isSecure) ? this.IMG_ROOT_SSL : this.IMG_ROOT; - - - 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; - - - if(this._checkString(p_oObject)) { - - this._createRootNodeStructure(); - - oConfig.setProperty("text", p_oObject); - - } - else if(this._checkDOMNode(p_oObject)) { - - switch(p_oObject.tagName.toUpperCase()) { - - case "OPTION": - - this._createRootNodeStructure(); - - oConfig.setProperty("text", p_oObject.text); - - this.srcElement = p_oObject; - - break; - - case "OPTGROUP": - - this._createRootNodeStructure(); - - oConfig.setProperty("text", p_oObject.label); - - this.srcElement = p_oObject; - - this._initSubTree(); - - break; - - case "LI": - - // Get the anchor node (if it exists) - - var oAnchor = this._getFirstElement(p_oObject, "A"), - sURL = "#", - sTarget, - sText; - - - // Capture the "text" and/or the "URL" - - if(oAnchor) { - - sURL = oAnchor.getAttribute("href"); - sTarget = oAnchor.getAttribute("target"); - - if(oAnchor.innerText) { - - sText = oAnchor.innerText; - - } - else { - - var oRange = oAnchor.ownerDocument.createRange(); - - oRange.selectNodeContents(oAnchor); - - sText = oRange.toString(); - - } - - } - else { - - var oText = p_oObject.firstChild; - - sText = oText.nodeValue; - - oAnchor = document.createElement("a"); - - oAnchor.setAttribute("href", sURL); - - p_oObject.replaceChild(oAnchor, oText); - - oAnchor.appendChild(oText); - - } - - - this.srcElement = p_oObject; - this.element = p_oObject; - this._oAnchor = oAnchor; - - - // Check if emphasis has been applied to the MenuItem - - var oEmphasisNode = this._getFirstElement(oAnchor), - bEmphasis = false, - bStrongEmphasis = false; - - if(oEmphasisNode) { - - // Set a reference to the text node - - this._oText = oEmphasisNode.firstChild; - - switch(oEmphasisNode.tagName.toUpperCase()) { - - case "EM": - - bEmphasis = true; - - break; - - case "STRONG": - - bStrongEmphasis = true; - - break; - - } - - } - else { - - // Set a reference to the text node - - this._oText = oAnchor.firstChild; - - } - - - /* - 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); - oConfig.setProperty("emphasis", bEmphasis, true); - oConfig.setProperty( - "strongemphasis", - bStrongEmphasis, - true - ); - - this._initSubTree(); - - break; - - } - - } - - - if(this.element) { - - - Dom.addClass(this.element, this.CSS_CLASS_NAME); - - - // Create custom events - - var CustomEvent = YAHOO.util.CustomEvent; - - this.destroyEvent = new CustomEvent("destroyEvent", this); - this.mouseOverEvent = new CustomEvent("mouseOverEvent", this); - this.mouseOutEvent = new CustomEvent("mouseOutEvent", this); - this.mouseDownEvent = new CustomEvent("mouseDownEvent", this); - this.mouseUpEvent = new CustomEvent("mouseUpEvent", this); - this.clickEvent = new CustomEvent("clickEvent", this); - this.keyPressEvent = new CustomEvent("keyPressEvent", this); - this.keyDownEvent = new CustomEvent("keyDownEvent", this); - this.keyUpEvent = new CustomEvent("keyUpEvent", this); - this.focusEvent = new CustomEvent("focusEvent", this); - this.blurEvent = new CustomEvent("blurEvent", this); - - - if(p_oConfig) { - - oConfig.applyConfig(p_oConfig); - - } - - oConfig.fireQueue(); - - } - - }, - - - - // Private methods - - /** - * @method _getFirstElement - * @description Returns an HTML element's first HTML element node. - * @private - * @param {HTMLElement} p_oElement Object - * reference specifying the element to be evaluated. - * @param {String} p_sTagName Optional. String specifying the tagname of - * the element to be retrieved. - * @return {HTMLElement} - */ - _getFirstElement: function(p_oElement, p_sTagName) { - - var oElement; - - if(p_oElement.firstChild && p_oElement.firstChild.nodeType == 1) { - - oElement = p_oElement.firstChild; - - } - else if( - p_oElement.firstChild && - p_oElement.firstChild.nextSibling && - p_oElement.firstChild.nextSibling.nodeType == 1 - ) { - - oElement = p_oElement.firstChild.nextSibling; - - } - - - if(p_sTagName) { - - return (oElement && oElement.tagName.toUpperCase() == p_sTagName) ? - oElement : false; - - } - - return oElement; - - }, - - - /** - * @method _checkString - * @description Determines if an object is a string. - * @private - * @param {Object} p_oObject Object to be evaluated. - * @return {Boolean} - */ - _checkString: function(p_oObject) { - - return (typeof p_oObject == "string"); - - }, - - - /** - * @method _checkDOMNode - * @description Determines if an object is an HTML element. - * @private - * @param {Object} p_oObject Object to be evaluated. - * @return {Boolean} - */ - _checkDOMNode: function(p_oObject) { - - return (p_oObject && p_oObject.tagName); - - }, - - - /** - * @method _createRootNodeStructure - * @description Creates the core DOM structure for the menu item. - * @private - */ - _createRootNodeStructure: function () { - - this.element = document.createElement("li"); - - this._oText = document.createTextNode(""); - - this._oAnchor = document.createElement("a"); - this._oAnchor.appendChild(this._oText); - - this.cfg.refireEvent("url"); - - this.element.appendChild(this._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; - - - 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 { - - var 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)); - - - var nOptions = aOptions.length; - - if(nOptions > 0) { - - var oMenu = new this.SUBMENU_TYPE(Dom.generateId()); - - oConfig.setProperty("submenu", oMenu); - - for(var n=0; n 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], - oAnchor = this._oAnchor, - oText = this._oText, - oConfig = this.cfg, - oEM; - - - if(bEmphasis && oConfig.getProperty("strongemphasis")) { - - oConfig.setProperty("strongemphasis", false); - - } - - - if(oAnchor) { - - if(bEmphasis) { - - oEM = document.createElement("em"); - oEM.appendChild(oText); - - oAnchor.appendChild(oEM); - - } - else { - - oEM = this._getFirstElement(oAnchor, "EM"); - - if(oEM) { - - oAnchor.removeChild(oEM); - oAnchor.appendChild(oText); - - } - - } - - } - - }, - - - /** - * @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], - oAnchor = this._oAnchor, - oText = this._oText, - oConfig = this.cfg, - oStrong; - - if(bStrongEmphasis && oConfig.getProperty("emphasis")) { - - oConfig.setProperty("emphasis", false); - - } - - if(oAnchor) { - - if(bStrongEmphasis) { - - oStrong = document.createElement("strong"); - oStrong.appendChild(oText); - - oAnchor.appendChild(oStrong); - - } - else { - - oStrong = this._getFirstElement(oAnchor, "STRONG"); - - if(oStrong) { - - oAnchor.removeChild(oStrong); - oAnchor.appendChild(oText); - - } - - } - - } - - }, - - - /** - * @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], - oEl = this.element, - oConfig = this.cfg, - oImg; - - - if(bChecked) { - - this._preloadImage(this.CHECKED_IMAGE_PATH); - this._preloadImage(this.SELECTED_CHECKED_IMAGE_PATH); - this._preloadImage(this.DISABLED_CHECKED_IMAGE_PATH); - - - oImg = document.createElement("img"); - oImg.src = (this.imageRoot + this.CHECKED_IMAGE_PATH); - oImg.alt = this.CHECKED_IMAGE_ALT_TEXT; - - var oSubmenu = this.cfg.getProperty("submenu"); - - if(oSubmenu) { - - oEl.insertBefore(oImg, oSubmenu.element); - - } - else { - - oEl.appendChild(oImg); - - } - - - Dom.addClass([oEl, oImg], "checked"); - - this._checkImage = oImg; - - if(oConfig.getProperty("disabled")) { - - oConfig.refireEvent("disabled"); - - } - - if(oConfig.getProperty("selected")) { - - oConfig.refireEvent("selected"); - - } - - } - else { - - oImg = this._checkImage; - - Dom.removeClass([oEl, oImg], "checked"); - - if(oImg) { - - oEl.removeChild(oImg); - - } - - this._checkImage = null; - - } - - }, - - - - /** - * @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], - oAnchor = this._oAnchor, - aNodes = [this.element, oAnchor], - oEM = this._oHelpTextEM, - oConfig = this.cfg, - oImg, - sImgSrc, - sImgAlt; - - - if(oEM) { - - aNodes[2] = oEM; - - } - - - if(this.cfg.getProperty("checked")) { - - sImgAlt = this.CHECKED_IMAGE_ALT_TEXT; - sImgSrc = this.CHECKED_IMAGE_PATH; - oImg = this._checkImage; - - if(bDisabled) { - - sImgAlt = this.DISABLED_CHECKED_IMAGE_ALT_TEXT; - sImgSrc = this.DISABLED_CHECKED_IMAGE_PATH; - - } - - oImg.src = document.images[(this.imageRoot + sImgSrc)].src; - oImg.alt = sImgAlt; - - } - - - oImg = this.submenuIndicator; - - if(bDisabled) { - - if(oConfig.getProperty("selected")) { - - oConfig.setProperty("selected", false); - - } - - oAnchor.removeAttribute("href"); - - Dom.addClass(aNodes, "disabled"); - - sImgSrc = this.DISABLED_SUBMENU_INDICATOR_IMAGE_PATH; - sImgAlt = this.DISABLED_SUBMENU_INDICATOR_ALT_TEXT; - - } - else { - - oAnchor.setAttribute("href", oConfig.getProperty("url")); - - Dom.removeClass(aNodes, "disabled"); - - sImgSrc = this.SUBMENU_INDICATOR_IMAGE_PATH; - sImgAlt = this.COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT; - - } - - - if(oImg) { - - oImg.src = this.imageRoot + sImgSrc; - oImg.alt = sImgAlt; - - } - - }, - - - /** - * @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) { - - if(!this.cfg.getProperty("disabled")) { - - var bSelected = p_aArgs[0], - oEM = this._oHelpTextEM, - aNodes = [this.element, this._oAnchor], - oImg = this.submenuIndicator, - sImgSrc; - - - if(oEM) { - - aNodes[aNodes.length] = oEM; - - } - - if(oImg) { - - aNodes[aNodes.length] = oImg; - - } - - - if(this.cfg.getProperty("checked")) { - - sImgSrc = this.imageRoot + (bSelected ? - this.SELECTED_CHECKED_IMAGE_PATH : this.CHECKED_IMAGE_PATH); - - this._checkImage.src = document.images[sImgSrc].src; - - } - - - if(bSelected) { - - Dom.addClass(aNodes, "selected"); - sImgSrc = this.SELECTED_SUBMENU_INDICATOR_IMAGE_PATH; - - } - else { - - Dom.removeClass(aNodes, "selected"); - sImgSrc = this.SUBMENU_INDICATOR_IMAGE_PATH; - - } - - if(oImg) { - - oImg.src = document.images[(this.imageRoot + sImgSrc)].src; - - } - - } - - }, - - - /** - * @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 oEl = this.element, - oSubmenu = p_aArgs[0], - oImg = this.submenuIndicator, - oConfig = this.cfg, - aNodes = [this.element, this._oAnchor], - oMenu, - bLazyLoad = this.parent && this.parent.lazyLoad; - - - if(oSubmenu) { - - if(oSubmenu instanceof Menu) { - - oMenu = oSubmenu; - oMenu.parent = this; - oMenu.lazyLoad = bLazyLoad; - - } - else if( - typeof oSubmenu == "object" && - oSubmenu.id && - !oSubmenu.nodeType - ) { - - var 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 - - this.cfg.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 - - this.cfg.setProperty("submenu", oMenu, true); - - } - - - if(oMenu) { - - this._oSubmenu = oMenu; - - - if(!oImg) { - - this._preloadImage(this.SUBMENU_INDICATOR_IMAGE_PATH); - this._preloadImage( - this.SELECTED_SUBMENU_INDICATOR_IMAGE_PATH - ); - - this._preloadImage( - this.DISABLED_SUBMENU_INDICATOR_IMAGE_PATH - ); - - oImg = document.createElement("img"); - - oImg.src = - (this.imageRoot + this.SUBMENU_INDICATOR_IMAGE_PATH); - - oImg.alt = this.COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT; - - oEl.appendChild(oImg); - - this.submenuIndicator = oImg; - - Dom.addClass(aNodes, "hassubmenu"); - - - if(oConfig.getProperty("disabled")) { - - oConfig.refireEvent("disabled"); - - } - - if(oConfig.getProperty("selected")) { - - oConfig.refireEvent("selected"); - - } - - } - - } - - } - else { - - Dom.removeClass(aNodes, "hassubmenu"); - - if(oImg) { - - oEl.removeChild(oImg); - - } - - if(this._oSubmenu) { - - this._oSubmenu.destroy(); - - } - - } - - }, - - - // Public methods - - /** - * @method initDefaultConfig - * @description Initializes an item's configurable properties. - */ - initDefaultConfig : function() { - - var oConfig = this.cfg, - CheckBoolean = oConfig.checkBoolean; - - - // Define the config properties - - /** - * @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", - { - value: "", - handler: this.configText, - validator: this._checkString, - suppressEvent: true - } - ); - - - /** - * @config helptext - * @description String specifying additional instructional text to - * accompany the text for the nenu item. - * @default null - * @type String| - * HTMLElement - */ - oConfig.addProperty("helptext", { handler: this.configHelpText }); - - - /** - * @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", - { value: "#", handler: this.configURL, suppressEvent: true } - ); - - - /** - * @config target - * @description String specifying the value for the "target" attribute - * of the menu item's anchor element. 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. - * 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", - { handler: this.configTarget, suppressEvent: true } - ); - - - /** - * @config emphasis - * @description Boolean indicating if the text of the menu item will be - * rendered with emphasis. When building a menu from existing HTML the - * value of this property will be interpreted from the menu's markup. - * @default false - * @type Boolean - */ - oConfig.addProperty( - "emphasis", - { - value: false, - handler: this.configEmphasis, - validator: CheckBoolean, - suppressEvent: true - } - ); - - - /** - * @config strongemphasis - * @description Boolean indicating if the text of the menu item will be - * rendered with strong emphasis. When building a menu from existing - * HTML the value of this property will be interpreted from the - * menu's markup. - * @default false - * @type Boolean - */ - oConfig.addProperty( - "strongemphasis", - { - value: false, - handler: this.configStrongEmphasis, - validator: CheckBoolean, - suppressEvent: true - } - ); - - - /** - * @config checked - * @description Boolean indicating if the menu item should be rendered - * with a checkmark. - * @default false - * @type Boolean - */ - oConfig.addProperty( - "checked", - { - value: false, - handler: this.configChecked, - validator: this.cfg.checkBoolean, - suppressEvent: true, - supercedes:["disabled"] - } - ); - - - /** - * @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", - { - value: false, - handler: this.configDisabled, - validator: CheckBoolean, - suppressEvent: true - } - ); - - - /** - * @config selected - * @description Boolean indicating if the menu item should - * be highlighted. - * @default false - * @type Boolean - */ - oConfig.addProperty( - "selected", - { - value: false, - handler: this.configSelected, - validator: CheckBoolean, - suppressEvent: true - } - ); - - - /** - * @config submenu - * @description Object specifying the submenu to be appended to the - * menu item. The value can be one of the following:
  • Object - * specifying a Menu instance.
  • Object literal specifying the - * menu to be created. Format: { id: [menu id], itemdata: - * [array of values for - * items] }.
  • String specifying the id attribute - * of the <div> element of the menu.
  • - * Object specifying the <div> element of the - * menu.
- * @default null - * @type Menu|String|Object| - * HTMLElement - */ - oConfig.addProperty("submenu", { handler: this.configSubmenu }); - - }, - - - /** - * @method getNextEnabledSibling - * @description Finds the menu item's next enabled sibling. - * @return YAHOO.widget.MenuItem - */ - getNextEnabledSibling: function() { - - if(this.parent instanceof Menu) { - - var nGroupIndex = this.groupIndex; - - /** - * Finds the next item in an array. - * @private - * @param {p_aArray} Array to search. - * @param {p_nStartIndex} Number indicating the index to - * start searching the array. - * @return {Object} - */ - function getNextArrayItem(p_aArray, p_nStartIndex) { - - return p_aArray[p_nStartIndex] || - getNextArrayItem(p_aArray, (p_nStartIndex+1)); - - } - - - var aItemGroups = this.parent.getItemGroups(), - oNextItem; - - - if(this.index < (aItemGroups[nGroupIndex].length - 1)) { - - oNextItem = getNextArrayItem( - aItemGroups[nGroupIndex], - (this.index+1) - ); - - } - else { - - var nNextGroupIndex; - - if(nGroupIndex < (aItemGroups.length - 1)) { - - nNextGroupIndex = nGroupIndex + 1; - - } - else { - - nNextGroupIndex = 0; - - } - - var aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex); - - // Retrieve the first menu item in the next group - - oNextItem = getNextArrayItem(aNextGroup, 0); - - } - - return ( - oNextItem.cfg.getProperty("disabled") || - oNextItem.element.style.display == "none" - ) ? - oNextItem.getNextEnabledSibling() : oNextItem; - - } - - }, - - - /** - * @method getPreviousEnabledSibling - * @description Finds the menu item's previous enabled sibling. - * @return {YAHOO.widget.MenuItem} - */ - getPreviousEnabledSibling: function() { - - if(this.parent instanceof Menu) { - - var nGroupIndex = this.groupIndex; - - /** - * Returns the previous item in an array - * @private - * @param {p_aArray} Array to search. - * @param {p_nStartIndex} Number indicating the index to - * start searching the array. - * @return {Object} - */ - function getPreviousArrayItem(p_aArray, p_nStartIndex) { - - return p_aArray[p_nStartIndex] || - getPreviousArrayItem(p_aArray, (p_nStartIndex-1)); - - } - - - /** - * Get the index of the first item in an array - * @private - * @param {p_aArray} Array to search. - * @param {p_nStartIndex} Number indicating the index to - * start searching the array. - * @return {Object} - */ - function getFirstItemIndex(p_aArray, p_nStartIndex) { - - return p_aArray[p_nStartIndex] ? - p_nStartIndex : - getFirstItemIndex(p_aArray, (p_nStartIndex+1)); - - } - - var aItemGroups = this.parent.getItemGroups(), - oPreviousItem; - - if( - this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0) - ) { - - oPreviousItem = - getPreviousArrayItem( - aItemGroups[nGroupIndex], - (this.index-1) - ); - - } - else { - - var nPreviousGroupIndex; - - if(nGroupIndex > getFirstItemIndex(aItemGroups, 0)) { - - nPreviousGroupIndex = nGroupIndex - 1; - - } - else { - - nPreviousGroupIndex = aItemGroups.length - 1; - - } - - var aPreviousGroup = - getPreviousArrayItem(aItemGroups, nPreviousGroupIndex); - - oPreviousItem = - getPreviousArrayItem( - aPreviousGroup, - (aPreviousGroup.length - 1) - ); - - } - - return ( - oPreviousItem.cfg.getProperty("disabled") || - oPreviousItem.element.style.display == "none" - ) ? - oPreviousItem.getPreviousEnabledSibling() : oPreviousItem; - - } - - }, - - - /** - * @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 { - - oAnchor.focus(); - - } - catch(e) { - - } - - } - - - if( - !this.cfg.getProperty("disabled") && - oParent && - oParent.cfg.getProperty("visible") && - this.element.style.display != "none" - ) { - - if(oActiveItem) { - - oActiveItem.blur(); - - } - - - /* - 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. - */ - - window.setTimeout(setFocus, 0); - - this.focusEvent.fire(); - - } - - }, - - - /** - * @method blur - * @description Causes the menu item to lose focus and fires the - * onblur event. - */ - blur: function() { - - var oParent = this.parent; - - if( - !this.cfg.getProperty("disabled") && - oParent && - Dom.getStyle(oParent.element, "visibility") == "visible" - ) { - - this._oAnchor.blur(); - - this.blurEvent.fire(); - - } - - }, - - - /** - * @method destroy - * @description Removes the menu item's <li> element - * from its parent <ul> element. - */ - destroy: function() { - - var oEl = this.element; - - if(oEl) { - - - // If the item has a submenu, destroy it first - - var oSubmenu = this.cfg.getProperty("submenu"); - - if(oSubmenu) { - - oSubmenu.destroy(); - - } - - - // Remove CustomEvent listeners - - this.mouseOverEvent.unsubscribeAll(); - this.mouseOutEvent.unsubscribeAll(); - this.mouseDownEvent.unsubscribeAll(); - this.mouseUpEvent.unsubscribeAll(); - this.clickEvent.unsubscribeAll(); - this.keyPressEvent.unsubscribeAll(); - this.keyDownEvent.unsubscribeAll(); - this.keyUpEvent.unsubscribeAll(); - this.focusEvent.unsubscribeAll(); - this.blurEvent.unsubscribeAll(); - this.cfg.configChangedEvent.unsubscribeAll(); - - - // Remove the element from the parent node - - var oParentNode = oEl.parentNode; - - if(oParentNode) { - - oParentNode.removeChild(oEl); - - this.destroyEvent.fire(); - - } - - this.destroyEvent.unsubscribeAll(); - - } - - }, - - - /** - * @method toString - * @description Returns a string representing the menu item. - * @return {String} - */ - toString: function() { - - return ("MenuItem: " + this.cfg.getProperty("text")); - - } - -}; - -})(); - - -/** -* Creates an item for a menu module. -* -* @param {String} p_oObject String specifying the text of the menu module item. -* @param {HTMLLIElement} p_oObject Object specifying the -* <li> element of the menu module item. -* @param {HTMLOptGroupElement} p_oObject Object specifying -* the <optgroup> element of the menu module item. -* @param {HTMLOptionElement} p_oObject Object specifying the -* <option> element of the menu module item. -* @param {Object} p_oConfig Optional. Object literal specifying the -* configuration for the menu module item. See configuration class documentation -* for more details. -* @class MenuModuleItem -* @constructor -* @deprecated As of version 0.12, all MenuModuleItem functionality has been -* implemented directly in YAHOO.widget.MenuItem, making YAHOO.widget.MenuItem -* the base class for all menu items. -*/ -YAHOO.widget.MenuModuleItem = YAHOO.widget.MenuItem; - - -/** -* 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 -* <div> element of the context menu. -* @param {String} p_oElement String specifying the id attribute of the -* <select> element to be used as the data source for the -* context menu. -* @param {HTMLDivElement} p_oElement Object specifying the -* <div> element of the context menu. -* @param {HTMLSelectElement} p_oElement Object specifying -* the <select> 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 - ); - -}; - - -YAHOO.extend(YAHOO.widget.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|HTMLElement|Array -*/ -_oTrigger: null, - - - -// 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 HTMLElement -*/ -contextEventTarget: 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 -* <div> element of the context menu. -* @param {String} p_oElement String specifying the id attribute of the -* <select> element to be used as the data source for -* the context menu. -* @param {HTMLDivElement} p_oElement Object specifying the -* <div> element of the context menu. -* @param {HTMLSelectElement} p_oElement Object specifying -* the <select> 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) { - - if(!this.ITEM_TYPE) { - - this.ITEM_TYPE = YAHOO.widget.ContextMenuItem; - - } - - - // Call the init of the superclass (YAHOO.widget.Menu) - - YAHOO.widget.ContextMenu.superclass.init.call(this, p_oElement); - - - this.beforeInitEvent.fire(YAHOO.widget.ContextMenu); - - - if(p_oConfig) { - - this.cfg.applyConfig(p_oConfig, true); - - } - - - this.initEvent.fire(YAHOO.widget.ContextMenu); - -}, - - - -// 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 Event = YAHOO.util.Event, - oTrigger = this._oTrigger, - bOpera = (this.browser == "opera"); - - - // Remove the event handlers from the trigger(s) - - Event.removeListener( - oTrigger, - (bOpera ? "mousedown" : "contextmenu"), - this._onTriggerContextMenu - ); - - if(bOpera) { - - Event.removeListener(oTrigger, "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) { - - YAHOO.util.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) { - - // Hide any other ContextMenu instances that might be visible - - YAHOO.widget.MenuManager.hideVisible(); - - - var Event = YAHOO.util.Event, - oConfig = this.cfg; - - if(p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) { - - return; - - } - - this.contextEventTarget = Event.getTarget(p_oEvent); - - - // Position and display the context menu - - var nX = Event.getPageX(p_oEvent), - nY = Event.getPageY(p_oEvent); - - - oConfig.applyConfig( { xy:[nX, nY], visible:true } ); - oConfig.fireQueue(); - - - /* - 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); - -}, - - - -// Public methods - - -/** -* @method toString -* @description Returns a string representing the context menu. -* @return {String} -*/ -toString: function() { - - return ("ContextMenu " + this.id); - -}, - - -/** -* @method initDefaultConfig -* @description Initializes the class's configurable properties which can be -* changed using the context menu's Config object ("cfg"). -*/ -initDefaultConfig: function() { - - YAHOO.widget.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|HTMLElement|Array - */ - this.cfg.addProperty("trigger", { handler: this.configTrigger }); - -}, - - -/** -* @method destroy -* @description Removes the context menu's <div> 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 - - YAHOO.widget.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 Event = YAHOO.util.Event, - 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 - */ - - var bOpera = (this.browser == "opera"); - - Event.addListener( - oTrigger, - (bOpera ? "mousedown" : "contextmenu"), - this._onTriggerContextMenu, - this, - true - ); - - - /* - Assign a "click" event handler to the trigger element(s) for - Opera to prevent default browser behaviors. - */ - - if(bOpera) { - - Event.addListener( - oTrigger, - "click", - this._onTriggerClick, - this, - true - ); - - } - - } - else { - - this._removeEventHandlers(); - - } - -} - -}); // END YAHOO.extend - - -/** -* Creates an item for a context menu. -* -* @param {String} p_oObject String specifying the text of the context menu item. -* @param {HTMLLIElement} p_oObject Object specifying the -* <li> element of the context menu item. -* @param {HTMLOptGroupElement} p_oObject Object -* specifying the <optgroup> element of the context -* menu item. -* @param {HTMLOptionElement} p_oObject Object specifying -* the <option> 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 -*/ -YAHOO.widget.ContextMenuItem = function(p_oObject, p_oConfig) { - - YAHOO.widget.ContextMenuItem.superclass.constructor.call( - this, - p_oObject, - p_oConfig - ); - -}; - -YAHOO.extend(YAHOO.widget.ContextMenuItem, YAHOO.widget.MenuItem, { - - -/** -* @method init -* @description The ContextMenuItem 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 context menu item. -* @param {HTMLLIElement} p_oObject Object specifying the -* <li> element of the context menu item. -* @param {HTMLOptGroupElement} p_oObject Object -* specifying the <optgroup> element of the context -* menu item. -* @param {HTMLOptionElement} p_oObject Object specifying -* the <option> 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. -*/ -init: function(p_oObject, p_oConfig) { - - if(!this.SUBMENU_TYPE) { - - this.SUBMENU_TYPE = YAHOO.widget.ContextMenu; - - } - - - /* - 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.ContextMenuItem.superclass.init.call(this, p_oObject); - - var oConfig = this.cfg; - - if(p_oConfig) { - - oConfig.applyConfig(p_oConfig, true); - - } - - oConfig.fireQueue(); - -}, - - - -// Public methods - - -/** -* @method toString -* @description Returns a string representing the context menu item. -* @return {String} -*/ -toString: function() { - - return ("MenuBarItem: " + this.cfg.getProperty("text")); - -} - -}); // END YAHOO.extend - - -/** -* Horizontal collection of items, each of which can contain a submenu. -* -* @param {String} p_oElement String specifying the id attribute of the -* <div> element of the menu bar. -* @param {String} p_oElement String specifying the id attribute of the -* <select> element to be used as the data source for the -* menu bar. -* @param {HTMLDivElement} p_oElement Object specifying -* the <div> element of the menu bar. -* @param {HTMLSelectElement} p_oElement Object -* specifying the <select> 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 - ); - -}; - -YAHOO.extend(YAHOO.widget.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 -* <div> element of the menu bar. -* @param {String} p_oElement String specifying the id attribute of the -* <select> element to be used as the data source for the -* menu bar. -* @param {HTMLDivElement} p_oElement Object specifying -* the <div> element of the menu bar. -* @param {HTMLSelectElement} p_oElement Object -* specifying the <select> 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) - - YAHOO.widget.MenuBar.superclass.init.call(this, p_oElement); - - - this.beforeInitEvent.fire(YAHOO.widget.MenuBar); - - - if(p_oConfig) { - - this.cfg.applyConfig(p_oConfig, true); - - } - - this.initEvent.fire(YAHOO.widget.MenuBar); - -}, - - - -// Constants - - -/** -* @property CSS_CLASS_NAME -* @description String representing the CSS class(es) to be applied to the menu -* bar's <div> element. -* @default "yuimenubar" -* @final -* @type String -*/ -CSS_CLASS_NAME: "yuimenubar", - - - -// 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 Event = YAHOO.util.Event, - oEvent = p_aArgs[0], - oItem = p_aArgs[1], - oSubmenu; - - - if(oItem && !oItem.cfg.getProperty("disabled")) { - - var 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 { - - var oNextItem = (oEvent.keyCode == 37) ? - oItem.getPreviousEnabledSibling() : - oItem.getNextEnabledSibling(); - - if(oNextItem) { - - this.clearActiveItem(); - - oNextItem.cfg.setProperty("selected", true); - - - if(this.cfg.getProperty("autosubmenudisplay")) { - - oSubmenu = oNextItem.cfg.getProperty("submenu"); - - if(oSubmenu) { - - oSubmenu.show(); - oSubmenu.activeItem.blur(); - oSubmenu.activeItem = null; - - } - - } - - 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(); - - } - - } - - 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) { - - YAHOO.widget.MenuBar.superclass._onClick.call( - this, - p_sType, - p_aArgs, - p_oMenuBar - ); - - - var oItem = p_aArgs[1]; - - if(oItem && !oItem.cfg.getProperty("disabled")) { - - var Event = YAHOO.util.Event, - Dom = YAHOO.util.Dom, - - 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(); - - } - - - // Select and focus the current item - - oItem.cfg.setProperty("selected", true); - oItem.focus(); - - - // Show the submenu for the item - - var oSubmenu = oItem.cfg.getProperty("submenu"); - - - if(oSubmenu && oTarget != oItem.submenuIndicator) { - - if(oSubmenu.cfg.getProperty("visible")) { - - oSubmenu.hide(); - - } - else { - - oSubmenu.show(); - - } - - } - - } - -}, - - - -// Public methods - - -/** -* @method toString -* @description Returns a string representing the menu bar. -* @return {String} -*/ -toString: function() { - - return ("MenuBar " + this.id); - -}, - - -/** -* @description Initializes the class's configurable properties which can be -* changed using the menu bar's Config object ("cfg"). -* @method initDefaultConfig -*/ -initDefaultConfig: function() { - - YAHOO.widget.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", - { - value: "static", - handler: this.configPosition, - validator: this._checkPosition, - supercedes: ["visible"] - } - ); - - - /* - 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("submenualignment", { value: ["tl","bl"] } ); - - - /* - 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( - "autosubmenudisplay", - { value: false, validator: oConfig.checkBoolean } - ); - -} - -}); // END YAHOO.extend - - -/** -* Creates an item for a menu bar. -* -* @param {String} p_oObject String specifying the text of the menu bar item. -* @param {HTMLLIElement} p_oObject Object specifying the -* <li> element of the menu bar item. -* @param {HTMLOptGroupElement} p_oObject Object -* specifying the <optgroup> element of the menu bar item. -* @param {HTMLOptionElement} p_oObject Object specifying -* the <option> 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.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 {HTMLLIElement} p_oObject Object specifying the -* <li> element of the menu bar item. -* @param {HTMLOptGroupElement} p_oObject Object -* specifying the <optgroup> element of the menu bar item. -* @param {HTMLOptionElement} p_oObject Object specifying -* the <option> 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 -* <li> element of the menu bar item. -* @default "yuimenubaritem" -* @final -* @type String -*/ -CSS_CLASS_NAME: "yuimenubaritem", - - -/** -* @property SUBMENU_INDICATOR_IMAGE_PATH -* @description String representing the path to the image to be used for the -* menu bar item's submenu arrow indicator. -* @default "nt/ic/ut/alt1/menuarodwn8_nrm_1.gif" -* @final -* @type String -*/ -SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_nrm_1.gif", - - -/** -* @property SELECTED_SUBMENU_INDICATOR_IMAGE_PATH -* @description String representing the path to the image to be used for the -* submenu arrow indicator when the menu bar item is selected. -* @default "nt/ic/ut/alt1/menuarodwn8_hov_1.gif" -* @final -* @type String -*/ -SELECTED_SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_hov_1.gif", - - -/** -* @property DISABLED_SUBMENU_INDICATOR_IMAGE_PATH -* @description String representing the path to the image to be used for the -* submenu arrow indicator when the menu bar item is disabled. -* @default "nt/ic/ut/alt1/menuarodwn8_dim_1.gif" -* @final -* @type String -*/ -DISABLED_SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_dim_1.gif", - - - -// Public methods - - -/** -* @method toString -* @description Returns a string representing the menu bar item. -* @return {String} -*/ -toString: function() { - - return ("MenuBarItem: " + this.cfg.getProperty("text")); - -} - -}); // END YAHOO.extend \ No newline at end of file +/* +Copyright (c) 2007, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.3.0 +*/ + + +/** +* @module menu +* @description

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.

The Menu family of controls features:

+*
    +*
  • Screen-reader accessibility.
  • +*
  • Keyboard and mouse navigation.
  • +*
  • A rich event model that provides access to all of a menu's +* interesting moments.
  • +*
  • Support for +* Progressive +* Enhancement; Menus can be created from simple, +* semantic markup on the page or purely through JavaScript.
  • +*
+* @title Menu +* @namespace YAHOO.widget +* @requires Event, Dom, Container +*/ +(function () { + + var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event; + + + /** + * 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" + }, + + + m_oFocusedMenuItem = null; + + + var m_oLogger = new YAHOO.widget.LogWriter("MenuManager"); + + + + // Private methods + + + /** + * @method getMenuRootElement + * @description Finds the root DIV node of a menu or the root LI node of + * a menu item. + * @private + * @param {HTMLElement} p_oElement Object + * specifying an HTML element. + */ + function getMenuRootElement(p_oElement) { + + var oParentNode; + + 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") + { + + return oParentNode; + + } + else { + + return p_oElement; + + } + + break; + + case "LI": + + return p_oElement; + + default: + + oParentNode = p_oElement.parentNode; + + if (oParentNode) { + + return getMenuRootElement(oParentNode); + + } + + break; + + } + + } + + } + + + + // 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); + + + if ( + p_oEvent.type == "keyup" || + p_oEvent.type == "mousedown") + { + + if (m_oFocusedMenuItem != oMenuItem) { + + if (m_oFocusedMenuItem) { + + m_oFocusedMenuItem.blurEvent.fire(); + + } + + oMenuItem.focusEvent.fire(); + + } + + } + + } + + oMenu[sCustomEventType].fire(p_oEvent, oMenuItem); + + } + else if (p_oEvent.type == "mousedown") { + + if (m_oFocusedMenuItem) { + + m_oFocusedMenuItem.blurEvent.fire(); + + m_oFocusedMenuItem = null; + + } + + + /* + If the target of the event wasn't a menu, hide all + dynamically positioned menus + */ + + for (var i in m_oMenus) { + + if (YAHOO.lang.hasOwnProperty(m_oMenus,i)) { + + oMenu = m_oMenus[i]; + + if (oMenu.cfg.getProperty("clicktohide") && + !(oMenu instanceof YAHOO.widget.MenuBar) && + oMenu.cfg.getProperty("position") == "dynamic") { + + oMenu.hide(); + + } + else { + + oMenu.clearActiveItem(true); + + } + + } + + } + + } + else if (p_oEvent.type == "keyup") { + + if (m_oFocusedMenuItem) { + + m_oFocusedMenuItem.blurEvent.fire(); + + m_oFocusedMenuItem = null; + + } + + } + + } + + + /** + * @method onMenuDestroy + * @description "destroy" event handler for a menu. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + * @param {Array} p_aArgs Array of arguments sent when the event + * was fired. + * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event. + */ + function onMenuDestroy(p_sType, p_aArgs, p_oMenu) { + + if (m_oMenus[p_oMenu.id]) { + + this.removeMenu(p_oMenu); + + } + + } + + + /** + * @method onMenuFocus + * @description "focus" event handler for a MenuItem instance. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + * @param {Array} p_aArgs Array of arguments sent when the event + * was fired. + */ + function onMenuFocus(p_sType, p_aArgs) { + + var oItem = p_aArgs[0]; + + if (oItem) { + + m_oFocusedMenuItem = oItem; + + } + + } + + + /** + * @method onMenuBlur + * @description "blur" event handler for a MenuItem instance. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + * @param {Array} p_aArgs Array of arguments sent when the event + * was fired. + */ + function onMenuBlur(p_sType, p_aArgs) { + + m_oFocusedMenuItem = null; + + } + + + + /** + * @method onMenuVisibleConfigChange + * @description Event handler for when the "visible" configuration + * property of a Menu instance changes. + * @private + * @param {String} p_sType String representing the name of the event + * that was fired. + * @param {Array} p_aArgs Array of arguments sent when the event + * was fired. + */ + function onMenuVisibleConfigChange(p_sType, p_aArgs) { + + var bVisible = p_aArgs[0], + sId = this.id; + + if (bVisible) { + + m_oVisibleMenus[sId] = this; + + m_oLogger.log( + this + + " added to the collection of visible menus."); + + } + else if (m_oVisibleMenus[sId]) { + + delete m_oVisibleMenus[sId]; + + m_oLogger.log( + this + + " removed from the collection of visible menus."); + + } + + } + + + /** + * @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) { + + var sId = this.id; + + if (sId && m_oItems[sId]) { + + if (m_oFocusedMenuItem == this) { + + m_oFocusedMenuItem = null; + + } + + delete m_oItems[sId]; + + m_oLogger.log(this + " successfully unregistered."); + + } + + } + + + /** + * @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); + + m_oLogger.log(oItem + " successfully registered."); + + } + + } + + } + + + 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); + + + m_bInitializedEventHandlers = true; + + m_oLogger.log("DOM event handlers initialized."); + + } + + p_oMenu.destroyEvent.subscribe( + onMenuDestroy, + p_oMenu, + this); + + p_oMenu.cfg.subscribeToConfigEvent( + "visible", + onMenuVisibleConfigChange); + + p_oMenu.itemAddedEvent.subscribe(onItemAdded); + p_oMenu.focusEvent.subscribe(onMenuFocus); + p_oMenu.blurEvent.subscribe(onMenuBlur); + + m_oLogger.log(p_oMenu + " successfully registered."); + + } + + }, + + + /** + * @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; + + if (p_oMenu) { + + sId = p_oMenu.id; + + if (m_oMenus[sId] == p_oMenu) { + + delete m_oMenus[sId]; + + m_oLogger.log(p_oMenu + " successfully unregistered."); + + + if (m_oVisibleMenus[sId] == p_oMenu) { + + delete m_oVisibleMenus[sId]; + + m_oLogger.log( + p_oMenu + + " unregistered from the" + + " collection of visible menus."); + + } + + } + + } + + }, + + + /** + * @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 (YAHOO.lang.hasOwnProperty(m_oVisibleMenus,i)) { + + oMenu = m_oVisibleMenus[i]; + + if (!(oMenu instanceof YAHOO.widget.MenuBar) && + oMenu.cfg.getProperty("position") == "dynamic") { + + oMenu.hide(); + + } + + } + + } + + }, + + + /** + * @method getMenus + * @description Returns an array of all menus registered with the + * menu manger. + * @return {Array} + */ + 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 + * <div> element representing the menu to + * be retrieved. + * @return {YAHOO.widget.Menu} + */ + getMenu: function (p_sId) { + + var oMenu = m_oMenus[p_sId]; + + if (oMenu) { + + return oMenu; + + } + + }, + + + /** + * @method getMenuItem + * @description Returns a menu item with the specified id. + * @param {String} p_sId String specifying the id of the + * <li> element representing the menu item to + * be retrieved. + * @return {YAHOO.widget.MenuItem} + */ + getMenuItem: function (p_sId) { + + var oItem = m_oItems[p_sId]; + + if (oItem) { + + return oItem; + + } + + }, + + + /** + * @method getMenuItemGroup + * @description Returns an array of menu item instances whose + * corresponding <li> elements are child + * nodes of the <ul> element with the + * specified id. + * @param {String} p_sId String specifying the id of the + * <ul> 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; + + + 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) { + + return aItems; + + } + + } + + } + + }, + + + /** + * @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 () { + + if (m_oFocusedMenuItem) { + + return (m_oFocusedMenuItem.parent.getRoot()); + + } + + }, + + + /** + * @method toString + * @description Returns a string representing the menu manager. + * @return {String} + */ + toString: function () { + + return "MenuManager"; + + } + + }; + + }(); + +})(); + + + +(function () { + + +/** +* 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 +* <div> element of the menu. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source +* for the menu. +* @param {HTMLDivElement} p_oElement Object +* specifying the <div> element of the menu. +* @param {HTMLSelectElement} p_oElement +* Object specifying the <select> 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) { + + if (typeof p_sPosition == "string") { + + return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1); + + } + +} + + +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, + Lang = YAHOO.lang, + + m_oShadowTemplate, + + /** + * Constant representing the name of the Menu's events + * @property EVENT_TYPES + * @private + * @final + * @type Object + */ + EVENT_TYPES = { + + "MOUSE_OVER": "mouseover", + "MOUSE_OUT": "mouseout", + "MOUSE_DOWN": "mousedown", + "MOUSE_UP": "mouseup", + "CLICK": "click", + "KEY_PRESS": "keypress", + "KEY_DOWN": "keydown", + "KEY_UP": "keyup", + "FOCUS": "focus", + "BLUR": "blur", + "ITEM_ADDED": "itemAdded", + "ITEM_REMOVED": "itemRemoved" + + }, + + + /** + * Constant representing the Menu's configuration properties + * @property DEFAULT_CONFIG + * @private + * @final + * @type Object + */ + DEFAULT_CONFIG = { + + "VISIBLE": { + key: "visible", + value: false, + validator: Lang.isBoolean + }, + + "CONSTRAIN_TO_VIEWPORT": { + key: "constraintoviewport", + value: true, + validator: Lang.isBoolean, + supercedes: ["iframe","x","y","xy"] + }, + + "POSITION": { + key: "position", + value: "dynamic", + validator: checkPosition, + supercedes: ["visible", "iframe"] + }, + + "SUBMENU_ALIGNMENT": { + key: "submenualignment", + value: ["tl","tr"] + }, + + "AUTO_SUBMENU_DISPLAY": { + key: "autosubmenudisplay", + value: true, + validator: Lang.isBoolean + }, + + "SHOW_DELAY": { + key: "showdelay", + value: 250, + validator: Lang.isNumber + }, + + "HIDE_DELAY": { + key: "hidedelay", + value: 0, + validator: Lang.isNumber, + suppressEvent: true + }, + + "SUBMENU_HIDE_DELAY": { + key: "submenuhidedelay", + value: 250, + validator: Lang.isNumber + }, + + "CLICK_TO_HIDE": { + key: "clicktohide", + value: true, + validator: Lang.isBoolean + }, + + "CONTAINER": { + key: "container" + }, + + "MAX_HEIGHT": { + key: "maxheight", + value: 0, + validator: Lang.isNumber, + supercedes: ["iframe"] + }, + + "CLASS_NAME": { + key: "classname", + value: null, + validator: Lang.isString + }, + + "DISABLED": { + key: "disabled", + 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 <div> 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 <li> element, +* <optgroup> element or <option>) +* 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", + + + +// Private properties + + +/** +* @property _nHideDelayId +* @description Number representing the time-out setting used to cancel the +* hiding of a menu. +* @default null +* @private +* @type Number +*/ +_nHideDelayId: null, + + +/** +* @property _nShowDelayId +* @description Number representing the time-out setting used to cancel the +* showing of a menu. +* @default null +* @private +* @type Number +*/ +_nShowDelayId: null, + + +/** +* @property _nSubmenuHideDelayId +* @description Number representing the time-out setting used to cancel the +* hiding of a submenu. +* @default null +* @private +* @type Number +*/ +_nSubmenuHideDelayId: null, + + +/** +* @property _nBodyScrollId +* @description Number representing the time-out setting used to cancel the +* scrolling of the menu's body element. +* @default null +* @private +* @type Number +*/ +_nBodyScrollId: null, + + +/** +* @property _bHideDelayEventHandlersAssigned +* @description Boolean indicating if the "mouseover" and "mouseout" event +* handlers used for hiding the menu via a call to "window.setTimeout" have +* already been assigned. +* @default false +* @private +* @type Boolean +*/ +_bHideDelayEventHandlersAssigned: 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 <ul> elements, each of which is +* the parent node for each item's <li> 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 _nMaxHeight +* @description The original value of the "maxheight" configuration property +* as set by the user. +* @default -1 +* @private +* @type Number +*/ +_nMaxHeight: -1, + + +/** +* @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, + + +/** +* @property _bDisabled +* @description The current value of the "disabled" configuration attribute. +* @default false +* @private +* @type Boolean +*/ +_bDisabled: false, + + +// 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 +* <select> or <div>) used to +* create the menu. +* @default null +* @type HTMLSelectElement|HTMLDivElement +*/ +srcElement: null, + + + +// Events + + +/** +* @event mouseOverEvent +* @description Fires when the mouse has entered the menu. Passes back +* the DOM Event object as an argument. +*/ +mouseOverEvent: null, + + +/** +* @event mouseOutEvent +* @description Fires when the mouse has left the menu. Passes back the DOM +* Event object as an argument. +* @type YAHOO.util.CustomEvent +*/ +mouseOutEvent: null, + + +/** +* @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 +*/ +mouseDownEvent: null, + + +/** +* @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 +*/ +mouseUpEvent: null, + + +/** +* @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 +*/ +clickEvent: null, + + +/** +* @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 +*/ +keyPressEvent: null, + + +/** +* @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 +*/ +keyDownEvent: null, + + +/** +* @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 +*/ +keyUpEvent: null, + + +/** +* @event itemAddedEvent +* @description Fires when an item is added to the menu. +* @type YAHOO.util.CustomEvent +*/ +itemAddedEvent: null, + + +/** +* @event itemRemovedEvent +* @description Fires when an item is removed to the menu. +* @type YAHOO.util.CustomEvent +*/ +itemRemovedEvent: null, + + +/** +* @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 +* <div> element of the menu. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source +* for the menu. +* @param {HTMLDivElement} p_oElement Object +* specifying the <div> element of the menu. +* @param {HTMLSelectElement} p_oElement +* Object specifying the <select> 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 (typeof p_oElement == "string") { + + oElement = document.getElementById(p_oElement); + + } + else if (p_oElement.tagName) { + + oElement = p_oElement; + + } + + + if (oElement && oElement.tagName) { + + switch(oElement.tagName.toUpperCase()) { + + case "DIV": + + 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); + + this.logger = new YAHOO.widget.LogWriter(this.toString()); + + this.logger.log("Source element: " + this.srcElement.tagName); + + 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); + + this.logger = new YAHOO.widget.LogWriter(this.toString()); + + this.logger.log("Source element: " + this.srcElement.tagName); + + 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); + + this.logger = new YAHOO.widget.LogWriter(this.toString()); + + this.logger.log("No source element found. " + + "Created element with id: " + this.id); + + } + + + 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.renderEvent.subscribe(this.onRender); + this.beforeShowEvent.subscribe(this._onBeforeShow); + this.showEvent.subscribe(this._onShow); + this.beforeHideEvent.subscribe(this._onBeforeHide); + this.hideEvent.subscribe(this._onHide); + 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); + + Module.textResizeEvent.subscribe(this._onTextResize, this, true); + + + 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") { + + // 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": + + 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; + + this.logger.log("Searching DOM for items to initialize."); + + + if (sSrcElementTagName) { + + switch (sSrcElementTagName) { + + case "DIV": + + aListElements = this._aListElements; + nListElements = aListElements.length; + + if (nListElements > 0) { + + this.logger.log("Found " + nListElements + + " item groups to initialize."); + + i = nListElements - 1; + + do { + + oNode = aListElements[i].firstChild; + + if (oNode) { + + this.logger.log("Scanning " + + aListElements[i].childNodes.length + + " child nodes for items to initialize."); + + do { + + if (oNode && oNode.tagName && + oNode.tagName.toUpperCase() == "LI") { + + this.logger.log("Initializing " + + oNode.tagName + " node."); + + this.addItem(new this.ITEM_TYPE(oNode, + { parent: this }), i); + + } + + } + while ((oNode = oNode.nextSibling)); + + } + + } + while (i--); + + } + + break; + + case "SELECT": + + this.logger.log("Scanning " + + oSrcElement.childNodes.length + + " child nodes for items to initialize."); + + oNode = oSrcElement.firstChild; + + do { + + if (oNode && oNode.tagName) { + + switch (oNode.tagName.toUpperCase()) { + + case "OPTGROUP": + case "OPTION": + + this.logger.log("Initializing " + + oNode.tagName + " node."); + + 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; + + for(var i=0; i= 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.logger.log("Item inserted." + + " Text: " + oGroupItem.cfg.getProperty("text") + ", " + + " Index: " + oGroupItem.index + ", " + + " Group Index: " + oGroupItem.groupIndex); + + this.itemAddedEvent.fire(oGroupItem); + this.changeContentEvent.fire(); + + return 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("groupindex", 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.logger.log("Item added." + + " Text: " + oGroupItem.cfg.getProperty("text") + ", " + + " Index: " + oGroupItem.index + ", " + + " Group Index: " + oGroupItem.groupIndex); + + + this.itemAddedEvent.fire(oGroupItem); + this.changeContentEvent.fire(); + + return oGroupItem; + + } + + } + + } + +}, + + +/** +* @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 = typeof p_nGroupIndex == "number" ? 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, + 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) { + + return (this._removeItemFromGroupByIndex(p_nGroupIndex, + nItemIndex)); + + } + + } + + } + +}, + + +/** +* @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("groupindex", 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 +* <ul> 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; + + if (!this._aItemGroups[p_nIndex]) { + + this._aItemGroups[p_nIndex] = []; + + oUL = document.createElement("ul"); + + this._aListElements[p_nIndex] = oUL; + + return this._aItemGroups[p_nIndex]; + + } + +}, + + +/** +* @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 = ((typeof p_nIndex == "number") ? p_nIndex : 0); + + return this._aItemGroups[nIndex]; + +}, + + +/** +* @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); + + oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow, null, + oSubmenu); + + oSubmenu.showEvent.subscribe(this._onSubmenuShow, null, p_oItem); + oSubmenu.hideEvent.subscribe(this._onSubmenuHide, null, p_oItem); + + } + +}, + + +/** +* @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.focusEvent.subscribe(this._onMenuItemFocus); + + p_oItem.blurEvent.subscribe(this._onMenuItemBlur); + + p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, + p_oItem, this); + +}, + + +/** +* @method _getOffsetWidth +* @description Returns the offset width of the menu's +* <div> element. +* @private +*/ +_getOffsetWidth: function () { + + var oClone = this.element.cloneNode(true); + + Dom.removeClass(oClone, "visible"); + + Dom.setStyle(oClone, "width", ""); + + document.body.appendChild(oClone); + + var sWidth = oClone.offsetWidth; + + document.body.removeChild(oClone); + + return sWidth; + +}, + + +/** +* @method _setWidth +* @description Sets the width of the menu's root <div> +* element to its offsetWidth. +* @private +*/ +_setWidth: function () { + + var oElement = this.element, + bVisible = false, + sWidth; + + if (oElement.parentNode.tagName.toUpperCase() == "BODY") { + + if (YAHOO.env.ua.opera) { + + sWidth = this._getOffsetWidth(); + + } + else { + + if (Dom.hasClass(oElement, "visible")) { + + bVisible = true; + + Dom.removeClass(oElement, "visible"); + + } + + Dom.setStyle(oElement, "width", "auto"); + + sWidth = oElement.offsetWidth; + + } + + } + else { + + sWidth = this._getOffsetWidth(); + + } + + this.cfg.setProperty("width", (sWidth + "px")); + + + if (bVisible) { + + Dom.addClass(oElement, "visible"); + + } + +}, + + +/** +* @method _onWidthChange +* @description Change event handler for the the menu's "width" 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. +*/ +_onWidthChange: function (p_sType, p_aArgs) { + + var sWidth = p_aArgs[0]; + + if (sWidth && !this._hasSetWidthHandlers) { + + this.itemAddedEvent.subscribe(this._setWidth); + this.itemRemovedEvent.subscribe(this._setWidth); + + this._hasSetWidthHandlers = true; + + } + else if (this._hasSetWidthHandlers) { + + this.itemAddedEvent.unsubscribe(this._setWidth); + this.itemRemovedEvent.unsubscribe(this._setWidth); + + this._hasSetWidthHandlers = false; + + } + +}, + + +/** +* @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 oRoot = this.getRoot(); + + if (oRoot._nHideDelayId) { + + window.clearTimeout(oRoot._nHideDelayId); + + } + +}, + + +/** +* @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(), + me = this; + + function hideMenu() { + + if (oRoot.activeItem) { + + oRoot.clearActiveItem(); + + } + + if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) && + me.cfg.getProperty("position") == "dynamic") { + + me.hide(); + + } + + } + + + oRoot._nHideDelayId = + window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay")); + +}, + + +/** +* @method _cancelShowDelay +* @description Cancels the call to the "showMenu." +* @private +*/ +_cancelShowDelay: function () { + + var oRoot = this.getRoot(); + + if (oRoot._nShowDelayId) { + + window.clearTimeout(oRoot._nShowDelayId); + + } + +}, + + +/** +* @method _execShowDelay +* @description Shows the menu after the number of milliseconds specified by +* the "showdelay" configuration property have ellapsed. +* @private +* @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should +* be made visible. +*/ +_execShowDelay: function (p_oMenu) { + + var oRoot = this.getRoot(); + + function showMenu() { + + if (p_oMenu.parent.cfg.getProperty("selected")) { + + p_oMenu.show(); + + } + + } + + + oRoot._nShowDelayId = + window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay")); + +}, + + +/** +* @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) { + + var me = this; + + p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () { + + if (me._nCurrentMouseX > (p_nMouseX + 10)) { + + p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () { + + p_oSubmenu.hide(); + + }, p_nHideDelay); + + } + else { + + p_oSubmenu.hide(); + + } + + }, 50); + +}, + + + +// 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, "topscrollbar_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, "bottomscrollbar_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, "topscrollbar_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, "bottomscrollbar_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) { + + if (this._bStopMouseEventHandlers) { + + return false; + + } + + + var oEvent = p_aArgs[0], + oItem = p_aArgs[1], + oTarget = Event.getTarget(oEvent), + oParentMenu, + nShowDelay, + bShowDelay, + oActiveItem, + oItemCfg, + oSubmenu; + + + if (!this._bHandledMouseOverEvent && (oTarget == this.element || + Dom.isAncestor(this.element, oTarget))) { + + // Menu mouseover logic + + this._nCurrentMouseX = 0; + + Event.on(this.element, "mousemove", this._onMouseMove, this, true); + + + this.clearActiveItem(); + + + if (this.parent && this._nSubmenuHideDelayId) { + + window.clearTimeout(this._nSubmenuHideDelayId); + + 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("showdelay"); + 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()) { + + oItem.focus(); + + } + + + if (this.cfg.getProperty("autosubmenudisplay")) { + + // Show the submenu this menu item + + oSubmenu = oItemCfg.getProperty("submenu"); + + if (oSubmenu) { + + if (bShowDelay) { + + this._execShowDelay(oSubmenu); + + } + 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) { + + if (this._bStopMouseEventHandlers) { + + return false; + + } + + + var oEvent = p_aArgs[0], + oItem = p_aArgs[1], + oRelatedTarget = Event.getRelatedTarget(oEvent), + bMovingToSubmenu = false, + oItemCfg, + oSubmenu, + nSubmenuHideDelay, + nShowDelay; + + + 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("submenuhidedelay"); + + nShowDelay = this.cfg.getProperty("showdelay"); + + 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 + + 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) { + + return false; + + } + + 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], + oTarget, + oItemCfg, + oSubmenu, + sURL, + oRoot; + + + if (oItem && !oItem.cfg.getProperty("disabled")) { + + oTarget = Event.getTarget(oEvent); + oItemCfg = oItem.cfg; + oSubmenu = oItemCfg.getProperty("submenu"); + + + /* + ACCESSIBILITY FEATURE FOR SCREEN READERS: + Expand/collapse the submenu when the user clicks + on the submenu indicator image. + */ + + if (oTarget == oItem.submenuIndicator && oSubmenu) { + + if (oSubmenu.cfg.getProperty("visible")) { + + oSubmenu.hide(); + + oSubmenu.parent.focus(); + + } + else { + + this.clearActiveItem(); + + oItemCfg.setProperty("selected", true); + + oSubmenu.show(); + + oSubmenu.setInitialFocus(); + + } + + Event.preventDefault(oEvent); + + } + else { + + sURL = oItemCfg.getProperty("url"); + + // Prevent the browser from following links equal to "#" + + if ((sURL.substr((sURL.length-1),1) == "#")) { + + Event.preventDefault(oEvent); + + oItem.focus(); + + } + + + if (!oSubmenu) { + + oRoot = this.getRoot(); + + if (oRoot instanceof YAHOO.widget.MenuBar || + oRoot.cfg.getProperty("position") == "static") { + + oRoot.clearActiveItem(); + + } + else if (oRoot.cfg.getProperty("clicktohide")) { + + oRoot.hide(); + + } + + } + + } + + } + +}, + + +/** +* @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], + me = this, + oSubmenu, + oItemCfg, + oParentItem, + oRoot, + oNextItem, + oBody, + nBodyScrollTop, + nBodyOffsetHeight, + aItems, + nItems, + nNextItemOffsetTop, + nScrollTarget, + oParentMenu; + + + /* + 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() { + + me._bStopMouseEventHandlers = true; + + window.setTimeout(function () { + + me._bStopMouseEventHandlers = false; + + }, 10); + + } + + + 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("maxheight") > 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(); + + } + + 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(); + + } + + 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 _onTextResize +* @description "textresize" 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. +* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that +* fired the event. +*/ +_onTextResize: function (p_sType, p_aArgs, p_oMenu) { + + if (YAHOO.env.ua.gecko && !this._handleResize) { + + this._handleResize = true; + return; + + } + + + var oConfig = this.cfg; + + if (oConfig.getProperty("position") == "dynamic") { + + oConfig.setProperty("width", (this._getOffsetWidth() + "px")); + + } + +}, + + +/** +* @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) { + + this._cancelHideDelay(); + + var oTarget = Event.getTarget(p_oEvent), + oBody = this.body, + me = this, + nScrollTarget, + fnScrollFunction; + + + function scrollBodyDown() { + + var nScrollTop = oBody.scrollTop; + + + if (nScrollTop < nScrollTarget) { + + oBody.scrollTop = (nScrollTop + 1); + + me._enableScrollHeader(); + + } + else { + + oBody.scrollTop = nScrollTarget; + + window.clearInterval(me._nBodyScrollId); + + me._disableScrollFooter(); + + } + + } + + + function scrollBodyUp() { + + var nScrollTop = oBody.scrollTop; + + + if (nScrollTop > 0) { + + oBody.scrollTop = (nScrollTop - 1); + + me._enableScrollFooter(); + + } + else { + + oBody.scrollTop = 0; + + window.clearInterval(me._nBodyScrollId); + + me._disableScrollHeader(); + + } + + } + + + if (Dom.hasClass(oTarget, "hd")) { + + fnScrollFunction = scrollBodyUp; + + } + else { + + nScrollTarget = oBody.scrollHeight - oBody.offsetHeight; + + fnScrollFunction = scrollBodyDown; + + } + + + this._nBodyScrollId = window.setInterval(fnScrollFunction, 10); + +}, + + +/** +* @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) { + + window.clearInterval(this._nBodyScrollId); + + 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("width", this._onWidthChange); + 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 +* <ul>, <li> 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 oConfig = this.cfg, + 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, "hastitle"); + + } + + } + + 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" && + !this.cfg.getProperty("width")) { + + this._setWidth(); + + } + +}, + + +/** +* @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, + nViewportHeight, + oRegion, + nMaxHeight, + oBody, + oSrcElement; + + + 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= nViewportHeight) { + + nMaxHeight = this.cfg.getProperty("maxheight"); + + /* + Cache the original value for the "maxheight" configuration + property so that we can set it back when the menu is hidden. + */ + + this._nMaxHeight = nMaxHeight; + + this.cfg.setProperty("maxheight", (nViewportHeight - 20)); + + } + + + if (this.cfg.getProperty("maxheight") > 0) { + + oBody = this.body; + + if (oBody.scrollTop > 0) { + + oBody.scrollTop = 0; + + } + + this._disableScrollHeader(); + this._enableScrollFooter(); + + } + + } + + +}, + + +/** +* @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, + aParentAlignment, + aAlignment; + + + 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("autosubmenudisplay", false); + + Event.removeListener(document, "mousedown", + disableAutoSubmenuDisplay); + + Event.removeListener(document, "keydown", + disableAutoSubmenuDisplay); + + } + + } + + } + + + if (oParent) { + + oParentMenu = oParent.parent; + aParentAlignment = oParentMenu.cfg.getProperty("submenualignment"); + aAlignment = this.cfg.getProperty("submenualignment"); + + + if ((aParentAlignment[0] != aAlignment[0]) && + (aParentAlignment[1] != aAlignment[1])) { + + this.cfg.setProperty("submenualignment", + [aParentAlignment[0], aParentAlignment[1]]); + + } + + + if (!oParentMenu.cfg.getProperty("autosubmenudisplay") && + (oParentMenu instanceof YAHOO.widget.MenuBar || + oParentMenu.cfg.getProperty("position") == "static")) { + + oParentMenu.cfg.setProperty("autosubmenudisplay", true); + + Event.on(document, "mousedown", disableAutoSubmenuDisplay); + Event.on(document, "keydown", disableAutoSubmenuDisplay); + + } + + } + +}, + + +/** +* @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, + oConfig, + oSubmenu; + + if (oActiveItem) { + + oConfig = oActiveItem.cfg; + + oConfig.setProperty("selected", false); + + oSubmenu = oConfig.getProperty("submenu"); + + if (oSubmenu) { + + oSubmenu.hide(); + + } + + } + + if (this.getRoot() == this) { + + this.blur(); + + } + +}, + + +/** +* @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._nMaxHeight != -1) { + + this.cfg.setProperty("maxheight", this._nMaxHeight); + + this._nMaxHeight = -1; + + } + +}, + + +/** +* @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 "constraintoviewport": + case "hidedelay": + case "showdelay": + case "submenuhidedelay": + case "clicktohide": + case "effect": + case "classname": + + 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, + + oConfig = { + + constraintoviewport: + oParentMenu.cfg.getProperty("constraintoviewport"), + + xy: [0,0], + + clicktohide: oParentMenu.cfg.getProperty("clicktohide"), + + effect: oParentMenu.cfg.getProperty("effect"), + + showdelay: oParentMenu.cfg.getProperty("showdelay"), + + hidedelay: oParentMenu.cfg.getProperty("hidedelay"), + + submenuhidedelay: oParentMenu.cfg.getProperty("submenuhidedelay"), + + classname: oParentMenu.cfg.getProperty("classname") + + }, + + oLI; + + + /* + Only sync the "iframe" configuration property if the parent + menu's "position" configuration is the same. + */ + + if (this.cfg.getProperty("position") == + oParentMenu.cfg.getProperty("position")) { + + oConfig.iframe = oParentMenu.cfg.getProperty("iframe"); + + } + + + p_oSubmenu.cfg.applyConfig(oConfig); + + + if (!this.lazyLoad) { + + oLI = this.parent.element; + + if (this.element.parentNode == oLI) { + + this.render(); + + } + else { + + this.render(oLI); + + } + + } + +}, + + +/** +* @method _onSubmenuBeforeShow +* @description "beforeshow" 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. +*/ +_onSubmenuBeforeShow: function (p_sType, p_aArgs) { + + var oParent = this.parent, + aAlignment = oParent.parent.cfg.getProperty("submenualignment"); + + this.cfg.setProperty("context", + [oParent.element, aAlignment[0], aAlignment[1]]); + + + var nScrollTop = oParent.parent.body.scrollTop; + + if ((YAHOO.env.ua.gecko || YAHOO.env.ua.webkit) && nScrollTop > 0) { + + this.cfg.setProperty("y", (this.cfg.getProperty("y") - nScrollTop)); + + } + +}, + + +/** +* @method _onSubmenuShow +* @description "show" 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. +*/ +_onSubmenuShow: function (p_sType, p_aArgs) { + + this.submenuIndicator.innerHTML = this.EXPANDED_SUBMENU_INDICATOR_TEXT; + +}, + + +/** +* @method _onSubmenuHide +* @description "hide" 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. +*/ +_onSubmenuHide: function (p_sType, p_aArgs) { + + this.submenuIndicator.innerHTML = this.COLLAPSED_SUBMENU_INDICATOR_TEXT; + +}, + + +/** +* @method _onMenuItemFocus +* @description "focus" 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. +*/ +_onMenuItemFocus: function (p_sType, p_aArgs) { + + this.parent.focusEvent.fire(this); + +}, + + +/** +* @method _onMenuItemBlur +* @description "blur" 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. +*/ +_onMenuItemBlur: function (p_sType, p_aArgs) { + + this.parent.blurEvent.fire(this); + +}, + + +/** +* @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], + sWidth, + 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; + + case "text": + case "helptext": + + /* + A change to an item's "text" or "helptext" + configuration properties requires the width of the parent + menu to be recalculated. + */ + + if (this.element.style.width) { + + sWidth = this._getOffsetWidth() + "px"; + + Dom.setStyle(this.element, "width", sWidth); + + } + + break; + + } + +}, + + + +// Public event handlers for configuration properties + + +/** +* @method enforceConstraints +* @description The default event handler executed when the moveEvent is fired, +* if the "constraintoviewport" configuration property is set to true. +* @param {String} type The name of the event that was fired. +* @param {Array} args Collection of arguments sent when the +* event was fired. +* @param {Array} obj Array containing the current Menu instance +* and the item that fired the event. +*/ +enforceConstraints: function (type, args, obj) { + + var oParentMenuItem = this.parent, + oElement, + oConfig, + pos, + x, + y, + offsetHeight, + offsetWidth, + viewPortWidth, + viewPortHeight, + scrollX, + scrollY, + nPadding, + topConstraint, + leftConstraint, + bottomConstraint, + rightConstraint, + aContext, + oContextElement; + + + if (oParentMenuItem && + !(oParentMenuItem.parent instanceof YAHOO.widget.MenuBar)) { + + oElement = this.element; + + oConfig = this.cfg; + pos = args[0]; + + x = pos[0]; + y = pos[1]; + + offsetHeight = oElement.offsetHeight; + offsetWidth = oElement.offsetWidth; + + viewPortWidth = Dom.getViewportWidth(); + viewPortHeight = Dom.getViewportHeight(); + + scrollX = Dom.getDocumentScrollLeft(); + scrollY = Dom.getDocumentScrollTop(); + + nPadding = + (oParentMenuItem.parent instanceof YAHOO.widget.MenuBar) ? 0 : 10; + + topConstraint = scrollY + nPadding; + leftConstraint = scrollX + nPadding; + + bottomConstraint = scrollY + viewPortHeight - offsetHeight - nPadding; + rightConstraint = scrollX + viewPortWidth - offsetWidth - nPadding; + + aContext = oConfig.getProperty("context"); + oContextElement = aContext ? aContext[0] : null; + + + if (x < 10) { + + x = leftConstraint; + + } else if ((x + offsetWidth) > viewPortWidth) { + + if (oContextElement && + ((x - oContextElement.offsetWidth) > offsetWidth)) { + + x = (x - (oContextElement.offsetWidth + offsetWidth)); + + } + else { + + x = rightConstraint; + + } + + } + + if (y < 10) { + + y = topConstraint; + + } else if (y > bottomConstraint) { + + if (oContextElement && (y > offsetHeight)) { + + y = ((y + oContextElement.offsetHeight) - offsetHeight); + + } + else { + + y = bottomConstraint; + + } + + } + + oConfig.setProperty("x", x, true); + oConfig.setProperty("y", y, true); + oConfig.setProperty("xy", [x,y], true); + + } + else if (this == this.getRoot() && + this.cfg.getProperty("position") == "dynamic") { + + Menu.superclass.enforceConstraints.call(this, type, args, obj); + + } + +}, + + +/** +* @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"); + + 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", + sCurrentPosition = Dom.getStyle(oElement, "position"), + oCfg = this.cfg, + nZIndex; + + + Dom.setStyle(this.element, "position", sCSSPosition); + + + if (sCSSPosition == "static") { + + /* + Remove the iframe for statically positioned menus since it will + intercept mouse events. + */ + + oCfg.setProperty("iframe", false); + + + // Statically positioned menus are visible by default + + Dom.setStyle(this.element, "display", "block"); + + oCfg.setProperty("visible", true); + + } + else { + + if (sCurrentPosition != "absolute") { + + oCfg.setProperty("iframe", (YAHOO.env.ua.ie == 6 ? true : false)); + + } + + /* + 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(this.element, "visibility", "hidden"); + + } + + + if (sCSSPosition == "absolute") { + + nZIndex = oCfg.getProperty("zindex"); + + if (!nZIndex || nZIndex === 0) { + + nZIndex = this.parent ? + (this.parent.parent.cfg.getProperty("zindex") + 1) : 1; + + oCfg.setProperty("zindex", nZIndex); + + } + + } + +}, + + +/** +* @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], + oMouseOutEvent = this.mouseOutEvent, + oMouseOverEvent = this.mouseOverEvent, + oKeyDownEvent = this.keyDownEvent; + + if (nHideDelay > 0) { + + /* + Only assign event handlers once. This way the user change + the value for the hidedelay as many times as they want. + */ + + if (!this._bHideDelayEventHandlersAssigned) { + + oMouseOutEvent.subscribe(this._execHideDelay); + oMouseOverEvent.subscribe(this._cancelHideDelay); + oKeyDownEvent.subscribe(this._cancelHideDelay); + + this._bHideDelayEventHandlersAssigned = true; + + } + + } + else { + + oMouseOutEvent.unsubscribe(this._execHideDelay); + oMouseOverEvent.unsubscribe(this._cancelHideDelay); + oKeyDownEvent.unsubscribe(this._cancelHideDelay); + + this._bHideDelayEventHandlersAssigned = false; + + } + +}, + + +/** +* @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 (typeof oElement == 'string') { + + this.cfg.setProperty("container", document.getElementById(oElement), + true); + + } + +}, + + +/** +* @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.cfg.setProperty("maxheight", 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], + oBody = this.body, + oHeader = this.header, + oFooter = this.footer, + fnMouseOver = this._onScrollTargetMouseOver, + fnMouseOut = this._onScrollTargetMouseOut, + nHeight; + + + if (this.lazyLoad && !oBody) { + + this.renderEvent.unsubscribe(this._setMaxHeight); + + if (nMaxHeight > 0) { + + this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this); + + } + + return; + + } + + Dom.setStyle(oBody, "height", "auto"); + Dom.setStyle(oBody, "overflow", "visible"); + + + if ((nMaxHeight > 0) && (oBody.offsetHeight > nMaxHeight)) { + + if (!this.cfg.getProperty("width")) { + + this._setWidth(); + + } + + if (!oHeader && !oFooter) { + + this.setHeader(" "); + this.setFooter(" "); + + oHeader = this.header; + oFooter = this.footer; + + Dom.addClass(oHeader, "topscrollbar"); + Dom.addClass(oFooter, "bottomscrollbar"); + + this.element.insertBefore(oHeader, oBody); + this.element.appendChild(oFooter); + + 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); + + } + + nHeight = (nMaxHeight - (this.footer.offsetHeight + + this.header.offsetHeight)); + + Dom.setStyle(oBody, "height", (nHeight + "px")); + Dom.setStyle(oBody, "overflow", "hidden"); + + } + else if (oHeader && oFooter) { + + Dom.setStyle(oBody, "height", "auto"); + Dom.setStyle(oBody, "overflow", "visible"); + + Event.removeListener(oHeader, "mouseover", fnMouseOver); + Event.removeListener(oHeader, "mouseout", fnMouseOut); + Event.removeListener(oFooter, "mouseover", fnMouseOver); + Event.removeListener(oFooter, "mouseout", fnMouseOut); + + this.element.removeChild(oHeader); + this.element.removeChild(oFooter); + + this.header = null; + this.footer = null; + + } + + this.cfg.refireEvent("iframe"); + +}, + + +/** +* @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, + nItems, + i; + + if (this._bDisabled != bDisabled) { + + aItems = this.getItems(); + nItems = aItems.length; + + if (nItems > 0) { + + i = nItems - 1; + + do { + + aItems[i].cfg.setProperty("disabled", bDisabled); + + } + while (i--); + + } + + Dom[(bDisabled ? "addClass" : "removeClass")](this.element, "disabled"); + + this.itemAddedEvent[(bDisabled ? "subscribe" : "unsubscribe")]( + this._onItemAdded); + + this._bDisabled = bDisabled; + + } + +}, + + +/** +* @method onRender +* @description "render" event handler for the menu. +* @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) { + + function sizeShadow() { + + var oElement = this.element, + oShadow = this._shadow; + + if (oShadow) { + + oShadow.style.width = (oElement.offsetWidth + 6) + "px"; + oShadow.style.height = (oElement.offsetHeight + 1) + "px"; + + } + + } + + + function addShadowVisibleClass() { + + Dom.addClass(this._shadow, "yui-menu-shadow-visible"); + + } + + + function removeShadowVisibleClass() { + + Dom.removeClass(this._shadow, "yui-menu-shadow-visible"); + + } + + + function createShadow() { + + var oShadow = this._shadow, + oElement, + me; + + if (!oShadow) { + + oElement = this.element; + me = this; + + if (!m_oShadowTemplate) { + + m_oShadowTemplate = document.createElement("div"); + m_oShadowTemplate.className = "yui-menu-shadow"; + + } + + oShadow = m_oShadowTemplate.cloneNode(false); + + oElement.appendChild(oShadow); + + this._shadow = oShadow; + + addShadowVisibleClass.call(this); + + this.beforeShowEvent.subscribe(addShadowVisibleClass); + this.beforeHideEvent.subscribe(removeShadowVisibleClass); + + if (YAHOO.env.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. + */ + + window.setTimeout(function () { + + sizeShadow.call(me); + me.syncIframe(); + + }, 0); + + this.cfg.subscribeToConfigEvent("width", sizeShadow); + this.cfg.subscribeToConfigEvent("height", sizeShadow); + this.changeContentEvent.subscribe(sizeShadow); + + Module.textResizeEvent.subscribe(sizeShadow, me, true); + + this.destroyEvent.subscribe(function () { + + Module.textResizeEvent.unsubscribe(sizeShadow, me); + + }); + + } + + } + + } + + + function onBeforeShow() { + + createShadow.call(this); + + this.beforeShowEvent.unsubscribe(onBeforeShow); + + } + + + if (this.cfg.getProperty("position") == "dynamic") { + + if (this.cfg.getProperty("visible")) { + + 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 SIGNATURE = CustomEvent.LIST; + + this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER); + this.mouseOverEvent.signature = SIGNATURE; + + this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT); + this.mouseOutEvent.signature = SIGNATURE; + + this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN); + this.mouseDownEvent.signature = SIGNATURE; + + this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP); + this.mouseUpEvent.signature = SIGNATURE; + + this.clickEvent = this.createEvent(EVENT_TYPES.CLICK); + this.clickEvent.signature = SIGNATURE; + + this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS); + this.keyPressEvent.signature = SIGNATURE; + + this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN); + this.keyDownEvent.signature = SIGNATURE; + + this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP); + this.keyUpEvent.signature = SIGNATURE; + + this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS); + this.focusEvent.signature = SIGNATURE; + + this.blurEvent = this.createEvent(EVENT_TYPES.BLUR); + this.blurEvent.signature = SIGNATURE; + + this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED); + this.itemAddedEvent.signature = SIGNATURE; + + this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED); + this.itemRemovedEvent.signature = SIGNATURE; + +}, + + +/** +* @method getRoot +* @description Finds the menu's root menu. +*/ +getRoot: function () { + + var oItem = this.parent, + oParentMenu; + + if (oItem) { + + oParentMenu = oItem.parent; + + return oParentMenu ? oParentMenu.getRoot() : this; + + } + else { + + return this; + + } + +}, + + +/** +* @method toString +* @description Returns a string representing the menu. +* @return {String} +*/ +toString: function () { + + var sReturnVal = "Menu", + sId = this.id; + + if (sId) { + + sReturnVal += (" " + 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 (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) { + + nGroupIndex = typeof p_nGroupIndex == "number" ? 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) { + + if (p_oItem) { + + 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; + + if (Lang.isArray(p_aItems)) { + + nItems = p_aItems.length; + aItems = []; + + for(i=0; i 0) { + + aSubmenus = []; + + for(i=0; i 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); + + } + + } + 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 = ""; + + } + + + this._aItemGroups = []; + this._aListElements = []; + this._aGroupTitleElements = []; + + this.cfg.setProperty("width", null); + +}, + + +/** +* @method destroy +* @description Removes the menu's <div> element +* (and accompanying child nodes) from the document. +*/ +destroy: function () { + + Module.textResizeEvent.unsubscribe(this._onTextResize, this); + + + // 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); + + this.logger.log("Destroyed."); + +}, + + +/** +* @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("showdelay") > 0) { + + this._cancelShowDelay(); + + } + + + var oActiveItem = this.activeItem, + oConfig, + oSubmenu; + + if (oActiveItem) { + + oConfig = oActiveItem.cfg; + + if (p_bBlur) { + + oActiveItem.blur(); + + } + + 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); + + } + + } + + + Menu.superclass.subscribe.apply(this, arguments); + Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments); + + + var aSubmenus = this.getSubmenus(), + nSubmenus, + oSubmenu, + i; + + if (aSubmenus) { + + nSubmenus = aSubmenus.length; + + if (nSubmenus > 0) { + + i = nSubmenus - 1; + + do { + + oSubmenu = aSubmenus[i]; + + oSubmenu.subscribe.apply(oSubmenu, 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; + + // 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 <div> + * 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 + * <div> element's "display" style property + * between "block" (true) or "none" (false). + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.VISIBLE.key, + { + handler: this.configVisible, + value: DEFAULT_CONFIG.VISIBLE.value, + validator: DEFAULT_CONFIG.VISIBLE.validator + } + ); + + + /* + Change the default value for the "constraintoviewport" configuration + property 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. + * @default true + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, + { + handler: this.configConstrainToViewport, + value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, + validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, + supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.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( + DEFAULT_CONFIG.POSITION.key, + { + handler: this.configPosition, + value: DEFAULT_CONFIG.POSITION.value, + validator: DEFAULT_CONFIG.POSITION.validator, + supercedes: DEFAULT_CONFIG.POSITION.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( + DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key, + { + value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value + } + ); + + + /** + * @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( + DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key, + { + value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value, + validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator + } + ); + + + /** + * @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. + * @default 250 + * @type Number + */ + oConfig.addProperty( + DEFAULT_CONFIG.SHOW_DELAY.key, + { + value: DEFAULT_CONFIG.SHOW_DELAY.value, + validator: DEFAULT_CONFIG.SHOW_DELAY.validator + } + ); + + + /** + * @config hidedelay + * @description Number indicating the time (in milliseconds) that should + * expire before the menu is hidden. + * @default 0 + * @type Number + */ + oConfig.addProperty( + DEFAULT_CONFIG.HIDE_DELAY.key, + { + handler: this.configHideDelay, + value: DEFAULT_CONFIG.HIDE_DELAY.value, + validator: DEFAULT_CONFIG.HIDE_DELAY.validator, + suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.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. + * @default 250 + * @type Number + */ + oConfig.addProperty( + DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key, + { + value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value, + validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator + } + ); + + + /** + * @config clicktohide + * @description Boolean indicating if the menu will automatically be + * hidden if the user clicks outside of it. + * @default true + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.CLICK_TO_HIDE.key, + { + value: DEFAULT_CONFIG.CLICK_TO_HIDE.value, + validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator + } + ); + + + /** + * @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 HTMLElement|String + * @default document.body + */ + oConfig.addProperty( + DEFAULT_CONFIG.CONTAINER.key, + { + handler: this.configContainer, + value: document.body + } + ); + + + /** + * @config maxheight + * @description Defines the maximum height (in pixels) for a menu before the + * contents of the body are scrolled. + * @default 0 + * @type Number + */ + oConfig.addProperty( + DEFAULT_CONFIG.MAX_HEIGHT.key, + { + handler: this.configMaxHeight, + value: DEFAULT_CONFIG.MAX_HEIGHT.value, + validator: DEFAULT_CONFIG.MAX_HEIGHT.validator + } + ); + + + /** + * @config classname + * @description CSS class to be applied to the menu's root + * <div> element. The specified class(es) are + * appended in addition to the default class as specified by the menu's + * CSS_CLASS_NAME constant. + * @default null + * @type String + */ + oConfig.addProperty( + DEFAULT_CONFIG.CLASS_NAME.key, + { + handler: this.configClassName, + value: DEFAULT_CONFIG.CLASS_NAME.value, + validator: DEFAULT_CONFIG.CLASS_NAME.validator + } + ); + + + /** + * @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 + * <div> element. + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.DISABLED.key, + { + handler: this.configDisabled, + value: DEFAULT_CONFIG.DISABLED.value, + validator: DEFAULT_CONFIG.DISABLED.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 {HTMLLIElement} p_oObject Object specifying +* the <li> element of the menu item. +* @param {HTMLOptGroupElement} p_oObject Object +* specifying the <optgroup> element of the menu item. +* @param {HTMLOptionElement} p_oObject Object +* specifying the <option> 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, + Lang = YAHOO.lang, + + m_oMenuItemTemplate, + + /** + * Constant representing the name of the MenuItem's events + * @property EVENT_TYPES + * @private + * @final + * @type Object + */ + EVENT_TYPES = { + + "MOUSE_OVER": "mouseover", + "MOUSE_OUT": "mouseout", + "MOUSE_DOWN": "mousedown", + "MOUSE_UP": "mouseup", + "CLICK": "click", + "KEY_PRESS": "keypress", + "KEY_DOWN": "keydown", + "KEY_UP": "keyup", + "ITEM_ADDED": "itemAdded", + "ITEM_REMOVED": "itemRemoved", + "FOCUS": "focus", + "BLUR": "blur", + "DESTROY": "destroy" + + }, + + /** + * Constant representing the MenuItem's configuration properties + * @property DEFAULT_CONFIG + * @private + * @final + * @type Object + */ + DEFAULT_CONFIG = { + + "TEXT": { + key: "text", + value: "", + validator: Lang.isString, + suppressEvent: true + }, + + "HELP_TEXT": { + key: "helptext", + supercedes: ["text"] + }, + + "URL": { + key: "url", + value: "#", + suppressEvent: true + }, + + "TARGET": { + key: "target", + suppressEvent: true + }, + + "EMPHASIS": { + key: "emphasis", + value: false, + validator: Lang.isBoolean, + suppressEvent: true, + supercedes: ["text"] + }, + + "STRONG_EMPHASIS": { + key: "strongemphasis", + value: false, + validator: Lang.isBoolean, + suppressEvent: true, + supercedes: ["text"] + }, + + "CHECKED": { + key: "checked", + value: false, + validator: Lang.isBoolean, + suppressEvent: true, + supercedes: ["text"] + }, + + "DISABLED": { + key: "disabled", + value: false, + validator: Lang.isBoolean, + suppressEvent: true, + supercedes: ["text"] + }, + + "SELECTED": { + key: "selected", + value: false, + validator: Lang.isBoolean, + suppressEvent: true + }, + + "SUBMENU": { + key: "submenu", + supercedes: ["text"] + }, + + "ONCLICK": { + key: "onclick" + }, + + "CLASS_NAME": { + key: "classname", + value: null, + validator: Lang.isString + } + + }; + + +MenuItem.prototype = { + + // Constants + + /** + * @property COLLAPSED_SUBMENU_INDICATOR_TEXT + * @description String representing the text for the <em> + * element used for the submenu arrow indicator. + * @default "Submenu collapsed. Click to expand submenu." + * @final + * @type String + */ + COLLAPSED_SUBMENU_INDICATOR_TEXT: + "Submenu collapsed. Click to expand submenu.", + + + /** + * @property EXPANDED_SUBMENU_INDICATOR_TEXT + * @description String representing the text for the submenu arrow indicator + * element (<em>) when the submenu is visible. + * @default "Submenu expanded. Click to collapse submenu." + * @final + * @type String + */ + EXPANDED_SUBMENU_INDICATOR_TEXT: + "Submenu expanded. Click to collapse submenu.", + + + /** + * @property DISABLED_SUBMENU_INDICATOR_TEXT + * @description String representing the text for the submenu arrow indicator + * element (<em>) when the menu item is disabled. + * @default "Submenu collapsed. (Item disabled.)." + * @final + * @type String + */ + DISABLED_SUBMENU_INDICATOR_TEXT: "Submenu collapsed. (Item disabled.)", + + + /** + * @property CHECKED_TEXT + * @description String representing the text to be used for the checked + * indicator element (<em>). + * @default "Checked." + * @final + * @type String + */ + CHECKED_TEXT: "Menu item checked.", + + + /** + * @property DISABLED_CHECKED_TEXT + * @description String representing the text to be used for the checked + * indicator element (<em>) when the menu item + * is disabled. + * @default "Checked. (Item disabled.)" + * @final + * @type String + */ + DISABLED_CHECKED_TEXT: "Checked. (Item disabled.)", + + + /** + * @property CSS_CLASS_NAME + * @description String representing the CSS class(es) to be applied to the + * <li> 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 <a> 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 + * <a> element. + * @default null + * @private + * @type HTMLAnchorElement + */ + _oAnchor: null, + + + /** + * @property _oHelpTextEM + * @description Object reference to the menu item's help text + * <em> element. + * @default null + * @private + * @type HTMLElement + */ + _oHelpTextEM: null, + + + /** + * @property _oSubmenu + * @description Object reference to the menu item's submenu. + * @default null + * @private + * @type YAHOO.widget.Menu + */ + _oSubmenu: null, + + + /** + * @property _oCheckedIndicator + * @description Object reference to the menu item's checkmark image. + * @default HTMLElement + * @private + * @type HTMLElement + */ + _oCheckedIndicator: 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 + * <li> element. + * @default HTMLLIElement + * @type HTMLLIElement + */ + element: null, + + + /** + * @property srcElement + * @description Object reference to the HTML element (either + * <li>, <optgroup> or + * <option>) used create the menu item. + * @default HTMLLIElement|HTMLOptGroupElement|HTMLOptionElement + * @type HTMLLIElement| + * HTMLOptGroupElement|HTMLOptionElement + */ + srcElement: null, + + + /** + * @property value + * @description Object reference to the menu item's value. + * @default null + * @type Object + */ + value: null, + + + /** + * @property submenuIndicator + * @description Object reference to the <em> element + * used to create the submenu indicator for the menu item. + * @default HTMLElement + * @type HTMLElement + */ + submenuIndicator: 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 <li> + * 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 <li> + * element is removed from its parent <ul> element. + * @type YAHOO.util.CustomEvent + */ + destroyEvent: null, + + + /** + * @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 + */ + mouseOverEvent: null, + + + /** + * @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 + */ + mouseOutEvent: null, + + + /** + * @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 + */ + mouseDownEvent: null, + + + /** + * @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 + */ + mouseUpEvent: null, + + + /** + * @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 + */ + clickEvent: null, + + + /** + * @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 + */ + keyPressEvent: null, + + + /** + * @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 + */ + keyDownEvent: null, + + + /** + * @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 + */ + keyUpEvent: null, + + + /** + * @event focusEvent + * @description Fires when the menu item receives focus. + * @type YAHOO.util.CustomEvent + */ + focusEvent: null, + + + /** + * @event blurEvent + * @description Fires when the menu item loses the input focus. + * @type YAHOO.util.CustomEvent + */ + blurEvent: null, + + + /** + * @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 {HTMLLIElement} p_oObject Object specifying + * the <li> element of the menu item. + * @param {HTMLOptGroupElement} p_oObject Object + * specifying the <optgroup> element of the menu item. + * @param {HTMLOptionElement} p_oObject Object + * specifying the <option> 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 SIGNATURE = CustomEvent.LIST, + oConfig = this.cfg, + sURL = "#", + oAnchor, + sTarget, + sText, + sId; + + + 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); + + this.srcElement = p_oObject; + + break; + + case "OPTGROUP": + + this._createRootNodeStructure(); + + oConfig.queueProperty("text", p_oObject.label); + + this.srcElement = p_oObject; + + this._initSubTree(); + + break; + + case "LI": + + // 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"); + 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.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); + + + // Create custom events + + this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER); + this.mouseOverEvent.signature = SIGNATURE; + + this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT); + this.mouseOutEvent.signature = SIGNATURE; + + this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN); + this.mouseDownEvent.signature = SIGNATURE; + + this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP); + this.mouseUpEvent.signature = SIGNATURE; + + this.clickEvent = this.createEvent(EVENT_TYPES.CLICK); + this.clickEvent.signature = SIGNATURE; + + this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS); + this.keyPressEvent.signature = SIGNATURE; + + this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN); + this.keyDownEvent.signature = SIGNATURE; + + this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP); + this.keyUpEvent.signature = SIGNATURE; + + this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS); + this.focusEvent.signature = SIGNATURE; + + this.blurEvent = this.createEvent(EVENT_TYPES.BLUR); + this.blurEvent.signature = SIGNATURE; + + this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY); + this.destroyEvent.signature = SIGNATURE; + + 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"); + m_oMenuItemTemplate.innerHTML = ""; + + } + + 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" + sHelpText + ""; + + } + + + if (oConfig.getProperty("checked")) { + + sCheckHTML = "" + + this.CHECKED_TEXT + ""; + + } + + + if (oSubmenu) { + + sSubmenuIndicatorHTML = "" + + ((oSubmenu instanceof Menu && + oSubmenu.cfg.getProperty("visible")) ? + this.EXPANDED_SUBMENU_INDICATOR_TEXT : + this.COLLAPSED_SUBMENU_INDICATOR_TEXT) + ""; + + } + + + if (oConfig.getProperty("emphasis")) { + + sEmphasisStartTag = ""; + sEmphasisEndTag = ""; + + } + + + if (oConfig.getProperty("strongemphasis")) { + + sEmphasisStartTag = ""; + sEmphasisEndTag = ""; + + } + + + oAnchor.innerHTML = (sEmphasisStartTag + sText + + sEmphasisEndTag + sHelpTextHTML + + sCheckHTML + sSubmenuIndicatorHTML); + + + if (oSubmenu) { + + this.submenuIndicator = oAnchor.lastChild; + + } + + } + + }, + + + /** + * @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) { + + var sHelpText = p_aArgs[0], + oAnchor = this._oAnchor; + + if (sHelpText) { + + Dom.addClass(oAnchor, "hashelptext"); + + } + else { + + Dom.removeClass(oAnchor, "hashelptext"); + + } + + 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 = "#"; + + } + + this._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("strongemphasis")) { + + oConfig.setProperty("strongemphasis", 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], + oAnchor = this._oAnchor; + + if (bChecked) { + + Dom.addClass(oAnchor, "checked"); + + } + else { + + Dom.removeClass(oAnchor, "checked"); + + } + + this.cfg.refireEvent("text"); + + }, + + + + /** + * @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, + oAnchor = this._oAnchor; + + + if(bDisabled) { + + if(oConfig.getProperty("selected")) { + + oConfig.setProperty("selected", false); + + } + + oAnchor.removeAttribute("href"); + + Dom.addClass(oAnchor, "disabled"); + + } + else { + + oAnchor.setAttribute("href", oConfig.getProperty("url")); + + Dom.removeClass(oAnchor, "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 bSelected, + oAnchor; + + if(!this.cfg.getProperty("disabled")) { + + bSelected = p_aArgs[0]; + oAnchor = this._oAnchor; + + + if(bSelected) { + + Dom.addClass(oAnchor, "selected"); + + } + else { + + Dom.removeClass(oAnchor, "selected"); + + } + + } + + }, + + + /** + * @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 oAnchor = this._oAnchor, + oSubmenu = p_aArgs[0], + oSubmenuIndicator = this.submenuIndicator, + 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(typeof oSubmenu == "object" && 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 + + this.cfg.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 + + this.cfg.setProperty("submenu", oMenu, true); + + } + + + if(oMenu) { + + Dom.addClass(oAnchor, "hassubmenu"); + + this._oSubmenu = oMenu; + + } + + } + else { + + Dom.removeClass(oAnchor, "hassubmenu"); + + if(oSubmenuIndicator) { + + oAnchor.removeChild(oSubmenuIndicator); + + } + + if(this._oSubmenu) { + + this._oSubmenu.destroy(); + + } + + } + + oConfig.refireEvent("text"); + + }, + + + /** + * @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 && typeof oObject == "object" && + typeof oObject.fn == "function") { + + this.clickEvent.subscribe(oObject.fn, + ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this), + oObject.scope); + + 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; + + }, + + + + // 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( + DEFAULT_CONFIG.TEXT.key, + { + handler: this.configText, + value: DEFAULT_CONFIG.TEXT.value, + validator: DEFAULT_CONFIG.TEXT.validator, + suppressEvent: DEFAULT_CONFIG.TEXT.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: oMenuItem.cfg.setProperty("text", "Copy <em + * class=\"helptext\">Ctrl + C</em<"); + * @default null + * @type String| + * HTMLElement + */ + oConfig.addProperty( + DEFAULT_CONFIG.HELP_TEXT.key, + { handler: this.configHelpText } + ); + + + /** + * @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( + DEFAULT_CONFIG.URL.key, + { + handler: this.configURL, + value: DEFAULT_CONFIG.URL.value, + suppressEvent: DEFAULT_CONFIG.URL.suppressEvent + } + ); + + + /** + * @config target + * @description String specifying the value for the "target" attribute + * of the menu item's anchor element. 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. + * 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( + DEFAULT_CONFIG.TARGET.key, + { + handler: this.configTarget, + suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent + } + ); + + + /** + * @config emphasis + * @description Boolean indicating if the text of the menu item will be + * rendered with emphasis. + * @deprecated Use "text" configuration property to add emphasis. + * For example: oMenuItem.cfg.setProperty("text", "<em>Some + * Text</em<"); + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.EMPHASIS.key, + { + handler: this.configEmphasis, + value: DEFAULT_CONFIG.EMPHASIS.value, + validator: DEFAULT_CONFIG.EMPHASIS.validator, + suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent + } + ); + + + /** + * @config strongemphasis + * @description Boolean indicating if the text of the menu item will be + * rendered with strong emphasis. + * @deprecated Use "text" configuration property to add strong emphasis. + * For example: oMenuItem.cfg.setProperty("text", "<strong> + * Some Text</strong<"); + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.STRONG_EMPHASIS.key, + { + handler: this.configStrongEmphasis, + value: DEFAULT_CONFIG.STRONG_EMPHASIS.value, + validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator, + suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent + } + ); + + + /** + * @config checked + * @description Boolean indicating if the menu item should be rendered + * with a checkmark. + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.CHECKED.key, + { + handler: this.configChecked, + value: DEFAULT_CONFIG.CHECKED.value, + validator: DEFAULT_CONFIG.CHECKED.validator, + suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent, + supercedes: DEFAULT_CONFIG.CHECKED.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( + DEFAULT_CONFIG.DISABLED.key, + { + handler: this.configDisabled, + value: DEFAULT_CONFIG.DISABLED.value, + validator: DEFAULT_CONFIG.DISABLED.validator, + suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent + } + ); + + + /** + * @config selected + * @description Boolean indicating if the menu item should + * be highlighted. + * @default false + * @type Boolean + */ + oConfig.addProperty( + DEFAULT_CONFIG.SELECTED.key, + { + handler: this.configSelected, + value: DEFAULT_CONFIG.SELECTED.value, + validator: DEFAULT_CONFIG.SELECTED.validator, + suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent + } + ); + + + /** + * @config submenu + * @description Object specifying the submenu to be appended to the + * menu item. The value can be one of the following:
  • Object + * specifying a Menu instance.
  • Object literal specifying the + * menu to be created. Format: { id: [menu id], itemdata: + * [array of values for + * items] }.
  • String specifying the id attribute + * of the <div> element of the menu.
  • + * Object specifying the <div> element of the + * menu.
+ * @default null + * @type Menu|String|Object| + * HTMLElement + */ + oConfig.addProperty( + DEFAULT_CONFIG.SUBMENU.key, + { handler: this.configSubmenu } + ); + + + /** + * @config onclick + * @description Object literal representing the code to be executed when + * the item is clicked. Format:
{
+ * fn: Function, // The handler to call when + * the event fires.
obj: Object, // An + * object to pass back to the handler.
scope: + * Object // The object to use for the scope of the handler. + *
}
+ * @type Object + * @default null + */ + oConfig.addProperty( + DEFAULT_CONFIG.ONCLICK.key, + { handler: this.configOnClick } + ); + + + /** + * @config classname + * @description CSS class to be applied to the menu item's root + * <li> 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( + DEFAULT_CONFIG.CLASS_NAME.key, + { + handler: this.configClassName, + value: DEFAULT_CONFIG.CLASS_NAME.value, + validator: DEFAULT_CONFIG.CLASS_NAME.validator + } + ); + + }, + + + /** + * @method getNextEnabledSibling + * @description Finds the menu item's next enabled sibling. + * @return YAHOO.widget.MenuItem + */ + getNextEnabledSibling: function() { + + var nGroupIndex, + aItemGroups, + oNextItem, + nNextGroupIndex, + aNextGroup; + + 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); + + } + + return (oNextItem.cfg.getProperty("disabled") || + oNextItem.element.style.display == "none") ? + oNextItem.getNextEnabledSibling() : oNextItem; + + } + + }, + + + /** + * @method getPreviousEnabledSibling + * @description Finds the menu item's previous enabled sibling. + * @return {YAHOO.widget.MenuItem} + */ + getPreviousEnabledSibling: function() { + + var nGroupIndex, + aItemGroups, + oPreviousItem, + nPreviousGroupIndex, + aPreviousGroup; + + 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)); + + } + + return (oPreviousItem.cfg.getProperty("disabled") || + oPreviousItem.element.style.display == "none") ? + oPreviousItem.getPreviousEnabledSibling() : oPreviousItem; + + } + + }, + + + /** + * @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, + me = this; + + + function setFocus() { + + try { + + if (YAHOO.env.ua.ie && !document.hasFocus()) { + + return; + + } + + oAnchor.focus(); + + } + catch(e) { + + } + + } + + + if(!this.cfg.getProperty("disabled") && oParent && + oParent.cfg.getProperty("visible") && + this.element.style.display != "none") { + + if(oActiveItem) { + + oActiveItem.blur(); + + } + + + /* + 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. + */ + + window.setTimeout(setFocus, 0); + + this.focusEvent.fire(); + + } + + }, + + + /** + * @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")) { + + this._oAnchor.blur(); + + this.blurEvent.fire(); + + } + + }, + + + /** + * @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 <li> element + * from its parent <ul> element. + */ + destroy: function() { + + var oEl = this.element, + oSubmenu, + oParentNode; + + if(oEl) { + + + // If the item has a submenu, destroy it first + + oSubmenu = this.cfg.getProperty("submenu"); + + if(oSubmenu) { + + oSubmenu.destroy(); + + } + + + // Remove CustomEvent listeners + + this.mouseOverEvent.unsubscribeAll(); + this.mouseOutEvent.unsubscribeAll(); + this.mouseDownEvent.unsubscribeAll(); + this.mouseUpEvent.unsubscribeAll(); + this.clickEvent.unsubscribeAll(); + this.keyPressEvent.unsubscribeAll(); + this.keyDownEvent.unsubscribeAll(); + this.keyUpEvent.unsubscribeAll(); + this.focusEvent.unsubscribeAll(); + this.blurEvent.unsubscribeAll(); + this.cfg.configChangedEvent.unsubscribeAll(); + + + // Remove the element from the parent node + + oParentNode = oEl.parentNode; + + if(oParentNode) { + + oParentNode.removeChild(oEl); + + this.destroyEvent.fire(); + + } + + this.destroyEvent.unsubscribeAll(); + + } + + }, + + + /** + * @method toString + * @description Returns a string representing the menu item. + * @return {String} + */ + toString: function() { + + var sReturnVal = "MenuItem", + sId = this.id; + + if(sId) { + + sReturnVal += (" " + sId); + + } + + return sReturnVal; + + } + +}; + +Lang.augmentProto(MenuItem, YAHOO.util.EventProvider); + +})(); +(function () { + + +/** +* 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 +* <div> element of the context menu. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source for the +* context menu. +* @param {HTMLDivElement} p_oElement Object specifying the +* <div> element of the context menu. +* @param {HTMLSelectElement} p_oElement Object specifying +* the <select> 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, + 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": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"), + "CLICK": "click" + + }, + + + /** + * Constant representing the ContextMenu's configuration properties + * @property DEFAULT_CONFIG + * @private + * @final + * @type Object + */ + DEFAULT_CONFIG = { + + "TRIGGER": { + key: "trigger" + } + + }; + + +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|HTMLElement|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 HTMLElement +*/ +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 +* <div> element of the context menu. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source for +* the context menu. +* @param {HTMLDivElement} p_oElement Object specifying the +* <div> element of the context menu. +* @param {HTMLSelectElement} p_oElement Object specifying +* the <select> 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) { + + if(!this.ITEM_TYPE) { + + this.ITEM_TYPE = YAHOO.widget.ContextMenuItem; + + } + + + // 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(YAHOO.env.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) { + + if(p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) { + + return; + + } + + + /* + 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 ContextMenu instances that might be visible + + YAHOO.widget.MenuManager.hideVisible(); + + + this.contextEventTarget = Event.getTarget(p_oEvent); + + this.triggerContextMenuEvent.fire(p_oEvent); + + + if(!this._bCancelled) { + + // Position and display the context menu + + this.cfg.setProperty("xy", Event.getXY(p_oEvent)); + + 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 += (" " + 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|HTMLElement|Array + */ + this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key, + { handler: this.configTrigger }); + +}, + + +/** +* @method destroy +* @description Removes the context menu's <div> 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(YAHOO.env.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 {HTMLLIElement} p_oObject Object specifying the +* <li> element of the context menu item. +* @param {HTMLOptGroupElement} p_oObject Object +* specifying the <optgroup> element of the context +* menu item. +* @param {HTMLOptionElement} p_oObject Object specifying +* the <option> 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 +*/ +YAHOO.widget.ContextMenuItem = function(p_oObject, p_oConfig) { + + YAHOO.widget.ContextMenuItem.superclass.constructor.call(this, + p_oObject, p_oConfig); + +}; + +YAHOO.lang.extend(YAHOO.widget.ContextMenuItem, YAHOO.widget.MenuItem, { + + +/** +* @method init +* @description The ContextMenuItem 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 context menu item. +* @param {HTMLLIElement} p_oObject Object specifying the +* <li> element of the context menu item. +* @param {HTMLOptGroupElement} p_oObject Object +* specifying the <optgroup> element of the context +* menu item. +* @param {HTMLOptionElement} p_oObject Object specifying +* the <option> 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. +*/ +init: function(p_oObject, p_oConfig) { + + if(!this.SUBMENU_TYPE) { + + this.SUBMENU_TYPE = YAHOO.widget.ContextMenu; + + } + + + /* + 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.ContextMenuItem.superclass.init.call(this, p_oObject); + + var oConfig = this.cfg; + + if(p_oConfig) { + + oConfig.applyConfig(p_oConfig, true); + + } + + oConfig.fireQueue(); + +}, + + + +// Public methods + + +/** +* @method toString +* @description Returns a string representing the context menu item. +* @return {String} +*/ +toString: function() { + + var sReturnVal = "ContextMenuItem"; + + if(this.cfg && this.cfg.getProperty("text")) { + + sReturnVal += (": " + this.cfg.getProperty("text")); + + } + + return sReturnVal; + +} + +}); // END YAHOO.lang.extend +(function () { + + +/** +* Horizontal collection of items, each of which can contain a submenu. +* +* @param {String} p_oElement String specifying the id attribute of the +* <div> element of the menu bar. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source for the +* menu bar. +* @param {HTMLDivElement} p_oElement Object specifying +* the <div> element of the menu bar. +* @param {HTMLSelectElement} p_oElement Object +* specifying the <select> 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) { + + if (typeof p_sPosition == "string") { + + return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1); + + } + +} + + +var Event = YAHOO.util.Event, + Dom = YAHOO.util.Dom, + MenuBar = YAHOO.widget.MenuBar, + + /** + * Constant representing the MenuBar's configuration properties + * @property DEFAULT_CONFIG + * @private + * @final + * @type Object + */ + DEFAULT_CONFIG = { + + "POSITION": { + key: "position", + value: "static", + validator: checkPosition, + supercedes: ["visible"] + }, + + "SUBMENU_ALIGNMENT": { + key: "submenualignment", + value: ["tl","bl"] + }, + + "AUTO_SUBMENU_DISPLAY": { + key: "autosubmenudisplay", + value: false, + validator: YAHOO.lang.isBoolean + } + + }; + + + +YAHOO.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 +* <div> element of the menu bar. +* @param {String} p_oElement String specifying the id attribute of the +* <select> element to be used as the data source for the +* menu bar. +* @param {HTMLDivElement} p_oElement Object specifying +* the <div> element of the menu bar. +* @param {HTMLSelectElement} p_oElement Object +* specifying the <select> 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 <div> element. +* @default "yuimenubar" +* @final +* @type String +*/ +CSS_CLASS_NAME: "yuimenubar", + + + +// 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); + + + if(this.cfg.getProperty("autosubmenudisplay")) { + + oSubmenu = oNextItem.cfg.getProperty("submenu"); + + if(oSubmenu) { + + oSubmenu.show(); + + } + + } + + 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(); + + } + + } + + 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], + oEvent, + oTarget, + oActiveItem, + oConfig, + oSubmenu; + + + 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 && oTarget != oItem.submenuIndicator) { + + if(oSubmenu.cfg.getProperty("visible")) { + + oSubmenu.hide(); + + } + else { + + oSubmenu.show(); + + } + + } + + } + +}, + + + +// Public methods + + +/** +* @method toString +* @description Returns a string representing the menu bar. +* @return {String} +*/ +toString: function() { + + var sReturnVal = "MenuBar", + sId = this.id; + + if(sId) { + + sReturnVal += (" " + 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( + DEFAULT_CONFIG.POSITION.key, + { + handler: this.configPosition, + value: DEFAULT_CONFIG.POSITION.value, + validator: DEFAULT_CONFIG.POSITION.validator, + supercedes: DEFAULT_CONFIG.POSITION.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( + DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key, + { + value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value + } + ); + + + /* + 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( + DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key, + { + value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value, + validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator + } + ); + +} + +}); // 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 {HTMLLIElement} p_oObject Object specifying the +* <li> element of the menu bar item. +* @param {HTMLOptGroupElement} p_oObject Object +* specifying the <optgroup> element of the menu bar item. +* @param {HTMLOptionElement} p_oObject Object specifying +* the <option> 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 {HTMLLIElement} p_oObject Object specifying the +* <li> element of the menu bar item. +* @param {HTMLOptGroupElement} p_oObject Object +* specifying the <optgroup> element of the menu bar item. +* @param {HTMLOptionElement} p_oObject Object specifying +* the <option> 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 +* <li> 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 <a> 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.3.0", build: "442"});