2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
11 * @description <p>The Menu family of components features a collection of
12 * controls that make it easy to add menus to your website or web application.
13 * With the Menu Controls you can create website fly-out menus, customized
14 * context menus, or application-style menu bars with just a small amount of
15 * scripting.</p><p>The Menu family of controls features:</p>
17 * <li>Keyboard and mouse navigation.</li>
18 * <li>A rich event model that provides access to all of a menu's
19 * interesting moments.</li>
21 * <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
22 * Enhancement</a>; Menus can be created from simple,
23 * semantic markup on the page or purely through JavaScript.</li>
26 * @namespace YAHOO.widget
27 * @requires Event, Dom, Container
36 _DISABLED = "disabled",
37 _MOUSEOVER = "mouseover",
38 _MOUSEOUT = "mouseout",
39 _MOUSEDOWN = "mousedown",
41 _FOCUS = YAHOO.env.ua.ie ? "focusin" : "focus",
45 _KEYPRESS = "keypress",
46 _CLICK_TO_HIDE = "clicktohide",
47 _POSITION = "position",
49 _SHOW_DELAY = "showdelay",
50 _SELECTED = "selected",
53 _MENUMANAGER = "MenuManager",
57 Event = YAHOO.util.Event,
62 * Singleton that manages a collection of all menus and menu items. Listens
63 * for DOM events at the document level and dispatches the events to the
64 * corresponding menu or menu item.
66 * @namespace YAHOO.widget
70 YAHOO.widget.MenuManager = function () {
72 // Private member variables
75 // Flag indicating if the DOM event handlers have been attached
77 var m_bInitializedEventHandlers = false,
80 // Collection of menus
85 // Collection of visible menus
90 // Collection of menu items
95 // Map of DOM event types to their equivalent CustomEvent types
98 "click": "clickEvent",
99 "mousedown": "mouseDownEvent",
100 "mouseup": "mouseUpEvent",
101 "mouseover": "mouseOverEvent",
102 "mouseout": "mouseOutEvent",
103 "keydown": "keyDownEvent",
104 "keyup": "keyUpEvent",
105 "keypress": "keyPressEvent",
106 "focus": "focusEvent",
107 "focusin": "focusEvent",
109 "focusout": "blurEvent"
113 // The element in the DOM that currently has focus
115 m_oFocusedElement = null,
118 m_oFocusedMenuItem = null;
126 * @method getMenuRootElement
127 * @description Finds the root DIV node of a menu or the root LI node of
130 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
131 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
132 * specifying an HTML element.
134 function getMenuRootElement(p_oElement) {
139 if (p_oElement && p_oElement.tagName) {
141 switch (p_oElement.tagName.toUpperCase()) {
145 oParentNode = p_oElement.parentNode;
147 // Check if the DIV is the inner "body" node of a menu
150 Dom.hasClass(p_oElement, _HD) ||
151 Dom.hasClass(p_oElement, _BD) ||
152 Dom.hasClass(p_oElement, _FT)
155 oParentNode.tagName &&
156 oParentNode.tagName.toUpperCase() == _DIV) {
158 returnVal = oParentNode;
163 returnVal = p_oElement;
171 returnVal = p_oElement;
177 oParentNode = p_oElement.parentNode;
181 returnVal = getMenuRootElement(oParentNode);
197 // Private event handlers
202 * @description Generic, global event handler for all of a menu's
203 * DOM-based events. This listens for events against the document
204 * object. If the target of a given event is a member of a menu or
205 * menu item's DOM, the instance's corresponding Custom Event is fired.
207 * @param {Event} p_oEvent Object representing the DOM event object
208 * passed back by the event utility (YAHOO.util.Event).
210 function onDOMEvent(p_oEvent) {
212 // Get the target node of the DOM event
214 var oTarget = Event.getTarget(p_oEvent),
216 // See if the target of the event was a menu, or a menu item
218 oElement = getMenuRootElement(oTarget),
228 sTagName = oElement.tagName.toUpperCase();
230 if (sTagName == _LI) {
234 if (sId && m_oItems[sId]) {
236 oMenuItem = m_oItems[sId];
237 oMenu = oMenuItem.parent;
242 else if (sTagName == _DIV) {
246 oMenu = m_oMenus[oElement.id];
257 sCustomEventType = m_oEventTypes[p_oEvent.type];
260 // Fire the Custom Event that corresponds the current DOM event
262 if (oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
264 oMenuItem[sCustomEventType].fire(p_oEvent);
268 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
271 else if (p_oEvent.type == _MOUSEDOWN) {
274 If the target of the event wasn't a menu, hide all
275 dynamically positioned menus
278 for (var i in m_oVisibleMenus) {
280 if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
282 oMenu = m_oVisibleMenus[i];
284 if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) &&
285 !(oMenu instanceof YAHOO.widget.MenuBar) &&
286 oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
293 if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
295 oMenu._cancelShowDelay();
300 if (oMenu.activeItem) {
302 oMenu.activeItem.blur();
303 oMenu.activeItem.cfg.setProperty(_SELECTED, false);
305 oMenu.activeItem = null;
316 else if (p_oEvent.type == _FOCUS) {
318 m_oFocusedElement = oTarget;
326 * @method onMenuDestroy
327 * @description "destroy" event handler for a menu.
329 * @param {String} p_sType String representing the name of the event
331 * @param {Array} p_aArgs Array of arguments sent when the event
333 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
335 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
337 if (m_oMenus[p_oMenu.id]) {
339 this.removeMenu(p_oMenu);
347 * @method onMenuFocus
348 * @description "focus" event handler for a MenuItem instance.
350 * @param {String} p_sType String representing the name of the event
352 * @param {Array} p_aArgs Array of arguments sent when the event
355 function onMenuFocus(p_sType, p_aArgs) {
357 var oItem = p_aArgs[1];
361 m_oFocusedMenuItem = oItem;
370 * @description "blur" event handler for a MenuItem instance.
372 * @param {String} p_sType String representing the name of the event
374 * @param {Array} p_aArgs Array of arguments sent when the event
377 function onMenuBlur(p_sType, p_aArgs) {
379 m_oFocusedMenuItem = null;
386 * @description "hide" event handler for a Menu instance.
388 * @param {String} p_sType String representing the name of the event
390 * @param {Array} p_aArgs Array of arguments sent when the event
392 * @param <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
393 * level-one-html.html#ID-58190037">p_oFocusedElement</a> The HTML element that had focus
394 * prior to the Menu being made visible
396 function onMenuHide(p_sType, p_aArgs, p_oFocusedElement) {
399 Restore focus to the element in the DOM that had focus prior to the Menu
403 if (p_oFocusedElement && p_oFocusedElement.focus) {
406 p_oFocusedElement.focus();
413 this.hideEvent.unsubscribe(onMenuHide, p_oFocusedElement);
420 * @description "show" event handler for a MenuItem instance.
422 * @param {String} p_sType String representing the name of the event
424 * @param {Array} p_aArgs Array of arguments sent when the event
427 function onMenuShow(p_sType, p_aArgs) {
430 Dynamically positioned, root Menus focus themselves when visible, and will then,
431 when hidden, restore focus to the UI control that had focus before the Menu was
435 if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
437 this.hideEvent.subscribe(onMenuHide, m_oFocusedElement);
446 * @method onMenuVisibleConfigChange
447 * @description Event handler for when the "visible" configuration
448 * property of a Menu instance changes.
450 * @param {String} p_sType String representing the name of the event
452 * @param {Array} p_aArgs Array of arguments sent when the event
455 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
457 var bVisible = p_aArgs[0],
462 m_oVisibleMenus[sId] = this;
464 YAHOO.log(this + " added to the collection of visible menus.",
465 "info", _MENUMANAGER);
468 else if (m_oVisibleMenus[sId]) {
470 delete m_oVisibleMenus[sId];
472 YAHOO.log(this + " removed from the collection of visible menus.",
473 "info", _MENUMANAGER);
481 * @method onItemDestroy
482 * @description "destroy" event handler for a MenuItem instance.
484 * @param {String} p_sType String representing the name of the event
486 * @param {Array} p_aArgs Array of arguments sent when the event
489 function onItemDestroy(p_sType, p_aArgs) {
498 * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
500 * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
502 function removeItem(p_oMenuItem) {
504 var sId = p_oMenuItem.id;
506 if (sId && m_oItems[sId]) {
508 if (m_oFocusedMenuItem == p_oMenuItem) {
510 m_oFocusedMenuItem = null;
514 delete m_oItems[sId];
516 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
518 YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
526 * @method onItemAdded
527 * @description "itemadded" event handler for a Menu instance.
529 * @param {String} p_sType String representing the name of the event
531 * @param {Array} p_aArgs Array of arguments sent when the event
534 function onItemAdded(p_sType, p_aArgs) {
536 var oItem = p_aArgs[0],
539 if (oItem instanceof YAHOO.widget.MenuItem) {
543 if (!m_oItems[sId]) {
545 m_oItems[sId] = oItem;
547 oItem.destroyEvent.subscribe(onItemDestroy);
549 YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
560 // Privileged methods
565 * @description Adds a menu to the collection of known menus.
566 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
567 * instance to be added.
569 addMenu: function (p_oMenu) {
573 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
574 !m_oMenus[p_oMenu.id]) {
576 m_oMenus[p_oMenu.id] = p_oMenu;
579 if (!m_bInitializedEventHandlers) {
583 Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
584 Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
585 Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
586 Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
587 Event.on(oDoc, _CLICK, onDOMEvent, this, true);
588 Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
589 Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
590 Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
592 Event.onFocus(oDoc, onDOMEvent, this, true);
593 Event.onBlur(oDoc, onDOMEvent, this, true);
595 m_bInitializedEventHandlers = true;
597 YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
601 p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
602 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
603 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
604 p_oMenu.focusEvent.subscribe(onMenuFocus);
605 p_oMenu.blurEvent.subscribe(onMenuBlur);
606 p_oMenu.showEvent.subscribe(onMenuShow);
608 YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
617 * @description Removes a menu from the collection of known menus.
618 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
619 * instance to be removed.
621 removeMenu: function (p_oMenu) {
631 if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
633 // Unregister each menu item
635 aItems = p_oMenu.getItems();
637 if (aItems && aItems.length > 0) {
639 i = aItems.length - 1;
643 removeItem(aItems[i]);
651 // Unregister the menu
653 delete m_oMenus[sId];
655 YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
659 Unregister the menu from the collection of
663 if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
665 delete m_oVisibleMenus[sId];
667 YAHOO.log(p_oMenu + " unregistered from the" +
668 " collection of visible menus.", "info", _MENUMANAGER);
673 // Unsubscribe event listeners
677 p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE,
678 onMenuVisibleConfigChange);
682 p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
685 p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
686 p_oMenu.focusEvent.unsubscribe(onMenuFocus);
687 p_oMenu.blurEvent.unsubscribe(onMenuBlur);
697 * @method hideVisible
698 * @description Hides all visible, dynamically positioned menus
699 * (excluding instances of YAHOO.widget.MenuBar).
701 hideVisible: function () {
705 for (var i in m_oVisibleMenus) {
707 if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
709 oMenu = m_oVisibleMenus[i];
711 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
712 oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
727 * @description Returns a collection of all visible menus registered
728 * with the menu manger.
731 getVisible: function () {
733 return m_oVisibleMenus;
740 * @description Returns a collection of all menus registered with the
744 getMenus: function () {
753 * @description Returns a menu with the specified id.
754 * @param {String} p_sId String specifying the id of the
755 * <code><div></code> element representing the menu to
757 * @return {YAHOO.widget.Menu}
759 getMenu: function (p_sId) {
763 if (p_sId in m_oMenus) {
765 returnVal = m_oMenus[p_sId];
775 * @method getMenuItem
776 * @description Returns a menu item with the specified id.
777 * @param {String} p_sId String specifying the id of the
778 * <code><li></code> element representing the menu item to
780 * @return {YAHOO.widget.MenuItem}
782 getMenuItem: function (p_sId) {
786 if (p_sId in m_oItems) {
788 returnVal = m_oItems[p_sId];
798 * @method getMenuItemGroup
799 * @description Returns an array of menu item instances whose
800 * corresponding <code><li></code> elements are child
801 * nodes of the <code><ul></code> element with the
803 * @param {String} p_sId String specifying the id of the
804 * <code><ul></code> element representing the group of
805 * menu items to be retrieved.
808 getMenuItemGroup: function (p_sId) {
810 var oUL = Dom.get(p_sId),
818 if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
820 oNode = oUL.firstChild;
832 oItem = this.getMenuItem(sId);
836 aItems[aItems.length] = oItem;
843 while ((oNode = oNode.nextSibling));
846 if (aItems.length > 0) {
862 * @method getFocusedMenuItem
863 * @description Returns a reference to the menu item that currently
865 * @return {YAHOO.widget.MenuItem}
867 getFocusedMenuItem: function () {
869 return m_oFocusedMenuItem;
875 * @method getFocusedMenu
876 * @description Returns a reference to the menu that currently
878 * @return {YAHOO.widget.Menu}
880 getFocusedMenu: function () {
884 if (m_oFocusedMenuItem) {
886 returnVal = m_oFocusedMenuItem.parent.getRoot();
897 * @description Returns a string representing the menu manager.
900 toString: function () {
916 var Lang = YAHOO.lang,
921 _DIV_UPPERCASE = "DIV",
922 _DIV_LOWERCASE = "div",
927 _UL_UPPERCASE = "UL",
928 _UL_LOWERCASE = "ul",
929 _FIRST_OF_TYPE = "first-of-type",
931 _OPTGROUP = "OPTGROUP",
933 _DISABLED = "disabled",
935 _SELECTED = "selected",
936 _GROUP_INDEX = "groupindex",
938 _SUBMENU = "submenu",
939 _VISIBLE = "visible",
940 _HIDE_DELAY = "hidedelay",
941 _POSITION = "position",
942 _DYNAMIC = "dynamic",
944 _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
945 _WINDOWS = "windows",
949 _MAX_HEIGHT = "maxheight",
950 _TOP_SCROLLBAR = "topscrollbar",
951 _BOTTOM_SCROLLBAR = "bottomscrollbar",
953 _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
954 _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
955 _MOUSEMOVE = "mousemove",
956 _SHOW_DELAY = "showdelay",
957 _SUBMENU_HIDE_DELAY = "submenuhidedelay",
959 _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
960 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
961 _SUBMENU_ALIGNMENT = "submenualignment",
962 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
963 _CLICK_TO_HIDE = "clicktohide",
964 _CONTAINER = "container",
965 _SCROLL_INCREMENT = "scrollincrement",
966 _MIN_SCROLL_HEIGHT = "minscrollheight",
967 _CLASSNAME = "classname",
969 _KEEP_OPEN = "keepopen",
971 _HAS_TITLE = "hastitle",
972 _CONTEXT = "context",
974 _MOUSEDOWN = "mousedown",
975 _KEYDOWN = "keydown",
980 _MONITOR_RESIZE = "monitorresize",
981 _DISPLAY = "display",
983 _VISIBILITY = "visibility",
984 _ABSOLUTE = "absolute",
986 _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
987 _NON_BREAKING_SPACE = " ",
989 _MOUSEOVER = "mouseover",
990 _MOUSEOUT = "mouseout",
991 _ITEM_ADDED = "itemAdded",
992 _ITEM_REMOVED = "itemRemoved",
994 _YUI_MENU_SHADOW = "yui-menu-shadow",
995 _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
996 _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
1000 * The Menu class creates a container that holds a vertical list representing
1001 * a set of options or commands. Menu is the base class for all
1003 * @param {String} p_oElement String specifying the id attribute of the
1004 * <code><div></code> element of the menu.
1005 * @param {String} p_oElement String specifying the id attribute of the
1006 * <code><select></code> element to be used as the data source
1008 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1009 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1010 * specifying the <code><div></code> element of the menu.
1011 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1012 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1013 * Object specifying the <code><select></code> element to be used as
1014 * the data source for the menu.
1015 * @param {Object} p_oConfig Optional. Object literal specifying the
1016 * configuration for the menu. See configuration class documentation for
1018 * @namespace YAHOO.widget
1021 * @extends YAHOO.widget.Overlay
1023 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
1027 this.parent = p_oConfig.parent;
1028 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
1029 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
1034 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1041 * @method checkPosition
1042 * @description Checks to make sure that the value of the "position" property
1043 * is one of the supported strings. Returns true if the position is supported.
1045 * @param {Object} p_sPosition String specifying the position of the menu.
1048 function checkPosition(p_sPosition) {
1050 var returnVal = false;
1052 if (Lang.isString(p_sPosition)) {
1054 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1063 var Dom = YAHOO.util.Dom,
1064 Event = YAHOO.util.Event,
1065 Module = YAHOO.widget.Module,
1066 Overlay = YAHOO.widget.Overlay,
1067 Menu = YAHOO.widget.Menu,
1068 MenuManager = YAHOO.widget.MenuManager,
1069 CustomEvent = YAHOO.util.CustomEvent,
1076 ["mouseOverEvent", _MOUSEOVER],
1077 ["mouseOutEvent", _MOUSEOUT],
1078 ["mouseDownEvent", _MOUSEDOWN],
1079 ["mouseUpEvent", "mouseup"],
1080 ["clickEvent", "click"],
1081 ["keyPressEvent", "keypress"],
1082 ["keyDownEvent", _KEYDOWN],
1083 ["keyUpEvent", "keyup"],
1084 ["focusEvent", "focus"],
1085 ["blurEvent", "blur"],
1086 ["itemAddedEvent", _ITEM_ADDED],
1087 ["itemRemovedEvent", _ITEM_REMOVED]
1094 validator: Lang.isBoolean
1097 CONSTRAIN_TO_VIEWPORT_CONFIG = {
1098 key: _CONSTRAIN_TO_VIEWPORT,
1100 validator: Lang.isBoolean,
1101 supercedes: [_IFRAME,"x",_Y,_XY]
1104 PREVENT_CONTEXT_OVERLAP_CONFIG = {
1105 key: _PREVENT_CONTEXT_OVERLAP,
1107 validator: Lang.isBoolean,
1108 supercedes: [_CONSTRAIN_TO_VIEWPORT]
1114 validator: checkPosition,
1115 supercedes: [_VISIBLE, _IFRAME]
1118 SUBMENU_ALIGNMENT_CONFIG = {
1119 key: _SUBMENU_ALIGNMENT,
1123 AUTO_SUBMENU_DISPLAY_CONFIG = {
1124 key: _AUTO_SUBMENU_DISPLAY,
1126 validator: Lang.isBoolean,
1130 SHOW_DELAY_CONFIG = {
1133 validator: Lang.isNumber,
1137 HIDE_DELAY_CONFIG = {
1140 validator: Lang.isNumber,
1144 SUBMENU_HIDE_DELAY_CONFIG = {
1145 key: _SUBMENU_HIDE_DELAY,
1147 validator: Lang.isNumber,
1151 CLICK_TO_HIDE_CONFIG = {
1152 key: _CLICK_TO_HIDE,
1154 validator: Lang.isBoolean,
1158 CONTAINER_CONFIG = {
1163 SCROLL_INCREMENT_CONFIG = {
1164 key: _SCROLL_INCREMENT,
1166 validator: Lang.isNumber,
1167 supercedes: [_MAX_HEIGHT],
1171 MIN_SCROLL_HEIGHT_CONFIG = {
1172 key: _MIN_SCROLL_HEIGHT,
1174 validator: Lang.isNumber,
1175 supercedes: [_MAX_HEIGHT],
1179 MAX_HEIGHT_CONFIG = {
1182 validator: Lang.isNumber,
1183 supercedes: [_IFRAME],
1187 CLASS_NAME_CONFIG = {
1190 validator: Lang.isString,
1197 validator: Lang.isBoolean,
1204 validator: Lang.isBoolean,
1205 suppressEvent: true,
1206 supercedes: [_VISIBLE]
1209 KEEP_OPEN_CONFIG = {
1212 validator: Lang.isBoolean
1217 YAHOO.lang.extend(Menu, Overlay, {
1224 * @property CSS_CLASS_NAME
1225 * @description String representing the CSS class(es) to be applied to the
1226 * menu's <code><div></code> element.
1227 * @default "yuimenu"
1231 CSS_CLASS_NAME: "yuimenu",
1235 * @property ITEM_TYPE
1236 * @description Object representing the type of menu item to instantiate and
1237 * add when parsing the child nodes (either <code><li></code> element,
1238 * <code><optgroup></code> element or <code><option></code>)
1239 * of the menu's source HTML element.
1240 * @default YAHOO.widget.MenuItem
1242 * @type YAHOO.widget.MenuItem
1248 * @property GROUP_TITLE_TAG_NAME
1249 * @description String representing the tagname of the HTML element used to
1250 * title the menu's item groups.
1255 GROUP_TITLE_TAG_NAME: "h6",
1259 * @property OFF_SCREEN_POSITION
1260 * @description Array representing the default x and y position that a menu
1261 * should have when it is positioned outside the viewport by the
1262 * "poistionOffScreen" method.
1267 OFF_SCREEN_POSITION: "-999em",
1270 // Private properties
1274 * @property _useHideDelay
1275 * @description Boolean indicating if the "mouseover" and "mouseout" event
1276 * handlers used for hiding the menu via a call to "YAHOO.lang.later" have
1277 * already been assigned.
1282 _useHideDelay: false,
1286 * @property _bHandledMouseOverEvent
1287 * @description Boolean indicating the current state of the menu's
1288 * "mouseover" event.
1293 _bHandledMouseOverEvent: false,
1297 * @property _bHandledMouseOutEvent
1298 * @description Boolean indicating the current state of the menu's
1304 _bHandledMouseOutEvent: false,
1308 * @property _aGroupTitleElements
1309 * @description Array of HTML element used to title groups of menu items.
1314 _aGroupTitleElements: null,
1318 * @property _aItemGroups
1319 * @description Multi-dimensional Array representing the menu items as they
1320 * are grouped in the menu.
1329 * @property _aListElements
1330 * @description Array of <code><ul></code> elements, each of which is
1331 * the parent node for each item's <code><li></code> element.
1336 _aListElements: null,
1340 * @property _nCurrentMouseX
1341 * @description The current x coordinate of the mouse inside the area of
1351 * @property _bStopMouseEventHandlers
1352 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1358 _bStopMouseEventHandlers: false,
1362 * @property _sClassName
1363 * @description The current value of the "classname" configuration attribute.
1372 // Public properties
1376 * @property lazyLoad
1377 * @description Boolean indicating if the menu's "lazy load" feature is
1378 * enabled. If set to "true," initialization and rendering of the menu's
1379 * items will be deferred until the first time it is made visible. This
1380 * property should be set via the constructor using the configuration
1389 * @property itemData
1390 * @description Array of items to be added to the menu. The array can contain
1391 * strings representing the text for each item to be created, object literals
1392 * representing the menu item configuration properties, or MenuItem instances.
1393 * This property should be set via the constructor using the configuration
1402 * @property activeItem
1403 * @description Object reference to the item in the menu that has is selected.
1405 * @type YAHOO.widget.MenuItem
1412 * @description Object reference to the menu's parent menu or menu item.
1413 * This property can be set via the constructor using the configuration
1416 * @type YAHOO.widget.MenuItem
1422 * @property srcElement
1423 * @description Object reference to the HTML element (either
1424 * <code><select></code> or <code><div></code>) used to
1427 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1428 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1429 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1430 * html#ID-22445964">HTMLDivElement</a>
1440 * @event mouseOverEvent
1441 * @description Fires when the mouse has entered the menu. Passes back
1442 * the DOM Event object as an argument.
1447 * @event mouseOutEvent
1448 * @description Fires when the mouse has left the menu. Passes back the DOM
1449 * Event object as an argument.
1450 * @type YAHOO.util.CustomEvent
1455 * @event mouseDownEvent
1456 * @description Fires when the user mouses down on the menu. Passes back the
1457 * DOM Event object as an argument.
1458 * @type YAHOO.util.CustomEvent
1463 * @event mouseUpEvent
1464 * @description Fires when the user releases a mouse button while the mouse is
1465 * over the menu. Passes back the DOM Event object as an argument.
1466 * @type YAHOO.util.CustomEvent
1472 * @description Fires when the user clicks the on the menu. Passes back the
1473 * DOM Event object as an argument.
1474 * @type YAHOO.util.CustomEvent
1479 * @event keyPressEvent
1480 * @description Fires when the user presses an alphanumeric key when one of the
1481 * menu's items has focus. Passes back the DOM Event object as an argument.
1482 * @type YAHOO.util.CustomEvent
1487 * @event keyDownEvent
1488 * @description Fires when the user presses a key when one of the menu's items
1489 * has focus. Passes back the DOM Event object as an argument.
1490 * @type YAHOO.util.CustomEvent
1496 * @description Fires when the user releases a key when one of the menu's items
1497 * has focus. Passes back the DOM Event object as an argument.
1498 * @type YAHOO.util.CustomEvent
1503 * @event itemAddedEvent
1504 * @description Fires when an item is added to the menu.
1505 * @type YAHOO.util.CustomEvent
1510 * @event itemRemovedEvent
1511 * @description Fires when an item is removed to the menu.
1512 * @type YAHOO.util.CustomEvent
1518 * @description The Menu class's initialization method. This method is
1519 * automatically called by the constructor, and sets up all DOM references
1520 * for pre-existing markup, and creates required markup if it is not
1522 * @param {String} p_oElement String specifying the id attribute of the
1523 * <code><div></code> element of the menu.
1524 * @param {String} p_oElement String specifying the id attribute of the
1525 * <code><select></code> element to be used as the data source
1527 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1528 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1529 * specifying the <code><div></code> element of the menu.
1530 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1531 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1532 * Object specifying the <code><select></code> element to be used as
1533 * the data source for the menu.
1534 * @param {Object} p_oConfig Optional. Object literal specifying the
1535 * configuration for the menu. See configuration class documentation for
1538 init: function (p_oElement, p_oConfig) {
1540 this._aItemGroups = [];
1541 this._aListElements = [];
1542 this._aGroupTitleElements = [];
1544 if (!this.ITEM_TYPE) {
1546 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1553 if (Lang.isString(p_oElement)) {
1555 oElement = Dom.get(p_oElement);
1558 else if (p_oElement.tagName) {
1560 oElement = p_oElement;
1565 if (oElement && oElement.tagName) {
1567 switch(oElement.tagName.toUpperCase()) {
1569 case _DIV_UPPERCASE:
1571 this.srcElement = oElement;
1575 oElement.setAttribute(_ID, Dom.generateId());
1581 Note: we don't pass the user config in here yet
1582 because we only want it executed once, at the lowest
1586 Menu.superclass.init.call(this, oElement);
1588 this.beforeInitEvent.fire(Menu);
1590 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1596 this.srcElement = oElement;
1600 The source element is not something that we can use
1601 outright, so we need to create a new Overlay
1603 Note: we don't pass the user config in here yet
1604 because we only want it executed once, at the lowest
1608 Menu.superclass.init.call(this, Dom.generateId());
1610 this.beforeInitEvent.fire(Menu);
1612 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1622 Note: we don't pass the user config in here yet
1623 because we only want it executed once, at the lowest
1627 Menu.superclass.init.call(this, p_oElement);
1629 this.beforeInitEvent.fire(Menu);
1631 YAHOO.log("No source element found. Created element with id: " + this.id, "info", this.toString());
1638 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1641 // Subscribe to Custom Events
1643 this.initEvent.subscribe(this._onInit);
1644 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1645 this.renderEvent.subscribe(this._onRender);
1646 this.beforeShowEvent.subscribe(this._onBeforeShow);
1647 this.hideEvent.subscribe(this._onHide);
1648 this.showEvent.subscribe(this._onShow);
1649 this.beforeHideEvent.subscribe(this._onBeforeHide);
1650 this.mouseOverEvent.subscribe(this._onMouseOver);
1651 this.mouseOutEvent.subscribe(this._onMouseOut);
1652 this.clickEvent.subscribe(this._onClick);
1653 this.keyDownEvent.subscribe(this._onKeyDown);
1654 this.keyPressEvent.subscribe(this._onKeyPress);
1655 this.blurEvent.subscribe(this._onBlur);
1658 // Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY"
1659 // methods return values that don't take scrollTop into consideration
1661 if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) {
1663 this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1670 this.cfg.applyConfig(p_oConfig, true);
1675 // Register the Menu instance with the MenuManager
1677 MenuManager.addMenu(this);
1680 this.initEvent.fire(Menu);
1692 * @method _initSubTree
1693 * @description Iterates the childNodes of the source element to find nodes
1694 * used to instantiate menu and menu items.
1697 _initSubTree: function () {
1699 var oSrcElement = this.srcElement,
1711 sSrcElementTagName =
1712 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1715 if (sSrcElementTagName == _DIV_UPPERCASE) {
1717 // Populate the collection of item groups and item group titles
1719 oNode = this.body.firstChild;
1725 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1730 if (oNode && oNode.tagName) {
1732 switch (oNode.tagName.toUpperCase()) {
1734 case sGroupTitleTagName:
1736 this._aGroupTitleElements[nGroup] = oNode;
1742 this._aListElements[nGroup] = oNode;
1743 this._aItemGroups[nGroup] = [];
1753 while ((oNode = oNode.nextSibling));
1757 Apply the "first-of-type" class to the first UL to mimic
1758 the ":first-of-type" CSS3 psuedo class.
1761 if (this._aListElements[0]) {
1763 Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1774 YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
1777 if (sSrcElementTagName) {
1779 switch (sSrcElementTagName) {
1781 case _DIV_UPPERCASE:
1783 aListElements = this._aListElements;
1784 nListElements = aListElements.length;
1786 if (nListElements > 0) {
1788 YAHOO.log("Found " + nListElements + " item groups to initialize.",
1789 "info", this.toString());
1791 i = nListElements - 1;
1795 oNode = aListElements[i].firstChild;
1799 YAHOO.log("Scanning " +
1800 aListElements[i].childNodes.length +
1801 " child nodes for items to initialize.", "info", this.toString());
1805 if (oNode && oNode.tagName &&
1806 oNode.tagName.toUpperCase() == _LI) {
1808 YAHOO.log("Initializing " +
1809 oNode.tagName + " node.", "info", this.toString());
1811 this.addItem(new this.ITEM_TYPE(oNode,
1812 { parent: this }), i);
1817 while ((oNode = oNode.nextSibling));
1830 YAHOO.log("Scanning " +
1831 oSrcElement.childNodes.length +
1832 " child nodes for items to initialize.", "info", this.toString());
1834 oNode = oSrcElement.firstChild;
1838 if (oNode && oNode.tagName) {
1840 switch (oNode.tagName.toUpperCase()) {
1845 YAHOO.log("Initializing " +
1846 oNode.tagName + " node.", "info", this.toString());
1862 while ((oNode = oNode.nextSibling));
1876 * @method _getFirstEnabledItem
1877 * @description Returns the first enabled item in the menu.
1878 * @return {YAHOO.widget.MenuItem}
1881 _getFirstEnabledItem: function () {
1883 var aItems = this.getItems(),
1884 nItems = aItems.length,
1889 for(var i=0; i<nItems; i++) {
1893 if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1908 * @method _addItemToGroup
1909 * @description Adds a menu item to a group.
1911 * @param {Number} p_nGroupIndex Number indicating the group to which the
1913 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1914 * instance to be added to the menu.
1915 * @param {String} p_oItem String specifying the text of the item to be added
1917 * @param {Object} p_oItem Object literal containing a set of menu item
1918 * configuration properties.
1919 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1920 * which the menu item should be added.
1921 * @return {YAHOO.widget.MenuItem}
1923 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1935 function getNextItemSibling(p_aArray, p_nStartIndex) {
1937 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1942 if (p_oItem instanceof this.ITEM_TYPE) {
1945 oItem.parent = this;
1948 else if (Lang.isString(p_oItem)) {
1950 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1953 else if (Lang.isObject(p_oItem)) {
1955 p_oItem.parent = this;
1957 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1964 if (oItem.cfg.getProperty(_SELECTED)) {
1966 this.activeItem = oItem;
1971 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1972 aGroup = this._getItemGroup(nGroupIndex);
1978 aGroup = this._createItemGroup(nGroupIndex);
1983 if (Lang.isNumber(p_nItemIndex)) {
1985 bAppend = (p_nItemIndex >= aGroup.length);
1988 if (aGroup[p_nItemIndex]) {
1990 aGroup.splice(p_nItemIndex, 0, oItem);
1995 aGroup[p_nItemIndex] = oItem;
2000 oGroupItem = aGroup[p_nItemIndex];
2004 if (bAppend && (!oGroupItem.element.parentNode ||
2005 oGroupItem.element.parentNode.nodeType == 11)) {
2007 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2012 oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
2014 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
2015 oGroupItem.element.parentNode.nodeType == 11)) {
2017 this._aListElements[nGroupIndex].insertBefore(
2018 oGroupItem.element, oNextItemSibling.element);
2025 oGroupItem.parent = this;
2027 this._subscribeToItemEvents(oGroupItem);
2029 this._configureSubmenu(oGroupItem);
2031 this._updateItemProperties(nGroupIndex);
2033 YAHOO.log("Item inserted." +
2034 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
2035 " Index: " + oGroupItem.index + ", " +
2036 " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2038 this.itemAddedEvent.fire(oGroupItem);
2039 this.changeContentEvent.fire();
2041 returnVal = oGroupItem;
2048 nItemIndex = aGroup.length;
2050 aGroup[nItemIndex] = oItem;
2052 oGroupItem = aGroup[nItemIndex];
2057 if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2059 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2063 oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2064 oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2066 oGroupItem.parent = this;
2068 oGroupItem.index = nItemIndex;
2069 oGroupItem.groupIndex = nGroupIndex;
2071 this._subscribeToItemEvents(oGroupItem);
2073 this._configureSubmenu(oGroupItem);
2075 if (nItemIndex === 0) {
2077 Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2081 YAHOO.log("Item added." +
2082 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
2083 " Index: " + oGroupItem.index + ", " +
2084 " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2087 this.itemAddedEvent.fire(oGroupItem);
2088 this.changeContentEvent.fire();
2090 returnVal = oGroupItem;
2104 * @method _removeItemFromGroupByIndex
2105 * @description Removes a menu item from a group by index. Returns the menu
2106 * item that was removed.
2108 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
2110 * @param {Number} p_nItemIndex Number indicating the index of the menu item
2112 * @return {YAHOO.widget.MenuItem}
2114 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2116 var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2117 aGroup = this._getItemGroup(nGroupIndex),
2124 aArray = aGroup.splice(p_nItemIndex, 1);
2129 // Update the index and className properties of each member
2131 this._updateItemProperties(nGroupIndex);
2133 if (aGroup.length === 0) {
2137 oUL = this._aListElements[nGroupIndex];
2139 if (this.body && oUL) {
2141 this.body.removeChild(oUL);
2145 // Remove the group from the array of items
2147 this._aItemGroups.splice(nGroupIndex, 1);
2150 // Remove the UL from the array of ULs
2152 this._aListElements.splice(nGroupIndex, 1);
2156 Assign the "first-of-type" class to the new first UL
2160 oUL = this._aListElements[0];
2164 Dom.addClass(oUL, _FIRST_OF_TYPE);
2171 this.itemRemovedEvent.fire(oItem);
2172 this.changeContentEvent.fire();
2178 // Return a reference to the item that was removed
2186 * @method _removeItemFromGroupByValue
2187 * @description Removes a menu item from a group by reference. Returns the
2188 * menu item that was removed.
2190 * @param {Number} p_nGroupIndex Number indicating the group to which the
2191 * menu item belongs.
2192 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2193 * instance to be removed.
2194 * @return {YAHOO.widget.MenuItem}
2196 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2198 var aGroup = this._getItemGroup(p_nGroupIndex),
2206 nItems = aGroup.length;
2215 if (aGroup[i] == p_oItem) {
2225 if (nItemIndex > -1) {
2227 returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2241 * @method _updateItemProperties
2242 * @description Updates the "index," "groupindex," and "className" properties
2243 * of the menu items in the specified group.
2245 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2247 _updateItemProperties: function (p_nGroupIndex) {
2249 var aGroup = this._getItemGroup(p_nGroupIndex),
2250 nItems = aGroup.length,
2260 // Update the index and className properties of each member
2268 oLI = oItem.element;
2271 oItem.groupIndex = p_nGroupIndex;
2273 oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2274 oLI.setAttribute(_INDEX, i);
2276 Dom.removeClass(oLI, _FIRST_OF_TYPE);
2286 Dom.addClass(oLI, _FIRST_OF_TYPE);
2296 * @method _createItemGroup
2297 * @description Creates a new menu item group (array) and its associated
2298 * <code><ul></code> element. Returns an aray of menu item groups.
2300 * @param {Number} p_nIndex Number indicating the group to create.
2303 _createItemGroup: function (p_nIndex) {
2308 if (!this._aItemGroups[p_nIndex]) {
2310 this._aItemGroups[p_nIndex] = [];
2312 oUL = document.createElement(_UL_LOWERCASE);
2314 this._aListElements[p_nIndex] = oUL;
2316 returnVal = this._aItemGroups[p_nIndex];
2326 * @method _getItemGroup
2327 * @description Returns the menu item group at the specified index.
2329 * @param {Number} p_nIndex Number indicating the index of the menu item group
2333 _getItemGroup: function (p_nIndex) {
2335 var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2336 aGroups = this._aItemGroups,
2339 if (nIndex in aGroups) {
2341 returnVal = aGroups[nIndex];
2351 * @method _configureSubmenu
2352 * @description Subscribes the menu item's submenu to its parent menu's events.
2354 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2355 * instance with the submenu to be configured.
2357 _configureSubmenu: function (p_oItem) {
2359 var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2364 Listen for configuration changes to the parent menu
2365 so they they can be applied to the submenu.
2368 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2370 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2380 * @method _subscribeToItemEvents
2381 * @description Subscribes a menu to a menu item's event.
2383 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2384 * instance whose events should be subscribed to.
2386 _subscribeToItemEvents: function (p_oItem) {
2388 p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2389 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2395 * @method _onVisibleChange
2396 * @description Change event handler for the the menu's "visible" configuration
2399 * @param {String} p_sType String representing the name of the event that
2401 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2403 _onVisibleChange: function (p_sType, p_aArgs) {
2405 var bVisible = p_aArgs[0];
2409 Dom.addClass(this.element, _VISIBLE);
2414 Dom.removeClass(this.element, _VISIBLE);
2422 * @method _cancelHideDelay
2423 * @description Cancels the call to "hideMenu."
2426 _cancelHideDelay: function () {
2428 var oTimer = this.getRoot()._hideDelayTimer;
2440 * @method _execHideDelay
2441 * @description Hides the menu after the number of milliseconds specified by
2442 * the "hidedelay" configuration property.
2445 _execHideDelay: function () {
2447 this._cancelHideDelay();
2449 var oRoot = this.getRoot();
2451 oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2453 if (oRoot.activeItem) {
2455 if (oRoot.hasFocus()) {
2457 oRoot.activeItem.focus();
2461 oRoot.clearActiveItem();
2465 if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) &&
2466 this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2478 * @method _cancelShowDelay
2479 * @description Cancels the call to the "showMenu."
2482 _cancelShowDelay: function () {
2484 var oTimer = this.getRoot()._showDelayTimer;
2496 * @method _execSubmenuHideDelay
2497 * @description Hides a submenu after the number of milliseconds specified by
2498 * the "submenuhidedelay" configuration property have ellapsed.
2500 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2502 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2503 * the specified submenu's parent menu item.
2504 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2505 * before the submenu is hidden.
2507 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2509 p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2511 if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2513 p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2532 // Protected methods
2536 * @method _disableScrollHeader
2537 * @description Disables the header used for scrolling the body of the menu.
2540 _disableScrollHeader: function () {
2542 if (!this._bHeaderDisabled) {
2544 Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2545 this._bHeaderDisabled = true;
2553 * @method _disableScrollFooter
2554 * @description Disables the footer used for scrolling the body of the menu.
2557 _disableScrollFooter: function () {
2559 if (!this._bFooterDisabled) {
2561 Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2562 this._bFooterDisabled = true;
2570 * @method _enableScrollHeader
2571 * @description Enables the header used for scrolling the body of the menu.
2574 _enableScrollHeader: function () {
2576 if (this._bHeaderDisabled) {
2578 Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2579 this._bHeaderDisabled = false;
2587 * @method _enableScrollFooter
2588 * @description Enables the footer used for scrolling the body of the menu.
2591 _enableScrollFooter: function () {
2593 if (this._bFooterDisabled) {
2595 Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2596 this._bFooterDisabled = false;
2604 * @method _onMouseOver
2605 * @description "mouseover" event handler for the menu.
2607 * @param {String} p_sType String representing the name of the event that
2609 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2611 _onMouseOver: function (p_sType, p_aArgs) {
2613 var oEvent = p_aArgs[0],
2615 oTarget = Event.getTarget(oEvent),
2616 oRoot = this.getRoot(),
2617 oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2626 var showSubmenu = function () {
2628 if (this.parent.cfg.getProperty(_SELECTED)) {
2637 if (!this._bStopMouseEventHandlers) {
2639 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2640 Dom.isAncestor(this.element, oTarget))) {
2642 // Menu mouseover logic
2644 if (this._useHideDelay) {
2645 this._cancelHideDelay();
2648 this._nCurrentMouseX = 0;
2650 Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2654 If the mouse is moving from the submenu back to its corresponding menu item,
2655 don't hide the submenu or clear the active MenuItem.
2658 if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2660 this.clearActiveItem();
2665 if (this.parent && oSubmenuHideDelayTimer) {
2667 oSubmenuHideDelayTimer.cancel();
2669 this.parent.cfg.setProperty(_SELECTED, true);
2671 oParentMenu = this.parent.parent;
2673 oParentMenu._bHandledMouseOutEvent = true;
2674 oParentMenu._bHandledMouseOverEvent = false;
2679 this._bHandledMouseOverEvent = true;
2680 this._bHandledMouseOutEvent = false;
2685 if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) &&
2686 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2688 // Menu Item mouseover logic
2690 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2691 bShowDelay = (nShowDelay > 0);
2696 this._cancelShowDelay();
2701 oActiveItem = this.activeItem;
2705 oActiveItem.cfg.setProperty(_SELECTED, false);
2710 oItemCfg = oItem.cfg;
2712 // Select and focus the current menu item
2714 oItemCfg.setProperty(_SELECTED, true);
2717 if (this.hasFocus() || oRoot._hasFocus) {
2721 oRoot._hasFocus = false;
2726 if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2728 // Show the submenu this menu item
2730 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2736 oRoot._showDelayTimer =
2737 Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2750 oItem.handledMouseOverEvent = true;
2751 oItem.handledMouseOutEvent = false;
2761 * @method _onMouseOut
2762 * @description "mouseout" event handler for the menu.
2764 * @param {String} p_sType String representing the name of the event that
2766 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2768 _onMouseOut: function (p_sType, p_aArgs) {
2770 var oEvent = p_aArgs[0],
2772 oRelatedTarget = Event.getRelatedTarget(oEvent),
2773 bMovingToSubmenu = false,
2780 if (!this._bStopMouseEventHandlers) {
2782 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2784 oItemCfg = oItem.cfg;
2785 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2788 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2789 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2791 bMovingToSubmenu = true;
2796 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2797 !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2799 // Menu Item mouseout logic
2801 if (!bMovingToSubmenu) {
2803 oItem.cfg.setProperty(_SELECTED, false);
2808 nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2810 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2812 if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 &&
2813 nShowDelay >= nSubmenuHideDelay) {
2815 this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
2830 oItem.handledMouseOutEvent = true;
2831 oItem.handledMouseOverEvent = false;
2838 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2839 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2841 // Menu mouseout logic
2843 if (this._useHideDelay) {
2844 this._execHideDelay();
2847 Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2849 this._nCurrentMouseX = Event.getPageX(oEvent);
2851 this._bHandledMouseOutEvent = true;
2852 this._bHandledMouseOverEvent = false;
2862 * @method _onMouseMove
2863 * @description "click" event handler for the menu.
2865 * @param {Event} p_oEvent Object representing the DOM event object passed
2866 * back by the event utility (YAHOO.util.Event).
2867 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2870 _onMouseMove: function (p_oEvent, p_oMenu) {
2872 if (!this._bStopMouseEventHandlers) {
2874 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2883 * @description "click" event handler for the menu.
2885 * @param {String} p_sType String representing the name of the event that
2887 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2889 _onClick: function (p_sType, p_aArgs) {
2891 var oEvent = p_aArgs[0],
2893 bInMenuAnchor = false,
2903 var hide = function () {
2906 There is an inconsistency between Firefox for Mac OS X and Firefox Windows
2907 regarding the triggering of the display of the browser's context menu and the
2908 subsequent firing of the "click" event. In Firefox for Windows, when the user
2909 triggers the display of the browser's context menu the "click" event also fires
2910 for the document object, even though the "click" event did not fire for the
2911 element that was the original target of the "contextmenu" event. This is unique
2912 to Firefox on Windows. For all other A-Grade browsers, including Firefox for
2913 Mac OS X, the "click" event doesn't fire for the document object.
2915 This bug in Firefox for Windows affects Menu as Menu instances listen for
2916 events at the document level and have an internal "click" event handler they
2917 use to hide themselves when clicked. As a result, in Firefox for Windows a
2918 Menu will hide when the user right clicks on a MenuItem to raise the browser's
2919 default context menu, because its internal "click" event handler ends up
2920 getting called. The following line fixes this bug.
2923 if (!((UA.gecko && this.platform == _WINDOWS) && oEvent.button > 0)) {
2925 oRoot = this.getRoot();
2927 if (oRoot instanceof YAHOO.widget.MenuBar ||
2928 oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2930 oRoot.clearActiveItem();
2946 if (oItem.cfg.getProperty(_DISABLED)) {
2948 Event.preventDefault(oEvent);
2955 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2959 Check if the URL of the anchor is pointing to an element that is
2960 a child of the menu.
2963 sURL = oItem.cfg.getProperty(_URL);
2968 nHashPos = sURL.indexOf(_HASH);
2973 if (nHashPos != -1) {
2975 sURL = sURL.substr(nHashPos, nLen);
2982 sId = sURL.substr(1, nLen);
2984 oMenu = YAHOO.widget.MenuManager.getMenu(sId);
2989 (this.getRoot() === oMenu.getRoot());
2994 else if (nLen === 1) {
2996 bInMenuAnchor = true;
3005 if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
3007 Event.preventDefault(oEvent);
3017 oItem.focusEvent.fire();
3024 if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
3038 * @method _onKeyDown
3039 * @description "keydown" event handler for the menu.
3041 * @param {String} p_sType String representing the name of the event that
3043 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3045 _onKeyDown: function (p_sType, p_aArgs) {
3047 var oEvent = p_aArgs[0],
3064 if (this._useHideDelay) {
3065 this._cancelHideDelay();
3070 This function is called to prevent a bug in Firefox. In Firefox,
3071 moving a DOM element into a stationary mouse pointer will cause the
3072 browser to fire mouse events. This can result in the menu mouse
3073 event handlers being called uncessarily, especially when menus are
3074 moved into a stationary mouse pointer as a result of a
3077 function stopMouseEventHandlers() {
3079 this._bStopMouseEventHandlers = true;
3081 Lang.later(10, this, function () {
3083 this._bStopMouseEventHandlers = false;
3090 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
3092 oItemCfg = oItem.cfg;
3093 oParentItem = this.parent;
3095 switch(oEvent.keyCode) {
3097 case 38: // Up arrow
3098 case 40: // Down arrow
3100 oNextItem = (oEvent.keyCode == 38) ?
3101 oItem.getPreviousEnabledSibling() :
3102 oItem.getNextEnabledSibling();
3106 this.clearActiveItem();
3108 oNextItem.cfg.setProperty(_SELECTED, true);
3112 if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
3115 nBodyScrollTop = oBody.scrollTop;
3116 nBodyOffsetHeight = oBody.offsetHeight;
3117 aItems = this.getItems();
3118 nItems = aItems.length - 1;
3119 nNextItemOffsetTop = oNextItem.element.offsetTop;
3122 if (oEvent.keyCode == 40 ) { // Down
3124 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3126 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3129 else if (nNextItemOffsetTop <= nBodyScrollTop) {
3131 oBody.scrollTop = 0;
3136 if (oNextItem == aItems[nItems]) {
3138 oBody.scrollTop = oNextItem.element.offsetTop;
3145 if (nNextItemOffsetTop <= nBodyScrollTop) {
3147 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3150 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3152 oBody.scrollTop = nNextItemOffsetTop;
3157 if (oNextItem == aItems[0]) {
3159 oBody.scrollTop = 0;
3166 nBodyScrollTop = oBody.scrollTop;
3167 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3169 if (nBodyScrollTop === 0) {
3171 this._disableScrollHeader();
3172 this._enableScrollFooter();
3175 else if (nBodyScrollTop == nScrollTarget) {
3177 this._enableScrollHeader();
3178 this._disableScrollFooter();
3183 this._enableScrollHeader();
3184 this._enableScrollFooter();
3193 Event.preventDefault(oEvent);
3195 stopMouseEventHandlers();
3200 case 39: // Right arrow
3202 oSubmenu = oItemCfg.getProperty(_SUBMENU);
3206 if (!oItemCfg.getProperty(_SELECTED)) {
3208 oItemCfg.setProperty(_SELECTED, true);
3213 oSubmenu.setInitialFocus();
3214 oSubmenu.setInitialSelection();
3219 oRoot = this.getRoot();
3221 if (oRoot instanceof YAHOO.widget.MenuBar) {
3223 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3227 oRoot.clearActiveItem();
3229 oNextItem.cfg.setProperty(_SELECTED, true);
3231 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3236 oSubmenu.setInitialFocus();
3252 Event.preventDefault(oEvent);
3254 stopMouseEventHandlers();
3259 case 37: // Left arrow
3263 oParentMenu = oParentItem.parent;
3265 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3268 oParentMenu.activeItem.getPreviousEnabledSibling();
3272 oParentMenu.clearActiveItem();
3274 oNextItem.cfg.setProperty(_SELECTED, true);
3276 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3281 oSubmenu.setInitialFocus();
3297 oParentItem.focus();
3303 Event.preventDefault(oEvent);
3305 stopMouseEventHandlers();
3315 if (oEvent.keyCode == 27) { // Esc key
3317 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3323 this.parent.focus();
3328 else if (this.activeItem) {
3330 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3332 if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3335 this.activeItem.focus();
3340 this.activeItem.blur();
3341 this.activeItem.cfg.setProperty(_SELECTED, false);
3348 Event.preventDefault(oEvent);
3356 * @method _onKeyPress
3357 * @description "keypress" event handler for a Menu instance.
3359 * @param {String} p_sType The name of the event that was fired.
3360 * @param {Array} p_aArgs Collection of arguments sent when the event
3363 _onKeyPress: function (p_sType, p_aArgs) {
3365 var oEvent = p_aArgs[0];
3368 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3370 Event.preventDefault(oEvent);
3379 * @description "blur" event handler for a Menu instance.
3381 * @param {String} p_sType The name of the event that was fired.
3382 * @param {Array} p_aArgs Collection of arguments sent when the event
3385 _onBlur: function (p_sType, p_aArgs) {
3387 if (this._hasFocus) {
3388 this._hasFocus = false;
3394 * @method _onYChange
3395 * @description "y" event handler for a Menu instance.
3397 * @param {String} p_sType The name of the event that was fired.
3398 * @param {Array} p_aArgs Collection of arguments sent when the event
3401 _onYChange: function (p_sType, p_aArgs) {
3403 var oParent = this.parent,
3411 nScrollTop = oParent.parent.body.scrollTop;
3414 if (nScrollTop > 0) {
3416 nY = (this.cfg.getProperty(_Y) - nScrollTop);
3418 Dom.setY(this.element, nY);
3420 oIFrame = this.iframe;
3425 Dom.setY(oIFrame, nY);
3429 this.cfg.setProperty(_Y, nY, true);
3439 * @method _onScrollTargetMouseOver
3440 * @description "mouseover" event handler for the menu's "header" and "footer"
3441 * elements. Used to scroll the body of the menu up and down when the
3442 * menu's "maxheight" configuration property is set to a value greater than 0.
3444 * @param {Event} p_oEvent Object representing the DOM event object passed
3445 * back by the event utility (YAHOO.util.Event).
3446 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3449 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3451 var oBodyScrollTimer = this._bodyScrollTimer;
3454 if (oBodyScrollTimer) {
3456 oBodyScrollTimer.cancel();
3461 this._cancelHideDelay();
3464 var oTarget = Event.getTarget(p_oEvent),
3466 nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3471 function scrollBodyDown() {
3473 var nScrollTop = oBody.scrollTop;
3476 if (nScrollTop < nScrollTarget) {
3478 oBody.scrollTop = (nScrollTop + nScrollIncrement);
3480 this._enableScrollHeader();
3485 oBody.scrollTop = nScrollTarget;
3487 this._bodyScrollTimer.cancel();
3489 this._disableScrollFooter();
3496 function scrollBodyUp() {
3498 var nScrollTop = oBody.scrollTop;
3501 if (nScrollTop > 0) {
3503 oBody.scrollTop = (nScrollTop - nScrollIncrement);
3505 this._enableScrollFooter();
3510 oBody.scrollTop = 0;
3512 this._bodyScrollTimer.cancel();
3514 this._disableScrollHeader();
3521 if (Dom.hasClass(oTarget, _HD)) {
3523 fnScrollFunction = scrollBodyUp;
3528 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3530 fnScrollFunction = scrollBodyDown;
3535 this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3541 * @method _onScrollTargetMouseOut
3542 * @description "mouseout" event handler for the menu's "header" and "footer"
3543 * elements. Used to stop scrolling the body of the menu up and down when the
3544 * menu's "maxheight" configuration property is set to a value greater than 0.
3546 * @param {Event} p_oEvent Object representing the DOM event object passed
3547 * back by the event utility (YAHOO.util.Event).
3548 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3551 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3553 var oBodyScrollTimer = this._bodyScrollTimer;
3555 if (oBodyScrollTimer) {
3557 oBodyScrollTimer.cancel();
3561 this._cancelHideDelay();
3572 * @description "init" event handler for the menu.
3574 * @param {String} p_sType String representing the name of the event that
3576 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3578 _onInit: function (p_sType, p_aArgs) {
3580 this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3582 var bRootMenu = !this.parent,
3583 bLazyLoad = this.lazyLoad;
3587 Automatically initialize a menu's subtree if:
3589 1) This is the root menu and lazyload is off
3591 2) This is the root menu, lazyload is on, but the menu is
3594 3) This menu is a submenu and lazyload is off
3599 if (((bRootMenu && !bLazyLoad) ||
3600 (bRootMenu && (this.cfg.getProperty(_VISIBLE) ||
3601 this.cfg.getProperty(_POSITION) == _STATIC)) ||
3602 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3604 if (this.srcElement) {
3606 this._initSubTree();
3611 if (this.itemData) {
3613 this.addItems(this.itemData);
3618 else if (bLazyLoad) {
3620 this.cfg.fireQueue();
3628 * @method _onBeforeRender
3629 * @description "beforerender" event handler for the menu. Appends all of the
3630 * <code><ul></code>, <code><li></code> and their accompanying
3631 * title elements to the body element of the menu.
3633 * @param {String} p_sType String representing the name of the event that
3635 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3637 _onBeforeRender: function (p_sType, p_aArgs) {
3639 var oEl = this.element,
3640 nListElements = this._aListElements.length,
3646 if (nListElements > 0) {
3650 oUL = this._aListElements[i];
3656 Dom.addClass(oUL, _FIRST_OF_TYPE);
3662 if (!Dom.isAncestor(oEl, oUL)) {
3664 this.appendToBody(oUL);
3669 oGroupTitle = this._aGroupTitleElements[i];
3673 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3675 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3680 Dom.addClass(oUL, _HAS_TITLE);
3689 while (i < nListElements);
3698 * @description "render" event handler for the menu.
3700 * @param {String} p_sType String representing the name of the event that
3702 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3704 _onRender: function (p_sType, p_aArgs) {
3706 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3708 if (!this.cfg.getProperty(_VISIBLE)) {
3710 this.positionOffScreen();
3723 * @method _onBeforeShow
3724 * @description "beforeshow" event handler for the menu.
3726 * @param {String} p_sType String representing the name of the event that
3728 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3730 _onBeforeShow: function (p_sType, p_aArgs) {
3735 oContainer = this.cfg.getProperty(_CONTAINER);
3738 if (this.lazyLoad && this.getItemGroups().length === 0) {
3740 if (this.srcElement) {
3742 this._initSubTree();
3747 if (this.itemData) {
3749 if (this.parent && this.parent.parent &&
3750 this.parent.parent.srcElement &&
3751 this.parent.parent.srcElement.tagName.toUpperCase() ==
3754 nOptions = this.itemData.length;
3756 for(n=0; n<nOptions; n++) {
3758 if (this.itemData[n].tagName) {
3760 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3769 this.addItems(this.itemData);
3776 oSrcElement = this.srcElement;
3780 if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3782 if (Dom.inDocument(oSrcElement)) {
3784 this.render(oSrcElement.parentNode);
3789 this.render(oContainer);
3805 this.render(this.parent.element);
3810 this.render(oContainer);
3820 var oParent = this.parent,
3824 if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3826 this.cfg.refireEvent(_XY);
3833 aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3835 this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3843 getConstrainedY: function (y) {
3847 aContext = oMenu.cfg.getProperty(_CONTEXT),
3848 nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3852 oOverlapPositions = {
3861 bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3863 oMenuEl = oMenu.element,
3864 nMenuOffsetHeight = oMenuEl.offsetHeight,
3866 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3867 viewPortHeight = Dom.getViewportHeight(),
3868 scrollY = Dom.getDocumentScrollTop(),
3871 (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3882 nBottomRegionHeight,
3884 topConstraint = scrollY + nViewportOffset,
3885 bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
3890 var flipVertical = function () {
3894 // The Menu is below the context element, flip it above
3895 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3896 nNewY = (nContextElY - nMenuOffsetHeight);
3898 else { // The Menu is above the context element, flip it below
3899 nNewY = (nContextElY + nContextElHeight);
3902 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3910 Uses the context element's position to calculate the availble height
3911 above and below it to display its corresponding Menu.
3914 var getDisplayRegionHeight = function () {
3916 // The Menu is below the context element
3917 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3918 return (nBottomRegionHeight - nViewportOffset);
3920 else { // The Menu is above the context element
3921 return (nTopRegionHeight - nViewportOffset);
3928 Sets the Menu's "y" configuration property to the correct value based on its
3929 current orientation.
3932 var alignY = function () {
3936 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3937 nNewY = (nContextElY + nContextElHeight);
3940 nNewY = (nContextElY - oMenuEl.offsetHeight);
3943 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3948 // Resets the maxheight of the Menu to the value set by the user
3950 var resetMaxHeight = function () {
3952 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3954 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3960 Trys to place the Menu in the best possible position (either above or
3961 below its corresponding context element).
3964 var setVerticalPosition = function () {
3966 var nDisplayRegionHeight = getDisplayRegionHeight(),
3967 bMenuHasItems = (oMenu.getItems().length > 0),
3968 nMenuMinScrollHeight,
3972 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3974 nMenuMinScrollHeight =
3975 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3978 if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3979 nMaxHeight = nDisplayRegionHeight;
3982 nMaxHeight = nInitialMaxHeight;
3986 oMenu._setScrollHeight(nMaxHeight);
3987 oMenu.hideEvent.subscribe(resetMaxHeight);
3990 // Re-align the Menu since its height has just changed
3991 // as a result of the setting of the maxheight property.
3996 if (nDisplayRegionHeight < nMenuMinScrollHeight) {
4001 All possible positions and values for the "maxheight"
4002 configuration property have been tried, but none were
4003 successful, so fall back to the original size and position.
4015 fnReturnVal = setVerticalPosition();
4022 else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
4024 oMenu._setScrollHeight(nInitialMaxHeight);
4025 oMenu.hideEvent.subscribe(resetMaxHeight);
4027 // Re-align the Menu since its height has just changed
4028 // as a result of the setting of the maxheight property.
4039 // Determine if the current value for the Menu's "y" configuration property will
4040 // result in the Menu being positioned outside the boundaries of the viewport
4042 if (y < topConstraint || y > bottomConstraint) {
4044 // The current value for the Menu's "y" configuration property WILL
4045 // result in the Menu being positioned outside the boundaries of the viewport
4047 if (bCanConstrain) {
4049 if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
4052 // If the "preventcontextoverlap" configuration property is set to "true",
4053 // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
4054 // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
4056 oContextEl = aContext[0];
4057 nContextElHeight = oContextEl.offsetHeight;
4058 nContextElY = (Dom.getY(oContextEl) - scrollY);
4060 nTopRegionHeight = nContextElY;
4061 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
4063 setVerticalPosition();
4065 yNew = oMenu.cfg.getProperty(_Y);
4068 else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
4069 nMenuOffsetHeight >= viewPortHeight) {
4072 // If the Menu exceeds the height of the viewport, introduce scroll bars
4073 // to keep the Menu inside the boundaries of the viewport
4075 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
4077 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
4079 oMenu._setScrollHeight(nAvailableHeight);
4080 oMenu.hideEvent.subscribe(resetMaxHeight);
4084 yNew = oMenu.cfg.getProperty(_Y);
4093 if (y < topConstraint) {
4094 yNew = topConstraint;
4095 } else if (y > bottomConstraint) {
4096 yNew = bottomConstraint;
4103 // The "y" configuration property cannot be set to a value that will keep
4104 // entire Menu inside the boundary of the viewport. Therefore, set
4105 // the "y" configuration property to scrollY to keep as much of the
4106 // Menu inside the viewport as possible.
4107 yNew = nViewportOffset + scrollY;
4119 * @description "hide" event handler for the menu.
4121 * @param {String} p_sType String representing the name of the event that
4123 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4125 _onHide: function (p_sType, p_aArgs) {
4127 if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4129 this.positionOffScreen();
4138 * @description "show" event handler for the menu.
4140 * @param {String} p_sType String representing the name of the event that
4142 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4144 _onShow: function (p_sType, p_aArgs) {
4146 var oParent = this.parent,
4153 function disableAutoSubmenuDisplay(p_oEvent) {
4157 if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4160 Set the "autosubmenudisplay" to "false" if the user
4161 clicks outside the menu bar.
4164 oTarget = Event.getTarget(p_oEvent);
4166 if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4168 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4170 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4171 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4180 function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4182 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4183 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4190 oParentMenu = oParent.parent;
4193 if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
4194 (oParentMenu instanceof YAHOO.widget.MenuBar ||
4195 oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4197 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4199 Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4200 Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4205 // The following fixes an issue with the selected state of a MenuItem
4206 // not rendering correctly when a submenu is aligned to the left of
4207 // its parent Menu instance.
4209 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
4210 (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4212 oElement = this.element;
4213 nOffsetWidth = oElement.offsetWidth;
4216 Measuring the difference of the offsetWidth before and after
4217 setting the "width" style attribute allows us to compute the
4218 about of padding and borders applied to the element, which in
4219 turn allows us to set the "width" property correctly.
4222 oElement.style.width = nOffsetWidth + _PX;
4224 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4226 this.cfg.setProperty(_WIDTH, sWidth);
4228 this.hideEvent.subscribe(onSubmenuHide, sWidth);
4238 * @method _onBeforeHide
4239 * @description "beforehide" event handler for the menu.
4241 * @param {String} p_sType String representing the name of the event that
4243 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4245 _onBeforeHide: function (p_sType, p_aArgs) {
4247 var oActiveItem = this.activeItem,
4248 oRoot = this.getRoot(),
4255 oConfig = oActiveItem.cfg;
4257 oConfig.setProperty(_SELECTED, false);
4259 oSubmenu = oConfig.getProperty(_SUBMENU);
4271 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
4272 For this reason, it is necessary to maintain the focused state in a private property
4273 so that the _onMouseOver event handler is able to determined whether or not to set focus
4274 to MenuItems as the user is moving the mouse.
4277 if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4279 oRoot._hasFocus = this.hasFocus();
4284 if (oRoot == this) {
4294 * @method _onParentMenuConfigChange
4295 * @description "configchange" event handler for a submenu.
4297 * @param {String} p_sType String representing the name of the event that
4299 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4300 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4301 * subscribed to the event.
4303 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4305 var sPropertyName = p_aArgs[0][0],
4306 oPropertyValue = p_aArgs[0][1];
4308 switch(sPropertyName) {
4311 case _CONSTRAIN_TO_VIEWPORT:
4314 case _SUBMENU_HIDE_DELAY:
4315 case _CLICK_TO_HIDE:
4318 case _SCROLL_INCREMENT:
4320 case _MIN_SCROLL_HEIGHT:
4321 case _MONITOR_RESIZE:
4323 case _PREVENT_CONTEXT_OVERLAP:
4325 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4329 case _SUBMENU_ALIGNMENT:
4331 if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4333 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4345 * @method _onParentMenuRender
4346 * @description "render" event handler for a submenu. Renders a
4347 * submenu in response to the firing of its parent's "render" event.
4349 * @param {String} p_sType String representing the name of the event that
4351 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4352 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4353 * subscribed to the event.
4355 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4357 var oParentMenu = p_oSubmenu.parent.parent,
4358 oParentCfg = oParentMenu.cfg,
4362 constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4366 clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4368 effect: oParentCfg.getProperty(_EFFECT),
4370 showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4372 hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4374 submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4376 classname: oParentCfg.getProperty(_CLASSNAME),
4378 scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4380 maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4382 minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4384 iframe: oParentCfg.getProperty(_IFRAME),
4386 shadow: oParentCfg.getProperty(_SHADOW),
4388 preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4390 monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE)
4398 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4400 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4405 p_oSubmenu.cfg.applyConfig(oConfig);
4408 if (!this.lazyLoad) {
4410 oLI = this.parent.element;
4412 if (this.element.parentNode == oLI) {
4429 * @method _onMenuItemDestroy
4430 * @description "destroy" event handler for the menu's items.
4432 * @param {String} p_sType String representing the name of the event
4434 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4435 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4436 * that fired the event.
4438 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4440 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4446 * @method _onMenuItemConfigChange
4447 * @description "configchange" event handler for the menu's items.
4449 * @param {String} p_sType String representing the name of the event that
4451 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4452 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4453 * that fired the event.
4455 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4457 var sPropertyName = p_aArgs[0][0],
4458 oPropertyValue = p_aArgs[0][1],
4462 switch(sPropertyName) {
4466 if (oPropertyValue === true) {
4468 this.activeItem = p_oItem;
4476 oSubmenu = p_aArgs[0][1];
4480 this._configureSubmenu(p_oItem);
4492 // Public event handlers for configuration properties
4496 * @method configVisible
4497 * @description Event handler for when the "visible" configuration property
4499 * @param {String} p_sType String representing the name of the event that
4501 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4502 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4505 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4510 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4512 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4517 bVisible = p_aArgs[0];
4518 sDisplay = Dom.getStyle(this.element, _DISPLAY);
4520 Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4524 if (sDisplay != _BLOCK) {
4525 this.beforeShowEvent.fire();
4526 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4527 this.showEvent.fire();
4533 if (sDisplay == _BLOCK) {
4534 this.beforeHideEvent.fire();
4535 Dom.setStyle(this.element, _DISPLAY, _NONE);
4536 this.hideEvent.fire();
4547 * @method configPosition
4548 * @description Event handler for when the "position" configuration property
4549 * of the menu changes.
4550 * @param {String} p_sType String representing the name of the event that
4552 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4553 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4556 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4558 var oElement = this.element,
4559 sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4564 Dom.setStyle(oElement, _POSITION, sCSSPosition);
4567 if (sCSSPosition == _STATIC) {
4569 // Statically positioned menus are visible by default
4571 Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4573 oCfg.setProperty(_VISIBLE, true);
4579 Even though the "visible" property is queued to
4580 "false" by default, we need to set the "visibility" property to
4581 "hidden" since Overlay's "configVisible" implementation checks the
4582 element's "visibility" style property before deciding whether
4583 or not to show an Overlay instance.
4586 Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4591 if (sCSSPosition == _ABSOLUTE) {
4593 nZIndex = oCfg.getProperty(_ZINDEX);
4595 if (!nZIndex || nZIndex === 0) {
4597 oCfg.setProperty(_ZINDEX, 1);
4607 * @method configIframe
4608 * @description Event handler for when the "iframe" configuration property of
4610 * @param {String} p_sType String representing the name of the event that
4612 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4613 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4616 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4618 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4620 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4628 * @method configHideDelay
4629 * @description Event handler for when the "hidedelay" configuration property
4630 * of the menu changes.
4631 * @param {String} p_sType String representing the name of the event that
4633 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4634 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4637 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4639 var nHideDelay = p_aArgs[0];
4641 this._useHideDelay = (nHideDelay > 0);
4647 * @method configContainer
4648 * @description Event handler for when the "container" configuration property
4649 * of the menu changes.
4650 * @param {String} p_sType String representing the name of the event that
4652 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4653 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4656 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4658 var oElement = p_aArgs[0];
4660 if (Lang.isString(oElement)) {
4662 this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4670 * @method _clearSetWidthFlag
4671 * @description Change event listener for the "width" configuration property. This listener is
4672 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
4673 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
4674 * is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
4675 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
4676 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4679 _clearSetWidthFlag: function () {
4681 this._widthSetForScroll = false;
4683 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4689 * @method _setScrollHeight
4691 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4694 _setScrollHeight: function (p_nScrollHeight) {
4696 var nScrollHeight = p_nScrollHeight,
4697 bRefireIFrameAndShadow = false,
4711 if (this.getItems().length > 0) {
4713 oElement = this.element;
4715 oHeader = this.header;
4716 oFooter = this.footer;
4717 fnMouseOver = this._onScrollTargetMouseOver;
4718 fnMouseOut = this._onScrollTargetMouseOut;
4719 nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4722 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4724 nScrollHeight = nMinScrollHeight;
4729 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4730 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4731 oBody.scrollTop = 0;
4734 // Need to set a width for the Menu to fix the following problems in
4735 // Firefox 2 and IE:
4737 // #1) Scrolled Menus will render at 1px wide in Firefox 2
4739 // #2) There is a bug in gecko-based browsers where an element whose
4740 // "position" property is set to "absolute" and "overflow" property is
4741 // set to "hidden" will not render at the correct width when its
4742 // offsetParent's "position" property is also set to "absolute." It is
4743 // possible to work around this bug by specifying a value for the width
4744 // property in addition to overflow.
4746 // #3) In IE it is necessary to give the Menu a width before the
4747 // scrollbars are rendered to prevent the Menu from rendering with a
4748 // width that is 100% of the browser viewport.
4750 bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4752 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4754 nOffsetWidth = oElement.offsetWidth;
4757 Measuring the difference of the offsetWidth before and after
4758 setting the "width" style attribute allows us to compute the
4759 about of padding and borders applied to the element, which in
4760 turn allows us to set the "width" property correctly.
4763 oElement.style.width = nOffsetWidth + _PX;
4765 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4768 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4770 YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.",
4771 "info", this.toString());
4773 this.cfg.setProperty(_WIDTH, sWidth);
4777 Set a flag (_widthSetForScroll) to maintain some history regarding how the
4778 "width" configuration property was set. If the "width" configuration property
4779 is set by something other than the "_setScrollHeight" method, it will be
4780 necessary to maintain that new value and not clear the width if scrolling
4784 this._widthSetForScroll = true;
4786 this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4791 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4793 YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
4795 this.setHeader(_NON_BREAKING_SPACE);
4796 this.setFooter(_NON_BREAKING_SPACE);
4798 oHeader = this.header;
4799 oFooter = this.footer;
4801 Dom.addClass(oHeader, _TOP_SCROLLBAR);
4802 Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4804 oElement.insertBefore(oHeader, oBody);
4805 oElement.appendChild(oFooter);
4810 nHeight = nScrollHeight;
4813 if (oHeader && oFooter) {
4814 nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4818 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4820 YAHOO.log("Setting up styles and event handlers for scrolling.",
4821 "info", this.toString());
4823 Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4824 Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4826 if (!this._hasScrollEventHandlers) {
4828 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4829 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4830 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4831 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4833 this._hasScrollEventHandlers = true;
4837 this._disableScrollHeader();
4838 this._enableScrollFooter();
4840 bRefireIFrameAndShadow = true;
4843 else if (oHeader && oFooter) {
4845 YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
4849 Only clear the the "width" configuration property if it was set the
4850 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4853 if (this._widthSetForScroll) {
4855 YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
4857 this._widthSetForScroll = false;
4859 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4861 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4866 this._enableScrollHeader();
4867 this._enableScrollFooter();
4869 if (this._hasScrollEventHandlers) {
4871 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4872 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4873 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4874 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4876 this._hasScrollEventHandlers = false;
4880 oElement.removeChild(oHeader);
4881 oElement.removeChild(oFooter);
4886 bRefireIFrameAndShadow = true;
4891 if (bRefireIFrameAndShadow) {
4893 this.cfg.refireEvent(_IFRAME);
4894 this.cfg.refireEvent(_SHADOW);
4904 * @method _setMaxHeight
4905 * @description "renderEvent" handler used to defer the setting of the
4906 * "maxheight" configuration property until the menu is rendered in lazy
4908 * @param {String} p_sType The name of the event that was fired.
4909 * @param {Array} p_aArgs Collection of arguments sent when the event
4911 * @param {Number} p_nMaxHeight Number representing the value to set for the
4912 * "maxheight" configuration property.
4915 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4917 this._setScrollHeight(p_nMaxHeight);
4918 this.renderEvent.unsubscribe(this._setMaxHeight);
4924 * @method configMaxHeight
4925 * @description Event handler for when the "maxheight" configuration property of
4927 * @param {String} p_sType The name of the event that was fired.
4928 * @param {Array} p_aArgs Collection of arguments sent when the event
4930 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4933 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4935 var nMaxHeight = p_aArgs[0];
4937 if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4939 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4944 this._setScrollHeight(nMaxHeight);
4952 * @method configClassName
4953 * @description Event handler for when the "classname" configuration property of
4955 * @param {String} p_sType The name of the event that was fired.
4956 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4957 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4959 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4961 var sClassName = p_aArgs[0];
4963 if (this._sClassName) {
4965 Dom.removeClass(this.element, this._sClassName);
4969 Dom.addClass(this.element, sClassName);
4970 this._sClassName = sClassName;
4976 * @method _onItemAdded
4977 * @description "itemadded" event handler for a Menu instance.
4979 * @param {String} p_sType The name of the event that was fired.
4980 * @param {Array} p_aArgs Collection of arguments sent when the event
4983 _onItemAdded: function (p_sType, p_aArgs) {
4985 var oItem = p_aArgs[0];
4989 oItem.cfg.setProperty(_DISABLED, true);
4997 * @method configDisabled
4998 * @description Event handler for when the "disabled" configuration property of
5000 * @param {String} p_sType The name of the event that was fired.
5001 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5002 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5004 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
5006 var bDisabled = p_aArgs[0],
5007 aItems = this.getItems(),
5011 if (Lang.isArray(aItems)) {
5013 nItems = aItems.length;
5021 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
5031 this.clearActiveItem(true);
5033 Dom.addClass(this.element, _DISABLED);
5035 this.itemAddedEvent.subscribe(this._onItemAdded);
5040 Dom.removeClass(this.element, _DISABLED);
5042 this.itemAddedEvent.unsubscribe(this._onItemAdded);
5052 * @method configShadow
5053 * @description Event handler for when the "shadow" configuration property of
5055 * @param {String} p_sType The name of the event that was fired.
5056 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5057 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5059 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5061 var sizeShadow = function () {
5063 var oElement = this.element,
5064 oShadow = this._shadow;
5066 if (oShadow && oElement) {
5068 // Clear the previous width
5070 if (oShadow.style.width && oShadow.style.height) {
5072 oShadow.style.width = _EMPTY_STRING;
5073 oShadow.style.height = _EMPTY_STRING;
5077 oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
5078 oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
5085 var replaceShadow = function () {
5087 this.element.appendChild(this._shadow);
5092 var addShadowVisibleClass = function () {
5094 Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5099 var removeShadowVisibleClass = function () {
5101 Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5106 var createShadow = function () {
5108 var oShadow = this._shadow,
5113 oElement = this.element;
5116 if (!m_oShadowTemplate) {
5118 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5119 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5123 oShadow = m_oShadowTemplate.cloneNode(false);
5125 oElement.appendChild(oShadow);
5127 this._shadow = oShadow;
5129 this.beforeShowEvent.subscribe(addShadowVisibleClass);
5130 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
5136 Need to call sizeShadow & syncIframe via setTimeout for
5137 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
5138 or the shadow and iframe shim will not be sized and
5139 positioned properly.
5142 Lang.later(0, this, function () {
5144 sizeShadow.call(this);
5150 this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
5151 this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
5152 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
5153 this.changeContentEvent.subscribe(sizeShadow);
5155 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5157 this.destroyEvent.subscribe(function () {
5159 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5165 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
5172 var onBeforeShow = function () {
5176 // If called because the "shadow" event was refired - just append again and resize
5178 replaceShadow.call(this);
5181 sizeShadow.call(this);
5187 createShadow.call(this);
5191 this.beforeShowEvent.unsubscribe(onBeforeShow);
5196 var bShadow = p_aArgs[0];
5199 if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5201 if (this.cfg.getProperty(_VISIBLE)) {
5205 // If the "shadow" event was refired - just append again and resize
5207 replaceShadow.call(this);
5210 sizeShadow.call(this);
5215 createShadow.call(this);
5221 this.beforeShowEvent.subscribe(onBeforeShow);
5235 * @method initEvents
5236 * @description Initializes the custom events for the menu.
5238 initEvents: function () {
5240 Menu.superclass.initEvents.call(this);
5242 // Create custom events
5244 var i = EVENT_TYPES.length - 1,
5251 aEventData = EVENT_TYPES[i];
5253 oCustomEvent = this.createEvent(aEventData[1]);
5254 oCustomEvent.signature = CustomEvent.LIST;
5256 this[aEventData[0]] = oCustomEvent;
5265 * @method positionOffScreen
5266 * @description Positions the menu outside of the boundaries of the browser's
5267 * viewport. Called automatically when a menu is hidden to ensure that
5268 * it doesn't force the browser to render uncessary scrollbars.
5270 positionOffScreen: function () {
5272 var oIFrame = this.iframe,
5273 oElement = this.element,
5274 sPos = this.OFF_SCREEN_POSITION;
5276 oElement.style.top = _EMPTY_STRING;
5277 oElement.style.left = _EMPTY_STRING;
5281 oIFrame.style.top = sPos;
5282 oIFrame.style.left = sPos;
5291 * @description Finds the menu's root menu.
5293 getRoot: function () {
5295 var oItem = this.parent,
5301 oParentMenu = oItem.parent;
5303 returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5319 * @description Returns a string representing the menu.
5322 toString: function () {
5324 var sReturnVal = _MENU,
5329 sReturnVal += (_SPACE + sId);
5339 * @method setItemGroupTitle
5340 * @description Sets the title of a group of menu items.
5341 * @param {String} p_sGroupTitle String specifying the title of the group.
5342 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5343 * the title belongs.
5345 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5352 if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5354 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5355 oTitle = this._aGroupTitleElements[nGroupIndex];
5360 oTitle.innerHTML = p_sGroupTitle;
5365 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5367 oTitle.innerHTML = p_sGroupTitle;
5369 this._aGroupTitleElements[nGroupIndex] = oTitle;
5374 i = this._aGroupTitleElements.length - 1;
5378 if (this._aGroupTitleElements[i]) {
5380 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5390 if (nFirstIndex !== null) {
5392 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
5397 this.changeContentEvent.fire();
5407 * @description Appends an item to the menu.
5408 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5409 * instance to be added to the menu.
5410 * @param {String} p_oItem String specifying the text of the item to be added
5412 * @param {Object} p_oItem Object literal containing a set of menu item
5413 * configuration properties.
5414 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5415 * which the item belongs.
5416 * @return {YAHOO.widget.MenuItem}
5418 addItem: function (p_oItem, p_nGroupIndex) {
5420 return this._addItemToGroup(p_nGroupIndex, p_oItem);
5427 * @description Adds an array of items to the menu.
5428 * @param {Array} p_aItems Array of items to be added to the menu. The array
5429 * can contain strings specifying the text for each item to be created, object
5430 * literals specifying each of the menu item configuration properties,
5431 * or MenuItem instances.
5432 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5433 * which the items belongs.
5436 addItems: function (p_aItems, p_nGroupIndex) {
5445 if (Lang.isArray(p_aItems)) {
5447 nItems = p_aItems.length;
5450 for(i=0; i<nItems; i++) {
5452 oItem = p_aItems[i];
5456 if (Lang.isArray(oItem)) {
5458 aItems[aItems.length] = this.addItems(oItem, i);
5463 aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5472 if (aItems.length) {
5486 * @method insertItem
5487 * @description Inserts an item into the menu at the specified index.
5488 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5489 * instance to be added to the menu.
5490 * @param {String} p_oItem String specifying the text of the item to be added
5492 * @param {Object} p_oItem Object literal containing a set of menu item
5493 * configuration properties.
5494 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5495 * the item should be added.
5496 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5498 * @return {YAHOO.widget.MenuItem}
5500 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5502 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5508 * @method removeItem
5509 * @description Removes the specified item from the menu.
5510 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5511 * instance to be removed from the menu.
5512 * @param {Number} p_oObject Number specifying the index of the item
5514 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5515 * which the item belongs.
5516 * @return {YAHOO.widget.MenuItem}
5518 removeItem: function (p_oObject, p_nGroupIndex) {
5523 if (!Lang.isUndefined(p_oObject)) {
5525 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5527 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5530 else if (Lang.isNumber(p_oObject)) {
5532 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5540 YAHOO.log("Item removed." +
5541 " Text: " + oItem.cfg.getProperty("text") + ", " +
5542 " Index: " + oItem.index + ", " +
5543 " Group Index: " + oItem.groupIndex, "info", this.toString());
5558 * @description Returns an array of all of the items in the menu.
5561 getItems: function () {
5563 var aGroups = this._aItemGroups,
5569 if (Lang.isArray(aGroups)) {
5571 nGroups = aGroups.length;
5573 returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5583 * @method getItemGroups
5584 * @description Multi-dimensional Array representing the menu items as they
5585 * are grouped in the menu.
5588 getItemGroups: function () {
5590 return this._aItemGroups;
5597 * @description Returns the item at the specified index.
5598 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5599 * item to be retrieved.
5600 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5602 * @return {YAHOO.widget.MenuItem}
5604 getItem: function (p_nItemIndex, p_nGroupIndex) {
5609 if (Lang.isNumber(p_nItemIndex)) {
5611 aGroup = this._getItemGroup(p_nGroupIndex);
5615 returnVal = aGroup[p_nItemIndex];
5627 * @method getSubmenus
5628 * @description Returns an array of all of the submenus that are immediate
5629 * children of the menu.
5632 getSubmenus: function () {
5634 var aItems = this.getItems(),
5635 nItems = aItems.length,
5646 for(i=0; i<nItems; i++) {
5652 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5656 aSubmenus[aSubmenus.length] = oSubmenu;
5672 * @method clearContent
5673 * @description Removes all of the content from the menu, including the menu
5674 * items, group titles, header and footer.
5676 clearContent: function () {
5678 var aItems = this.getItems(),
5679 nItems = aItems.length,
5680 oElement = this.element,
5682 oHeader = this.header,
5683 oFooter = this.footer,
5699 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5703 this.cfg.configChangedEvent.unsubscribe(
5704 this._onParentMenuConfigChange, oSubmenu);
5706 this.renderEvent.unsubscribe(this._onParentMenuRender,
5711 this.removeItem(oItem, oItem.groupIndex);
5723 Event.purgeElement(oHeader);
5724 oElement.removeChild(oHeader);
5731 Event.purgeElement(oFooter);
5732 oElement.removeChild(oFooter);
5738 Event.purgeElement(oBody);
5740 oBody.innerHTML = _EMPTY_STRING;
5744 this.activeItem = null;
5746 this._aItemGroups = [];
5747 this._aListElements = [];
5748 this._aGroupTitleElements = [];
5750 this.cfg.setProperty(_WIDTH, null);
5757 * @description Removes the menu's <code><div></code> element
5758 * (and accompanying child nodes) from the document.
5760 destroy: function () {
5764 this.clearContent();
5766 this._aItemGroups = null;
5767 this._aListElements = null;
5768 this._aGroupTitleElements = null;
5771 // Continue with the superclass implementation of this method
5773 Menu.superclass.destroy.call(this);
5775 YAHOO.log("Destroyed.", "info", this.toString());
5781 * @method setInitialFocus
5782 * @description Sets focus to the menu's first enabled item.
5784 setInitialFocus: function () {
5786 var oItem = this._getFirstEnabledItem();
5798 * @method setInitialSelection
5799 * @description Sets the "selected" configuration property of the menu's first
5800 * enabled item to "true."
5802 setInitialSelection: function () {
5804 var oItem = this._getFirstEnabledItem();
5808 oItem.cfg.setProperty(_SELECTED, true);
5815 * @method clearActiveItem
5816 * @description Sets the "selected" configuration property of the menu's active
5817 * item to "false" and hides the item's submenu.
5818 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5819 * should be blurred.
5821 clearActiveItem: function (p_bBlur) {
5823 if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5825 this._cancelShowDelay();
5830 var oActiveItem = this.activeItem,
5836 oConfig = oActiveItem.cfg;
5842 this.getRoot()._hasFocus = true;
5846 oConfig.setProperty(_SELECTED, false);
5848 oSubmenu = oConfig.getProperty(_SUBMENU);
5857 this.activeItem = null;
5866 * @description Causes the menu to receive focus and fires the "focus" event.
5868 focus: function () {
5870 if (!this.hasFocus()) {
5872 this.setInitialFocus();
5881 * @description Causes the menu to lose focus and fires the "blur" event.
5887 if (this.hasFocus()) {
5889 oItem = MenuManager.getFocusedMenuItem();
5904 * @description Returns a boolean indicating whether or not the menu has focus.
5907 hasFocus: function () {
5909 return (MenuManager.getFocusedMenu() == this.getRoot());
5915 * Adds the specified CustomEvent subscriber to the menu and each of
5918 * @param p_type {string} the type, or name of the event
5919 * @param p_fn {function} the function to exectute when the event fires
5920 * @param p_obj {Object} An object to be passed along when the event
5922 * @param p_override {boolean} If true, the obj passed in becomes the
5923 * execution scope of the listener
5925 subscribe: function () {
5927 function onItemAdded(p_sType, p_aArgs, p_oObject) {
5929 var oItem = p_aArgs[0],
5930 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5934 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5941 function onSubmenuAdded(p_sType, p_aArgs, p_oObject) {
5943 var oSubmenu = this.cfg.getProperty(_SUBMENU);
5947 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5954 Menu.superclass.subscribe.apply(this, arguments);
5955 Menu.superclass.subscribe.call(this, _ITEM_ADDED, onItemAdded, arguments);
5958 var aItems = this.getItems(),
5967 nItems = aItems.length;
5977 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5981 oSubmenu.subscribe.apply(oSubmenu, arguments);
5986 oItem.cfg.subscribeToConfigEvent(_SUBMENU, onSubmenuAdded, arguments);
6001 * @description Initializes the class's configurable properties which can be
6002 * changed using the menu's Config object ("cfg").
6003 * @method initDefaultConfig
6005 initDefaultConfig: function () {
6007 Menu.superclass.initDefaultConfig.call(this);
6009 var oConfig = this.cfg;
6012 // Module documentation overrides
6016 * @description Object or array of objects representing the ContainerEffect
6017 * classes that are active for animating the container. When set this
6018 * property is automatically applied to all submenus.
6023 // Overlay documentation overrides
6028 * @description Number representing the absolute x-coordinate position of
6029 * the Menu. This property is only applied when the "position"
6030 * configuration property is set to dynamic.
6038 * @description Number representing the absolute y-coordinate position of
6039 * the Menu. This property is only applied when the "position"
6040 * configuration property is set to dynamic.
6047 * @description Array of the absolute x and y positions of the Menu. This
6048 * property is only applied when the "position" configuration property is
6058 * @description Array of context arguments for context-sensitive positioning.
6059 * The format is: [id or element, element corner, context corner].
6060 * For example, setting this property to ["img1", "tl", "bl"] would
6061 * align the Mnu's top left corner to the context element's
6062 * bottom left corner. This property is only applied when the "position"
6063 * configuration property is set to dynamic.
6070 * @config fixedcenter
6071 * @description Boolean indicating if the Menu should be anchored to the
6072 * center of the viewport. This property is only applied when the
6073 * "position" configuration property is set to dynamic.
6081 * @description Boolean indicating whether or not the Menu should
6082 * have an IFRAME shim; used to prevent SELECT elements from
6083 * poking through an Overlay instance in IE6. When set to "true",
6084 * the iframe shim is created when the Menu instance is intially
6085 * made visible. This property is only applied when the "position"
6086 * configuration property is set to dynamic and is automatically applied
6089 * @default true for IE6 and below, false for all other browsers.
6093 // Add configuration attributes
6096 Change the default value for the "visible" configuration
6097 property to "false" by re-adding the property.
6102 * @description Boolean indicating whether or not the menu is visible. If
6103 * the menu's "position" configuration property is set to "dynamic" (the
6104 * default), this property toggles the menu's <code><div></code>
6105 * element's "visibility" style property between "visible" (true) or
6106 * "hidden" (false). If the menu's "position" configuration property is
6107 * set to "static" this property toggles the menu's
6108 * <code><div></code> element's "display" style property
6109 * between "block" (true) or "none" (false).
6113 oConfig.addProperty(
6116 handler: this.configVisible,
6117 value: VISIBLE_CONFIG.value,
6118 validator: VISIBLE_CONFIG.validator
6124 Change the default value for the "constraintoviewport" configuration
6125 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6129 * @config constraintoviewport
6130 * @description Boolean indicating if the menu will try to remain inside
6131 * the boundaries of the size of viewport. This property is only applied
6132 * when the "position" configuration property is set to dynamic and is
6133 * automatically applied to all submenus.
6137 oConfig.addProperty(
6138 CONSTRAIN_TO_VIEWPORT_CONFIG.key,
6140 handler: this.configConstrainToViewport,
6141 value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
6142 validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
6143 supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
6149 Change the default value for the "preventcontextoverlap" configuration
6150 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6154 * @config preventcontextoverlap
6155 * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
6156 * when the "constraintoviewport" configuration property is set to "true".
6160 oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6162 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
6163 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
6164 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6171 * @description String indicating how a menu should be positioned on the
6172 * screen. Possible values are "static" and "dynamic." Static menus are
6173 * visible by default and reside in the normal flow of the document
6174 * (CSS position: static). Dynamic menus are hidden by default, reside
6175 * out of the normal flow of the document (CSS position: absolute), and
6176 * can overlay other elements on the screen.
6180 oConfig.addProperty(
6181 POSITION_CONFIG.key,
6183 handler: this.configPosition,
6184 value: POSITION_CONFIG.value,
6185 validator: POSITION_CONFIG.validator,
6186 supercedes: POSITION_CONFIG.supercedes
6192 * @config submenualignment
6193 * @description Array defining how submenus should be aligned to their
6194 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6195 * a submenu's top left corner is aligned to its parent menu item's top
6197 * @default ["tl","tr"]
6200 oConfig.addProperty(
6201 SUBMENU_ALIGNMENT_CONFIG.key,
6203 value: SUBMENU_ALIGNMENT_CONFIG.value,
6204 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6210 * @config autosubmenudisplay
6211 * @description Boolean indicating if submenus are automatically made
6212 * visible when the user mouses over the menu's items.
6216 oConfig.addProperty(
6217 AUTO_SUBMENU_DISPLAY_CONFIG.key,
6219 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
6220 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6221 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6228 * @description Number indicating the time (in milliseconds) that should
6229 * expire before a submenu is made visible when the user mouses over
6230 * the menu's items. This property is only applied when the "position"
6231 * configuration property is set to dynamic and is automatically applied
6236 oConfig.addProperty(
6237 SHOW_DELAY_CONFIG.key,
6239 value: SHOW_DELAY_CONFIG.value,
6240 validator: SHOW_DELAY_CONFIG.validator,
6241 suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6248 * @description Number indicating the time (in milliseconds) that should
6249 * expire before the menu is hidden. This property is only applied when
6250 * the "position" configuration property is set to dynamic and is
6251 * automatically applied to all submenus.
6255 oConfig.addProperty(
6256 HIDE_DELAY_CONFIG.key,
6258 handler: this.configHideDelay,
6259 value: HIDE_DELAY_CONFIG.value,
6260 validator: HIDE_DELAY_CONFIG.validator,
6261 suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6267 * @config submenuhidedelay
6268 * @description Number indicating the time (in milliseconds) that should
6269 * expire before a submenu is hidden when the user mouses out of a menu item
6270 * heading in the direction of a submenu. The value must be greater than or
6271 * equal to the value specified for the "showdelay" configuration property.
6272 * This property is only applied when the "position" configuration property
6273 * is set to dynamic and is automatically applied to all submenus.
6277 oConfig.addProperty(
6278 SUBMENU_HIDE_DELAY_CONFIG.key,
6280 value: SUBMENU_HIDE_DELAY_CONFIG.value,
6281 validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6282 suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6288 * @config clicktohide
6289 * @description Boolean indicating if the menu will automatically be
6290 * hidden if the user clicks outside of it. This property is only
6291 * applied when the "position" configuration property is set to dynamic
6292 * and is automatically applied to all submenus.
6296 oConfig.addProperty(
6297 CLICK_TO_HIDE_CONFIG.key,
6299 value: CLICK_TO_HIDE_CONFIG.value,
6300 validator: CLICK_TO_HIDE_CONFIG.validator,
6301 suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6308 * @description HTML element reference or string specifying the id
6309 * attribute of the HTML element that the menu's markup should be
6311 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6312 * level-one-html.html#ID-58190037">HTMLElement</a>|String
6313 * @default document.body
6315 oConfig.addProperty(
6316 CONTAINER_CONFIG.key,
6318 handler: this.configContainer,
6319 value: document.body,
6320 suppressEvent: CONTAINER_CONFIG.suppressEvent
6326 * @config scrollincrement
6327 * @description Number used to control the scroll speed of a menu. Used to
6328 * increment the "scrollTop" property of the menu's body by when a menu's
6329 * content is scrolling. When set this property is automatically applied
6334 oConfig.addProperty(
6335 SCROLL_INCREMENT_CONFIG.key,
6337 value: SCROLL_INCREMENT_CONFIG.value,
6338 validator: SCROLL_INCREMENT_CONFIG.validator,
6339 supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6340 suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6346 * @config minscrollheight
6347 * @description Number defining the minimum threshold for the "maxheight"
6348 * configuration property. When set this property is automatically applied
6353 oConfig.addProperty(
6354 MIN_SCROLL_HEIGHT_CONFIG.key,
6356 value: MIN_SCROLL_HEIGHT_CONFIG.value,
6357 validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6358 supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6359 suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6366 * @description Number defining the maximum height (in pixels) for a menu's
6367 * body element (<code><div class="bd"<</code>). Once a menu's body
6368 * exceeds this height, the contents of the body are scrolled to maintain
6369 * this value. This value cannot be set lower than the value of the
6370 * "minscrollheight" configuration property.
6374 oConfig.addProperty(
6375 MAX_HEIGHT_CONFIG.key,
6377 handler: this.configMaxHeight,
6378 value: MAX_HEIGHT_CONFIG.value,
6379 validator: MAX_HEIGHT_CONFIG.validator,
6380 suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6381 supercedes: MAX_HEIGHT_CONFIG.supercedes
6388 * @description String representing the CSS class to be applied to the
6389 * menu's root <code><div></code> element. The specified class(es)
6390 * are appended in addition to the default class as specified by the menu's
6391 * CSS_CLASS_NAME constant. When set this property is automatically
6392 * applied to all submenus.
6396 oConfig.addProperty(
6397 CLASS_NAME_CONFIG.key,
6399 handler: this.configClassName,
6400 value: CLASS_NAME_CONFIG.value,
6401 validator: CLASS_NAME_CONFIG.validator,
6402 supercedes: CLASS_NAME_CONFIG.supercedes
6409 * @description Boolean indicating if the menu should be disabled.
6410 * Disabling a menu disables each of its items. (Disabled menu items are
6411 * dimmed and will not respond to user input or fire events.) Disabled
6412 * menus have a corresponding "disabled" CSS class applied to their root
6413 * <code><div></code> element.
6417 oConfig.addProperty(
6418 DISABLED_CONFIG.key,
6420 handler: this.configDisabled,
6421 value: DISABLED_CONFIG.value,
6422 validator: DISABLED_CONFIG.validator,
6423 suppressEvent: DISABLED_CONFIG.suppressEvent
6430 * @description Boolean indicating if the menu should have a shadow.
6434 oConfig.addProperty(
6437 handler: this.configShadow,
6438 value: SHADOW_CONFIG.value,
6439 validator: SHADOW_CONFIG.validator
6446 * @description Boolean indicating if the menu should remain open when clicked.
6450 oConfig.addProperty(
6451 KEEP_OPEN_CONFIG.key,
6453 value: KEEP_OPEN_CONFIG.value,
6454 validator: KEEP_OPEN_CONFIG.validator
6460 }); // END YAHOO.lang.extend
6469 * Creates an item for a menu.
6471 * @param {String} p_oObject String specifying the text of the menu item.
6472 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6473 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6474 * the <code><li></code> element of the menu item.
6475 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6476 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6477 * specifying the <code><optgroup></code> element of the menu item.
6478 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6479 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6480 * specifying the <code><option></code> element of the menu item.
6481 * @param {Object} p_oConfig Optional. Object literal specifying the
6482 * configuration for the menu item. See configuration class documentation
6487 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6493 this.parent = p_oConfig.parent;
6494 this.value = p_oConfig.value;
6495 this.id = p_oConfig.id;
6499 this.init(p_oObject, p_oConfig);
6506 var Dom = YAHOO.util.Dom,
6507 Module = YAHOO.widget.Module,
6508 Menu = YAHOO.widget.Menu,
6509 MenuItem = YAHOO.widget.MenuItem,
6510 CustomEvent = YAHOO.util.CustomEvent,
6514 // Private string constants
6519 _HELP_TEXT = "helptext",
6522 _EMPHASIS = "emphasis",
6523 _STRONG_EMPHASIS = "strongemphasis",
6524 _CHECKED = "checked",
6525 _SUBMENU = "submenu",
6526 _DISABLED = "disabled",
6527 _SELECTED = "selected",
6528 _HAS_SUBMENU = "hassubmenu",
6529 _CHECKED_DISABLED = "checked-disabled",
6530 _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6531 _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6532 _CHECKED_SELECTED = "checked-selected",
6533 _ONCLICK = "onclick",
6534 _CLASSNAME = "classname",
6537 _OPTGROUP = "OPTGROUP",
6538 _LI_UPPERCASE = "LI",
6542 _START_HELP_TEXT = "<em class=\"helptext\">",
6545 _START_STRONG = "<strong>",
6546 _END_STRONG = "</strong>",
6547 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6551 _VISIBLE = "visible",
6553 _MENUITEM = "MenuItem",
6557 _LI_LOWERCASE = "li",
6558 _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6562 ["mouseOverEvent", "mouseover"],
6563 ["mouseOutEvent", "mouseout"],
6564 ["mouseDownEvent", "mousedown"],
6565 ["mouseUpEvent", "mouseup"],
6566 ["clickEvent", _CLICK],
6567 ["keyPressEvent", "keypress"],
6568 ["keyDownEvent", "keydown"],
6569 ["keyUpEvent", "keyup"],
6570 ["focusEvent", "focus"],
6571 ["blurEvent", "blur"],
6572 ["destroyEvent", "destroy"]
6578 value: _EMPTY_STRING,
6579 validator: Lang.isString,
6583 HELP_TEXT_CONFIG = {
6585 supercedes: [_TEXT],
6603 validator: Lang.isBoolean,
6604 suppressEvent: true,
6608 STRONG_EMPHASIS_CONFIG = {
6609 key: _STRONG_EMPHASIS,
6611 validator: Lang.isBoolean,
6612 suppressEvent: true,
6619 validator: Lang.isBoolean,
6620 suppressEvent: true,
6621 supercedes: [_DISABLED, _SELECTED]
6626 suppressEvent: true,
6627 supercedes: [_DISABLED, _SELECTED]
6633 validator: Lang.isBoolean,
6634 suppressEvent: true,
6635 supercedes: [_TEXT, _SELECTED]
6641 validator: Lang.isBoolean,
6650 CLASS_NAME_CONFIG = {
6653 validator: Lang.isString,
6657 KEY_LISTENER_CONFIG = {
6663 m_oMenuItemTemplate = null,
6669 * @method getClassNameForState
6670 * @description Returns a class name for the specified prefix and state. If the class name does not
6671 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6673 * @param {String} prefix String representing the prefix for the class name
6674 * @param {String} state String representing a state - "disabled," "checked," etc.
6676 var getClassNameForState = function (prefix, state) {
6678 var oClassNames = CLASS_NAMES[prefix];
6681 CLASS_NAMES[prefix] = {};
6682 oClassNames = CLASS_NAMES[prefix];
6686 var sClassName = oClassNames[state];
6689 sClassName = prefix + _HYPHEN + state;
6690 oClassNames[state] = sClassName;
6699 * @method addClassNameForState
6700 * @description Applies a class name to a MenuItem instance's <LI> and <A> elements
6701 * that represents a MenuItem's state - "disabled," "checked," etc.
6703 * @param {String} state String representing a state - "disabled," "checked," etc.
6705 var addClassNameForState = function (state) {
6707 Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6708 Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6713 * @method removeClassNameForState
6714 * @description Removes a class name from a MenuItem instance's <LI> and <A> elements
6715 * that represents a MenuItem's state - "disabled," "checked," etc.
6717 * @param {String} state String representing a state - "disabled," "checked," etc.
6719 var removeClassNameForState = function (state) {
6721 Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6722 Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6727 MenuItem.prototype = {
6730 * @property CSS_CLASS_NAME
6731 * @description String representing the CSS class(es) to be applied to the
6732 * <code><li></code> element of the menu item.
6733 * @default "yuimenuitem"
6737 CSS_CLASS_NAME: "yuimenuitem",
6741 * @property CSS_LABEL_CLASS_NAME
6742 * @description String representing the CSS class(es) to be applied to the
6743 * menu item's <code><a></code> element.
6744 * @default "yuimenuitemlabel"
6748 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6752 * @property SUBMENU_TYPE
6753 * @description Object representing the type of menu to instantiate and
6754 * add when parsing the child nodes of the menu item's source HTML element.
6756 * @type YAHOO.widget.Menu
6762 // Private member variables
6766 * @property _oAnchor
6767 * @description Object reference to the menu item's
6768 * <code><a></code> element.
6771 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6772 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6778 * @property _oHelpTextEM
6779 * @description Object reference to the menu item's help text
6780 * <code><em></code> element.
6783 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6784 * one-html.html#ID-58190037">HTMLElement</a>
6790 * @property _oSubmenu
6791 * @description Object reference to the menu item's submenu.
6794 * @type YAHOO.widget.Menu
6800 * @property _oOnclickAttributeValue
6801 * @description Object reference to the menu item's current value for the
6802 * "onclick" configuration attribute.
6807 _oOnclickAttributeValue: null,
6811 * @property _sClassName
6812 * @description The current value of the "classname" configuration attribute.
6821 // Public properties
6825 * @property constructor
6826 * @description Object reference to the menu item's constructor function.
6827 * @default YAHOO.widget.MenuItem
6828 * @type YAHOO.widget.MenuItem
6830 constructor: MenuItem,
6835 * @description Number indicating the ordinal position of the menu item in
6844 * @property groupIndex
6845 * @description Number indicating the index of the group to which the menu
6855 * @description Object reference to the menu item's parent menu.
6857 * @type YAHOO.widget.Menu
6864 * @description Object reference to the menu item's
6865 * <code><li></code> element.
6866 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6867 * -one-html.html#ID-74680021">HTMLLIElement</a>
6868 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6869 * one-html.html#ID-74680021">HTMLLIElement</a>
6875 * @property srcElement
6876 * @description Object reference to the HTML element (either
6877 * <code><li></code>, <code><optgroup></code> or
6878 * <code><option></code>) used create the menu item.
6879 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6880 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6881 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6882 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6883 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6884 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6885 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6886 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6887 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6888 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6895 * @description Object reference to the menu item's value.
6904 * @deprecated Use YAHOO.env.ua
6905 * @description String representing the browser.
6908 browser: Module.prototype.browser,
6913 * @description Id of the menu item's root <code><li></code>
6914 * element. This property should be set via the constructor using the
6915 * configuration object literal. If an id is not specified, then one will
6916 * be created using the "generateId" method of the Dom utility.
6928 * @event destroyEvent
6929 * @description Fires when the menu item's <code><li></code>
6930 * element is removed from its parent <code><ul></code> element.
6931 * @type YAHOO.util.CustomEvent
6936 * @event mouseOverEvent
6937 * @description Fires when the mouse has entered the menu item. Passes
6938 * back the DOM Event object as an argument.
6939 * @type YAHOO.util.CustomEvent
6944 * @event mouseOutEvent
6945 * @description Fires when the mouse has left the menu item. Passes back
6946 * the DOM Event object as an argument.
6947 * @type YAHOO.util.CustomEvent
6952 * @event mouseDownEvent
6953 * @description Fires when the user mouses down on the menu item. Passes
6954 * back the DOM Event object as an argument.
6955 * @type YAHOO.util.CustomEvent
6960 * @event mouseUpEvent
6961 * @description Fires when the user releases a mouse button while the mouse
6962 * is over the menu item. Passes back the DOM Event object as an argument.
6963 * @type YAHOO.util.CustomEvent
6969 * @description Fires when the user clicks the on the menu item. Passes
6970 * back the DOM Event object as an argument.
6971 * @type YAHOO.util.CustomEvent
6976 * @event keyPressEvent
6977 * @description Fires when the user presses an alphanumeric key when the
6978 * menu item has focus. Passes back the DOM Event object as an argument.
6979 * @type YAHOO.util.CustomEvent
6984 * @event keyDownEvent
6985 * @description Fires when the user presses a key when the menu item has
6986 * focus. Passes back the DOM Event object as an argument.
6987 * @type YAHOO.util.CustomEvent
6993 * @description Fires when the user releases a key when the menu item has
6994 * focus. Passes back the DOM Event object as an argument.
6995 * @type YAHOO.util.CustomEvent
7001 * @description Fires when the menu item receives focus.
7002 * @type YAHOO.util.CustomEvent
7008 * @description Fires when the menu item loses the input focus.
7009 * @type YAHOO.util.CustomEvent
7015 * @description The MenuItem class's initialization method. This method is
7016 * automatically called by the constructor, and sets up all DOM references
7017 * for pre-existing markup, and creates required markup if it is not
7019 * @param {String} p_oObject String specifying the text of the menu item.
7020 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7021 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
7022 * the <code><li></code> element of the menu item.
7023 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7024 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
7025 * specifying the <code><optgroup></code> element of the menu item.
7026 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7027 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
7028 * specifying the <code><option></code> element of the menu item.
7029 * @param {Object} p_oConfig Optional. Object literal specifying the
7030 * configuration for the menu item. See configuration class documentation
7033 init: function (p_oObject, p_oConfig) {
7036 if (!this.SUBMENU_TYPE) {
7038 this.SUBMENU_TYPE = Menu;
7043 // Create the config object
7045 this.cfg = new YAHOO.util.Config(this);
7047 this.initDefaultConfig();
7049 var oConfig = this.cfg,
7060 if (Lang.isString(p_oObject)) {
7062 this._createRootNodeStructure();
7064 oConfig.queueProperty(_TEXT, p_oObject);
7067 else if (p_oObject && p_oObject.tagName) {
7069 switch(p_oObject.tagName.toUpperCase()) {
7073 this._createRootNodeStructure();
7075 oConfig.queueProperty(_TEXT, p_oObject.text);
7076 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7078 this.value = p_oObject.value;
7080 this.srcElement = p_oObject;
7086 this._createRootNodeStructure();
7088 oConfig.queueProperty(_TEXT, p_oObject.label);
7089 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7091 this.srcElement = p_oObject;
7093 this._initSubTree();
7099 // Get the anchor node (if it exists)
7101 oAnchor = Dom.getFirstChild(p_oObject);
7104 // Capture the "text" and/or the "URL"
7108 sURL = oAnchor.getAttribute(_HREF, 2);
7109 sTarget = oAnchor.getAttribute(_TARGET);
7111 sText = oAnchor.innerHTML;
7115 this.srcElement = p_oObject;
7116 this.element = p_oObject;
7117 this._oAnchor = oAnchor;
7120 Set these properties silently to sync up the
7121 configuration object without making changes to the
7125 oConfig.setProperty(_TEXT, sText, true);
7126 oConfig.setProperty(_URL, sURL, true);
7127 oConfig.setProperty(_TARGET, sTarget, true);
7129 this._initSubTree();
7140 sId = (this.srcElement || this.element).id;
7144 sId = this.id || Dom.generateId();
7146 this.element.id = sId;
7153 Dom.addClass(this.element, this.CSS_CLASS_NAME);
7154 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7157 i = EVENT_TYPES.length - 1;
7161 aEventData = EVENT_TYPES[i];
7163 oCustomEvent = this.createEvent(aEventData[1]);
7164 oCustomEvent.signature = CustomEvent.LIST;
7166 this[aEventData[0]] = oCustomEvent;
7174 oConfig.applyConfig(p_oConfig);
7178 oConfig.fireQueue();
7189 * @method _createRootNodeStructure
7190 * @description Creates the core DOM structure for the menu item.
7193 _createRootNodeStructure: function () {
7198 if (!m_oMenuItemTemplate) {
7200 m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7201 m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7205 oElement = m_oMenuItemTemplate.cloneNode(true);
7206 oElement.className = this.CSS_CLASS_NAME;
7208 oAnchor = oElement.firstChild;
7209 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7211 this.element = oElement;
7212 this._oAnchor = oAnchor;
7218 * @method _initSubTree
7219 * @description Iterates the source element's childNodes collection and uses
7220 * the child nodes to instantiate other menus.
7223 _initSubTree: function () {
7225 var oSrcEl = this.srcElement,
7234 if (oSrcEl.childNodes.length > 0) {
7236 if (this.parent.lazyLoad && this.parent.srcElement &&
7237 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7239 oConfig.setProperty(
7241 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7247 oNode = oSrcEl.firstChild;
7252 if (oNode && oNode.tagName) {
7254 switch(oNode.tagName.toUpperCase()) {
7258 oConfig.setProperty(_SUBMENU, oNode);
7264 aOptions[aOptions.length] = oNode;
7273 while((oNode = oNode.nextSibling));
7276 nOptions = aOptions.length;
7280 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7282 oConfig.setProperty(_SUBMENU, oMenu);
7284 for(n=0; n<nOptions; n++) {
7286 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7300 // Event handlers for configuration properties
7304 * @method configText
7305 * @description Event handler for when the "text" configuration property of
7306 * the menu item changes.
7307 * @param {String} p_sType String representing the name of the event that
7309 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7310 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7311 * that fired the event.
7313 configText: function (p_sType, p_aArgs, p_oItem) {
7315 var sText = p_aArgs[0],
7317 oAnchor = this._oAnchor,
7318 sHelpText = oConfig.getProperty(_HELP_TEXT),
7319 sHelpTextHTML = _EMPTY_STRING,
7320 sEmphasisStartTag = _EMPTY_STRING,
7321 sEmphasisEndTag = _EMPTY_STRING;
7329 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7334 if (oConfig.getProperty(_EMPHASIS)) {
7336 sEmphasisStartTag = _START_EM;
7337 sEmphasisEndTag = _END_EM;
7342 if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7344 sEmphasisStartTag = _START_STRONG;
7345 sEmphasisEndTag = _END_STRONG;
7350 oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7358 * @method configHelpText
7359 * @description Event handler for when the "helptext" configuration property
7360 * of the menu item changes.
7361 * @param {String} p_sType String representing the name of the event that
7363 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7364 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7365 * that fired the event.
7367 configHelpText: function (p_sType, p_aArgs, p_oItem) {
7369 this.cfg.refireEvent(_TEXT);
7376 * @description Event handler for when the "url" configuration property of
7377 * the menu item changes.
7378 * @param {String} p_sType String representing the name of the event that
7380 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7381 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7382 * that fired the event.
7384 configURL: function (p_sType, p_aArgs, p_oItem) {
7386 var sURL = p_aArgs[0];
7394 var oAnchor = this._oAnchor;
7398 oAnchor.removeAttribute(_HREF);
7402 oAnchor.setAttribute(_HREF, sURL);
7408 * @method configTarget
7409 * @description Event handler for when the "target" configuration property
7410 * of the menu item changes.
7411 * @param {String} p_sType String representing the name of the event that
7413 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7414 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7415 * that fired the event.
7417 configTarget: function (p_sType, p_aArgs, p_oItem) {
7419 var sTarget = p_aArgs[0],
7420 oAnchor = this._oAnchor;
7422 if (sTarget && sTarget.length > 0) {
7424 oAnchor.setAttribute(_TARGET, sTarget);
7429 oAnchor.removeAttribute(_TARGET);
7437 * @method configEmphasis
7438 * @description Event handler for when the "emphasis" configuration property
7439 * of the menu item changes.
7440 * @param {String} p_sType String representing the name of the event that
7442 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7443 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7444 * that fired the event.
7446 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7448 var bEmphasis = p_aArgs[0],
7452 if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7454 oConfig.setProperty(_STRONG_EMPHASIS, false);
7459 oConfig.refireEvent(_TEXT);
7465 * @method configStrongEmphasis
7466 * @description Event handler for when the "strongemphasis" configuration
7467 * property of the menu item changes.
7468 * @param {String} p_sType String representing the name of the event that
7470 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7471 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7472 * that fired the event.
7474 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7476 var bStrongEmphasis = p_aArgs[0],
7480 if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7482 oConfig.setProperty(_EMPHASIS, false);
7486 oConfig.refireEvent(_TEXT);
7492 * @method configChecked
7493 * @description Event handler for when the "checked" configuration property
7494 * of the menu item changes.
7495 * @param {String} p_sType String representing the name of the event that
7497 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7498 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7499 * that fired the event.
7501 configChecked: function (p_sType, p_aArgs, p_oItem) {
7503 var bChecked = p_aArgs[0],
7509 addClassNameForState.call(this, _CHECKED);
7514 removeClassNameForState.call(this, _CHECKED);
7518 oConfig.refireEvent(_TEXT);
7521 if (oConfig.getProperty(_DISABLED)) {
7523 oConfig.refireEvent(_DISABLED);
7528 if (oConfig.getProperty(_SELECTED)) {
7530 oConfig.refireEvent(_SELECTED);
7539 * @method configDisabled
7540 * @description Event handler for when the "disabled" configuration property
7541 * of the menu item changes.
7542 * @param {String} p_sType String representing the name of the event that
7544 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7545 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7546 * that fired the event.
7548 configDisabled: function (p_sType, p_aArgs, p_oItem) {
7550 var bDisabled = p_aArgs[0],
7552 oSubmenu = oConfig.getProperty(_SUBMENU),
7553 bChecked = oConfig.getProperty(_CHECKED);
7558 if (oConfig.getProperty(_SELECTED)) {
7560 oConfig.setProperty(_SELECTED, false);
7565 addClassNameForState.call(this, _DISABLED);
7570 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7577 addClassNameForState.call(this, _CHECKED_DISABLED);
7584 removeClassNameForState.call(this, _DISABLED);
7589 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7596 removeClassNameForState.call(this, _CHECKED_DISABLED);
7606 * @method configSelected
7607 * @description Event handler for when the "selected" configuration property
7608 * of the menu item changes.
7609 * @param {String} p_sType String representing the name of the event that
7611 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7612 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7613 * that fired the event.
7615 configSelected: function (p_sType, p_aArgs, p_oItem) {
7617 var oConfig = this.cfg,
7618 oAnchor = this._oAnchor,
7620 bSelected = p_aArgs[0],
7621 bChecked = oConfig.getProperty(_CHECKED),
7622 oSubmenu = oConfig.getProperty(_SUBMENU);
7632 if (bSelected && !oConfig.getProperty(_DISABLED)) {
7634 addClassNameForState.call(this, _SELECTED);
7639 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7646 addClassNameForState.call(this, _CHECKED_SELECTED);
7653 removeClassNameForState.call(this, _SELECTED);
7658 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7665 removeClassNameForState.call(this, _CHECKED_SELECTED);
7672 if (this.hasFocus() && UA.opera) {
7682 * @method _onSubmenuBeforeHide
7683 * @description "beforehide" Custom Event handler for a submenu.
7685 * @param {String} p_sType String representing the name of the event that
7687 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7689 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7691 var oItem = this.parent,
7696 oItem._oAnchor.blur();
7697 oMenu.beforeHideEvent.unsubscribe(onHide);
7702 if (oItem.hasFocus()) {
7704 oMenu = oItem.parent;
7706 oMenu.beforeHideEvent.subscribe(onHide);
7714 * @method configSubmenu
7715 * @description Event handler for when the "submenu" configuration property
7716 * of the menu item changes.
7717 * @param {String} p_sType String representing the name of the event that
7719 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7720 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7721 * that fired the event.
7723 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7725 var oSubmenu = p_aArgs[0],
7727 bLazyLoad = this.parent && this.parent.lazyLoad,
7735 if (oSubmenu instanceof Menu) {
7738 oMenu.parent = this;
7739 oMenu.lazyLoad = bLazyLoad;
7742 else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7744 sSubmenuId = oSubmenu.id;
7745 oSubmenuConfig = oSubmenu;
7747 oSubmenuConfig.lazyload = bLazyLoad;
7748 oSubmenuConfig.parent = this;
7750 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7753 // Set the value of the property to the Menu instance
7755 oConfig.setProperty(_SUBMENU, oMenu, true);
7760 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7763 // Set the value of the property to the Menu instance
7765 oConfig.setProperty(_SUBMENU, oMenu, true);
7772 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7774 addClassNameForState.call(this, _HAS_SUBMENU);
7777 if (oConfig.getProperty(_URL) === _HASH) {
7779 oConfig.setProperty(_URL, (_HASH + oMenu.id));
7784 this._oSubmenu = oMenu;
7789 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7798 removeClassNameForState.call(this, _HAS_SUBMENU);
7800 if (this._oSubmenu) {
7802 this._oSubmenu.destroy();
7809 if (oConfig.getProperty(_DISABLED)) {
7811 oConfig.refireEvent(_DISABLED);
7816 if (oConfig.getProperty(_SELECTED)) {
7818 oConfig.refireEvent(_SELECTED);
7826 * @method configOnClick
7827 * @description Event handler for when the "onclick" configuration property
7828 * of the menu item changes.
7829 * @param {String} p_sType String representing the name of the event that
7831 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7832 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7833 * that fired the event.
7835 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7837 var oObject = p_aArgs[0];
7840 Remove any existing listeners if a "click" event handler has
7841 already been specified.
7844 if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7846 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7847 this._oOnclickAttributeValue.obj);
7849 this._oOnclickAttributeValue = null;
7854 if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
7855 Lang.isFunction(oObject.fn)) {
7857 this.clickEvent.subscribe(oObject.fn,
7858 ((_OBJ in oObject) ? oObject.obj : this),
7859 ((_SCOPE in oObject) ? oObject.scope : null) );
7861 this._oOnclickAttributeValue = oObject;
7869 * @method configClassName
7870 * @description Event handler for when the "classname" configuration
7871 * property of a menu item changes.
7872 * @param {String} p_sType String representing the name of the event that
7874 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7875 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7876 * that fired the event.
7878 configClassName: function (p_sType, p_aArgs, p_oItem) {
7880 var sClassName = p_aArgs[0];
7882 if (this._sClassName) {
7884 Dom.removeClass(this.element, this._sClassName);
7888 Dom.addClass(this.element, sClassName);
7889 this._sClassName = sClassName;
7895 * @method _dispatchClickEvent
7896 * @description Dispatches a DOM "click" event to the anchor element of a
7897 * MenuItem instance.
7900 _dispatchClickEvent: function () {
7902 var oMenuItem = this,
7906 if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7908 oAnchor = Dom.getFirstChild(oMenuItem.element);
7910 // Dispatch a "click" event to the MenuItem's anchor so that its
7911 // "click" event handlers will get called in response to the user
7912 // pressing the keyboard shortcut defined by the "keylistener"
7913 // configuration property.
7916 oAnchor.fireEvent(_ONCLICK);
7920 if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7922 oEvent = document.createEvent("HTMLEvents");
7923 oEvent.initEvent(_CLICK, true, true);
7928 oEvent = document.createEvent("MouseEvents");
7929 oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0,
7930 0, 0, false, false, false, false, 0, null);
7934 oAnchor.dispatchEvent(oEvent);
7944 * @method _createKeyListener
7945 * @description "show" event handler for a Menu instance - responsible for
7946 * setting up the KeyListener instance for a MenuItem.
7948 * @param {String} type String representing the name of the event that
7950 * @param {Array} args Array of arguments sent when the event was fired.
7951 * @param {Array} keyData Array of arguments sent when the event was fired.
7953 _createKeyListener: function (type, args, keyData) {
7955 var oMenuItem = this,
7956 oMenu = oMenuItem.parent;
7958 var oKeyListener = new YAHOO.util.KeyListener(
7959 oMenu.element.ownerDocument,
7962 fn: oMenuItem._dispatchClickEvent,
7964 correctScope: true });
7967 if (oMenu.cfg.getProperty(_VISIBLE)) {
7968 oKeyListener.enable();
7972 oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
7973 oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
7975 oMenuItem._keyListener = oKeyListener;
7977 oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
7983 * @method configKeyListener
7984 * @description Event handler for when the "keylistener" configuration
7985 * property of a menu item changes.
7986 * @param {String} p_sType String representing the name of the event that
7988 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7990 configKeyListener: function (p_sType, p_aArgs) {
7992 var oKeyData = p_aArgs[0],
7994 oMenu = oMenuItem.parent;
7996 if (oMenuItem._keyData) {
7998 // Unsubscribe from the "show" event in case the keylistener
7999 // config was changed before the Menu was ever made visible.
8001 oMenu.unsubscribe(_SHOW,
8002 oMenuItem._createKeyListener, oMenuItem._keyData);
8004 oMenuItem._keyData = null;
8009 // Tear down for the previous value of the "keylistener" property
8011 if (oMenuItem._keyListener) {
8013 oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
8014 oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
8016 oMenuItem._keyListener.disable();
8017 oMenuItem._keyListener = null;
8024 oMenuItem._keyData = oKeyData;
8026 // Defer the creation of the KeyListener instance until the
8027 // parent Menu is visible. This is necessary since the
8028 // KeyListener instance needs to be bound to the document the
8029 // Menu has been rendered into. Deferring creation of the
8030 // KeyListener instance also improves performance.
8032 oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
8033 oKeyData, oMenuItem);
8043 * @method initDefaultConfig
8044 * @description Initializes an item's configurable properties.
8046 initDefaultConfig : function () {
8048 var oConfig = this.cfg;
8051 // Define the configuration attributes
8055 * @description String specifying the text label for the menu item.
8056 * When building a menu from existing HTML the value of this property
8057 * will be interpreted from the menu's markup.
8061 oConfig.addProperty(
8064 handler: this.configText,
8065 value: TEXT_CONFIG.value,
8066 validator: TEXT_CONFIG.validator,
8067 suppressEvent: TEXT_CONFIG.suppressEvent
8074 * @description String specifying additional instructional text to
8075 * accompany the text for the menu item.
8076 * @deprecated Use "text" configuration property to add help text markup.
8077 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em
8078 * class=\"helptext\">Ctrl + C</em>");</code>
8080 * @type String|<a href="http://www.w3.org/TR/
8081 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8084 oConfig.addProperty(
8085 HELP_TEXT_CONFIG.key,
8087 handler: this.configHelpText,
8088 supercedes: HELP_TEXT_CONFIG.supercedes,
8089 suppressEvent: HELP_TEXT_CONFIG.suppressEvent
8096 * @description String specifying the URL for the menu item's anchor's
8097 * "href" attribute. When building a menu from existing HTML the value
8098 * of this property will be interpreted from the menu's markup.
8102 oConfig.addProperty(
8105 handler: this.configURL,
8106 value: URL_CONFIG.value,
8107 suppressEvent: URL_CONFIG.suppressEvent
8114 * @description String specifying the value for the "target" attribute
8115 * of the menu item's anchor element. <strong>Specifying a target will
8116 * require the user to click directly on the menu item's anchor node in
8117 * order to cause the browser to navigate to the specified URL.</strong>
8118 * When building a menu from existing HTML the value of this property
8119 * will be interpreted from the menu's markup.
8123 oConfig.addProperty(
8126 handler: this.configTarget,
8127 suppressEvent: TARGET_CONFIG.suppressEvent
8134 * @description Boolean indicating if the text of the menu item will be
8135 * rendered with emphasis.
8136 * @deprecated Use the "text" configuration property to add emphasis.
8137 * For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some
8138 * Text</em>");</code>
8142 oConfig.addProperty(
8143 EMPHASIS_CONFIG.key,
8145 handler: this.configEmphasis,
8146 value: EMPHASIS_CONFIG.value,
8147 validator: EMPHASIS_CONFIG.validator,
8148 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8149 supercedes: EMPHASIS_CONFIG.supercedes
8155 * @config strongemphasis
8156 * @description Boolean indicating if the text of the menu item will be
8157 * rendered with strong emphasis.
8158 * @deprecated Use the "text" configuration property to add strong emphasis.
8159 * For example: <code>oMenuItem.cfg.setProperty("text", "<strong>
8160 * Some Text</strong>");</code>
8164 oConfig.addProperty(
8165 STRONG_EMPHASIS_CONFIG.key,
8167 handler: this.configStrongEmphasis,
8168 value: STRONG_EMPHASIS_CONFIG.value,
8169 validator: STRONG_EMPHASIS_CONFIG.validator,
8170 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8171 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8178 * @description Boolean indicating if the menu item should be rendered
8183 oConfig.addProperty(
8186 handler: this.configChecked,
8187 value: CHECKED_CONFIG.value,
8188 validator: CHECKED_CONFIG.validator,
8189 suppressEvent: CHECKED_CONFIG.suppressEvent,
8190 supercedes: CHECKED_CONFIG.supercedes
8197 * @description Boolean indicating if the menu item should be disabled.
8198 * (Disabled menu items are dimmed and will not respond to user input
8203 oConfig.addProperty(
8204 DISABLED_CONFIG.key,
8206 handler: this.configDisabled,
8207 value: DISABLED_CONFIG.value,
8208 validator: DISABLED_CONFIG.validator,
8209 suppressEvent: DISABLED_CONFIG.suppressEvent
8216 * @description Boolean indicating if the menu item should
8221 oConfig.addProperty(
8222 SELECTED_CONFIG.key,
8224 handler: this.configSelected,
8225 value: SELECTED_CONFIG.value,
8226 validator: SELECTED_CONFIG.validator,
8227 suppressEvent: SELECTED_CONFIG.suppressEvent
8234 * @description Object specifying the submenu to be appended to the
8235 * menu item. The value can be one of the following: <ul><li>Object
8236 * specifying a Menu instance.</li><li>Object literal specifying the
8237 * menu to be created. Format: <code>{ id: [menu id], itemdata:
8238 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
8239 * items</a>] }</code>.</li><li>String specifying the id attribute
8240 * of the <code><div></code> element of the menu.</li><li>
8241 * Object specifying the <code><div></code> element of the
8244 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8245 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8248 oConfig.addProperty(
8251 handler: this.configSubmenu,
8252 supercedes: SUBMENU_CONFIG.supercedes,
8253 suppressEvent: SUBMENU_CONFIG.suppressEvent
8260 * @description Object literal representing the code to be executed when
8261 * the item is clicked. Format:<br> <code> {<br>
8262 * <strong>fn:</strong> Function, // The handler to call when
8263 * the event fires.<br> <strong>obj:</strong> Object, // An
8264 * object to pass back to the handler.<br> <strong>scope:</strong>
8265 * Object // The object to use for the scope of the handler.
8270 oConfig.addProperty(
8273 handler: this.configOnClick,
8274 suppressEvent: ONCLICK_CONFIG.suppressEvent
8281 * @description CSS class to be applied to the menu item's root
8282 * <code><li></code> element. The specified class(es) are
8283 * appended in addition to the default class as specified by the menu
8284 * item's CSS_CLASS_NAME constant.
8288 oConfig.addProperty(
8289 CLASS_NAME_CONFIG.key,
8291 handler: this.configClassName,
8292 value: CLASS_NAME_CONFIG.value,
8293 validator: CLASS_NAME_CONFIG.validator,
8294 suppressEvent: CLASS_NAME_CONFIG.suppressEvent
8300 * @config keylistener
8301 * @description Object literal representing the key(s) that can be used
8302 * to trigger the MenuItem's "click" event. Possible attributes are
8303 * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
8304 * or an array of ints representing keycodes).
8308 oConfig.addProperty(
8309 KEY_LISTENER_CONFIG.key,
8311 handler: this.configKeyListener,
8312 value: KEY_LISTENER_CONFIG.value,
8313 suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
8321 * @method getNextEnabledSibling
8322 * @description Finds the menu item's next enabled sibling.
8323 * @return YAHOO.widget.MenuItem
8325 getNextEnabledSibling: function () {
8334 function getNextArrayItem(p_aArray, p_nStartIndex) {
8336 return p_aArray[p_nStartIndex] || getNextArrayItem(p_aArray, (p_nStartIndex+1));
8340 if (this.parent instanceof Menu) {
8342 nGroupIndex = this.groupIndex;
8344 aItemGroups = this.parent.getItemGroups();
8346 if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
8348 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
8354 if (nGroupIndex < (aItemGroups.length - 1)) {
8356 nNextGroupIndex = nGroupIndex + 1;
8361 nNextGroupIndex = 0;
8365 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
8367 // Retrieve the first menu item in the next group
8369 oNextItem = getNextArrayItem(aNextGroup, 0);
8373 returnVal = (oNextItem.cfg.getProperty(_DISABLED) ||
8374 oNextItem.element.style.display == _NONE) ?
8375 oNextItem.getNextEnabledSibling() : oNextItem;
8385 * @method getPreviousEnabledSibling
8386 * @description Finds the menu item's previous enabled sibling.
8387 * @return {YAHOO.widget.MenuItem}
8389 getPreviousEnabledSibling: function () {
8394 nPreviousGroupIndex,
8398 function getPreviousArrayItem(p_aArray, p_nStartIndex) {
8400 return p_aArray[p_nStartIndex] || getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
8404 function getFirstItemIndex(p_aArray, p_nStartIndex) {
8406 return p_aArray[p_nStartIndex] ? p_nStartIndex :
8407 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
8411 if (this.parent instanceof Menu) {
8413 nGroupIndex = this.groupIndex;
8414 aItemGroups = this.parent.getItemGroups();
8417 if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
8419 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
8425 if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
8427 nPreviousGroupIndex = nGroupIndex - 1;
8432 nPreviousGroupIndex = aItemGroups.length - 1;
8436 aPreviousGroup = getPreviousArrayItem(aItemGroups,
8437 nPreviousGroupIndex);
8439 oPreviousItem = getPreviousArrayItem(aPreviousGroup,
8440 (aPreviousGroup.length - 1));
8444 returnVal = (oPreviousItem.cfg.getProperty(_DISABLED) ||
8445 oPreviousItem.element.style.display == _NONE) ?
8446 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
8457 * @description Causes the menu item to receive the focus and fires the
8460 focus: function () {
8462 var oParent = this.parent,
8463 oAnchor = this._oAnchor,
8464 oActiveItem = oParent.activeItem;
8467 function setFocus() {
8471 if (!(UA.ie && !document.hasFocus())) {
8475 oActiveItem.blurEvent.fire();
8481 this.focusEvent.fire();
8493 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
8494 this.element.style.display != _NONE) {
8498 Setting focus via a timer fixes a race condition in Firefox, IE
8499 and Opera where the browser viewport jumps as it trys to
8500 position and focus the menu.
8503 Lang.later(0, this, setFocus);
8512 * @description Causes the menu item to lose focus and fires the
8517 var oParent = this.parent;
8519 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8521 Lang.later(0, this, function () {
8525 this._oAnchor.blur();
8526 this.blurEvent.fire();
8542 * @description Returns a boolean indicating whether or not the menu item
8546 hasFocus: function () {
8548 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8555 * @description Removes the menu item's <code><li></code> element
8556 * from its parent <code><ul></code> element.
8558 destroy: function () {
8560 var oEl = this.element,
8570 // If the item has a submenu, destroy it first
8572 oSubmenu = this.cfg.getProperty(_SUBMENU);
8581 // Remove the element from the parent node
8583 oParentNode = oEl.parentNode;
8587 oParentNode.removeChild(oEl);
8589 this.destroyEvent.fire();
8594 // Remove CustomEvent listeners
8596 i = EVENT_TYPES.length - 1;
8600 aEventData = EVENT_TYPES[i];
8602 this[aEventData[0]].unsubscribeAll();
8608 this.cfg.configChangedEvent.unsubscribeAll();
8617 * @description Returns a string representing the menu item.
8620 toString: function () {
8622 var sReturnVal = _MENUITEM,
8627 sReturnVal += (_SPACE + sId);
8637 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8643 _MOUSEDOWN = "mousedown",
8644 _CONTEXTMENU = "ContextMenu",
8648 * Creates a list of options or commands which are made visible in response to
8649 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8651 * @param {String} p_oElement String specifying the id attribute of the
8652 * <code><div></code> element of the context menu.
8653 * @param {String} p_oElement String specifying the id attribute of the
8654 * <code><select></code> element to be used as the data source for the
8656 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8657 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8658 * <code><div></code> element of the context menu.
8659 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8660 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8661 * the <code><select></code> element to be used as the data source for
8663 * @param {Object} p_oConfig Optional. Object literal specifying the
8664 * configuration for the context menu. See configuration class documentation
8666 * @class ContextMenu
8668 * @extends YAHOO.widget.Menu
8669 * @namespace YAHOO.widget
8671 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8673 YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8678 var Event = YAHOO.util.Event,
8680 ContextMenu = YAHOO.widget.ContextMenu,
8685 * Constant representing the name of the ContextMenu's events
8686 * @property EVENT_TYPES
8693 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8694 "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8701 * Constant representing the ContextMenu's configuration properties
8702 * @property DEFAULT_CONFIG
8715 * @description "beforeShow" event handler used to position the contextmenu.
8717 * @param {String} p_sType String representing the name of the event that
8719 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8720 * @param {Array} p_aPos Array representing the xy position for the context menu.
8722 function position(p_sType, p_aArgs, p_aPos) {
8724 this.cfg.setProperty(_XY, p_aPos);
8726 this.beforeShowEvent.unsubscribe(position, p_aPos);
8731 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8735 // Private properties
8739 * @property _oTrigger
8740 * @description Object reference to the current value of the "trigger"
8741 * configuration property.
8744 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8745 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8751 * @property _bCancelled
8752 * @description Boolean indicating if the display of the context menu should
8762 // Public properties
8766 * @property contextEventTarget
8767 * @description Object reference for the HTML element that was the target of the
8768 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8771 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8772 * html.html#ID-58190037">HTMLElement</a>
8774 contextEventTarget: null,
8782 * @event triggerContextMenuEvent
8783 * @description Custom Event wrapper for the "contextmenu" DOM event
8784 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8787 triggerContextMenuEvent: null,
8793 * @description The ContextMenu class's initialization method. This method is
8794 * automatically called by the constructor, and sets up all DOM references for
8795 * pre-existing markup, and creates required markup if it is not already present.
8796 * @param {String} p_oElement String specifying the id attribute of the
8797 * <code><div></code> element of the context menu.
8798 * @param {String} p_oElement String specifying the id attribute of the
8799 * <code><select></code> element to be used as the data source for
8801 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8802 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8803 * <code><div></code> element of the context menu.
8804 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8805 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8806 * the <code><select></code> element to be used as the data source for
8808 * @param {Object} p_oConfig Optional. Object literal specifying the
8809 * configuration for the context menu. See configuration class documentation
8812 init: function(p_oElement, p_oConfig) {
8815 // Call the init of the superclass (YAHOO.widget.Menu)
8817 ContextMenu.superclass.init.call(this, p_oElement);
8820 this.beforeInitEvent.fire(ContextMenu);
8825 this.cfg.applyConfig(p_oConfig, true);
8829 this.initEvent.fire(ContextMenu);
8835 * @method initEvents
8836 * @description Initializes the custom events for the context menu.
8838 initEvents: function() {
8840 ContextMenu.superclass.initEvents.call(this);
8842 // Create custom events
8844 this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8846 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8853 * @description Cancels the display of the context menu.
8855 cancel: function() {
8857 this._bCancelled = true;
8867 * @method _removeEventHandlers
8868 * @description Removes all of the DOM event handlers from the HTML element(s)
8869 * whose "context menu" event ("click" for Opera) trigger the display of
8873 _removeEventHandlers: function() {
8875 var oTrigger = this._oTrigger;
8878 // Remove the event handlers from the trigger(s)
8882 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
8886 Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8896 // Private event handlers
8901 * @method _onTriggerClick
8902 * @description "click" event handler for the HTML element(s) identified as the
8903 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8905 * @param {Event} p_oEvent Object representing the DOM event object passed back
8906 * by the event utility (YAHOO.util.Event).
8907 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8908 * menu that is handling the event.
8910 _onTriggerClick: function(p_oEvent, p_oMenu) {
8912 if (p_oEvent.ctrlKey) {
8914 Event.stopEvent(p_oEvent);
8922 * @method _onTriggerContextMenu
8923 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8924 * element(s) that trigger the display of the context menu.
8926 * @param {Event} p_oEvent Object representing the DOM event object passed back
8927 * by the event utility (YAHOO.util.Event).
8928 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8929 * menu that is handling the event.
8931 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8935 if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8937 this.contextEventTarget = Event.getTarget(p_oEvent);
8939 this.triggerContextMenuEvent.fire(p_oEvent);
8942 if (!this._bCancelled) {
8945 Prevent the browser's default context menu from appearing and
8946 stop the propagation of the "contextmenu" event so that
8947 other ContextMenu instances are not displayed.
8950 Event.stopEvent(p_oEvent);
8953 // Hide any other Menu instances that might be visible
8955 YAHOO.widget.MenuManager.hideVisible();
8959 // Position and display the context menu
8961 aXY = Event.getXY(p_oEvent);
8964 if (!YAHOO.util.Dom.inDocument(this.element)) {
8966 this.beforeShowEvent.subscribe(position, aXY);
8971 this.cfg.setProperty(_XY, aXY);
8980 this._bCancelled = false;
8993 * @description Returns a string representing the context menu.
8996 toString: function() {
8998 var sReturnVal = _CONTEXTMENU,
9003 sReturnVal += (_SPACE + sId);
9013 * @method initDefaultConfig
9014 * @description Initializes the class's configurable properties which can be
9015 * changed using the context menu's Config object ("cfg").
9017 initDefaultConfig: function() {
9019 ContextMenu.superclass.initDefaultConfig.call(this);
9023 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
9024 * for Opera) trigger the display of the context menu. Can be a string
9025 * representing the id attribute of the HTML element, an object reference
9026 * for the HTML element, or an array of strings or HTML element references.
9028 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
9029 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
9031 this.cfg.addProperty(TRIGGER_CONFIG.key,
9033 handler: this.configTrigger,
9034 suppressEvent: TRIGGER_CONFIG.suppressEvent
9043 * @description Removes the context menu's <code><div></code> element
9044 * (and accompanying child nodes) from the document.
9046 destroy: function() {
9048 // Remove the DOM event handlers from the current trigger(s)
9050 this._removeEventHandlers();
9053 // Continue with the superclass implementation of this method
9055 ContextMenu.superclass.destroy.call(this);
9061 // Public event handlers for configuration properties
9065 * @method configTrigger
9066 * @description Event handler for when the value of the "trigger" configuration
9068 * @param {String} p_sType String representing the name of the event that
9070 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9071 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
9072 * menu that fired the event.
9074 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
9076 var oTrigger = p_aArgs[0];
9081 If there is a current "trigger" - remove the event handlers
9082 from that element(s) before assigning new ones
9085 if (this._oTrigger) {
9087 this._removeEventHandlers();
9091 this._oTrigger = oTrigger;
9095 Listen for the "mousedown" event in Opera b/c it does not
9096 support the "contextmenu" event
9099 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9103 Assign a "click" event handler to the trigger element(s) for
9104 Opera to prevent default browser behaviors.
9109 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9116 this._removeEventHandlers();
9122 }); // END YAHOO.lang.extend
9129 * Creates an item for a context menu.
9131 * @param {String} p_oObject String specifying the text of the context menu item.
9132 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9133 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9134 * <code><li></code> element of the context menu item.
9135 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9136 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9137 * specifying the <code><optgroup></code> element of the context
9139 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9140 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9141 * the <code><option></code> element of the context menu item.
9142 * @param {Object} p_oConfig Optional. Object literal specifying the
9143 * configuration for the context menu item. See configuration class
9144 * documentation for more details.
9145 * @class ContextMenuItem
9147 * @extends YAHOO.widget.MenuItem
9148 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9149 * are of type YAHOO.widget.MenuItem.
9151 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9154 var Lang = YAHOO.lang,
9159 _DYNAMIC_STATIC = "dynamic," + _STATIC,
9160 _DISABLED = "disabled",
9161 _SELECTED = "selected",
9162 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9163 _SUBMENU = "submenu",
9164 _VISIBLE = "visible",
9166 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9167 _MENUBAR = "MenuBar";
9170 * Horizontal collection of items, each of which can contain a submenu.
9172 * @param {String} p_oElement String specifying the id attribute of the
9173 * <code><div></code> element of the menu bar.
9174 * @param {String} p_oElement String specifying the id attribute of the
9175 * <code><select></code> element to be used as the data source for the
9177 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9178 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9179 * the <code><div></code> element of the menu bar.
9180 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9181 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9182 * specifying the <code><select></code> element to be used as the data
9183 * source for the menu bar.
9184 * @param {Object} p_oConfig Optional. Object literal specifying the
9185 * configuration for the menu bar. See configuration class documentation for
9189 * @extends YAHOO.widget.Menu
9190 * @namespace YAHOO.widget
9192 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9194 YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9200 * @method checkPosition
9201 * @description Checks to make sure that the value of the "position" property
9202 * is one of the supported strings. Returns true if the position is supported.
9204 * @param {Object} p_sPosition String specifying the position of the menu.
9207 function checkPosition(p_sPosition) {
9209 var returnVal = false;
9211 if (Lang.isString(p_sPosition)) {
9213 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9222 var Event = YAHOO.util.Event,
9223 MenuBar = YAHOO.widget.MenuBar,
9228 validator: checkPosition,
9229 supercedes: [_VISIBLE]
9232 SUBMENU_ALIGNMENT_CONFIG = {
9233 key: "submenualignment",
9237 AUTO_SUBMENU_DISPLAY_CONFIG = {
9238 key: _AUTO_SUBMENU_DISPLAY,
9240 validator: Lang.isBoolean,
9244 SUBMENU_TOGGLE_REGION_CONFIG = {
9245 key: _SUBMENU_TOGGLE_REGION,
9247 validator: Lang.isBoolean
9252 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9256 * @description The MenuBar class's initialization method. This method is
9257 * automatically called by the constructor, and sets up all DOM references for
9258 * pre-existing markup, and creates required markup if it is not already present.
9259 * @param {String} p_oElement String specifying the id attribute of the
9260 * <code><div></code> element of the menu bar.
9261 * @param {String} p_oElement String specifying the id attribute of the
9262 * <code><select></code> element to be used as the data source for the
9264 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9265 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9266 * the <code><div></code> element of the menu bar.
9267 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9268 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9269 * specifying the <code><select></code> element to be used as the data
9270 * source for the menu bar.
9271 * @param {Object} p_oConfig Optional. Object literal specifying the
9272 * configuration for the menu bar. See configuration class documentation for
9275 init: function(p_oElement, p_oConfig) {
9277 if(!this.ITEM_TYPE) {
9279 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9284 // Call the init of the superclass (YAHOO.widget.Menu)
9286 MenuBar.superclass.init.call(this, p_oElement);
9289 this.beforeInitEvent.fire(MenuBar);
9294 this.cfg.applyConfig(p_oConfig, true);
9298 this.initEvent.fire(MenuBar);
9308 * @property CSS_CLASS_NAME
9309 * @description String representing the CSS class(es) to be applied to the menu
9310 * bar's <code><div></code> element.
9311 * @default "yuimenubar"
9315 CSS_CLASS_NAME: "yuimenubar",
9319 * @property SUBMENU_TOGGLE_REGION_WIDTH
9320 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9321 * display of the MenuBarItem's submenu.
9326 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9329 // Protected event handlers
9333 * @method _onKeyDown
9334 * @description "keydown" Custom Event handler for the menu bar.
9336 * @param {String} p_sType String representing the name of the event that
9338 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9339 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9340 * that fired the event.
9342 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9344 var oEvent = p_aArgs[0],
9351 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9353 oItemCfg = oItem.cfg;
9355 switch(oEvent.keyCode) {
9357 case 37: // Left arrow
9358 case 39: // Right arrow
9360 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9362 oItemCfg.setProperty(_SELECTED, true);
9367 oNextItem = (oEvent.keyCode == 37) ?
9368 oItem.getPreviousEnabledSibling() :
9369 oItem.getNextEnabledSibling();
9373 this.clearActiveItem();
9375 oNextItem.cfg.setProperty(_SELECTED, true);
9377 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9382 oSubmenu.setInitialFocus();
9393 Event.preventDefault(oEvent);
9397 case 40: // Down arrow
9399 if(this.activeItem != oItem) {
9401 this.clearActiveItem();
9403 oItemCfg.setProperty(_SELECTED, true);
9408 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9412 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9414 oSubmenu.setInitialSelection();
9415 oSubmenu.setInitialFocus();
9421 oSubmenu.setInitialFocus();
9427 Event.preventDefault(oEvent);
9436 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9438 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9440 if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9443 this.activeItem.focus();
9448 this.activeItem.cfg.setProperty(_SELECTED, false);
9449 this.activeItem.blur();
9453 Event.preventDefault(oEvent);
9462 * @description "click" event handler for the menu bar.
9464 * @param {String} p_sType String representing the name of the event that
9466 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9467 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9468 * that fired the event.
9470 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9472 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9474 var oItem = p_aArgs[1],
9486 var toggleSubmenuDisplay = function () {
9488 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9502 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9504 oEvent = p_aArgs[0];
9505 oTarget = Event.getTarget(oEvent);
9506 oActiveItem = this.activeItem;
9510 // Hide any other submenus that might be visible
9512 if(oActiveItem && oActiveItem != oItem) {
9514 this.clearActiveItem();
9519 oItem.cfg.setProperty(_SELECTED, true);
9522 // Show the submenu for the item
9524 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9529 oItemEl = oItem.element;
9530 nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9531 nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9533 if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9535 if (Event.getPageX(oEvent) > nToggleRegion) {
9537 toggleSubmenuDisplay();
9539 Event.preventDefault(oEvent);
9542 Return false so that other click event handlers are not called when the
9543 user clicks inside the toggle region.
9552 toggleSubmenuDisplay();
9570 * @method configSubmenuToggle
9571 * @description Event handler for when the "submenutoggleregion" configuration property of
9572 * a MenuBar changes.
9573 * @param {String} p_sType The name of the event that was fired.
9574 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9576 configSubmenuToggle: function (p_sType, p_aArgs) {
9578 var bSubmenuToggle = p_aArgs[0];
9580 if (bSubmenuToggle) {
9582 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9591 * @description Returns a string representing the menu bar.
9594 toString: function() {
9596 var sReturnVal = _MENUBAR,
9601 sReturnVal += (_SPACE + sId);
9611 * @description Initializes the class's configurable properties which can be
9612 * changed using the menu bar's Config object ("cfg").
9613 * @method initDefaultConfig
9615 initDefaultConfig: function() {
9617 MenuBar.superclass.initDefaultConfig.call(this);
9619 var oConfig = this.cfg;
9621 // Add configuration properties
9625 Set the default value for the "position" configuration property
9626 to "static" by re-adding the property.
9632 * @description String indicating how a menu bar should be positioned on the
9633 * screen. Possible values are "static" and "dynamic." Static menu bars
9634 * are visible by default and reside in the normal flow of the document
9635 * (CSS position: static). Dynamic menu bars are hidden by default, reside
9636 * out of the normal flow of the document (CSS position: absolute), and can
9637 * overlay other elements on the screen.
9641 oConfig.addProperty(
9642 POSITION_CONFIG.key,
9644 handler: this.configPosition,
9645 value: POSITION_CONFIG.value,
9646 validator: POSITION_CONFIG.validator,
9647 supercedes: POSITION_CONFIG.supercedes
9653 Set the default value for the "submenualignment" configuration property
9654 to ["tl","bl"] by re-adding the property.
9658 * @config submenualignment
9659 * @description Array defining how submenus should be aligned to their
9660 * parent menu bar item. The format is: [itemCorner, submenuCorner].
9661 * @default ["tl","bl"]
9664 oConfig.addProperty(
9665 SUBMENU_ALIGNMENT_CONFIG.key,
9667 value: SUBMENU_ALIGNMENT_CONFIG.value,
9668 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9674 Change the default value for the "autosubmenudisplay" configuration
9675 property to "false" by re-adding the property.
9679 * @config autosubmenudisplay
9680 * @description Boolean indicating if submenus are automatically made
9681 * visible when the user mouses over the menu bar's items.
9685 oConfig.addProperty(
9686 AUTO_SUBMENU_DISPLAY_CONFIG.key,
9688 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
9689 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9690 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9696 * @config submenutoggleregion
9697 * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
9698 * display of a submenu. The default width of the region is determined by the value of the
9699 * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
9700 * configuration property will be set to false, and any click event listeners will not be
9701 * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
9702 * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
9703 * standard behavior.
9707 oConfig.addProperty(
9708 SUBMENU_TOGGLE_REGION_CONFIG.key,
9710 value: SUBMENU_TOGGLE_REGION_CONFIG.value,
9711 validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9712 handler: this.configSubmenuToggle
9718 }); // END YAHOO.lang.extend
9725 * Creates an item for a menu bar.
9727 * @param {String} p_oObject String specifying the text of the menu bar item.
9728 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9729 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9730 * <code><li></code> element of the menu bar item.
9731 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9732 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9733 * specifying the <code><optgroup></code> element of the menu bar item.
9734 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9735 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9736 * the <code><option></code> element of the menu bar item.
9737 * @param {Object} p_oConfig Optional. Object literal specifying the
9738 * configuration for the menu bar item. See configuration class documentation
9740 * @class MenuBarItem
9742 * @extends YAHOO.widget.MenuItem
9744 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9746 YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9750 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9756 * @description The MenuBarItem class's initialization method. This method is
9757 * automatically called by the constructor, and sets up all DOM references for
9758 * pre-existing markup, and creates required markup if it is not already present.
9759 * @param {String} p_oObject String specifying the text of the menu bar item.
9760 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9761 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9762 * <code><li></code> element of the menu bar item.
9763 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9764 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9765 * specifying the <code><optgroup></code> element of the menu bar item.
9766 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9767 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9768 * the <code><option></code> element of the menu bar item.
9769 * @param {Object} p_oConfig Optional. Object literal specifying the
9770 * configuration for the menu bar item. See configuration class documentation
9773 init: function(p_oObject, p_oConfig) {
9775 if(!this.SUBMENU_TYPE) {
9777 this.SUBMENU_TYPE = YAHOO.widget.Menu;
9783 Call the init of the superclass (YAHOO.widget.MenuItem)
9784 Note: We don't pass the user config in here yet
9785 because we only want it executed once, at the lowest
9789 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
9792 var oConfig = this.cfg;
9796 oConfig.applyConfig(p_oConfig, true);
9800 oConfig.fireQueue();
9810 * @property CSS_CLASS_NAME
9811 * @description String representing the CSS class(es) to be applied to the
9812 * <code><li></code> element of the menu bar item.
9813 * @default "yuimenubaritem"
9817 CSS_CLASS_NAME: "yuimenubaritem",
9821 * @property CSS_LABEL_CLASS_NAME
9822 * @description String representing the CSS class(es) to be applied to the
9823 * menu bar item's <code><a></code> element.
9824 * @default "yuimenubaritemlabel"
9828 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9837 * @description Returns a string representing the menu bar item.
9840 toString: function() {
9842 var sReturnVal = "MenuBarItem";
9844 if(this.cfg && this.cfg.getProperty("text")) {
9846 sReturnVal += (": " + this.cfg.getProperty("text"));
9854 }); // END YAHOO.lang.extend
9855 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.7.0", build: "1799"});