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 () {
3821 // The Menu is below the context element
3822 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3823 return (nBottomRegionHeight - nViewportOffset);
3825 else { // The Menu is above the context element
3826 return (nTopRegionHeight - nViewportOffset);
3833 Sets the Menu's "y" configuration property to the correct value based on its
3834 current orientation.
3837 var alignY = function () {
3841 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3842 nNewY = (nContextElY + nContextElHeight);
3845 nNewY = (nContextElY - oMenuEl.offsetHeight);
3848 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3853 // Resets the maxheight of the Menu to the value set by the user
3855 var resetMaxHeight = function () {
3857 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3859 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3865 Trys to place the Menu in the best possible position (either above or
3866 below its corresponding context element).
3869 var setVerticalPosition = function () {
3871 var nDisplayRegionHeight = getDisplayRegionHeight(),
3872 bMenuHasItems = (oMenu.getItems().length > 0),
3873 nMenuMinScrollHeight,
3877 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3879 nMenuMinScrollHeight =
3880 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3883 if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3884 nMaxHeight = nDisplayRegionHeight;
3887 nMaxHeight = nInitialMaxHeight;
3891 oMenu._setScrollHeight(nMaxHeight);
3892 oMenu.hideEvent.subscribe(resetMaxHeight);
3895 // Re-align the Menu since its height has just changed
3896 // as a result of the setting of the maxheight property.
3901 if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3906 All possible positions and values for the "maxheight"
3907 configuration property have been tried, but none were
3908 successful, so fall back to the original size and position.
3920 fnReturnVal = setVerticalPosition();
3927 else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
3929 oMenu._setScrollHeight(nInitialMaxHeight);
3930 oMenu.hideEvent.subscribe(resetMaxHeight);
3932 // Re-align the Menu since its height has just changed
3933 // as a result of the setting of the maxheight property.
3944 // Determine if the current value for the Menu's "y" configuration property will
3945 // result in the Menu being positioned outside the boundaries of the viewport
3947 if (y < topConstraint || y > bottomConstraint) {
3949 // The current value for the Menu's "y" configuration property WILL
3950 // result in the Menu being positioned outside the boundaries of the viewport
3952 if (bCanConstrain) {
3954 if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
3957 // If the "preventcontextoverlap" configuration property is set to "true",
3958 // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
3959 // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
3961 oContextEl = aContext[0];
3962 nContextElHeight = oContextEl.offsetHeight;
3963 nContextElY = (Dom.getY(oContextEl) - scrollY);
3965 nTopRegionHeight = nContextElY;
3966 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3968 setVerticalPosition();
3970 yNew = oMenu.cfg.getProperty(_Y);
3973 else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
3974 nMenuOffsetHeight >= viewPortHeight) {
3977 // If the Menu exceeds the height of the viewport, introduce scroll bars
3978 // to keep the Menu inside the boundaries of the viewport
3980 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
3982 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
3984 oMenu._setScrollHeight(nAvailableHeight);
3985 oMenu.hideEvent.subscribe(resetMaxHeight);
3989 yNew = oMenu.cfg.getProperty(_Y);
3998 if (y < topConstraint) {
3999 yNew = topConstraint;
4000 } else if (y > bottomConstraint) {
4001 yNew = bottomConstraint;
4008 // The "y" configuration property cannot be set to a value that will keep
4009 // entire Menu inside the boundary of the viewport. Therefore, set
4010 // the "y" configuration property to scrollY to keep as much of the
4011 // Menu inside the viewport as possible.
4012 yNew = nViewportOffset + scrollY;
4024 * @description "hide" event handler for the menu.
4026 * @param {String} p_sType String representing the name of the event that
4028 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4030 _onHide: function (p_sType, p_aArgs) {
4032 if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4034 this.positionOffScreen();
4043 * @description "show" event handler for the menu.
4045 * @param {String} p_sType String representing the name of the event that
4047 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4049 _onShow: function (p_sType, p_aArgs) {
4051 var oParent = this.parent,
4058 function disableAutoSubmenuDisplay(p_oEvent) {
4062 if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4065 Set the "autosubmenudisplay" to "false" if the user
4066 clicks outside the menu bar.
4069 oTarget = Event.getTarget(p_oEvent);
4071 if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4073 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4075 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4076 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4085 function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4087 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4088 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4095 oParentMenu = oParent.parent;
4098 if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
4099 (oParentMenu instanceof YAHOO.widget.MenuBar ||
4100 oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4102 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4104 Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4105 Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4110 // The following fixes an issue with the selected state of a MenuItem
4111 // not rendering correctly when a submenu is aligned to the left of
4112 // its parent Menu instance.
4114 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
4115 (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4117 oElement = this.element;
4118 nOffsetWidth = oElement.offsetWidth;
4121 Measuring the difference of the offsetWidth before and after
4122 setting the "width" style attribute allows us to compute the
4123 about of padding and borders applied to the element, which in
4124 turn allows us to set the "width" property correctly.
4127 oElement.style.width = nOffsetWidth + _PX;
4129 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4131 this.cfg.setProperty(_WIDTH, sWidth);
4133 this.hideEvent.subscribe(onSubmenuHide, sWidth);
4141 Dynamically positioned, root Menus focus themselves when visible, and
4142 will then, when hidden, restore focus to the UI control that had focus
4143 before the Menu was made visible.
4146 if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4148 this._focusedElement = oFocusedElement;
4159 * @method _onBeforeHide
4160 * @description "beforehide" event handler for the menu.
4162 * @param {String} p_sType String representing the name of the event that
4164 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4166 _onBeforeHide: function (p_sType, p_aArgs) {
4168 var oActiveItem = this.activeItem,
4169 oRoot = this.getRoot(),
4176 oConfig = oActiveItem.cfg;
4178 oConfig.setProperty(_SELECTED, false);
4180 oSubmenu = oConfig.getProperty(_SUBMENU);
4192 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
4193 For this reason, it is necessary to maintain the focused state in a private property
4194 so that the _onMouseOver event handler is able to determined whether or not to set focus
4195 to MenuItems as the user is moving the mouse.
4198 if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4200 oRoot._hasFocus = this.hasFocus();
4205 if (oRoot == this) {
4215 * @method _onParentMenuConfigChange
4216 * @description "configchange" event handler for a submenu.
4218 * @param {String} p_sType String representing the name of the event that
4220 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4221 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4222 * subscribed to the event.
4224 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4226 var sPropertyName = p_aArgs[0][0],
4227 oPropertyValue = p_aArgs[0][1];
4229 switch(sPropertyName) {
4232 case _CONSTRAIN_TO_VIEWPORT:
4235 case _SUBMENU_HIDE_DELAY:
4236 case _CLICK_TO_HIDE:
4239 case _SCROLL_INCREMENT:
4241 case _MIN_SCROLL_HEIGHT:
4242 case _MONITOR_RESIZE:
4244 case _PREVENT_CONTEXT_OVERLAP:
4247 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4251 case _SUBMENU_ALIGNMENT:
4253 if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4255 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4267 * @method _onParentMenuRender
4268 * @description "render" event handler for a submenu. Renders a
4269 * submenu in response to the firing of its parent's "render" event.
4271 * @param {String} p_sType String representing the name of the event that
4273 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4274 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
4275 * subscribed to the event.
4277 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4279 var oParentMenu = p_oSubmenu.parent.parent,
4280 oParentCfg = oParentMenu.cfg,
4284 constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4288 clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4290 effect: oParentCfg.getProperty(_EFFECT),
4292 showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4294 hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4296 submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4298 classname: oParentCfg.getProperty(_CLASSNAME),
4300 scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4302 maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4304 minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4306 iframe: oParentCfg.getProperty(_IFRAME),
4308 shadow: oParentCfg.getProperty(_SHADOW),
4310 preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4312 monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
4314 keepopen: oParentCfg.getProperty(_KEEP_OPEN)
4322 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4324 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4329 p_oSubmenu.cfg.applyConfig(oConfig);
4332 if (!this.lazyLoad) {
4334 oLI = this.parent.element;
4336 if (this.element.parentNode == oLI) {
4353 * @method _onMenuItemDestroy
4354 * @description "destroy" event handler for the menu's items.
4356 * @param {String} p_sType String representing the name of the event
4358 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4359 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4360 * that fired the event.
4362 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4364 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4370 * @method _onMenuItemConfigChange
4371 * @description "configchange" event handler for the menu's items.
4373 * @param {String} p_sType String representing the name of the event that
4375 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4376 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4377 * that fired the event.
4379 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4381 var sPropertyName = p_aArgs[0][0],
4382 oPropertyValue = p_aArgs[0][1],
4386 switch(sPropertyName) {
4390 if (oPropertyValue === true) {
4392 this.activeItem = p_oItem;
4400 oSubmenu = p_aArgs[0][1];
4404 this._configureSubmenu(p_oItem);
4416 // Public event handlers for configuration properties
4420 * @method configVisible
4421 * @description Event handler for when the "visible" configuration property
4423 * @param {String} p_sType String representing the name of the event that
4425 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4426 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4429 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4434 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4436 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4441 bVisible = p_aArgs[0];
4442 sDisplay = Dom.getStyle(this.element, _DISPLAY);
4444 Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4448 if (sDisplay != _BLOCK) {
4449 this.beforeShowEvent.fire();
4450 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4451 this.showEvent.fire();
4457 if (sDisplay == _BLOCK) {
4458 this.beforeHideEvent.fire();
4459 Dom.setStyle(this.element, _DISPLAY, _NONE);
4460 this.hideEvent.fire();
4471 * @method configPosition
4472 * @description Event handler for when the "position" configuration property
4473 * of the menu changes.
4474 * @param {String} p_sType String representing the name of the event that
4476 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4477 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4480 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4482 var oElement = this.element,
4483 sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4488 Dom.setStyle(oElement, _POSITION, sCSSPosition);
4491 if (sCSSPosition == _STATIC) {
4493 // Statically positioned menus are visible by default
4495 Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4497 oCfg.setProperty(_VISIBLE, true);
4503 Even though the "visible" property is queued to
4504 "false" by default, we need to set the "visibility" property to
4505 "hidden" since Overlay's "configVisible" implementation checks the
4506 element's "visibility" style property before deciding whether
4507 or not to show an Overlay instance.
4510 Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4515 if (sCSSPosition == _ABSOLUTE) {
4516 nZIndex = oCfg.getProperty(_ZINDEX);
4518 if (!nZIndex || nZIndex === 0) {
4519 oCfg.setProperty(_ZINDEX, 1);
4528 * @method configIframe
4529 * @description Event handler for when the "iframe" configuration property of
4531 * @param {String} p_sType String representing the name of the event that
4533 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4534 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4537 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4539 if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4541 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4549 * @method configHideDelay
4550 * @description Event handler for when the "hidedelay" configuration property
4551 * of the menu changes.
4552 * @param {String} p_sType String representing the name of the event that
4554 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4555 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4558 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4560 var nHideDelay = p_aArgs[0];
4562 this._useHideDelay = (nHideDelay > 0);
4568 * @method configContainer
4569 * @description Event handler for when the "container" configuration property
4570 * of the menu changes.
4571 * @param {String} p_sType String representing the name of the event that
4573 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4574 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4577 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4579 var oElement = p_aArgs[0];
4581 if (Lang.isString(oElement)) {
4583 this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4591 * @method _clearSetWidthFlag
4592 * @description Change event listener for the "width" configuration property. This listener is
4593 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
4594 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
4595 * is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
4596 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
4597 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4600 _clearSetWidthFlag: function () {
4602 this._widthSetForScroll = false;
4604 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4609 * @method _subscribeScrollHandlers
4610 * @param {HTMLElement} oHeader The scroll header element
4611 * @param {HTMLElement} oFooter The scroll footer element
4613 _subscribeScrollHandlers : function(oHeader, oFooter) {
4614 var fnMouseOver = this._onScrollTargetMouseOver;
4615 var fnMouseOut = this._onScrollTargetMouseOut;
4617 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4618 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4619 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4620 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4624 * @method _unsubscribeScrollHandlers
4625 * @param {HTMLElement} oHeader The scroll header element
4626 * @param {HTMLElement} oFooter The scroll footer element
4628 _unsubscribeScrollHandlers : function(oHeader, oFooter) {
4629 var fnMouseOver = this._onScrollTargetMouseOver;
4630 var fnMouseOut = this._onScrollTargetMouseOut;
4632 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4633 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4634 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4635 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4639 * @method _setScrollHeight
4641 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4644 _setScrollHeight: function (p_nScrollHeight) {
4646 var nScrollHeight = p_nScrollHeight,
4647 bRefireIFrameAndShadow = false,
4658 if (this.getItems().length > 0) {
4660 oElement = this.element;
4662 oHeader = this.header;
4663 oFooter = this.footer;
4664 nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4666 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4667 nScrollHeight = nMinScrollHeight;
4670 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4671 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4672 oBody.scrollTop = 0;
4674 // Need to set a width for the Menu to fix the following problems in
4675 // Firefox 2 and IE:
4677 // #1) Scrolled Menus will render at 1px wide in Firefox 2
4679 // #2) There is a bug in gecko-based browsers where an element whose
4680 // "position" property is set to "absolute" and "overflow" property is
4681 // set to "hidden" will not render at the correct width when its
4682 // offsetParent's "position" property is also set to "absolute." It is
4683 // possible to work around this bug by specifying a value for the width
4684 // property in addition to overflow.
4686 // #3) In IE it is necessary to give the Menu a width before the
4687 // scrollbars are rendered to prevent the Menu from rendering with a
4688 // width that is 100% of the browser viewport.
4690 bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4692 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4694 nOffsetWidth = oElement.offsetWidth;
4697 Measuring the difference of the offsetWidth before and after
4698 setting the "width" style attribute allows us to compute the
4699 about of padding and borders applied to the element, which in
4700 turn allows us to set the "width" property correctly.
4703 oElement.style.width = nOffsetWidth + _PX;
4705 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4708 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4711 this.cfg.setProperty(_WIDTH, sWidth);
4715 Set a flag (_widthSetForScroll) to maintain some history regarding how the
4716 "width" configuration property was set. If the "width" configuration property
4717 is set by something other than the "_setScrollHeight" method, it will be
4718 necessary to maintain that new value and not clear the width if scrolling
4722 this._widthSetForScroll = true;
4724 this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4729 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4732 this.setHeader(_NON_BREAKING_SPACE);
4733 this.setFooter(_NON_BREAKING_SPACE);
4735 oHeader = this.header;
4736 oFooter = this.footer;
4738 Dom.addClass(oHeader, _TOP_SCROLLBAR);
4739 Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4741 oElement.insertBefore(oHeader, oBody);
4742 oElement.appendChild(oFooter);
4746 nHeight = nScrollHeight;
4748 if (oHeader && oFooter) {
4749 nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4753 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4756 Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4757 Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4759 if (!this._hasScrollEventHandlers) {
4760 this._subscribeScrollHandlers(oHeader, oFooter);
4761 this._hasScrollEventHandlers = true;
4764 this._disableScrollHeader();
4765 this._enableScrollFooter();
4767 bRefireIFrameAndShadow = true;
4770 else if (oHeader && oFooter) {
4775 Only clear the the "width" configuration property if it was set the
4776 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4779 if (this._widthSetForScroll) {
4782 this._widthSetForScroll = false;
4784 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4786 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4791 this._enableScrollHeader();
4792 this._enableScrollFooter();
4794 if (this._hasScrollEventHandlers) {
4795 this._unsubscribeScrollHandlers(oHeader, oFooter);
4796 this._hasScrollEventHandlers = false;
4799 oElement.removeChild(oHeader);
4800 oElement.removeChild(oFooter);
4805 bRefireIFrameAndShadow = true;
4810 if (bRefireIFrameAndShadow) {
4812 this.cfg.refireEvent(_IFRAME);
4813 this.cfg.refireEvent(_SHADOW);
4823 * @method _setMaxHeight
4824 * @description "renderEvent" handler used to defer the setting of the
4825 * "maxheight" configuration property until the menu is rendered in lazy
4827 * @param {String} p_sType The name of the event that was fired.
4828 * @param {Array} p_aArgs Collection of arguments sent when the event
4830 * @param {Number} p_nMaxHeight Number representing the value to set for the
4831 * "maxheight" configuration property.
4834 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4836 this._setScrollHeight(p_nMaxHeight);
4837 this.renderEvent.unsubscribe(this._setMaxHeight);
4843 * @method configMaxHeight
4844 * @description Event handler for when the "maxheight" configuration property of
4846 * @param {String} p_sType The name of the event that was fired.
4847 * @param {Array} p_aArgs Collection of arguments sent when the event
4849 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4852 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4854 var nMaxHeight = p_aArgs[0];
4856 if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4858 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4863 this._setScrollHeight(nMaxHeight);
4871 * @method configClassName
4872 * @description Event handler for when the "classname" configuration property of
4874 * @param {String} p_sType The name of the event that was fired.
4875 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4876 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4878 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4880 var sClassName = p_aArgs[0];
4882 if (this._sClassName) {
4884 Dom.removeClass(this.element, this._sClassName);
4888 Dom.addClass(this.element, sClassName);
4889 this._sClassName = sClassName;
4895 * @method _onItemAdded
4896 * @description "itemadded" event handler for a Menu instance.
4898 * @param {String} p_sType The name of the event that was fired.
4899 * @param {Array} p_aArgs Collection of arguments sent when the event
4902 _onItemAdded: function (p_sType, p_aArgs) {
4904 var oItem = p_aArgs[0];
4908 oItem.cfg.setProperty(_DISABLED, true);
4916 * @method configDisabled
4917 * @description Event handler for when the "disabled" configuration property of
4919 * @param {String} p_sType The name of the event that was fired.
4920 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4921 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4923 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4925 var bDisabled = p_aArgs[0],
4926 aItems = this.getItems(),
4930 if (Lang.isArray(aItems)) {
4932 nItems = aItems.length;
4940 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
4950 this.clearActiveItem(true);
4952 Dom.addClass(this.element, _DISABLED);
4954 this.itemAddedEvent.subscribe(this._onItemAdded);
4959 Dom.removeClass(this.element, _DISABLED);
4961 this.itemAddedEvent.unsubscribe(this._onItemAdded);
4970 * Resizes the shadow to match the container bounding element
4972 * @method _sizeShadow
4975 _sizeShadow : function () {
4977 var oElement = this.element,
4978 oShadow = this._shadow;
4980 if (oShadow && oElement) {
4981 // Clear the previous width
4982 if (oShadow.style.width && oShadow.style.height) {
4983 oShadow.style.width = _EMPTY_STRING;
4984 oShadow.style.height = _EMPTY_STRING;
4987 oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
4988 oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
4993 * Replaces the shadow element in the DOM with the current shadow element (this._shadow)
4995 * @method _replaceShadow
4998 _replaceShadow : function () {
4999 this.element.appendChild(this._shadow);
5003 * Adds the classname marker for a visible shadow, to the shadow element
5005 * @method _addShadowVisibleClass
5008 _addShadowVisibleClass : function () {
5009 Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5013 * Removes the classname marker for a visible shadow, from the shadow element
5015 * @method _removeShadowVisibleClass
5018 _removeShadowVisibleClass : function () {
5019 Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5023 * Removes the shadow element from the DOM, and unsubscribes all the listeners used to keep it in sync. Used
5024 * to handle setting the shadow to false.
5026 * @method _removeShadow
5029 _removeShadow : function() {
5031 var p = (this._shadow && this._shadow.parentNode);
5034 p.removeChild(this._shadow);
5037 this.beforeShowEvent.unsubscribe(this._addShadowVisibleClass);
5038 this.beforeHideEvent.unsubscribe(this._removeShadowVisibleClass);
5040 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._sizeShadow);
5041 this.cfg.unsubscribeFromConfigEvent(_HEIGHT, this._sizeShadow);
5042 this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5043 this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5045 this.changeContentEvent.unsubscribe(this._sizeShadow);
5047 Module.textResizeEvent.unsubscribe(this._sizeShadow);
5051 * Used to create the shadow element, add it to the DOM, and subscribe listeners to keep it in sync.
5053 * @method _createShadow
5056 _createShadow : function () {
5058 var oShadow = this._shadow,
5062 oElement = this.element;
5064 if (!m_oShadowTemplate) {
5065 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5066 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5069 oShadow = m_oShadowTemplate.cloneNode(false);
5071 oElement.appendChild(oShadow);
5073 this._shadow = oShadow;
5075 this.beforeShowEvent.subscribe(this._addShadowVisibleClass);
5076 this.beforeHideEvent.subscribe(this._removeShadowVisibleClass);
5080 Need to call sizeShadow & syncIframe via setTimeout for
5081 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
5082 or the shadow and iframe shim will not be sized and
5083 positioned properly.
5085 Lang.later(0, this, function () {
5090 this.cfg.subscribeToConfigEvent(_WIDTH, this._sizeShadow);
5091 this.cfg.subscribeToConfigEvent(_HEIGHT, this._sizeShadow);
5092 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5093 this.changeContentEvent.subscribe(this._sizeShadow);
5095 Module.textResizeEvent.subscribe(this._sizeShadow, this, true);
5097 this.destroyEvent.subscribe(function () {
5098 Module.textResizeEvent.unsubscribe(this._sizeShadow, this);
5102 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5107 * The beforeShow event handler used to set up the shadow lazily when the menu is made visible.
5108 * @method _shadowBeforeShow
5111 _shadowBeforeShow : function () {
5114 // If called because the "shadow" event was refired - just append again and resize
5115 this._replaceShadow();
5121 this._createShadow();
5124 this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5128 * @method configShadow
5129 * @description Event handler for when the "shadow" configuration property of
5131 * @param {String} p_sType The name of the event that was fired.
5132 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5133 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5135 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5137 var bShadow = p_aArgs[0];
5139 if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5140 if (this.cfg.getProperty(_VISIBLE)) {
5142 // If the "shadow" event was refired - just append again and resize
5143 this._replaceShadow();
5149 this._createShadow();
5152 this.beforeShowEvent.subscribe(this._shadowBeforeShow);
5154 } else if (!bShadow) {
5155 this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5156 this._removeShadow();
5163 * @method initEvents
5164 * @description Initializes the custom events for the menu.
5166 initEvents: function () {
5168 Menu.superclass.initEvents.call(this);
5170 // Create custom events
5172 var i = EVENT_TYPES.length - 1,
5179 aEventData = EVENT_TYPES[i];
5181 oCustomEvent = this.createEvent(aEventData[1]);
5182 oCustomEvent.signature = CustomEvent.LIST;
5184 this[aEventData[0]] = oCustomEvent;
5193 * @method positionOffScreen
5194 * @description Positions the menu outside of the boundaries of the browser's
5195 * viewport. Called automatically when a menu is hidden to ensure that
5196 * it doesn't force the browser to render uncessary scrollbars.
5198 positionOffScreen: function () {
5200 var oIFrame = this.iframe,
5201 oElement = this.element,
5202 sPos = this.OFF_SCREEN_POSITION;
5204 oElement.style.top = _EMPTY_STRING;
5205 oElement.style.left = _EMPTY_STRING;
5209 oIFrame.style.top = sPos;
5210 oIFrame.style.left = sPos;
5219 * @description Finds the menu's root menu.
5221 getRoot: function () {
5223 var oItem = this.parent,
5229 oParentMenu = oItem.parent;
5231 returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5247 * @description Returns a string representing the menu.
5250 toString: function () {
5252 var sReturnVal = _MENU,
5257 sReturnVal += (_SPACE + sId);
5267 * @method setItemGroupTitle
5268 * @description Sets the title of a group of menu items.
5269 * @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.
5270 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5271 * the title belongs.
5273 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5280 if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5282 nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5283 oTitle = this._aGroupTitleElements[nGroupIndex];
5288 oTitle.innerHTML = p_sGroupTitle;
5293 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5295 oTitle.innerHTML = p_sGroupTitle;
5297 this._aGroupTitleElements[nGroupIndex] = oTitle;
5302 i = this._aGroupTitleElements.length - 1;
5306 if (this._aGroupTitleElements[i]) {
5308 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5318 if (nFirstIndex !== null) {
5320 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
5325 this.changeContentEvent.fire();
5335 * @description Appends an item to the menu.
5336 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5337 * instance to be added to the menu.
5338 * @param {HTML} p_oItem String or markup specifying content of the item to be added
5339 * 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.
5340 * @param {Object} p_oItem Object literal containing a set of menu item
5341 * configuration properties.
5342 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5343 * which the item belongs.
5344 * @return {YAHOO.widget.MenuItem}
5346 addItem: function (p_oItem, p_nGroupIndex) {
5348 return this._addItemToGroup(p_nGroupIndex, p_oItem);
5355 * @description Adds an array of items to the menu.
5356 * @param {Array} p_aItems Array of items to be added to the menu. The array
5357 * can contain strings specifying the markup for the content of each item to be created, object
5358 * literals specifying each of the menu item configuration properties,
5359 * 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.
5360 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5361 * which the items belongs.
5364 addItems: function (p_aItems, p_nGroupIndex) {
5373 if (Lang.isArray(p_aItems)) {
5375 nItems = p_aItems.length;
5378 for(i=0; i<nItems; i++) {
5380 oItem = p_aItems[i];
5384 if (Lang.isArray(oItem)) {
5386 aItems[aItems.length] = this.addItems(oItem, i);
5391 aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5400 if (aItems.length) {
5414 * @method insertItem
5415 * @description Inserts an item into the menu at the specified index.
5416 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5417 * instance to be added to the menu.
5418 * @param {String} p_oItem String specifying the text of the item to be added
5420 * @param {Object} p_oItem Object literal containing a set of menu item
5421 * configuration properties.
5422 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5423 * the item should be added.
5424 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5426 * @return {YAHOO.widget.MenuItem}
5428 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5430 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5436 * @method removeItem
5437 * @description Removes the specified item from the menu.
5438 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5439 * instance to be removed from the menu.
5440 * @param {Number} p_oObject Number specifying the index of the item
5442 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5443 * which the item belongs.
5444 * @return {YAHOO.widget.MenuItem}
5446 removeItem: function (p_oObject, p_nGroupIndex) {
5451 if (!Lang.isUndefined(p_oObject)) {
5453 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5455 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5458 else if (Lang.isNumber(p_oObject)) {
5460 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5482 * @description Returns an array of all of the items in the menu.
5485 getItems: function () {
5487 var aGroups = this._aItemGroups,
5493 if (Lang.isArray(aGroups)) {
5495 nGroups = aGroups.length;
5497 returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5507 * @method getItemGroups
5508 * @description Multi-dimensional Array representing the menu items as they
5509 * are grouped in the menu.
5512 getItemGroups: function () {
5514 return this._aItemGroups;
5521 * @description Returns the item at the specified index.
5522 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5523 * item to be retrieved.
5524 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5526 * @return {YAHOO.widget.MenuItem}
5528 getItem: function (p_nItemIndex, p_nGroupIndex) {
5533 if (Lang.isNumber(p_nItemIndex)) {
5535 aGroup = this._getItemGroup(p_nGroupIndex);
5539 returnVal = aGroup[p_nItemIndex];
5551 * @method getSubmenus
5552 * @description Returns an array of all of the submenus that are immediate
5553 * children of the menu.
5556 getSubmenus: function () {
5558 var aItems = this.getItems(),
5559 nItems = aItems.length,
5570 for(i=0; i<nItems; i++) {
5576 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5580 aSubmenus[aSubmenus.length] = oSubmenu;
5596 * @method clearContent
5597 * @description Removes all of the content from the menu, including the menu
5598 * items, group titles, header and footer.
5600 clearContent: function () {
5602 var aItems = this.getItems(),
5603 nItems = aItems.length,
5604 oElement = this.element,
5606 oHeader = this.header,
5607 oFooter = this.footer,
5623 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5627 this.cfg.configChangedEvent.unsubscribe(
5628 this._onParentMenuConfigChange, oSubmenu);
5630 this.renderEvent.unsubscribe(this._onParentMenuRender,
5635 this.removeItem(oItem, oItem.groupIndex);
5647 Event.purgeElement(oHeader);
5648 oElement.removeChild(oHeader);
5655 Event.purgeElement(oFooter);
5656 oElement.removeChild(oFooter);
5662 Event.purgeElement(oBody);
5664 oBody.innerHTML = _EMPTY_STRING;
5668 this.activeItem = null;
5670 this._aItemGroups = [];
5671 this._aListElements = [];
5672 this._aGroupTitleElements = [];
5674 this.cfg.setProperty(_WIDTH, null);
5681 * @description Removes the menu's <code><div></code> element
5682 * (and accompanying child nodes) from the document.
5683 * @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.
5684 * 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.
5687 destroy: function (shallowPurge) {
5691 this.clearContent();
5693 this._aItemGroups = null;
5694 this._aListElements = null;
5695 this._aGroupTitleElements = null;
5698 // Continue with the superclass implementation of this method
5700 Menu.superclass.destroy.call(this, shallowPurge);
5707 * @method setInitialFocus
5708 * @description Sets focus to the menu's first enabled item.
5710 setInitialFocus: function () {
5712 var oItem = this._getFirstEnabledItem();
5724 * @method setInitialSelection
5725 * @description Sets the "selected" configuration property of the menu's first
5726 * enabled item to "true."
5728 setInitialSelection: function () {
5730 var oItem = this._getFirstEnabledItem();
5734 oItem.cfg.setProperty(_SELECTED, true);
5741 * @method clearActiveItem
5742 * @description Sets the "selected" configuration property of the menu's active
5743 * item to "false" and hides the item's submenu.
5744 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5745 * should be blurred.
5747 clearActiveItem: function (p_bBlur) {
5749 if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5751 this._cancelShowDelay();
5756 var oActiveItem = this.activeItem,
5762 oConfig = oActiveItem.cfg;
5768 this.getRoot()._hasFocus = true;
5772 oConfig.setProperty(_SELECTED, false);
5774 oSubmenu = oConfig.getProperty(_SUBMENU);
5783 this.activeItem = null;
5792 * @description Causes the menu to receive focus and fires the "focus" event.
5794 focus: function () {
5796 if (!this.hasFocus()) {
5798 this.setInitialFocus();
5807 * @description Causes the menu to lose focus and fires the "blur" event.
5813 if (this.hasFocus()) {
5815 oItem = MenuManager.getFocusedMenuItem();
5830 * @description Returns a boolean indicating whether or not the menu has focus.
5833 hasFocus: function () {
5835 return (MenuManager.getFocusedMenu() == this.getRoot());
5840 _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5842 var oItem = p_aArgs[0],
5843 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5846 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5852 _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5854 var oSubmenu = this.cfg.getProperty(_SUBMENU);
5857 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5864 * Adds the specified CustomEvent subscriber to the menu and each of
5867 * @param p_type {string} the type, or name of the event
5868 * @param p_fn {function} the function to exectute when the event fires
5869 * @param p_obj {Object} An object to be passed along when the event
5871 * @param p_override {boolean} If true, the obj passed in becomes the
5872 * execution scope of the listener
5874 subscribe: function () {
5876 // Subscribe to the event for this Menu instance
5877 Menu.superclass.subscribe.apply(this, arguments);
5879 // Subscribe to the "itemAdded" event so that all future submenus
5880 // also subscribe to this event
5881 Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5884 var aItems = this.getItems(),
5893 nItems = aItems.length;
5902 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5905 oSubmenu.subscribe.apply(oSubmenu, arguments);
5908 oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5921 unsubscribe: function () {
5923 // Remove the event for this Menu instance
5924 Menu.superclass.unsubscribe.apply(this, arguments);
5926 // Remove the "itemAdded" event so that all future submenus don't have
5927 // the event handler
5928 Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5931 var aItems = this.getItems(),
5940 nItems = aItems.length;
5949 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5952 oSubmenu.unsubscribe.apply(oSubmenu, arguments);
5955 oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5969 * @description Initializes the class's configurable properties which can be
5970 * changed using the menu's Config object ("cfg").
5971 * @method initDefaultConfig
5973 initDefaultConfig: function () {
5975 Menu.superclass.initDefaultConfig.call(this);
5977 var oConfig = this.cfg;
5980 // Module documentation overrides
5984 * @description Object or array of objects representing the ContainerEffect
5985 * classes that are active for animating the container. When set this
5986 * property is automatically applied to all submenus.
5991 // Overlay documentation overrides
5996 * @description Number representing the absolute x-coordinate position of
5997 * the Menu. This property is only applied when the "position"
5998 * configuration property is set to dynamic.
6006 * @description Number representing the absolute y-coordinate position of
6007 * the Menu. This property is only applied when the "position"
6008 * configuration property is set to dynamic.
6015 * @description Array of the absolute x and y positions of the Menu. This
6016 * property is only applied when the "position" configuration property is
6026 * @description Array of context arguments for context-sensitive positioning.
6027 * The format is: [id or element, element corner, context corner].
6028 * For example, setting this property to ["img1", "tl", "bl"] would
6029 * align the Menu's top left corner to the context element's
6030 * bottom left corner. This property is only applied when the "position"
6031 * configuration property is set to dynamic.
6038 * @config fixedcenter
6039 * @description Boolean indicating if the Menu should be anchored to the
6040 * center of the viewport. This property is only applied when the
6041 * "position" configuration property is set to dynamic.
6049 * @description Boolean indicating whether or not the Menu should
6050 * have an IFRAME shim; used to prevent SELECT elements from
6051 * poking through an Overlay instance in IE6. When set to "true",
6052 * the iframe shim is created when the Menu instance is intially
6053 * made visible. This property is only applied when the "position"
6054 * configuration property is set to dynamic and is automatically applied
6057 * @default true for IE6 and below, false for all other browsers.
6061 // Add configuration attributes
6064 Change the default value for the "visible" configuration
6065 property to "false" by re-adding the property.
6070 * @description Boolean indicating whether or not the menu is visible. If
6071 * the menu's "position" configuration property is set to "dynamic" (the
6072 * default), this property toggles the menu's <code><div></code>
6073 * element's "visibility" style property between "visible" (true) or
6074 * "hidden" (false). If the menu's "position" configuration property is
6075 * set to "static" this property toggles the menu's
6076 * <code><div></code> element's "display" style property
6077 * between "block" (true) or "none" (false).
6081 oConfig.addProperty(
6084 handler: this.configVisible,
6085 value: VISIBLE_CONFIG.value,
6086 validator: VISIBLE_CONFIG.validator
6092 Change the default value for the "constraintoviewport" configuration
6093 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6097 * @config constraintoviewport
6098 * @description Boolean indicating if the menu will try to remain inside
6099 * the boundaries of the size of viewport. This property is only applied
6100 * when the "position" configuration property is set to dynamic and is
6101 * automatically applied to all submenus.
6105 oConfig.addProperty(
6106 CONSTRAIN_TO_VIEWPORT_CONFIG.key,
6108 handler: this.configConstrainToViewport,
6109 value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
6110 validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
6111 supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
6117 Change the default value for the "preventcontextoverlap" configuration
6118 property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6122 * @config preventcontextoverlap
6123 * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
6124 * when the "constraintoviewport" configuration property is set to "true".
6128 oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6130 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
6131 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
6132 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6139 * @description String indicating how a menu should be positioned on the
6140 * screen. Possible values are "static" and "dynamic." Static menus are
6141 * visible by default and reside in the normal flow of the document
6142 * (CSS position: static). Dynamic menus are hidden by default, reside
6143 * out of the normal flow of the document (CSS position: absolute), and
6144 * can overlay other elements on the screen.
6148 oConfig.addProperty(
6149 POSITION_CONFIG.key,
6151 handler: this.configPosition,
6152 value: POSITION_CONFIG.value,
6153 validator: POSITION_CONFIG.validator,
6154 supercedes: POSITION_CONFIG.supercedes
6160 * @config submenualignment
6161 * @description Array defining how submenus should be aligned to their
6162 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6163 * a submenu's top left corner is aligned to its parent menu item's top
6165 * @default ["tl","tr"]
6168 oConfig.addProperty(
6169 SUBMENU_ALIGNMENT_CONFIG.key,
6171 value: SUBMENU_ALIGNMENT_CONFIG.value,
6172 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6178 * @config autosubmenudisplay
6179 * @description Boolean indicating if submenus are automatically made
6180 * visible when the user mouses over the menu's items.
6184 oConfig.addProperty(
6185 AUTO_SUBMENU_DISPLAY_CONFIG.key,
6187 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
6188 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6189 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6196 * @description Number indicating the time (in milliseconds) that should
6197 * expire before a submenu is made visible when the user mouses over
6198 * the menu's items. This property is only applied when the "position"
6199 * configuration property is set to dynamic and is automatically applied
6204 oConfig.addProperty(
6205 SHOW_DELAY_CONFIG.key,
6207 value: SHOW_DELAY_CONFIG.value,
6208 validator: SHOW_DELAY_CONFIG.validator,
6209 suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6216 * @description Number indicating the time (in milliseconds) that should
6217 * expire before the menu is hidden. This property is only applied when
6218 * the "position" configuration property is set to dynamic and is
6219 * automatically applied to all submenus.
6223 oConfig.addProperty(
6224 HIDE_DELAY_CONFIG.key,
6226 handler: this.configHideDelay,
6227 value: HIDE_DELAY_CONFIG.value,
6228 validator: HIDE_DELAY_CONFIG.validator,
6229 suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6235 * @config submenuhidedelay
6236 * @description Number indicating the time (in milliseconds) that should
6237 * expire before a submenu is hidden when the user mouses out of a menu item
6238 * heading in the direction of a submenu. The value must be greater than or
6239 * equal to the value specified for the "showdelay" configuration property.
6240 * This property is only applied when the "position" configuration property
6241 * is set to dynamic and is automatically applied to all submenus.
6245 oConfig.addProperty(
6246 SUBMENU_HIDE_DELAY_CONFIG.key,
6248 value: SUBMENU_HIDE_DELAY_CONFIG.value,
6249 validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6250 suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6256 * @config clicktohide
6257 * @description Boolean indicating if the menu will automatically be
6258 * hidden if the user clicks outside of it. This property is only
6259 * applied when the "position" configuration property is set to dynamic
6260 * and is automatically applied to all submenus.
6264 oConfig.addProperty(
6265 CLICK_TO_HIDE_CONFIG.key,
6267 value: CLICK_TO_HIDE_CONFIG.value,
6268 validator: CLICK_TO_HIDE_CONFIG.validator,
6269 suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6276 * @description HTML element reference or string specifying the id
6277 * attribute of the HTML element that the menu's markup should be
6279 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6280 * level-one-html.html#ID-58190037">HTMLElement</a>|String
6281 * @default document.body
6283 oConfig.addProperty(
6284 CONTAINER_CONFIG.key,
6286 handler: this.configContainer,
6287 value: document.body,
6288 suppressEvent: CONTAINER_CONFIG.suppressEvent
6294 * @config scrollincrement
6295 * @description Number used to control the scroll speed of a menu. Used to
6296 * increment the "scrollTop" property of the menu's body by when a menu's
6297 * content is scrolling. When set this property is automatically applied
6302 oConfig.addProperty(
6303 SCROLL_INCREMENT_CONFIG.key,
6305 value: SCROLL_INCREMENT_CONFIG.value,
6306 validator: SCROLL_INCREMENT_CONFIG.validator,
6307 supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6308 suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6314 * @config minscrollheight
6315 * @description Number defining the minimum threshold for the "maxheight"
6316 * configuration property. When set this property is automatically applied
6321 oConfig.addProperty(
6322 MIN_SCROLL_HEIGHT_CONFIG.key,
6324 value: MIN_SCROLL_HEIGHT_CONFIG.value,
6325 validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6326 supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6327 suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6334 * @description Number defining the maximum height (in pixels) for a menu's
6335 * body element (<code><div class="bd"></code>). Once a menu's body
6336 * exceeds this height, the contents of the body are scrolled to maintain
6337 * this value. This value cannot be set lower than the value of the
6338 * "minscrollheight" configuration property.
6342 oConfig.addProperty(
6343 MAX_HEIGHT_CONFIG.key,
6345 handler: this.configMaxHeight,
6346 value: MAX_HEIGHT_CONFIG.value,
6347 validator: MAX_HEIGHT_CONFIG.validator,
6348 suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6349 supercedes: MAX_HEIGHT_CONFIG.supercedes
6356 * @description String representing the CSS class to be applied to the
6357 * menu's root <code><div></code> element. The specified class(es)
6358 * are appended in addition to the default class as specified by the menu's
6359 * CSS_CLASS_NAME constant. When set this property is automatically
6360 * applied to all submenus.
6364 oConfig.addProperty(
6365 CLASS_NAME_CONFIG.key,
6367 handler: this.configClassName,
6368 value: CLASS_NAME_CONFIG.value,
6369 validator: CLASS_NAME_CONFIG.validator,
6370 supercedes: CLASS_NAME_CONFIG.supercedes
6377 * @description Boolean indicating if the menu should be disabled.
6378 * Disabling a menu disables each of its items. (Disabled menu items are
6379 * dimmed and will not respond to user input or fire events.) Disabled
6380 * menus have a corresponding "disabled" CSS class applied to their root
6381 * <code><div></code> element.
6385 oConfig.addProperty(
6386 DISABLED_CONFIG.key,
6388 handler: this.configDisabled,
6389 value: DISABLED_CONFIG.value,
6390 validator: DISABLED_CONFIG.validator,
6391 suppressEvent: DISABLED_CONFIG.suppressEvent
6398 * @description Boolean indicating if the menu should have a shadow.
6402 oConfig.addProperty(
6405 handler: this.configShadow,
6406 value: SHADOW_CONFIG.value,
6407 validator: SHADOW_CONFIG.validator
6414 * @description Boolean indicating if the menu should remain open when clicked.
6418 oConfig.addProperty(
6419 KEEP_OPEN_CONFIG.key,
6421 value: KEEP_OPEN_CONFIG.value,
6422 validator: KEEP_OPEN_CONFIG.validator
6428 }); // END YAHOO.lang.extend
6437 * Creates an item for a menu.
6439 * @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.
6440 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6441 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6442 * the <code><li></code> element of the menu item.
6443 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6444 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6445 * specifying the <code><optgroup></code> element of the menu item.
6446 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6447 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6448 * specifying the <code><option></code> element of the menu item.
6449 * @param {Object} p_oConfig Optional. Object literal specifying the
6450 * configuration for the menu item. See configuration class documentation
6455 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6461 this.parent = p_oConfig.parent;
6462 this.value = p_oConfig.value;
6463 this.id = p_oConfig.id;
6467 this.init(p_oObject, p_oConfig);
6474 var Dom = YAHOO.util.Dom,
6475 Module = YAHOO.widget.Module,
6476 Menu = YAHOO.widget.Menu,
6477 MenuItem = YAHOO.widget.MenuItem,
6478 CustomEvent = YAHOO.util.CustomEvent,
6482 // Private string constants
6487 _HELP_TEXT = "helptext",
6490 _EMPHASIS = "emphasis",
6491 _STRONG_EMPHASIS = "strongemphasis",
6492 _CHECKED = "checked",
6493 _SUBMENU = "submenu",
6494 _DISABLED = "disabled",
6495 _SELECTED = "selected",
6496 _HAS_SUBMENU = "hassubmenu",
6497 _CHECKED_DISABLED = "checked-disabled",
6498 _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6499 _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6500 _CHECKED_SELECTED = "checked-selected",
6501 _ONCLICK = "onclick",
6502 _CLASSNAME = "classname",
6505 _OPTGROUP = "OPTGROUP",
6506 _LI_UPPERCASE = "LI",
6510 _START_HELP_TEXT = "<em class=\"helptext\">",
6513 _START_STRONG = "<strong>",
6514 _END_STRONG = "</strong>",
6515 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6519 _VISIBLE = "visible",
6521 _MENUITEM = "MenuItem",
6525 _LI_LOWERCASE = "li",
6526 _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6530 ["mouseOverEvent", "mouseover"],
6531 ["mouseOutEvent", "mouseout"],
6532 ["mouseDownEvent", "mousedown"],
6533 ["mouseUpEvent", "mouseup"],
6534 ["clickEvent", _CLICK],
6535 ["keyPressEvent", "keypress"],
6536 ["keyDownEvent", "keydown"],
6537 ["keyUpEvent", "keyup"],
6538 ["focusEvent", "focus"],
6539 ["blurEvent", "blur"],
6540 ["destroyEvent", "destroy"]
6546 value: _EMPTY_STRING,
6547 validator: Lang.isString,
6551 HELP_TEXT_CONFIG = {
6553 supercedes: [_TEXT],
6571 validator: Lang.isBoolean,
6572 suppressEvent: true,
6576 STRONG_EMPHASIS_CONFIG = {
6577 key: _STRONG_EMPHASIS,
6579 validator: Lang.isBoolean,
6580 suppressEvent: true,
6587 validator: Lang.isBoolean,
6588 suppressEvent: true,
6589 supercedes: [_DISABLED, _SELECTED]
6594 suppressEvent: true,
6595 supercedes: [_DISABLED, _SELECTED]
6601 validator: Lang.isBoolean,
6602 suppressEvent: true,
6603 supercedes: [_TEXT, _SELECTED]
6609 validator: Lang.isBoolean,
6618 CLASS_NAME_CONFIG = {
6621 validator: Lang.isString,
6625 KEY_LISTENER_CONFIG = {
6631 m_oMenuItemTemplate = null,
6637 * @method getClassNameForState
6638 * @description Returns a class name for the specified prefix and state. If the class name does not
6639 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6641 * @param {String} prefix String representing the prefix for the class name
6642 * @param {String} state String representing a state - "disabled," "checked," etc.
6644 var getClassNameForState = function (prefix, state) {
6646 var oClassNames = CLASS_NAMES[prefix];
6649 CLASS_NAMES[prefix] = {};
6650 oClassNames = CLASS_NAMES[prefix];
6654 var sClassName = oClassNames[state];
6657 sClassName = prefix + _HYPHEN + state;
6658 oClassNames[state] = sClassName;
6667 * @method addClassNameForState
6668 * @description Applies a class name to a MenuItem instance's <LI> and <A> elements
6669 * that represents a MenuItem's state - "disabled," "checked," etc.
6671 * @param {String} state String representing a state - "disabled," "checked," etc.
6673 var addClassNameForState = function (state) {
6675 Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6676 Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6681 * @method removeClassNameForState
6682 * @description Removes a class name from a MenuItem instance's <LI> and <A> elements
6683 * that represents a MenuItem's state - "disabled," "checked," etc.
6685 * @param {String} state String representing a state - "disabled," "checked," etc.
6687 var removeClassNameForState = function (state) {
6689 Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6690 Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6695 MenuItem.prototype = {
6698 * @property CSS_CLASS_NAME
6699 * @description String representing the CSS class(es) to be applied to the
6700 * <code><li></code> element of the menu item.
6701 * @default "yuimenuitem"
6705 CSS_CLASS_NAME: "yuimenuitem",
6709 * @property CSS_LABEL_CLASS_NAME
6710 * @description String representing the CSS class(es) to be applied to the
6711 * menu item's <code><a></code> element.
6712 * @default "yuimenuitemlabel"
6716 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6720 * @property SUBMENU_TYPE
6721 * @description Object representing the type of menu to instantiate and
6722 * add when parsing the child nodes of the menu item's source HTML element.
6724 * @type YAHOO.widget.Menu
6730 // Private member variables
6734 * @property _oAnchor
6735 * @description Object reference to the menu item's
6736 * <code><a></code> element.
6739 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6740 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6746 * @property _oHelpTextEM
6747 * @description Object reference to the menu item's help text
6748 * <code><em></code> element.
6751 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6752 * one-html.html#ID-58190037">HTMLElement</a>
6758 * @property _oSubmenu
6759 * @description Object reference to the menu item's submenu.
6762 * @type YAHOO.widget.Menu
6768 * @property _oOnclickAttributeValue
6769 * @description Object reference to the menu item's current value for the
6770 * "onclick" configuration attribute.
6775 _oOnclickAttributeValue: null,
6779 * @property _sClassName
6780 * @description The current value of the "classname" configuration attribute.
6789 // Public properties
6793 * @property constructor
6794 * @description Object reference to the menu item's constructor function.
6795 * @default YAHOO.widget.MenuItem
6796 * @type YAHOO.widget.MenuItem
6798 constructor: MenuItem,
6803 * @description Number indicating the ordinal position of the menu item in
6812 * @property groupIndex
6813 * @description Number indicating the index of the group to which the menu
6823 * @description Object reference to the menu item's parent menu.
6825 * @type YAHOO.widget.Menu
6832 * @description Object reference to the menu item's
6833 * <code><li></code> element.
6834 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6835 * -one-html.html#ID-74680021">HTMLLIElement</a>
6836 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6837 * one-html.html#ID-74680021">HTMLLIElement</a>
6843 * @property srcElement
6844 * @description Object reference to the HTML element (either
6845 * <code><li></code>, <code><optgroup></code> or
6846 * <code><option></code>) used create the menu item.
6847 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6848 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6849 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6850 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6851 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6852 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6853 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6854 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6855 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6856 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6863 * @description Object reference to the menu item's value.
6872 * @deprecated Use YAHOO.env.ua
6873 * @description String representing the browser.
6876 browser: Module.prototype.browser,
6881 * @description Id of the menu item's root <code><li></code>
6882 * element. This property should be set via the constructor using the
6883 * configuration object literal. If an id is not specified, then one will
6884 * be created using the "generateId" method of the Dom utility.
6896 * @event destroyEvent
6897 * @description Fires when the menu item's <code><li></code>
6898 * element is removed from its parent <code><ul></code> element.
6899 * @type YAHOO.util.CustomEvent
6904 * @event mouseOverEvent
6905 * @description Fires when the mouse has entered the menu item. Passes
6906 * back the DOM Event object as an argument.
6907 * @type YAHOO.util.CustomEvent
6912 * @event mouseOutEvent
6913 * @description Fires when the mouse has left the menu item. Passes back
6914 * the DOM Event object as an argument.
6915 * @type YAHOO.util.CustomEvent
6920 * @event mouseDownEvent
6921 * @description Fires when the user mouses down on the menu item. Passes
6922 * back the DOM Event object as an argument.
6923 * @type YAHOO.util.CustomEvent
6928 * @event mouseUpEvent
6929 * @description Fires when the user releases a mouse button while the mouse
6930 * is over the menu item. Passes back the DOM Event object as an argument.
6931 * @type YAHOO.util.CustomEvent
6937 * @description Fires when the user clicks the on the menu item. Passes
6938 * back the DOM Event object as an argument.
6939 * @type YAHOO.util.CustomEvent
6944 * @event keyPressEvent
6945 * @description Fires when the user presses an alphanumeric key when the
6946 * menu item has focus. Passes back the DOM Event object as an argument.
6947 * @type YAHOO.util.CustomEvent
6952 * @event keyDownEvent
6953 * @description Fires when the user presses a key when the menu item has
6954 * focus. Passes back the DOM Event object as an argument.
6955 * @type YAHOO.util.CustomEvent
6961 * @description Fires when the user releases a key when the menu item has
6962 * focus. Passes back the DOM Event object as an argument.
6963 * @type YAHOO.util.CustomEvent
6969 * @description Fires when the menu item receives focus.
6970 * @type YAHOO.util.CustomEvent
6976 * @description Fires when the menu item loses the input focus.
6977 * @type YAHOO.util.CustomEvent
6983 * @description The MenuItem class's initialization method. This method is
6984 * automatically called by the constructor, and sets up all DOM references
6985 * for pre-existing markup, and creates required markup if it is not
6987 * @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.
6988 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6989 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6990 * the <code><li></code> element of the menu item.
6991 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6992 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6993 * specifying the <code><optgroup></code> element of the menu item.
6994 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6995 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6996 * specifying the <code><option></code> element of the menu item.
6997 * @param {Object} p_oConfig Optional. Object literal specifying the
6998 * configuration for the menu item. See configuration class documentation
7001 init: function (p_oObject, p_oConfig) {
7004 if (!this.SUBMENU_TYPE) {
7006 this.SUBMENU_TYPE = Menu;
7011 // Create the config object
7013 this.cfg = new YAHOO.util.Config(this);
7015 this.initDefaultConfig();
7017 var oConfig = this.cfg,
7028 if (Lang.isString(p_oObject)) {
7030 this._createRootNodeStructure();
7032 oConfig.queueProperty(_TEXT, p_oObject);
7035 else if (p_oObject && p_oObject.tagName) {
7037 switch(p_oObject.tagName.toUpperCase()) {
7041 this._createRootNodeStructure();
7043 oConfig.queueProperty(_TEXT, p_oObject.text);
7044 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7046 this.value = p_oObject.value;
7048 this.srcElement = p_oObject;
7054 this._createRootNodeStructure();
7056 oConfig.queueProperty(_TEXT, p_oObject.label);
7057 oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7059 this.srcElement = p_oObject;
7061 this._initSubTree();
7067 // Get the anchor node (if it exists)
7069 oAnchor = Dom.getFirstChild(p_oObject);
7072 // Capture the "text" and/or the "URL"
7076 sURL = oAnchor.getAttribute(_HREF, 2);
7077 sTarget = oAnchor.getAttribute(_TARGET);
7079 sText = oAnchor.innerHTML;
7083 this.srcElement = p_oObject;
7084 this.element = p_oObject;
7085 this._oAnchor = oAnchor;
7088 Set these properties silently to sync up the
7089 configuration object without making changes to the
7093 oConfig.setProperty(_TEXT, sText, true);
7094 oConfig.setProperty(_URL, sURL, true);
7095 oConfig.setProperty(_TARGET, sTarget, true);
7097 this._initSubTree();
7108 sId = (this.srcElement || this.element).id;
7112 sId = this.id || Dom.generateId();
7114 this.element.id = sId;
7121 Dom.addClass(this.element, this.CSS_CLASS_NAME);
7122 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7125 i = EVENT_TYPES.length - 1;
7129 aEventData = EVENT_TYPES[i];
7131 oCustomEvent = this.createEvent(aEventData[1]);
7132 oCustomEvent.signature = CustomEvent.LIST;
7134 this[aEventData[0]] = oCustomEvent;
7142 oConfig.applyConfig(p_oConfig);
7146 oConfig.fireQueue();
7157 * @method _createRootNodeStructure
7158 * @description Creates the core DOM structure for the menu item.
7161 _createRootNodeStructure: function () {
7166 if (!m_oMenuItemTemplate) {
7168 m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7169 m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7173 oElement = m_oMenuItemTemplate.cloneNode(true);
7174 oElement.className = this.CSS_CLASS_NAME;
7176 oAnchor = oElement.firstChild;
7177 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7179 this.element = oElement;
7180 this._oAnchor = oAnchor;
7186 * @method _initSubTree
7187 * @description Iterates the source element's childNodes collection and uses
7188 * the child nodes to instantiate other menus.
7191 _initSubTree: function () {
7193 var oSrcEl = this.srcElement,
7202 if (oSrcEl.childNodes.length > 0) {
7204 if (this.parent.lazyLoad && this.parent.srcElement &&
7205 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7207 oConfig.setProperty(
7209 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7215 oNode = oSrcEl.firstChild;
7220 if (oNode && oNode.tagName) {
7222 switch(oNode.tagName.toUpperCase()) {
7226 oConfig.setProperty(_SUBMENU, oNode);
7232 aOptions[aOptions.length] = oNode;
7241 while((oNode = oNode.nextSibling));
7244 nOptions = aOptions.length;
7248 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7250 oConfig.setProperty(_SUBMENU, oMenu);
7252 for(n=0; n<nOptions; n++) {
7254 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7268 // Event handlers for configuration properties
7272 * @method configText
7273 * @description Event handler for when the "text" configuration property of
7274 * the menu item changes.
7275 * @param {String} p_sType String representing the name of the event that
7277 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7278 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7279 * that fired the event.
7281 configText: function (p_sType, p_aArgs, p_oItem) {
7283 var sText = p_aArgs[0],
7285 oAnchor = this._oAnchor,
7286 sHelpText = oConfig.getProperty(_HELP_TEXT),
7287 sHelpTextHTML = _EMPTY_STRING,
7288 sEmphasisStartTag = _EMPTY_STRING,
7289 sEmphasisEndTag = _EMPTY_STRING;
7297 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7302 if (oConfig.getProperty(_EMPHASIS)) {
7304 sEmphasisStartTag = _START_EM;
7305 sEmphasisEndTag = _END_EM;
7310 if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7312 sEmphasisStartTag = _START_STRONG;
7313 sEmphasisEndTag = _END_STRONG;
7318 oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7326 * @method configHelpText
7327 * @description Event handler for when the "helptext" configuration property
7328 * of the menu item changes.
7329 * @param {String} p_sType String representing the name of the event that
7331 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7332 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7333 * that fired the event.
7335 configHelpText: function (p_sType, p_aArgs, p_oItem) {
7337 this.cfg.refireEvent(_TEXT);
7344 * @description Event handler for when the "url" configuration property of
7345 * the menu item changes.
7346 * @param {String} p_sType String representing the name of the event that
7348 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7349 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7350 * that fired the event.
7352 configURL: function (p_sType, p_aArgs, p_oItem) {
7354 var sURL = p_aArgs[0];
7362 var oAnchor = this._oAnchor;
7366 oAnchor.removeAttribute(_HREF);
7370 oAnchor.setAttribute(_HREF, sURL);
7376 * @method configTarget
7377 * @description Event handler for when the "target" configuration property
7378 * of the menu item changes.
7379 * @param {String} p_sType String representing the name of the event that
7381 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7382 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7383 * that fired the event.
7385 configTarget: function (p_sType, p_aArgs, p_oItem) {
7387 var sTarget = p_aArgs[0],
7388 oAnchor = this._oAnchor;
7390 if (sTarget && sTarget.length > 0) {
7392 oAnchor.setAttribute(_TARGET, sTarget);
7397 oAnchor.removeAttribute(_TARGET);
7405 * @method configEmphasis
7406 * @description Event handler for when the "emphasis" configuration property
7407 * of the menu item changes.
7408 * @param {String} p_sType String representing the name of the event that
7410 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7411 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7412 * that fired the event.
7414 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7416 var bEmphasis = p_aArgs[0],
7420 if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7422 oConfig.setProperty(_STRONG_EMPHASIS, false);
7427 oConfig.refireEvent(_TEXT);
7433 * @method configStrongEmphasis
7434 * @description Event handler for when the "strongemphasis" configuration
7435 * property of the menu item changes.
7436 * @param {String} p_sType String representing the name of the event that
7438 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7439 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7440 * that fired the event.
7442 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7444 var bStrongEmphasis = p_aArgs[0],
7448 if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7450 oConfig.setProperty(_EMPHASIS, false);
7454 oConfig.refireEvent(_TEXT);
7460 * @method configChecked
7461 * @description Event handler for when the "checked" configuration property
7462 * of the menu item changes.
7463 * @param {String} p_sType String representing the name of the event that
7465 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7466 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7467 * that fired the event.
7469 configChecked: function (p_sType, p_aArgs, p_oItem) {
7471 var bChecked = p_aArgs[0],
7477 addClassNameForState.call(this, _CHECKED);
7482 removeClassNameForState.call(this, _CHECKED);
7486 oConfig.refireEvent(_TEXT);
7489 if (oConfig.getProperty(_DISABLED)) {
7491 oConfig.refireEvent(_DISABLED);
7496 if (oConfig.getProperty(_SELECTED)) {
7498 oConfig.refireEvent(_SELECTED);
7507 * @method configDisabled
7508 * @description Event handler for when the "disabled" configuration property
7509 * of the menu item changes.
7510 * @param {String} p_sType String representing the name of the event that
7512 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7513 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7514 * that fired the event.
7516 configDisabled: function (p_sType, p_aArgs, p_oItem) {
7518 var bDisabled = p_aArgs[0],
7520 oSubmenu = oConfig.getProperty(_SUBMENU),
7521 bChecked = oConfig.getProperty(_CHECKED);
7526 if (oConfig.getProperty(_SELECTED)) {
7528 oConfig.setProperty(_SELECTED, false);
7533 addClassNameForState.call(this, _DISABLED);
7538 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7545 addClassNameForState.call(this, _CHECKED_DISABLED);
7552 removeClassNameForState.call(this, _DISABLED);
7557 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7564 removeClassNameForState.call(this, _CHECKED_DISABLED);
7574 * @method configSelected
7575 * @description Event handler for when the "selected" configuration property
7576 * of the menu item changes.
7577 * @param {String} p_sType String representing the name of the event that
7579 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7580 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7581 * that fired the event.
7583 configSelected: function (p_sType, p_aArgs, p_oItem) {
7585 var oConfig = this.cfg,
7586 oAnchor = this._oAnchor,
7588 bSelected = p_aArgs[0],
7589 bChecked = oConfig.getProperty(_CHECKED),
7590 oSubmenu = oConfig.getProperty(_SUBMENU);
7600 if (bSelected && !oConfig.getProperty(_DISABLED)) {
7602 addClassNameForState.call(this, _SELECTED);
7607 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7614 addClassNameForState.call(this, _CHECKED_SELECTED);
7621 removeClassNameForState.call(this, _SELECTED);
7626 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7633 removeClassNameForState.call(this, _CHECKED_SELECTED);
7640 if (this.hasFocus() && UA.opera) {
7650 * @method _onSubmenuBeforeHide
7651 * @description "beforehide" Custom Event handler for a submenu.
7653 * @param {String} p_sType String representing the name of the event that
7655 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7657 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7659 var oItem = this.parent,
7664 oItem._oAnchor.blur();
7665 oMenu.beforeHideEvent.unsubscribe(onHide);
7670 if (oItem.hasFocus()) {
7672 oMenu = oItem.parent;
7674 oMenu.beforeHideEvent.subscribe(onHide);
7682 * @method configSubmenu
7683 * @description Event handler for when the "submenu" configuration property
7684 * of the menu item changes.
7685 * @param {String} p_sType String representing the name of the event that
7687 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7688 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7689 * that fired the event.
7691 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7693 var oSubmenu = p_aArgs[0],
7695 bLazyLoad = this.parent && this.parent.lazyLoad,
7703 if (oSubmenu instanceof Menu) {
7706 oMenu.parent = this;
7707 oMenu.lazyLoad = bLazyLoad;
7710 else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7712 sSubmenuId = oSubmenu.id;
7713 oSubmenuConfig = oSubmenu;
7715 oSubmenuConfig.lazyload = bLazyLoad;
7716 oSubmenuConfig.parent = this;
7718 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7721 // Set the value of the property to the Menu instance
7723 oConfig.setProperty(_SUBMENU, oMenu, true);
7728 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7731 // Set the value of the property to the Menu instance
7733 oConfig.setProperty(_SUBMENU, oMenu, true);
7740 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7742 addClassNameForState.call(this, _HAS_SUBMENU);
7745 if (oConfig.getProperty(_URL) === _HASH) {
7747 oConfig.setProperty(_URL, (_HASH + oMenu.id));
7752 this._oSubmenu = oMenu;
7757 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7766 removeClassNameForState.call(this, _HAS_SUBMENU);
7768 if (this._oSubmenu) {
7770 this._oSubmenu.destroy();
7777 if (oConfig.getProperty(_DISABLED)) {
7779 oConfig.refireEvent(_DISABLED);
7784 if (oConfig.getProperty(_SELECTED)) {
7786 oConfig.refireEvent(_SELECTED);
7794 * @method configOnClick
7795 * @description Event handler for when the "onclick" configuration property
7796 * of the menu item changes.
7797 * @param {String} p_sType String representing the name of the event that
7799 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7800 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7801 * that fired the event.
7803 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7805 var oObject = p_aArgs[0];
7808 Remove any existing listeners if a "click" event handler has
7809 already been specified.
7812 if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7814 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7815 this._oOnclickAttributeValue.obj);
7817 this._oOnclickAttributeValue = null;
7822 if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
7823 Lang.isFunction(oObject.fn)) {
7825 this.clickEvent.subscribe(oObject.fn,
7826 ((_OBJ in oObject) ? oObject.obj : this),
7827 ((_SCOPE in oObject) ? oObject.scope : null) );
7829 this._oOnclickAttributeValue = oObject;
7837 * @method configClassName
7838 * @description Event handler for when the "classname" configuration
7839 * property of a menu item changes.
7840 * @param {String} p_sType String representing the name of the event that
7842 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7843 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7844 * that fired the event.
7846 configClassName: function (p_sType, p_aArgs, p_oItem) {
7848 var sClassName = p_aArgs[0];
7850 if (this._sClassName) {
7852 Dom.removeClass(this.element, this._sClassName);
7856 Dom.addClass(this.element, sClassName);
7857 this._sClassName = sClassName;
7863 * @method _dispatchClickEvent
7864 * @description Dispatches a DOM "click" event to the anchor element of a
7865 * MenuItem instance.
7868 _dispatchClickEvent: function () {
7870 var oMenuItem = this,
7873 if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7874 oAnchor = Dom.getFirstChild(oMenuItem.element);
7876 // Dispatch a "click" event to the MenuItem's anchor so that its
7877 // "click" event handlers will get called in response to the user
7878 // pressing the keyboard shortcut defined by the "keylistener"
7879 // configuration property.
7881 this._dispatchDOMClick(oAnchor);
7886 * Utility method to dispatch a DOM click event on the HTMLElement passed in
7888 * @method _dispatchDOMClick
7890 * @param {HTMLElement} el
7892 _dispatchDOMClick : function(el) {
7895 // Choose the standards path for IE9
7896 if (UA.ie && UA.ie < 9) {
7897 el.fireEvent(_ONCLICK);
7899 if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7900 oEvent = document.createEvent("HTMLEvents");
7901 oEvent.initEvent(_CLICK, true, true);
7903 oEvent = document.createEvent("MouseEvents");
7904 oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
7906 el.dispatchEvent(oEvent);
7911 * @method _createKeyListener
7912 * @description "show" event handler for a Menu instance - responsible for
7913 * setting up the KeyListener instance for a MenuItem.
7915 * @param {String} type String representing the name of the event that
7917 * @param {Array} args Array of arguments sent when the event was fired.
7918 * @param {Array} keyData Array of arguments sent when the event was fired.
7920 _createKeyListener: function (type, args, keyData) {
7922 var oMenuItem = this,
7923 oMenu = oMenuItem.parent;
7925 var oKeyListener = new YAHOO.util.KeyListener(
7926 oMenu.element.ownerDocument,
7929 fn: oMenuItem._dispatchClickEvent,
7931 correctScope: true });
7934 if (oMenu.cfg.getProperty(_VISIBLE)) {
7935 oKeyListener.enable();
7939 oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
7940 oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
7942 oMenuItem._keyListener = oKeyListener;
7944 oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
7950 * @method configKeyListener
7951 * @description Event handler for when the "keylistener" configuration
7952 * property of a menu item changes.
7953 * @param {String} p_sType String representing the name of the event that
7955 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7957 configKeyListener: function (p_sType, p_aArgs) {
7959 var oKeyData = p_aArgs[0],
7961 oMenu = oMenuItem.parent;
7963 if (oMenuItem._keyData) {
7965 // Unsubscribe from the "show" event in case the keylistener
7966 // config was changed before the Menu was ever made visible.
7968 oMenu.unsubscribe(_SHOW,
7969 oMenuItem._createKeyListener, oMenuItem._keyData);
7971 oMenuItem._keyData = null;
7976 // Tear down for the previous value of the "keylistener" property
7978 if (oMenuItem._keyListener) {
7980 oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
7981 oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
7983 oMenuItem._keyListener.disable();
7984 oMenuItem._keyListener = null;
7991 oMenuItem._keyData = oKeyData;
7993 // Defer the creation of the KeyListener instance until the
7994 // parent Menu is visible. This is necessary since the
7995 // KeyListener instance needs to be bound to the document the
7996 // Menu has been rendered into. Deferring creation of the
7997 // KeyListener instance also improves performance.
7999 oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
8000 oKeyData, oMenuItem);
8010 * @method initDefaultConfig
8011 * @description Initializes an item's configurable properties.
8013 initDefaultConfig : function () {
8015 var oConfig = this.cfg;
8018 // Define the configuration attributes
8022 * @description String or markup specifying the text label for the menu item.
8023 * When building a menu from existing HTML the value of this property
8024 * 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.
8028 oConfig.addProperty(
8031 handler: this.configText,
8032 value: TEXT_CONFIG.value,
8033 validator: TEXT_CONFIG.validator,
8034 suppressEvent: TEXT_CONFIG.suppressEvent
8041 * @description String or markup specifying additional instructional text to
8042 * 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.
8043 * @deprecated Use "text" configuration property to add help text markup.
8044 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em
8045 * class=\"helptext\">Ctrl + C</em>");</code>
8047 * @type HTML|<a href="http://www.w3.org/TR/
8048 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8051 oConfig.addProperty(
8052 HELP_TEXT_CONFIG.key,
8054 handler: this.configHelpText,
8055 supercedes: HELP_TEXT_CONFIG.supercedes,
8056 suppressEvent: HELP_TEXT_CONFIG.suppressEvent
8063 * @description String specifying the URL for the menu item's anchor's
8064 * "href" attribute. When building a menu from existing HTML the value
8065 * 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.
8069 oConfig.addProperty(
8072 handler: this.configURL,
8073 value: URL_CONFIG.value,
8074 suppressEvent: URL_CONFIG.suppressEvent
8081 * @description String specifying the value for the "target" attribute
8082 * of the menu item's anchor element. <strong>Specifying a target will
8083 * require the user to click directly on the menu item's anchor node in
8084 * order to cause the browser to navigate to the specified URL.</strong>
8085 * When building a menu from existing HTML the value of this property
8086 * 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.
8090 oConfig.addProperty(
8093 handler: this.configTarget,
8094 suppressEvent: TARGET_CONFIG.suppressEvent
8101 * @description Boolean indicating if the text of the menu item will be
8102 * rendered with emphasis.
8103 * @deprecated Use the "text" configuration property to add emphasis.
8104 * For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some
8105 * Text</em>");</code>
8109 oConfig.addProperty(
8110 EMPHASIS_CONFIG.key,
8112 handler: this.configEmphasis,
8113 value: EMPHASIS_CONFIG.value,
8114 validator: EMPHASIS_CONFIG.validator,
8115 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8116 supercedes: EMPHASIS_CONFIG.supercedes
8122 * @config strongemphasis
8123 * @description Boolean indicating if the text of the menu item will be
8124 * rendered with strong emphasis.
8125 * @deprecated Use the "text" configuration property to add strong emphasis.
8126 * For example: <code>oMenuItem.cfg.setProperty("text", "<strong>
8127 * Some Text</strong>");</code>
8131 oConfig.addProperty(
8132 STRONG_EMPHASIS_CONFIG.key,
8134 handler: this.configStrongEmphasis,
8135 value: STRONG_EMPHASIS_CONFIG.value,
8136 validator: STRONG_EMPHASIS_CONFIG.validator,
8137 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8138 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8145 * @description Boolean indicating if the menu item should be rendered
8150 oConfig.addProperty(
8153 handler: this.configChecked,
8154 value: CHECKED_CONFIG.value,
8155 validator: CHECKED_CONFIG.validator,
8156 suppressEvent: CHECKED_CONFIG.suppressEvent,
8157 supercedes: CHECKED_CONFIG.supercedes
8164 * @description Boolean indicating if the menu item should be disabled.
8165 * (Disabled menu items are dimmed and will not respond to user input
8170 oConfig.addProperty(
8171 DISABLED_CONFIG.key,
8173 handler: this.configDisabled,
8174 value: DISABLED_CONFIG.value,
8175 validator: DISABLED_CONFIG.validator,
8176 suppressEvent: DISABLED_CONFIG.suppressEvent
8183 * @description Boolean indicating if the menu item should
8188 oConfig.addProperty(
8189 SELECTED_CONFIG.key,
8191 handler: this.configSelected,
8192 value: SELECTED_CONFIG.value,
8193 validator: SELECTED_CONFIG.validator,
8194 suppressEvent: SELECTED_CONFIG.suppressEvent
8201 * @description Object specifying the submenu to be appended to the
8202 * menu item. The value can be one of the following: <ul><li>Object
8203 * specifying a Menu instance.</li><li>Object literal specifying the
8204 * menu to be created. Format: <code>{ id: [menu id], itemdata:
8205 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
8206 * items</a>] }</code>.</li><li>String specifying the id attribute
8207 * of the <code><div></code> element of the menu.</li><li>
8208 * Object specifying the <code><div></code> element of the
8211 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8212 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8215 oConfig.addProperty(
8218 handler: this.configSubmenu,
8219 supercedes: SUBMENU_CONFIG.supercedes,
8220 suppressEvent: SUBMENU_CONFIG.suppressEvent
8227 * @description Object literal representing the code to be executed when
8228 * the item is clicked. Format:<br> <code> {<br>
8229 * <strong>fn:</strong> Function, // The handler to call when
8230 * the event fires.<br> <strong>obj:</strong> Object, // An
8231 * object to pass back to the handler.<br> <strong>scope:</strong>
8232 * Object // The object to use for the scope of the handler.
8237 oConfig.addProperty(
8240 handler: this.configOnClick,
8241 suppressEvent: ONCLICK_CONFIG.suppressEvent
8248 * @description CSS class to be applied to the menu item's root
8249 * <code><li></code> element. The specified class(es) are
8250 * appended in addition to the default class as specified by the menu
8251 * item's CSS_CLASS_NAME constant.
8255 oConfig.addProperty(
8256 CLASS_NAME_CONFIG.key,
8258 handler: this.configClassName,
8259 value: CLASS_NAME_CONFIG.value,
8260 validator: CLASS_NAME_CONFIG.validator,
8261 suppressEvent: CLASS_NAME_CONFIG.suppressEvent
8267 * @config keylistener
8268 * @description Object literal representing the key(s) that can be used
8269 * to trigger the MenuItem's "click" event. Possible attributes are
8270 * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
8271 * or an array of ints representing keycodes).
8275 oConfig.addProperty(
8276 KEY_LISTENER_CONFIG.key,
8278 handler: this.configKeyListener,
8279 value: KEY_LISTENER_CONFIG.value,
8280 suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
8287 * @method getNextSibling
8288 * @description Finds the menu item's next sibling.
8289 * @return YAHOO.widget.MenuItem
8291 getNextSibling: function () {
8293 var isUL = function (el) {
8294 return (el.nodeName.toLowerCase() === "ul");
8297 menuitemEl = this.element,
8298 next = Dom.getNextSibling(menuitemEl),
8305 parent = menuitemEl.parentNode;
8306 sibling = Dom.getNextSiblingBy(parent, isUL);
8312 list = Dom.getFirstChildBy(parent.parentNode, isUL);
8315 next = Dom.getFirstChild(list);
8319 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8324 * @method getNextEnabledSibling
8325 * @description Finds the menu item's next enabled sibling.
8326 * @return YAHOO.widget.MenuItem
8328 getNextEnabledSibling: function () {
8330 var next = this.getNextSibling();
8332 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
8338 * @method getPreviousSibling
8339 * @description Finds the menu item's previous sibling.
8340 * @return {YAHOO.widget.MenuItem}
8342 getPreviousSibling: function () {
8344 var isUL = function (el) {
8345 return (el.nodeName.toLowerCase() === "ul");
8348 menuitemEl = this.element,
8349 next = Dom.getPreviousSibling(menuitemEl),
8356 parent = menuitemEl.parentNode;
8357 sibling = Dom.getPreviousSiblingBy(parent, isUL);
8363 list = Dom.getLastChildBy(parent.parentNode, isUL);
8366 next = Dom.getLastChild(list);
8370 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8376 * @method getPreviousEnabledSibling
8377 * @description Finds the menu item's previous enabled sibling.
8378 * @return {YAHOO.widget.MenuItem}
8380 getPreviousEnabledSibling: function () {
8382 var next = this.getPreviousSibling();
8384 return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
8391 * @description Causes the menu item to receive the focus and fires the
8394 focus: function () {
8396 var oParent = this.parent,
8397 oAnchor = this._oAnchor,
8398 oActiveItem = oParent.activeItem;
8401 function setFocus() {
8405 if (!(UA.ie && !document.hasFocus())) {
8409 oActiveItem.blurEvent.fire();
8415 this.focusEvent.fire();
8427 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
8428 this.element.style.display != _NONE) {
8432 Setting focus via a timer fixes a race condition in Firefox, IE
8433 and Opera where the browser viewport jumps as it trys to
8434 position and focus the menu.
8437 Lang.later(0, this, setFocus);
8446 * @description Causes the menu item to lose focus and fires the
8451 var oParent = this.parent;
8453 if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8455 Lang.later(0, this, function () {
8459 this._oAnchor.blur();
8460 this.blurEvent.fire();
8476 * @description Returns a boolean indicating whether or not the menu item
8480 hasFocus: function () {
8482 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8489 * @description Removes the menu item's <code><li></code> element
8490 * from its parent <code><ul></code> element.
8492 destroy: function () {
8494 var oEl = this.element,
8504 // If the item has a submenu, destroy it first
8506 oSubmenu = this.cfg.getProperty(_SUBMENU);
8515 // Remove the element from the parent node
8517 oParentNode = oEl.parentNode;
8521 oParentNode.removeChild(oEl);
8523 this.destroyEvent.fire();
8528 // Remove CustomEvent listeners
8530 i = EVENT_TYPES.length - 1;
8534 aEventData = EVENT_TYPES[i];
8536 this[aEventData[0]].unsubscribeAll();
8542 this.cfg.configChangedEvent.unsubscribeAll();
8551 * @description Returns a string representing the menu item.
8554 toString: function () {
8556 var sReturnVal = _MENUITEM,
8561 sReturnVal += (_SPACE + sId);
8571 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8577 _MOUSEDOWN = "mousedown",
8578 _CONTEXTMENU = "ContextMenu",
8582 * Creates a list of options or commands which are made visible in response to
8583 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8585 * @param {String} p_oElement String specifying the id attribute of the
8586 * <code><div></code> element of the context menu.
8587 * @param {String} p_oElement String specifying the id attribute of the
8588 * <code><select></code> element to be used as the data source for the
8590 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8591 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8592 * <code><div></code> element of the context menu.
8593 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8594 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8595 * the <code><select></code> element to be used as the data source for
8597 * @param {Object} p_oConfig Optional. Object literal specifying the
8598 * configuration for the context menu. See configuration class documentation
8600 * @class ContextMenu
8602 * @extends YAHOO.widget.Menu
8603 * @namespace YAHOO.widget
8605 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8606 YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8610 var Event = YAHOO.util.Event,
8612 ContextMenu = YAHOO.widget.ContextMenu,
8617 * Constant representing the name of the ContextMenu's events
8618 * @property EVENT_TYPES
8625 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8626 "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8633 * Constant representing the ContextMenu's configuration properties
8634 * @property DEFAULT_CONFIG
8647 * @description "beforeShow" event handler used to position the contextmenu.
8649 * @param {String} p_sType String representing the name of the event that
8651 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8652 * @param {Array} p_aPos Array representing the xy position for the context menu.
8654 function position(p_sType, p_aArgs, p_aPos) {
8655 this.cfg.setProperty(_XY, p_aPos);
8656 this.beforeShowEvent.unsubscribe(position, p_aPos);
8660 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8664 // Private properties
8668 * @property _oTrigger
8669 * @description Object reference to the current value of the "trigger"
8670 * configuration property.
8673 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8674 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8680 * @property _bCancelled
8681 * @description Boolean indicating if the display of the context menu should
8691 // Public properties
8695 * @property contextEventTarget
8696 * @description Object reference for the HTML element that was the target of the
8697 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8700 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8701 * html.html#ID-58190037">HTMLElement</a>
8703 contextEventTarget: null,
8711 * @event triggerContextMenuEvent
8712 * @param type {String} The name of the event, "triggerContextMenu"
8713 * @param args {Array} The array of event arguments. For this event, the underlying
8714 * DOM event is the only argument, available from args[0].
8715 * @description Custom Event wrapper for the "contextmenu" DOM event
8716 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8719 triggerContextMenuEvent: null,
8725 * @description The ContextMenu class's initialization method. This method is
8726 * automatically called by the constructor, and sets up all DOM references for
8727 * pre-existing markup, and creates required markup if it is not already present.
8728 * @param {String} p_oElement String specifying the id attribute of the
8729 * <code><div></code> element of the context menu.
8730 * @param {String} p_oElement String specifying the id attribute of the
8731 * <code><select></code> element to be used as the data source for
8733 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8734 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8735 * <code><div></code> element of the context menu.
8736 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8737 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8738 * the <code><select></code> element to be used as the data source for
8740 * @param {Object} p_oConfig Optional. Object literal specifying the
8741 * configuration for the context menu. See configuration class documentation
8744 init: function(p_oElement, p_oConfig) {
8747 // Call the init of the superclass (YAHOO.widget.Menu)
8749 ContextMenu.superclass.init.call(this, p_oElement);
8751 this.beforeInitEvent.fire(ContextMenu);
8754 this.cfg.applyConfig(p_oConfig, true);
8757 this.initEvent.fire(ContextMenu);
8762 * @method initEvents
8763 * @description Initializes the custom events for the context menu.
8765 initEvents: function() {
8766 ContextMenu.superclass.initEvents.call(this);
8768 // Create custom events
8769 this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8770 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8775 * @description Cancels the display of the context menu.
8777 cancel: function() {
8778 this._bCancelled = true;
8785 * @method _removeEventHandlers
8786 * @description Removes all of the DOM event handlers from the HTML element(s)
8787 * whose "context menu" event ("click" for Opera) trigger the display of
8791 _removeEventHandlers: function() {
8793 var oTrigger = this._oTrigger;
8795 // Remove the event handlers from the trigger(s)
8797 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
8800 Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8806 // Private event handlers
8809 * @method _onTriggerClick
8810 * @description "click" event handler for the HTML element(s) identified as the
8811 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8813 * @param {Event} p_oEvent Object representing the DOM event object passed back
8814 * by the event utility (YAHOO.util.Event).
8815 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8816 * menu that is handling the event.
8818 _onTriggerClick: function(p_oEvent, p_oMenu) {
8820 if (p_oEvent.ctrlKey) {
8821 Event.stopEvent(p_oEvent);
8828 * @method _onTriggerContextMenu
8829 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8830 * element(s) that trigger the display of the context menu.
8832 * @param {Event} p_oEvent Object representing the DOM event object passed back
8833 * by the event utility (YAHOO.util.Event).
8834 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8835 * menu that is handling the event.
8837 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8841 if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8843 this.contextEventTarget = Event.getTarget(p_oEvent);
8845 this.triggerContextMenuEvent.fire(p_oEvent);
8848 if (!this._bCancelled) {
8851 Prevent the browser's default context menu from appearing and
8852 stop the propagation of the "contextmenu" event so that
8853 other ContextMenu instances are not displayed.
8856 Event.stopEvent(p_oEvent);
8859 // Hide any other Menu instances that might be visible
8861 YAHOO.widget.MenuManager.hideVisible();
8865 // Position and display the context menu
8867 aXY = Event.getXY(p_oEvent);
8870 if (!YAHOO.util.Dom.inDocument(this.element)) {
8872 this.beforeShowEvent.subscribe(position, aXY);
8877 this.cfg.setProperty(_XY, aXY);
8886 this._bCancelled = false;
8899 * @description Returns a string representing the context menu.
8902 toString: function() {
8904 var sReturnVal = _CONTEXTMENU,
8909 sReturnVal += (_SPACE + sId);
8919 * @method initDefaultConfig
8920 * @description Initializes the class's configurable properties which can be
8921 * changed using the context menu's Config object ("cfg").
8923 initDefaultConfig: function() {
8925 ContextMenu.superclass.initDefaultConfig.call(this);
8929 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
8930 * for Opera) trigger the display of the context menu. Can be a string
8931 * representing the id attribute of the HTML element, an object reference
8932 * for the HTML element, or an array of strings or HTML element references.
8934 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8935 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8937 this.cfg.addProperty(TRIGGER_CONFIG.key,
8939 handler: this.configTrigger,
8940 suppressEvent: TRIGGER_CONFIG.suppressEvent
8949 * @description Removes the context menu's <code><div></code> element
8950 * (and accompanying child nodes) from the document.
8951 * @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.
8952 * 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.
8954 destroy: function(shallowPurge) {
8956 // Remove the DOM event handlers from the current trigger(s)
8958 this._removeEventHandlers();
8961 // Continue with the superclass implementation of this method
8963 ContextMenu.superclass.destroy.call(this, shallowPurge);
8969 // Public event handlers for configuration properties
8973 * @method configTrigger
8974 * @description Event handler for when the value of the "trigger" configuration
8976 * @param {String} p_sType String representing the name of the event that
8978 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8979 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8980 * menu that fired the event.
8982 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8984 var oTrigger = p_aArgs[0];
8989 If there is a current "trigger" - remove the event handlers
8990 from that element(s) before assigning new ones
8993 if (this._oTrigger) {
8995 this._removeEventHandlers();
8999 this._oTrigger = oTrigger;
9003 Listen for the "mousedown" event in Opera b/c it does not
9004 support the "contextmenu" event
9007 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9011 Assign a "click" event handler to the trigger element(s) for
9012 Opera to prevent default browser behaviors.
9017 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9024 this._removeEventHandlers();
9030 }); // END YAHOO.lang.extend
9037 * Creates an item for a context menu.
9039 * @param {String} p_oObject String specifying the text of the context menu item.
9040 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9041 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9042 * <code><li></code> element of the context menu item.
9043 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9044 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9045 * specifying the <code><optgroup></code> element of the context
9047 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9048 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9049 * the <code><option></code> element of the context menu item.
9050 * @param {Object} p_oConfig Optional. Object literal specifying the
9051 * configuration for the context menu item. See configuration class
9052 * documentation for more details.
9053 * @class ContextMenuItem
9055 * @extends YAHOO.widget.MenuItem
9056 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9057 * are of type YAHOO.widget.MenuItem.
9059 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9062 var Lang = YAHOO.lang,
9067 _DYNAMIC_STATIC = "dynamic," + _STATIC,
9068 _DISABLED = "disabled",
9069 _SELECTED = "selected",
9070 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9071 _SUBMENU = "submenu",
9072 _VISIBLE = "visible",
9074 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9075 _MENUBAR = "MenuBar";
9078 * Horizontal collection of items, each of which can contain a submenu.
9080 * @param {String} p_oElement String specifying the id attribute of the
9081 * <code><div></code> element of the menu bar.
9082 * @param {String} p_oElement String specifying the id attribute of the
9083 * <code><select></code> element to be used as the data source for the
9085 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9086 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9087 * the <code><div></code> element of the menu bar.
9088 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9089 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9090 * specifying the <code><select></code> element to be used as the data
9091 * source for the menu bar.
9092 * @param {Object} p_oConfig Optional. Object literal specifying the
9093 * configuration for the menu bar. See configuration class documentation for
9097 * @extends YAHOO.widget.Menu
9098 * @namespace YAHOO.widget
9100 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9102 YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9108 * @method checkPosition
9109 * @description Checks to make sure that the value of the "position" property
9110 * is one of the supported strings. Returns true if the position is supported.
9112 * @param {Object} p_sPosition String specifying the position of the menu.
9115 function checkPosition(p_sPosition) {
9117 var returnVal = false;
9119 if (Lang.isString(p_sPosition)) {
9121 returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9130 var Event = YAHOO.util.Event,
9131 MenuBar = YAHOO.widget.MenuBar,
9136 validator: checkPosition,
9137 supercedes: [_VISIBLE]
9140 SUBMENU_ALIGNMENT_CONFIG = {
9141 key: "submenualignment",
9145 AUTO_SUBMENU_DISPLAY_CONFIG = {
9146 key: _AUTO_SUBMENU_DISPLAY,
9148 validator: Lang.isBoolean,
9152 SUBMENU_TOGGLE_REGION_CONFIG = {
9153 key: _SUBMENU_TOGGLE_REGION,
9155 validator: Lang.isBoolean
9160 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9164 * @description The MenuBar class's initialization method. This method is
9165 * automatically called by the constructor, and sets up all DOM references for
9166 * pre-existing markup, and creates required markup if it is not already present.
9167 * @param {String} p_oElement String specifying the id attribute of the
9168 * <code><div></code> element of the menu bar.
9169 * @param {String} p_oElement String specifying the id attribute of the
9170 * <code><select></code> element to be used as the data source for the
9172 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9173 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
9174 * the <code><div></code> element of the menu bar.
9175 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9176 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
9177 * specifying the <code><select></code> element to be used as the data
9178 * source for the menu bar.
9179 * @param {Object} p_oConfig Optional. Object literal specifying the
9180 * configuration for the menu bar. See configuration class documentation for
9183 init: function(p_oElement, p_oConfig) {
9185 if(!this.ITEM_TYPE) {
9187 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9192 // Call the init of the superclass (YAHOO.widget.Menu)
9194 MenuBar.superclass.init.call(this, p_oElement);
9197 this.beforeInitEvent.fire(MenuBar);
9202 this.cfg.applyConfig(p_oConfig, true);
9206 this.initEvent.fire(MenuBar);
9216 * @property CSS_CLASS_NAME
9217 * @description String representing the CSS class(es) to be applied to the menu
9218 * bar's <code><div></code> element.
9219 * @default "yuimenubar"
9223 CSS_CLASS_NAME: "yuimenubar",
9227 * @property SUBMENU_TOGGLE_REGION_WIDTH
9228 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9229 * display of the MenuBarItem's submenu.
9234 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9237 // Protected event handlers
9241 * @method _onKeyDown
9242 * @description "keydown" Custom Event handler for the menu bar.
9244 * @param {String} p_sType String representing the name of the event that
9246 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9247 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9248 * that fired the event.
9250 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9252 var oEvent = p_aArgs[0],
9259 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9261 oItemCfg = oItem.cfg;
9263 switch(oEvent.keyCode) {
9265 case 37: // Left arrow
9266 case 39: // Right arrow
9268 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9270 oItemCfg.setProperty(_SELECTED, true);
9275 oNextItem = (oEvent.keyCode == 37) ?
9276 oItem.getPreviousEnabledSibling() :
9277 oItem.getNextEnabledSibling();
9281 this.clearActiveItem();
9283 oNextItem.cfg.setProperty(_SELECTED, true);
9285 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9290 oSubmenu.setInitialFocus();
9301 Event.preventDefault(oEvent);
9305 case 40: // Down arrow
9307 if(this.activeItem != oItem) {
9309 this.clearActiveItem();
9311 oItemCfg.setProperty(_SELECTED, true);
9316 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9320 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9322 oSubmenu.setInitialSelection();
9323 oSubmenu.setInitialFocus();
9329 oSubmenu.setInitialFocus();
9335 Event.preventDefault(oEvent);
9344 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9346 oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9348 if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9351 this.activeItem.focus();
9356 this.activeItem.cfg.setProperty(_SELECTED, false);
9357 this.activeItem.blur();
9361 Event.preventDefault(oEvent);
9370 * @description "click" event handler for the menu bar.
9372 * @param {String} p_sType String representing the name of the event that
9374 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9375 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
9376 * that fired the event.
9378 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9380 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9382 var oItem = p_aArgs[1],
9394 var toggleSubmenuDisplay = function () {
9396 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9410 if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9412 oEvent = p_aArgs[0];
9413 oTarget = Event.getTarget(oEvent);
9414 oActiveItem = this.activeItem;
9418 // Hide any other submenus that might be visible
9420 if(oActiveItem && oActiveItem != oItem) {
9422 this.clearActiveItem();
9427 oItem.cfg.setProperty(_SELECTED, true);
9430 // Show the submenu for the item
9432 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9437 oItemEl = oItem.element;
9438 nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9439 nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9441 if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9443 if (Event.getPageX(oEvent) > nToggleRegion) {
9445 toggleSubmenuDisplay();
9447 Event.preventDefault(oEvent);
9450 Return false so that other click event handlers are not called when the
9451 user clicks inside the toggle region.
9460 toggleSubmenuDisplay();
9478 * @method configSubmenuToggle
9479 * @description Event handler for when the "submenutoggleregion" configuration property of
9480 * a MenuBar changes.
9481 * @param {String} p_sType The name of the event that was fired.
9482 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9484 configSubmenuToggle: function (p_sType, p_aArgs) {
9486 var bSubmenuToggle = p_aArgs[0];
9488 if (bSubmenuToggle) {
9490 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9499 * @description Returns a string representing the menu bar.
9502 toString: function() {
9504 var sReturnVal = _MENUBAR,
9509 sReturnVal += (_SPACE + sId);
9519 * @description Initializes the class's configurable properties which can be
9520 * changed using the menu bar's Config object ("cfg").
9521 * @method initDefaultConfig
9523 initDefaultConfig: function() {
9525 MenuBar.superclass.initDefaultConfig.call(this);
9527 var oConfig = this.cfg;
9529 // Add configuration properties
9533 Set the default value for the "position" configuration property
9534 to "static" by re-adding the property.
9540 * @description String indicating how a menu bar should be positioned on the
9541 * screen. Possible values are "static" and "dynamic." Static menu bars
9542 * are visible by default and reside in the normal flow of the document
9543 * (CSS position: static). Dynamic menu bars are hidden by default, reside
9544 * out of the normal flow of the document (CSS position: absolute), and can
9545 * overlay other elements on the screen.
9549 oConfig.addProperty(
9550 POSITION_CONFIG.key,
9552 handler: this.configPosition,
9553 value: POSITION_CONFIG.value,
9554 validator: POSITION_CONFIG.validator,
9555 supercedes: POSITION_CONFIG.supercedes
9561 Set the default value for the "submenualignment" configuration property
9562 to ["tl","bl"] by re-adding the property.
9566 * @config submenualignment
9567 * @description Array defining how submenus should be aligned to their
9568 * parent menu bar item. The format is: [itemCorner, submenuCorner].
9569 * @default ["tl","bl"]
9572 oConfig.addProperty(
9573 SUBMENU_ALIGNMENT_CONFIG.key,
9575 value: SUBMENU_ALIGNMENT_CONFIG.value,
9576 suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9582 Change the default value for the "autosubmenudisplay" configuration
9583 property to "false" by re-adding the property.
9587 * @config autosubmenudisplay
9588 * @description Boolean indicating if submenus are automatically made
9589 * visible when the user mouses over the menu bar's items.
9593 oConfig.addProperty(
9594 AUTO_SUBMENU_DISPLAY_CONFIG.key,
9596 value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
9597 validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9598 suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9604 * @config submenutoggleregion
9605 * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
9606 * display of a submenu. The default width of the region is determined by the value of the
9607 * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
9608 * configuration property will be set to false, and any click event listeners will not be
9609 * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
9610 * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
9611 * standard behavior.
9615 oConfig.addProperty(
9616 SUBMENU_TOGGLE_REGION_CONFIG.key,
9618 value: SUBMENU_TOGGLE_REGION_CONFIG.value,
9619 validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9620 handler: this.configSubmenuToggle
9626 }); // END YAHOO.lang.extend
9633 * Creates an item for a menu bar.
9635 * @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.
9636 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9637 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9638 * <code><li></code> element of the menu bar item.
9639 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9640 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9641 * specifying the <code><optgroup></code> element of the menu bar item.
9642 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9643 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9644 * the <code><option></code> element of the menu bar item.
9645 * @param {Object} p_oConfig Optional. Object literal specifying the
9646 * configuration for the menu bar item. See configuration class documentation
9648 * @class MenuBarItem
9650 * @extends YAHOO.widget.MenuItem
9652 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9654 YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9658 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9664 * @description The MenuBarItem class's initialization method. This method is
9665 * automatically called by the constructor, and sets up all DOM references for
9666 * pre-existing markup, and creates required markup if it is not already present.
9667 * @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.
9668 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9669 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
9670 * <code><li></code> element of the menu bar item.
9671 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9672 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
9673 * specifying the <code><optgroup></code> element of the menu bar item.
9674 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9675 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
9676 * the <code><option></code> element of the menu bar item.
9677 * @param {Object} p_oConfig Optional. Object literal specifying the
9678 * configuration for the menu bar item. See configuration class documentation
9681 init: function(p_oObject, p_oConfig) {
9683 if(!this.SUBMENU_TYPE) {
9685 this.SUBMENU_TYPE = YAHOO.widget.Menu;
9691 Call the init of the superclass (YAHOO.widget.MenuItem)
9692 Note: We don't pass the user config in here yet
9693 because we only want it executed once, at the lowest
9697 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
9700 var oConfig = this.cfg;
9704 oConfig.applyConfig(p_oConfig, true);
9708 oConfig.fireQueue();
9718 * @property CSS_CLASS_NAME
9719 * @description String representing the CSS class(es) to be applied to the
9720 * <code><li></code> element of the menu bar item.
9721 * @default "yuimenubaritem"
9725 CSS_CLASS_NAME: "yuimenubaritem",
9729 * @property CSS_LABEL_CLASS_NAME
9730 * @description String representing the CSS class(es) to be applied to the
9731 * menu bar item's <code><a></code> element.
9732 * @default "yuimenubaritemlabel"
9736 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9745 * @description Returns a string representing the menu bar item.
9748 toString: function() {
9750 var sReturnVal = "MenuBarItem";
9752 if(this.cfg && this.cfg.getProperty("text")) {
9754 sReturnVal += (": " + this.cfg.getProperty("text"));
9762 }); // END YAHOO.lang.extend
9763 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.9.0", build: "2800"});