2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
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 && (UA.ie < 9)) {
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;
443 else if (m_oVisibleMenus[sId]) {
445 delete m_oVisibleMenus[sId];
454 * @method onItemDestroy
455 * @description "destroy" event handler for a MenuItem instance.
457 * @param {String} p_sType String representing the name of the event
459 * @param {Array} p_aArgs Array of arguments sent when the event
462 function onItemDestroy(p_sType, p_aArgs) {
471 * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
473 * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
475 function removeItem(p_oMenuItem) {
477 var sId = p_oMenuItem.id;
479 if (sId && m_oItems[sId]) {
481 if (m_oFocusedMenuItem == p_oMenuItem) {
483 m_oFocusedMenuItem = null;
487 delete m_oItems[sId];
489 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
498 * @method onItemAdded
499 * @description "itemadded" event handler for a Menu instance.
501 * @param {String} p_sType String representing the name of the event
503 * @param {Array} p_aArgs Array of arguments sent when the event
506 function onItemAdded(p_sType, p_aArgs) {
508 var oItem = p_aArgs[0],
511 if (oItem instanceof YAHOO.widget.MenuItem) {
515 if (!m_oItems[sId]) {
517 m_oItems[sId] = oItem;
519 oItem.destroyEvent.subscribe(onItemDestroy);
531 // Privileged methods
536 * @description Adds a menu to the collection of known menus.
537 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
538 * instance to be added.
540 addMenu: function (p_oMenu) {
544 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
545 !m_oMenus[p_oMenu.id]) {
547 m_oMenus[p_oMenu.id] = p_oMenu;
550 if (!m_bInitializedEventHandlers) {
554 Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
555 Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
556 Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
557 Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
558 Event.on(oDoc, _CLICK, onDOMEvent, this, true);
559 Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
560 Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
561 Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
563 Event.onFocus(oDoc, onDOMEvent, this, true);
564 Event.onBlur(oDoc, onDOMEvent, this, true);
566 m_bInitializedEventHandlers = true;
571 p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
572 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
573 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
574 p_oMenu.focusEvent.subscribe(onMenuFocus);
575 p_oMenu.blurEvent.subscribe(onMenuBlur);
585 * @description Removes a menu from the collection of known menus.
586 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
587 * instance to be removed.
589 removeMenu: function (p_oMenu) {
599 if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
601 // Unregister each menu item
603 aItems = p_oMenu.getItems();
605 if (aItems && aItems.length > 0) {
607 i = aItems.length - 1;
611 removeItem(aItems[i]);
619 // Unregister the menu
621 delete m_oMenus[sId];
626 Unregister the menu from the collection of
630 if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
632 delete m_oVisibleMenus[sId];
638 // Unsubscribe event listeners
642 p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE,
643 onMenuVisibleConfigChange);
647 p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
650 p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
651 p_oMenu.focusEvent.unsubscribe(onMenuFocus);
652 p_oMenu.blurEvent.unsubscribe(onMenuBlur);
662 * @method hideVisible
663 * @description Hides all visible, dynamically positioned menus
664 * (excluding instances of YAHOO.widget.MenuBar).
666 hideVisible: function () {
670 for (var i in m_oVisibleMenus) {
672 if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
674 oMenu = m_oVisibleMenus[i];
676 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
677 oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
692 * @description Returns a collection of all visible menus registered
693 * with the menu manger.
696 getVisible: function () {
698 return m_oVisibleMenus;
705 * @description Returns a collection of all menus registered with the
709 getMenus: function () {
718 * @description Returns a menu with the specified id.
719 * @param {String} p_sId String specifying the id of the
720 * <code><div></code> element representing the menu to
722 * @return {YAHOO.widget.Menu}
724 getMenu: function (p_sId) {
728 if (p_sId in m_oMenus) {
730 returnVal = m_oMenus[p_sId];
740 * @method getMenuItem
741 * @description Returns a menu item with the specified id.
742 * @param {String} p_sId String specifying the id of the
743 * <code><li></code> element representing the menu item to
745 * @return {YAHOO.widget.MenuItem}
747 getMenuItem: function (p_sId) {
751 if (p_sId in m_oItems) {
753 returnVal = m_oItems[p_sId];
763 * @method getMenuItemGroup
764 * @description Returns an array of menu item instances whose
765 * corresponding <code><li></code> elements are child
766 * nodes of the <code><ul></code> element with the
768 * @param {String} p_sId String specifying the id of the
769 * <code><ul></code> element representing the group of
770 * menu items to be retrieved.
773 getMenuItemGroup: function (p_sId) {
775 var oUL = Dom.get(p_sId),
783 if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
785 oNode = oUL.firstChild;
797 oItem = this.getMenuItem(sId);
801 aItems[aItems.length] = oItem;
808 while ((oNode = oNode.nextSibling));
811 if (aItems.length > 0) {
827 * @method getFocusedMenuItem
828 * @description Returns a reference to the menu item that currently
830 * @return {YAHOO.widget.MenuItem}
832 getFocusedMenuItem: function () {
834 return m_oFocusedMenuItem;
840 * @method getFocusedMenu
841 * @description Returns a reference to the menu that currently
843 * @return {YAHOO.widget.Menu}
845 getFocusedMenu: function () {
849 if (m_oFocusedMenuItem) {
851 returnVal = m_oFocusedMenuItem.parent.getRoot();
862 * @description Returns a string representing the menu manager.
865 toString: function () {
881 var Lang = YAHOO.lang,
886 _DIV_UPPERCASE = "DIV",
887 _DIV_LOWERCASE = "div",
892 _UL_UPPERCASE = "UL",
893 _UL_LOWERCASE = "ul",
894 _FIRST_OF_TYPE = "first-of-type",
896 _OPTGROUP = "OPTGROUP",
898 _DISABLED = "disabled",
900 _SELECTED = "selected",
901 _GROUP_INDEX = "groupindex",
903 _SUBMENU = "submenu",
904 _VISIBLE = "visible",
905 _HIDE_DELAY = "hidedelay",
906 _POSITION = "position",
907 _DYNAMIC = "dynamic",
909 _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
913 _MAX_HEIGHT = "maxheight",
914 _TOP_SCROLLBAR = "topscrollbar",
915 _BOTTOM_SCROLLBAR = "bottomscrollbar",
917 _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
918 _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
919 _MOUSEMOVE = "mousemove",
920 _SHOW_DELAY = "showdelay",
921 _SUBMENU_HIDE_DELAY = "submenuhidedelay",
923 _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
924 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
925 _SUBMENU_ALIGNMENT = "submenualignment",
926 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
927 _CLICK_TO_HIDE = "clicktohide",
928 _CONTAINER = "container",
929 _SCROLL_INCREMENT = "scrollincrement",
930 _MIN_SCROLL_HEIGHT = "minscrollheight",
931 _CLASSNAME = "classname",
933 _KEEP_OPEN = "keepopen",
935 _HAS_TITLE = "hastitle",
936 _CONTEXT = "context",
938 _MOUSEDOWN = "mousedown",
939 _KEYDOWN = "keydown",
944 _MONITOR_RESIZE = "monitorresize",
945 _DISPLAY = "display",
947 _VISIBILITY = "visibility",
948 _ABSOLUTE = "absolute",
950 _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
951 _NON_BREAKING_SPACE = " ",
953 _MOUSEOVER = "mouseover",
954 _MOUSEOUT = "mouseout",
955 _ITEM_ADDED = "itemAdded",
956 _ITEM_REMOVED = "itemRemoved",
958 _YUI_MENU_SHADOW = "yui-menu-shadow",
959 _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
960 _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
964 * The Menu class creates a container that holds a vertical list representing
965 * a set of options or commands. Menu is the base class for all
967 * @param {String} p_oElement String specifying the id attribute of the
968 * <code><div></code> element of the menu.
969 * @param {String} p_oElement String specifying the id attribute of the
970 * <code><select></code> element to be used as the data source
972 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
973 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
974 * specifying the <code><div></code> element of the menu.
975 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
976 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
977 * Object specifying the <code><select></code> element to be used as
978 * the data source for the menu.
979 * @param {Object} p_oConfig Optional. Object literal specifying the
980 * configuration for the menu. See configuration class documentation for
982 * @namespace YAHOO.widget
985 * @extends YAHOO.widget.Overlay
987 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
990 this.parent = p_oConfig.parent;
991 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
992 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
995 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1001 * @method checkPosition
1002 * @description Checks to make sure that the value of the "position" property
1003 * is one of the supported strings. Returns true if the position is supported.
1005 * @param {Object} p_sPosition String specifying the position of the menu.
1008 function checkPosition(p_sPosition) {
1010 var returnVal = false;
1012 if (Lang.isString(p_sPosition)) {
1014 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1023 var Dom = YAHOO.util.Dom,
1024 Event = YAHOO.util.Event,
1025 Module = YAHOO.widget.Module,
1026 Overlay = YAHOO.widget.Overlay,
1027 Menu = YAHOO.widget.Menu,
1028 MenuManager = YAHOO.widget.MenuManager,
1029 CustomEvent = YAHOO.util.CustomEvent,
1034 bFocusListenerInitialized = false,
1040 ["mouseOverEvent", _MOUSEOVER],
1041 ["mouseOutEvent", _MOUSEOUT],
1042 ["mouseDownEvent", _MOUSEDOWN],
1043 ["mouseUpEvent", "mouseup"],
1044 ["clickEvent", "click"],
1045 ["keyPressEvent", "keypress"],
1046 ["keyDownEvent", _KEYDOWN],
1047 ["keyUpEvent", "keyup"],
1048 ["focusEvent", "focus"],
1049 ["blurEvent", "blur"],
1050 ["itemAddedEvent", _ITEM_ADDED],
1051 ["itemRemovedEvent", _ITEM_REMOVED]
1058 validator: Lang.isBoolean
1061 CONSTRAIN_TO_VIEWPORT_CONFIG = {
1062 key: _CONSTRAIN_TO_VIEWPORT,
1064 validator: Lang.isBoolean,
1065 supercedes: [_IFRAME,"x",_Y,_XY]
1068 PREVENT_CONTEXT_OVERLAP_CONFIG = {
1069 key: _PREVENT_CONTEXT_OVERLAP,
1071 validator: Lang.isBoolean,
1072 supercedes: [_CONSTRAIN_TO_VIEWPORT]
1078 validator: checkPosition,
1079 supercedes: [_VISIBLE, _IFRAME]
1082 SUBMENU_ALIGNMENT_CONFIG = {
1083 key: _SUBMENU_ALIGNMENT,
1087 AUTO_SUBMENU_DISPLAY_CONFIG = {
1088 key: _AUTO_SUBMENU_DISPLAY,
1090 validator: Lang.isBoolean,
1094 SHOW_DELAY_CONFIG = {
1097 validator: Lang.isNumber,
1101 HIDE_DELAY_CONFIG = {
1104 validator: Lang.isNumber,
1108 SUBMENU_HIDE_DELAY_CONFIG = {
1109 key: _SUBMENU_HIDE_DELAY,
1111 validator: Lang.isNumber,
1115 CLICK_TO_HIDE_CONFIG = {
1116 key: _CLICK_TO_HIDE,
1118 validator: Lang.isBoolean,
1122 CONTAINER_CONFIG = {
1127 SCROLL_INCREMENT_CONFIG = {
1128 key: _SCROLL_INCREMENT,
1130 validator: Lang.isNumber,
1131 supercedes: [_MAX_HEIGHT],
1135 MIN_SCROLL_HEIGHT_CONFIG = {
1136 key: _MIN_SCROLL_HEIGHT,
1138 validator: Lang.isNumber,
1139 supercedes: [_MAX_HEIGHT],
1143 MAX_HEIGHT_CONFIG = {
1146 validator: Lang.isNumber,
1147 supercedes: [_IFRAME],
1151 CLASS_NAME_CONFIG = {
1154 validator: Lang.isString,
1161 validator: Lang.isBoolean,
1168 validator: Lang.isBoolean,
1169 suppressEvent: true,
1170 supercedes: [_VISIBLE]
1173 KEEP_OPEN_CONFIG = {
1176 validator: Lang.isBoolean
1180 function onDocFocus(event) {
1182 oFocusedElement = Event.getTarget(event);
1188 YAHOO.lang.extend(Menu, Overlay, {
1195 * @property CSS_CLASS_NAME
1196 * @description String representing the CSS class(es) to be applied to the
1197 * menu's <code><div></code> element.
1198 * @default "yuimenu"
1202 CSS_CLASS_NAME: "yuimenu",
1206 * @property ITEM_TYPE
1207 * @description Object representing the type of menu item to instantiate and
1208 * add when parsing the child nodes (either <code><li></code> element,
1209 * <code><optgroup></code> element or <code><option></code>)
1210 * of the menu's source HTML element.
1211 * @default YAHOO.widget.MenuItem
1213 * @type YAHOO.widget.MenuItem
1219 * @property GROUP_TITLE_TAG_NAME
1220 * @description String representing the tagname of the HTML element used to
1221 * title the menu's item groups.
1226 GROUP_TITLE_TAG_NAME: "h6",
1230 * @property OFF_SCREEN_POSITION
1231 * @description Array representing the default x and y position that a menu
1232 * should have when it is positioned outside the viewport by the
1233 * "poistionOffScreen" method.
1238 OFF_SCREEN_POSITION: "-999em",
1241 // Private properties
1245 * @property _useHideDelay
1246 * @description Boolean indicating if the "mouseover" and "mouseout" event
1247 * handlers used for hiding the menu via a call to "YAHOO.lang.later" have
1248 * already been assigned.
1253 _useHideDelay: false,
1257 * @property _bHandledMouseOverEvent
1258 * @description Boolean indicating the current state of the menu's
1259 * "mouseover" event.
1264 _bHandledMouseOverEvent: false,
1268 * @property _bHandledMouseOutEvent
1269 * @description Boolean indicating the current state of the menu's
1275 _bHandledMouseOutEvent: false,
1279 * @property _aGroupTitleElements
1280 * @description Array of HTML element used to title groups of menu items.
1285 _aGroupTitleElements: null,
1289 * @property _aItemGroups
1290 * @description Multi-dimensional Array representing the menu items as they
1291 * are grouped in the menu.
1300 * @property _aListElements
1301 * @description Array of <code><ul></code> elements, each of which is
1302 * the parent node for each item's <code><li></code> element.
1307 _aListElements: null,
1311 * @property _nCurrentMouseX
1312 * @description The current x coordinate of the mouse inside the area of
1322 * @property _bStopMouseEventHandlers
1323 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1329 _bStopMouseEventHandlers: false,
1333 * @property _sClassName
1334 * @description The current value of the "classname" configuration attribute.
1343 // Public properties
1347 * @property lazyLoad
1348 * @description Boolean indicating if the menu's "lazy load" feature is
1349 * enabled. If set to "true," initialization and rendering of the menu's
1350 * items will be deferred until the first time it is made visible. This
1351 * property should be set via the constructor using the configuration
1360 * @property itemData
1361 * @description Array of items to be added to the menu. The array can contain
1362 * strings representing the text for each item to be created, object literals
1363 * representing the menu item configuration properties, or MenuItem instances.
1364 * This property should be set via the constructor using the configuration
1373 * @property activeItem
1374 * @description Object reference to the item in the menu that has is selected.
1376 * @type YAHOO.widget.MenuItem
1383 * @description Object reference to the menu's parent menu or menu item.
1384 * This property can be set via the constructor using the configuration
1387 * @type YAHOO.widget.MenuItem
1393 * @property srcElement
1394 * @description Object reference to the HTML element (either
1395 * <code><select></code> or <code><div></code>) used to
1398 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1399 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1400 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1401 * html#ID-22445964">HTMLDivElement</a>
1411 * @event mouseOverEvent
1412 * @description Fires when the mouse has entered the menu. Passes back
1413 * the DOM Event object as an argument.
1418 * @event mouseOutEvent
1419 * @description Fires when the mouse has left the menu. Passes back the DOM
1420 * Event object as an argument.
1421 * @type YAHOO.util.CustomEvent
1426 * @event mouseDownEvent
1427 * @description Fires when the user mouses down on the menu. Passes back the
1428 * DOM Event object as an argument.
1429 * @type YAHOO.util.CustomEvent
1434 * @event mouseUpEvent
1435 * @description Fires when the user releases a mouse button while the mouse is
1436 * over the menu. Passes back the DOM Event object as an argument.
1437 * @type YAHOO.util.CustomEvent
1443 * @description Fires when the user clicks the on the menu. Passes back the
1444 * DOM Event object as an argument.
1445 * @type YAHOO.util.CustomEvent
1450 * @event keyPressEvent
1451 * @description Fires when the user presses an alphanumeric key when one of the
1452 * menu's items has focus. Passes back the DOM Event object as an argument.
1453 * @type YAHOO.util.CustomEvent
1458 * @event keyDownEvent
1459 * @description Fires when the user presses a key when one of the menu's items
1460 * has focus. Passes back the DOM Event object as an argument.
1461 * @type YAHOO.util.CustomEvent
1467 * @description Fires when the user releases a key when one of the menu's items
1468 * has focus. Passes back the DOM Event object as an argument.
1469 * @type YAHOO.util.CustomEvent
1474 * @event itemAddedEvent
1475 * @description Fires when an item is added to the menu.
1476 * @type YAHOO.util.CustomEvent
1481 * @event itemRemovedEvent
1482 * @description Fires when an item is removed to the menu.
1483 * @type YAHOO.util.CustomEvent
1489 * @description The Menu class's initialization method. This method is
1490 * automatically called by the constructor, and sets up all DOM references
1491 * for pre-existing markup, and creates required markup if it is not
1493 * @param {String} p_oElement String specifying the id attribute of the
1494 * <code><div></code> element of the menu.
1495 * @param {String} p_oElement String specifying the id attribute of the
1496 * <code><select></code> element to be used as the data source
1498 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1499 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1500 * specifying the <code><div></code> element of the menu.
1501 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1502 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1503 * Object specifying the <code><select></code> element to be used as
1504 * the data source for the menu.
1505 * @param {Object} p_oConfig Optional. Object literal specifying the
1506 * configuration for the menu. See configuration class documentation for
1509 init: function (p_oElement, p_oConfig) {
1511 this._aItemGroups = [];
1512 this._aListElements = [];
1513 this._aGroupTitleElements = [];
1515 if (!this.ITEM_TYPE) {
1517 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1524 if (Lang.isString(p_oElement)) {
1526 oElement = Dom.get(p_oElement);
1529 else if (p_oElement.tagName) {
1531 oElement = p_oElement;
1536 if (oElement && oElement.tagName) {
1538 switch(oElement.tagName.toUpperCase()) {
1540 case _DIV_UPPERCASE:
1542 this.srcElement = oElement;
1546 oElement.setAttribute(_ID, Dom.generateId());
1552 Note: we don't pass the user config in here yet
1553 because we only want it executed once, at the lowest
1557 Menu.superclass.init.call(this, oElement);
1559 this.beforeInitEvent.fire(Menu);
1566 this.srcElement = oElement;
1570 The source element is not something that we can use
1571 outright, so we need to create a new Overlay
1573 Note: we don't pass the user config in here yet
1574 because we only want it executed once, at the lowest
1578 Menu.superclass.init.call(this, Dom.generateId());
1580 this.beforeInitEvent.fire(Menu);
1591 Note: we don't pass the user config in here yet
1592 because we only want it executed once, at the lowest
1596 Menu.superclass.init.call(this, p_oElement);
1598 this.beforeInitEvent.fire(Menu);
1605 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1607 // Subscribe to Custom Events
1608 this.initEvent.subscribe(this._onInit);
1609 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1610 this.renderEvent.subscribe(this._onRender);
1611 this.beforeShowEvent.subscribe(this._onBeforeShow);
1612 this.hideEvent.subscribe(this._onHide);
1613 this.showEvent.subscribe(this._onShow);
1614 this.beforeHideEvent.subscribe(this._onBeforeHide);
1615 this.mouseOverEvent.subscribe(this._onMouseOver);
1616 this.mouseOutEvent.subscribe(this._onMouseOut);
1617 this.clickEvent.subscribe(this._onClick);
1618 this.keyDownEvent.subscribe(this._onKeyDown);
1619 this.keyPressEvent.subscribe(this._onKeyPress);
1620 this.blurEvent.subscribe(this._onBlur);
1622 if (!bFocusListenerInitialized) {
1623 Event.onFocus(document, onDocFocus);
1624 bFocusListenerInitialized = true;
1627 // Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY"
1628 // methods return values that don't take scrollTop into consideration
1630 if ((UA.gecko && UA.gecko < 1.9) || (UA.webkit && UA.webkit < 523)) {
1631 this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1636 this.cfg.applyConfig(p_oConfig, true);
1639 // Register the Menu instance with the MenuManager
1640 MenuManager.addMenu(this);
1642 this.initEvent.fire(Menu);
1652 * @method _initSubTree
1653 * @description Iterates the childNodes of the source element to find nodes
1654 * used to instantiate menu and menu items.
1657 _initSubTree: function () {
1659 var oSrcElement = this.srcElement,
1671 sSrcElementTagName =
1672 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1675 if (sSrcElementTagName == _DIV_UPPERCASE) {
1677 // Populate the collection of item groups and item group titles
1679 oNode = this.body.firstChild;
1685 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1690 if (oNode && oNode.tagName) {
1692 switch (oNode.tagName.toUpperCase()) {
1694 case sGroupTitleTagName:
1696 this._aGroupTitleElements[nGroup] = oNode;
1702 this._aListElements[nGroup] = oNode;
1703 this._aItemGroups[nGroup] = [];
1713 while ((oNode = oNode.nextSibling));
1717 Apply the "first-of-type" class to the first UL to mimic
1718 the ":first-of-type" CSS3 psuedo class.
1721 if (this._aListElements[0]) {
1723 Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1736 if (sSrcElementTagName) {
1738 switch (sSrcElementTagName) {
1740 case _DIV_UPPERCASE:
1742 aListElements = this._aListElements;
1743 nListElements = aListElements.length;
1745 if (nListElements > 0) {
1748 i = nListElements - 1;
1752 oNode = aListElements[i].firstChild;
1759 if (oNode && oNode.tagName &&
1760 oNode.tagName.toUpperCase() == _LI) {
1763 this.addItem(new this.ITEM_TYPE(oNode,
1764 { parent: this }), i);
1769 while ((oNode = oNode.nextSibling));
1783 oNode = oSrcElement.firstChild;
1787 if (oNode && oNode.tagName) {
1789 switch (oNode.tagName.toUpperCase()) {
1809 while ((oNode = oNode.nextSibling));
1823 * @method _getFirstEnabledItem
1824 * @description Returns the first enabled item in the menu.
1825 * @return {YAHOO.widget.MenuItem}
1828 _getFirstEnabledItem: function () {
1830 var aItems = this.getItems(),
1831 nItems = aItems.length,
1836 for(var i=0; i<nItems; i++) {
1840 if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1855 * @method _addItemToGroup
1856 * @description Adds a menu item to a group.
1858 * @param {Number} p_nGroupIndex Number indicating the group to which the
1860 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1861 * instance to be added to the menu.
1862 * @param {HTML} p_oItem String or markup specifying the content of the item to be added
1863 * to the menu. The item is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
1864 * @param {Object} p_oItem Object literal containing a set of menu item
1865 * configuration properties.
1866 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1867 * which the menu item should be added.
1868 * @return {YAHOO.widget.MenuItem}
1870 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1882 function getNextItemSibling(p_aArray, p_nStartIndex) {
1884 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1889 if (p_oItem instanceof this.ITEM_TYPE) {
1892 oItem.parent = this;
1895 else if (Lang.isString(p_oItem)) {
1897 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1900 else if (Lang.isObject(p_oItem)) {
1902 p_oItem.parent = this;
1904 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1911 if (oItem.cfg.getProperty(_SELECTED)) {
1913 this.activeItem = oItem;
1918 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1919 aGroup = this._getItemGroup(nGroupIndex);
1925 aGroup = this._createItemGroup(nGroupIndex);
1930 if (Lang.isNumber(p_nItemIndex)) {
1932 bAppend = (p_nItemIndex >= aGroup.length);
1935 if (aGroup[p_nItemIndex]) {
1937 aGroup.splice(p_nItemIndex, 0, oItem);
1942 aGroup[p_nItemIndex] = oItem;
1947 oGroupItem = aGroup[p_nItemIndex];
1951 if (bAppend && (!oGroupItem.element.parentNode ||
1952 oGroupItem.element.parentNode.nodeType == 11)) {
1954 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
1959 oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
1961 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
1962 oGroupItem.element.parentNode.nodeType == 11)) {
1964 this._aListElements[nGroupIndex].insertBefore(
1965 oGroupItem.element, oNextItemSibling.element);
1972 oGroupItem.parent = this;
1974 this._subscribeToItemEvents(oGroupItem);
1976 this._configureSubmenu(oGroupItem);
1978 this._updateItemProperties(nGroupIndex);
1981 this.itemAddedEvent.fire(oGroupItem);
1982 this.changeContentEvent.fire();
1984 returnVal = oGroupItem;
1991 nItemIndex = aGroup.length;
1993 aGroup[nItemIndex] = oItem;
1995 oGroupItem = aGroup[nItemIndex];
2000 if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2002 this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2006 oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2007 oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2009 oGroupItem.parent = this;
2011 oGroupItem.index = nItemIndex;
2012 oGroupItem.groupIndex = nGroupIndex;
2014 this._subscribeToItemEvents(oGroupItem);
2016 this._configureSubmenu(oGroupItem);
2018 if (nItemIndex === 0) {
2020 Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2026 this.itemAddedEvent.fire(oGroupItem);
2027 this.changeContentEvent.fire();
2029 returnVal = oGroupItem;
2043 * @method _removeItemFromGroupByIndex
2044 * @description Removes a menu item from a group by index. Returns the menu
2045 * item that was removed.
2047 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
2049 * @param {Number} p_nItemIndex Number indicating the index of the menu item
2051 * @return {YAHOO.widget.MenuItem}
2053 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2055 var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2056 aGroup = this._getItemGroup(nGroupIndex),
2063 aArray = aGroup.splice(p_nItemIndex, 1);
2068 // Update the index and className properties of each member
2070 this._updateItemProperties(nGroupIndex);
2072 if (aGroup.length === 0) {
2076 oUL = this._aListElements[nGroupIndex];
2078 if (oUL && oUL.parentNode) {
2079 oUL.parentNode.removeChild(oUL);
2082 // Remove the group from the array of items
2084 this._aItemGroups.splice(nGroupIndex, 1);
2087 // Remove the UL from the array of ULs
2089 this._aListElements.splice(nGroupIndex, 1);
2093 Assign the "first-of-type" class to the new first UL
2097 oUL = this._aListElements[0];
2101 Dom.addClass(oUL, _FIRST_OF_TYPE);
2108 this.itemRemovedEvent.fire(oItem);
2109 this.changeContentEvent.fire();
2115 // Return a reference to the item that was removed
2123 * @method _removeItemFromGroupByValue
2124 * @description Removes a menu item from a group by reference. Returns the
2125 * menu item that was removed.
2127 * @param {Number} p_nGroupIndex Number indicating the group to which the
2128 * menu item belongs.
2129 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2130 * instance to be removed.
2131 * @return {YAHOO.widget.MenuItem}
2133 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2135 var aGroup = this._getItemGroup(p_nGroupIndex),
2143 nItems = aGroup.length;
2152 if (aGroup[i] == p_oItem) {
2162 if (nItemIndex > -1) {
2164 returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2178 * @method _updateItemProperties
2179 * @description Updates the "index," "groupindex," and "className" properties
2180 * of the menu items in the specified group.
2182 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2184 _updateItemProperties: function (p_nGroupIndex) {
2186 var aGroup = this._getItemGroup(p_nGroupIndex),
2187 nItems = aGroup.length,
2197 // Update the index and className properties of each member
2205 oLI = oItem.element;
2208 oItem.groupIndex = p_nGroupIndex;
2210 oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2211 oLI.setAttribute(_INDEX, i);
2213 Dom.removeClass(oLI, _FIRST_OF_TYPE);
2223 Dom.addClass(oLI, _FIRST_OF_TYPE);
2233 * @method _createItemGroup
2234 * @description Creates a new menu item group (array) and its associated
2235 * <code><ul></code> element. Returns an aray of menu item groups.
2237 * @param {Number} p_nIndex Number indicating the group to create.
2240 _createItemGroup: function (p_nIndex) {
2245 if (!this._aItemGroups[p_nIndex]) {
2247 this._aItemGroups[p_nIndex] = [];
2249 oUL = document.createElement(_UL_LOWERCASE);
2251 this._aListElements[p_nIndex] = oUL;
2253 returnVal = this._aItemGroups[p_nIndex];
2263 * @method _getItemGroup
2264 * @description Returns the menu item group at the specified index.
2266 * @param {Number} p_nIndex Number indicating the index of the menu item group
2270 _getItemGroup: function (p_nIndex) {
2272 var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2273 aGroups = this._aItemGroups,
2276 if (nIndex in aGroups) {
2278 returnVal = aGroups[nIndex];
2288 * @method _configureSubmenu
2289 * @description Subscribes the menu item's submenu to its parent menu's events.
2291 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2292 * instance with the submenu to be configured.
2294 _configureSubmenu: function (p_oItem) {
2296 var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2301 Listen for configuration changes to the parent menu
2302 so they they can be applied to the submenu.
2305 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2307 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2317 * @method _subscribeToItemEvents
2318 * @description Subscribes a menu to a menu item's event.
2320 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2321 * instance whose events should be subscribed to.
2323 _subscribeToItemEvents: function (p_oItem) {
2325 p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2326 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2332 * @method _onVisibleChange
2333 * @description Change event handler for the the menu's "visible" configuration
2336 * @param {String} p_sType String representing the name of the event that
2338 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2340 _onVisibleChange: function (p_sType, p_aArgs) {
2342 var bVisible = p_aArgs[0];
2346 Dom.addClass(this.element, _VISIBLE);
2351 Dom.removeClass(this.element, _VISIBLE);
2359 * @method _cancelHideDelay
2360 * @description Cancels the call to "hideMenu."
2363 _cancelHideDelay: function () {
2365 var oTimer = this.getRoot()._hideDelayTimer;
2377 * @method _execHideDelay
2378 * @description Hides the menu after the number of milliseconds specified by
2379 * the "hidedelay" configuration property.
2382 _execHideDelay: function () {
2384 this._cancelHideDelay();
2386 var oRoot = this.getRoot();
2388 oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2390 if (oRoot.activeItem) {
2391 if (oRoot.hasFocus()) {
2392 oRoot.activeItem.focus();
2394 oRoot.clearActiveItem();
2397 if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) &&
2398 this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2407 * @method _cancelShowDelay
2408 * @description Cancels the call to the "showMenu."
2411 _cancelShowDelay: function () {
2412 var oTimer = this.getRoot()._showDelayTimer;
2420 * @method _execSubmenuHideDelay
2421 * @description Hides a submenu after the number of milliseconds specified by
2422 * the "submenuhidedelay" configuration property have elapsed.
2424 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2426 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2427 * the specified submenu's parent menu item.
2428 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2429 * before the submenu is hidden.
2431 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2433 p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2435 if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2437 p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2456 // Protected methods
2460 * @method _disableScrollHeader
2461 * @description Disables the header used for scrolling the body of the menu.
2464 _disableScrollHeader: function () {
2466 if (!this._bHeaderDisabled) {
2468 Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2469 this._bHeaderDisabled = true;
2477 * @method _disableScrollFooter
2478 * @description Disables the footer used for scrolling the body of the menu.
2481 _disableScrollFooter: function () {
2483 if (!this._bFooterDisabled) {
2485 Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2486 this._bFooterDisabled = true;
2494 * @method _enableScrollHeader
2495 * @description Enables the header used for scrolling the body of the menu.
2498 _enableScrollHeader: function () {
2500 if (this._bHeaderDisabled) {
2502 Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2503 this._bHeaderDisabled = false;
2511 * @method _enableScrollFooter
2512 * @description Enables the footer used for scrolling the body of the menu.
2515 _enableScrollFooter: function () {
2517 if (this._bFooterDisabled) {
2519 Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2520 this._bFooterDisabled = false;
2528 * @method _onMouseOver
2529 * @description "mouseover" event handler for the menu.
2531 * @param {String} p_sType String representing the name of the event that
2533 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2535 _onMouseOver: function (p_sType, p_aArgs) {
2537 var oEvent = p_aArgs[0],
2539 oTarget = Event.getTarget(oEvent),
2540 oRoot = this.getRoot(),
2541 oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2550 var showSubmenu = function () {
2552 if (this.parent.cfg.getProperty(_SELECTED)) {
2561 if (!this._bStopMouseEventHandlers) {
2563 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2564 Dom.isAncestor(this.element, oTarget))) {
2566 // Menu mouseover logic
2568 if (this._useHideDelay) {
2569 this._cancelHideDelay();
2572 this._nCurrentMouseX = 0;
2574 Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2578 If the mouse is moving from the submenu back to its corresponding menu item,
2579 don't hide the submenu or clear the active MenuItem.
2582 if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2584 this.clearActiveItem();
2589 if (this.parent && oSubmenuHideDelayTimer) {
2591 oSubmenuHideDelayTimer.cancel();
2593 this.parent.cfg.setProperty(_SELECTED, true);
2595 oParentMenu = this.parent.parent;
2597 oParentMenu._bHandledMouseOutEvent = true;
2598 oParentMenu._bHandledMouseOverEvent = false;
2603 this._bHandledMouseOverEvent = true;
2604 this._bHandledMouseOutEvent = false;
2609 if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) &&
2610 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2612 // Menu Item mouseover logic
2614 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2615 bShowDelay = (nShowDelay > 0);
2620 this._cancelShowDelay();
2625 oActiveItem = this.activeItem;
2629 oActiveItem.cfg.setProperty(_SELECTED, false);
2634 oItemCfg = oItem.cfg;
2636 // Select and focus the current menu item
2638 oItemCfg.setProperty(_SELECTED, true);
2641 if (this.hasFocus() || oRoot._hasFocus) {
2645 oRoot._hasFocus = false;
2650 if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2652 // Show the submenu this menu item
2654 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2660 oRoot._showDelayTimer =
2661 Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2674 oItem.handledMouseOverEvent = true;
2675 oItem.handledMouseOutEvent = false;
2685 * @method _onMouseOut
2686 * @description "mouseout" event handler for the menu.
2688 * @param {String} p_sType String representing the name of the event that
2690 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2692 _onMouseOut: function (p_sType, p_aArgs) {
2694 var oEvent = p_aArgs[0],
2696 oRelatedTarget = Event.getRelatedTarget(oEvent),
2697 bMovingToSubmenu = false,
2705 if (!this._bStopMouseEventHandlers) {
2707 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2709 oItemCfg = oItem.cfg;
2710 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2713 if (oSubmenu && (oRelatedTarget == oSubmenu.element || Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2714 bMovingToSubmenu = true;
2717 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element && !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2718 if (!bMovingToSubmenu) {
2719 oItem.cfg.setProperty(_SELECTED, false);
2722 nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2723 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2724 if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 && nSubmenuHideDelay >= nShowDelay) {
2725 this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent), nSubmenuHideDelay);
2732 oItem.handledMouseOutEvent = true;
2733 oItem.handledMouseOverEvent = false;
2738 if (!this._bHandledMouseOutEvent) {
2739 if (this._didMouseLeave(oRelatedTarget) || bMovingToSubmenu) {
2740 // Menu mouseout logic
2741 if (this._useHideDelay) {
2742 this._execHideDelay();
2745 Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2747 this._nCurrentMouseX = Event.getPageX(oEvent);
2749 this._bHandledMouseOutEvent = true;
2750 this._bHandledMouseOverEvent = false;
2758 * Utilility method to determine if we really moused out of the menu based on the related target
2759 * @method _didMouseLeave
2761 * @param {HTMLElement} oRelatedTarget The related target based on which we're making the decision
2762 * @return {boolean} true if it's OK to hide based on the related target.
2764 _didMouseLeave : function(oRelatedTarget) {
2765 // Hide if we're not moving back to the element from somewhere inside the element, or we're moving to an element inside the menu.
2766 // The shadow is treated as an edge case, inside inside the menu, but we get no further mouseouts, because it overflows the element,
2767 // so we need to close when moving to the menu.
2768 return (oRelatedTarget === this._shadow || (oRelatedTarget != this.element && !Dom.isAncestor(this.element, oRelatedTarget)));
2772 * @method _onMouseMove
2773 * @description "click" event handler for the menu.
2775 * @param {Event} p_oEvent Object representing the DOM event object passed
2776 * back by the event utility (YAHOO.util.Event).
2777 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2780 _onMouseMove: function (p_oEvent, p_oMenu) {
2782 if (!this._bStopMouseEventHandlers) {
2784 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2793 * @description "click" event handler for the menu.
2795 * @param {String} p_sType String representing the name of the event that
2797 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2799 _onClick: function (p_sType, p_aArgs) {
2801 var oEvent = p_aArgs[0],
2803 bInMenuAnchor = false,
2813 var hide = function () {
2815 oRoot = this.getRoot();
2817 if (oRoot instanceof YAHOO.widget.MenuBar ||
2818 oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2820 oRoot.clearActiveItem();
2834 if (oItem.cfg.getProperty(_DISABLED)) {
2836 Event.preventDefault(oEvent);
2843 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2847 Check if the URL of the anchor is pointing to an element that is
2848 a child of the menu.
2851 sURL = oItem.cfg.getProperty(_URL);
2856 nHashPos = sURL.indexOf(_HASH);
2861 if (nHashPos != -1) {
2863 sURL = sURL.substr(nHashPos, nLen);
2870 sId = sURL.substr(1, nLen);
2872 oMenu = YAHOO.widget.MenuManager.getMenu(sId);
2877 (this.getRoot() === oMenu.getRoot());
2882 else if (nLen === 1) {
2884 bInMenuAnchor = true;
2893 if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
2895 Event.preventDefault(oEvent);
2905 oItem.focusEvent.fire();
2912 if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
2925 This function is called to prevent a bug in Firefox. In Firefox,
2926 moving a DOM element into a stationary mouse pointer will cause the
2927 browser to fire mouse events. This can result in the menu mouse
2928 event handlers being called uncessarily, especially when menus are
2929 moved into a stationary mouse pointer as a result of a
2933 * Utility method to stop mouseevents from being fired if the DOM
2934 * changes under a stationary mouse pointer (as opposed to the mouse moving
2935 * over a DOM element).
2937 * @method _stopMouseEventHandlers
2940 _stopMouseEventHandlers: function() {
2941 this._bStopMouseEventHandlers = true;
2943 Lang.later(10, this, function () {
2944 this._bStopMouseEventHandlers = false;
2949 * @method _onKeyDown
2950 * @description "keydown" event handler for the menu.
2952 * @param {String} p_sType String representing the name of the event that
2954 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2956 _onKeyDown: function (p_sType, p_aArgs) {
2958 var oEvent = p_aArgs[0],
2976 if (this._useHideDelay) {
2977 this._cancelHideDelay();
2980 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2982 oItemCfg = oItem.cfg;
2983 oParentItem = this.parent;
2985 switch(oEvent.keyCode) {
2987 case 38: // Up arrow
2988 case 40: // Down arrow
2990 oNextItem = (oEvent.keyCode == 38) ?
2991 oItem.getPreviousEnabledSibling() :
2992 oItem.getNextEnabledSibling();
2996 this.clearActiveItem();
2998 oNextItem.cfg.setProperty(_SELECTED, true);
3001 if (this.cfg.getProperty(_MAX_HEIGHT) > 0 || Dom.hasClass(this.body, _YUI_MENU_BODY_SCROLLED)) {
3004 nBodyScrollTop = oBody.scrollTop;
3005 nBodyOffsetHeight = oBody.offsetHeight;
3006 aItems = this.getItems();
3007 nItems = aItems.length - 1;
3008 nNextItemOffsetTop = oNextItem.element.offsetTop;
3011 if (oEvent.keyCode == 40 ) { // Down
3013 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3015 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3018 else if (nNextItemOffsetTop <= nBodyScrollTop) {
3020 oBody.scrollTop = 0;
3025 if (oNextItem == aItems[nItems]) {
3027 oBody.scrollTop = oNextItem.element.offsetTop;
3034 if (nNextItemOffsetTop <= nBodyScrollTop) {
3036 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3039 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3041 oBody.scrollTop = nNextItemOffsetTop;
3046 if (oNextItem == aItems[0]) {
3048 oBody.scrollTop = 0;
3055 nBodyScrollTop = oBody.scrollTop;
3056 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3058 if (nBodyScrollTop === 0) {
3060 this._disableScrollHeader();
3061 this._enableScrollFooter();
3064 else if (nBodyScrollTop == nScrollTarget) {
3066 this._enableScrollHeader();
3067 this._disableScrollFooter();
3072 this._enableScrollHeader();
3073 this._enableScrollFooter();
3082 Event.preventDefault(oEvent);
3084 this._stopMouseEventHandlers();
3089 case 39: // Right arrow
3091 oSubmenu = oItemCfg.getProperty(_SUBMENU);
3095 if (!oItemCfg.getProperty(_SELECTED)) {
3097 oItemCfg.setProperty(_SELECTED, true);
3102 oSubmenu.setInitialFocus();
3103 oSubmenu.setInitialSelection();
3108 oRoot = this.getRoot();
3110 if (oRoot instanceof YAHOO.widget.MenuBar) {
3112 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3116 oRoot.clearActiveItem();
3118 oNextItem.cfg.setProperty(_SELECTED, true);
3120 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3125 oSubmenu.setInitialFocus();
3141 Event.preventDefault(oEvent);
3143 this._stopMouseEventHandlers();
3148 case 37: // Left arrow
3152 oParentMenu = oParentItem.parent;
3154 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3157 oParentMenu.activeItem.getPreviousEnabledSibling();
3161 oParentMenu.clearActiveItem();
3163 oNextItem.cfg.setProperty(_SELECTED, true);
3165 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3170 oSubmenu.setInitialFocus();
3186 oParentItem.focus();
3192 Event.preventDefault(oEvent);
3194 this._stopMouseEventHandlers();
3204 if (oEvent.keyCode == 27) { // Esc key
3206 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3212 this.parent.focus();
3216 // Focus the element that previously had focus
3218 oFocusedEl = this._focusedElement;
3220 if (oFocusedEl && oFocusedEl.focus) {
3233 else if (this.activeItem) {
3235 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3237 if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3240 this.activeItem.focus();
3245 this.activeItem.blur();
3246 this.activeItem.cfg.setProperty(_SELECTED, false);
3253 Event.preventDefault(oEvent);
3261 * @method _onKeyPress
3262 * @description "keypress" event handler for a Menu instance.
3264 * @param {String} p_sType The name of the event that was fired.
3265 * @param {Array} p_aArgs Collection of arguments sent when the event
3268 _onKeyPress: function (p_sType, p_aArgs) {
3270 var oEvent = p_aArgs[0];
3273 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3275 Event.preventDefault(oEvent);
3284 * @description "blur" event handler for a Menu instance.
3286 * @param {String} p_sType The name of the event that was fired.
3287 * @param {Array} p_aArgs Collection of arguments sent when the event
3290 _onBlur: function (p_sType, p_aArgs) {
3292 if (this._hasFocus) {
3293 this._hasFocus = false;
3299 * @method _onYChange
3300 * @description "y" event handler for a Menu instance.
3302 * @param {String} p_sType The name of the event that was fired.
3303 * @param {Array} p_aArgs Collection of arguments sent when the event
3306 _onYChange: function (p_sType, p_aArgs) {
3308 var oParent = this.parent,
3316 nScrollTop = oParent.parent.body.scrollTop;
3319 if (nScrollTop > 0) {
3321 nY = (this.cfg.getProperty(_Y) - nScrollTop);
3323 Dom.setY(this.element, nY);
3325 oIFrame = this.iframe;
3330 Dom.setY(oIFrame, nY);
3334 this.cfg.setProperty(_Y, nY, true);
3344 * @method _onScrollTargetMouseOver
3345 * @description "mouseover" event handler for the menu's "header" and "footer"
3346 * elements. Used to scroll the body of the menu up and down when the
3347 * menu's "maxheight" configuration property is set to a value greater than 0.
3349 * @param {Event} p_oEvent Object representing the DOM event object passed
3350 * back by the event utility (YAHOO.util.Event).
3351 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3354 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3356 var oBodyScrollTimer = this._bodyScrollTimer;
3359 if (oBodyScrollTimer) {
3361 oBodyScrollTimer.cancel();
3366 this._cancelHideDelay();
3369 var oTarget = Event.getTarget(p_oEvent),
3371 nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3376 function scrollBodyDown() {
3378 var nScrollTop = oBody.scrollTop;
3381 if (nScrollTop < nScrollTarget) {
3383 oBody.scrollTop = (nScrollTop + nScrollIncrement);
3385 this._enableScrollHeader();
3390 oBody.scrollTop = nScrollTarget;
3392 this._bodyScrollTimer.cancel();
3394 this._disableScrollFooter();
3401 function scrollBodyUp() {
3403 var nScrollTop = oBody.scrollTop;
3406 if (nScrollTop > 0) {
3408 oBody.scrollTop = (nScrollTop - nScrollIncrement);
3410 this._enableScrollFooter();
3415 oBody.scrollTop = 0;
3417 this._bodyScrollTimer.cancel();
3419 this._disableScrollHeader();
3426 if (Dom.hasClass(oTarget, _HD)) {
3428 fnScrollFunction = scrollBodyUp;
3433 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3435 fnScrollFunction = scrollBodyDown;
3440 this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3446 * @method _onScrollTargetMouseOut
3447 * @description "mouseout" event handler for the menu's "header" and "footer"
3448 * elements. Used to stop scrolling the body of the menu up and down when the
3449 * menu's "maxheight" configuration property is set to a value greater than 0.
3451 * @param {Event} p_oEvent Object representing the DOM event object passed
3452 * back by the event utility (YAHOO.util.Event).
3453 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3456 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3458 var oBodyScrollTimer = this._bodyScrollTimer;
3460 if (oBodyScrollTimer) {
3462 oBodyScrollTimer.cancel();
3466 this._cancelHideDelay();
3477 * @description "init" event handler for the menu.
3479 * @param {String} p_sType String representing the name of the event that
3481 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3483 _onInit: function (p_sType, p_aArgs) {
3485 this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3487 var bRootMenu = !this.parent,
3488 bLazyLoad = this.lazyLoad;
3492 Automatically initialize a menu's subtree if:
3494 1) This is the root menu and lazyload is off
3496 2) This is the root menu, lazyload is on, but the menu is
3499 3) This menu is a submenu and lazyload is off
3504 if (((bRootMenu && !bLazyLoad) ||
3505 (bRootMenu && (this.cfg.getProperty(_VISIBLE) ||
3506 this.cfg.getProperty(_POSITION) == _STATIC)) ||
3507 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3509 if (this.srcElement) {
3511 this._initSubTree();
3516 if (this.itemData) {
3518 this.addItems(this.itemData);
3523 else if (bLazyLoad) {
3525 this.cfg.fireQueue();
3533 * @method _onBeforeRender
3534 * @description "beforerender" event handler for the menu. Appends all of the
3535 * <code><ul></code>, <code><li></code> and their accompanying
3536 * title elements to the body element of the menu.
3538 * @param {String} p_sType String representing the name of the event that
3540 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3542 _onBeforeRender: function (p_sType, p_aArgs) {
3544 var oEl = this.element,
3545 nListElements = this._aListElements.length,
3551 if (nListElements > 0) {
3555 oUL = this._aListElements[i];
3561 Dom.addClass(oUL, _FIRST_OF_TYPE);
3567 if (!Dom.isAncestor(oEl, oUL)) {
3569 this.appendToBody(oUL);
3574 oGroupTitle = this._aGroupTitleElements[i];
3578 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3580 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3585 Dom.addClass(oUL, _HAS_TITLE);
3594 while (i < nListElements);
3603 * @description "render" event handler for the menu.
3605 * @param {String} p_sType String representing the name of the event that
3607 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3609 _onRender: function (p_sType, p_aArgs) {
3611 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3613 if (!this.cfg.getProperty(_VISIBLE)) {
3615 this.positionOffScreen();
3628 * @method _onBeforeShow
3629 * @description "beforeshow" event handler for the menu.
3631 * @param {String} p_sType String representing the name of the event that
3633 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3635 _onBeforeShow: function (p_sType, p_aArgs) {
3640 oContainer = this.cfg.getProperty(_CONTAINER);
3643 if (this.lazyLoad && this.getItemGroups().length === 0) {
3645 if (this.srcElement) {
3647 this._initSubTree();
3652 if (this.itemData) {
3654 if (this.parent && this.parent.parent &&
3655 this.parent.parent.srcElement &&
3656 this.parent.parent.srcElement.tagName.toUpperCase() ==
3659 nOptions = this.itemData.length;
3661 for(n=0; n<nOptions; n++) {
3663 if (this.itemData[n].tagName) {
3665 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3674 this.addItems(this.itemData);
3681 oSrcElement = this.srcElement;
3685 if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3687 if (Dom.inDocument(oSrcElement)) {
3689 this.render(oSrcElement.parentNode);
3694 this.render(oContainer);
3710 this.render(this.parent.element);
3715 this.render(oContainer);
3725 var oParent = this.parent,
3729 if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3731 this.cfg.refireEvent(_XY);
3738 aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3740 this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3748 getConstrainedY: function (y) {
3752 aContext = oMenu.cfg.getProperty(_CONTEXT),
3753 nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3757 oOverlapPositions = {
3766 bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3768 oMenuEl = oMenu.element,
3769 nMenuOffsetHeight = oMenuEl.offsetHeight,
3771 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3772 viewPortHeight = Dom.getViewportHeight(),
3773 scrollY = Dom.getDocumentScrollTop(),
3776 (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3787 nBottomRegionHeight,
3789 topConstraint = scrollY + nViewportOffset,
3790 bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
3795 var flipVertical = function () {
3799 // The Menu is below the context element, flip it above
3800 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3801 nNewY = (nContextElY - nMenuOffsetHeight);
3803 else { // The Menu is above the context element, flip it below
3804 nNewY = (nContextElY + nContextElHeight);
3807 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3815 Uses the context element's position to calculate the availble height
3816 above and below it to display its corresponding Menu.
3819 var getDisplayRegionHeight = function () {
3820 //Bug43168: since the initial value Y is empty, the case is calculated in wrong way
3821 var _y = oMenu.cfg.getProperty(_Y);
3822 // The Menu is below the context element
3823 if ( _y == 0 || (_y - scrollY) > nContextElY ) {
3824 return (nBottomRegionHeight - nViewportOffset);
3826 else { // The Menu is above the context element
3827 return (nTopRegionHeight - nViewportOffset);
3834 Sets the Menu's "y" configuration property to the correct value based on its
3835 current orientation.
3838 var alignY = function () {
3842 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3843 nNewY = (nContextElY + nContextElHeight);
3846 nNewY = (nContextElY - oMenuEl.offsetHeight);
3849 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3854 // Resets the maxheight of the Menu to the value set by the user
3856 var resetMaxHeight = function () {
3858 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3860 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3866 Trys to place the Menu in the best possible position (either above or
3867 below its corresponding context element).
3870 var setVerticalPosition = function () {
3872 var nDisplayRegionHeight = getDisplayRegionHeight(),
3873 bMenuHasItems = (oMenu.getItems().length > 0),
3874 nMenuMinScrollHeight,
3878 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3880 nMenuMinScrollHeight =
3881 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3884 if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3885 nMaxHeight = nDisplayRegionHeight;
3888 nMaxHeight = nInitialMaxHeight;
3892 oMenu._setScrollHeight(nMaxHeight);
3893 oMenu.hideEvent.subscribe(resetMaxHeight);
3896 // Re-align the Menu since its height has just changed
3897 // as a result of the setting of the maxheight property.
3902 if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3907 All possible positions and values for the "maxheight"
3908 configuration property have been tried, but none were
3909 successful, so fall back to the original size and position.
3921 fnReturnVal = setVerticalPosition();
3928 else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
3930 oMenu._setScrollHeight(nInitialMaxHeight);
3931 oMenu.hideEvent.subscribe(resetMaxHeight);
3933 // Re-align the Menu since its height has just changed
3934 // as a result of the setting of the maxheight property.
3945 // Determine if the current value for the Menu's "y" configuration property will
3946 // result in the Menu being positioned outside the boundaries of the viewport
3948 if (y < topConstraint || y > bottomConstraint) {
3950 // The current value for the Menu's "y" configuration property WILL
3951 // result in the Menu being positioned outside the boundaries of the viewport
3953 if (bCanConstrain) {
3955 if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
3958 // If the "preventcontextoverlap" configuration property is set to "true",
3959 // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
3960 // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
3962 oContextEl = aContext[0];
3963 nContextElHeight = oContextEl.offsetHeight;
3964 nContextElY = (Dom.getY(oContextEl) - scrollY);
3966 nTopRegionHeight = nContextElY;
3967 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3969 setVerticalPosition();
3971 yNew = oMenu.cfg.getProperty(_Y);
3974 else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
3975 nMenuOffsetHeight >= viewPortHeight) {
3978 // If the Menu exceeds the height of the viewport, introduce scroll bars
3979 // to keep the Menu inside the boundaries of the viewport
3981 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
3983 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
3985 oMenu._setScrollHeight(nAvailableHeight);
3986 oMenu.hideEvent.subscribe(resetMaxHeight);
3990 yNew = oMenu.cfg.getProperty(_Y);
3999 if (y < topConstraint) {
4000 yNew = topConstraint;
4001 } else if (y > bottomConstraint) {
4002 yNew = bottomConstraint;
4009 // The "y" configuration property cannot be set to a value that will keep
4010 // entire Menu inside the boundary of the viewport. Therefore, set
4011 // the "y" configuration property to scrollY to keep as much of the
4012 // Menu inside the viewport as possible.
4013 yNew = nViewportOffset + scrollY;
4025 * @description "hide" event handler for the menu.
4027 * @param {String} p_sType String representing the name of the event that
4029 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4031 _onHide: function (p_sType, p_aArgs) {
4033 if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4035 this.positionOffScreen();
4044 * @description "show" event handler for the menu.
4046 * @param {String} p_sType String representing the name of the event that
4048 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4050 _onShow: function (p_sType, p_aArgs) {
4052 var oParent = this.parent,
4059 function disableAutoSubmenuDisplay(p_oEvent) {
4063 if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4066 Set the "autosubmenudisplay" to "false" if the user
4067 clicks outside the menu bar.
4070 oTarget = Event.getTarget(p_oEvent);
4072 if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4074 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4076 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4077 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4086 function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4088 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4089 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4096 oParentMenu = oParent.parent;
4099 if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
4100 (oParentMenu instanceof YAHOO.widget.MenuBar ||
4101 oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4103 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4105 Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4106 Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4111 // The following fixes an issue with the selected state of a MenuItem
4112 // not rendering correctly when a submenu is aligned to the left of
4113 // its parent Menu instance.
4115 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
4116 (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4118 oElement = this.element;
4119 nOffsetWidth = oElement.offsetWidth;
4122 Measuring the difference of the offsetWidth before and after
4123 setting the "width" style attribute allows us to compute the
4124 about of padding and borders applied to the element, which in
4125 turn allows us to set the "width" property correctly.
4128 oElement.style.width = nOffsetWidth + _PX;
4130 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4132 this.cfg.setProperty(_WIDTH, sWidth);
4134 this.hideEvent.subscribe(onSubmenuHide, sWidth);
4142 Dynamically positioned, root Menus focus themselves when visible, and
4143 will then, when hidden, restore focus to the UI control that had focus
4144 before the Menu was made visible.
4147 if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4149 this._focusedElement = oFocusedElement;
4160 * @method _onBeforeHide
4161 * @description "beforehide" event handler for the menu.
4163 * @param {String} p_sType String representing the name of the event that
4165 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4167 _onBeforeHide: function (p_sType, p_aArgs) {
4169 var oActiveItem = this.activeItem,
4170 oRoot = this.getRoot(),
4177 oConfig = oActiveItem.cfg;
4179 oConfig.setProperty(_SELECTED, false);
4181 oSubmenu = oConfig.getProperty(_SUBMENU);
4193 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
4194 For this reason, it is necessary to maintain the focused state in a private property
4195 so that the _onMouseOver event handler is able to determined whether or not to set focus
4196 to MenuItems as the user is moving the mouse.
4199 if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4201 oRoot._hasFocus = this.hasFocus();
4206 if (oRoot == this) {
4216 * @method _onParentMenuConfigChange
4217 * @description "configchange" event handler for a submenu.
4219 * @param {String} p_sType String representing the name of the event that
4221 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4222 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4223 * subscribed to the event.
4225 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4227 var sPropertyName = p_aArgs[0][0],
4228 oPropertyValue = p_aArgs[0][1];
4230 switch(sPropertyName) {
4233 case _CONSTRAIN_TO_VIEWPORT:
4236 case _SUBMENU_HIDE_DELAY:
4237 case _CLICK_TO_HIDE:
4240 case _SCROLL_INCREMENT:
4242 case _MIN_SCROLL_HEIGHT:
4243 case _MONITOR_RESIZE:
4245 case _PREVENT_CONTEXT_OVERLAP:
4248 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4252 case _SUBMENU_ALIGNMENT:
4254 if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4256 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4268 * @method _onParentMenuRender
4269 * @description "render" event handler for a submenu. Renders a
4270 * submenu in response to the firing of its parent's "render" event.
4272 * @param {String} p_sType String representing the name of the event that
4274 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4275 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4276 * subscribed to the event.
4278 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4280 var oParentMenu = p_oSubmenu.parent.parent,
4281 oParentCfg = oParentMenu.cfg,
4285 constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4289 clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4291 effect: oParentCfg.getProperty(_EFFECT),
4293 showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4295 hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4297 submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4299 classname: oParentCfg.getProperty(_CLASSNAME),
4301 scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4303 maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4305 minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4307 iframe: oParentCfg.getProperty(_IFRAME),
4309 shadow: oParentCfg.getProperty(_SHADOW),
4311 preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4313 monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
4315 keepopen: oParentCfg.getProperty(_KEEP_OPEN)
4323 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4325 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4330 p_oSubmenu.cfg.applyConfig(oConfig);
4333 if (!this.lazyLoad) {
4335 oLI = this.parent.element;
4337 if (this.element.parentNode == oLI) {
4354 * @method _onMenuItemDestroy
4355 * @description "destroy" event handler for the menu's items.
4357 * @param {String} p_sType String representing the name of the event
4359 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4360 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4361 * that fired the event.
4363 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4365 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4371 * @method _onMenuItemConfigChange
4372 * @description "configchange" event handler for the menu's items.
4374 * @param {String} p_sType String representing the name of the event that
4376 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4377 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4378 * that fired the event.
4380 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4382 var sPropertyName = p_aArgs[0][0],
4383 oPropertyValue = p_aArgs[0][1],
4387 switch(sPropertyName) {
4391 if (oPropertyValue === true) {
4393 this.activeItem = p_oItem;
4401 oSubmenu = p_aArgs[0][1];
4405 this._configureSubmenu(p_oItem);
4417 // Public event handlers for configuration properties
4421 * @method configVisible
4422 * @description Event handler for when the "visible" configuration property
4424 * @param {String} p_sType String representing the name of the event that
4426 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4427 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4430 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4435 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4437 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4442 bVisible = p_aArgs[0];
4443 sDisplay = Dom.getStyle(this.element, _DISPLAY);
4445 Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4449 if (sDisplay != _BLOCK) {
4450 this.beforeShowEvent.fire();
4451 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4452 this.showEvent.fire();
4458 if (sDisplay == _BLOCK) {
4459 this.beforeHideEvent.fire();
4460 Dom.setStyle(this.element, _DISPLAY, _NONE);
4461 this.hideEvent.fire();
4472 * @method configPosition
4473 * @description Event handler for when the "position" configuration property
4474 * of the menu changes.
4475 * @param {String} p_sType String representing the name of the event that
4477 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4478 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4481 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4483 var oElement = this.element,
4484 sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4489 Dom.setStyle(oElement, _POSITION, sCSSPosition);
4492 if (sCSSPosition == _STATIC) {
4494 // Statically positioned menus are visible by default
4496 Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4498 oCfg.setProperty(_VISIBLE, true);
4504 Even though the "visible" property is queued to
4505 "false" by default, we need to set the "visibility" property to
4506 "hidden" since Overlay's "configVisible" implementation checks the
4507 element's "visibility" style property before deciding whether
4508 or not to show an Overlay instance.
4511 Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4516 if (sCSSPosition == _ABSOLUTE) {
4517 nZIndex = oCfg.getProperty(_ZINDEX);
4519 if (!nZIndex || nZIndex === 0) {
4520 oCfg.setProperty(_ZINDEX, 1);
4529 * @method configIframe
4530 * @description Event handler for when the "iframe" configuration property of
4532 * @param {String} p_sType String representing the name of the event that
4534 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4535 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4538 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4540 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4542 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4550 * @method configHideDelay
4551 * @description Event handler for when the "hidedelay" configuration property
4552 * of the menu changes.
4553 * @param {String} p_sType String representing the name of the event that
4555 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4556 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4559 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4561 var nHideDelay = p_aArgs[0];
4563 this._useHideDelay = (nHideDelay > 0);
4569 * @method configContainer
4570 * @description Event handler for when the "container" configuration property
4571 * of the menu changes.
4572 * @param {String} p_sType String representing the name of the event that
4574 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4575 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4578 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4580 var oElement = p_aArgs[0];
4582 if (Lang.isString(oElement)) {
4584 this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4592 * @method _clearSetWidthFlag
4593 * @description Change event listener for the "width" configuration property. This listener is
4594 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
4595 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
4596 * is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
4597 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
4598 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4601 _clearSetWidthFlag: function () {
4603 this._widthSetForScroll = false;
4605 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4610 * @method _subscribeScrollHandlers
4611 * @param {HTMLElement} oHeader The scroll header element
4612 * @param {HTMLElement} oFooter The scroll footer element
4614 _subscribeScrollHandlers : function(oHeader, oFooter) {
4615 var fnMouseOver = this._onScrollTargetMouseOver;
4616 var fnMouseOut = this._onScrollTargetMouseOut;
4618 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4619 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4620 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4621 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4625 * @method _unsubscribeScrollHandlers
4626 * @param {HTMLElement} oHeader The scroll header element
4627 * @param {HTMLElement} oFooter The scroll footer element
4629 _unsubscribeScrollHandlers : function(oHeader, oFooter) {
4630 var fnMouseOver = this._onScrollTargetMouseOver;
4631 var fnMouseOut = this._onScrollTargetMouseOut;
4633 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4634 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4635 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4636 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4640 * @method _setScrollHeight
4642 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4645 _setScrollHeight: function (p_nScrollHeight) {
4647 var nScrollHeight = p_nScrollHeight,
4648 bRefireIFrameAndShadow = false,
4659 if (this.getItems().length > 0) {
4661 oElement = this.element;
4663 oHeader = this.header;
4664 oFooter = this.footer;
4665 nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4667 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4668 nScrollHeight = nMinScrollHeight;
4671 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4672 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4673 oBody.scrollTop = 0;
4675 // Need to set a width for the Menu to fix the following problems in
4676 // Firefox 2 and IE:
4678 // #1) Scrolled Menus will render at 1px wide in Firefox 2
4680 // #2) There is a bug in gecko-based browsers where an element whose
4681 // "position" property is set to "absolute" and "overflow" property is
4682 // set to "hidden" will not render at the correct width when its
4683 // offsetParent's "position" property is also set to "absolute." It is
4684 // possible to work around this bug by specifying a value for the width
4685 // property in addition to overflow.
4687 // #3) In IE it is necessary to give the Menu a width before the
4688 // scrollbars are rendered to prevent the Menu from rendering with a
4689 // width that is 100% of the browser viewport.
4691 bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4693 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4695 nOffsetWidth = oElement.offsetWidth;
4698 Measuring the difference of the offsetWidth before and after
4699 setting the "width" style attribute allows us to compute the
4700 about of padding and borders applied to the element, which in
4701 turn allows us to set the "width" property correctly.
4704 oElement.style.width = nOffsetWidth + _PX;
4706 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4709 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4712 this.cfg.setProperty(_WIDTH, sWidth);
4716 Set a flag (_widthSetForScroll) to maintain some history regarding how the
4717 "width" configuration property was set. If the "width" configuration property
4718 is set by something other than the "_setScrollHeight" method, it will be
4719 necessary to maintain that new value and not clear the width if scrolling
4723 this._widthSetForScroll = true;
4725 this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4730 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4733 this.setHeader(_NON_BREAKING_SPACE);
4734 this.setFooter(_NON_BREAKING_SPACE);
4736 oHeader = this.header;
4737 oFooter = this.footer;
4739 Dom.addClass(oHeader, _TOP_SCROLLBAR);
4740 Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4742 oElement.insertBefore(oHeader, oBody);
4743 oElement.appendChild(oFooter);
4747 nHeight = nScrollHeight;
4749 if (oHeader && oFooter) {
4750 nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4754 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4757 Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4758 Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4760 if (!this._hasScrollEventHandlers) {
4761 this._subscribeScrollHandlers(oHeader, oFooter);
4762 this._hasScrollEventHandlers = true;
4765 this._disableScrollHeader();
4766 this._enableScrollFooter();
4768 bRefireIFrameAndShadow = true;
4771 else if (oHeader && oFooter) {
4776 Only clear the the "width" configuration property if it was set the
4777 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4780 if (this._widthSetForScroll) {
4783 this._widthSetForScroll = false;
4785 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4787 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4792 this._enableScrollHeader();
4793 this._enableScrollFooter();
4795 if (this._hasScrollEventHandlers) {
4796 this._unsubscribeScrollHandlers(oHeader, oFooter);
4797 this._hasScrollEventHandlers = false;
4800 oElement.removeChild(oHeader);
4801 oElement.removeChild(oFooter);
4806 bRefireIFrameAndShadow = true;
4811 if (bRefireIFrameAndShadow) {
4813 this.cfg.refireEvent(_IFRAME);
4814 this.cfg.refireEvent(_SHADOW);
4824 * @method _setMaxHeight
4825 * @description "renderEvent" handler used to defer the setting of the
4826 * "maxheight" configuration property until the menu is rendered in lazy
4828 * @param {String} p_sType The name of the event that was fired.
4829 * @param {Array} p_aArgs Collection of arguments sent when the event
4831 * @param {Number} p_nMaxHeight Number representing the value to set for the
4832 * "maxheight" configuration property.
4835 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4837 this._setScrollHeight(p_nMaxHeight);
4838 this.renderEvent.unsubscribe(this._setMaxHeight);
4844 * @method configMaxHeight
4845 * @description Event handler for when the "maxheight" configuration property of
4847 * @param {String} p_sType The name of the event that was fired.
4848 * @param {Array} p_aArgs Collection of arguments sent when the event
4850 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4853 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4855 var nMaxHeight = p_aArgs[0];
4857 if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4859 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4864 this._setScrollHeight(nMaxHeight);
4872 * @method configClassName
4873 * @description Event handler for when the "classname" configuration property of
4875 * @param {String} p_sType The name of the event that was fired.
4876 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4877 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4879 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4881 var sClassName = p_aArgs[0];
4883 if (this._sClassName) {
4885 Dom.removeClass(this.element, this._sClassName);
4889 Dom.addClass(this.element, sClassName);
4890 this._sClassName = sClassName;
4896 * @method _onItemAdded
4897 * @description "itemadded" event handler for a Menu instance.
4899 * @param {String} p_sType The name of the event that was fired.
4900 * @param {Array} p_aArgs Collection of arguments sent when the event
4903 _onItemAdded: function (p_sType, p_aArgs) {
4905 var oItem = p_aArgs[0];
4909 oItem.cfg.setProperty(_DISABLED, true);
4917 * @method configDisabled
4918 * @description Event handler for when the "disabled" configuration property of
4920 * @param {String} p_sType The name of the event that was fired.
4921 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4922 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4924 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4926 var bDisabled = p_aArgs[0],
4927 aItems = this.getItems(),
4931 if (Lang.isArray(aItems)) {
4933 nItems = aItems.length;
4941 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
4951 this.clearActiveItem(true);
4953 Dom.addClass(this.element, _DISABLED);
4955 this.itemAddedEvent.subscribe(this._onItemAdded);
4960 Dom.removeClass(this.element, _DISABLED);
4962 this.itemAddedEvent.unsubscribe(this._onItemAdded);
4971 * Resizes the shadow to match the container bounding element
4973 * @method _sizeShadow
4976 _sizeShadow : function () {
4978 var oElement = this.element,
4979 oShadow = this._shadow;
4981 if (oShadow && oElement) {
4982 // Clear the previous width
4983 if (oShadow.style.width && oShadow.style.height) {
4984 oShadow.style.width = _EMPTY_STRING;
4985 oShadow.style.height = _EMPTY_STRING;
4988 oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
4989 oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
4994 * Replaces the shadow element in the DOM with the current shadow element (this._shadow)
4996 * @method _replaceShadow
4999 _replaceShadow : function () {
5000 this.element.appendChild(this._shadow);
5004 * Adds the classname marker for a visible shadow, to the shadow element
5006 * @method _addShadowVisibleClass
5009 _addShadowVisibleClass : function () {
5010 Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5014 * Removes the classname marker for a visible shadow, from the shadow element
5016 * @method _removeShadowVisibleClass
5019 _removeShadowVisibleClass : function () {
5020 Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5024 * Removes the shadow element from the DOM, and unsubscribes all the listeners used to keep it in sync. Used
5025 * to handle setting the shadow to false.
5027 * @method _removeShadow
5030 _removeShadow : function() {
5032 var p = (this._shadow && this._shadow.parentNode);
5035 p.removeChild(this._shadow);
5038 this.beforeShowEvent.unsubscribe(this._addShadowVisibleClass);
5039 this.beforeHideEvent.unsubscribe(this._removeShadowVisibleClass);
5041 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._sizeShadow);
5042 this.cfg.unsubscribeFromConfigEvent(_HEIGHT, this._sizeShadow);
5043 this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5044 this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5046 this.changeContentEvent.unsubscribe(this._sizeShadow);
5048 Module.textResizeEvent.unsubscribe(this._sizeShadow);
5052 * Used to create the shadow element, add it to the DOM, and subscribe listeners to keep it in sync.
5054 * @method _createShadow
5057 _createShadow : function () {
5059 var oShadow = this._shadow,
5063 oElement = this.element;
5065 if (!m_oShadowTemplate) {
5066 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5067 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5070 oShadow = m_oShadowTemplate.cloneNode(false);
5072 oElement.appendChild(oShadow);
5074 this._shadow = oShadow;
5076 this.beforeShowEvent.subscribe(this._addShadowVisibleClass);
5077 this.beforeHideEvent.subscribe(this._removeShadowVisibleClass);
5081 Need to call sizeShadow & syncIframe via setTimeout for
5082 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
5083 or the shadow and iframe shim will not be sized and
5084 positioned properly.
5086 Lang.later(0, this, function () {
5091 this.cfg.subscribeToConfigEvent(_WIDTH, this._sizeShadow);
5092 this.cfg.subscribeToConfigEvent(_HEIGHT, this._sizeShadow);
5093 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5094 this.changeContentEvent.subscribe(this._sizeShadow);
5096 Module.textResizeEvent.subscribe(this._sizeShadow, this, true);
5098 this.destroyEvent.subscribe(function () {
5099 Module.textResizeEvent.unsubscribe(this._sizeShadow, this);
5103 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5108 * The beforeShow event handler used to set up the shadow lazily when the menu is made visible.
5109 * @method _shadowBeforeShow
5112 _shadowBeforeShow : function () {
5115 // If called because the "shadow" event was refired - just append again and resize
5116 this._replaceShadow();
5122 this._createShadow();
5125 this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5129 * @method configShadow
5130 * @description Event handler for when the "shadow" configuration property of
5132 * @param {String} p_sType The name of the event that was fired.
5133 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5134 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5136 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5138 var bShadow = p_aArgs[0];
5140 if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5141 if (this.cfg.getProperty(_VISIBLE)) {
5143 // If the "shadow" event was refired - just append again and resize
5144 this._replaceShadow();
5150 this._createShadow();
5153 this.beforeShowEvent.subscribe(this._shadowBeforeShow);
5155 } else if (!bShadow) {
5156 this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5157 this._removeShadow();
5164 * @method initEvents
5165 * @description Initializes the custom events for the menu.
5167 initEvents: function () {
5169 Menu.superclass.initEvents.call(this);
5171 // Create custom events
5173 var i = EVENT_TYPES.length - 1,
5180 aEventData = EVENT_TYPES[i];
5182 oCustomEvent = this.createEvent(aEventData[1]);
5183 oCustomEvent.signature = CustomEvent.LIST;
5185 this[aEventData[0]] = oCustomEvent;
5194 * @method positionOffScreen
5195 * @description Positions the menu outside of the boundaries of the browser's
5196 * viewport. Called automatically when a menu is hidden to ensure that
5197 * it doesn't force the browser to render uncessary scrollbars.
5199 positionOffScreen: function () {
5201 var oIFrame = this.iframe,
5202 oElement = this.element,
5203 sPos = this.OFF_SCREEN_POSITION;
5205 oElement.style.top = _EMPTY_STRING;
5206 oElement.style.left = _EMPTY_STRING;
5210 oIFrame.style.top = sPos;
5211 oIFrame.style.left = sPos;
5220 * @description Finds the menu's root menu.
5222 getRoot: function () {
5224 var oItem = this.parent,
5230 oParentMenu = oItem.parent;
5232 returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5248 * @description Returns a string representing the menu.
5251 toString: function () {
5253 var sReturnVal = _MENU,
5258 sReturnVal += (_SPACE + sId);
5268 * @method setItemGroupTitle
5269 * @description Sets the title of a group of menu items.
5270 * @param {HTML} p_sGroupTitle String or markup specifying the title of the group. The title is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5271 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5272 * the title belongs.
5274 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5281 if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5283 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5284 oTitle = this._aGroupTitleElements[nGroupIndex];
5289 oTitle.innerHTML = p_sGroupTitle;
5294 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5296 oTitle.innerHTML = p_sGroupTitle;
5298 this._aGroupTitleElements[nGroupIndex] = oTitle;
5303 i = this._aGroupTitleElements.length - 1;
5307 if (this._aGroupTitleElements[i]) {
5309 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5319 if (nFirstIndex !== null) {
5321 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
5326 this.changeContentEvent.fire();
5336 * @description Appends an item to the menu.
5337 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5338 * instance to be added to the menu.
5339 * @param {HTML} p_oItem String or markup specifying content of the item to be added
5340 * to the menu. The item text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5341 * @param {Object} p_oItem Object literal containing a set of menu item
5342 * configuration properties.
5343 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5344 * which the item belongs.
5345 * @return {YAHOO.widget.MenuItem}
5347 addItem: function (p_oItem, p_nGroupIndex) {
5349 return this._addItemToGroup(p_nGroupIndex, p_oItem);
5356 * @description Adds an array of items to the menu.
5357 * @param {Array} p_aItems Array of items to be added to the menu. The array
5358 * can contain strings specifying the markup for the content of each item to be created, object
5359 * literals specifying each of the menu item configuration properties,
5360 * or MenuItem instances. The item content if provided as a string is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5361 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5362 * which the items belongs.
5365 addItems: function (p_aItems, p_nGroupIndex) {
5374 if (Lang.isArray(p_aItems)) {
5376 nItems = p_aItems.length;
5379 for(i=0; i<nItems; i++) {
5381 oItem = p_aItems[i];
5385 if (Lang.isArray(oItem)) {
5387 aItems[aItems.length] = this.addItems(oItem, i);
5392 aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5401 if (aItems.length) {
5415 * @method insertItem
5416 * @description Inserts an item into the menu at the specified index.
5417 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5418 * instance to be added to the menu.
5419 * @param {String} p_oItem String specifying the text of the item to be added
5421 * @param {Object} p_oItem Object literal containing a set of menu item
5422 * configuration properties.
5423 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5424 * the item should be added.
5425 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5427 * @return {YAHOO.widget.MenuItem}
5429 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5431 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5437 * @method removeItem
5438 * @description Removes the specified item from the menu.
5439 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5440 * instance to be removed from the menu.
5441 * @param {Number} p_oObject Number specifying the index of the item
5443 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5444 * which the item belongs.
5445 * @return {YAHOO.widget.MenuItem}
5447 removeItem: function (p_oObject, p_nGroupIndex) {
5452 if (!Lang.isUndefined(p_oObject)) {
5454 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5456 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5459 else if (Lang.isNumber(p_oObject)) {
5461 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5483 * @description Returns an array of all of the items in the menu.
5486 getItems: function () {
5488 var aGroups = this._aItemGroups,
5494 if (Lang.isArray(aGroups)) {
5496 nGroups = aGroups.length;
5498 returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5508 * @method getItemGroups
5509 * @description Multi-dimensional Array representing the menu items as they
5510 * are grouped in the menu.
5513 getItemGroups: function () {
5515 return this._aItemGroups;
5522 * @description Returns the item at the specified index.
5523 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5524 * item to be retrieved.
5525 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5527 * @return {YAHOO.widget.MenuItem}
5529 getItem: function (p_nItemIndex, p_nGroupIndex) {
5534 if (Lang.isNumber(p_nItemIndex)) {
5536 aGroup = this._getItemGroup(p_nGroupIndex);
5540 returnVal = aGroup[p_nItemIndex];
5552 * @method getSubmenus
5553 * @description Returns an array of all of the submenus that are immediate
5554 * children of the menu.
5557 getSubmenus: function () {
5559 var aItems = this.getItems(),
5560 nItems = aItems.length,
5571 for(i=0; i<nItems; i++) {
5577 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5581 aSubmenus[aSubmenus.length] = oSubmenu;
5597 * @method clearContent
5598 * @description Removes all of the content from the menu, including the menu
5599 * items, group titles, header and footer.
5601 clearContent: function () {
5603 var aItems = this.getItems(),
5604 nItems = aItems.length,
5605 oElement = this.element,
5607 oHeader = this.header,
5608 oFooter = this.footer,
5624 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5628 this.cfg.configChangedEvent.unsubscribe(
5629 this._onParentMenuConfigChange, oSubmenu);
5631 this.renderEvent.unsubscribe(this._onParentMenuRender,
5636 this.removeItem(oItem, oItem.groupIndex);
5648 Event.purgeElement(oHeader);
5649 oElement.removeChild(oHeader);
5656 Event.purgeElement(oFooter);
5657 oElement.removeChild(oFooter);
5663 Event.purgeElement(oBody);
5665 oBody.innerHTML = _EMPTY_STRING;
5669 this.activeItem = null;
5671 this._aItemGroups = [];
5672 this._aListElements = [];
5673 this._aGroupTitleElements = [];
5675 this.cfg.setProperty(_WIDTH, null);
5682 * @description Removes the menu's <code><div></code> element
5683 * (and accompanying child nodes) from the document.
5684 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
5685 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
5688 destroy: function (shallowPurge) {
5692 this.clearContent();
5694 this._aItemGroups = null;
5695 this._aListElements = null;
5696 this._aGroupTitleElements = null;
5699 // Continue with the superclass implementation of this method
5701 Menu.superclass.destroy.call(this, shallowPurge);
5708 * @method setInitialFocus
5709 * @description Sets focus to the menu's first enabled item.
5711 setInitialFocus: function () {
5713 var oItem = this._getFirstEnabledItem();
5725 * @method setInitialSelection
5726 * @description Sets the "selected" configuration property of the menu's first
5727 * enabled item to "true."
5729 setInitialSelection: function () {
5731 var oItem = this._getFirstEnabledItem();
5735 oItem.cfg.setProperty(_SELECTED, true);
5742 * @method clearActiveItem
5743 * @description Sets the "selected" configuration property of the menu's active
5744 * item to "false" and hides the item's submenu.
5745 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5746 * should be blurred.
5748 clearActiveItem: function (p_bBlur) {
5750 if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5752 this._cancelShowDelay();
5757 var oActiveItem = this.activeItem,
5763 oConfig = oActiveItem.cfg;
5769 this.getRoot()._hasFocus = true;
5773 oConfig.setProperty(_SELECTED, false);
5775 oSubmenu = oConfig.getProperty(_SUBMENU);
5784 this.activeItem = null;
5793 * @description Causes the menu to receive focus and fires the "focus" event.
5795 focus: function () {
5797 if (!this.hasFocus()) {
5799 this.setInitialFocus();
5808 * @description Causes the menu to lose focus and fires the "blur" event.
5814 if (this.hasFocus()) {
5816 oItem = MenuManager.getFocusedMenuItem();
5831 * @description Returns a boolean indicating whether or not the menu has focus.
5834 hasFocus: function () {
5836 return (MenuManager.getFocusedMenu() == this.getRoot());
5841 _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5843 var oItem = p_aArgs[0],
5844 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5847 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5853 _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5855 var oSubmenu = this.cfg.getProperty(_SUBMENU);
5858 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5865 * Adds the specified CustomEvent subscriber to the menu and each of
5868 * @param p_type {string} the type, or name of the event
5869 * @param p_fn {function} the function to exectute when the event fires
5870 * @param p_obj {Object} An object to be passed along when the event
5872 * @param p_override {boolean} If true, the obj passed in becomes the
5873 * execution scope of the listener
5875 subscribe: function () {
5877 // Subscribe to the event for this Menu instance
5878 Menu.superclass.subscribe.apply(this, arguments);
5880 // Subscribe to the "itemAdded" event so that all future submenus
5881 // also subscribe to this event
5882 Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5885 var aItems = this.getItems(),
5894 nItems = aItems.length;
5903 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5906 oSubmenu.subscribe.apply(oSubmenu, arguments);
5909 oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5922 unsubscribe: function () {
5924 // Remove the event for this Menu instance
5925 Menu.superclass.unsubscribe.apply(this, arguments);
5927 // Remove the "itemAdded" event so that all future submenus don't have
5928 // the event handler
5929 Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5932 var aItems = this.getItems(),
5941 nItems = aItems.length;
5950 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5953 oSubmenu.unsubscribe.apply(oSubmenu, arguments);
5956 oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5970 * @description Initializes the class's configurable properties which can be
5971 * changed using the menu's Config object ("cfg").
5972 * @method initDefaultConfig
5974 initDefaultConfig: function () {
5976 Menu.superclass.initDefaultConfig.call(this);
5978 var oConfig = this.cfg;
5981 // Module documentation overrides
5985 * @description Object or array of objects representing the ContainerEffect
5986 * classes that are active for animating the container. When set this
5987 * property is automatically applied to all submenus.
5992 // Overlay documentation overrides
5997 * @description Number representing the absolute x-coordinate position of
5998 * the Menu. This property is only applied when the "position"
5999 * configuration property is set to dynamic.
6007 * @description Number representing the absolute y-coordinate position of
6008 * the Menu. This property is only applied when the "position"
6009 * configuration property is set to dynamic.
6016 * @description Array of the absolute x and y positions of the Menu. This
6017 * property is only applied when the "position" configuration property is
6027 * @description Array of context arguments for context-sensitive positioning.
6028 * The format is: [id or element, element corner, context corner].
6029 * For example, setting this property to ["img1", "tl", "bl"] would
6030 * align the Menu's top left corner to the context element's
6031 * bottom left corner. This property is only applied when the "position"
6032 * configuration property is set to dynamic.
6039 * @config fixedcenter
6040 * @description Boolean indicating if the Menu should be anchored to the
6041 * center of the viewport. This property is only applied when the
6042 * "position" configuration property is set to dynamic.
6050 * @description Boolean indicating whether or not the Menu should
6051 * have an IFRAME shim; used to prevent SELECT elements from
6052 * poking through an Overlay instance in IE6. When set to "true",
6053 * the iframe shim is created when the Menu instance is intially
6054 * made visible. This property is only applied when the "position"
6055 * configuration property is set to dynamic and is automatically applied
6058 * @default true for IE6 and below, false for all other browsers.
6062 // Add configuration attributes
6065 Change the default value for the "visible" configuration
6066 property to "false" by re-adding the property.
6071 * @description Boolean indicating whether or not the menu is visible. If
6072 * the menu's "position" configuration property is set to "dynamic" (the
6073 * default), this property toggles the menu's <code><div></code>
6074 * element's "visibility" style property between "visible" (true) or
6075 * "hidden" (false). If the menu's "position" configuration property is
6076 * set to "static" this property toggles the menu's
6077 * <code><div></code> element's "display" style property
6078 * between "block" (true) or "none" (false).
6082 oConfig.addProperty(
6085 handler: this.configVisible,
6086 value: VISIBLE_CONFIG.value,
6087 validator: VISIBLE_CONFIG.validator
6093 Change the default value for the "constraintoviewport" configuration
6094 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6098 * @config constraintoviewport
6099 * @description Boolean indicating if the menu will try to remain inside
6100 * the boundaries of the size of viewport. This property is only applied
6101 * when the "position" configuration property is set to dynamic and is
6102 * automatically applied to all submenus.
6106 oConfig.addProperty(
6107 CONSTRAIN_TO_VIEWPORT_CONFIG.key,
6109 handler: this.configConstrainToViewport,
6110 value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
6111 validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
6112 supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
6118 Change the default value for the "preventcontextoverlap" configuration
6119 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6123 * @config preventcontextoverlap
6124 * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
6125 * when the "constraintoviewport" configuration property is set to "true".
6129 oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6131 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
6132 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
6133 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6140 * @description String indicating how a menu should be positioned on the
6141 * screen. Possible values are "static" and "dynamic." Static menus are
6142 * visible by default and reside in the normal flow of the document
6143 * (CSS position: static). Dynamic menus are hidden by default, reside
6144 * out of the normal flow of the document (CSS position: absolute), and
6145 * can overlay other elements on the screen.
6149 oConfig.addProperty(
6150 POSITION_CONFIG.key,
6152 handler: this.configPosition,
6153 value: POSITION_CONFIG.value,
6154 validator: POSITION_CONFIG.validator,
6155 supercedes: POSITION_CONFIG.supercedes
6161 * @config submenualignment
6162 * @description Array defining how submenus should be aligned to their
6163 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6164 * a submenu's top left corner is aligned to its parent menu item's top
6166 * @default ["tl","tr"]
6169 oConfig.addProperty(
6170 SUBMENU_ALIGNMENT_CONFIG.key,
6172 value: SUBMENU_ALIGNMENT_CONFIG.value,
6173 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6179 * @config autosubmenudisplay
6180 * @description Boolean indicating if submenus are automatically made
6181 * visible when the user mouses over the menu's items.
6185 oConfig.addProperty(
6186 AUTO_SUBMENU_DISPLAY_CONFIG.key,
6188 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
6189 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6190 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6197 * @description Number indicating the time (in milliseconds) that should
6198 * expire before a submenu is made visible when the user mouses over
6199 * the menu's items. This property is only applied when the "position"
6200 * configuration property is set to dynamic and is automatically applied
6205 oConfig.addProperty(
6206 SHOW_DELAY_CONFIG.key,
6208 value: SHOW_DELAY_CONFIG.value,
6209 validator: SHOW_DELAY_CONFIG.validator,
6210 suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6217 * @description Number indicating the time (in milliseconds) that should
6218 * expire before the menu is hidden. This property is only applied when
6219 * the "position" configuration property is set to dynamic and is
6220 * automatically applied to all submenus.
6224 oConfig.addProperty(
6225 HIDE_DELAY_CONFIG.key,
6227 handler: this.configHideDelay,
6228 value: HIDE_DELAY_CONFIG.value,
6229 validator: HIDE_DELAY_CONFIG.validator,
6230 suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6236 * @config submenuhidedelay
6237 * @description Number indicating the time (in milliseconds) that should
6238 * expire before a submenu is hidden when the user mouses out of a menu item
6239 * heading in the direction of a submenu. The value must be greater than or
6240 * equal to the value specified for the "showdelay" configuration property.
6241 * This property is only applied when the "position" configuration property
6242 * is set to dynamic and is automatically applied to all submenus.
6246 oConfig.addProperty(
6247 SUBMENU_HIDE_DELAY_CONFIG.key,
6249 value: SUBMENU_HIDE_DELAY_CONFIG.value,
6250 validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6251 suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6257 * @config clicktohide
6258 * @description Boolean indicating if the menu will automatically be
6259 * hidden if the user clicks outside of it. This property is only
6260 * applied when the "position" configuration property is set to dynamic
6261 * and is automatically applied to all submenus.
6265 oConfig.addProperty(
6266 CLICK_TO_HIDE_CONFIG.key,
6268 value: CLICK_TO_HIDE_CONFIG.value,
6269 validator: CLICK_TO_HIDE_CONFIG.validator,
6270 suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6277 * @description HTML element reference or string specifying the id
6278 * attribute of the HTML element that the menu's markup should be
6280 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6281 * level-one-html.html#ID-58190037">HTMLElement</a>|String
6282 * @default document.body
6284 oConfig.addProperty(
6285 CONTAINER_CONFIG.key,
6287 handler: this.configContainer,
6288 value: document.body,
6289 suppressEvent: CONTAINER_CONFIG.suppressEvent
6295 * @config scrollincrement
6296 * @description Number used to control the scroll speed of a menu. Used to
6297 * increment the "scrollTop" property of the menu's body by when a menu's
6298 * content is scrolling. When set this property is automatically applied
6303 oConfig.addProperty(
6304 SCROLL_INCREMENT_CONFIG.key,
6306 value: SCROLL_INCREMENT_CONFIG.value,
6307 validator: SCROLL_INCREMENT_CONFIG.validator,
6308 supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6309 suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6315 * @config minscrollheight
6316 * @description Number defining the minimum threshold for the "maxheight"
6317 * configuration property. When set this property is automatically applied
6322 oConfig.addProperty(
6323 MIN_SCROLL_HEIGHT_CONFIG.key,
6325 value: MIN_SCROLL_HEIGHT_CONFIG.value,
6326 validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6327 supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6328 suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6335 * @description Number defining the maximum height (in pixels) for a menu's
6336 * body element (<code><div class="bd"></code>). Once a menu's body
6337 * exceeds this height, the contents of the body are scrolled to maintain
6338 * this value. This value cannot be set lower than the value of the
6339 * "minscrollheight" configuration property.
6343 oConfig.addProperty(
6344 MAX_HEIGHT_CONFIG.key,
6346 handler: this.configMaxHeight,
6347 value: MAX_HEIGHT_CONFIG.value,
6348 validator: MAX_HEIGHT_CONFIG.validator,
6349 suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6350 supercedes: MAX_HEIGHT_CONFIG.supercedes
6357 * @description String representing the CSS class to be applied to the
6358 * menu's root <code><div></code> element. The specified class(es)
6359 * are appended in addition to the default class as specified by the menu's
6360 * CSS_CLASS_NAME constant. When set this property is automatically
6361 * applied to all submenus.
6365 oConfig.addProperty(
6366 CLASS_NAME_CONFIG.key,
6368 handler: this.configClassName,
6369 value: CLASS_NAME_CONFIG.value,
6370 validator: CLASS_NAME_CONFIG.validator,
6371 supercedes: CLASS_NAME_CONFIG.supercedes
6378 * @description Boolean indicating if the menu should be disabled.
6379 * Disabling a menu disables each of its items. (Disabled menu items are
6380 * dimmed and will not respond to user input or fire events.) Disabled
6381 * menus have a corresponding "disabled" CSS class applied to their root
6382 * <code><div></code> element.
6386 oConfig.addProperty(
6387 DISABLED_CONFIG.key,
6389 handler: this.configDisabled,
6390 value: DISABLED_CONFIG.value,
6391 validator: DISABLED_CONFIG.validator,
6392 suppressEvent: DISABLED_CONFIG.suppressEvent
6399 * @description Boolean indicating if the menu should have a shadow.
6403 oConfig.addProperty(
6406 handler: this.configShadow,
6407 value: SHADOW_CONFIG.value,
6408 validator: SHADOW_CONFIG.validator
6415 * @description Boolean indicating if the menu should remain open when clicked.
6419 oConfig.addProperty(
6420 KEEP_OPEN_CONFIG.key,
6422 value: KEEP_OPEN_CONFIG.value,
6423 validator: KEEP_OPEN_CONFIG.validator
6429 }); // END YAHOO.lang.extend
6438 * Creates an item for a menu.
6440 * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6441 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6442 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6443 * the <code><li></code> element of the menu item.
6444 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6445 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6446 * specifying the <code><optgroup></code> element of the menu item.
6447 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6448 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6449 * specifying the <code><option></code> element of the menu item.
6450 * @param {Object} p_oConfig Optional. Object literal specifying the
6451 * configuration for the menu item. See configuration class documentation
6456 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6462 this.parent = p_oConfig.parent;
6463 this.value = p_oConfig.value;
6464 this.id = p_oConfig.id;
6468 this.init(p_oObject, p_oConfig);
6475 var Dom = YAHOO.util.Dom,
6476 Module = YAHOO.widget.Module,
6477 Menu = YAHOO.widget.Menu,
6478 MenuItem = YAHOO.widget.MenuItem,
6479 CustomEvent = YAHOO.util.CustomEvent,
6483 // Private string constants
6488 _HELP_TEXT = "helptext",
6491 _EMPHASIS = "emphasis",
6492 _STRONG_EMPHASIS = "strongemphasis",
6493 _CHECKED = "checked",
6494 _SUBMENU = "submenu",
6495 _DISABLED = "disabled",
6496 _SELECTED = "selected",
6497 _HAS_SUBMENU = "hassubmenu",
6498 _CHECKED_DISABLED = "checked-disabled",
6499 _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6500 _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6501 _CHECKED_SELECTED = "checked-selected",
6502 _ONCLICK = "onclick",
6503 _CLASSNAME = "classname",
6506 _OPTGROUP = "OPTGROUP",
6507 _LI_UPPERCASE = "LI",
6511 _START_HELP_TEXT = "<em class=\"helptext\">",
6514 _START_STRONG = "<strong>",
6515 _END_STRONG = "</strong>",
6516 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6520 _VISIBLE = "visible",
6522 _MENUITEM = "MenuItem",
6526 _LI_LOWERCASE = "li",
6527 _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6531 ["mouseOverEvent", "mouseover"],
6532 ["mouseOutEvent", "mouseout"],
6533 ["mouseDownEvent", "mousedown"],
6534 ["mouseUpEvent", "mouseup"],
6535 ["clickEvent", _CLICK],
6536 ["keyPressEvent", "keypress"],
6537 ["keyDownEvent", "keydown"],
6538 ["keyUpEvent", "keyup"],
6539 ["focusEvent", "focus"],
6540 ["blurEvent", "blur"],
6541 ["destroyEvent", "destroy"]
6547 value: _EMPTY_STRING,
6548 validator: Lang.isString,
6552 HELP_TEXT_CONFIG = {
6554 supercedes: [_TEXT],
6572 validator: Lang.isBoolean,
6573 suppressEvent: true,
6577 STRONG_EMPHASIS_CONFIG = {
6578 key: _STRONG_EMPHASIS,
6580 validator: Lang.isBoolean,
6581 suppressEvent: true,
6588 validator: Lang.isBoolean,
6589 suppressEvent: true,
6590 supercedes: [_DISABLED, _SELECTED]
6595 suppressEvent: true,
6596 supercedes: [_DISABLED, _SELECTED]
6602 validator: Lang.isBoolean,
6603 suppressEvent: true,
6604 supercedes: [_TEXT, _SELECTED]
6610 validator: Lang.isBoolean,
6619 CLASS_NAME_CONFIG = {
6622 validator: Lang.isString,
6626 KEY_LISTENER_CONFIG = {
6632 m_oMenuItemTemplate = null,
6638 * @method getClassNameForState
6639 * @description Returns a class name for the specified prefix and state. If the class name does not
6640 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6642 * @param {String} prefix String representing the prefix for the class name
6643 * @param {String} state String representing a state - "disabled," "checked," etc.
6645 var getClassNameForState = function (prefix, state) {
6647 var oClassNames = CLASS_NAMES[prefix];
6650 CLASS_NAMES[prefix] = {};
6651 oClassNames = CLASS_NAMES[prefix];
6655 var sClassName = oClassNames[state];
6658 sClassName = prefix + _HYPHEN + state;
6659 oClassNames[state] = sClassName;
6668 * @method addClassNameForState
6669 * @description Applies a class name to a MenuItem instance's <LI> and <A> elements
6670 * that represents a MenuItem's state - "disabled," "checked," etc.
6672 * @param {String} state String representing a state - "disabled," "checked," etc.
6674 var addClassNameForState = function (state) {
6676 Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6677 Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6682 * @method removeClassNameForState
6683 * @description Removes a class name from a MenuItem instance's <LI> and <A> elements
6684 * that represents a MenuItem's state - "disabled," "checked," etc.
6686 * @param {String} state String representing a state - "disabled," "checked," etc.
6688 var removeClassNameForState = function (state) {
6690 Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6691 Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6696 MenuItem.prototype = {
6699 * @property CSS_CLASS_NAME
6700 * @description String representing the CSS class(es) to be applied to the
6701 * <code><li></code> element of the menu item.
6702 * @default "yuimenuitem"
6706 CSS_CLASS_NAME: "yuimenuitem",
6710 * @property CSS_LABEL_CLASS_NAME
6711 * @description String representing the CSS class(es) to be applied to the
6712 * menu item's <code><a></code> element.
6713 * @default "yuimenuitemlabel"
6717 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6721 * @property SUBMENU_TYPE
6722 * @description Object representing the type of menu to instantiate and
6723 * add when parsing the child nodes of the menu item's source HTML element.
6725 * @type YAHOO.widget.Menu
6731 // Private member variables
6735 * @property _oAnchor
6736 * @description Object reference to the menu item's
6737 * <code><a></code> element.
6740 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6741 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6747 * @property _oHelpTextEM
6748 * @description Object reference to the menu item's help text
6749 * <code><em></code> element.
6752 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6753 * one-html.html#ID-58190037">HTMLElement</a>
6759 * @property _oSubmenu
6760 * @description Object reference to the menu item's submenu.
6763 * @type YAHOO.widget.Menu
6769 * @property _oOnclickAttributeValue
6770 * @description Object reference to the menu item's current value for the
6771 * "onclick" configuration attribute.
6776 _oOnclickAttributeValue: null,
6780 * @property _sClassName
6781 * @description The current value of the "classname" configuration attribute.
6790 // Public properties
6794 * @property constructor
6795 * @description Object reference to the menu item's constructor function.
6796 * @default YAHOO.widget.MenuItem
6797 * @type YAHOO.widget.MenuItem
6799 constructor: MenuItem,
6804 * @description Number indicating the ordinal position of the menu item in
6813 * @property groupIndex
6814 * @description Number indicating the index of the group to which the menu
6824 * @description Object reference to the menu item's parent menu.
6826 * @type YAHOO.widget.Menu
6833 * @description Object reference to the menu item's
6834 * <code><li></code> element.
6835 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6836 * -one-html.html#ID-74680021">HTMLLIElement</a>
6837 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6838 * one-html.html#ID-74680021">HTMLLIElement</a>
6844 * @property srcElement
6845 * @description Object reference to the HTML element (either
6846 * <code><li></code>, <code><optgroup></code> or
6847 * <code><option></code>) used create the menu item.
6848 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6849 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6850 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6851 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6852 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6853 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6854 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6855 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6856 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6857 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6864 * @description Object reference to the menu item's value.
6873 * @deprecated Use YAHOO.env.ua
6874 * @description String representing the browser.
6877 browser: Module.prototype.browser,
6882 * @description Id of the menu item's root <code><li></code>
6883 * element. This property should be set via the constructor using the
6884 * configuration object literal. If an id is not specified, then one will
6885 * be created using the "generateId" method of the Dom utility.
6897 * @event destroyEvent
6898 * @description Fires when the menu item's <code><li></code>
6899 * element is removed from its parent <code><ul></code> element.
6900 * @type YAHOO.util.CustomEvent
6905 * @event mouseOverEvent
6906 * @description Fires when the mouse has entered the menu item. Passes
6907 * back the DOM Event object as an argument.
6908 * @type YAHOO.util.CustomEvent
6913 * @event mouseOutEvent
6914 * @description Fires when the mouse has left the menu item. Passes back
6915 * the DOM Event object as an argument.
6916 * @type YAHOO.util.CustomEvent
6921 * @event mouseDownEvent
6922 * @description Fires when the user mouses down on the menu item. Passes
6923 * back the DOM Event object as an argument.
6924 * @type YAHOO.util.CustomEvent
6929 * @event mouseUpEvent
6930 * @description Fires when the user releases a mouse button while the mouse
6931 * is over the menu item. Passes back the DOM Event object as an argument.
6932 * @type YAHOO.util.CustomEvent
6938 * @description Fires when the user clicks the on the menu item. Passes
6939 * back the DOM Event object as an argument.
6940 * @type YAHOO.util.CustomEvent
6945 * @event keyPressEvent
6946 * @description Fires when the user presses an alphanumeric key when the
6947 * menu item has focus. Passes back the DOM Event object as an argument.
6948 * @type YAHOO.util.CustomEvent
6953 * @event keyDownEvent
6954 * @description Fires when the user presses a key when the menu item has
6955 * focus. Passes back the DOM Event object as an argument.
6956 * @type YAHOO.util.CustomEvent
6962 * @description Fires when the user releases a key when the menu item has
6963 * focus. Passes back the DOM Event object as an argument.
6964 * @type YAHOO.util.CustomEvent
6970 * @description Fires when the menu item receives focus.
6971 * @type YAHOO.util.CustomEvent
6977 * @description Fires when the menu item loses the input focus.
6978 * @type YAHOO.util.CustomEvent
6984 * @description The MenuItem class's initialization method. This method is
6985 * automatically called by the constructor, and sets up all DOM references
6986 * for pre-existing markup, and creates required markup if it is not
6988 * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6989 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6990 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6991 * the <code><li></code> element of the menu item.
6992 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6993 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6994 * specifying the <code><optgroup></code> element of the menu item.
6995 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6996 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6997 * specifying the <code><option></code> element of the menu item.
6998 * @param {Object} p_oConfig Optional. Object literal specifying the
6999 * configuration for the menu item. See configuration class documentation
7002 init: function (p_oObject, p_oConfig) {
7005 if (!this.SUBMENU_TYPE) {
7007 this.SUBMENU_TYPE = Menu;
7012 // Create the config object
7014 this.cfg = new YAHOO.util.Config(this);
7016 this.initDefaultConfig();
7018 var oConfig = this.cfg,
7029 if (Lang.isString(p_oObject)) {
7031 this._createRootNodeStructure();
7033 oConfig.queueProperty(_TEXT, p_oObject);
7036 else if (p_oObject && p_oObject.tagName) {
7038 switch(p_oObject.tagName.toUpperCase()) {
7042 this._createRootNodeStructure();
7044 oConfig.queueProperty(_TEXT, p_oObject.text);
7045 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7047 this.value = p_oObject.value;
7049 this.srcElement = p_oObject;
7055 this._createRootNodeStructure();
7057 oConfig.queueProperty(_TEXT, p_oObject.label);
7058 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7060 this.srcElement = p_oObject;
7062 this._initSubTree();
7068 // Get the anchor node (if it exists)
7070 oAnchor = Dom.getFirstChild(p_oObject);
7073 // Capture the "text" and/or the "URL"
7077 sURL = oAnchor.getAttribute(_HREF, 2);
7078 sTarget = oAnchor.getAttribute(_TARGET);
7080 sText = oAnchor.innerHTML;
7084 this.srcElement = p_oObject;
7085 this.element = p_oObject;
7086 this._oAnchor = oAnchor;
7089 Set these properties silently to sync up the
7090 configuration object without making changes to the
7094 oConfig.setProperty(_TEXT, sText, true);
7095 oConfig.setProperty(_URL, sURL, true);
7096 oConfig.setProperty(_TARGET, sTarget, true);
7098 this._initSubTree();
7109 sId = (this.srcElement || this.element).id;
7113 sId = this.id || Dom.generateId();
7115 this.element.id = sId;
7122 Dom.addClass(this.element, this.CSS_CLASS_NAME);
7123 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7126 i = EVENT_TYPES.length - 1;
7130 aEventData = EVENT_TYPES[i];
7132 oCustomEvent = this.createEvent(aEventData[1]);
7133 oCustomEvent.signature = CustomEvent.LIST;
7135 this[aEventData[0]] = oCustomEvent;
7143 oConfig.applyConfig(p_oConfig);
7147 oConfig.fireQueue();
7158 * @method _createRootNodeStructure
7159 * @description Creates the core DOM structure for the menu item.
7162 _createRootNodeStructure: function () {
7167 if (!m_oMenuItemTemplate) {
7169 m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7170 m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7174 oElement = m_oMenuItemTemplate.cloneNode(true);
7175 oElement.className = this.CSS_CLASS_NAME;
7177 oAnchor = oElement.firstChild;
7178 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7180 this.element = oElement;
7181 this._oAnchor = oAnchor;
7187 * @method _initSubTree
7188 * @description Iterates the source element's childNodes collection and uses
7189 * the child nodes to instantiate other menus.
7192 _initSubTree: function () {
7194 var oSrcEl = this.srcElement,
7203 if (oSrcEl.childNodes.length > 0) {
7205 if (this.parent.lazyLoad && this.parent.srcElement &&
7206 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7208 oConfig.setProperty(
7210 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7216 oNode = oSrcEl.firstChild;
7221 if (oNode && oNode.tagName) {
7223 switch(oNode.tagName.toUpperCase()) {
7227 oConfig.setProperty(_SUBMENU, oNode);
7233 aOptions[aOptions.length] = oNode;
7242 while((oNode = oNode.nextSibling));
7245 nOptions = aOptions.length;
7249 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7251 oConfig.setProperty(_SUBMENU, oMenu);
7253 for(n=0; n<nOptions; n++) {
7255 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7269 // Event handlers for configuration properties
7273 * @method configText
7274 * @description Event handler for when the "text" configuration property of
7275 * the menu item changes.
7276 * @param {String} p_sType String representing the name of the event that
7278 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7279 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7280 * that fired the event.
7282 configText: function (p_sType, p_aArgs, p_oItem) {
7284 var sText = p_aArgs[0],
7286 oAnchor = this._oAnchor,
7287 sHelpText = oConfig.getProperty(_HELP_TEXT),
7288 sHelpTextHTML = _EMPTY_STRING,
7289 sEmphasisStartTag = _EMPTY_STRING,
7290 sEmphasisEndTag = _EMPTY_STRING;
7298 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7303 if (oConfig.getProperty(_EMPHASIS)) {
7305 sEmphasisStartTag = _START_EM;
7306 sEmphasisEndTag = _END_EM;
7311 if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7313 sEmphasisStartTag = _START_STRONG;
7314 sEmphasisEndTag = _END_STRONG;
7319 oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7327 * @method configHelpText
7328 * @description Event handler for when the "helptext" configuration property
7329 * of the menu item changes.
7330 * @param {String} p_sType String representing the name of the event that
7332 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7333 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7334 * that fired the event.
7336 configHelpText: function (p_sType, p_aArgs, p_oItem) {
7338 this.cfg.refireEvent(_TEXT);
7345 * @description Event handler for when the "url" configuration property of
7346 * the menu item changes.
7347 * @param {String} p_sType String representing the name of the event that
7349 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7350 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7351 * that fired the event.
7353 configURL: function (p_sType, p_aArgs, p_oItem) {
7355 var sURL = p_aArgs[0];
7363 var oAnchor = this._oAnchor;
7367 oAnchor.removeAttribute(_HREF);
7371 oAnchor.setAttribute(_HREF, sURL);
7377 * @method configTarget
7378 * @description Event handler for when the "target" configuration property
7379 * of the menu item changes.
7380 * @param {String} p_sType String representing the name of the event that
7382 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7383 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7384 * that fired the event.
7386 configTarget: function (p_sType, p_aArgs, p_oItem) {
7388 var sTarget = p_aArgs[0],
7389 oAnchor = this._oAnchor;
7391 if (sTarget && sTarget.length > 0) {
7393 oAnchor.setAttribute(_TARGET, sTarget);
7398 oAnchor.removeAttribute(_TARGET);
7406 * @method configEmphasis
7407 * @description Event handler for when the "emphasis" 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 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7417 var bEmphasis = p_aArgs[0],
7421 if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7423 oConfig.setProperty(_STRONG_EMPHASIS, false);
7428 oConfig.refireEvent(_TEXT);
7434 * @method configStrongEmphasis
7435 * @description Event handler for when the "strongemphasis" configuration
7436 * property of the menu item changes.
7437 * @param {String} p_sType String representing the name of the event that
7439 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7440 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7441 * that fired the event.
7443 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7445 var bStrongEmphasis = p_aArgs[0],
7449 if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7451 oConfig.setProperty(_EMPHASIS, false);
7455 oConfig.refireEvent(_TEXT);
7461 * @method configChecked
7462 * @description Event handler for when the "checked" configuration property
7463 * of the menu item changes.
7464 * @param {String} p_sType String representing the name of the event that
7466 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7467 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7468 * that fired the event.
7470 configChecked: function (p_sType, p_aArgs, p_oItem) {
7472 var bChecked = p_aArgs[0],
7478 addClassNameForState.call(this, _CHECKED);
7483 removeClassNameForState.call(this, _CHECKED);
7487 oConfig.refireEvent(_TEXT);
7490 if (oConfig.getProperty(_DISABLED)) {
7492 oConfig.refireEvent(_DISABLED);
7497 if (oConfig.getProperty(_SELECTED)) {
7499 oConfig.refireEvent(_SELECTED);
7508 * @method configDisabled
7509 * @description Event handler for when the "disabled" configuration property
7510 * of the menu item changes.
7511 * @param {String} p_sType String representing the name of the event that
7513 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7514 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7515 * that fired the event.
7517 configDisabled: function (p_sType, p_aArgs, p_oItem) {
7519 var bDisabled = p_aArgs[0],
7521 oSubmenu = oConfig.getProperty(_SUBMENU),
7522 bChecked = oConfig.getProperty(_CHECKED);
7527 if (oConfig.getProperty(_SELECTED)) {
7529 oConfig.setProperty(_SELECTED, false);
7534 addClassNameForState.call(this, _DISABLED);
7539 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7546 addClassNameForState.call(this, _CHECKED_DISABLED);
7553 removeClassNameForState.call(this, _DISABLED);
7558 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7565 removeClassNameForState.call(this, _CHECKED_DISABLED);
7575 * @method configSelected
7576 * @description Event handler for when the "selected" configuration property
7577 * of the menu item changes.
7578 * @param {String} p_sType String representing the name of the event that
7580 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7581 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7582 * that fired the event.
7584 configSelected: function (p_sType, p_aArgs, p_oItem) {
7586 var oConfig = this.cfg,
7587 oAnchor = this._oAnchor,
7589 bSelected = p_aArgs[0],
7590 bChecked = oConfig.getProperty(_CHECKED),
7591 oSubmenu = oConfig.getProperty(_SUBMENU);
7601 if (bSelected && !oConfig.getProperty(_DISABLED)) {
7603 addClassNameForState.call(this, _SELECTED);
7608 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7615 addClassNameForState.call(this, _CHECKED_SELECTED);
7622 removeClassNameForState.call(this, _SELECTED);
7627 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7634 removeClassNameForState.call(this, _CHECKED_SELECTED);
7641 if (this.hasFocus() && UA.opera) {
7651 * @method _onSubmenuBeforeHide
7652 * @description "beforehide" Custom Event handler for a submenu.
7654 * @param {String} p_sType String representing the name of the event that
7656 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7658 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7660 var oItem = this.parent,
7665 oItem._oAnchor.blur();
7666 oMenu.beforeHideEvent.unsubscribe(onHide);
7671 if (oItem.hasFocus()) {
7673 oMenu = oItem.parent;
7675 oMenu.beforeHideEvent.subscribe(onHide);
7683 * @method configSubmenu
7684 * @description Event handler for when the "submenu" configuration property
7685 * of the menu item changes.
7686 * @param {String} p_sType String representing the name of the event that
7688 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7689 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7690 * that fired the event.
7692 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7694 var oSubmenu = p_aArgs[0],
7696 bLazyLoad = this.parent && this.parent.lazyLoad,
7704 if (oSubmenu instanceof Menu) {
7707 oMenu.parent = this;
7708 oMenu.lazyLoad = bLazyLoad;
7711 else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7713 sSubmenuId = oSubmenu.id;
7714 oSubmenuConfig = oSubmenu;
7716 oSubmenuConfig.lazyload = bLazyLoad;
7717 oSubmenuConfig.parent = this;
7719 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7722 // Set the value of the property to the Menu instance
7724 oConfig.setProperty(_SUBMENU, oMenu, true);
7729 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7732 // Set the value of the property to the Menu instance
7734 oConfig.setProperty(_SUBMENU, oMenu, true);
7741 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7743 addClassNameForState.call(this, _HAS_SUBMENU);
7746 if (oConfig.getProperty(_URL) === _HASH) {
7748 oConfig.setProperty(_URL, (_HASH + oMenu.id));
7753 this._oSubmenu = oMenu;
7758 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7767 removeClassNameForState.call(this, _HAS_SUBMENU);
7769 if (this._oSubmenu) {
7771 this._oSubmenu.destroy();
7778 if (oConfig.getProperty(_DISABLED)) {
7780 oConfig.refireEvent(_DISABLED);
7785 if (oConfig.getProperty(_SELECTED)) {
7787 oConfig.refireEvent(_SELECTED);
7795 * @method configOnClick
7796 * @description Event handler for when the "onclick" configuration property
7797 * of the menu item changes.
7798 * @param {String} p_sType String representing the name of the event that
7800 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7801 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7802 * that fired the event.
7804 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7806 var oObject = p_aArgs[0];
7809 Remove any existing listeners if a "click" event handler has
7810 already been specified.
7813 if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7815 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7816 this._oOnclickAttributeValue.obj);
7818 this._oOnclickAttributeValue = null;
7823 if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
7824 Lang.isFunction(oObject.fn)) {
7826 this.clickEvent.subscribe(oObject.fn,
7827 ((_OBJ in oObject) ? oObject.obj : this),
7828 ((_SCOPE in oObject) ? oObject.scope : null) );
7830 this._oOnclickAttributeValue = oObject;
7838 * @method configClassName
7839 * @description Event handler for when the "classname" configuration
7840 * property of a menu item changes.
7841 * @param {String} p_sType String representing the name of the event that
7843 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7844 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7845 * that fired the event.
7847 configClassName: function (p_sType, p_aArgs, p_oItem) {
7849 var sClassName = p_aArgs[0];
7851 if (this._sClassName) {
7853 Dom.removeClass(this.element, this._sClassName);
7857 Dom.addClass(this.element, sClassName);
7858 this._sClassName = sClassName;
7864 * @method _dispatchClickEvent
7865 * @description Dispatches a DOM "click" event to the anchor element of a
7866 * MenuItem instance.
7869 _dispatchClickEvent: function () {
7871 var oMenuItem = this,
7874 if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7875 oAnchor = Dom.getFirstChild(oMenuItem.element);
7877 // Dispatch a "click" event to the MenuItem's anchor so that its
7878 // "click" event handlers will get called in response to the user
7879 // pressing the keyboard shortcut defined by the "keylistener"
7880 // configuration property.
7882 this._dispatchDOMClick(oAnchor);
7887 * Utility method to dispatch a DOM click event on the HTMLElement passed in
7889 * @method _dispatchDOMClick
7891 * @param {HTMLElement} el
7893 _dispatchDOMClick : function(el) {
7896 // Choose the standards path for IE9
7897 if (UA.ie && UA.ie < 9) {
7898 el.fireEvent(_ONCLICK);
7900 if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7901 oEvent = document.createEvent("HTMLEvents");
7902 oEvent.initEvent(_CLICK, true, true);
7904 oEvent = document.createEvent("MouseEvents");
7905 oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
7907 el.dispatchEvent(oEvent);
7912 * @method _createKeyListener
7913 * @description "show" event handler for a Menu instance - responsible for
7914 * setting up the KeyListener instance for a MenuItem.
7916 * @param {String} type String representing the name of the event that
7918 * @param {Array} args Array of arguments sent when the event was fired.
7919 * @param {Array} keyData Array of arguments sent when the event was fired.
7921 _createKeyListener: function (type, args, keyData) {
7923 var oMenuItem = this,
7924 oMenu = oMenuItem.parent;
7926 var oKeyListener = new YAHOO.util.KeyListener(
7927 oMenu.element.ownerDocument,
7930 fn: oMenuItem._dispatchClickEvent,
7932 correctScope: true });
7935 if (oMenu.cfg.getProperty(_VISIBLE)) {
7936 oKeyListener.enable();
7940 oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
7941 oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
7943 oMenuItem._keyListener = oKeyListener;
7945 oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
7951 * @method configKeyListener
7952 * @description Event handler for when the "keylistener" configuration
7953 * property of a menu item changes.
7954 * @param {String} p_sType String representing the name of the event that
7956 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7958 configKeyListener: function (p_sType, p_aArgs) {
7960 var oKeyData = p_aArgs[0],
7962 oMenu = oMenuItem.parent;
7964 if (oMenuItem._keyData) {
7966 // Unsubscribe from the "show" event in case the keylistener
7967 // config was changed before the Menu was ever made visible.
7969 oMenu.unsubscribe(_SHOW,
7970 oMenuItem._createKeyListener, oMenuItem._keyData);
7972 oMenuItem._keyData = null;
7977 // Tear down for the previous value of the "keylistener" property
7979 if (oMenuItem._keyListener) {
7981 oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
7982 oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
7984 oMenuItem._keyListener.disable();
7985 oMenuItem._keyListener = null;
7992 oMenuItem._keyData = oKeyData;
7994 // Defer the creation of the KeyListener instance until the
7995 // parent Menu is visible. This is necessary since the
7996 // KeyListener instance needs to be bound to the document the
7997 // Menu has been rendered into. Deferring creation of the
7998 // KeyListener instance also improves performance.
8000 oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
8001 oKeyData, oMenuItem);
8011 * @method initDefaultConfig
8012 * @description Initializes an item's configurable properties.
8014 initDefaultConfig : function () {
8016 var oConfig = this.cfg;
8019 // Define the configuration attributes
8023 * @description String or markup specifying the text label for the menu item.
8024 * When building a menu from existing HTML the value of this property
8025 * will be interpreted from the menu's markup. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8029 oConfig.addProperty(
8032 handler: this.configText,
8033 value: TEXT_CONFIG.value,
8034 validator: TEXT_CONFIG.validator,
8035 suppressEvent: TEXT_CONFIG.suppressEvent
8042 * @description String or markup specifying additional instructional text to
8043 * accompany the text for the menu item. The helptext is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8044 * @deprecated Use "text" configuration property to add help text markup.
8045 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em
8046 * class=\"helptext\">Ctrl + C</em>");</code>
8048 * @type HTML|<a href="http://www.w3.org/TR/
8049 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8052 oConfig.addProperty(
8053 HELP_TEXT_CONFIG.key,
8055 handler: this.configHelpText,
8056 supercedes: HELP_TEXT_CONFIG.supercedes,
8057 suppressEvent: HELP_TEXT_CONFIG.suppressEvent
8064 * @description String specifying the URL for the menu item's anchor's
8065 * "href" attribute. When building a menu from existing HTML the value
8066 * of this property will be interpreted from the menu's markup. Markup for the menu item content. The url is inserted into the DOM as an attribute value, and should be escaped by the implementor if coming from an external source.
8070 oConfig.addProperty(
8073 handler: this.configURL,
8074 value: URL_CONFIG.value,
8075 suppressEvent: URL_CONFIG.suppressEvent
8082 * @description String specifying the value for the "target" attribute
8083 * of the menu item's anchor element. <strong>Specifying a target will
8084 * require the user to click directly on the menu item's anchor node in
8085 * order to cause the browser to navigate to the specified URL.</strong>
8086 * When building a menu from existing HTML the value of this property
8087 * will be interpreted from the menu's markup. The target is inserted into the DOM as an attribute value, and should be escaped by the implementor if coming from an external source.
8091 oConfig.addProperty(
8094 handler: this.configTarget,
8095 suppressEvent: TARGET_CONFIG.suppressEvent
8102 * @description Boolean indicating if the text of the menu item will be
8103 * rendered with emphasis.
8104 * @deprecated Use the "text" configuration property to add emphasis.
8105 * For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some
8106 * Text</em>");</code>
8110 oConfig.addProperty(
8111 EMPHASIS_CONFIG.key,
8113 handler: this.configEmphasis,
8114 value: EMPHASIS_CONFIG.value,
8115 validator: EMPHASIS_CONFIG.validator,
8116 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8117 supercedes: EMPHASIS_CONFIG.supercedes
8123 * @config strongemphasis
8124 * @description Boolean indicating if the text of the menu item will be
8125 * rendered with strong emphasis.
8126 * @deprecated Use the "text" configuration property to add strong emphasis.
8127 * For example: <code>oMenuItem.cfg.setProperty("text", "<strong>
8128 * Some Text</strong>");</code>
8132 oConfig.addProperty(
8133 STRONG_EMPHASIS_CONFIG.key,
8135 handler: this.configStrongEmphasis,
8136 value: STRONG_EMPHASIS_CONFIG.value,
8137 validator: STRONG_EMPHASIS_CONFIG.validator,
8138 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8139 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8146 * @description Boolean indicating if the menu item should be rendered
8151 oConfig.addProperty(
8154 handler: this.configChecked,
8155 value: CHECKED_CONFIG.value,
8156 validator: CHECKED_CONFIG.validator,
8157 suppressEvent: CHECKED_CONFIG.suppressEvent,
8158 supercedes: CHECKED_CONFIG.supercedes
8165 * @description Boolean indicating if the menu item should be disabled.
8166 * (Disabled menu items are dimmed and will not respond to user input
8171 oConfig.addProperty(
8172 DISABLED_CONFIG.key,
8174 handler: this.configDisabled,
8175 value: DISABLED_CONFIG.value,
8176 validator: DISABLED_CONFIG.validator,
8177 suppressEvent: DISABLED_CONFIG.suppressEvent
8184 * @description Boolean indicating if the menu item should
8189 oConfig.addProperty(
8190 SELECTED_CONFIG.key,
8192 handler: this.configSelected,
8193 value: SELECTED_CONFIG.value,
8194 validator: SELECTED_CONFIG.validator,
8195 suppressEvent: SELECTED_CONFIG.suppressEvent
8202 * @description Object specifying the submenu to be appended to the
8203 * menu item. The value can be one of the following: <ul><li>Object
8204 * specifying a Menu instance.</li><li>Object literal specifying the
8205 * menu to be created. Format: <code>{ id: [menu id], itemdata:
8206 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
8207 * items</a>] }</code>.</li><li>String specifying the id attribute
8208 * of the <code><div></code> element of the menu.</li><li>
8209 * Object specifying the <code><div></code> element of the
8212 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8213 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8216 oConfig.addProperty(
8219 handler: this.configSubmenu,
8220 supercedes: SUBMENU_CONFIG.supercedes,
8221 suppressEvent: SUBMENU_CONFIG.suppressEvent
8228 * @description Object literal representing the code to be executed when
8229 * the item is clicked. Format:<br> <code> {<br>
8230 * <strong>fn:</strong> Function, // The handler to call when
8231 * the event fires.<br> <strong>obj:</strong> Object, // An
8232 * object to pass back to the handler.<br> <strong>scope:</strong>
8233 * Object // The object to use for the scope of the handler.
8238 oConfig.addProperty(
8241 handler: this.configOnClick,
8242 suppressEvent: ONCLICK_CONFIG.suppressEvent
8249 * @description CSS class to be applied to the menu item's root
8250 * <code><li></code> element. The specified class(es) are
8251 * appended in addition to the default class as specified by the menu
8252 * item's CSS_CLASS_NAME constant.
8256 oConfig.addProperty(
8257 CLASS_NAME_CONFIG.key,
8259 handler: this.configClassName,
8260 value: CLASS_NAME_CONFIG.value,
8261 validator: CLASS_NAME_CONFIG.validator,
8262 suppressEvent: CLASS_NAME_CONFIG.suppressEvent
8268 * @config keylistener
8269 * @description Object literal representing the key(s) that can be used
8270 * to trigger the MenuItem's "click" event. Possible attributes are
8271 * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
8272 * or an array of ints representing keycodes).
8276 oConfig.addProperty(
8277 KEY_LISTENER_CONFIG.key,
8279 handler: this.configKeyListener,
8280 value: KEY_LISTENER_CONFIG.value,
8281 suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
8288 * @method getNextSibling
8289 * @description Finds the menu item's next sibling.
8290 * @return YAHOO.widget.MenuItem
8292 getNextSibling: function () {
8294 var isUL = function (el) {
8295 return (el.nodeName.toLowerCase() === "ul");
8298 menuitemEl = this.element,
8299 next = Dom.getNextSibling(menuitemEl),
8306 parent = menuitemEl.parentNode;
8307 sibling = Dom.getNextSiblingBy(parent, isUL);
8313 list = Dom.getFirstChildBy(parent.parentNode, isUL);
8316 next = Dom.getFirstChild(list);
8320 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8325 * @method getNextEnabledSibling
8326 * @description Finds the menu item's next enabled sibling.
8327 * @return YAHOO.widget.MenuItem
8329 getNextEnabledSibling: function () {
8331 var next = this.getNextSibling();
8333 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
8339 * @method getPreviousSibling
8340 * @description Finds the menu item's previous sibling.
8341 * @return {YAHOO.widget.MenuItem}
8343 getPreviousSibling: function () {
8345 var isUL = function (el) {
8346 return (el.nodeName.toLowerCase() === "ul");
8349 menuitemEl = this.element,
8350 next = Dom.getPreviousSibling(menuitemEl),
8357 parent = menuitemEl.parentNode;
8358 sibling = Dom.getPreviousSiblingBy(parent, isUL);
8364 list = Dom.getLastChildBy(parent.parentNode, isUL);
8367 next = Dom.getLastChild(list);
8371 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8377 * @method getPreviousEnabledSibling
8378 * @description Finds the menu item's previous enabled sibling.
8379 * @return {YAHOO.widget.MenuItem}
8381 getPreviousEnabledSibling: function () {
8383 var next = this.getPreviousSibling();
8385 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
8392 * @description Causes the menu item to receive the focus and fires the
8395 focus: function () {
8397 var oParent = this.parent,
8398 oAnchor = this._oAnchor,
8399 oActiveItem = oParent.activeItem;
8402 function setFocus() {
8406 if (!(UA.ie && !document.hasFocus())) {
8410 oActiveItem.blurEvent.fire();
8416 this.focusEvent.fire();
8428 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
8429 this.element.style.display != _NONE) {
8433 Setting focus via a timer fixes a race condition in Firefox, IE
8434 and Opera where the browser viewport jumps as it trys to
8435 position and focus the menu.
8438 Lang.later(0, this, setFocus);
8447 * @description Causes the menu item to lose focus and fires the
8452 var oParent = this.parent;
8454 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8456 Lang.later(0, this, function () {
8460 this._oAnchor.blur();
8461 this.blurEvent.fire();
8477 * @description Returns a boolean indicating whether or not the menu item
8481 hasFocus: function () {
8483 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8490 * @description Removes the menu item's <code><li></code> element
8491 * from its parent <code><ul></code> element.
8493 destroy: function () {
8495 var oEl = this.element,
8505 // If the item has a submenu, destroy it first
8507 oSubmenu = this.cfg.getProperty(_SUBMENU);
8516 // Remove the element from the parent node
8518 oParentNode = oEl.parentNode;
8522 oParentNode.removeChild(oEl);
8524 this.destroyEvent.fire();
8529 // Remove CustomEvent listeners
8531 i = EVENT_TYPES.length - 1;
8535 aEventData = EVENT_TYPES[i];
8537 this[aEventData[0]].unsubscribeAll();
8543 this.cfg.configChangedEvent.unsubscribeAll();
8552 * @description Returns a string representing the menu item.
8555 toString: function () {
8557 var sReturnVal = _MENUITEM,
8562 sReturnVal += (_SPACE + sId);
8572 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8578 _MOUSEDOWN = "mousedown",
8579 _CONTEXTMENU = "ContextMenu",
8583 * Creates a list of options or commands which are made visible in response to
8584 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8586 * @param {String} p_oElement String specifying the id attribute of the
8587 * <code><div></code> element of the context menu.
8588 * @param {String} p_oElement String specifying the id attribute of the
8589 * <code><select></code> element to be used as the data source for the
8591 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8592 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8593 * <code><div></code> element of the context menu.
8594 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8595 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8596 * the <code><select></code> element to be used as the data source for
8598 * @param {Object} p_oConfig Optional. Object literal specifying the
8599 * configuration for the context menu. See configuration class documentation
8601 * @class ContextMenu
8603 * @extends YAHOO.widget.Menu
8604 * @namespace YAHOO.widget
8606 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8607 YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8611 var Event = YAHOO.util.Event,
8613 ContextMenu = YAHOO.widget.ContextMenu,
8618 * Constant representing the name of the ContextMenu's events
8619 * @property EVENT_TYPES
8626 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8627 "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8634 * Constant representing the ContextMenu's configuration properties
8635 * @property DEFAULT_CONFIG
8648 * @description "beforeShow" event handler used to position the contextmenu.
8650 * @param {String} p_sType String representing the name of the event that
8652 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8653 * @param {Array} p_aPos Array representing the xy position for the context menu.
8655 function position(p_sType, p_aArgs, p_aPos) {
8656 this.cfg.setProperty(_XY, p_aPos);
8657 this.beforeShowEvent.unsubscribe(position, p_aPos);
8661 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8665 // Private properties
8669 * @property _oTrigger
8670 * @description Object reference to the current value of the "trigger"
8671 * configuration property.
8674 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8675 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8681 * @property _bCancelled
8682 * @description Boolean indicating if the display of the context menu should
8692 // Public properties
8696 * @property contextEventTarget
8697 * @description Object reference for the HTML element that was the target of the
8698 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8701 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8702 * html.html#ID-58190037">HTMLElement</a>
8704 contextEventTarget: null,
8712 * @event triggerContextMenuEvent
8713 * @param type {String} The name of the event, "triggerContextMenu"
8714 * @param args {Array} The array of event arguments. For this event, the underlying
8715 * DOM event is the only argument, available from args[0].
8716 * @description Custom Event wrapper for the "contextmenu" DOM event
8717 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8720 triggerContextMenuEvent: null,
8726 * @description The ContextMenu class's initialization method. This method is
8727 * automatically called by the constructor, and sets up all DOM references for
8728 * pre-existing markup, and creates required markup if it is not already present.
8729 * @param {String} p_oElement String specifying the id attribute of the
8730 * <code><div></code> element of the context menu.
8731 * @param {String} p_oElement String specifying the id attribute of the
8732 * <code><select></code> element to be used as the data source for
8734 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8735 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8736 * <code><div></code> element of the context menu.
8737 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8738 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8739 * the <code><select></code> element to be used as the data source for
8741 * @param {Object} p_oConfig Optional. Object literal specifying the
8742 * configuration for the context menu. See configuration class documentation
8745 init: function(p_oElement, p_oConfig) {
8748 // Call the init of the superclass (YAHOO.widget.Menu)
8750 ContextMenu.superclass.init.call(this, p_oElement);
8752 this.beforeInitEvent.fire(ContextMenu);
8755 this.cfg.applyConfig(p_oConfig, true);
8758 this.initEvent.fire(ContextMenu);
8763 * @method initEvents
8764 * @description Initializes the custom events for the context menu.
8766 initEvents: function() {
8767 ContextMenu.superclass.initEvents.call(this);
8769 // Create custom events
8770 this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8771 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8776 * @description Cancels the display of the context menu.
8778 cancel: function() {
8779 this._bCancelled = true;
8786 * @method _removeEventHandlers
8787 * @description Removes all of the DOM event handlers from the HTML element(s)
8788 * whose "context menu" event ("click" for Opera) trigger the display of
8792 _removeEventHandlers: function() {
8794 var oTrigger = this._oTrigger;
8796 // Remove the event handlers from the trigger(s)
8798 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
8801 Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8807 // Private event handlers
8810 * @method _onTriggerClick
8811 * @description "click" event handler for the HTML element(s) identified as the
8812 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8814 * @param {Event} p_oEvent Object representing the DOM event object passed back
8815 * by the event utility (YAHOO.util.Event).
8816 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8817 * menu that is handling the event.
8819 _onTriggerClick: function(p_oEvent, p_oMenu) {
8821 if (p_oEvent.ctrlKey) {
8822 Event.stopEvent(p_oEvent);
8829 * @method _onTriggerContextMenu
8830 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8831 * element(s) that trigger the display of the context menu.
8833 * @param {Event} p_oEvent Object representing the DOM event object passed back
8834 * by the event utility (YAHOO.util.Event).
8835 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8836 * menu that is handling the event.
8838 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8842 if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8844 this.contextEventTarget = Event.getTarget(p_oEvent);
8846 this.triggerContextMenuEvent.fire(p_oEvent);
8849 if (!this._bCancelled) {
8852 Prevent the browser's default context menu from appearing and
8853 stop the propagation of the "contextmenu" event so that
8854 other ContextMenu instances are not displayed.
8857 Event.stopEvent(p_oEvent);
8860 // Hide any other Menu instances that might be visible
8862 YAHOO.widget.MenuManager.hideVisible();
8866 // Position and display the context menu
8868 aXY = Event.getXY(p_oEvent);
8871 if (!YAHOO.util.Dom.inDocument(this.element)) {
8873 this.beforeShowEvent.subscribe(position, aXY);
8878 this.cfg.setProperty(_XY, aXY);
8887 this._bCancelled = false;
8900 * @description Returns a string representing the context menu.
8903 toString: function() {
8905 var sReturnVal = _CONTEXTMENU,
8910 sReturnVal += (_SPACE + sId);
8920 * @method initDefaultConfig
8921 * @description Initializes the class's configurable properties which can be
8922 * changed using the context menu's Config object ("cfg").
8924 initDefaultConfig: function() {
8926 ContextMenu.superclass.initDefaultConfig.call(this);
8930 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
8931 * for Opera) trigger the display of the context menu. Can be a string
8932 * representing the id attribute of the HTML element, an object reference
8933 * for the HTML element, or an array of strings or HTML element references.
8935 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8936 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8938 this.cfg.addProperty(TRIGGER_CONFIG.key,
8940 handler: this.configTrigger,
8941 suppressEvent: TRIGGER_CONFIG.suppressEvent
8950 * @description Removes the context menu's <code><div></code> element
8951 * (and accompanying child nodes) from the document.
8952 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
8953 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
8955 destroy: function(shallowPurge) {
8957 // Remove the DOM event handlers from the current trigger(s)
8959 this._removeEventHandlers();
8962 // Continue with the superclass implementation of this method
8964 ContextMenu.superclass.destroy.call(this, shallowPurge);
8970 // Public event handlers for configuration properties
8974 * @method configTrigger
8975 * @description Event handler for when the value of the "trigger" configuration
8977 * @param {String} p_sType String representing the name of the event that
8979 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8980 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8981 * menu that fired the event.
8983 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8985 var oTrigger = p_aArgs[0];
8990 If there is a current "trigger" - remove the event handlers
8991 from that element(s) before assigning new ones
8994 if (this._oTrigger) {
8996 this._removeEventHandlers();
9000 this._oTrigger = oTrigger;
9004 Listen for the "mousedown" event in Opera b/c it does not
9005 support the "contextmenu" event
9008 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9012 Assign a "click" event handler to the trigger element(s) for
9013 Opera to prevent default browser behaviors.
9018 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9025 this._removeEventHandlers();
9031 }); // END YAHOO.lang.extend
9038 * Creates an item for a context menu.
9040 * @param {String} p_oObject String specifying the text of the context menu item.
9041 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9042 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9043 * <code><li></code> element of the context menu item.
9044 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9045 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9046 * specifying the <code><optgroup></code> element of the context
9048 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9049 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9050 * the <code><option></code> element of the context menu item.
9051 * @param {Object} p_oConfig Optional. Object literal specifying the
9052 * configuration for the context menu item. See configuration class
9053 * documentation for more details.
9054 * @class ContextMenuItem
9056 * @extends YAHOO.widget.MenuItem
9057 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9058 * are of type YAHOO.widget.MenuItem.
9060 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9063 var Lang = YAHOO.lang,
9068 _DYNAMIC_STATIC = "dynamic," + _STATIC,
9069 _DISABLED = "disabled",
9070 _SELECTED = "selected",
9071 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9072 _SUBMENU = "submenu",
9073 _VISIBLE = "visible",
9075 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9076 _MENUBAR = "MenuBar";
9079 * Horizontal collection of items, each of which can contain a submenu.
9081 * @param {String} p_oElement String specifying the id attribute of the
9082 * <code><div></code> element of the menu bar.
9083 * @param {String} p_oElement String specifying the id attribute of the
9084 * <code><select></code> element to be used as the data source for the
9086 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9087 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9088 * the <code><div></code> element of the menu bar.
9089 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9090 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9091 * specifying the <code><select></code> element to be used as the data
9092 * source for the menu bar.
9093 * @param {Object} p_oConfig Optional. Object literal specifying the
9094 * configuration for the menu bar. See configuration class documentation for
9098 * @extends YAHOO.widget.Menu
9099 * @namespace YAHOO.widget
9101 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9103 YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9109 * @method checkPosition
9110 * @description Checks to make sure that the value of the "position" property
9111 * is one of the supported strings. Returns true if the position is supported.
9113 * @param {Object} p_sPosition String specifying the position of the menu.
9116 function checkPosition(p_sPosition) {
9118 var returnVal = false;
9120 if (Lang.isString(p_sPosition)) {
9122 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9131 var Event = YAHOO.util.Event,
9132 MenuBar = YAHOO.widget.MenuBar,
9137 validator: checkPosition,
9138 supercedes: [_VISIBLE]
9141 SUBMENU_ALIGNMENT_CONFIG = {
9142 key: "submenualignment",
9146 AUTO_SUBMENU_DISPLAY_CONFIG = {
9147 key: _AUTO_SUBMENU_DISPLAY,
9149 validator: Lang.isBoolean,
9153 SUBMENU_TOGGLE_REGION_CONFIG = {
9154 key: _SUBMENU_TOGGLE_REGION,
9156 validator: Lang.isBoolean
9161 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9165 * @description The MenuBar class's initialization method. This method is
9166 * automatically called by the constructor, and sets up all DOM references for
9167 * pre-existing markup, and creates required markup if it is not already present.
9168 * @param {String} p_oElement String specifying the id attribute of the
9169 * <code><div></code> element of the menu bar.
9170 * @param {String} p_oElement String specifying the id attribute of the
9171 * <code><select></code> element to be used as the data source for the
9173 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9174 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9175 * the <code><div></code> element of the menu bar.
9176 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9177 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9178 * specifying the <code><select></code> element to be used as the data
9179 * source for the menu bar.
9180 * @param {Object} p_oConfig Optional. Object literal specifying the
9181 * configuration for the menu bar. See configuration class documentation for
9184 init: function(p_oElement, p_oConfig) {
9186 if(!this.ITEM_TYPE) {
9188 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9193 // Call the init of the superclass (YAHOO.widget.Menu)
9195 MenuBar.superclass.init.call(this, p_oElement);
9198 this.beforeInitEvent.fire(MenuBar);
9203 this.cfg.applyConfig(p_oConfig, true);
9207 this.initEvent.fire(MenuBar);
9217 * @property CSS_CLASS_NAME
9218 * @description String representing the CSS class(es) to be applied to the menu
9219 * bar's <code><div></code> element.
9220 * @default "yuimenubar"
9224 CSS_CLASS_NAME: "yuimenubar",
9228 * @property SUBMENU_TOGGLE_REGION_WIDTH
9229 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9230 * display of the MenuBarItem's submenu.
9235 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9238 // Protected event handlers
9242 * @method _onKeyDown
9243 * @description "keydown" Custom Event handler for the menu bar.
9245 * @param {String} p_sType String representing the name of the event that
9247 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9248 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9249 * that fired the event.
9251 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9253 var oEvent = p_aArgs[0],
9260 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9262 oItemCfg = oItem.cfg;
9264 switch(oEvent.keyCode) {
9266 case 37: // Left arrow
9267 case 39: // Right arrow
9269 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9271 oItemCfg.setProperty(_SELECTED, true);
9276 oNextItem = (oEvent.keyCode == 37) ?
9277 oItem.getPreviousEnabledSibling() :
9278 oItem.getNextEnabledSibling();
9282 this.clearActiveItem();
9284 oNextItem.cfg.setProperty(_SELECTED, true);
9286 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9291 oSubmenu.setInitialFocus();
9302 Event.preventDefault(oEvent);
9306 case 40: // Down arrow
9308 if(this.activeItem != oItem) {
9310 this.clearActiveItem();
9312 oItemCfg.setProperty(_SELECTED, true);
9317 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9321 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9323 oSubmenu.setInitialSelection();
9324 oSubmenu.setInitialFocus();
9330 oSubmenu.setInitialFocus();
9336 Event.preventDefault(oEvent);
9345 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9347 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9349 if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9352 this.activeItem.focus();
9357 this.activeItem.cfg.setProperty(_SELECTED, false);
9358 this.activeItem.blur();
9362 Event.preventDefault(oEvent);
9371 * @description "click" event handler for the menu bar.
9373 * @param {String} p_sType String representing the name of the event that
9375 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9376 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9377 * that fired the event.
9379 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9381 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9383 var oItem = p_aArgs[1],
9395 var toggleSubmenuDisplay = function () {
9397 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9411 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9413 oEvent = p_aArgs[0];
9414 oTarget = Event.getTarget(oEvent);
9415 oActiveItem = this.activeItem;
9419 // Hide any other submenus that might be visible
9421 if(oActiveItem && oActiveItem != oItem) {
9423 this.clearActiveItem();
9428 oItem.cfg.setProperty(_SELECTED, true);
9431 // Show the submenu for the item
9433 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9438 oItemEl = oItem.element;
9439 nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9440 nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9442 if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9444 if (Event.getPageX(oEvent) > nToggleRegion) {
9446 toggleSubmenuDisplay();
9448 Event.preventDefault(oEvent);
9451 Return false so that other click event handlers are not called when the
9452 user clicks inside the toggle region.
9461 toggleSubmenuDisplay();
9479 * @method configSubmenuToggle
9480 * @description Event handler for when the "submenutoggleregion" configuration property of
9481 * a MenuBar changes.
9482 * @param {String} p_sType The name of the event that was fired.
9483 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9485 configSubmenuToggle: function (p_sType, p_aArgs) {
9487 var bSubmenuToggle = p_aArgs[0];
9489 if (bSubmenuToggle) {
9491 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9500 * @description Returns a string representing the menu bar.
9503 toString: function() {
9505 var sReturnVal = _MENUBAR,
9510 sReturnVal += (_SPACE + sId);
9520 * @description Initializes the class's configurable properties which can be
9521 * changed using the menu bar's Config object ("cfg").
9522 * @method initDefaultConfig
9524 initDefaultConfig: function() {
9526 MenuBar.superclass.initDefaultConfig.call(this);
9528 var oConfig = this.cfg;
9530 // Add configuration properties
9534 Set the default value for the "position" configuration property
9535 to "static" by re-adding the property.
9541 * @description String indicating how a menu bar should be positioned on the
9542 * screen. Possible values are "static" and "dynamic." Static menu bars
9543 * are visible by default and reside in the normal flow of the document
9544 * (CSS position: static). Dynamic menu bars are hidden by default, reside
9545 * out of the normal flow of the document (CSS position: absolute), and can
9546 * overlay other elements on the screen.
9550 oConfig.addProperty(
9551 POSITION_CONFIG.key,
9553 handler: this.configPosition,
9554 value: POSITION_CONFIG.value,
9555 validator: POSITION_CONFIG.validator,
9556 supercedes: POSITION_CONFIG.supercedes
9562 Set the default value for the "submenualignment" configuration property
9563 to ["tl","bl"] by re-adding the property.
9567 * @config submenualignment
9568 * @description Array defining how submenus should be aligned to their
9569 * parent menu bar item. The format is: [itemCorner, submenuCorner].
9570 * @default ["tl","bl"]
9573 oConfig.addProperty(
9574 SUBMENU_ALIGNMENT_CONFIG.key,
9576 value: SUBMENU_ALIGNMENT_CONFIG.value,
9577 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9583 Change the default value for the "autosubmenudisplay" configuration
9584 property to "false" by re-adding the property.
9588 * @config autosubmenudisplay
9589 * @description Boolean indicating if submenus are automatically made
9590 * visible when the user mouses over the menu bar's items.
9594 oConfig.addProperty(
9595 AUTO_SUBMENU_DISPLAY_CONFIG.key,
9597 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
9598 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9599 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9605 * @config submenutoggleregion
9606 * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
9607 * display of a submenu. The default width of the region is determined by the value of the
9608 * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
9609 * configuration property will be set to false, and any click event listeners will not be
9610 * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
9611 * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
9612 * standard behavior.
9616 oConfig.addProperty(
9617 SUBMENU_TOGGLE_REGION_CONFIG.key,
9619 value: SUBMENU_TOGGLE_REGION_CONFIG.value,
9620 validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9621 handler: this.configSubmenuToggle
9627 }); // END YAHOO.lang.extend
9634 * Creates an item for a menu bar.
9636 * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
9637 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9638 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9639 * <code><li></code> element of the menu bar item.
9640 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9641 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9642 * specifying the <code><optgroup></code> element of the menu bar item.
9643 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9644 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9645 * the <code><option></code> element of the menu bar item.
9646 * @param {Object} p_oConfig Optional. Object literal specifying the
9647 * configuration for the menu bar item. See configuration class documentation
9649 * @class MenuBarItem
9651 * @extends YAHOO.widget.MenuItem
9653 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9655 YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9659 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9665 * @description The MenuBarItem class's initialization method. This method is
9666 * automatically called by the constructor, and sets up all DOM references for
9667 * pre-existing markup, and creates required markup if it is not already present.
9668 * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
9669 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9670 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9671 * <code><li></code> element of the menu bar item.
9672 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9673 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9674 * specifying the <code><optgroup></code> element of the menu bar item.
9675 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9676 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9677 * the <code><option></code> element of the menu bar item.
9678 * @param {Object} p_oConfig Optional. Object literal specifying the
9679 * configuration for the menu bar item. See configuration class documentation
9682 init: function(p_oObject, p_oConfig) {
9684 if(!this.SUBMENU_TYPE) {
9686 this.SUBMENU_TYPE = YAHOO.widget.Menu;
9692 Call the init of the superclass (YAHOO.widget.MenuItem)
9693 Note: We don't pass the user config in here yet
9694 because we only want it executed once, at the lowest
9698 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
9701 var oConfig = this.cfg;
9705 oConfig.applyConfig(p_oConfig, true);
9709 oConfig.fireQueue();
9719 * @property CSS_CLASS_NAME
9720 * @description String representing the CSS class(es) to be applied to the
9721 * <code><li></code> element of the menu bar item.
9722 * @default "yuimenubaritem"
9726 CSS_CLASS_NAME: "yuimenubaritem",
9730 * @property CSS_LABEL_CLASS_NAME
9731 * @description String representing the CSS class(es) to be applied to the
9732 * menu bar item's <code><a></code> element.
9733 * @default "yuimenubaritemlabel"
9737 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9746 * @description Returns a string representing the menu bar item.
9749 toString: function() {
9751 var sReturnVal = "MenuBarItem";
9753 if(this.cfg && this.cfg.getProperty("text")) {
9755 sReturnVal += (": " + this.cfg.getProperty("text"));
9763 }); // END YAHOO.lang.extend
9764 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.9.0", build: "2800"});