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
31 var UA = YAHOO.env.ua,
33 Event = YAHOO.util.Event,
41 _DISABLED = "disabled",
42 _MOUSEOVER = "mouseover",
43 _MOUSEOUT = "mouseout",
44 _MOUSEDOWN = "mousedown",
49 _KEYPRESS = "keypress",
50 _CLICK_TO_HIDE = "clicktohide",
51 _POSITION = "position",
53 _SHOW_DELAY = "showdelay",
54 _SELECTED = "selected",
57 _MENUMANAGER = "MenuManager";
61 * Singleton that manages a collection of all menus and menu items. Listens
62 * for DOM events at the document level and dispatches the events to the
63 * corresponding menu or menu item.
65 * @namespace YAHOO.widget
69 YAHOO.widget.MenuManager = function () {
71 // Private member variables
74 // Flag indicating if the DOM event handlers have been attached
76 var m_bInitializedEventHandlers = false,
79 // Collection of menus
84 // Collection of visible menus
89 // Collection of menu items
94 // Map of DOM event types to their equivalent CustomEvent types
97 "click": "clickEvent",
98 "mousedown": "mouseDownEvent",
99 "mouseup": "mouseUpEvent",
100 "mouseover": "mouseOverEvent",
101 "mouseout": "mouseOutEvent",
102 "keydown": "keyDownEvent",
103 "keyup": "keyUpEvent",
104 "keypress": "keyPressEvent",
105 "focus": "focusEvent",
106 "focusin": "focusEvent",
108 "focusout": "blurEvent"
112 m_oFocusedMenuItem = null;
120 * @method getMenuRootElement
121 * @description Finds the root DIV node of a menu or the root LI node of
124 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
125 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
126 * specifying an HTML element.
128 function getMenuRootElement(p_oElement) {
133 if (p_oElement && p_oElement.tagName) {
135 switch (p_oElement.tagName.toUpperCase()) {
139 oParentNode = p_oElement.parentNode;
141 // Check if the DIV is the inner "body" node of a menu
144 Dom.hasClass(p_oElement, _HD) ||
145 Dom.hasClass(p_oElement, _BD) ||
146 Dom.hasClass(p_oElement, _FT)
149 oParentNode.tagName &&
150 oParentNode.tagName.toUpperCase() == _DIV) {
152 returnVal = oParentNode;
157 returnVal = p_oElement;
165 returnVal = p_oElement;
171 oParentNode = p_oElement.parentNode;
175 returnVal = getMenuRootElement(oParentNode);
191 // Private event handlers
196 * @description Generic, global event handler for all of a menu's
197 * DOM-based events. This listens for events against the document
198 * object. If the target of a given event is a member of a menu or
199 * menu item's DOM, the instance's corresponding Custom Event is fired.
201 * @param {Event} p_oEvent Object representing the DOM event object
202 * passed back by the event utility (YAHOO.util.Event).
204 function onDOMEvent(p_oEvent) {
206 // Get the target node of the DOM event
208 var oTarget = Event.getTarget(p_oEvent),
210 // See if the target of the event was a menu, or a menu item
212 oElement = getMenuRootElement(oTarget),
214 sEventType = p_oEvent.type,
224 sTagName = oElement.tagName.toUpperCase();
226 if (sTagName == _LI) {
230 if (sId && m_oItems[sId]) {
232 oMenuItem = m_oItems[sId];
233 oMenu = oMenuItem.parent;
238 else if (sTagName == _DIV) {
242 oMenu = m_oMenus[oElement.id];
253 sCustomEventType = m_oEventTypes[sEventType];
256 There is an inconsistency between Firefox for Mac OS X and
257 Firefox Windows & Linux regarding the triggering of the
258 display of the browser's context menu and the subsequent
259 firing of the "click" event. In Firefox for Windows & Linux,
260 when the user triggers the display of the browser's context
261 menu the "click" event also fires for the document object,
262 even though the "click" event did not fire for the element
263 that was the original target of the "contextmenu" event.
264 This is unique to Firefox on Windows & Linux. For all
265 other A-Grade browsers, including Firefox for Mac OS X, the
266 "click" event doesn't fire for the document object.
268 This bug in Firefox for Windows affects Menu, as Menu
269 instances listen for events at the document level and
270 dispatches Custom Events of the same name. Therefore users
271 of Menu will get an unwanted firing of the "click"
272 custom event. The following line fixes this bug.
277 if (sEventType == "click" &&
278 (UA.gecko && oMenu.platform != "mac") &&
279 p_oEvent.button > 0) {
285 // Fire the Custom Event that corresponds the current DOM event
287 if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
288 oMenuItem[sCustomEventType].fire(p_oEvent);
292 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
296 else if (sEventType == _MOUSEDOWN) {
299 If the target of the event wasn't a menu, hide all
300 dynamically positioned menus
303 for (var i in m_oVisibleMenus) {
305 if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
307 oMenu = m_oVisibleMenus[i];
309 if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) &&
310 !(oMenu instanceof YAHOO.widget.MenuBar) &&
311 oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
315 // In IE when the user mouses down on a focusable
316 // element that element will be focused and become
317 // the "activeElement".
318 // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
319 // However, there is a bug in IE where if there is
320 // a positioned element with a focused descendant
321 // that is hidden in response to the mousedown
322 // event, the target of the mousedown event will
323 // appear to have focus, but will not be set as
324 // the activeElement. This will result in the
325 // element not firing key events, even though it
326 // appears to have focus. The following call to
327 // "setActive" fixes this bug.
329 if (UA.ie && oTarget.focus) {
336 if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
338 oMenu._cancelShowDelay();
343 if (oMenu.activeItem) {
345 oMenu.activeItem.blur();
346 oMenu.activeItem.cfg.setProperty(_SELECTED, false);
348 oMenu.activeItem = null;
364 * @method onMenuDestroy
365 * @description "destroy" event handler for a menu.
367 * @param {String} p_sType String representing the name of the event
369 * @param {Array} p_aArgs Array of arguments sent when the event
371 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
373 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
375 if (m_oMenus[p_oMenu.id]) {
377 this.removeMenu(p_oMenu);
385 * @method onMenuFocus
386 * @description "focus" event handler for a MenuItem 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
393 function onMenuFocus(p_sType, p_aArgs) {
395 var oItem = p_aArgs[1];
399 m_oFocusedMenuItem = oItem;
408 * @description "blur" event handler for a MenuItem instance.
410 * @param {String} p_sType String representing the name of the event
412 * @param {Array} p_aArgs Array of arguments sent when the event
415 function onMenuBlur(p_sType, p_aArgs) {
417 m_oFocusedMenuItem = null;
423 * @method onMenuVisibleConfigChange
424 * @description Event handler for when the "visible" configuration
425 * property of a Menu instance changes.
427 * @param {String} p_sType String representing the name of the event
429 * @param {Array} p_aArgs Array of arguments sent when the event
432 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
434 var bVisible = p_aArgs[0],
439 m_oVisibleMenus[sId] = this;
441 YAHOO.log(this + " added to the collection of visible menus.",
442 "info", _MENUMANAGER);
445 else if (m_oVisibleMenus[sId]) {
447 delete m_oVisibleMenus[sId];
449 YAHOO.log(this + " removed from the collection of visible menus.",
450 "info", _MENUMANAGER);
458 * @method onItemDestroy
459 * @description "destroy" event handler for a MenuItem instance.
461 * @param {String} p_sType String representing the name of the event
463 * @param {Array} p_aArgs Array of arguments sent when the event
466 function onItemDestroy(p_sType, p_aArgs) {
475 * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
477 * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
479 function removeItem(p_oMenuItem) {
481 var sId = p_oMenuItem.id;
483 if (sId && m_oItems[sId]) {
485 if (m_oFocusedMenuItem == p_oMenuItem) {
487 m_oFocusedMenuItem = null;
491 delete m_oItems[sId];
493 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
495 YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
503 * @method onItemAdded
504 * @description "itemadded" event handler for a Menu instance.
506 * @param {String} p_sType String representing the name of the event
508 * @param {Array} p_aArgs Array of arguments sent when the event
511 function onItemAdded(p_sType, p_aArgs) {
513 var oItem = p_aArgs[0],
516 if (oItem instanceof YAHOO.widget.MenuItem) {
520 if (!m_oItems[sId]) {
522 m_oItems[sId] = oItem;
524 oItem.destroyEvent.subscribe(onItemDestroy);
526 YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
537 // Privileged methods
542 * @description Adds a menu to the collection of known menus.
543 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
544 * instance to be added.
546 addMenu: function (p_oMenu) {
550 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
551 !m_oMenus[p_oMenu.id]) {
553 m_oMenus[p_oMenu.id] = p_oMenu;
556 if (!m_bInitializedEventHandlers) {
560 Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
561 Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
562 Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
563 Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
564 Event.on(oDoc, _CLICK, onDOMEvent, this, true);
565 Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
566 Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
567 Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
569 Event.onFocus(oDoc, onDOMEvent, this, true);
570 Event.onBlur(oDoc, onDOMEvent, this, true);
572 m_bInitializedEventHandlers = true;
574 YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
578 p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
579 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
580 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
581 p_oMenu.focusEvent.subscribe(onMenuFocus);
582 p_oMenu.blurEvent.subscribe(onMenuBlur);
584 YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
593 * @description Removes a menu from the collection of known menus.
594 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
595 * instance to be removed.
597 removeMenu: function (p_oMenu) {
607 if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
609 // Unregister each menu item
611 aItems = p_oMenu.getItems();
613 if (aItems && aItems.length > 0) {
615 i = aItems.length - 1;
619 removeItem(aItems[i]);
627 // Unregister the menu
629 delete m_oMenus[sId];
631 YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
635 Unregister the menu from the collection of
639 if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
641 delete m_oVisibleMenus[sId];
643 YAHOO.log(p_oMenu + " unregistered from the" +
644 " collection of visible menus.", "info", _MENUMANAGER);
649 // Unsubscribe event listeners
653 p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE,
654 onMenuVisibleConfigChange);
658 p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
661 p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
662 p_oMenu.focusEvent.unsubscribe(onMenuFocus);
663 p_oMenu.blurEvent.unsubscribe(onMenuBlur);
673 * @method hideVisible
674 * @description Hides all visible, dynamically positioned menus
675 * (excluding instances of YAHOO.widget.MenuBar).
677 hideVisible: function () {
681 for (var i in m_oVisibleMenus) {
683 if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
685 oMenu = m_oVisibleMenus[i];
687 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
688 oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
703 * @description Returns a collection of all visible menus registered
704 * with the menu manger.
707 getVisible: function () {
709 return m_oVisibleMenus;
716 * @description Returns a collection of all menus registered with the
720 getMenus: function () {
729 * @description Returns a menu with the specified id.
730 * @param {String} p_sId String specifying the id of the
731 * <code><div></code> element representing the menu to
733 * @return {YAHOO.widget.Menu}
735 getMenu: function (p_sId) {
739 if (p_sId in m_oMenus) {
741 returnVal = m_oMenus[p_sId];
751 * @method getMenuItem
752 * @description Returns a menu item with the specified id.
753 * @param {String} p_sId String specifying the id of the
754 * <code><li></code> element representing the menu item to
756 * @return {YAHOO.widget.MenuItem}
758 getMenuItem: function (p_sId) {
762 if (p_sId in m_oItems) {
764 returnVal = m_oItems[p_sId];
774 * @method getMenuItemGroup
775 * @description Returns an array of menu item instances whose
776 * corresponding <code><li></code> elements are child
777 * nodes of the <code><ul></code> element with the
779 * @param {String} p_sId String specifying the id of the
780 * <code><ul></code> element representing the group of
781 * menu items to be retrieved.
784 getMenuItemGroup: function (p_sId) {
786 var oUL = Dom.get(p_sId),
794 if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
796 oNode = oUL.firstChild;
808 oItem = this.getMenuItem(sId);
812 aItems[aItems.length] = oItem;
819 while ((oNode = oNode.nextSibling));
822 if (aItems.length > 0) {
838 * @method getFocusedMenuItem
839 * @description Returns a reference to the menu item that currently
841 * @return {YAHOO.widget.MenuItem}
843 getFocusedMenuItem: function () {
845 return m_oFocusedMenuItem;
851 * @method getFocusedMenu
852 * @description Returns a reference to the menu that currently
854 * @return {YAHOO.widget.Menu}
856 getFocusedMenu: function () {
860 if (m_oFocusedMenuItem) {
862 returnVal = m_oFocusedMenuItem.parent.getRoot();
873 * @description Returns a string representing the menu manager.
876 toString: function () {
892 var Lang = YAHOO.lang,
897 _DIV_UPPERCASE = "DIV",
898 _DIV_LOWERCASE = "div",
903 _UL_UPPERCASE = "UL",
904 _UL_LOWERCASE = "ul",
905 _FIRST_OF_TYPE = "first-of-type",
907 _OPTGROUP = "OPTGROUP",
909 _DISABLED = "disabled",
911 _SELECTED = "selected",
912 _GROUP_INDEX = "groupindex",
914 _SUBMENU = "submenu",
915 _VISIBLE = "visible",
916 _HIDE_DELAY = "hidedelay",
917 _POSITION = "position",
918 _DYNAMIC = "dynamic",
920 _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
924 _MAX_HEIGHT = "maxheight",
925 _TOP_SCROLLBAR = "topscrollbar",
926 _BOTTOM_SCROLLBAR = "bottomscrollbar",
928 _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
929 _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
930 _MOUSEMOVE = "mousemove",
931 _SHOW_DELAY = "showdelay",
932 _SUBMENU_HIDE_DELAY = "submenuhidedelay",
934 _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
935 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
936 _SUBMENU_ALIGNMENT = "submenualignment",
937 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
938 _CLICK_TO_HIDE = "clicktohide",
939 _CONTAINER = "container",
940 _SCROLL_INCREMENT = "scrollincrement",
941 _MIN_SCROLL_HEIGHT = "minscrollheight",
942 _CLASSNAME = "classname",
944 _KEEP_OPEN = "keepopen",
946 _HAS_TITLE = "hastitle",
947 _CONTEXT = "context",
949 _MOUSEDOWN = "mousedown",
950 _KEYDOWN = "keydown",
955 _MONITOR_RESIZE = "monitorresize",
956 _DISPLAY = "display",
958 _VISIBILITY = "visibility",
959 _ABSOLUTE = "absolute",
961 _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
962 _NON_BREAKING_SPACE = " ",
964 _MOUSEOVER = "mouseover",
965 _MOUSEOUT = "mouseout",
966 _ITEM_ADDED = "itemAdded",
967 _ITEM_REMOVED = "itemRemoved",
969 _YUI_MENU_SHADOW = "yui-menu-shadow",
970 _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
971 _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
975 * The Menu class creates a container that holds a vertical list representing
976 * a set of options or commands. Menu is the base class for all
978 * @param {String} p_oElement String specifying the id attribute of the
979 * <code><div></code> element of the menu.
980 * @param {String} p_oElement String specifying the id attribute of the
981 * <code><select></code> element to be used as the data source
983 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
984 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
985 * specifying the <code><div></code> element of the menu.
986 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
987 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
988 * Object specifying the <code><select></code> element to be used as
989 * the data source for the menu.
990 * @param {Object} p_oConfig Optional. Object literal specifying the
991 * configuration for the menu. See configuration class documentation for
993 * @namespace YAHOO.widget
996 * @extends YAHOO.widget.Overlay
998 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
1002 this.parent = p_oConfig.parent;
1003 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
1004 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
1009 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1016 * @method checkPosition
1017 * @description Checks to make sure that the value of the "position" property
1018 * is one of the supported strings. Returns true if the position is supported.
1020 * @param {Object} p_sPosition String specifying the position of the menu.
1023 function checkPosition(p_sPosition) {
1025 var returnVal = false;
1027 if (Lang.isString(p_sPosition)) {
1029 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1038 var Dom = YAHOO.util.Dom,
1039 Event = YAHOO.util.Event,
1040 Module = YAHOO.widget.Module,
1041 Overlay = YAHOO.widget.Overlay,
1042 Menu = YAHOO.widget.Menu,
1043 MenuManager = YAHOO.widget.MenuManager,
1044 CustomEvent = YAHOO.util.CustomEvent,
1049 bFocusListenerInitialized = false,
1055 ["mouseOverEvent", _MOUSEOVER],
1056 ["mouseOutEvent", _MOUSEOUT],
1057 ["mouseDownEvent", _MOUSEDOWN],
1058 ["mouseUpEvent", "mouseup"],
1059 ["clickEvent", "click"],
1060 ["keyPressEvent", "keypress"],
1061 ["keyDownEvent", _KEYDOWN],
1062 ["keyUpEvent", "keyup"],
1063 ["focusEvent", "focus"],
1064 ["blurEvent", "blur"],
1065 ["itemAddedEvent", _ITEM_ADDED],
1066 ["itemRemovedEvent", _ITEM_REMOVED]
1073 validator: Lang.isBoolean
1076 CONSTRAIN_TO_VIEWPORT_CONFIG = {
1077 key: _CONSTRAIN_TO_VIEWPORT,
1079 validator: Lang.isBoolean,
1080 supercedes: [_IFRAME,"x",_Y,_XY]
1083 PREVENT_CONTEXT_OVERLAP_CONFIG = {
1084 key: _PREVENT_CONTEXT_OVERLAP,
1086 validator: Lang.isBoolean,
1087 supercedes: [_CONSTRAIN_TO_VIEWPORT]
1093 validator: checkPosition,
1094 supercedes: [_VISIBLE, _IFRAME]
1097 SUBMENU_ALIGNMENT_CONFIG = {
1098 key: _SUBMENU_ALIGNMENT,
1102 AUTO_SUBMENU_DISPLAY_CONFIG = {
1103 key: _AUTO_SUBMENU_DISPLAY,
1105 validator: Lang.isBoolean,
1109 SHOW_DELAY_CONFIG = {
1112 validator: Lang.isNumber,
1116 HIDE_DELAY_CONFIG = {
1119 validator: Lang.isNumber,
1123 SUBMENU_HIDE_DELAY_CONFIG = {
1124 key: _SUBMENU_HIDE_DELAY,
1126 validator: Lang.isNumber,
1130 CLICK_TO_HIDE_CONFIG = {
1131 key: _CLICK_TO_HIDE,
1133 validator: Lang.isBoolean,
1137 CONTAINER_CONFIG = {
1142 SCROLL_INCREMENT_CONFIG = {
1143 key: _SCROLL_INCREMENT,
1145 validator: Lang.isNumber,
1146 supercedes: [_MAX_HEIGHT],
1150 MIN_SCROLL_HEIGHT_CONFIG = {
1151 key: _MIN_SCROLL_HEIGHT,
1153 validator: Lang.isNumber,
1154 supercedes: [_MAX_HEIGHT],
1158 MAX_HEIGHT_CONFIG = {
1161 validator: Lang.isNumber,
1162 supercedes: [_IFRAME],
1166 CLASS_NAME_CONFIG = {
1169 validator: Lang.isString,
1176 validator: Lang.isBoolean,
1183 validator: Lang.isBoolean,
1184 suppressEvent: true,
1185 supercedes: [_VISIBLE]
1188 KEEP_OPEN_CONFIG = {
1191 validator: Lang.isBoolean
1195 function onDocFocus(event) {
1197 oFocusedElement = Event.getTarget(event);
1203 YAHOO.lang.extend(Menu, Overlay, {
1210 * @property CSS_CLASS_NAME
1211 * @description String representing the CSS class(es) to be applied to the
1212 * menu's <code><div></code> element.
1213 * @default "yuimenu"
1217 CSS_CLASS_NAME: "yuimenu",
1221 * @property ITEM_TYPE
1222 * @description Object representing the type of menu item to instantiate and
1223 * add when parsing the child nodes (either <code><li></code> element,
1224 * <code><optgroup></code> element or <code><option></code>)
1225 * of the menu's source HTML element.
1226 * @default YAHOO.widget.MenuItem
1228 * @type YAHOO.widget.MenuItem
1234 * @property GROUP_TITLE_TAG_NAME
1235 * @description String representing the tagname of the HTML element used to
1236 * title the menu's item groups.
1241 GROUP_TITLE_TAG_NAME: "h6",
1245 * @property OFF_SCREEN_POSITION
1246 * @description Array representing the default x and y position that a menu
1247 * should have when it is positioned outside the viewport by the
1248 * "poistionOffScreen" method.
1253 OFF_SCREEN_POSITION: "-999em",
1256 // Private properties
1260 * @property _useHideDelay
1261 * @description Boolean indicating if the "mouseover" and "mouseout" event
1262 * handlers used for hiding the menu via a call to "YAHOO.lang.later" have
1263 * already been assigned.
1268 _useHideDelay: false,
1272 * @property _bHandledMouseOverEvent
1273 * @description Boolean indicating the current state of the menu's
1274 * "mouseover" event.
1279 _bHandledMouseOverEvent: false,
1283 * @property _bHandledMouseOutEvent
1284 * @description Boolean indicating the current state of the menu's
1290 _bHandledMouseOutEvent: false,
1294 * @property _aGroupTitleElements
1295 * @description Array of HTML element used to title groups of menu items.
1300 _aGroupTitleElements: null,
1304 * @property _aItemGroups
1305 * @description Multi-dimensional Array representing the menu items as they
1306 * are grouped in the menu.
1315 * @property _aListElements
1316 * @description Array of <code><ul></code> elements, each of which is
1317 * the parent node for each item's <code><li></code> element.
1322 _aListElements: null,
1326 * @property _nCurrentMouseX
1327 * @description The current x coordinate of the mouse inside the area of
1337 * @property _bStopMouseEventHandlers
1338 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1344 _bStopMouseEventHandlers: false,
1348 * @property _sClassName
1349 * @description The current value of the "classname" configuration attribute.
1358 // Public properties
1362 * @property lazyLoad
1363 * @description Boolean indicating if the menu's "lazy load" feature is
1364 * enabled. If set to "true," initialization and rendering of the menu's
1365 * items will be deferred until the first time it is made visible. This
1366 * property should be set via the constructor using the configuration
1375 * @property itemData
1376 * @description Array of items to be added to the menu. The array can contain
1377 * strings representing the text for each item to be created, object literals
1378 * representing the menu item configuration properties, or MenuItem instances.
1379 * This property should be set via the constructor using the configuration
1388 * @property activeItem
1389 * @description Object reference to the item in the menu that has is selected.
1391 * @type YAHOO.widget.MenuItem
1398 * @description Object reference to the menu's parent menu or menu item.
1399 * This property can be set via the constructor using the configuration
1402 * @type YAHOO.widget.MenuItem
1408 * @property srcElement
1409 * @description Object reference to the HTML element (either
1410 * <code><select></code> or <code><div></code>) used to
1413 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1414 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1415 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1416 * html#ID-22445964">HTMLDivElement</a>
1426 * @event mouseOverEvent
1427 * @description Fires when the mouse has entered the menu. Passes back
1428 * the DOM Event object as an argument.
1433 * @event mouseOutEvent
1434 * @description Fires when the mouse has left the menu. Passes back the DOM
1435 * Event object as an argument.
1436 * @type YAHOO.util.CustomEvent
1441 * @event mouseDownEvent
1442 * @description Fires when the user mouses down on the menu. Passes back the
1443 * DOM Event object as an argument.
1444 * @type YAHOO.util.CustomEvent
1449 * @event mouseUpEvent
1450 * @description Fires when the user releases a mouse button while the mouse is
1451 * over the menu. Passes back the DOM Event object as an argument.
1452 * @type YAHOO.util.CustomEvent
1458 * @description Fires when the user clicks the on the menu. Passes back the
1459 * DOM Event object as an argument.
1460 * @type YAHOO.util.CustomEvent
1465 * @event keyPressEvent
1466 * @description Fires when the user presses an alphanumeric key when one of the
1467 * menu's items has focus. Passes back the DOM Event object as an argument.
1468 * @type YAHOO.util.CustomEvent
1473 * @event keyDownEvent
1474 * @description Fires when the user presses a key when one of the menu's items
1475 * has focus. Passes back the DOM Event object as an argument.
1476 * @type YAHOO.util.CustomEvent
1482 * @description Fires when the user releases a key when one of the menu's items
1483 * has focus. Passes back the DOM Event object as an argument.
1484 * @type YAHOO.util.CustomEvent
1489 * @event itemAddedEvent
1490 * @description Fires when an item is added to the menu.
1491 * @type YAHOO.util.CustomEvent
1496 * @event itemRemovedEvent
1497 * @description Fires when an item is removed to the menu.
1498 * @type YAHOO.util.CustomEvent
1504 * @description The Menu class's initialization method. This method is
1505 * automatically called by the constructor, and sets up all DOM references
1506 * for pre-existing markup, and creates required markup if it is not
1508 * @param {String} p_oElement String specifying the id attribute of the
1509 * <code><div></code> element of the menu.
1510 * @param {String} p_oElement String specifying the id attribute of the
1511 * <code><select></code> element to be used as the data source
1513 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1514 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1515 * specifying the <code><div></code> element of the menu.
1516 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1517 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1518 * Object specifying the <code><select></code> element to be used as
1519 * the data source for the menu.
1520 * @param {Object} p_oConfig Optional. Object literal specifying the
1521 * configuration for the menu. See configuration class documentation for
1524 init: function (p_oElement, p_oConfig) {
1526 this._aItemGroups = [];
1527 this._aListElements = [];
1528 this._aGroupTitleElements = [];
1530 if (!this.ITEM_TYPE) {
1532 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1539 if (Lang.isString(p_oElement)) {
1541 oElement = Dom.get(p_oElement);
1544 else if (p_oElement.tagName) {
1546 oElement = p_oElement;
1551 if (oElement && oElement.tagName) {
1553 switch(oElement.tagName.toUpperCase()) {
1555 case _DIV_UPPERCASE:
1557 this.srcElement = oElement;
1561 oElement.setAttribute(_ID, Dom.generateId());
1567 Note: we don't pass the user config in here yet
1568 because we only want it executed once, at the lowest
1572 Menu.superclass.init.call(this, oElement);
1574 this.beforeInitEvent.fire(Menu);
1576 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1582 this.srcElement = oElement;
1586 The source element is not something that we can use
1587 outright, so we need to create a new Overlay
1589 Note: we don't pass the user config in here yet
1590 because we only want it executed once, at the lowest
1594 Menu.superclass.init.call(this, Dom.generateId());
1596 this.beforeInitEvent.fire(Menu);
1598 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1608 Note: we don't pass the user config in here yet
1609 because we only want it executed once, at the lowest
1613 Menu.superclass.init.call(this, p_oElement);
1615 this.beforeInitEvent.fire(Menu);
1617 YAHOO.log("No source element found. Created element with id: " + this.id, "info", this.toString());
1624 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1627 // Subscribe to Custom Events
1629 this.initEvent.subscribe(this._onInit);
1630 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1631 this.renderEvent.subscribe(this._onRender);
1632 this.beforeShowEvent.subscribe(this._onBeforeShow);
1633 this.hideEvent.subscribe(this._onHide);
1634 this.showEvent.subscribe(this._onShow);
1635 this.beforeHideEvent.subscribe(this._onBeforeHide);
1636 this.mouseOverEvent.subscribe(this._onMouseOver);
1637 this.mouseOutEvent.subscribe(this._onMouseOut);
1638 this.clickEvent.subscribe(this._onClick);
1639 this.keyDownEvent.subscribe(this._onKeyDown);
1640 this.keyPressEvent.subscribe(this._onKeyPress);
1641 this.blurEvent.subscribe(this._onBlur);
1644 if (!bFocusListenerInitialized) {
1645 Event.onFocus(document, onDocFocus);
1646 bFocusListenerInitialized = true;
1650 // Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY"
1651 // methods return values that don't take scrollTop into consideration
1653 if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) {
1655 this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1662 this.cfg.applyConfig(p_oConfig, true);
1667 // Register the Menu instance with the MenuManager
1669 MenuManager.addMenu(this);
1672 this.initEvent.fire(Menu);
1684 * @method _initSubTree
1685 * @description Iterates the childNodes of the source element to find nodes
1686 * used to instantiate menu and menu items.
1689 _initSubTree: function () {
1691 var oSrcElement = this.srcElement,
1703 sSrcElementTagName =
1704 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1707 if (sSrcElementTagName == _DIV_UPPERCASE) {
1709 // Populate the collection of item groups and item group titles
1711 oNode = this.body.firstChild;
1717 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1722 if (oNode && oNode.tagName) {
1724 switch (oNode.tagName.toUpperCase()) {
1726 case sGroupTitleTagName:
1728 this._aGroupTitleElements[nGroup] = oNode;
1734 this._aListElements[nGroup] = oNode;
1735 this._aItemGroups[nGroup] = [];
1745 while ((oNode = oNode.nextSibling));
1749 Apply the "first-of-type" class to the first UL to mimic
1750 the ":first-of-type" CSS3 psuedo class.
1753 if (this._aListElements[0]) {
1755 Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1766 YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
1769 if (sSrcElementTagName) {
1771 switch (sSrcElementTagName) {
1773 case _DIV_UPPERCASE:
1775 aListElements = this._aListElements;
1776 nListElements = aListElements.length;
1778 if (nListElements > 0) {
1780 YAHOO.log("Found " + nListElements + " item groups to initialize.",
1781 "info", this.toString());
1783 i = nListElements - 1;
1787 oNode = aListElements[i].firstChild;
1791 YAHOO.log("Scanning " +
1792 aListElements[i].childNodes.length +
1793 " child nodes for items to initialize.", "info", this.toString());
1797 if (oNode && oNode.tagName &&
1798 oNode.tagName.toUpperCase() == _LI) {
1800 YAHOO.log("Initializing " +
1801 oNode.tagName + " node.", "info", this.toString());
1803 this.addItem(new this.ITEM_TYPE(oNode,
1804 { parent: this }), i);
1809 while ((oNode = oNode.nextSibling));
1822 YAHOO.log("Scanning " +
1823 oSrcElement.childNodes.length +
1824 " child nodes for items to initialize.", "info", this.toString());
1826 oNode = oSrcElement.firstChild;
1830 if (oNode && oNode.tagName) {
1832 switch (oNode.tagName.toUpperCase()) {
1837 YAHOO.log("Initializing " +
1838 oNode.tagName + " node.", "info", this.toString());
1854 while ((oNode = oNode.nextSibling));
1868 * @method _getFirstEnabledItem
1869 * @description Returns the first enabled item in the menu.
1870 * @return {YAHOO.widget.MenuItem}
1873 _getFirstEnabledItem: function () {
1875 var aItems = this.getItems(),
1876 nItems = aItems.length,
1881 for(var i=0; i<nItems; i++) {
1885 if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1900 * @method _addItemToGroup
1901 * @description Adds a menu item to a group.
1903 * @param {Number} p_nGroupIndex Number indicating the group to which the
1905 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1906 * instance to be added to the menu.
1907 * @param {String} p_oItem String specifying the text of the item to be added
1909 * @param {Object} p_oItem Object literal containing a set of menu item
1910 * configuration properties.
1911 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1912 * which the menu item should be added.
1913 * @return {YAHOO.widget.MenuItem}
1915 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1927 function getNextItemSibling(p_aArray, p_nStartIndex) {
1929 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1934 if (p_oItem instanceof this.ITEM_TYPE) {
1937 oItem.parent = this;
1940 else if (Lang.isString(p_oItem)) {
1942 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1945 else if (Lang.isObject(p_oItem)) {
1947 p_oItem.parent = this;
1949 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1956 if (oItem.cfg.getProperty(_SELECTED)) {
1958 this.activeItem = oItem;
1963 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1964 aGroup = this._getItemGroup(nGroupIndex);
1970 aGroup = this._createItemGroup(nGroupIndex);
1975 if (Lang.isNumber(p_nItemIndex)) {
1977 bAppend = (p_nItemIndex >= aGroup.length);
1980 if (aGroup[p_nItemIndex]) {
1982 aGroup.splice(p_nItemIndex, 0, oItem);
1987 aGroup[p_nItemIndex] = oItem;
1992 oGroupItem = aGroup[p_nItemIndex];
1996 if (bAppend && (!oGroupItem.element.parentNode ||
1997 oGroupItem.element.parentNode.nodeType == 11)) {
1999 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2004 oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
2006 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
2007 oGroupItem.element.parentNode.nodeType == 11)) {
2009 this._aListElements[nGroupIndex].insertBefore(
2010 oGroupItem.element, oNextItemSibling.element);
2017 oGroupItem.parent = this;
2019 this._subscribeToItemEvents(oGroupItem);
2021 this._configureSubmenu(oGroupItem);
2023 this._updateItemProperties(nGroupIndex);
2025 YAHOO.log("Item inserted." +
2026 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
2027 " Index: " + oGroupItem.index + ", " +
2028 " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2030 this.itemAddedEvent.fire(oGroupItem);
2031 this.changeContentEvent.fire();
2033 returnVal = oGroupItem;
2040 nItemIndex = aGroup.length;
2042 aGroup[nItemIndex] = oItem;
2044 oGroupItem = aGroup[nItemIndex];
2049 if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2051 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2055 oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2056 oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2058 oGroupItem.parent = this;
2060 oGroupItem.index = nItemIndex;
2061 oGroupItem.groupIndex = nGroupIndex;
2063 this._subscribeToItemEvents(oGroupItem);
2065 this._configureSubmenu(oGroupItem);
2067 if (nItemIndex === 0) {
2069 Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2073 YAHOO.log("Item added." +
2074 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
2075 " Index: " + oGroupItem.index + ", " +
2076 " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2079 this.itemAddedEvent.fire(oGroupItem);
2080 this.changeContentEvent.fire();
2082 returnVal = oGroupItem;
2096 * @method _removeItemFromGroupByIndex
2097 * @description Removes a menu item from a group by index. Returns the menu
2098 * item that was removed.
2100 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
2102 * @param {Number} p_nItemIndex Number indicating the index of the menu item
2104 * @return {YAHOO.widget.MenuItem}
2106 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2108 var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2109 aGroup = this._getItemGroup(nGroupIndex),
2116 aArray = aGroup.splice(p_nItemIndex, 1);
2121 // Update the index and className properties of each member
2123 this._updateItemProperties(nGroupIndex);
2125 if (aGroup.length === 0) {
2129 oUL = this._aListElements[nGroupIndex];
2131 if (this.body && oUL) {
2133 this.body.removeChild(oUL);
2137 // Remove the group from the array of items
2139 this._aItemGroups.splice(nGroupIndex, 1);
2142 // Remove the UL from the array of ULs
2144 this._aListElements.splice(nGroupIndex, 1);
2148 Assign the "first-of-type" class to the new first UL
2152 oUL = this._aListElements[0];
2156 Dom.addClass(oUL, _FIRST_OF_TYPE);
2163 this.itemRemovedEvent.fire(oItem);
2164 this.changeContentEvent.fire();
2170 // Return a reference to the item that was removed
2178 * @method _removeItemFromGroupByValue
2179 * @description Removes a menu item from a group by reference. Returns the
2180 * menu item that was removed.
2182 * @param {Number} p_nGroupIndex Number indicating the group to which the
2183 * menu item belongs.
2184 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2185 * instance to be removed.
2186 * @return {YAHOO.widget.MenuItem}
2188 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2190 var aGroup = this._getItemGroup(p_nGroupIndex),
2198 nItems = aGroup.length;
2207 if (aGroup[i] == p_oItem) {
2217 if (nItemIndex > -1) {
2219 returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2233 * @method _updateItemProperties
2234 * @description Updates the "index," "groupindex," and "className" properties
2235 * of the menu items in the specified group.
2237 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2239 _updateItemProperties: function (p_nGroupIndex) {
2241 var aGroup = this._getItemGroup(p_nGroupIndex),
2242 nItems = aGroup.length,
2252 // Update the index and className properties of each member
2260 oLI = oItem.element;
2263 oItem.groupIndex = p_nGroupIndex;
2265 oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2266 oLI.setAttribute(_INDEX, i);
2268 Dom.removeClass(oLI, _FIRST_OF_TYPE);
2278 Dom.addClass(oLI, _FIRST_OF_TYPE);
2288 * @method _createItemGroup
2289 * @description Creates a new menu item group (array) and its associated
2290 * <code><ul></code> element. Returns an aray of menu item groups.
2292 * @param {Number} p_nIndex Number indicating the group to create.
2295 _createItemGroup: function (p_nIndex) {
2300 if (!this._aItemGroups[p_nIndex]) {
2302 this._aItemGroups[p_nIndex] = [];
2304 oUL = document.createElement(_UL_LOWERCASE);
2306 this._aListElements[p_nIndex] = oUL;
2308 returnVal = this._aItemGroups[p_nIndex];
2318 * @method _getItemGroup
2319 * @description Returns the menu item group at the specified index.
2321 * @param {Number} p_nIndex Number indicating the index of the menu item group
2325 _getItemGroup: function (p_nIndex) {
2327 var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2328 aGroups = this._aItemGroups,
2331 if (nIndex in aGroups) {
2333 returnVal = aGroups[nIndex];
2343 * @method _configureSubmenu
2344 * @description Subscribes the menu item's submenu to its parent menu's events.
2346 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2347 * instance with the submenu to be configured.
2349 _configureSubmenu: function (p_oItem) {
2351 var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2356 Listen for configuration changes to the parent menu
2357 so they they can be applied to the submenu.
2360 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2362 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2372 * @method _subscribeToItemEvents
2373 * @description Subscribes a menu to a menu item's event.
2375 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2376 * instance whose events should be subscribed to.
2378 _subscribeToItemEvents: function (p_oItem) {
2380 p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2381 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2387 * @method _onVisibleChange
2388 * @description Change event handler for the menu's "visible" configuration
2391 * @param {String} p_sType String representing the name of the event that
2393 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2395 _onVisibleChange: function (p_sType, p_aArgs) {
2397 var bVisible = p_aArgs[0];
2401 Dom.addClass(this.element, _VISIBLE);
2406 Dom.removeClass(this.element, _VISIBLE);
2414 * @method _cancelHideDelay
2415 * @description Cancels the call to "hideMenu."
2418 _cancelHideDelay: function () {
2420 var oTimer = this.getRoot()._hideDelayTimer;
2432 * @method _execHideDelay
2433 * @description Hides the menu after the number of milliseconds specified by
2434 * the "hidedelay" configuration property.
2437 _execHideDelay: function () {
2439 this._cancelHideDelay();
2441 var oRoot = this.getRoot();
2443 oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2445 if (oRoot.activeItem) {
2447 if (oRoot.hasFocus()) {
2449 oRoot.activeItem.focus();
2453 oRoot.clearActiveItem();
2457 if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) &&
2458 this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2470 * @method _cancelShowDelay
2471 * @description Cancels the call to the "showMenu."
2474 _cancelShowDelay: function () {
2476 var oTimer = this.getRoot()._showDelayTimer;
2488 * @method _execSubmenuHideDelay
2489 * @description Hides a submenu after the number of milliseconds specified by
2490 * the "submenuhidedelay" configuration property have ellapsed.
2492 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2494 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2495 * the specified submenu's parent menu item.
2496 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2497 * before the submenu is hidden.
2499 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2501 p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2503 if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2505 p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2524 // Protected methods
2528 * @method _disableScrollHeader
2529 * @description Disables the header used for scrolling the body of the menu.
2532 _disableScrollHeader: function () {
2534 if (!this._bHeaderDisabled) {
2536 Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2537 this._bHeaderDisabled = true;
2545 * @method _disableScrollFooter
2546 * @description Disables the footer used for scrolling the body of the menu.
2549 _disableScrollFooter: function () {
2551 if (!this._bFooterDisabled) {
2553 Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2554 this._bFooterDisabled = true;
2562 * @method _enableScrollHeader
2563 * @description Enables the header used for scrolling the body of the menu.
2566 _enableScrollHeader: function () {
2568 if (this._bHeaderDisabled) {
2570 Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2571 this._bHeaderDisabled = false;
2579 * @method _enableScrollFooter
2580 * @description Enables the footer used for scrolling the body of the menu.
2583 _enableScrollFooter: function () {
2585 if (this._bFooterDisabled) {
2587 Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2588 this._bFooterDisabled = false;
2596 * @method _onMouseOver
2597 * @description "mouseover" event handler for the menu.
2599 * @param {String} p_sType String representing the name of the event that
2601 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2603 _onMouseOver: function (p_sType, p_aArgs) {
2605 var oEvent = p_aArgs[0],
2607 oTarget = Event.getTarget(oEvent),
2608 oRoot = this.getRoot(),
2609 oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2618 var showSubmenu = function () {
2620 if (this.parent.cfg.getProperty(_SELECTED)) {
2629 if (!this._bStopMouseEventHandlers) {
2631 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2632 Dom.isAncestor(this.element, oTarget))) {
2634 // Menu mouseover logic
2636 if (this._useHideDelay) {
2637 this._cancelHideDelay();
2640 this._nCurrentMouseX = 0;
2642 Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2646 If the mouse is moving from the submenu back to its corresponding menu item,
2647 don't hide the submenu or clear the active MenuItem.
2650 if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2652 this.clearActiveItem();
2657 if (this.parent && oSubmenuHideDelayTimer) {
2659 oSubmenuHideDelayTimer.cancel();
2661 this.parent.cfg.setProperty(_SELECTED, true);
2663 oParentMenu = this.parent.parent;
2665 oParentMenu._bHandledMouseOutEvent = true;
2666 oParentMenu._bHandledMouseOverEvent = false;
2671 this._bHandledMouseOverEvent = true;
2672 this._bHandledMouseOutEvent = false;
2677 if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) &&
2678 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2680 // Menu Item mouseover logic
2682 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2683 bShowDelay = (nShowDelay > 0);
2688 this._cancelShowDelay();
2693 oActiveItem = this.activeItem;
2697 oActiveItem.cfg.setProperty(_SELECTED, false);
2702 oItemCfg = oItem.cfg;
2704 // Select and focus the current menu item
2706 oItemCfg.setProperty(_SELECTED, true);
2709 if (this.hasFocus() || oRoot._hasFocus) {
2713 oRoot._hasFocus = false;
2718 if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2720 // Show the submenu this menu item
2722 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2728 oRoot._showDelayTimer =
2729 Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2742 oItem.handledMouseOverEvent = true;
2743 oItem.handledMouseOutEvent = false;
2753 * @method _onMouseOut
2754 * @description "mouseout" event handler for the menu.
2756 * @param {String} p_sType String representing the name of the event that
2758 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2760 _onMouseOut: function (p_sType, p_aArgs) {
2762 var oEvent = p_aArgs[0],
2764 oRelatedTarget = Event.getRelatedTarget(oEvent),
2765 bMovingToSubmenu = false,
2772 if (!this._bStopMouseEventHandlers) {
2774 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2776 oItemCfg = oItem.cfg;
2777 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2780 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2781 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2783 bMovingToSubmenu = true;
2788 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2789 !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2791 // Menu Item mouseout logic
2793 if (!bMovingToSubmenu) {
2795 oItem.cfg.setProperty(_SELECTED, false);
2800 nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2802 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2804 if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 &&
2805 nShowDelay >= nSubmenuHideDelay) {
2807 this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
2822 oItem.handledMouseOutEvent = true;
2823 oItem.handledMouseOverEvent = false;
2830 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2831 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2833 // Menu mouseout logic
2835 if (this._useHideDelay) {
2836 this._execHideDelay();
2839 Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2841 this._nCurrentMouseX = Event.getPageX(oEvent);
2843 this._bHandledMouseOutEvent = true;
2844 this._bHandledMouseOverEvent = false;
2854 * @method _onMouseMove
2855 * @description "click" event handler for the menu.
2857 * @param {Event} p_oEvent Object representing the DOM event object passed
2858 * back by the event utility (YAHOO.util.Event).
2859 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2862 _onMouseMove: function (p_oEvent, p_oMenu) {
2864 if (!this._bStopMouseEventHandlers) {
2866 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2875 * @description "click" event handler for the menu.
2877 * @param {String} p_sType String representing the name of the event that
2879 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2881 _onClick: function (p_sType, p_aArgs) {
2883 var oEvent = p_aArgs[0],
2885 bInMenuAnchor = false,
2895 var hide = function () {
2897 oRoot = this.getRoot();
2899 if (oRoot instanceof YAHOO.widget.MenuBar ||
2900 oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2902 oRoot.clearActiveItem();
2916 if (oItem.cfg.getProperty(_DISABLED)) {
2918 Event.preventDefault(oEvent);
2925 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2929 Check if the URL of the anchor is pointing to an element that is
2930 a child of the menu.
2933 sURL = oItem.cfg.getProperty(_URL);
2938 nHashPos = sURL.indexOf(_HASH);
2943 if (nHashPos != -1) {
2945 sURL = sURL.substr(nHashPos, nLen);
2952 sId = sURL.substr(1, nLen);
2954 oMenu = YAHOO.widget.MenuManager.getMenu(sId);
2959 (this.getRoot() === oMenu.getRoot());
2964 else if (nLen === 1) {
2966 bInMenuAnchor = true;
2975 if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
2977 Event.preventDefault(oEvent);
2987 oItem.focusEvent.fire();
2994 if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
3008 * @method _onKeyDown
3009 * @description "keydown" event handler for the menu.
3011 * @param {String} p_sType String representing the name of the event that
3013 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3015 _onKeyDown: function (p_sType, p_aArgs) {
3017 var oEvent = p_aArgs[0],
3035 if (this._useHideDelay) {
3036 this._cancelHideDelay();
3041 This function is called to prevent a bug in Firefox. In Firefox,
3042 moving a DOM element into a stationary mouse pointer will cause the
3043 browser to fire mouse events. This can result in the menu mouse
3044 event handlers being called uncessarily, especially when menus are
3045 moved into a stationary mouse pointer as a result of a
3048 function stopMouseEventHandlers() {
3050 this._bStopMouseEventHandlers = true;
3052 Lang.later(10, this, function () {
3054 this._bStopMouseEventHandlers = false;
3061 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
3063 oItemCfg = oItem.cfg;
3064 oParentItem = this.parent;
3066 switch(oEvent.keyCode) {
3068 case 38: // Up arrow
3069 case 40: // Down arrow
3071 oNextItem = (oEvent.keyCode == 38) ?
3072 oItem.getPreviousEnabledSibling() :
3073 oItem.getNextEnabledSibling();
3077 this.clearActiveItem();
3079 oNextItem.cfg.setProperty(_SELECTED, true);
3083 if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
3086 nBodyScrollTop = oBody.scrollTop;
3087 nBodyOffsetHeight = oBody.offsetHeight;
3088 aItems = this.getItems();
3089 nItems = aItems.length - 1;
3090 nNextItemOffsetTop = oNextItem.element.offsetTop;
3093 if (oEvent.keyCode == 40 ) { // Down
3095 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3097 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3100 else if (nNextItemOffsetTop <= nBodyScrollTop) {
3102 oBody.scrollTop = 0;
3107 if (oNextItem == aItems[nItems]) {
3109 oBody.scrollTop = oNextItem.element.offsetTop;
3116 if (nNextItemOffsetTop <= nBodyScrollTop) {
3118 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3121 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3123 oBody.scrollTop = nNextItemOffsetTop;
3128 if (oNextItem == aItems[0]) {
3130 oBody.scrollTop = 0;
3137 nBodyScrollTop = oBody.scrollTop;
3138 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3140 if (nBodyScrollTop === 0) {
3142 this._disableScrollHeader();
3143 this._enableScrollFooter();
3146 else if (nBodyScrollTop == nScrollTarget) {
3148 this._enableScrollHeader();
3149 this._disableScrollFooter();
3154 this._enableScrollHeader();
3155 this._enableScrollFooter();
3164 Event.preventDefault(oEvent);
3166 stopMouseEventHandlers();
3171 case 39: // Right arrow
3173 oSubmenu = oItemCfg.getProperty(_SUBMENU);
3177 if (!oItemCfg.getProperty(_SELECTED)) {
3179 oItemCfg.setProperty(_SELECTED, true);
3184 oSubmenu.setInitialFocus();
3185 oSubmenu.setInitialSelection();
3190 oRoot = this.getRoot();
3192 if (oRoot instanceof YAHOO.widget.MenuBar) {
3194 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3198 oRoot.clearActiveItem();
3200 oNextItem.cfg.setProperty(_SELECTED, true);
3202 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3207 oSubmenu.setInitialFocus();
3223 Event.preventDefault(oEvent);
3225 stopMouseEventHandlers();
3230 case 37: // Left arrow
3234 oParentMenu = oParentItem.parent;
3236 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3239 oParentMenu.activeItem.getPreviousEnabledSibling();
3243 oParentMenu.clearActiveItem();
3245 oNextItem.cfg.setProperty(_SELECTED, true);
3247 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3252 oSubmenu.setInitialFocus();
3268 oParentItem.focus();
3274 Event.preventDefault(oEvent);
3276 stopMouseEventHandlers();
3286 if (oEvent.keyCode == 27) { // Esc key
3288 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3294 this.parent.focus();
3298 // Focus the element that previously had focus
3300 oFocusedEl = this._focusedElement;
3302 if (oFocusedEl && oFocusedEl.focus) {
3315 else if (this.activeItem) {
3317 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3319 if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3322 this.activeItem.focus();
3327 this.activeItem.blur();
3328 this.activeItem.cfg.setProperty(_SELECTED, false);
3335 Event.preventDefault(oEvent);
3343 * @method _onKeyPress
3344 * @description "keypress" event handler for a Menu instance.
3346 * @param {String} p_sType The name of the event that was fired.
3347 * @param {Array} p_aArgs Collection of arguments sent when the event
3350 _onKeyPress: function (p_sType, p_aArgs) {
3352 var oEvent = p_aArgs[0];
3355 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3357 Event.preventDefault(oEvent);
3366 * @description "blur" event handler for a Menu instance.
3368 * @param {String} p_sType The name of the event that was fired.
3369 * @param {Array} p_aArgs Collection of arguments sent when the event
3372 _onBlur: function (p_sType, p_aArgs) {
3374 if (this._hasFocus) {
3375 this._hasFocus = false;
3381 * @method _onYChange
3382 * @description "y" event handler for a Menu instance.
3384 * @param {String} p_sType The name of the event that was fired.
3385 * @param {Array} p_aArgs Collection of arguments sent when the event
3388 _onYChange: function (p_sType, p_aArgs) {
3390 var oParent = this.parent,
3398 nScrollTop = oParent.parent.body.scrollTop;
3401 if (nScrollTop > 0) {
3403 nY = (this.cfg.getProperty(_Y) - nScrollTop);
3405 Dom.setY(this.element, nY);
3407 oIFrame = this.iframe;
3412 Dom.setY(oIFrame, nY);
3416 this.cfg.setProperty(_Y, nY, true);
3426 * @method _onScrollTargetMouseOver
3427 * @description "mouseover" event handler for the menu's "header" and "footer"
3428 * elements. Used to scroll the body of the menu up and down when the
3429 * menu's "maxheight" configuration property is set to a value greater than 0.
3431 * @param {Event} p_oEvent Object representing the DOM event object passed
3432 * back by the event utility (YAHOO.util.Event).
3433 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3436 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3438 var oBodyScrollTimer = this._bodyScrollTimer;
3441 if (oBodyScrollTimer) {
3443 oBodyScrollTimer.cancel();
3448 this._cancelHideDelay();
3451 var oTarget = Event.getTarget(p_oEvent),
3453 nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3458 function scrollBodyDown() {
3460 var nScrollTop = oBody.scrollTop;
3463 if (nScrollTop < nScrollTarget) {
3465 oBody.scrollTop = (nScrollTop + nScrollIncrement);
3467 this._enableScrollHeader();
3472 oBody.scrollTop = nScrollTarget;
3474 this._bodyScrollTimer.cancel();
3476 this._disableScrollFooter();
3483 function scrollBodyUp() {
3485 var nScrollTop = oBody.scrollTop;
3488 if (nScrollTop > 0) {
3490 oBody.scrollTop = (nScrollTop - nScrollIncrement);
3492 this._enableScrollFooter();
3497 oBody.scrollTop = 0;
3499 this._bodyScrollTimer.cancel();
3501 this._disableScrollHeader();
3508 if (Dom.hasClass(oTarget, _HD)) {
3510 fnScrollFunction = scrollBodyUp;
3515 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3517 fnScrollFunction = scrollBodyDown;
3522 this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3528 * @method _onScrollTargetMouseOut
3529 * @description "mouseout" event handler for the menu's "header" and "footer"
3530 * elements. Used to stop scrolling the body of the menu up and down when the
3531 * menu's "maxheight" configuration property is set to a value greater than 0.
3533 * @param {Event} p_oEvent Object representing the DOM event object passed
3534 * back by the event utility (YAHOO.util.Event).
3535 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3538 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3540 var oBodyScrollTimer = this._bodyScrollTimer;
3542 if (oBodyScrollTimer) {
3544 oBodyScrollTimer.cancel();
3548 this._cancelHideDelay();
3559 * @description "init" event handler for the menu.
3561 * @param {String} p_sType String representing the name of the event that
3563 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3565 _onInit: function (p_sType, p_aArgs) {
3567 this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3569 var bRootMenu = !this.parent,
3570 bLazyLoad = this.lazyLoad;
3574 Automatically initialize a menu's subtree if:
3576 1) This is the root menu and lazyload is off
3578 2) This is the root menu, lazyload is on, but the menu is
3581 3) This menu is a submenu and lazyload is off
3586 if (((bRootMenu && !bLazyLoad) ||
3587 (bRootMenu && (this.cfg.getProperty(_VISIBLE) ||
3588 this.cfg.getProperty(_POSITION) == _STATIC)) ||
3589 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3591 if (this.srcElement) {
3593 this._initSubTree();
3598 if (this.itemData) {
3600 this.addItems(this.itemData);
3605 else if (bLazyLoad) {
3607 this.cfg.fireQueue();
3615 * @method _onBeforeRender
3616 * @description "beforerender" event handler for the menu. Appends all of the
3617 * <code><ul></code>, <code><li></code> and their accompanying
3618 * title elements to the body element of the menu.
3620 * @param {String} p_sType String representing the name of the event that
3622 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3624 _onBeforeRender: function (p_sType, p_aArgs) {
3626 var oEl = this.element,
3627 nListElements = this._aListElements.length,
3633 if (nListElements > 0) {
3637 oUL = this._aListElements[i];
3643 Dom.addClass(oUL, _FIRST_OF_TYPE);
3649 if (!Dom.isAncestor(oEl, oUL)) {
3651 this.appendToBody(oUL);
3656 oGroupTitle = this._aGroupTitleElements[i];
3660 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3662 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3667 Dom.addClass(oUL, _HAS_TITLE);
3676 while (i < nListElements);
3685 * @description "render" event handler for the menu.
3687 * @param {String} p_sType String representing the name of the event that
3689 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3691 _onRender: function (p_sType, p_aArgs) {
3693 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3695 if (!this.cfg.getProperty(_VISIBLE)) {
3697 this.positionOffScreen();
3710 * @method _onBeforeShow
3711 * @description "beforeshow" event handler for the menu.
3713 * @param {String} p_sType String representing the name of the event that
3715 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3717 _onBeforeShow: function (p_sType, p_aArgs) {
3722 oContainer = this.cfg.getProperty(_CONTAINER);
3725 if (this.lazyLoad && this.getItemGroups().length === 0) {
3727 if (this.srcElement) {
3729 this._initSubTree();
3734 if (this.itemData) {
3736 if (this.parent && this.parent.parent &&
3737 this.parent.parent.srcElement &&
3738 this.parent.parent.srcElement.tagName.toUpperCase() ==
3741 nOptions = this.itemData.length;
3743 for(n=0; n<nOptions; n++) {
3745 if (this.itemData[n].tagName) {
3747 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3756 this.addItems(this.itemData);
3763 oSrcElement = this.srcElement;
3767 if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3769 if (Dom.inDocument(oSrcElement)) {
3771 this.render(oSrcElement.parentNode);
3776 this.render(oContainer);
3792 this.render(this.parent.element);
3797 this.render(oContainer);
3807 var oParent = this.parent,
3811 if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3813 this.cfg.refireEvent(_XY);
3820 aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3822 this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3830 getConstrainedY: function (y) {
3834 aContext = oMenu.cfg.getProperty(_CONTEXT),
3835 nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3839 oOverlapPositions = {
3848 bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3850 oMenuEl = oMenu.element,
3851 nMenuOffsetHeight = oMenuEl.offsetHeight,
3853 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3854 viewPortHeight = Dom.getViewportHeight(),
3855 scrollY = Dom.getDocumentScrollTop(),
3858 (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3869 nBottomRegionHeight,
3871 topConstraint = scrollY + nViewportOffset,
3872 bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
3877 var flipVertical = function () {
3881 // The Menu is below the context element, flip it above
3882 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3883 nNewY = (nContextElY - nMenuOffsetHeight);
3885 else { // The Menu is above the context element, flip it below
3886 nNewY = (nContextElY + nContextElHeight);
3889 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3897 Uses the context element's position to calculate the availble height
3898 above and below it to display its corresponding Menu.
3901 var getDisplayRegionHeight = function () {
3903 // The Menu is below the context element
3904 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3905 return (nBottomRegionHeight - nViewportOffset);
3907 else { // The Menu is above the context element
3908 return (nTopRegionHeight - nViewportOffset);
3915 Sets the Menu's "y" configuration property to the correct value based on its
3916 current orientation.
3919 var alignY = function () {
3923 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3924 nNewY = (nContextElY + nContextElHeight);
3927 nNewY = (nContextElY - oMenuEl.offsetHeight);
3930 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3935 // Resets the maxheight of the Menu to the value set by the user
3937 var resetMaxHeight = function () {
3939 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3941 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3947 Trys to place the Menu in the best possible position (either above or
3948 below its corresponding context element).
3951 var setVerticalPosition = function () {
3953 var nDisplayRegionHeight = getDisplayRegionHeight(),
3954 bMenuHasItems = (oMenu.getItems().length > 0),
3955 nMenuMinScrollHeight,
3959 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3961 nMenuMinScrollHeight =
3962 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3965 if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3966 nMaxHeight = nDisplayRegionHeight;
3969 nMaxHeight = nInitialMaxHeight;
3973 oMenu._setScrollHeight(nMaxHeight);
3974 oMenu.hideEvent.subscribe(resetMaxHeight);
3977 // Re-align the Menu since its height has just changed
3978 // as a result of the setting of the maxheight property.
3983 if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3988 All possible positions and values for the "maxheight"
3989 configuration property have been tried, but none were
3990 successful, so fall back to the original size and position.
4002 fnReturnVal = setVerticalPosition();
4009 else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
4011 oMenu._setScrollHeight(nInitialMaxHeight);
4012 oMenu.hideEvent.subscribe(resetMaxHeight);
4014 // Re-align the Menu since its height has just changed
4015 // as a result of the setting of the maxheight property.
4026 // Determine if the current value for the Menu's "y" configuration property will
4027 // result in the Menu being positioned outside the boundaries of the viewport
4029 if (y < topConstraint || y > bottomConstraint) {
4031 // The current value for the Menu's "y" configuration property WILL
4032 // result in the Menu being positioned outside the boundaries of the viewport
4034 if (bCanConstrain) {
4036 if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
4039 // If the "preventcontextoverlap" configuration property is set to "true",
4040 // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
4041 // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
4043 oContextEl = aContext[0];
4044 nContextElHeight = oContextEl.offsetHeight;
4045 nContextElY = (Dom.getY(oContextEl) - scrollY);
4047 nTopRegionHeight = nContextElY;
4048 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
4050 setVerticalPosition();
4052 yNew = oMenu.cfg.getProperty(_Y);
4055 else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
4056 nMenuOffsetHeight >= viewPortHeight) {
4059 // If the Menu exceeds the height of the viewport, introduce scroll bars
4060 // to keep the Menu inside the boundaries of the viewport
4062 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
4064 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
4066 oMenu._setScrollHeight(nAvailableHeight);
4067 oMenu.hideEvent.subscribe(resetMaxHeight);
4071 yNew = oMenu.cfg.getProperty(_Y);
4080 if (y < topConstraint) {
4081 yNew = topConstraint;
4082 } else if (y > bottomConstraint) {
4083 yNew = bottomConstraint;
4090 // The "y" configuration property cannot be set to a value that will keep
4091 // entire Menu inside the boundary of the viewport. Therefore, set
4092 // the "y" configuration property to scrollY to keep as much of the
4093 // Menu inside the viewport as possible.
4094 yNew = nViewportOffset + scrollY;
4106 * @description "hide" event handler for the menu.
4108 * @param {String} p_sType String representing the name of the event that
4110 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4112 _onHide: function (p_sType, p_aArgs) {
4114 if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4116 this.positionOffScreen();
4125 * @description "show" event handler for the menu.
4127 * @param {String} p_sType String representing the name of the event that
4129 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4131 _onShow: function (p_sType, p_aArgs) {
4133 var oParent = this.parent,
4140 function disableAutoSubmenuDisplay(p_oEvent) {
4144 if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4147 Set the "autosubmenudisplay" to "false" if the user
4148 clicks outside the menu bar.
4151 oTarget = Event.getTarget(p_oEvent);
4153 if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4155 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4157 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4158 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4167 function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4169 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4170 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4177 oParentMenu = oParent.parent;
4180 if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
4181 (oParentMenu instanceof YAHOO.widget.MenuBar ||
4182 oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4184 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4186 Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4187 Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4192 // The following fixes an issue with the selected state of a MenuItem
4193 // not rendering correctly when a submenu is aligned to the left of
4194 // its parent Menu instance.
4196 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
4197 (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4199 oElement = this.element;
4200 nOffsetWidth = oElement.offsetWidth;
4203 Measuring the difference of the offsetWidth before and after
4204 setting the "width" style attribute allows us to compute the
4205 about of padding and borders applied to the element, which in
4206 turn allows us to set the "width" property correctly.
4209 oElement.style.width = nOffsetWidth + _PX;
4211 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4213 this.cfg.setProperty(_WIDTH, sWidth);
4215 this.hideEvent.subscribe(onSubmenuHide, sWidth);
4223 Dynamically positioned, root Menus focus themselves when visible, and
4224 will then, when hidden, restore focus to the UI control that had focus
4225 before the Menu was made visible.
4228 if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4230 this._focusedElement = oFocusedElement;
4241 * @method _onBeforeHide
4242 * @description "beforehide" event handler for the menu.
4244 * @param {String} p_sType String representing the name of the event that
4246 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4248 _onBeforeHide: function (p_sType, p_aArgs) {
4250 var oActiveItem = this.activeItem,
4251 oRoot = this.getRoot(),
4258 oConfig = oActiveItem.cfg;
4260 oConfig.setProperty(_SELECTED, false);
4262 oSubmenu = oConfig.getProperty(_SUBMENU);
4274 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
4275 For this reason, it is necessary to maintain the focused state in a private property
4276 so that the _onMouseOver event handler is able to determined whether or not to set focus
4277 to MenuItems as the user is moving the mouse.
4280 if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4282 oRoot._hasFocus = this.hasFocus();
4287 if (oRoot == this) {
4297 * @method _onParentMenuConfigChange
4298 * @description "configchange" event handler for a submenu.
4300 * @param {String} p_sType String representing the name of the event that
4302 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4303 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4304 * subscribed to the event.
4306 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4308 var sPropertyName = p_aArgs[0][0],
4309 oPropertyValue = p_aArgs[0][1];
4311 switch(sPropertyName) {
4314 case _CONSTRAIN_TO_VIEWPORT:
4317 case _SUBMENU_HIDE_DELAY:
4318 case _CLICK_TO_HIDE:
4321 case _SCROLL_INCREMENT:
4323 case _MIN_SCROLL_HEIGHT:
4324 case _MONITOR_RESIZE:
4326 case _PREVENT_CONTEXT_OVERLAP:
4329 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4333 case _SUBMENU_ALIGNMENT:
4335 if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4337 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4349 * @method _onParentMenuRender
4350 * @description "render" event handler for a submenu. Renders a
4351 * submenu in response to the firing of its parent's "render" event.
4353 * @param {String} p_sType String representing the name of the event that
4355 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4356 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4357 * subscribed to the event.
4359 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4361 var oParentMenu = p_oSubmenu.parent.parent,
4362 oParentCfg = oParentMenu.cfg,
4366 constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4370 clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4372 effect: oParentCfg.getProperty(_EFFECT),
4374 showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4376 hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4378 submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4380 classname: oParentCfg.getProperty(_CLASSNAME),
4382 scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4384 maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4386 minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4388 iframe: oParentCfg.getProperty(_IFRAME),
4390 shadow: oParentCfg.getProperty(_SHADOW),
4392 preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4394 monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
4396 keepopen: oParentCfg.getProperty(_KEEP_OPEN)
4404 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4406 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4411 p_oSubmenu.cfg.applyConfig(oConfig);
4414 if (!this.lazyLoad) {
4416 oLI = this.parent.element;
4418 if (this.element.parentNode == oLI) {
4435 * @method _onMenuItemDestroy
4436 * @description "destroy" event handler for the menu's items.
4438 * @param {String} p_sType String representing the name of the event
4440 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4441 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4442 * that fired the event.
4444 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4446 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4452 * @method _onMenuItemConfigChange
4453 * @description "configchange" event handler for the menu's items.
4455 * @param {String} p_sType String representing the name of the event that
4457 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4458 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4459 * that fired the event.
4461 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4463 var sPropertyName = p_aArgs[0][0],
4464 oPropertyValue = p_aArgs[0][1],
4468 switch(sPropertyName) {
4472 if (oPropertyValue === true) {
4474 this.activeItem = p_oItem;
4482 oSubmenu = p_aArgs[0][1];
4486 this._configureSubmenu(p_oItem);
4498 // Public event handlers for configuration properties
4502 * @method configVisible
4503 * @description Event handler for when the "visible" configuration property
4505 * @param {String} p_sType String representing the name of the event that
4507 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4508 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4511 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4516 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4518 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4523 bVisible = p_aArgs[0];
4524 sDisplay = Dom.getStyle(this.element, _DISPLAY);
4526 Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4530 if (sDisplay != _BLOCK) {
4531 this.beforeShowEvent.fire();
4532 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4533 this.showEvent.fire();
4539 if (sDisplay == _BLOCK) {
4540 this.beforeHideEvent.fire();
4541 Dom.setStyle(this.element, _DISPLAY, _NONE);
4542 this.hideEvent.fire();
4553 * @method configPosition
4554 * @description Event handler for when the "position" configuration property
4555 * of the menu changes.
4556 * @param {String} p_sType String representing the name of the event that
4558 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4559 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4562 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4564 var oElement = this.element,
4565 sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4570 Dom.setStyle(oElement, _POSITION, sCSSPosition);
4573 if (sCSSPosition == _STATIC) {
4575 // Statically positioned menus are visible by default
4577 Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4579 oCfg.setProperty(_VISIBLE, true);
4585 Even though the "visible" property is queued to
4586 "false" by default, we need to set the "visibility" property to
4587 "hidden" since Overlay's "configVisible" implementation checks the
4588 element's "visibility" style property before deciding whether
4589 or not to show an Overlay instance.
4592 Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4597 if (sCSSPosition == _ABSOLUTE) {
4599 nZIndex = oCfg.getProperty(_ZINDEX);
4601 if (!nZIndex || nZIndex === 0) {
4603 oCfg.setProperty(_ZINDEX, 1);
4613 * @method configIframe
4614 * @description Event handler for when the "iframe" configuration property of
4616 * @param {String} p_sType String representing the name of the event that
4618 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4619 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4622 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4624 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4626 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4634 * @method configHideDelay
4635 * @description Event handler for when the "hidedelay" configuration property
4636 * of the menu changes.
4637 * @param {String} p_sType String representing the name of the event that
4639 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4640 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4643 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4645 var nHideDelay = p_aArgs[0];
4647 this._useHideDelay = (nHideDelay > 0);
4653 * @method configContainer
4654 * @description Event handler for when the "container" configuration property
4655 * of the menu changes.
4656 * @param {String} p_sType String representing the name of the event that
4658 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4659 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4662 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4664 var oElement = p_aArgs[0];
4666 if (Lang.isString(oElement)) {
4668 this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4676 * @method _clearSetWidthFlag
4677 * @description Change event listener for the "width" configuration property. This listener is
4678 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
4679 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
4680 * is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
4681 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
4682 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4685 _clearSetWidthFlag: function () {
4687 this._widthSetForScroll = false;
4689 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4695 * @method _setScrollHeight
4697 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4700 _setScrollHeight: function (p_nScrollHeight) {
4702 var nScrollHeight = p_nScrollHeight,
4703 bRefireIFrameAndShadow = false,
4717 if (this.getItems().length > 0) {
4719 oElement = this.element;
4721 oHeader = this.header;
4722 oFooter = this.footer;
4723 fnMouseOver = this._onScrollTargetMouseOver;
4724 fnMouseOut = this._onScrollTargetMouseOut;
4725 nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4728 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4730 nScrollHeight = nMinScrollHeight;
4735 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4736 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4737 oBody.scrollTop = 0;
4740 // Need to set a width for the Menu to fix the following problems in
4741 // Firefox 2 and IE:
4743 // #1) Scrolled Menus will render at 1px wide in Firefox 2
4745 // #2) There is a bug in gecko-based browsers where an element whose
4746 // "position" property is set to "absolute" and "overflow" property is
4747 // set to "hidden" will not render at the correct width when its
4748 // offsetParent's "position" property is also set to "absolute." It is
4749 // possible to work around this bug by specifying a value for the width
4750 // property in addition to overflow.
4752 // #3) In IE it is necessary to give the Menu a width before the
4753 // scrollbars are rendered to prevent the Menu from rendering with a
4754 // width that is 100% of the browser viewport.
4756 bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4758 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4760 nOffsetWidth = oElement.offsetWidth;
4763 Measuring the difference of the offsetWidth before and after
4764 setting the "width" style attribute allows us to compute the
4765 about of padding and borders applied to the element, which in
4766 turn allows us to set the "width" property correctly.
4769 oElement.style.width = nOffsetWidth + _PX;
4771 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4774 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4776 YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.",
4777 "info", this.toString());
4779 this.cfg.setProperty(_WIDTH, sWidth);
4783 Set a flag (_widthSetForScroll) to maintain some history regarding how the
4784 "width" configuration property was set. If the "width" configuration property
4785 is set by something other than the "_setScrollHeight" method, it will be
4786 necessary to maintain that new value and not clear the width if scrolling
4790 this._widthSetForScroll = true;
4792 this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4797 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4799 YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
4801 this.setHeader(_NON_BREAKING_SPACE);
4802 this.setFooter(_NON_BREAKING_SPACE);
4804 oHeader = this.header;
4805 oFooter = this.footer;
4807 Dom.addClass(oHeader, _TOP_SCROLLBAR);
4808 Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4810 oElement.insertBefore(oHeader, oBody);
4811 oElement.appendChild(oFooter);
4816 nHeight = nScrollHeight;
4819 if (oHeader && oFooter) {
4820 nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4824 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4826 YAHOO.log("Setting up styles and event handlers for scrolling.",
4827 "info", this.toString());
4829 Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4830 Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4832 if (!this._hasScrollEventHandlers) {
4834 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4835 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4836 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4837 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4839 this._hasScrollEventHandlers = true;
4843 this._disableScrollHeader();
4844 this._enableScrollFooter();
4846 bRefireIFrameAndShadow = true;
4849 else if (oHeader && oFooter) {
4851 YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
4855 Only clear the "width" configuration property if it was set the
4856 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4859 if (this._widthSetForScroll) {
4861 YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
4863 this._widthSetForScroll = false;
4865 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4867 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4872 this._enableScrollHeader();
4873 this._enableScrollFooter();
4875 if (this._hasScrollEventHandlers) {
4877 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4878 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4879 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4880 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4882 this._hasScrollEventHandlers = false;
4886 oElement.removeChild(oHeader);
4887 oElement.removeChild(oFooter);
4892 bRefireIFrameAndShadow = true;
4897 if (bRefireIFrameAndShadow) {
4899 this.cfg.refireEvent(_IFRAME);
4900 this.cfg.refireEvent(_SHADOW);
4910 * @method _setMaxHeight
4911 * @description "renderEvent" handler used to defer the setting of the
4912 * "maxheight" configuration property until the menu is rendered in lazy
4914 * @param {String} p_sType The name of the event that was fired.
4915 * @param {Array} p_aArgs Collection of arguments sent when the event
4917 * @param {Number} p_nMaxHeight Number representing the value to set for the
4918 * "maxheight" configuration property.
4921 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4923 this._setScrollHeight(p_nMaxHeight);
4924 this.renderEvent.unsubscribe(this._setMaxHeight);
4930 * @method configMaxHeight
4931 * @description Event handler for when the "maxheight" configuration property of
4933 * @param {String} p_sType The name of the event that was fired.
4934 * @param {Array} p_aArgs Collection of arguments sent when the event
4936 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4939 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4941 var nMaxHeight = p_aArgs[0];
4943 if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4945 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4950 this._setScrollHeight(nMaxHeight);
4958 * @method configClassName
4959 * @description Event handler for when the "classname" configuration property of
4961 * @param {String} p_sType The name of the event that was fired.
4962 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4963 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4965 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4967 var sClassName = p_aArgs[0];
4969 if (this._sClassName) {
4971 Dom.removeClass(this.element, this._sClassName);
4975 Dom.addClass(this.element, sClassName);
4976 this._sClassName = sClassName;
4982 * @method _onItemAdded
4983 * @description "itemadded" event handler for a Menu instance.
4985 * @param {String} p_sType The name of the event that was fired.
4986 * @param {Array} p_aArgs Collection of arguments sent when the event
4989 _onItemAdded: function (p_sType, p_aArgs) {
4991 var oItem = p_aArgs[0];
4995 oItem.cfg.setProperty(_DISABLED, true);
5003 * @method configDisabled
5004 * @description Event handler for when the "disabled" configuration property of
5006 * @param {String} p_sType The name of the event that was fired.
5007 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5008 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5010 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
5012 var bDisabled = p_aArgs[0],
5013 aItems = this.getItems(),
5017 if (Lang.isArray(aItems)) {
5019 nItems = aItems.length;
5027 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
5037 this.clearActiveItem(true);
5039 Dom.addClass(this.element, _DISABLED);
5041 this.itemAddedEvent.subscribe(this._onItemAdded);
5046 Dom.removeClass(this.element, _DISABLED);
5048 this.itemAddedEvent.unsubscribe(this._onItemAdded);
5058 * @method configShadow
5059 * @description Event handler for when the "shadow" configuration property of
5061 * @param {String} p_sType The name of the event that was fired.
5062 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5063 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5065 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5067 var sizeShadow = function () {
5069 var oElement = this.element,
5070 oShadow = this._shadow;
5072 if (oShadow && oElement) {
5074 // Clear the previous width
5076 if (oShadow.style.width && oShadow.style.height) {
5078 oShadow.style.width = _EMPTY_STRING;
5079 oShadow.style.height = _EMPTY_STRING;
5083 oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
5084 oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
5091 var replaceShadow = function () {
5093 this.element.appendChild(this._shadow);
5098 var addShadowVisibleClass = function () {
5100 Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5105 var removeShadowVisibleClass = function () {
5107 Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5112 var createShadow = function () {
5114 var oShadow = this._shadow,
5119 oElement = this.element;
5122 if (!m_oShadowTemplate) {
5124 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5125 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5129 oShadow = m_oShadowTemplate.cloneNode(false);
5131 oElement.appendChild(oShadow);
5133 this._shadow = oShadow;
5135 this.beforeShowEvent.subscribe(addShadowVisibleClass);
5136 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
5142 Need to call sizeShadow & syncIframe via setTimeout for
5143 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
5144 or the shadow and iframe shim will not be sized and
5145 positioned properly.
5148 Lang.later(0, this, function () {
5150 sizeShadow.call(this);
5156 this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
5157 this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
5158 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
5159 this.changeContentEvent.subscribe(sizeShadow);
5161 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5163 this.destroyEvent.subscribe(function () {
5165 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5171 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
5178 var onBeforeShow = function () {
5182 // If called because the "shadow" event was refired - just append again and resize
5184 replaceShadow.call(this);
5187 sizeShadow.call(this);
5193 createShadow.call(this);
5197 this.beforeShowEvent.unsubscribe(onBeforeShow);
5202 var bShadow = p_aArgs[0];
5205 if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5207 if (this.cfg.getProperty(_VISIBLE)) {
5211 // If the "shadow" event was refired - just append again and resize
5213 replaceShadow.call(this);
5216 sizeShadow.call(this);
5221 createShadow.call(this);
5227 this.beforeShowEvent.subscribe(onBeforeShow);
5241 * @method initEvents
5242 * @description Initializes the custom events for the menu.
5244 initEvents: function () {
5246 Menu.superclass.initEvents.call(this);
5248 // Create custom events
5250 var i = EVENT_TYPES.length - 1,
5257 aEventData = EVENT_TYPES[i];
5259 oCustomEvent = this.createEvent(aEventData[1]);
5260 oCustomEvent.signature = CustomEvent.LIST;
5262 this[aEventData[0]] = oCustomEvent;
5271 * @method positionOffScreen
5272 * @description Positions the menu outside of the boundaries of the browser's
5273 * viewport. Called automatically when a menu is hidden to ensure that
5274 * it doesn't force the browser to render uncessary scrollbars.
5276 positionOffScreen: function () {
5278 var oIFrame = this.iframe,
5279 oElement = this.element,
5280 sPos = this.OFF_SCREEN_POSITION;
5282 oElement.style.top = _EMPTY_STRING;
5283 oElement.style.left = _EMPTY_STRING;
5287 oIFrame.style.top = sPos;
5288 oIFrame.style.left = sPos;
5297 * @description Finds the menu's root menu.
5299 getRoot: function () {
5301 var oItem = this.parent,
5307 oParentMenu = oItem.parent;
5309 returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5325 * @description Returns a string representing the menu.
5328 toString: function () {
5330 var sReturnVal = _MENU,
5335 sReturnVal += (_SPACE + sId);
5345 * @method setItemGroupTitle
5346 * @description Sets the title of a group of menu items.
5347 * @param {String} p_sGroupTitle String specifying the title of the group.
5348 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5349 * the title belongs.
5351 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5358 if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5360 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5361 oTitle = this._aGroupTitleElements[nGroupIndex];
5366 oTitle.innerHTML = p_sGroupTitle;
5371 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5373 oTitle.innerHTML = p_sGroupTitle;
5375 this._aGroupTitleElements[nGroupIndex] = oTitle;
5380 i = this._aGroupTitleElements.length - 1;
5384 if (this._aGroupTitleElements[i]) {
5386 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5396 if (nFirstIndex !== null) {
5398 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
5403 this.changeContentEvent.fire();
5413 * @description Appends an item to the menu.
5414 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5415 * instance to be added to the menu.
5416 * @param {String} p_oItem String specifying the text of the item to be added
5418 * @param {Object} p_oItem Object literal containing a set of menu item
5419 * configuration properties.
5420 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5421 * which the item belongs.
5422 * @return {YAHOO.widget.MenuItem}
5424 addItem: function (p_oItem, p_nGroupIndex) {
5426 return this._addItemToGroup(p_nGroupIndex, p_oItem);
5433 * @description Adds an array of items to the menu.
5434 * @param {Array} p_aItems Array of items to be added to the menu. The array
5435 * can contain strings specifying the text for each item to be created, object
5436 * literals specifying each of the menu item configuration properties,
5437 * or MenuItem instances.
5438 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5439 * which the items belongs.
5442 addItems: function (p_aItems, p_nGroupIndex) {
5451 if (Lang.isArray(p_aItems)) {
5453 nItems = p_aItems.length;
5456 for(i=0; i<nItems; i++) {
5458 oItem = p_aItems[i];
5462 if (Lang.isArray(oItem)) {
5464 aItems[aItems.length] = this.addItems(oItem, i);
5469 aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5478 if (aItems.length) {
5492 * @method insertItem
5493 * @description Inserts an item into the menu at the specified index.
5494 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5495 * instance to be added to the menu.
5496 * @param {String} p_oItem String specifying the text of the item to be added
5498 * @param {Object} p_oItem Object literal containing a set of menu item
5499 * configuration properties.
5500 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5501 * the item should be added.
5502 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5504 * @return {YAHOO.widget.MenuItem}
5506 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5508 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5514 * @method removeItem
5515 * @description Removes the specified item from the menu.
5516 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5517 * instance to be removed from the menu.
5518 * @param {Number} p_oObject Number specifying the index of the item
5520 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5521 * which the item belongs.
5522 * @return {YAHOO.widget.MenuItem}
5524 removeItem: function (p_oObject, p_nGroupIndex) {
5529 if (!Lang.isUndefined(p_oObject)) {
5531 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5533 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5536 else if (Lang.isNumber(p_oObject)) {
5538 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5546 YAHOO.log("Item removed." +
5547 " Text: " + oItem.cfg.getProperty("text") + ", " +
5548 " Index: " + oItem.index + ", " +
5549 " Group Index: " + oItem.groupIndex, "info", this.toString());
5564 * @description Returns an array of all of the items in the menu.
5567 getItems: function () {
5569 var aGroups = this._aItemGroups,
5575 if (Lang.isArray(aGroups)) {
5577 nGroups = aGroups.length;
5579 returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5589 * @method getItemGroups
5590 * @description Multi-dimensional Array representing the menu items as they
5591 * are grouped in the menu.
5594 getItemGroups: function () {
5596 return this._aItemGroups;
5603 * @description Returns the item at the specified index.
5604 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5605 * item to be retrieved.
5606 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5608 * @return {YAHOO.widget.MenuItem}
5610 getItem: function (p_nItemIndex, p_nGroupIndex) {
5615 if (Lang.isNumber(p_nItemIndex)) {
5617 aGroup = this._getItemGroup(p_nGroupIndex);
5621 returnVal = aGroup[p_nItemIndex];
5633 * @method getSubmenus
5634 * @description Returns an array of all of the submenus that are immediate
5635 * children of the menu.
5638 getSubmenus: function () {
5640 var aItems = this.getItems(),
5641 nItems = aItems.length,
5652 for(i=0; i<nItems; i++) {
5658 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5662 aSubmenus[aSubmenus.length] = oSubmenu;
5678 * @method clearContent
5679 * @description Removes all of the content from the menu, including the menu
5680 * items, group titles, header and footer.
5682 clearContent: function () {
5684 var aItems = this.getItems(),
5685 nItems = aItems.length,
5686 oElement = this.element,
5688 oHeader = this.header,
5689 oFooter = this.footer,
5705 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5709 this.cfg.configChangedEvent.unsubscribe(
5710 this._onParentMenuConfigChange, oSubmenu);
5712 this.renderEvent.unsubscribe(this._onParentMenuRender,
5717 this.removeItem(oItem, oItem.groupIndex);
5729 Event.purgeElement(oHeader);
5730 oElement.removeChild(oHeader);
5737 Event.purgeElement(oFooter);
5738 oElement.removeChild(oFooter);
5744 Event.purgeElement(oBody);
5746 oBody.innerHTML = _EMPTY_STRING;
5750 this.activeItem = null;
5752 this._aItemGroups = [];
5753 this._aListElements = [];
5754 this._aGroupTitleElements = [];
5756 this.cfg.setProperty(_WIDTH, null);
5763 * @description Removes the menu's <code><div></code> element
5764 * (and accompanying child nodes) from the document.
5766 destroy: function () {
5770 this.clearContent();
5772 this._aItemGroups = null;
5773 this._aListElements = null;
5774 this._aGroupTitleElements = null;
5777 // Continue with the superclass implementation of this method
5779 Menu.superclass.destroy.call(this);
5781 YAHOO.log("Destroyed.", "info", this.toString());
5787 * @method setInitialFocus
5788 * @description Sets focus to the menu's first enabled item.
5790 setInitialFocus: function () {
5792 var oItem = this._getFirstEnabledItem();
5804 * @method setInitialSelection
5805 * @description Sets the "selected" configuration property of the menu's first
5806 * enabled item to "true."
5808 setInitialSelection: function () {
5810 var oItem = this._getFirstEnabledItem();
5814 oItem.cfg.setProperty(_SELECTED, true);
5821 * @method clearActiveItem
5822 * @description Sets the "selected" configuration property of the menu's active
5823 * item to "false" and hides the item's submenu.
5824 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5825 * should be blurred.
5827 clearActiveItem: function (p_bBlur) {
5829 if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5831 this._cancelShowDelay();
5836 var oActiveItem = this.activeItem,
5842 oConfig = oActiveItem.cfg;
5848 this.getRoot()._hasFocus = true;
5852 oConfig.setProperty(_SELECTED, false);
5854 oSubmenu = oConfig.getProperty(_SUBMENU);
5863 this.activeItem = null;
5872 * @description Causes the menu to receive focus and fires the "focus" event.
5874 focus: function () {
5876 if (!this.hasFocus()) {
5878 this.setInitialFocus();
5887 * @description Causes the menu to lose focus and fires the "blur" event.
5893 if (this.hasFocus()) {
5895 oItem = MenuManager.getFocusedMenuItem();
5910 * @description Returns a boolean indicating whether or not the menu has focus.
5913 hasFocus: function () {
5915 return (MenuManager.getFocusedMenu() == this.getRoot());
5920 _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5922 var oItem = p_aArgs[0],
5923 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5926 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5932 _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5934 var oSubmenu = this.cfg.getProperty(_SUBMENU);
5937 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5944 * Adds the specified CustomEvent subscriber to the menu and each of
5947 * @param p_type {string} the type, or name of the event
5948 * @param p_fn {function} the function to exectute when the event fires
5949 * @param p_obj {Object} An object to be passed along when the event
5951 * @param p_override {boolean} If true, the obj passed in becomes the
5952 * execution scope of the listener
5954 subscribe: function () {
5956 // Subscribe to the event for this Menu instance
5957 Menu.superclass.subscribe.apply(this, arguments);
5959 // Subscribe to the "itemAdded" event so that all future submenus
5960 // also subscribe to this event
5961 Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5964 var aItems = this.getItems(),
5973 nItems = aItems.length;
5982 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5985 oSubmenu.subscribe.apply(oSubmenu, arguments);
5988 oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
6001 unsubscribe: function () {
6003 // Remove the event for this Menu instance
6004 Menu.superclass.unsubscribe.apply(this, arguments);
6006 // Remove the "itemAdded" event so that all future submenus don't have
6007 // the event handler
6008 Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
6011 var aItems = this.getItems(),
6020 nItems = aItems.length;
6029 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
6032 oSubmenu.unsubscribe.apply(oSubmenu, arguments);
6035 oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
6049 * @description Initializes the class's configurable properties which can be
6050 * changed using the menu's Config object ("cfg").
6051 * @method initDefaultConfig
6053 initDefaultConfig: function () {
6055 Menu.superclass.initDefaultConfig.call(this);
6057 var oConfig = this.cfg;
6060 // Module documentation overrides
6064 * @description Object or array of objects representing the ContainerEffect
6065 * classes that are active for animating the container. When set this
6066 * property is automatically applied to all submenus.
6071 // Overlay documentation overrides
6076 * @description Number representing the absolute x-coordinate position of
6077 * the Menu. This property is only applied when the "position"
6078 * configuration property is set to dynamic.
6086 * @description Number representing the absolute y-coordinate position of
6087 * the Menu. This property is only applied when the "position"
6088 * configuration property is set to dynamic.
6095 * @description Array of the absolute x and y positions of the Menu. This
6096 * property is only applied when the "position" configuration property is
6106 * @description Array of context arguments for context-sensitive positioning.
6107 * The format is: [id or element, element corner, context corner].
6108 * For example, setting this property to ["img1", "tl", "bl"] would
6109 * align the Menu's top left corner to the context element's
6110 * bottom left corner. This property is only applied when the "position"
6111 * configuration property is set to dynamic.
6118 * @config fixedcenter
6119 * @description Boolean indicating if the Menu should be anchored to the
6120 * center of the viewport. This property is only applied when the
6121 * "position" configuration property is set to dynamic.
6129 * @description Boolean indicating whether or not the Menu should
6130 * have an IFRAME shim; used to prevent SELECT elements from
6131 * poking through an Overlay instance in IE6. When set to "true",
6132 * the iframe shim is created when the Menu instance is intially
6133 * made visible. This property is only applied when the "position"
6134 * configuration property is set to dynamic and is automatically applied
6137 * @default true for IE6 and below, false for all other browsers.
6141 // Add configuration attributes
6144 Change the default value for the "visible" configuration
6145 property to "false" by re-adding the property.
6150 * @description Boolean indicating whether or not the menu is visible. If
6151 * the menu's "position" configuration property is set to "dynamic" (the
6152 * default), this property toggles the menu's <code><div></code>
6153 * element's "visibility" style property between "visible" (true) or
6154 * "hidden" (false). If the menu's "position" configuration property is
6155 * set to "static" this property toggles the menu's
6156 * <code><div></code> element's "display" style property
6157 * between "block" (true) or "none" (false).
6161 oConfig.addProperty(
6164 handler: this.configVisible,
6165 value: VISIBLE_CONFIG.value,
6166 validator: VISIBLE_CONFIG.validator
6172 Change the default value for the "constraintoviewport" configuration
6173 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6177 * @config constraintoviewport
6178 * @description Boolean indicating if the menu will try to remain inside
6179 * the boundaries of the size of viewport. This property is only applied
6180 * when the "position" configuration property is set to dynamic and is
6181 * automatically applied to all submenus.
6185 oConfig.addProperty(
6186 CONSTRAIN_TO_VIEWPORT_CONFIG.key,
6188 handler: this.configConstrainToViewport,
6189 value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
6190 validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
6191 supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
6197 Change the default value for the "preventcontextoverlap" configuration
6198 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6202 * @config preventcontextoverlap
6203 * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
6204 * when the "constraintoviewport" configuration property is set to "true".
6208 oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6210 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
6211 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
6212 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6219 * @description String indicating how a menu should be positioned on the
6220 * screen. Possible values are "static" and "dynamic." Static menus are
6221 * visible by default and reside in the normal flow of the document
6222 * (CSS position: static). Dynamic menus are hidden by default, reside
6223 * out of the normal flow of the document (CSS position: absolute), and
6224 * can overlay other elements on the screen.
6228 oConfig.addProperty(
6229 POSITION_CONFIG.key,
6231 handler: this.configPosition,
6232 value: POSITION_CONFIG.value,
6233 validator: POSITION_CONFIG.validator,
6234 supercedes: POSITION_CONFIG.supercedes
6240 * @config submenualignment
6241 * @description Array defining how submenus should be aligned to their
6242 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6243 * a submenu's top left corner is aligned to its parent menu item's top
6245 * @default ["tl","tr"]
6248 oConfig.addProperty(
6249 SUBMENU_ALIGNMENT_CONFIG.key,
6251 value: SUBMENU_ALIGNMENT_CONFIG.value,
6252 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6258 * @config autosubmenudisplay
6259 * @description Boolean indicating if submenus are automatically made
6260 * visible when the user mouses over the menu's items.
6264 oConfig.addProperty(
6265 AUTO_SUBMENU_DISPLAY_CONFIG.key,
6267 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
6268 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6269 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6276 * @description Number indicating the time (in milliseconds) that should
6277 * expire before a submenu is made visible when the user mouses over
6278 * the menu's items. This property is only applied when the "position"
6279 * configuration property is set to dynamic and is automatically applied
6284 oConfig.addProperty(
6285 SHOW_DELAY_CONFIG.key,
6287 value: SHOW_DELAY_CONFIG.value,
6288 validator: SHOW_DELAY_CONFIG.validator,
6289 suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6296 * @description Number indicating the time (in milliseconds) that should
6297 * expire before the menu is hidden. This property is only applied when
6298 * the "position" configuration property is set to dynamic and is
6299 * automatically applied to all submenus.
6303 oConfig.addProperty(
6304 HIDE_DELAY_CONFIG.key,
6306 handler: this.configHideDelay,
6307 value: HIDE_DELAY_CONFIG.value,
6308 validator: HIDE_DELAY_CONFIG.validator,
6309 suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6315 * @config submenuhidedelay
6316 * @description Number indicating the time (in milliseconds) that should
6317 * expire before a submenu is hidden when the user mouses out of a menu item
6318 * heading in the direction of a submenu. The value must be greater than or
6319 * equal to the value specified for the "showdelay" configuration property.
6320 * This property is only applied when the "position" configuration property
6321 * is set to dynamic and is automatically applied to all submenus.
6325 oConfig.addProperty(
6326 SUBMENU_HIDE_DELAY_CONFIG.key,
6328 value: SUBMENU_HIDE_DELAY_CONFIG.value,
6329 validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6330 suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6336 * @config clicktohide
6337 * @description Boolean indicating if the menu will automatically be
6338 * hidden if the user clicks outside of it. This property is only
6339 * applied when the "position" configuration property is set to dynamic
6340 * and is automatically applied to all submenus.
6344 oConfig.addProperty(
6345 CLICK_TO_HIDE_CONFIG.key,
6347 value: CLICK_TO_HIDE_CONFIG.value,
6348 validator: CLICK_TO_HIDE_CONFIG.validator,
6349 suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6356 * @description HTML element reference or string specifying the id
6357 * attribute of the HTML element that the menu's markup should be
6359 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6360 * level-one-html.html#ID-58190037">HTMLElement</a>|String
6361 * @default document.body
6363 oConfig.addProperty(
6364 CONTAINER_CONFIG.key,
6366 handler: this.configContainer,
6367 value: document.body,
6368 suppressEvent: CONTAINER_CONFIG.suppressEvent
6374 * @config scrollincrement
6375 * @description Number used to control the scroll speed of a menu. Used to
6376 * increment the "scrollTop" property of the menu's body by when a menu's
6377 * content is scrolling. When set this property is automatically applied
6382 oConfig.addProperty(
6383 SCROLL_INCREMENT_CONFIG.key,
6385 value: SCROLL_INCREMENT_CONFIG.value,
6386 validator: SCROLL_INCREMENT_CONFIG.validator,
6387 supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6388 suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6394 * @config minscrollheight
6395 * @description Number defining the minimum threshold for the "maxheight"
6396 * configuration property. When set this property is automatically applied
6401 oConfig.addProperty(
6402 MIN_SCROLL_HEIGHT_CONFIG.key,
6404 value: MIN_SCROLL_HEIGHT_CONFIG.value,
6405 validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6406 supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6407 suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6414 * @description Number defining the maximum height (in pixels) for a menu's
6415 * body element (<code><div class="bd"></code>). Once a menu's body
6416 * exceeds this height, the contents of the body are scrolled to maintain
6417 * this value. This value cannot be set lower than the value of the
6418 * "minscrollheight" configuration property.
6422 oConfig.addProperty(
6423 MAX_HEIGHT_CONFIG.key,
6425 handler: this.configMaxHeight,
6426 value: MAX_HEIGHT_CONFIG.value,
6427 validator: MAX_HEIGHT_CONFIG.validator,
6428 suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6429 supercedes: MAX_HEIGHT_CONFIG.supercedes
6436 * @description String representing the CSS class to be applied to the
6437 * menu's root <code><div></code> element. The specified class(es)
6438 * are appended in addition to the default class as specified by the menu's
6439 * CSS_CLASS_NAME constant. When set this property is automatically
6440 * applied to all submenus.
6444 oConfig.addProperty(
6445 CLASS_NAME_CONFIG.key,
6447 handler: this.configClassName,
6448 value: CLASS_NAME_CONFIG.value,
6449 validator: CLASS_NAME_CONFIG.validator,
6450 supercedes: CLASS_NAME_CONFIG.supercedes
6457 * @description Boolean indicating if the menu should be disabled.
6458 * Disabling a menu disables each of its items. (Disabled menu items are
6459 * dimmed and will not respond to user input or fire events.) Disabled
6460 * menus have a corresponding "disabled" CSS class applied to their root
6461 * <code><div></code> element.
6465 oConfig.addProperty(
6466 DISABLED_CONFIG.key,
6468 handler: this.configDisabled,
6469 value: DISABLED_CONFIG.value,
6470 validator: DISABLED_CONFIG.validator,
6471 suppressEvent: DISABLED_CONFIG.suppressEvent
6478 * @description Boolean indicating if the menu should have a shadow.
6482 oConfig.addProperty(
6485 handler: this.configShadow,
6486 value: SHADOW_CONFIG.value,
6487 validator: SHADOW_CONFIG.validator
6494 * @description Boolean indicating if the menu should remain open when clicked.
6498 oConfig.addProperty(
6499 KEEP_OPEN_CONFIG.key,
6501 value: KEEP_OPEN_CONFIG.value,
6502 validator: KEEP_OPEN_CONFIG.validator
6508 }); // END YAHOO.lang.extend
6517 * Creates an item for a menu.
6519 * @param {String} p_oObject String specifying the text of the menu item.
6520 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6521 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6522 * the <code><li></code> element of the menu item.
6523 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6524 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6525 * specifying the <code><optgroup></code> element of the menu item.
6526 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6527 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6528 * specifying the <code><option></code> element of the menu item.
6529 * @param {Object} p_oConfig Optional. Object literal specifying the
6530 * configuration for the menu item. See configuration class documentation
6535 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6541 this.parent = p_oConfig.parent;
6542 this.value = p_oConfig.value;
6543 this.id = p_oConfig.id;
6547 this.init(p_oObject, p_oConfig);
6554 var Dom = YAHOO.util.Dom,
6555 Module = YAHOO.widget.Module,
6556 Menu = YAHOO.widget.Menu,
6557 MenuItem = YAHOO.widget.MenuItem,
6558 CustomEvent = YAHOO.util.CustomEvent,
6562 // Private string constants
6567 _HELP_TEXT = "helptext",
6570 _EMPHASIS = "emphasis",
6571 _STRONG_EMPHASIS = "strongemphasis",
6572 _CHECKED = "checked",
6573 _SUBMENU = "submenu",
6574 _DISABLED = "disabled",
6575 _SELECTED = "selected",
6576 _HAS_SUBMENU = "hassubmenu",
6577 _CHECKED_DISABLED = "checked-disabled",
6578 _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6579 _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6580 _CHECKED_SELECTED = "checked-selected",
6581 _ONCLICK = "onclick",
6582 _CLASSNAME = "classname",
6585 _OPTGROUP = "OPTGROUP",
6586 _LI_UPPERCASE = "LI",
6590 _START_HELP_TEXT = "<em class=\"helptext\">",
6593 _START_STRONG = "<strong>",
6594 _END_STRONG = "</strong>",
6595 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6599 _VISIBLE = "visible",
6601 _MENUITEM = "MenuItem",
6605 _LI_LOWERCASE = "li",
6606 _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6610 ["mouseOverEvent", "mouseover"],
6611 ["mouseOutEvent", "mouseout"],
6612 ["mouseDownEvent", "mousedown"],
6613 ["mouseUpEvent", "mouseup"],
6614 ["clickEvent", _CLICK],
6615 ["keyPressEvent", "keypress"],
6616 ["keyDownEvent", "keydown"],
6617 ["keyUpEvent", "keyup"],
6618 ["focusEvent", "focus"],
6619 ["blurEvent", "blur"],
6620 ["destroyEvent", "destroy"]
6626 value: _EMPTY_STRING,
6627 validator: Lang.isString,
6631 HELP_TEXT_CONFIG = {
6633 supercedes: [_TEXT],
6651 validator: Lang.isBoolean,
6652 suppressEvent: true,
6656 STRONG_EMPHASIS_CONFIG = {
6657 key: _STRONG_EMPHASIS,
6659 validator: Lang.isBoolean,
6660 suppressEvent: true,
6667 validator: Lang.isBoolean,
6668 suppressEvent: true,
6669 supercedes: [_DISABLED, _SELECTED]
6674 suppressEvent: true,
6675 supercedes: [_DISABLED, _SELECTED]
6681 validator: Lang.isBoolean,
6682 suppressEvent: true,
6683 supercedes: [_TEXT, _SELECTED]
6689 validator: Lang.isBoolean,
6698 CLASS_NAME_CONFIG = {
6701 validator: Lang.isString,
6705 KEY_LISTENER_CONFIG = {
6711 m_oMenuItemTemplate = null,
6717 * @method getClassNameForState
6718 * @description Returns a class name for the specified prefix and state. If the class name does not
6719 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6721 * @param {String} prefix String representing the prefix for the class name
6722 * @param {String} state String representing a state - "disabled," "checked," etc.
6724 var getClassNameForState = function (prefix, state) {
6726 var oClassNames = CLASS_NAMES[prefix];
6729 CLASS_NAMES[prefix] = {};
6730 oClassNames = CLASS_NAMES[prefix];
6734 var sClassName = oClassNames[state];
6737 sClassName = prefix + _HYPHEN + state;
6738 oClassNames[state] = sClassName;
6747 * @method addClassNameForState
6748 * @description Applies a class name to a MenuItem instance's <LI> and <A> elements
6749 * that represents a MenuItem's state - "disabled," "checked," etc.
6751 * @param {String} state String representing a state - "disabled," "checked," etc.
6753 var addClassNameForState = function (state) {
6755 Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6756 Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6761 * @method removeClassNameForState
6762 * @description Removes a class name from a MenuItem instance's <LI> and <A> elements
6763 * that represents a MenuItem's state - "disabled," "checked," etc.
6765 * @param {String} state String representing a state - "disabled," "checked," etc.
6767 var removeClassNameForState = function (state) {
6769 Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6770 Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6775 MenuItem.prototype = {
6778 * @property CSS_CLASS_NAME
6779 * @description String representing the CSS class(es) to be applied to the
6780 * <code><li></code> element of the menu item.
6781 * @default "yuimenuitem"
6785 CSS_CLASS_NAME: "yuimenuitem",
6789 * @property CSS_LABEL_CLASS_NAME
6790 * @description String representing the CSS class(es) to be applied to the
6791 * menu item's <code><a></code> element.
6792 * @default "yuimenuitemlabel"
6796 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6800 * @property SUBMENU_TYPE
6801 * @description Object representing the type of menu to instantiate and
6802 * add when parsing the child nodes of the menu item's source HTML element.
6804 * @type YAHOO.widget.Menu
6810 // Private member variables
6814 * @property _oAnchor
6815 * @description Object reference to the menu item's
6816 * <code><a></code> element.
6819 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6820 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6826 * @property _oHelpTextEM
6827 * @description Object reference to the menu item's help text
6828 * <code><em></code> element.
6831 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6832 * one-html.html#ID-58190037">HTMLElement</a>
6838 * @property _oSubmenu
6839 * @description Object reference to the menu item's submenu.
6842 * @type YAHOO.widget.Menu
6848 * @property _oOnclickAttributeValue
6849 * @description Object reference to the menu item's current value for the
6850 * "onclick" configuration attribute.
6855 _oOnclickAttributeValue: null,
6859 * @property _sClassName
6860 * @description The current value of the "classname" configuration attribute.
6869 // Public properties
6873 * @property constructor
6874 * @description Object reference to the menu item's constructor function.
6875 * @default YAHOO.widget.MenuItem
6876 * @type YAHOO.widget.MenuItem
6878 constructor: MenuItem,
6883 * @description Number indicating the ordinal position of the menu item in
6892 * @property groupIndex
6893 * @description Number indicating the index of the group to which the menu
6903 * @description Object reference to the menu item's parent menu.
6905 * @type YAHOO.widget.Menu
6912 * @description Object reference to the menu item's
6913 * <code><li></code> element.
6914 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6915 * -one-html.html#ID-74680021">HTMLLIElement</a>
6916 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6917 * one-html.html#ID-74680021">HTMLLIElement</a>
6923 * @property srcElement
6924 * @description Object reference to the HTML element (either
6925 * <code><li></code>, <code><optgroup></code> or
6926 * <code><option></code>) used create the menu item.
6927 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6928 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6929 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6930 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6931 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6932 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6933 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6934 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6935 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6936 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6943 * @description Object reference to the menu item's value.
6952 * @deprecated Use YAHOO.env.ua
6953 * @description String representing the browser.
6956 browser: Module.prototype.browser,
6961 * @description Id of the menu item's root <code><li></code>
6962 * element. This property should be set via the constructor using the
6963 * configuration object literal. If an id is not specified, then one will
6964 * be created using the "generateId" method of the Dom utility.
6976 * @event destroyEvent
6977 * @description Fires when the menu item's <code><li></code>
6978 * element is removed from its parent <code><ul></code> element.
6979 * @type YAHOO.util.CustomEvent
6984 * @event mouseOverEvent
6985 * @description Fires when the mouse has entered the menu item. Passes
6986 * back the DOM Event object as an argument.
6987 * @type YAHOO.util.CustomEvent
6992 * @event mouseOutEvent
6993 * @description Fires when the mouse has left the menu item. Passes back
6994 * the DOM Event object as an argument.
6995 * @type YAHOO.util.CustomEvent
7000 * @event mouseDownEvent
7001 * @description Fires when the user mouses down on the menu item. Passes
7002 * back the DOM Event object as an argument.
7003 * @type YAHOO.util.CustomEvent
7008 * @event mouseUpEvent
7009 * @description Fires when the user releases a mouse button while the mouse
7010 * is over the menu item. Passes back the DOM Event object as an argument.
7011 * @type YAHOO.util.CustomEvent
7017 * @description Fires when the user clicks the on the menu item. Passes
7018 * back the DOM Event object as an argument.
7019 * @type YAHOO.util.CustomEvent
7024 * @event keyPressEvent
7025 * @description Fires when the user presses an alphanumeric key when the
7026 * menu item has focus. Passes back the DOM Event object as an argument.
7027 * @type YAHOO.util.CustomEvent
7032 * @event keyDownEvent
7033 * @description Fires when the user presses a key when the menu item has
7034 * focus. Passes back the DOM Event object as an argument.
7035 * @type YAHOO.util.CustomEvent
7041 * @description Fires when the user releases a key when the menu item has
7042 * focus. Passes back the DOM Event object as an argument.
7043 * @type YAHOO.util.CustomEvent
7049 * @description Fires when the menu item receives focus.
7050 * @type YAHOO.util.CustomEvent
7056 * @description Fires when the menu item loses the input focus.
7057 * @type YAHOO.util.CustomEvent
7063 * @description The MenuItem class's initialization method. This method is
7064 * automatically called by the constructor, and sets up all DOM references
7065 * for pre-existing markup, and creates required markup if it is not
7067 * @param {String} p_oObject String specifying the text of the menu item.
7068 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7069 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
7070 * the <code><li></code> element of the menu item.
7071 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7072 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
7073 * specifying the <code><optgroup></code> element of the menu item.
7074 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7075 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
7076 * specifying the <code><option></code> element of the menu item.
7077 * @param {Object} p_oConfig Optional. Object literal specifying the
7078 * configuration for the menu item. See configuration class documentation
7081 init: function (p_oObject, p_oConfig) {
7084 if (!this.SUBMENU_TYPE) {
7086 this.SUBMENU_TYPE = Menu;
7091 // Create the config object
7093 this.cfg = new YAHOO.util.Config(this);
7095 this.initDefaultConfig();
7097 var oConfig = this.cfg,
7108 if (Lang.isString(p_oObject)) {
7110 this._createRootNodeStructure();
7112 oConfig.queueProperty(_TEXT, p_oObject);
7115 else if (p_oObject && p_oObject.tagName) {
7117 switch(p_oObject.tagName.toUpperCase()) {
7121 this._createRootNodeStructure();
7123 oConfig.queueProperty(_TEXT, p_oObject.text);
7124 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7126 this.value = p_oObject.value;
7128 this.srcElement = p_oObject;
7134 this._createRootNodeStructure();
7136 oConfig.queueProperty(_TEXT, p_oObject.label);
7137 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7139 this.srcElement = p_oObject;
7141 this._initSubTree();
7147 // Get the anchor node (if it exists)
7149 oAnchor = Dom.getFirstChild(p_oObject);
7152 // Capture the "text" and/or the "URL"
7156 sURL = oAnchor.getAttribute(_HREF, 2);
7157 sTarget = oAnchor.getAttribute(_TARGET);
7159 sText = oAnchor.innerHTML;
7163 this.srcElement = p_oObject;
7164 this.element = p_oObject;
7165 this._oAnchor = oAnchor;
7168 Set these properties silently to sync up the
7169 configuration object without making changes to the
7173 oConfig.setProperty(_TEXT, sText, true);
7174 oConfig.setProperty(_URL, sURL, true);
7175 oConfig.setProperty(_TARGET, sTarget, true);
7177 this._initSubTree();
7188 sId = (this.srcElement || this.element).id;
7192 sId = this.id || Dom.generateId();
7194 this.element.id = sId;
7201 Dom.addClass(this.element, this.CSS_CLASS_NAME);
7202 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7205 i = EVENT_TYPES.length - 1;
7209 aEventData = EVENT_TYPES[i];
7211 oCustomEvent = this.createEvent(aEventData[1]);
7212 oCustomEvent.signature = CustomEvent.LIST;
7214 this[aEventData[0]] = oCustomEvent;
7222 oConfig.applyConfig(p_oConfig);
7226 oConfig.fireQueue();
7237 * @method _createRootNodeStructure
7238 * @description Creates the core DOM structure for the menu item.
7241 _createRootNodeStructure: function () {
7246 if (!m_oMenuItemTemplate) {
7248 m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7249 m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7253 oElement = m_oMenuItemTemplate.cloneNode(true);
7254 oElement.className = this.CSS_CLASS_NAME;
7256 oAnchor = oElement.firstChild;
7257 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7259 this.element = oElement;
7260 this._oAnchor = oAnchor;
7266 * @method _initSubTree
7267 * @description Iterates the source element's childNodes collection and uses
7268 * the child nodes to instantiate other menus.
7271 _initSubTree: function () {
7273 var oSrcEl = this.srcElement,
7282 if (oSrcEl.childNodes.length > 0) {
7284 if (this.parent.lazyLoad && this.parent.srcElement &&
7285 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7287 oConfig.setProperty(
7289 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7295 oNode = oSrcEl.firstChild;
7300 if (oNode && oNode.tagName) {
7302 switch(oNode.tagName.toUpperCase()) {
7306 oConfig.setProperty(_SUBMENU, oNode);
7312 aOptions[aOptions.length] = oNode;
7321 while((oNode = oNode.nextSibling));
7324 nOptions = aOptions.length;
7328 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7330 oConfig.setProperty(_SUBMENU, oMenu);
7332 for(n=0; n<nOptions; n++) {
7334 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7348 // Event handlers for configuration properties
7352 * @method configText
7353 * @description Event handler for when the "text" configuration property of
7354 * the menu item changes.
7355 * @param {String} p_sType String representing the name of the event that
7357 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7358 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7359 * that fired the event.
7361 configText: function (p_sType, p_aArgs, p_oItem) {
7363 var sText = p_aArgs[0],
7365 oAnchor = this._oAnchor,
7366 sHelpText = oConfig.getProperty(_HELP_TEXT),
7367 sHelpTextHTML = _EMPTY_STRING,
7368 sEmphasisStartTag = _EMPTY_STRING,
7369 sEmphasisEndTag = _EMPTY_STRING;
7377 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7382 if (oConfig.getProperty(_EMPHASIS)) {
7384 sEmphasisStartTag = _START_EM;
7385 sEmphasisEndTag = _END_EM;
7390 if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7392 sEmphasisStartTag = _START_STRONG;
7393 sEmphasisEndTag = _END_STRONG;
7398 oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7406 * @method configHelpText
7407 * @description Event handler for when the "helptext" configuration property
7408 * of the menu item changes.
7409 * @param {String} p_sType String representing the name of the event that
7411 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7412 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7413 * that fired the event.
7415 configHelpText: function (p_sType, p_aArgs, p_oItem) {
7417 this.cfg.refireEvent(_TEXT);
7424 * @description Event handler for when the "url" configuration property of
7425 * the menu item changes.
7426 * @param {String} p_sType String representing the name of the event that
7428 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7429 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7430 * that fired the event.
7432 configURL: function (p_sType, p_aArgs, p_oItem) {
7434 var sURL = p_aArgs[0];
7442 var oAnchor = this._oAnchor;
7446 oAnchor.removeAttribute(_HREF);
7450 oAnchor.setAttribute(_HREF, sURL);
7456 * @method configTarget
7457 * @description Event handler for when the "target" configuration property
7458 * of the menu item changes.
7459 * @param {String} p_sType String representing the name of the event that
7461 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7462 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7463 * that fired the event.
7465 configTarget: function (p_sType, p_aArgs, p_oItem) {
7467 var sTarget = p_aArgs[0],
7468 oAnchor = this._oAnchor;
7470 if (sTarget && sTarget.length > 0) {
7472 oAnchor.setAttribute(_TARGET, sTarget);
7477 oAnchor.removeAttribute(_TARGET);
7485 * @method configEmphasis
7486 * @description Event handler for when the "emphasis" configuration property
7487 * of the menu item changes.
7488 * @param {String} p_sType String representing the name of the event that
7490 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7491 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7492 * that fired the event.
7494 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7496 var bEmphasis = p_aArgs[0],
7500 if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7502 oConfig.setProperty(_STRONG_EMPHASIS, false);
7507 oConfig.refireEvent(_TEXT);
7513 * @method configStrongEmphasis
7514 * @description Event handler for when the "strongemphasis" configuration
7515 * property of the menu item changes.
7516 * @param {String} p_sType String representing the name of the event that
7518 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7519 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7520 * that fired the event.
7522 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7524 var bStrongEmphasis = p_aArgs[0],
7528 if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7530 oConfig.setProperty(_EMPHASIS, false);
7534 oConfig.refireEvent(_TEXT);
7540 * @method configChecked
7541 * @description Event handler for when the "checked" configuration property
7542 * of the menu item changes.
7543 * @param {String} p_sType String representing the name of the event that
7545 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7546 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7547 * that fired the event.
7549 configChecked: function (p_sType, p_aArgs, p_oItem) {
7551 var bChecked = p_aArgs[0],
7557 addClassNameForState.call(this, _CHECKED);
7562 removeClassNameForState.call(this, _CHECKED);
7566 oConfig.refireEvent(_TEXT);
7569 if (oConfig.getProperty(_DISABLED)) {
7571 oConfig.refireEvent(_DISABLED);
7576 if (oConfig.getProperty(_SELECTED)) {
7578 oConfig.refireEvent(_SELECTED);
7587 * @method configDisabled
7588 * @description Event handler for when the "disabled" configuration property
7589 * of the menu item changes.
7590 * @param {String} p_sType String representing the name of the event that
7592 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7593 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7594 * that fired the event.
7596 configDisabled: function (p_sType, p_aArgs, p_oItem) {
7598 var bDisabled = p_aArgs[0],
7600 oSubmenu = oConfig.getProperty(_SUBMENU),
7601 bChecked = oConfig.getProperty(_CHECKED);
7606 if (oConfig.getProperty(_SELECTED)) {
7608 oConfig.setProperty(_SELECTED, false);
7613 addClassNameForState.call(this, _DISABLED);
7618 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7625 addClassNameForState.call(this, _CHECKED_DISABLED);
7632 removeClassNameForState.call(this, _DISABLED);
7637 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7644 removeClassNameForState.call(this, _CHECKED_DISABLED);
7654 * @method configSelected
7655 * @description Event handler for when the "selected" configuration property
7656 * of the menu item changes.
7657 * @param {String} p_sType String representing the name of the event that
7659 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7660 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7661 * that fired the event.
7663 configSelected: function (p_sType, p_aArgs, p_oItem) {
7665 var oConfig = this.cfg,
7666 oAnchor = this._oAnchor,
7668 bSelected = p_aArgs[0],
7669 bChecked = oConfig.getProperty(_CHECKED),
7670 oSubmenu = oConfig.getProperty(_SUBMENU);
7680 if (bSelected && !oConfig.getProperty(_DISABLED)) {
7682 addClassNameForState.call(this, _SELECTED);
7687 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7694 addClassNameForState.call(this, _CHECKED_SELECTED);
7701 removeClassNameForState.call(this, _SELECTED);
7706 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7713 removeClassNameForState.call(this, _CHECKED_SELECTED);
7720 if (this.hasFocus() && UA.opera) {
7730 * @method _onSubmenuBeforeHide
7731 * @description "beforehide" Custom Event handler for a submenu.
7733 * @param {String} p_sType String representing the name of the event that
7735 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7737 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7739 var oItem = this.parent,
7744 oItem._oAnchor.blur();
7745 oMenu.beforeHideEvent.unsubscribe(onHide);
7750 if (oItem.hasFocus()) {
7752 oMenu = oItem.parent;
7754 oMenu.beforeHideEvent.subscribe(onHide);
7762 * @method configSubmenu
7763 * @description Event handler for when the "submenu" configuration property
7764 * of the menu item changes.
7765 * @param {String} p_sType String representing the name of the event that
7767 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7768 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7769 * that fired the event.
7771 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7773 var oSubmenu = p_aArgs[0],
7775 bLazyLoad = this.parent && this.parent.lazyLoad,
7783 if (oSubmenu instanceof Menu) {
7786 oMenu.parent = this;
7787 oMenu.lazyLoad = bLazyLoad;
7790 else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7792 sSubmenuId = oSubmenu.id;
7793 oSubmenuConfig = oSubmenu;
7795 oSubmenuConfig.lazyload = bLazyLoad;
7796 oSubmenuConfig.parent = this;
7798 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7801 // Set the value of the property to the Menu instance
7803 oConfig.setProperty(_SUBMENU, oMenu, true);
7808 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7811 // Set the value of the property to the Menu instance
7813 oConfig.setProperty(_SUBMENU, oMenu, true);
7820 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7822 addClassNameForState.call(this, _HAS_SUBMENU);
7825 if (oConfig.getProperty(_URL) === _HASH) {
7827 oConfig.setProperty(_URL, (_HASH + oMenu.id));
7832 this._oSubmenu = oMenu;
7837 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7846 removeClassNameForState.call(this, _HAS_SUBMENU);
7848 if (this._oSubmenu) {
7850 this._oSubmenu.destroy();
7857 if (oConfig.getProperty(_DISABLED)) {
7859 oConfig.refireEvent(_DISABLED);
7864 if (oConfig.getProperty(_SELECTED)) {
7866 oConfig.refireEvent(_SELECTED);
7874 * @method configOnClick
7875 * @description Event handler for when the "onclick" configuration property
7876 * of the menu item changes.
7877 * @param {String} p_sType String representing the name of the event that
7879 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7880 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7881 * that fired the event.
7883 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7885 var oObject = p_aArgs[0];
7888 Remove any existing listeners if a "click" event handler has
7889 already been specified.
7892 if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7894 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7895 this._oOnclickAttributeValue.obj);
7897 this._oOnclickAttributeValue = null;
7902 if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
7903 Lang.isFunction(oObject.fn)) {
7905 this.clickEvent.subscribe(oObject.fn,
7906 ((_OBJ in oObject) ? oObject.obj : this),
7907 ((_SCOPE in oObject) ? oObject.scope : null) );
7909 this._oOnclickAttributeValue = oObject;
7917 * @method configClassName
7918 * @description Event handler for when the "classname" configuration
7919 * property of a menu item changes.
7920 * @param {String} p_sType String representing the name of the event that
7922 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7923 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7924 * that fired the event.
7926 configClassName: function (p_sType, p_aArgs, p_oItem) {
7928 var sClassName = p_aArgs[0];
7930 if (this._sClassName) {
7932 Dom.removeClass(this.element, this._sClassName);
7936 Dom.addClass(this.element, sClassName);
7937 this._sClassName = sClassName;
7943 * @method _dispatchClickEvent
7944 * @description Dispatches a DOM "click" event to the anchor element of a
7945 * MenuItem instance.
7948 _dispatchClickEvent: function () {
7950 var oMenuItem = this,
7954 if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7956 oAnchor = Dom.getFirstChild(oMenuItem.element);
7958 // Dispatch a "click" event to the MenuItem's anchor so that its
7959 // "click" event handlers will get called in response to the user
7960 // pressing the keyboard shortcut defined by the "keylistener"
7961 // configuration property.
7964 oAnchor.fireEvent(_ONCLICK);
7968 if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7970 oEvent = document.createEvent("HTMLEvents");
7971 oEvent.initEvent(_CLICK, true, true);
7976 oEvent = document.createEvent("MouseEvents");
7977 oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0,
7978 0, 0, false, false, false, false, 0, null);
7982 oAnchor.dispatchEvent(oEvent);
7992 * @method _createKeyListener
7993 * @description "show" event handler for a Menu instance - responsible for
7994 * setting up the KeyListener instance for a MenuItem.
7996 * @param {String} type String representing the name of the event that
7998 * @param {Array} args Array of arguments sent when the event was fired.
7999 * @param {Array} keyData Array of arguments sent when the event was fired.
8001 _createKeyListener: function (type, args, keyData) {
8003 var oMenuItem = this,
8004 oMenu = oMenuItem.parent;
8006 var oKeyListener = new YAHOO.util.KeyListener(
8007 oMenu.element.ownerDocument,
8010 fn: oMenuItem._dispatchClickEvent,
8012 correctScope: true });
8015 if (oMenu.cfg.getProperty(_VISIBLE)) {
8016 oKeyListener.enable();
8020 oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
8021 oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
8023 oMenuItem._keyListener = oKeyListener;
8025 oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
8031 * @method configKeyListener
8032 * @description Event handler for when the "keylistener" configuration
8033 * property of a menu item changes.
8034 * @param {String} p_sType String representing the name of the event that
8036 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8038 configKeyListener: function (p_sType, p_aArgs) {
8040 var oKeyData = p_aArgs[0],
8042 oMenu = oMenuItem.parent;
8044 if (oMenuItem._keyData) {
8046 // Unsubscribe from the "show" event in case the keylistener
8047 // config was changed before the Menu was ever made visible.
8049 oMenu.unsubscribe(_SHOW,
8050 oMenuItem._createKeyListener, oMenuItem._keyData);
8052 oMenuItem._keyData = null;
8057 // Tear down for the previous value of the "keylistener" property
8059 if (oMenuItem._keyListener) {
8061 oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
8062 oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
8064 oMenuItem._keyListener.disable();
8065 oMenuItem._keyListener = null;
8072 oMenuItem._keyData = oKeyData;
8074 // Defer the creation of the KeyListener instance until the
8075 // parent Menu is visible. This is necessary since the
8076 // KeyListener instance needs to be bound to the document the
8077 // Menu has been rendered into. Deferring creation of the
8078 // KeyListener instance also improves performance.
8080 oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
8081 oKeyData, oMenuItem);
8091 * @method initDefaultConfig
8092 * @description Initializes an item's configurable properties.
8094 initDefaultConfig : function () {
8096 var oConfig = this.cfg;
8099 // Define the configuration attributes
8103 * @description String specifying the text label for the menu item.
8104 * When building a menu from existing HTML the value of this property
8105 * will be interpreted from the menu's markup.
8109 oConfig.addProperty(
8112 handler: this.configText,
8113 value: TEXT_CONFIG.value,
8114 validator: TEXT_CONFIG.validator,
8115 suppressEvent: TEXT_CONFIG.suppressEvent
8122 * @description String specifying additional instructional text to
8123 * accompany the text for the menu item.
8124 * @deprecated Use "text" configuration property to add help text markup.
8125 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em
8126 * class=\"helptext\">Ctrl + C</em>");</code>
8128 * @type String|<a href="http://www.w3.org/TR/
8129 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8132 oConfig.addProperty(
8133 HELP_TEXT_CONFIG.key,
8135 handler: this.configHelpText,
8136 supercedes: HELP_TEXT_CONFIG.supercedes,
8137 suppressEvent: HELP_TEXT_CONFIG.suppressEvent
8144 * @description String specifying the URL for the menu item's anchor's
8145 * "href" attribute. When building a menu from existing HTML the value
8146 * of this property will be interpreted from the menu's markup.
8150 oConfig.addProperty(
8153 handler: this.configURL,
8154 value: URL_CONFIG.value,
8155 suppressEvent: URL_CONFIG.suppressEvent
8162 * @description String specifying the value for the "target" attribute
8163 * of the menu item's anchor element. <strong>Specifying a target will
8164 * require the user to click directly on the menu item's anchor node in
8165 * order to cause the browser to navigate to the specified URL.</strong>
8166 * When building a menu from existing HTML the value of this property
8167 * will be interpreted from the menu's markup.
8171 oConfig.addProperty(
8174 handler: this.configTarget,
8175 suppressEvent: TARGET_CONFIG.suppressEvent
8182 * @description Boolean indicating if the text of the menu item will be
8183 * rendered with emphasis.
8184 * @deprecated Use the "text" configuration property to add emphasis.
8185 * For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some
8186 * Text</em>");</code>
8190 oConfig.addProperty(
8191 EMPHASIS_CONFIG.key,
8193 handler: this.configEmphasis,
8194 value: EMPHASIS_CONFIG.value,
8195 validator: EMPHASIS_CONFIG.validator,
8196 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8197 supercedes: EMPHASIS_CONFIG.supercedes
8203 * @config strongemphasis
8204 * @description Boolean indicating if the text of the menu item will be
8205 * rendered with strong emphasis.
8206 * @deprecated Use the "text" configuration property to add strong emphasis.
8207 * For example: <code>oMenuItem.cfg.setProperty("text", "<strong>
8208 * Some Text</strong>");</code>
8212 oConfig.addProperty(
8213 STRONG_EMPHASIS_CONFIG.key,
8215 handler: this.configStrongEmphasis,
8216 value: STRONG_EMPHASIS_CONFIG.value,
8217 validator: STRONG_EMPHASIS_CONFIG.validator,
8218 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8219 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8226 * @description Boolean indicating if the menu item should be rendered
8231 oConfig.addProperty(
8234 handler: this.configChecked,
8235 value: CHECKED_CONFIG.value,
8236 validator: CHECKED_CONFIG.validator,
8237 suppressEvent: CHECKED_CONFIG.suppressEvent,
8238 supercedes: CHECKED_CONFIG.supercedes
8245 * @description Boolean indicating if the menu item should be disabled.
8246 * (Disabled menu items are dimmed and will not respond to user input
8251 oConfig.addProperty(
8252 DISABLED_CONFIG.key,
8254 handler: this.configDisabled,
8255 value: DISABLED_CONFIG.value,
8256 validator: DISABLED_CONFIG.validator,
8257 suppressEvent: DISABLED_CONFIG.suppressEvent
8264 * @description Boolean indicating if the menu item should
8269 oConfig.addProperty(
8270 SELECTED_CONFIG.key,
8272 handler: this.configSelected,
8273 value: SELECTED_CONFIG.value,
8274 validator: SELECTED_CONFIG.validator,
8275 suppressEvent: SELECTED_CONFIG.suppressEvent
8282 * @description Object specifying the submenu to be appended to the
8283 * menu item. The value can be one of the following: <ul><li>Object
8284 * specifying a Menu instance.</li><li>Object literal specifying the
8285 * menu to be created. Format: <code>{ id: [menu id], itemdata:
8286 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
8287 * items</a>] }</code>.</li><li>String specifying the id attribute
8288 * of the <code><div></code> element of the menu.</li><li>
8289 * Object specifying the <code><div></code> element of the
8292 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8293 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8296 oConfig.addProperty(
8299 handler: this.configSubmenu,
8300 supercedes: SUBMENU_CONFIG.supercedes,
8301 suppressEvent: SUBMENU_CONFIG.suppressEvent
8308 * @description Object literal representing the code to be executed when
8309 * the item is clicked. Format:<br> <code> {<br>
8310 * <strong>fn:</strong> Function, // The handler to call when
8311 * the event fires.<br> <strong>obj:</strong> Object, // An
8312 * object to pass back to the handler.<br> <strong>scope:</strong>
8313 * Object // The object to use for the scope of the handler.
8318 oConfig.addProperty(
8321 handler: this.configOnClick,
8322 suppressEvent: ONCLICK_CONFIG.suppressEvent
8329 * @description CSS class to be applied to the menu item's root
8330 * <code><li></code> element. The specified class(es) are
8331 * appended in addition to the default class as specified by the menu
8332 * item's CSS_CLASS_NAME constant.
8336 oConfig.addProperty(
8337 CLASS_NAME_CONFIG.key,
8339 handler: this.configClassName,
8340 value: CLASS_NAME_CONFIG.value,
8341 validator: CLASS_NAME_CONFIG.validator,
8342 suppressEvent: CLASS_NAME_CONFIG.suppressEvent
8348 * @config keylistener
8349 * @description Object literal representing the key(s) that can be used
8350 * to trigger the MenuItem's "click" event. Possible attributes are
8351 * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
8352 * or an array of ints representing keycodes).
8356 oConfig.addProperty(
8357 KEY_LISTENER_CONFIG.key,
8359 handler: this.configKeyListener,
8360 value: KEY_LISTENER_CONFIG.value,
8361 suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
8368 * @method getNextSibling
8369 * @description Finds the menu item's next sibling.
8370 * @return YAHOO.widget.MenuItem
8372 getNextSibling: function () {
8374 var isUL = function (el) {
8375 return (el.nodeName.toLowerCase() === "ul");
8378 menuitemEl = this.element,
8379 next = Dom.getNextSibling(menuitemEl),
8386 parent = menuitemEl.parentNode;
8387 sibling = Dom.getNextSiblingBy(parent, isUL);
8393 list = Dom.getFirstChildBy(parent.parentNode, isUL);
8396 next = Dom.getFirstChild(list);
8400 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8405 * @method getNextEnabledSibling
8406 * @description Finds the menu item's next enabled sibling.
8407 * @return YAHOO.widget.MenuItem
8409 getNextEnabledSibling: function () {
8411 var next = this.getNextSibling();
8413 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
8419 * @method getPreviousSibling
8420 * @description Finds the menu item's previous sibling.
8421 * @return {YAHOO.widget.MenuItem}
8423 getPreviousSibling: function () {
8425 var isUL = function (el) {
8426 return (el.nodeName.toLowerCase() === "ul");
8429 menuitemEl = this.element,
8430 next = Dom.getPreviousSibling(menuitemEl),
8437 parent = menuitemEl.parentNode;
8438 sibling = Dom.getPreviousSiblingBy(parent, isUL);
8444 list = Dom.getLastChildBy(parent.parentNode, isUL);
8447 next = Dom.getLastChild(list);
8451 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8457 * @method getPreviousEnabledSibling
8458 * @description Finds the menu item's previous enabled sibling.
8459 * @return {YAHOO.widget.MenuItem}
8461 getPreviousEnabledSibling: function () {
8463 var next = this.getPreviousSibling();
8465 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
8472 * @description Causes the menu item to receive the focus and fires the
8475 focus: function () {
8477 var oParent = this.parent,
8478 oAnchor = this._oAnchor,
8479 oActiveItem = oParent.activeItem;
8482 function setFocus() {
8486 if (!(UA.ie && !document.hasFocus())) {
8490 oActiveItem.blurEvent.fire();
8496 this.focusEvent.fire();
8508 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
8509 this.element.style.display != _NONE) {
8513 Setting focus via a timer fixes a race condition in Firefox, IE
8514 and Opera where the browser viewport jumps as it trys to
8515 position and focus the menu.
8518 Lang.later(0, this, setFocus);
8527 * @description Causes the menu item to lose focus and fires the
8532 var oParent = this.parent;
8534 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8536 Lang.later(0, this, function () {
8540 this._oAnchor.blur();
8541 this.blurEvent.fire();
8557 * @description Returns a boolean indicating whether or not the menu item
8561 hasFocus: function () {
8563 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8570 * @description Removes the menu item's <code><li></code> element
8571 * from its parent <code><ul></code> element.
8573 destroy: function () {
8575 var oEl = this.element,
8585 // If the item has a submenu, destroy it first
8587 oSubmenu = this.cfg.getProperty(_SUBMENU);
8596 // Remove the element from the parent node
8598 oParentNode = oEl.parentNode;
8602 oParentNode.removeChild(oEl);
8604 this.destroyEvent.fire();
8609 // Remove CustomEvent listeners
8611 i = EVENT_TYPES.length - 1;
8615 aEventData = EVENT_TYPES[i];
8617 this[aEventData[0]].unsubscribeAll();
8623 this.cfg.configChangedEvent.unsubscribeAll();
8632 * @description Returns a string representing the menu item.
8635 toString: function () {
8637 var sReturnVal = _MENUITEM,
8642 sReturnVal += (_SPACE + sId);
8652 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8658 _MOUSEDOWN = "mousedown",
8659 _CONTEXTMENU = "ContextMenu",
8663 * Creates a list of options or commands which are made visible in response to
8664 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8666 * @param {String} p_oElement String specifying the id attribute of the
8667 * <code><div></code> element of the context menu.
8668 * @param {String} p_oElement String specifying the id attribute of the
8669 * <code><select></code> element to be used as the data source for the
8671 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8672 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8673 * <code><div></code> element of the context menu.
8674 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8675 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8676 * the <code><select></code> element to be used as the data source for
8678 * @param {Object} p_oConfig Optional. Object literal specifying the
8679 * configuration for the context menu. See configuration class documentation
8681 * @class ContextMenu
8683 * @extends YAHOO.widget.Menu
8684 * @namespace YAHOO.widget
8686 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8688 YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8693 var Event = YAHOO.util.Event,
8695 ContextMenu = YAHOO.widget.ContextMenu,
8700 * Constant representing the name of the ContextMenu's events
8701 * @property EVENT_TYPES
8708 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8709 "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8716 * Constant representing the ContextMenu's configuration properties
8717 * @property DEFAULT_CONFIG
8730 * @description "beforeShow" event handler used to position the contextmenu.
8732 * @param {String} p_sType String representing the name of the event that
8734 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8735 * @param {Array} p_aPos Array representing the xy position for the context menu.
8737 function position(p_sType, p_aArgs, p_aPos) {
8739 this.cfg.setProperty(_XY, p_aPos);
8741 this.beforeShowEvent.unsubscribe(position, p_aPos);
8746 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8750 // Private properties
8754 * @property _oTrigger
8755 * @description Object reference to the current value of the "trigger"
8756 * configuration property.
8759 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8760 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8766 * @property _bCancelled
8767 * @description Boolean indicating if the display of the context menu should
8777 // Public properties
8781 * @property contextEventTarget
8782 * @description Object reference for the HTML element that was the target of the
8783 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8786 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8787 * html.html#ID-58190037">HTMLElement</a>
8789 contextEventTarget: null,
8797 * @event triggerContextMenuEvent
8798 * @description Custom Event wrapper for the "contextmenu" DOM event
8799 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8802 triggerContextMenuEvent: null,
8808 * @description The ContextMenu class's initialization method. This method is
8809 * automatically called by the constructor, and sets up all DOM references for
8810 * pre-existing markup, and creates required markup if it is not already present.
8811 * @param {String} p_oElement String specifying the id attribute of the
8812 * <code><div></code> element of the context menu.
8813 * @param {String} p_oElement String specifying the id attribute of the
8814 * <code><select></code> element to be used as the data source for
8816 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8817 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8818 * <code><div></code> element of the context menu.
8819 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8820 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8821 * the <code><select></code> element to be used as the data source for
8823 * @param {Object} p_oConfig Optional. Object literal specifying the
8824 * configuration for the context menu. See configuration class documentation
8827 init: function(p_oElement, p_oConfig) {
8830 // Call the init of the superclass (YAHOO.widget.Menu)
8832 ContextMenu.superclass.init.call(this, p_oElement);
8835 this.beforeInitEvent.fire(ContextMenu);
8840 this.cfg.applyConfig(p_oConfig, true);
8844 this.initEvent.fire(ContextMenu);
8850 * @method initEvents
8851 * @description Initializes the custom events for the context menu.
8853 initEvents: function() {
8855 ContextMenu.superclass.initEvents.call(this);
8857 // Create custom events
8859 this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8861 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8868 * @description Cancels the display of the context menu.
8870 cancel: function() {
8872 this._bCancelled = true;
8882 * @method _removeEventHandlers
8883 * @description Removes all of the DOM event handlers from the HTML element(s)
8884 * whose "context menu" event ("click" for Opera) trigger the display of
8888 _removeEventHandlers: function() {
8890 var oTrigger = this._oTrigger;
8893 // Remove the event handlers from the trigger(s)
8897 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
8901 Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8911 // Private event handlers
8916 * @method _onTriggerClick
8917 * @description "click" event handler for the HTML element(s) identified as the
8918 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8920 * @param {Event} p_oEvent Object representing the DOM event object passed back
8921 * by the event utility (YAHOO.util.Event).
8922 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8923 * menu that is handling the event.
8925 _onTriggerClick: function(p_oEvent, p_oMenu) {
8927 if (p_oEvent.ctrlKey) {
8929 Event.stopEvent(p_oEvent);
8937 * @method _onTriggerContextMenu
8938 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8939 * element(s) that trigger the display of the context menu.
8941 * @param {Event} p_oEvent Object representing the DOM event object passed back
8942 * by the event utility (YAHOO.util.Event).
8943 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8944 * menu that is handling the event.
8946 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8950 if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8952 this.contextEventTarget = Event.getTarget(p_oEvent);
8954 this.triggerContextMenuEvent.fire(p_oEvent);
8957 if (!this._bCancelled) {
8960 Prevent the browser's default context menu from appearing and
8961 stop the propagation of the "contextmenu" event so that
8962 other ContextMenu instances are not displayed.
8965 Event.stopEvent(p_oEvent);
8968 // Hide any other Menu instances that might be visible
8970 YAHOO.widget.MenuManager.hideVisible();
8974 // Position and display the context menu
8976 aXY = Event.getXY(p_oEvent);
8979 if (!YAHOO.util.Dom.inDocument(this.element)) {
8981 this.beforeShowEvent.subscribe(position, aXY);
8986 this.cfg.setProperty(_XY, aXY);
8995 this._bCancelled = false;
9008 * @description Returns a string representing the context menu.
9011 toString: function() {
9013 var sReturnVal = _CONTEXTMENU,
9018 sReturnVal += (_SPACE + sId);
9028 * @method initDefaultConfig
9029 * @description Initializes the class's configurable properties which can be
9030 * changed using the context menu's Config object ("cfg").
9032 initDefaultConfig: function() {
9034 ContextMenu.superclass.initDefaultConfig.call(this);
9038 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
9039 * for Opera) trigger the display of the context menu. Can be a string
9040 * representing the id attribute of the HTML element, an object reference
9041 * for the HTML element, or an array of strings or HTML element references.
9043 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
9044 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
9046 this.cfg.addProperty(TRIGGER_CONFIG.key,
9048 handler: this.configTrigger,
9049 suppressEvent: TRIGGER_CONFIG.suppressEvent
9058 * @description Removes the context menu's <code><div></code> element
9059 * (and accompanying child nodes) from the document.
9061 destroy: function() {
9063 // Remove the DOM event handlers from the current trigger(s)
9065 this._removeEventHandlers();
9068 // Continue with the superclass implementation of this method
9070 ContextMenu.superclass.destroy.call(this);
9076 // Public event handlers for configuration properties
9080 * @method configTrigger
9081 * @description Event handler for when the value of the "trigger" configuration
9083 * @param {String} p_sType String representing the name of the event that
9085 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9086 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
9087 * menu that fired the event.
9089 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
9091 var oTrigger = p_aArgs[0];
9096 If there is a current "trigger" - remove the event handlers
9097 from that element(s) before assigning new ones
9100 if (this._oTrigger) {
9102 this._removeEventHandlers();
9106 this._oTrigger = oTrigger;
9110 Listen for the "mousedown" event in Opera b/c it does not
9111 support the "contextmenu" event
9114 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9118 Assign a "click" event handler to the trigger element(s) for
9119 Opera to prevent default browser behaviors.
9124 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9131 this._removeEventHandlers();
9137 }); // END YAHOO.lang.extend
9144 * Creates an item for a context menu.
9146 * @param {String} p_oObject String specifying the text of the context menu item.
9147 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9148 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9149 * <code><li></code> element of the context menu item.
9150 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9151 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9152 * specifying the <code><optgroup></code> element of the context
9154 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9155 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9156 * the <code><option></code> element of the context menu item.
9157 * @param {Object} p_oConfig Optional. Object literal specifying the
9158 * configuration for the context menu item. See configuration class
9159 * documentation for more details.
9160 * @class ContextMenuItem
9162 * @extends YAHOO.widget.MenuItem
9163 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9164 * are of type YAHOO.widget.MenuItem.
9166 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9169 var Lang = YAHOO.lang,
9174 _DYNAMIC_STATIC = "dynamic," + _STATIC,
9175 _DISABLED = "disabled",
9176 _SELECTED = "selected",
9177 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9178 _SUBMENU = "submenu",
9179 _VISIBLE = "visible",
9181 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9182 _MENUBAR = "MenuBar";
9185 * Horizontal collection of items, each of which can contain a submenu.
9187 * @param {String} p_oElement String specifying the id attribute of the
9188 * <code><div></code> element of the menu bar.
9189 * @param {String} p_oElement String specifying the id attribute of the
9190 * <code><select></code> element to be used as the data source for the
9192 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9193 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9194 * the <code><div></code> element of the menu bar.
9195 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9196 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9197 * specifying the <code><select></code> element to be used as the data
9198 * source for the menu bar.
9199 * @param {Object} p_oConfig Optional. Object literal specifying the
9200 * configuration for the menu bar. See configuration class documentation for
9204 * @extends YAHOO.widget.Menu
9205 * @namespace YAHOO.widget
9207 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9209 YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9215 * @method checkPosition
9216 * @description Checks to make sure that the value of the "position" property
9217 * is one of the supported strings. Returns true if the position is supported.
9219 * @param {Object} p_sPosition String specifying the position of the menu.
9222 function checkPosition(p_sPosition) {
9224 var returnVal = false;
9226 if (Lang.isString(p_sPosition)) {
9228 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9237 var Event = YAHOO.util.Event,
9238 MenuBar = YAHOO.widget.MenuBar,
9243 validator: checkPosition,
9244 supercedes: [_VISIBLE]
9247 SUBMENU_ALIGNMENT_CONFIG = {
9248 key: "submenualignment",
9252 AUTO_SUBMENU_DISPLAY_CONFIG = {
9253 key: _AUTO_SUBMENU_DISPLAY,
9255 validator: Lang.isBoolean,
9259 SUBMENU_TOGGLE_REGION_CONFIG = {
9260 key: _SUBMENU_TOGGLE_REGION,
9262 validator: Lang.isBoolean
9267 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9271 * @description The MenuBar class's initialization method. This method is
9272 * automatically called by the constructor, and sets up all DOM references for
9273 * pre-existing markup, and creates required markup if it is not already present.
9274 * @param {String} p_oElement String specifying the id attribute of the
9275 * <code><div></code> element of the menu bar.
9276 * @param {String} p_oElement String specifying the id attribute of the
9277 * <code><select></code> element to be used as the data source for the
9279 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9280 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9281 * the <code><div></code> element of the menu bar.
9282 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9283 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9284 * specifying the <code><select></code> element to be used as the data
9285 * source for the menu bar.
9286 * @param {Object} p_oConfig Optional. Object literal specifying the
9287 * configuration for the menu bar. See configuration class documentation for
9290 init: function(p_oElement, p_oConfig) {
9292 if(!this.ITEM_TYPE) {
9294 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9299 // Call the init of the superclass (YAHOO.widget.Menu)
9301 MenuBar.superclass.init.call(this, p_oElement);
9304 this.beforeInitEvent.fire(MenuBar);
9309 this.cfg.applyConfig(p_oConfig, true);
9313 this.initEvent.fire(MenuBar);
9323 * @property CSS_CLASS_NAME
9324 * @description String representing the CSS class(es) to be applied to the menu
9325 * bar's <code><div></code> element.
9326 * @default "yuimenubar"
9330 CSS_CLASS_NAME: "yuimenubar",
9334 * @property SUBMENU_TOGGLE_REGION_WIDTH
9335 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9336 * display of the MenuBarItem's submenu.
9341 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9344 // Protected event handlers
9348 * @method _onKeyDown
9349 * @description "keydown" Custom Event handler for the menu bar.
9351 * @param {String} p_sType String representing the name of the event that
9353 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9354 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9355 * that fired the event.
9357 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9359 var oEvent = p_aArgs[0],
9366 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9368 oItemCfg = oItem.cfg;
9370 switch(oEvent.keyCode) {
9372 case 37: // Left arrow
9373 case 39: // Right arrow
9375 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9377 oItemCfg.setProperty(_SELECTED, true);
9382 oNextItem = (oEvent.keyCode == 37) ?
9383 oItem.getPreviousEnabledSibling() :
9384 oItem.getNextEnabledSibling();
9388 this.clearActiveItem();
9390 oNextItem.cfg.setProperty(_SELECTED, true);
9392 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9397 oSubmenu.setInitialFocus();
9408 Event.preventDefault(oEvent);
9412 case 40: // Down arrow
9414 if(this.activeItem != oItem) {
9416 this.clearActiveItem();
9418 oItemCfg.setProperty(_SELECTED, true);
9423 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9427 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9429 oSubmenu.setInitialSelection();
9430 oSubmenu.setInitialFocus();
9436 oSubmenu.setInitialFocus();
9442 Event.preventDefault(oEvent);
9451 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9453 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9455 if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9458 this.activeItem.focus();
9463 this.activeItem.cfg.setProperty(_SELECTED, false);
9464 this.activeItem.blur();
9468 Event.preventDefault(oEvent);
9477 * @description "click" event handler for the menu bar.
9479 * @param {String} p_sType String representing the name of the event that
9481 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9482 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9483 * that fired the event.
9485 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9487 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9489 var oItem = p_aArgs[1],
9501 var toggleSubmenuDisplay = function () {
9503 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9517 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9519 oEvent = p_aArgs[0];
9520 oTarget = Event.getTarget(oEvent);
9521 oActiveItem = this.activeItem;
9525 // Hide any other submenus that might be visible
9527 if(oActiveItem && oActiveItem != oItem) {
9529 this.clearActiveItem();
9534 oItem.cfg.setProperty(_SELECTED, true);
9537 // Show the submenu for the item
9539 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9544 oItemEl = oItem.element;
9545 nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9546 nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9548 if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9550 if (Event.getPageX(oEvent) > nToggleRegion) {
9552 toggleSubmenuDisplay();
9554 Event.preventDefault(oEvent);
9557 Return false so that other click event handlers are not called when the
9558 user clicks inside the toggle region.
9567 toggleSubmenuDisplay();
9585 * @method configSubmenuToggle
9586 * @description Event handler for when the "submenutoggleregion" configuration property of
9587 * a MenuBar changes.
9588 * @param {String} p_sType The name of the event that was fired.
9589 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9591 configSubmenuToggle: function (p_sType, p_aArgs) {
9593 var bSubmenuToggle = p_aArgs[0];
9595 if (bSubmenuToggle) {
9597 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9606 * @description Returns a string representing the menu bar.
9609 toString: function() {
9611 var sReturnVal = _MENUBAR,
9616 sReturnVal += (_SPACE + sId);
9626 * @description Initializes the class's configurable properties which can be
9627 * changed using the menu bar's Config object ("cfg").
9628 * @method initDefaultConfig
9630 initDefaultConfig: function() {
9632 MenuBar.superclass.initDefaultConfig.call(this);
9634 var oConfig = this.cfg;
9636 // Add configuration properties
9640 Set the default value for the "position" configuration property
9641 to "static" by re-adding the property.
9647 * @description String indicating how a menu bar should be positioned on the
9648 * screen. Possible values are "static" and "dynamic." Static menu bars
9649 * are visible by default and reside in the normal flow of the document
9650 * (CSS position: static). Dynamic menu bars are hidden by default, reside
9651 * out of the normal flow of the document (CSS position: absolute), and can
9652 * overlay other elements on the screen.
9656 oConfig.addProperty(
9657 POSITION_CONFIG.key,
9659 handler: this.configPosition,
9660 value: POSITION_CONFIG.value,
9661 validator: POSITION_CONFIG.validator,
9662 supercedes: POSITION_CONFIG.supercedes
9668 Set the default value for the "submenualignment" configuration property
9669 to ["tl","bl"] by re-adding the property.
9673 * @config submenualignment
9674 * @description Array defining how submenus should be aligned to their
9675 * parent menu bar item. The format is: [itemCorner, submenuCorner].
9676 * @default ["tl","bl"]
9679 oConfig.addProperty(
9680 SUBMENU_ALIGNMENT_CONFIG.key,
9682 value: SUBMENU_ALIGNMENT_CONFIG.value,
9683 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9689 Change the default value for the "autosubmenudisplay" configuration
9690 property to "false" by re-adding the property.
9694 * @config autosubmenudisplay
9695 * @description Boolean indicating if submenus are automatically made
9696 * visible when the user mouses over the menu bar's items.
9700 oConfig.addProperty(
9701 AUTO_SUBMENU_DISPLAY_CONFIG.key,
9703 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
9704 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9705 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9711 * @config submenutoggleregion
9712 * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
9713 * display of a submenu. The default width of the region is determined by the value of the
9714 * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
9715 * configuration property will be set to false, and any click event listeners will not be
9716 * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
9717 * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
9718 * standard behavior.
9722 oConfig.addProperty(
9723 SUBMENU_TOGGLE_REGION_CONFIG.key,
9725 value: SUBMENU_TOGGLE_REGION_CONFIG.value,
9726 validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9727 handler: this.configSubmenuToggle
9733 }); // END YAHOO.lang.extend
9740 * Creates an item for a menu bar.
9742 * @param {String} p_oObject String specifying the text of the menu bar item.
9743 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9744 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9745 * <code><li></code> element of the menu bar item.
9746 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9747 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9748 * specifying the <code><optgroup></code> element of the menu bar item.
9749 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9750 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9751 * the <code><option></code> element of the menu bar item.
9752 * @param {Object} p_oConfig Optional. Object literal specifying the
9753 * configuration for the menu bar item. See configuration class documentation
9755 * @class MenuBarItem
9757 * @extends YAHOO.widget.MenuItem
9759 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9761 YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9765 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9771 * @description The MenuBarItem class's initialization method. This method is
9772 * automatically called by the constructor, and sets up all DOM references for
9773 * pre-existing markup, and creates required markup if it is not already present.
9774 * @param {String} p_oObject String specifying the text of the menu bar item.
9775 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9776 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9777 * <code><li></code> element of the menu bar item.
9778 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9779 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9780 * specifying the <code><optgroup></code> element of the menu bar item.
9781 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9782 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9783 * the <code><option></code> element of the menu bar item.
9784 * @param {Object} p_oConfig Optional. Object literal specifying the
9785 * configuration for the menu bar item. See configuration class documentation
9788 init: function(p_oObject, p_oConfig) {
9790 if(!this.SUBMENU_TYPE) {
9792 this.SUBMENU_TYPE = YAHOO.widget.Menu;
9798 Call the init of the superclass (YAHOO.widget.MenuItem)
9799 Note: We don't pass the user config in here yet
9800 because we only want it executed once, at the lowest
9804 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
9807 var oConfig = this.cfg;
9811 oConfig.applyConfig(p_oConfig, true);
9815 oConfig.fireQueue();
9825 * @property CSS_CLASS_NAME
9826 * @description String representing the CSS class(es) to be applied to the
9827 * <code><li></code> element of the menu bar item.
9828 * @default "yuimenubaritem"
9832 CSS_CLASS_NAME: "yuimenubaritem",
9836 * @property CSS_LABEL_CLASS_NAME
9837 * @description String representing the CSS class(es) to be applied to the
9838 * menu bar item's <code><a></code> element.
9839 * @default "yuimenubaritemlabel"
9843 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9852 * @description Returns a string representing the menu bar item.
9855 toString: function() {
9857 var sReturnVal = "MenuBarItem";
9859 if(this.cfg && this.cfg.getProperty("text")) {
9861 sReturnVal += (": " + this.cfg.getProperty("text"));
9869 }); // END YAHOO.lang.extend
9870 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.8.0r4", build: "2449"});