Deleting the check_defaults test from 19_STABLE. MDL-14854
[moodle-linuxchix.git] / lib / yui / menu / menu.js
blobf6c776389c15fe08a1b76c25dfd8ff4cbdb5ec82
1 /*
2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.3.0
6 */
9 /**
10 * @module menu
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>
16 * <ul>
17 * <li>Screen-reader accessibility.</li>
18 * <li>Keyboard and mouse navigation.</li>
19 * <li>A rich event model that provides access to all of a menu's
20 * interesting moments.</li>
21 * <li>Support for
22 * <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
23 * Enhancement</a>; Menus can be created from simple,
24 * semantic markup on the page or purely through JavaScript.</li>
25 * </ul>
26 * @title Menu
27 * @namespace YAHOO.widget
28 * @requires Event, Dom, Container
30 (function () {
32 var Dom = YAHOO.util.Dom,
33 Event = YAHOO.util.Event;
36 /**
37 * Singleton that manages a collection of all menus and menu items. Listens
38 * for DOM events at the document level and dispatches the events to the
39 * corresponding menu or menu item.
41 * @namespace YAHOO.widget
42 * @class MenuManager
43 * @static
45 YAHOO.widget.MenuManager = function () {
47 // Private member variables
50 // Flag indicating if the DOM event handlers have been attached
52 var m_bInitializedEventHandlers = false,
55 // Collection of menus
57 m_oMenus = {},
60 // Collection of visible menus
62 m_oVisibleMenus = {},
65 // Collection of menu items
67 m_oItems = {},
70 // Map of DOM event types to their equivalent CustomEvent types
72 m_oEventTypes = {
73 "click": "clickEvent",
74 "mousedown": "mouseDownEvent",
75 "mouseup": "mouseUpEvent",
76 "mouseover": "mouseOverEvent",
77 "mouseout": "mouseOutEvent",
78 "keydown": "keyDownEvent",
79 "keyup": "keyUpEvent",
80 "keypress": "keyPressEvent"
84 m_oFocusedMenuItem = null;
90 // Private methods
93 /**
94 * @method getMenuRootElement
95 * @description Finds the root DIV node of a menu or the root LI node of
96 * a menu item.
97 * @private
98 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
99 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
100 * specifying an HTML element.
102 function getMenuRootElement(p_oElement) {
104 var oParentNode;
106 if (p_oElement && p_oElement.tagName) {
108 switch (p_oElement.tagName.toUpperCase()) {
110 case "DIV":
112 oParentNode = p_oElement.parentNode;
114 // Check if the DIV is the inner "body" node of a menu
116 if (
118 Dom.hasClass(p_oElement, "hd") ||
119 Dom.hasClass(p_oElement, "bd") ||
120 Dom.hasClass(p_oElement, "ft")
121 ) &&
122 oParentNode &&
123 oParentNode.tagName &&
124 oParentNode.tagName.toUpperCase() == "DIV")
127 return oParentNode;
130 else {
132 return p_oElement;
136 break;
138 case "LI":
140 return p_oElement;
142 default:
144 oParentNode = p_oElement.parentNode;
146 if (oParentNode) {
148 return getMenuRootElement(oParentNode);
152 break;
162 // Private event handlers
166 * @method onDOMEvent
167 * @description Generic, global event handler for all of a menu's
168 * DOM-based events. This listens for events against the document
169 * object. If the target of a given event is a member of a menu or
170 * menu item's DOM, the instance's corresponding Custom Event is fired.
171 * @private
172 * @param {Event} p_oEvent Object representing the DOM event object
173 * passed back by the event utility (YAHOO.util.Event).
175 function onDOMEvent(p_oEvent) {
177 // Get the target node of the DOM event
179 var oTarget = Event.getTarget(p_oEvent),
181 // See if the target of the event was a menu, or a menu item
183 oElement = getMenuRootElement(oTarget),
184 sCustomEventType,
185 sTagName,
186 sId,
187 oMenuItem,
188 oMenu;
191 if (oElement) {
193 sTagName = oElement.tagName.toUpperCase();
195 if (sTagName == "LI") {
197 sId = oElement.id;
199 if (sId && m_oItems[sId]) {
201 oMenuItem = m_oItems[sId];
202 oMenu = oMenuItem.parent;
207 else if (sTagName == "DIV") {
209 if (oElement.id) {
211 oMenu = m_oMenus[oElement.id];
220 if (oMenu) {
222 sCustomEventType = m_oEventTypes[p_oEvent.type];
225 // Fire the Custom Event that corresponds the current DOM event
227 if (oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
229 oMenuItem[sCustomEventType].fire(p_oEvent);
232 if (
233 p_oEvent.type == "keyup" ||
234 p_oEvent.type == "mousedown")
237 if (m_oFocusedMenuItem != oMenuItem) {
239 if (m_oFocusedMenuItem) {
241 m_oFocusedMenuItem.blurEvent.fire();
245 oMenuItem.focusEvent.fire();
253 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
256 else if (p_oEvent.type == "mousedown") {
258 if (m_oFocusedMenuItem) {
260 m_oFocusedMenuItem.blurEvent.fire();
262 m_oFocusedMenuItem = null;
268 If the target of the event wasn't a menu, hide all
269 dynamically positioned menus
272 for (var i in m_oMenus) {
274 if (YAHOO.lang.hasOwnProperty(m_oMenus,i)) {
276 oMenu = m_oMenus[i];
278 if (oMenu.cfg.getProperty("clicktohide") &&
279 !(oMenu instanceof YAHOO.widget.MenuBar) &&
280 oMenu.cfg.getProperty("position") == "dynamic") {
282 oMenu.hide();
285 else {
287 oMenu.clearActiveItem(true);
296 else if (p_oEvent.type == "keyup") {
298 if (m_oFocusedMenuItem) {
300 m_oFocusedMenuItem.blurEvent.fire();
302 m_oFocusedMenuItem = null;
312 * @method onMenuDestroy
313 * @description "destroy" event handler for a menu.
314 * @private
315 * @param {String} p_sType String representing the name of the event
316 * that was fired.
317 * @param {Array} p_aArgs Array of arguments sent when the event
318 * was fired.
319 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
321 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
323 if (m_oMenus[p_oMenu.id]) {
325 this.removeMenu(p_oMenu);
333 * @method onMenuFocus
334 * @description "focus" event handler for a MenuItem instance.
335 * @private
336 * @param {String} p_sType String representing the name of the event
337 * that was fired.
338 * @param {Array} p_aArgs Array of arguments sent when the event
339 * was fired.
341 function onMenuFocus(p_sType, p_aArgs) {
343 var oItem = p_aArgs[0];
345 if (oItem) {
347 m_oFocusedMenuItem = oItem;
355 * @method onMenuBlur
356 * @description "blur" event handler for a MenuItem instance.
357 * @private
358 * @param {String} p_sType String representing the name of the event
359 * that was fired.
360 * @param {Array} p_aArgs Array of arguments sent when the event
361 * was fired.
363 function onMenuBlur(p_sType, p_aArgs) {
365 m_oFocusedMenuItem = null;
372 * @method onMenuVisibleConfigChange
373 * @description Event handler for when the "visible" configuration
374 * property of a Menu instance changes.
375 * @private
376 * @param {String} p_sType String representing the name of the event
377 * that was fired.
378 * @param {Array} p_aArgs Array of arguments sent when the event
379 * was fired.
381 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
383 var bVisible = p_aArgs[0],
384 sId = this.id;
386 if (bVisible) {
388 m_oVisibleMenus[sId] = this;
392 else if (m_oVisibleMenus[sId]) {
394 delete m_oVisibleMenus[sId];
403 * @method onItemDestroy
404 * @description "destroy" event handler for a MenuItem instance.
405 * @private
406 * @param {String} p_sType String representing the name of the event
407 * that was fired.
408 * @param {Array} p_aArgs Array of arguments sent when the event
409 * was fired.
411 function onItemDestroy(p_sType, p_aArgs) {
413 var sId = this.id;
415 if (sId && m_oItems[sId]) {
417 if (m_oFocusedMenuItem == this) {
419 m_oFocusedMenuItem = null;
423 delete m_oItems[sId];
432 * @method onItemAdded
433 * @description "itemadded" event handler for a Menu instance.
434 * @private
435 * @param {String} p_sType String representing the name of the event
436 * that was fired.
437 * @param {Array} p_aArgs Array of arguments sent when the event
438 * was fired.
440 function onItemAdded(p_sType, p_aArgs) {
442 var oItem = p_aArgs[0],
443 sId;
445 if (oItem instanceof YAHOO.widget.MenuItem) {
447 sId = oItem.id;
449 if (!m_oItems[sId]) {
451 m_oItems[sId] = oItem;
453 oItem.destroyEvent.subscribe(onItemDestroy);
463 return {
465 // Privileged methods
469 * @method addMenu
470 * @description Adds a menu to the collection of known menus.
471 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
472 * instance to be added.
474 addMenu: function (p_oMenu) {
476 var oDoc;
478 if (
479 p_oMenu instanceof YAHOO.widget.Menu &&
480 p_oMenu.id &&
481 !m_oMenus[p_oMenu.id]
484 m_oMenus[p_oMenu.id] = p_oMenu;
487 if (!m_bInitializedEventHandlers) {
489 oDoc = document;
491 Event.on(oDoc, "mouseover", onDOMEvent, this, true);
492 Event.on(oDoc, "mouseout", onDOMEvent, this, true);
493 Event.on(oDoc, "mousedown", onDOMEvent, this, true);
494 Event.on(oDoc, "mouseup", onDOMEvent, this, true);
495 Event.on(oDoc, "click", onDOMEvent, this, true);
496 Event.on(oDoc, "keydown", onDOMEvent, this, true);
497 Event.on(oDoc, "keyup", onDOMEvent, this, true);
498 Event.on(oDoc, "keypress", onDOMEvent, this, true);
501 m_bInitializedEventHandlers = true;
506 p_oMenu.destroyEvent.subscribe(
507 onMenuDestroy,
508 p_oMenu,
509 this);
511 p_oMenu.cfg.subscribeToConfigEvent(
512 "visible",
513 onMenuVisibleConfigChange);
515 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
516 p_oMenu.focusEvent.subscribe(onMenuFocus);
517 p_oMenu.blurEvent.subscribe(onMenuBlur);
526 * @method removeMenu
527 * @description Removes a menu from the collection of known menus.
528 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
529 * instance to be removed.
531 removeMenu: function (p_oMenu) {
533 var sId;
535 if (p_oMenu) {
537 sId = p_oMenu.id;
539 if (m_oMenus[sId] == p_oMenu) {
541 delete m_oMenus[sId];
545 if (m_oVisibleMenus[sId] == p_oMenu) {
547 delete m_oVisibleMenus[sId];
560 * @method hideVisible
561 * @description Hides all visible, dynamically positioned menus
562 * (excluding instances of YAHOO.widget.MenuBar).
564 hideVisible: function () {
566 var oMenu;
568 for (var i in m_oVisibleMenus) {
570 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus,i)) {
572 oMenu = m_oVisibleMenus[i];
574 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
575 oMenu.cfg.getProperty("position") == "dynamic") {
577 oMenu.hide();
589 * @method getMenus
590 * @description Returns an array of all menus registered with the
591 * menu manger.
592 * @return {Array}
594 getMenus: function () {
596 return m_oMenus;
602 * @method getMenu
603 * @description Returns a menu with the specified id.
604 * @param {String} p_sId String specifying the id of the
605 * <code>&#60;div&#62;</code> element representing the menu to
606 * be retrieved.
607 * @return {YAHOO.widget.Menu}
609 getMenu: function (p_sId) {
611 var oMenu = m_oMenus[p_sId];
613 if (oMenu) {
615 return oMenu;
623 * @method getMenuItem
624 * @description Returns a menu item with the specified id.
625 * @param {String} p_sId String specifying the id of the
626 * <code>&#60;li&#62;</code> element representing the menu item to
627 * be retrieved.
628 * @return {YAHOO.widget.MenuItem}
630 getMenuItem: function (p_sId) {
632 var oItem = m_oItems[p_sId];
634 if (oItem) {
636 return oItem;
644 * @method getMenuItemGroup
645 * @description Returns an array of menu item instances whose
646 * corresponding <code>&#60;li&#62;</code> elements are child
647 * nodes of the <code>&#60;ul&#62;</code> element with the
648 * specified id.
649 * @param {String} p_sId String specifying the id of the
650 * <code>&#60;ul&#62;</code> element representing the group of
651 * menu items to be retrieved.
652 * @return {Array}
654 getMenuItemGroup: function (p_sId) {
656 var oUL = Dom.get(p_sId),
657 aItems,
658 oNode,
659 oItem,
660 sId;
663 if (oUL && oUL.tagName &&
664 oUL.tagName.toUpperCase() == "UL") {
666 oNode = oUL.firstChild;
668 if (oNode) {
670 aItems = [];
672 do {
674 sId = oNode.id;
676 if (sId) {
678 oItem = this.getMenuItem(sId);
680 if (oItem) {
682 aItems[aItems.length] = oItem;
689 while ((oNode = oNode.nextSibling));
692 if (aItems.length > 0) {
694 return aItems;
706 * @method getFocusedMenuItem
707 * @description Returns a reference to the menu item that currently
708 * has focus.
709 * @return {YAHOO.widget.MenuItem}
711 getFocusedMenuItem: function () {
713 return m_oFocusedMenuItem;
719 * @method getFocusedMenu
720 * @description Returns a reference to the menu that currently
721 * has focus.
722 * @return {YAHOO.widget.Menu}
724 getFocusedMenu: function () {
726 if (m_oFocusedMenuItem) {
728 return (m_oFocusedMenuItem.parent.getRoot());
736 * @method toString
737 * @description Returns a string representing the menu manager.
738 * @return {String}
740 toString: function () {
742 return "MenuManager";
748 }();
750 })();
754 (function () {
758 * The Menu class creates a container that holds a vertical list representing
759 * a set of options or commands. Menu is the base class for all
760 * menu containers.
761 * @param {String} p_oElement String specifying the id attribute of the
762 * <code>&#60;div&#62;</code> element of the menu.
763 * @param {String} p_oElement String specifying the id attribute of the
764 * <code>&#60;select&#62;</code> element to be used as the data source
765 * for the menu.
766 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
767 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
768 * specifying the <code>&#60;div&#62;</code> element of the menu.
769 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
770 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
771 * Object specifying the <code>&#60;select&#62;</code> element to be used as
772 * the data source for the menu.
773 * @param {Object} p_oConfig Optional. Object literal specifying the
774 * configuration for the menu. See configuration class documentation for
775 * more details.
776 * @namespace YAHOO.widget
777 * @class Menu
778 * @constructor
779 * @extends YAHOO.widget.Overlay
781 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
783 if (p_oConfig) {
785 this.parent = p_oConfig.parent;
786 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
787 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
792 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
799 * @method checkPosition
800 * @description Checks to make sure that the value of the "position" property
801 * is one of the supported strings. Returns true if the position is supported.
802 * @private
803 * @param {Object} p_sPosition String specifying the position of the menu.
804 * @return {Boolean}
806 function checkPosition(p_sPosition) {
808 if (typeof p_sPosition == "string") {
810 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
817 var Dom = YAHOO.util.Dom,
818 Event = YAHOO.util.Event,
819 Module = YAHOO.widget.Module,
820 Overlay = YAHOO.widget.Overlay,
821 Menu = YAHOO.widget.Menu,
822 MenuManager = YAHOO.widget.MenuManager,
823 CustomEvent = YAHOO.util.CustomEvent,
824 Lang = YAHOO.lang,
826 m_oShadowTemplate,
829 * Constant representing the name of the Menu's events
830 * @property EVENT_TYPES
831 * @private
832 * @final
833 * @type Object
835 EVENT_TYPES = {
837 "MOUSE_OVER": "mouseover",
838 "MOUSE_OUT": "mouseout",
839 "MOUSE_DOWN": "mousedown",
840 "MOUSE_UP": "mouseup",
841 "CLICK": "click",
842 "KEY_PRESS": "keypress",
843 "KEY_DOWN": "keydown",
844 "KEY_UP": "keyup",
845 "FOCUS": "focus",
846 "BLUR": "blur",
847 "ITEM_ADDED": "itemAdded",
848 "ITEM_REMOVED": "itemRemoved"
854 * Constant representing the Menu's configuration properties
855 * @property DEFAULT_CONFIG
856 * @private
857 * @final
858 * @type Object
860 DEFAULT_CONFIG = {
862 "VISIBLE": {
863 key: "visible",
864 value: false,
865 validator: Lang.isBoolean
868 "CONSTRAIN_TO_VIEWPORT": {
869 key: "constraintoviewport",
870 value: true,
871 validator: Lang.isBoolean,
872 supercedes: ["iframe","x","y","xy"]
875 "POSITION": {
876 key: "position",
877 value: "dynamic",
878 validator: checkPosition,
879 supercedes: ["visible", "iframe"]
882 "SUBMENU_ALIGNMENT": {
883 key: "submenualignment",
884 value: ["tl","tr"]
887 "AUTO_SUBMENU_DISPLAY": {
888 key: "autosubmenudisplay",
889 value: true,
890 validator: Lang.isBoolean
893 "SHOW_DELAY": {
894 key: "showdelay",
895 value: 250,
896 validator: Lang.isNumber
899 "HIDE_DELAY": {
900 key: "hidedelay",
901 value: 0,
902 validator: Lang.isNumber,
903 suppressEvent: true
906 "SUBMENU_HIDE_DELAY": {
907 key: "submenuhidedelay",
908 value: 250,
909 validator: Lang.isNumber
912 "CLICK_TO_HIDE": {
913 key: "clicktohide",
914 value: true,
915 validator: Lang.isBoolean
918 "CONTAINER": {
919 key: "container"
922 "MAX_HEIGHT": {
923 key: "maxheight",
924 value: 0,
925 validator: Lang.isNumber,
926 supercedes: ["iframe"]
929 "CLASS_NAME": {
930 key: "classname",
931 value: null,
932 validator: Lang.isString
935 "DISABLED": {
936 key: "disabled",
937 value: false,
938 validator: Lang.isBoolean
945 YAHOO.lang.extend(Menu, Overlay, {
948 // Constants
952 * @property CSS_CLASS_NAME
953 * @description String representing the CSS class(es) to be applied to the
954 * menu's <code>&#60;div&#62;</code> element.
955 * @default "yuimenu"
956 * @final
957 * @type String
959 CSS_CLASS_NAME: "yuimenu",
963 * @property ITEM_TYPE
964 * @description Object representing the type of menu item to instantiate and
965 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
966 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
967 * of the menu's source HTML element.
968 * @default YAHOO.widget.MenuItem
969 * @final
970 * @type YAHOO.widget.MenuItem
972 ITEM_TYPE: null,
976 * @property GROUP_TITLE_TAG_NAME
977 * @description String representing the tagname of the HTML element used to
978 * title the menu's item groups.
979 * @default H6
980 * @final
981 * @type String
983 GROUP_TITLE_TAG_NAME: "h6",
987 // Private properties
990 /**
991 * @property _nHideDelayId
992 * @description Number representing the time-out setting used to cancel the
993 * hiding of a menu.
994 * @default null
995 * @private
996 * @type Number
998 _nHideDelayId: null,
1001 /**
1002 * @property _nShowDelayId
1003 * @description Number representing the time-out setting used to cancel the
1004 * showing of a menu.
1005 * @default null
1006 * @private
1007 * @type Number
1009 _nShowDelayId: null,
1012 /**
1013 * @property _nSubmenuHideDelayId
1014 * @description Number representing the time-out setting used to cancel the
1015 * hiding of a submenu.
1016 * @default null
1017 * @private
1018 * @type Number
1020 _nSubmenuHideDelayId: null,
1023 /**
1024 * @property _nBodyScrollId
1025 * @description Number representing the time-out setting used to cancel the
1026 * scrolling of the menu's body element.
1027 * @default null
1028 * @private
1029 * @type Number
1031 _nBodyScrollId: null,
1034 /**
1035 * @property _bHideDelayEventHandlersAssigned
1036 * @description Boolean indicating if the "mouseover" and "mouseout" event
1037 * handlers used for hiding the menu via a call to "window.setTimeout" have
1038 * already been assigned.
1039 * @default false
1040 * @private
1041 * @type Boolean
1043 _bHideDelayEventHandlersAssigned: false,
1047 * @property _bHandledMouseOverEvent
1048 * @description Boolean indicating the current state of the menu's
1049 * "mouseover" event.
1050 * @default false
1051 * @private
1052 * @type Boolean
1054 _bHandledMouseOverEvent: false,
1058 * @property _bHandledMouseOutEvent
1059 * @description Boolean indicating the current state of the menu's
1060 * "mouseout" event.
1061 * @default false
1062 * @private
1063 * @type Boolean
1065 _bHandledMouseOutEvent: false,
1069 * @property _aGroupTitleElements
1070 * @description Array of HTML element used to title groups of menu items.
1071 * @default []
1072 * @private
1073 * @type Array
1075 _aGroupTitleElements: null,
1079 * @property _aItemGroups
1080 * @description Multi-dimensional Array representing the menu items as they
1081 * are grouped in the menu.
1082 * @default []
1083 * @private
1084 * @type Array
1086 _aItemGroups: null,
1090 * @property _aListElements
1091 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is
1092 * the parent node for each item's <code>&#60;li&#62;</code> element.
1093 * @default []
1094 * @private
1095 * @type Array
1097 _aListElements: null,
1101 * @property _nCurrentMouseX
1102 * @description The current x coordinate of the mouse inside the area of
1103 * the menu.
1104 * @default 0
1105 * @private
1106 * @type Number
1108 _nCurrentMouseX: 0,
1112 * @property _nMaxHeight
1113 * @description The original value of the "maxheight" configuration property
1114 * as set by the user.
1115 * @default -1
1116 * @private
1117 * @type Number
1119 _nMaxHeight: -1,
1123 * @property _bStopMouseEventHandlers
1124 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1125 * from executing.
1126 * @default false
1127 * @private
1128 * @type Boolean
1130 _bStopMouseEventHandlers: false,
1134 * @property _sClassName
1135 * @description The current value of the "classname" configuration attribute.
1136 * @default null
1137 * @private
1138 * @type String
1140 _sClassName: null,
1144 * @property _bDisabled
1145 * @description The current value of the "disabled" configuration attribute.
1146 * @default false
1147 * @private
1148 * @type Boolean
1150 _bDisabled: false,
1153 // Public properties
1157 * @property lazyLoad
1158 * @description Boolean indicating if the menu's "lazy load" feature is
1159 * enabled. If set to "true," initialization and rendering of the menu's
1160 * items will be deferred until the first time it is made visible. This
1161 * property should be set via the constructor using the configuration
1162 * object literal.
1163 * @default false
1164 * @type Boolean
1166 lazyLoad: false,
1170 * @property itemData
1171 * @description Array of items to be added to the menu. The array can contain
1172 * strings representing the text for each item to be created, object literals
1173 * representing the menu item configuration properties, or MenuItem instances.
1174 * This property should be set via the constructor using the configuration
1175 * object literal.
1176 * @default null
1177 * @type Array
1179 itemData: null,
1183 * @property activeItem
1184 * @description Object reference to the item in the menu that has is selected.
1185 * @default null
1186 * @type YAHOO.widget.MenuItem
1188 activeItem: null,
1192 * @property parent
1193 * @description Object reference to the menu's parent menu or menu item.
1194 * This property can be set via the constructor using the configuration
1195 * object literal.
1196 * @default null
1197 * @type YAHOO.widget.MenuItem
1199 parent: null,
1203 * @property srcElement
1204 * @description Object reference to the HTML element (either
1205 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
1206 * create the menu.
1207 * @default null
1208 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1209 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1210 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1211 * html#ID-22445964">HTMLDivElement</a>
1213 srcElement: null,
1217 // Events
1221 * @event mouseOverEvent
1222 * @description Fires when the mouse has entered the menu. Passes back
1223 * the DOM Event object as an argument.
1225 mouseOverEvent: null,
1229 * @event mouseOutEvent
1230 * @description Fires when the mouse has left the menu. Passes back the DOM
1231 * Event object as an argument.
1232 * @type YAHOO.util.CustomEvent
1234 mouseOutEvent: null,
1238 * @event mouseDownEvent
1239 * @description Fires when the user mouses down on the menu. Passes back the
1240 * DOM Event object as an argument.
1241 * @type YAHOO.util.CustomEvent
1243 mouseDownEvent: null,
1247 * @event mouseUpEvent
1248 * @description Fires when the user releases a mouse button while the mouse is
1249 * over the menu. Passes back the DOM Event object as an argument.
1250 * @type YAHOO.util.CustomEvent
1252 mouseUpEvent: null,
1256 * @event clickEvent
1257 * @description Fires when the user clicks the on the menu. Passes back the
1258 * DOM Event object as an argument.
1259 * @type YAHOO.util.CustomEvent
1261 clickEvent: null,
1265 * @event keyPressEvent
1266 * @description Fires when the user presses an alphanumeric key when one of the
1267 * menu's items has focus. Passes back the DOM Event object as an argument.
1268 * @type YAHOO.util.CustomEvent
1270 keyPressEvent: null,
1274 * @event keyDownEvent
1275 * @description Fires when the user presses a key when one of the menu's items
1276 * has focus. Passes back the DOM Event object as an argument.
1277 * @type YAHOO.util.CustomEvent
1279 keyDownEvent: null,
1283 * @event keyUpEvent
1284 * @description Fires when the user releases a key when one of the menu's items
1285 * has focus. Passes back the DOM Event object as an argument.
1286 * @type YAHOO.util.CustomEvent
1288 keyUpEvent: null,
1292 * @event itemAddedEvent
1293 * @description Fires when an item is added to the menu.
1294 * @type YAHOO.util.CustomEvent
1296 itemAddedEvent: null,
1300 * @event itemRemovedEvent
1301 * @description Fires when an item is removed to the menu.
1302 * @type YAHOO.util.CustomEvent
1304 itemRemovedEvent: null,
1308 * @method init
1309 * @description The Menu class's initialization method. This method is
1310 * automatically called by the constructor, and sets up all DOM references
1311 * for pre-existing markup, and creates required markup if it is not
1312 * already present.
1313 * @param {String} p_oElement String specifying the id attribute of the
1314 * <code>&#60;div&#62;</code> element of the menu.
1315 * @param {String} p_oElement String specifying the id attribute of the
1316 * <code>&#60;select&#62;</code> element to be used as the data source
1317 * for the menu.
1318 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1319 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1320 * specifying the <code>&#60;div&#62;</code> element of the menu.
1321 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1322 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1323 * Object specifying the <code>&#60;select&#62;</code> element to be used as
1324 * the data source for the menu.
1325 * @param {Object} p_oConfig Optional. Object literal specifying the
1326 * configuration for the menu. See configuration class documentation for
1327 * more details.
1329 init: function (p_oElement, p_oConfig) {
1331 this._aItemGroups = [];
1332 this._aListElements = [];
1333 this._aGroupTitleElements = [];
1335 if (!this.ITEM_TYPE) {
1337 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1342 var oElement;
1344 if (typeof p_oElement == "string") {
1346 oElement = document.getElementById(p_oElement);
1349 else if (p_oElement.tagName) {
1351 oElement = p_oElement;
1356 if (oElement && oElement.tagName) {
1358 switch(oElement.tagName.toUpperCase()) {
1360 case "DIV":
1362 this.srcElement = oElement;
1364 if (!oElement.id) {
1366 oElement.setAttribute("id", Dom.generateId());
1372 Note: we don't pass the user config in here yet
1373 because we only want it executed once, at the lowest
1374 subclass level.
1377 Menu.superclass.init.call(this, oElement);
1379 this.beforeInitEvent.fire(Menu);
1383 break;
1385 case "SELECT":
1387 this.srcElement = oElement;
1391 The source element is not something that we can use
1392 outright, so we need to create a new Overlay
1394 Note: we don't pass the user config in here yet
1395 because we only want it executed once, at the lowest
1396 subclass level.
1399 Menu.superclass.init.call(this, Dom.generateId());
1401 this.beforeInitEvent.fire(Menu);
1405 break;
1410 else {
1413 Note: we don't pass the user config in here yet
1414 because we only want it executed once, at the lowest
1415 subclass level.
1418 Menu.superclass.init.call(this, p_oElement);
1420 this.beforeInitEvent.fire(Menu);
1427 if (this.element) {
1429 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1432 // Subscribe to Custom Events
1434 this.initEvent.subscribe(this._onInit);
1435 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1436 this.renderEvent.subscribe(this._onRender);
1437 this.renderEvent.subscribe(this.onRender);
1438 this.beforeShowEvent.subscribe(this._onBeforeShow);
1439 this.showEvent.subscribe(this._onShow);
1440 this.beforeHideEvent.subscribe(this._onBeforeHide);
1441 this.hideEvent.subscribe(this._onHide);
1442 this.mouseOverEvent.subscribe(this._onMouseOver);
1443 this.mouseOutEvent.subscribe(this._onMouseOut);
1444 this.clickEvent.subscribe(this._onClick);
1445 this.keyDownEvent.subscribe(this._onKeyDown);
1446 this.keyPressEvent.subscribe(this._onKeyPress);
1448 Module.textResizeEvent.subscribe(this._onTextResize, this, true);
1451 if (p_oConfig) {
1453 this.cfg.applyConfig(p_oConfig, true);
1458 // Register the Menu instance with the MenuManager
1460 MenuManager.addMenu(this);
1463 this.initEvent.fire(Menu);
1471 // Private methods
1475 * @method _initSubTree
1476 * @description Iterates the childNodes of the source element to find nodes
1477 * used to instantiate menu and menu items.
1478 * @private
1480 _initSubTree: function () {
1482 var oSrcElement = this.srcElement,
1483 sSrcElementTagName,
1484 nGroup,
1485 sGroupTitleTagName,
1486 oNode,
1487 aListElements,
1488 nListElements,
1492 if (oSrcElement) {
1494 sSrcElementTagName =
1495 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1498 if (sSrcElementTagName == "DIV") {
1500 // Populate the collection of item groups and item group titles
1502 oNode = this.body.firstChild;
1505 if (oNode) {
1507 nGroup = 0;
1508 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1510 do {
1513 if (oNode && oNode.tagName) {
1515 switch (oNode.tagName.toUpperCase()) {
1517 case sGroupTitleTagName:
1519 this._aGroupTitleElements[nGroup] = oNode;
1521 break;
1523 case "UL":
1525 this._aListElements[nGroup] = oNode;
1526 this._aItemGroups[nGroup] = [];
1527 nGroup++;
1529 break;
1536 while ((oNode = oNode.nextSibling));
1540 Apply the "first-of-type" class to the first UL to mimic
1541 the "first-of-type" CSS3 psuedo class.
1544 if (this._aListElements[0]) {
1546 Dom.addClass(this._aListElements[0], "first-of-type");
1555 oNode = null;
1559 if (sSrcElementTagName) {
1561 switch (sSrcElementTagName) {
1563 case "DIV":
1565 aListElements = this._aListElements;
1566 nListElements = aListElements.length;
1568 if (nListElements > 0) {
1571 i = nListElements - 1;
1573 do {
1575 oNode = aListElements[i].firstChild;
1577 if (oNode) {
1580 do {
1582 if (oNode && oNode.tagName &&
1583 oNode.tagName.toUpperCase() == "LI") {
1586 this.addItem(new this.ITEM_TYPE(oNode,
1587 { parent: this }), i);
1592 while ((oNode = oNode.nextSibling));
1597 while (i--);
1601 break;
1603 case "SELECT":
1606 oNode = oSrcElement.firstChild;
1608 do {
1610 if (oNode && oNode.tagName) {
1612 switch (oNode.tagName.toUpperCase()) {
1614 case "OPTGROUP":
1615 case "OPTION":
1618 this.addItem(
1619 new this.ITEM_TYPE(
1620 oNode,
1621 { parent: this }
1625 break;
1632 while ((oNode = oNode.nextSibling));
1634 break;
1646 * @method _getFirstEnabledItem
1647 * @description Returns the first enabled item in the menu.
1648 * @return {YAHOO.widget.MenuItem}
1649 * @private
1651 _getFirstEnabledItem: function () {
1653 var aItems = this.getItems(),
1654 nItems = aItems.length,
1655 oItem;
1657 for(var i=0; i<nItems; i++) {
1659 oItem = aItems[i];
1661 if (oItem && !oItem.cfg.getProperty("disabled") &&
1662 oItem.element.style.display != "none") {
1664 return oItem;
1674 * @method _addItemToGroup
1675 * @description Adds a menu item to a group.
1676 * @private
1677 * @param {Number} p_nGroupIndex Number indicating the group to which the
1678 * item belongs.
1679 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1680 * instance to be added to the menu.
1681 * @param {String} p_oItem String specifying the text of the item to be added
1682 * to the menu.
1683 * @param {Object} p_oItem Object literal containing a set of menu item
1684 * configuration properties.
1685 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1686 * which the menu item should be added.
1687 * @return {YAHOO.widget.MenuItem}
1689 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1691 var oItem,
1692 bDisabled = this.cfg.getProperty("disabled"),
1693 nGroupIndex,
1694 aGroup,
1695 oGroupItem,
1696 bAppend,
1697 oNextItemSibling,
1698 nItemIndex;
1700 function getNextItemSibling(p_aArray, p_nStartIndex) {
1702 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray,
1703 (p_nStartIndex+1)));
1707 if (p_oItem instanceof this.ITEM_TYPE) {
1709 oItem = p_oItem;
1710 oItem.parent = this;
1713 else if (typeof p_oItem == "string") {
1715 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1718 else if (typeof p_oItem == "object") {
1720 p_oItem.parent = this;
1722 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1727 if (oItem) {
1729 if (oItem.cfg.getProperty("selected")) {
1731 this.activeItem = oItem;
1736 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1737 aGroup = this._getItemGroup(nGroupIndex);
1741 if (!aGroup) {
1743 aGroup = this._createItemGroup(nGroupIndex);
1748 if (typeof p_nItemIndex == "number") {
1750 bAppend = (p_nItemIndex >= aGroup.length);
1753 if (aGroup[p_nItemIndex]) {
1755 aGroup.splice(p_nItemIndex, 0, oItem);
1758 else {
1760 aGroup[p_nItemIndex] = oItem;
1765 oGroupItem = aGroup[p_nItemIndex];
1767 if (oGroupItem) {
1769 if (bAppend && (!oGroupItem.element.parentNode ||
1770 oGroupItem.element.parentNode.nodeType == 11)) {
1772 this._aListElements[nGroupIndex].appendChild(
1773 oGroupItem.element);
1776 else {
1778 oNextItemSibling = getNextItemSibling(aGroup,
1779 (p_nItemIndex+1));
1781 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
1782 oGroupItem.element.parentNode.nodeType == 11)) {
1784 this._aListElements[nGroupIndex].insertBefore(
1785 oGroupItem.element,
1786 oNextItemSibling.element);
1793 oGroupItem.parent = this;
1795 this._subscribeToItemEvents(oGroupItem);
1797 this._configureSubmenu(oGroupItem);
1799 this._updateItemProperties(nGroupIndex);
1802 this.itemAddedEvent.fire(oGroupItem);
1803 this.changeContentEvent.fire();
1805 return oGroupItem;
1810 else {
1812 nItemIndex = aGroup.length;
1814 aGroup[nItemIndex] = oItem;
1816 oGroupItem = aGroup[nItemIndex];
1819 if (oGroupItem) {
1821 if (!Dom.isAncestor(this._aListElements[nGroupIndex],
1822 oGroupItem.element)) {
1824 this._aListElements[nGroupIndex].appendChild(
1825 oGroupItem.element);
1829 oGroupItem.element.setAttribute("groupindex", nGroupIndex);
1830 oGroupItem.element.setAttribute("index", nItemIndex);
1832 oGroupItem.parent = this;
1834 oGroupItem.index = nItemIndex;
1835 oGroupItem.groupIndex = nGroupIndex;
1837 this._subscribeToItemEvents(oGroupItem);
1839 this._configureSubmenu(oGroupItem);
1841 if (nItemIndex === 0) {
1843 Dom.addClass(oGroupItem.element, "first-of-type");
1849 this.itemAddedEvent.fire(oGroupItem);
1850 this.changeContentEvent.fire();
1852 return oGroupItem;
1864 * @method _removeItemFromGroupByIndex
1865 * @description Removes a menu item from a group by index. Returns the menu
1866 * item that was removed.
1867 * @private
1868 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
1869 * item belongs.
1870 * @param {Number} p_nItemIndex Number indicating the index of the menu item
1871 * to be removed.
1872 * @return {YAHOO.widget.MenuItem}
1874 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
1876 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0,
1877 aGroup = this._getItemGroup(nGroupIndex),
1878 aArray,
1879 oItem,
1880 oUL;
1882 if (aGroup) {
1884 aArray = aGroup.splice(p_nItemIndex, 1);
1885 oItem = aArray[0];
1887 if (oItem) {
1889 // Update the index and className properties of each member
1891 this._updateItemProperties(nGroupIndex);
1893 if (aGroup.length === 0) {
1895 // Remove the UL
1897 oUL = this._aListElements[nGroupIndex];
1899 if (this.body && oUL) {
1901 this.body.removeChild(oUL);
1905 // Remove the group from the array of items
1907 this._aItemGroups.splice(nGroupIndex, 1);
1910 // Remove the UL from the array of ULs
1912 this._aListElements.splice(nGroupIndex, 1);
1916 Assign the "first-of-type" class to the new first UL
1917 in the collection
1920 oUL = this._aListElements[0];
1922 if (oUL) {
1924 Dom.addClass(oUL, "first-of-type");
1931 this.itemRemovedEvent.fire(oItem);
1932 this.changeContentEvent.fire();
1935 // Return a reference to the item that was removed
1937 return oItem;
1947 * @method _removeItemFromGroupByValue
1948 * @description Removes a menu item from a group by reference. Returns the
1949 * menu item that was removed.
1950 * @private
1951 * @param {Number} p_nGroupIndex Number indicating the group to which the
1952 * menu item belongs.
1953 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1954 * instance to be removed.
1955 * @return {YAHOO.widget.MenuItem}
1957 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
1959 var aGroup = this._getItemGroup(p_nGroupIndex),
1960 nItems,
1961 nItemIndex,
1964 if (aGroup) {
1966 nItems = aGroup.length;
1967 nItemIndex = -1;
1969 if (nItems > 0) {
1971 i = nItems-1;
1973 do {
1975 if (aGroup[i] == p_oItem) {
1977 nItemIndex = i;
1978 break;
1983 while(i--);
1985 if (nItemIndex > -1) {
1987 return (this._removeItemFromGroupByIndex(p_nGroupIndex,
1988 nItemIndex));
2000 * @method _updateItemProperties
2001 * @description Updates the "index," "groupindex," and "className" properties
2002 * of the menu items in the specified group.
2003 * @private
2004 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2006 _updateItemProperties: function (p_nGroupIndex) {
2008 var aGroup = this._getItemGroup(p_nGroupIndex),
2009 nItems = aGroup.length,
2010 oItem,
2011 oLI,
2015 if (nItems > 0) {
2017 i = nItems - 1;
2019 // Update the index and className properties of each member
2021 do {
2023 oItem = aGroup[i];
2025 if (oItem) {
2027 oLI = oItem.element;
2029 oItem.index = i;
2030 oItem.groupIndex = p_nGroupIndex;
2032 oLI.setAttribute("groupindex", p_nGroupIndex);
2033 oLI.setAttribute("index", i);
2035 Dom.removeClass(oLI, "first-of-type");
2040 while(i--);
2043 if (oLI) {
2045 Dom.addClass(oLI, "first-of-type");
2055 * @method _createItemGroup
2056 * @description Creates a new menu item group (array) and its associated
2057 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2058 * @private
2059 * @param {Number} p_nIndex Number indicating the group to create.
2060 * @return {Array}
2062 _createItemGroup: function (p_nIndex) {
2064 var oUL;
2066 if (!this._aItemGroups[p_nIndex]) {
2068 this._aItemGroups[p_nIndex] = [];
2070 oUL = document.createElement("ul");
2072 this._aListElements[p_nIndex] = oUL;
2074 return this._aItemGroups[p_nIndex];
2082 * @method _getItemGroup
2083 * @description Returns the menu item group at the specified index.
2084 * @private
2085 * @param {Number} p_nIndex Number indicating the index of the menu item group
2086 * to be retrieved.
2087 * @return {Array}
2089 _getItemGroup: function (p_nIndex) {
2091 var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);
2093 return this._aItemGroups[nIndex];
2099 * @method _configureSubmenu
2100 * @description Subscribes the menu item's submenu to its parent menu's events.
2101 * @private
2102 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2103 * instance with the submenu to be configured.
2105 _configureSubmenu: function (p_oItem) {
2107 var oSubmenu = p_oItem.cfg.getProperty("submenu");
2109 if (oSubmenu) {
2112 Listen for configuration changes to the parent menu
2113 so they they can be applied to the submenu.
2116 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange,
2117 oSubmenu, true);
2119 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2121 oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow, null,
2122 oSubmenu);
2124 oSubmenu.showEvent.subscribe(this._onSubmenuShow, null, p_oItem);
2125 oSubmenu.hideEvent.subscribe(this._onSubmenuHide, null, p_oItem);
2133 * @method _subscribeToItemEvents
2134 * @description Subscribes a menu to a menu item's event.
2135 * @private
2136 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2137 * instance whose events should be subscribed to.
2139 _subscribeToItemEvents: function (p_oItem) {
2141 p_oItem.focusEvent.subscribe(this._onMenuItemFocus);
2143 p_oItem.blurEvent.subscribe(this._onMenuItemBlur);
2145 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,
2146 p_oItem, this);
2152 * @method _getOffsetWidth
2153 * @description Returns the offset width of the menu's
2154 * <code>&#60;div&#62;</code> element.
2155 * @private
2157 _getOffsetWidth: function () {
2159 var oClone = this.element.cloneNode(true);
2161 Dom.removeClass(oClone, "visible");
2163 Dom.setStyle(oClone, "width", "");
2165 document.body.appendChild(oClone);
2167 var sWidth = oClone.offsetWidth;
2169 document.body.removeChild(oClone);
2171 return sWidth;
2177 * @method _setWidth
2178 * @description Sets the width of the menu's root <code>&#60;div&#62;</code>
2179 * element to its offsetWidth.
2180 * @private
2182 _setWidth: function () {
2184 var oElement = this.element,
2185 bVisible = false,
2186 sWidth;
2188 if (oElement.parentNode.tagName.toUpperCase() == "BODY") {
2190 if (YAHOO.env.ua.opera) {
2192 sWidth = this._getOffsetWidth();
2195 else {
2197 if (Dom.hasClass(oElement, "visible")) {
2199 bVisible = true;
2201 Dom.removeClass(oElement, "visible");
2205 Dom.setStyle(oElement, "width", "auto");
2207 sWidth = oElement.offsetWidth;
2212 else {
2214 sWidth = this._getOffsetWidth();
2218 this.cfg.setProperty("width", (sWidth + "px"));
2221 if (bVisible) {
2223 Dom.addClass(oElement, "visible");
2231 * @method _onWidthChange
2232 * @description Change event handler for the the menu's "width" configuration
2233 * property.
2234 * @private
2235 * @param {String} p_sType String representing the name of the event that
2236 * was fired.
2237 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2239 _onWidthChange: function (p_sType, p_aArgs) {
2241 var sWidth = p_aArgs[0];
2243 if (sWidth && !this._hasSetWidthHandlers) {
2245 this.itemAddedEvent.subscribe(this._setWidth);
2246 this.itemRemovedEvent.subscribe(this._setWidth);
2248 this._hasSetWidthHandlers = true;
2251 else if (this._hasSetWidthHandlers) {
2253 this.itemAddedEvent.unsubscribe(this._setWidth);
2254 this.itemRemovedEvent.unsubscribe(this._setWidth);
2256 this._hasSetWidthHandlers = false;
2264 * @method _onVisibleChange
2265 * @description Change event handler for the the menu's "visible" configuration
2266 * property.
2267 * @private
2268 * @param {String} p_sType String representing the name of the event that
2269 * was fired.
2270 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2272 _onVisibleChange: function (p_sType, p_aArgs) {
2274 var bVisible = p_aArgs[0];
2276 if (bVisible) {
2278 Dom.addClass(this.element, "visible");
2281 else {
2283 Dom.removeClass(this.element, "visible");
2291 * @method _cancelHideDelay
2292 * @description Cancels the call to "hideMenu."
2293 * @private
2295 _cancelHideDelay: function () {
2297 var oRoot = this.getRoot();
2299 if (oRoot._nHideDelayId) {
2301 window.clearTimeout(oRoot._nHideDelayId);
2309 * @method _execHideDelay
2310 * @description Hides the menu after the number of milliseconds specified by
2311 * the "hidedelay" configuration property.
2312 * @private
2314 _execHideDelay: function () {
2316 this._cancelHideDelay();
2318 var oRoot = this.getRoot(),
2319 me = this;
2321 function hideMenu() {
2323 if (oRoot.activeItem) {
2325 oRoot.clearActiveItem();
2329 if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) &&
2330 me.cfg.getProperty("position") == "dynamic") {
2332 me.hide();
2339 oRoot._nHideDelayId =
2340 window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));
2346 * @method _cancelShowDelay
2347 * @description Cancels the call to the "showMenu."
2348 * @private
2350 _cancelShowDelay: function () {
2352 var oRoot = this.getRoot();
2354 if (oRoot._nShowDelayId) {
2356 window.clearTimeout(oRoot._nShowDelayId);
2364 * @method _execShowDelay
2365 * @description Shows the menu after the number of milliseconds specified by
2366 * the "showdelay" configuration property have ellapsed.
2367 * @private
2368 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should
2369 * be made visible.
2371 _execShowDelay: function (p_oMenu) {
2373 var oRoot = this.getRoot();
2375 function showMenu() {
2377 if (p_oMenu.parent.cfg.getProperty("selected")) {
2379 p_oMenu.show();
2386 oRoot._nShowDelayId =
2387 window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));
2393 * @method _execSubmenuHideDelay
2394 * @description Hides a submenu after the number of milliseconds specified by
2395 * the "submenuhidedelay" configuration property have ellapsed.
2396 * @private
2397 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2398 * should be hidden.
2399 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2400 * the specified submenu's parent menu item.
2401 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2402 * before the submenu is hidden.
2404 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2406 var me = this;
2408 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2410 if (me._nCurrentMouseX > (p_nMouseX + 10)) {
2412 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2414 p_oSubmenu.hide();
2416 }, p_nHideDelay);
2419 else {
2421 p_oSubmenu.hide();
2425 }, 50);
2431 // Protected methods
2435 * @method _disableScrollHeader
2436 * @description Disables the header used for scrolling the body of the menu.
2437 * @protected
2439 _disableScrollHeader: function () {
2441 if (!this._bHeaderDisabled) {
2443 Dom.addClass(this.header, "topscrollbar_disabled");
2444 this._bHeaderDisabled = true;
2452 * @method _disableScrollFooter
2453 * @description Disables the footer used for scrolling the body of the menu.
2454 * @protected
2456 _disableScrollFooter: function () {
2458 if (!this._bFooterDisabled) {
2460 Dom.addClass(this.footer, "bottomscrollbar_disabled");
2461 this._bFooterDisabled = true;
2469 * @method _enableScrollHeader
2470 * @description Enables the header used for scrolling the body of the menu.
2471 * @protected
2473 _enableScrollHeader: function () {
2475 if (this._bHeaderDisabled) {
2477 Dom.removeClass(this.header, "topscrollbar_disabled");
2478 this._bHeaderDisabled = false;
2486 * @method _enableScrollFooter
2487 * @description Enables the footer used for scrolling the body of the menu.
2488 * @protected
2490 _enableScrollFooter: function () {
2492 if (this._bFooterDisabled) {
2494 Dom.removeClass(this.footer, "bottomscrollbar_disabled");
2495 this._bFooterDisabled = false;
2503 * @method _onMouseOver
2504 * @description "mouseover" event handler for the menu.
2505 * @protected
2506 * @param {String} p_sType String representing the name of the event that
2507 * was fired.
2508 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2510 _onMouseOver: function (p_sType, p_aArgs) {
2512 if (this._bStopMouseEventHandlers) {
2514 return false;
2519 var oEvent = p_aArgs[0],
2520 oItem = p_aArgs[1],
2521 oTarget = Event.getTarget(oEvent),
2522 oParentMenu,
2523 nShowDelay,
2524 bShowDelay,
2525 oActiveItem,
2526 oItemCfg,
2527 oSubmenu;
2530 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2531 Dom.isAncestor(this.element, oTarget))) {
2533 // Menu mouseover logic
2535 this._nCurrentMouseX = 0;
2537 Event.on(this.element, "mousemove", this._onMouseMove, this, true);
2540 this.clearActiveItem();
2543 if (this.parent && this._nSubmenuHideDelayId) {
2545 window.clearTimeout(this._nSubmenuHideDelayId);
2547 this.parent.cfg.setProperty("selected", true);
2549 oParentMenu = this.parent.parent;
2551 oParentMenu._bHandledMouseOutEvent = true;
2552 oParentMenu._bHandledMouseOverEvent = false;
2557 this._bHandledMouseOverEvent = true;
2558 this._bHandledMouseOutEvent = false;
2563 if (oItem && !oItem.handledMouseOverEvent &&
2564 !oItem.cfg.getProperty("disabled") &&
2565 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2567 // Menu Item mouseover logic
2569 nShowDelay = this.cfg.getProperty("showdelay");
2570 bShowDelay = (nShowDelay > 0);
2573 if (bShowDelay) {
2575 this._cancelShowDelay();
2580 oActiveItem = this.activeItem;
2582 if (oActiveItem) {
2584 oActiveItem.cfg.setProperty("selected", false);
2589 oItemCfg = oItem.cfg;
2591 // Select and focus the current menu item
2593 oItemCfg.setProperty("selected", true);
2596 if (this.hasFocus()) {
2598 oItem.focus();
2603 if (this.cfg.getProperty("autosubmenudisplay")) {
2605 // Show the submenu this menu item
2607 oSubmenu = oItemCfg.getProperty("submenu");
2609 if (oSubmenu) {
2611 if (bShowDelay) {
2613 this._execShowDelay(oSubmenu);
2616 else {
2618 oSubmenu.show();
2626 oItem.handledMouseOverEvent = true;
2627 oItem.handledMouseOutEvent = false;
2635 * @method _onMouseOut
2636 * @description "mouseout" event handler for the menu.
2637 * @protected
2638 * @param {String} p_sType String representing the name of the event that
2639 * was fired.
2640 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2642 _onMouseOut: function (p_sType, p_aArgs) {
2644 if (this._bStopMouseEventHandlers) {
2646 return false;
2651 var oEvent = p_aArgs[0],
2652 oItem = p_aArgs[1],
2653 oRelatedTarget = Event.getRelatedTarget(oEvent),
2654 bMovingToSubmenu = false,
2655 oItemCfg,
2656 oSubmenu,
2657 nSubmenuHideDelay,
2658 nShowDelay;
2661 if (oItem && !oItem.cfg.getProperty("disabled")) {
2663 oItemCfg = oItem.cfg;
2664 oSubmenu = oItemCfg.getProperty("submenu");
2667 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2668 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2670 bMovingToSubmenu = true;
2675 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2676 !Dom.isAncestor(oItem.element, oRelatedTarget)) ||
2677 bMovingToSubmenu)) {
2679 // Menu Item mouseout logic
2681 if (!bMovingToSubmenu) {
2683 oItem.cfg.setProperty("selected", false);
2686 if (oSubmenu) {
2688 nSubmenuHideDelay =
2689 this.cfg.getProperty("submenuhidedelay");
2691 nShowDelay = this.cfg.getProperty("showdelay");
2693 if (!(this instanceof YAHOO.widget.MenuBar) &&
2694 nSubmenuHideDelay > 0 &&
2695 nShowDelay >= nSubmenuHideDelay) {
2697 this._execSubmenuHideDelay(oSubmenu,
2698 Event.getPageX(oEvent),
2699 nSubmenuHideDelay);
2702 else {
2704 oSubmenu.hide();
2713 oItem.handledMouseOutEvent = true;
2714 oItem.handledMouseOverEvent = false;
2721 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2722 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2724 // Menu mouseout logic
2726 Event.removeListener(this.element, "mousemove", this._onMouseMove);
2728 this._nCurrentMouseX = Event.getPageX(oEvent);
2730 this._bHandledMouseOutEvent = true;
2731 this._bHandledMouseOverEvent = false;
2739 * @method _onMouseMove
2740 * @description "click" event handler for the menu.
2741 * @protected
2742 * @param {Event} p_oEvent Object representing the DOM event object passed
2743 * back by the event utility (YAHOO.util.Event).
2744 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2745 * fired the event.
2747 _onMouseMove: function (p_oEvent, p_oMenu) {
2749 if (this._bStopMouseEventHandlers) {
2751 return false;
2755 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2761 * @method _onClick
2762 * @description "click" event handler for the menu.
2763 * @protected
2764 * @param {String} p_sType String representing the name of the event that
2765 * was fired.
2766 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2768 _onClick: function (p_sType, p_aArgs) {
2770 var oEvent = p_aArgs[0],
2771 oItem = p_aArgs[1],
2772 oTarget,
2773 oItemCfg,
2774 oSubmenu,
2775 sURL,
2776 oRoot;
2779 if (oItem && !oItem.cfg.getProperty("disabled")) {
2781 oTarget = Event.getTarget(oEvent);
2782 oItemCfg = oItem.cfg;
2783 oSubmenu = oItemCfg.getProperty("submenu");
2787 ACCESSIBILITY FEATURE FOR SCREEN READERS:
2788 Expand/collapse the submenu when the user clicks
2789 on the submenu indicator image.
2792 if (oTarget == oItem.submenuIndicator && oSubmenu) {
2794 if (oSubmenu.cfg.getProperty("visible")) {
2796 oSubmenu.hide();
2798 oSubmenu.parent.focus();
2801 else {
2803 this.clearActiveItem();
2805 oItemCfg.setProperty("selected", true);
2807 oSubmenu.show();
2809 oSubmenu.setInitialFocus();
2813 Event.preventDefault(oEvent);
2816 else {
2818 sURL = oItemCfg.getProperty("url");
2820 // Prevent the browser from following links equal to "#"
2822 if ((sURL.substr((sURL.length-1),1) == "#")) {
2824 Event.preventDefault(oEvent);
2826 oItem.focus();
2831 if (!oSubmenu) {
2833 oRoot = this.getRoot();
2835 if (oRoot instanceof YAHOO.widget.MenuBar ||
2836 oRoot.cfg.getProperty("position") == "static") {
2838 oRoot.clearActiveItem();
2841 else if (oRoot.cfg.getProperty("clicktohide")) {
2843 oRoot.hide();
2857 * @method _onKeyDown
2858 * @description "keydown" event handler for the menu.
2859 * @protected
2860 * @param {String} p_sType String representing the name of the event that
2861 * was fired.
2862 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2864 _onKeyDown: function (p_sType, p_aArgs) {
2866 var oEvent = p_aArgs[0],
2867 oItem = p_aArgs[1],
2868 me = this,
2869 oSubmenu,
2870 oItemCfg,
2871 oParentItem,
2872 oRoot,
2873 oNextItem,
2874 oBody,
2875 nBodyScrollTop,
2876 nBodyOffsetHeight,
2877 aItems,
2878 nItems,
2879 nNextItemOffsetTop,
2880 nScrollTarget,
2881 oParentMenu;
2885 This function is called to prevent a bug in Firefox. In Firefox,
2886 moving a DOM element into a stationary mouse pointer will cause the
2887 browser to fire mouse events. This can result in the menu mouse
2888 event handlers being called uncessarily, especially when menus are
2889 moved into a stationary mouse pointer as a result of a
2890 key event handler.
2892 function stopMouseEventHandlers() {
2894 me._bStopMouseEventHandlers = true;
2896 window.setTimeout(function () {
2898 me._bStopMouseEventHandlers = false;
2900 }, 10);
2905 if (oItem && !oItem.cfg.getProperty("disabled")) {
2907 oItemCfg = oItem.cfg;
2908 oParentItem = this.parent;
2910 switch(oEvent.keyCode) {
2912 case 38: // Up arrow
2913 case 40: // Down arrow
2915 oNextItem = (oEvent.keyCode == 38) ?
2916 oItem.getPreviousEnabledSibling() :
2917 oItem.getNextEnabledSibling();
2919 if (oNextItem) {
2921 this.clearActiveItem();
2923 oNextItem.cfg.setProperty("selected", true);
2924 oNextItem.focus();
2927 if (this.cfg.getProperty("maxheight") > 0) {
2929 oBody = this.body;
2930 nBodyScrollTop = oBody.scrollTop;
2931 nBodyOffsetHeight = oBody.offsetHeight;
2932 aItems = this.getItems();
2933 nItems = aItems.length - 1;
2934 nNextItemOffsetTop = oNextItem.element.offsetTop;
2937 if (oEvent.keyCode == 40 ) { // Down
2939 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
2941 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
2944 else if (nNextItemOffsetTop <= nBodyScrollTop) {
2946 oBody.scrollTop = 0;
2951 if (oNextItem == aItems[nItems]) {
2953 oBody.scrollTop = oNextItem.element.offsetTop;
2958 else { // Up
2960 if (nNextItemOffsetTop <= nBodyScrollTop) {
2962 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
2965 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
2967 oBody.scrollTop = nNextItemOffsetTop;
2972 if (oNextItem == aItems[0]) {
2974 oBody.scrollTop = 0;
2981 nBodyScrollTop = oBody.scrollTop;
2982 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
2984 if (nBodyScrollTop === 0) {
2986 this._disableScrollHeader();
2987 this._enableScrollFooter();
2990 else if (nBodyScrollTop == nScrollTarget) {
2992 this._enableScrollHeader();
2993 this._disableScrollFooter();
2996 else {
2998 this._enableScrollHeader();
2999 this._enableScrollFooter();
3008 Event.preventDefault(oEvent);
3010 stopMouseEventHandlers();
3012 break;
3015 case 39: // Right arrow
3017 oSubmenu = oItemCfg.getProperty("submenu");
3019 if (oSubmenu) {
3021 if (!oItemCfg.getProperty("selected")) {
3023 oItemCfg.setProperty("selected", true);
3027 oSubmenu.show();
3028 oSubmenu.setInitialFocus();
3029 oSubmenu.setInitialSelection();
3032 else {
3034 oRoot = this.getRoot();
3036 if (oRoot instanceof YAHOO.widget.MenuBar) {
3038 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3040 if (oNextItem) {
3042 oRoot.clearActiveItem();
3044 oNextItem.cfg.setProperty("selected", true);
3046 oSubmenu = oNextItem.cfg.getProperty("submenu");
3048 if (oSubmenu) {
3050 oSubmenu.show();
3054 oNextItem.focus();
3063 Event.preventDefault(oEvent);
3065 stopMouseEventHandlers();
3067 break;
3070 case 37: // Left arrow
3072 if (oParentItem) {
3074 oParentMenu = oParentItem.parent;
3076 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3078 oNextItem =
3079 oParentMenu.activeItem.getPreviousEnabledSibling();
3081 if (oNextItem) {
3083 oParentMenu.clearActiveItem();
3085 oNextItem.cfg.setProperty("selected", true);
3087 oSubmenu = oNextItem.cfg.getProperty("submenu");
3089 if (oSubmenu) {
3091 oSubmenu.show();
3095 oNextItem.focus();
3100 else {
3102 this.hide();
3104 oParentItem.focus();
3110 Event.preventDefault(oEvent);
3112 stopMouseEventHandlers();
3114 break;
3122 if (oEvent.keyCode == 27) { // Esc key
3124 if (this.cfg.getProperty("position") == "dynamic") {
3126 this.hide();
3128 if (this.parent) {
3130 this.parent.focus();
3135 else if (this.activeItem) {
3137 oSubmenu = this.activeItem.cfg.getProperty("submenu");
3139 if (oSubmenu && oSubmenu.cfg.getProperty("visible")) {
3141 oSubmenu.hide();
3142 this.activeItem.focus();
3145 else {
3147 this.activeItem.blur();
3148 this.activeItem.cfg.setProperty("selected", false);
3155 Event.preventDefault(oEvent);
3163 * @method _onKeyPress
3164 * @description "keypress" event handler for a Menu instance.
3165 * @protected
3166 * @param {String} p_sType The name of the event that was fired.
3167 * @param {Array} p_aArgs Collection of arguments sent when the event
3168 * was fired.
3170 _onKeyPress: function (p_sType, p_aArgs) {
3172 var oEvent = p_aArgs[0];
3175 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3177 Event.preventDefault(oEvent);
3185 * @method _onTextResize
3186 * @description "textresize" event handler for the menu.
3187 * @protected
3188 * @param {String} p_sType String representing the name of the event that
3189 * was fired.
3190 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3191 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3192 * fired the event.
3194 _onTextResize: function (p_sType, p_aArgs, p_oMenu) {
3196 if (YAHOO.env.ua.gecko && !this._handleResize) {
3198 this._handleResize = true;
3199 return;
3204 var oConfig = this.cfg;
3206 if (oConfig.getProperty("position") == "dynamic") {
3208 oConfig.setProperty("width", (this._getOffsetWidth() + "px"));
3216 * @method _onScrollTargetMouseOver
3217 * @description "mouseover" event handler for the menu's "header" and "footer"
3218 * elements. Used to scroll the body of the menu up and down when the
3219 * menu's "maxheight" configuration property is set to a value greater than 0.
3220 * @protected
3221 * @param {Event} p_oEvent Object representing the DOM event object passed
3222 * back by the event utility (YAHOO.util.Event).
3223 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3224 * fired the event.
3226 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3228 this._cancelHideDelay();
3230 var oTarget = Event.getTarget(p_oEvent),
3231 oBody = this.body,
3232 me = this,
3233 nScrollTarget,
3234 fnScrollFunction;
3237 function scrollBodyDown() {
3239 var nScrollTop = oBody.scrollTop;
3242 if (nScrollTop < nScrollTarget) {
3244 oBody.scrollTop = (nScrollTop + 1);
3246 me._enableScrollHeader();
3249 else {
3251 oBody.scrollTop = nScrollTarget;
3253 window.clearInterval(me._nBodyScrollId);
3255 me._disableScrollFooter();
3262 function scrollBodyUp() {
3264 var nScrollTop = oBody.scrollTop;
3267 if (nScrollTop > 0) {
3269 oBody.scrollTop = (nScrollTop - 1);
3271 me._enableScrollFooter();
3274 else {
3276 oBody.scrollTop = 0;
3278 window.clearInterval(me._nBodyScrollId);
3280 me._disableScrollHeader();
3287 if (Dom.hasClass(oTarget, "hd")) {
3289 fnScrollFunction = scrollBodyUp;
3292 else {
3294 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3296 fnScrollFunction = scrollBodyDown;
3301 this._nBodyScrollId = window.setInterval(fnScrollFunction, 10);
3307 * @method _onScrollTargetMouseOut
3308 * @description "mouseout" event handler for the menu's "header" and "footer"
3309 * elements. Used to stop scrolling the body of the menu up and down when the
3310 * menu's "maxheight" configuration property is set to a value greater than 0.
3311 * @protected
3312 * @param {Event} p_oEvent Object representing the DOM event object passed
3313 * back by the event utility (YAHOO.util.Event).
3314 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3315 * fired the event.
3317 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3319 window.clearInterval(this._nBodyScrollId);
3321 this._cancelHideDelay();
3327 // Private methods
3331 * @method _onInit
3332 * @description "init" event handler for the menu.
3333 * @private
3334 * @param {String} p_sType String representing the name of the event that
3335 * was fired.
3336 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3338 _onInit: function (p_sType, p_aArgs) {
3340 this.cfg.subscribeToConfigEvent("width", this._onWidthChange);
3341 this.cfg.subscribeToConfigEvent("visible", this._onVisibleChange);
3343 var bRootMenu = !this.parent,
3344 bLazyLoad = this.lazyLoad;
3348 Automatically initialize a menu's subtree if:
3350 1) This is the root menu and lazyload is off
3352 2) This is the root menu, lazyload is on, but the menu is
3353 already visible
3355 3) This menu is a submenu and lazyload is off
3360 if (((bRootMenu && !bLazyLoad) ||
3361 (bRootMenu && (this.cfg.getProperty("visible") ||
3362 this.cfg.getProperty("position") == "static")) ||
3363 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3365 if (this.srcElement) {
3367 this._initSubTree();
3372 if (this.itemData) {
3374 this.addItems(this.itemData);
3379 else if (bLazyLoad) {
3381 this.cfg.fireQueue();
3389 * @method _onBeforeRender
3390 * @description "beforerender" event handler for the menu. Appends all of the
3391 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
3392 * title elements to the body element of the menu.
3393 * @private
3394 * @param {String} p_sType String representing the name of the event that
3395 * was fired.
3396 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3398 _onBeforeRender: function (p_sType, p_aArgs) {
3400 var oConfig = this.cfg,
3401 oEl = this.element,
3402 nListElements = this._aListElements.length,
3403 bFirstList = true,
3404 i = 0,
3405 oUL,
3406 oGroupTitle;
3408 if (nListElements > 0) {
3410 do {
3412 oUL = this._aListElements[i];
3414 if (oUL) {
3416 if (bFirstList) {
3418 Dom.addClass(oUL, "first-of-type");
3419 bFirstList = false;
3424 if (!Dom.isAncestor(oEl, oUL)) {
3426 this.appendToBody(oUL);
3431 oGroupTitle = this._aGroupTitleElements[i];
3433 if (oGroupTitle) {
3435 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3437 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3442 Dom.addClass(oUL, "hastitle");
3448 i++;
3451 while(i < nListElements);
3459 * @method _onRender
3460 * @description "render" event handler for the menu.
3461 * @private
3462 * @param {String} p_sType String representing the name of the event that
3463 * was fired.
3464 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3466 _onRender: function (p_sType, p_aArgs) {
3468 if (this.cfg.getProperty("position") == "dynamic" &&
3469 !this.cfg.getProperty("width")) {
3471 this._setWidth();
3479 * @method _onBeforeShow
3480 * @description "beforeshow" event handler for the menu.
3481 * @private
3482 * @param {String} p_sType String representing the name of the event that
3483 * was fired.
3484 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3486 _onBeforeShow: function (p_sType, p_aArgs) {
3488 var nOptions,
3490 nViewportHeight,
3491 oRegion,
3492 nMaxHeight,
3493 oBody,
3494 oSrcElement;
3497 if (this.lazyLoad && this.getItemGroups().length === 0) {
3499 if (this.srcElement) {
3501 this._initSubTree();
3506 if (this.itemData) {
3508 if (this.parent && this.parent.parent &&
3509 this.parent.parent.srcElement &&
3510 this.parent.parent.srcElement.tagName.toUpperCase() ==
3511 "SELECT") {
3513 nOptions = this.itemData.length;
3515 for(n=0; n<nOptions; n++) {
3517 if (this.itemData[n].tagName) {
3519 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3526 else {
3528 this.addItems(this.itemData);
3535 oSrcElement = this.srcElement;
3537 if (oSrcElement) {
3539 if (oSrcElement.tagName.toUpperCase() == "SELECT") {
3541 if (Dom.inDocument(oSrcElement)) {
3543 this.render(oSrcElement.parentNode);
3546 else {
3548 this.render(this.cfg.getProperty("container"));
3553 else {
3555 this.render();
3560 else {
3562 if (this.parent) {
3564 this.render(this.parent.element);
3567 else {
3569 this.render(this.cfg.getProperty("container"));
3570 this.cfg.refireEvent("xy");
3579 if (!(this instanceof YAHOO.widget.MenuBar) &&
3580 this.cfg.getProperty("position") == "dynamic") {
3582 nViewportHeight = Dom.getViewportHeight();
3585 if (this.parent && this.parent.parent instanceof YAHOO.widget.MenuBar) {
3587 oRegion = YAHOO.util.Region.getRegion(this.parent.element);
3589 nViewportHeight = (nViewportHeight - oRegion.bottom);
3594 if (this.element.offsetHeight >= nViewportHeight) {
3596 nMaxHeight = this.cfg.getProperty("maxheight");
3599 Cache the original value for the "maxheight" configuration
3600 property so that we can set it back when the menu is hidden.
3603 this._nMaxHeight = nMaxHeight;
3605 this.cfg.setProperty("maxheight", (nViewportHeight - 20));
3610 if (this.cfg.getProperty("maxheight") > 0) {
3612 oBody = this.body;
3614 if (oBody.scrollTop > 0) {
3616 oBody.scrollTop = 0;
3620 this._disableScrollHeader();
3621 this._enableScrollFooter();
3632 * @method _onShow
3633 * @description "show" event handler for the menu.
3634 * @private
3635 * @param {String} p_sType String representing the name of the event that
3636 * was fired.
3637 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3639 _onShow: function (p_sType, p_aArgs) {
3641 var oParent = this.parent,
3642 oParentMenu,
3643 aParentAlignment,
3644 aAlignment;
3647 function disableAutoSubmenuDisplay(p_oEvent) {
3649 var oTarget;
3651 if (p_oEvent.type == "mousedown" || (p_oEvent.type == "keydown" &&
3652 p_oEvent.keyCode == 27)) {
3655 Set the "autosubmenudisplay" to "false" if the user
3656 clicks outside the menu bar.
3659 oTarget = Event.getTarget(p_oEvent);
3661 if (oTarget != oParentMenu.element ||
3662 !Dom.isAncestor(oParentMenu.element, oTarget)) {
3664 oParentMenu.cfg.setProperty("autosubmenudisplay", false);
3666 Event.removeListener(document, "mousedown",
3667 disableAutoSubmenuDisplay);
3669 Event.removeListener(document, "keydown",
3670 disableAutoSubmenuDisplay);
3679 if (oParent) {
3681 oParentMenu = oParent.parent;
3682 aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
3683 aAlignment = this.cfg.getProperty("submenualignment");
3686 if ((aParentAlignment[0] != aAlignment[0]) &&
3687 (aParentAlignment[1] != aAlignment[1])) {
3689 this.cfg.setProperty("submenualignment",
3690 [aParentAlignment[0], aParentAlignment[1]]);
3695 if (!oParentMenu.cfg.getProperty("autosubmenudisplay") &&
3696 (oParentMenu instanceof YAHOO.widget.MenuBar ||
3697 oParentMenu.cfg.getProperty("position") == "static")) {
3699 oParentMenu.cfg.setProperty("autosubmenudisplay", true);
3701 Event.on(document, "mousedown", disableAutoSubmenuDisplay);
3702 Event.on(document, "keydown", disableAutoSubmenuDisplay);
3712 * @method _onBeforeHide
3713 * @description "beforehide" event handler for the menu.
3714 * @private
3715 * @param {String} p_sType String representing the name of the event that
3716 * was fired.
3717 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3719 _onBeforeHide: function (p_sType, p_aArgs) {
3721 var oActiveItem = this.activeItem,
3722 oConfig,
3723 oSubmenu;
3725 if (oActiveItem) {
3727 oConfig = oActiveItem.cfg;
3729 oConfig.setProperty("selected", false);
3731 oSubmenu = oConfig.getProperty("submenu");
3733 if (oSubmenu) {
3735 oSubmenu.hide();
3741 if (this.getRoot() == this) {
3743 this.blur();
3751 * @method _onHide
3752 * @description "hide" event handler for the menu.
3753 * @private
3754 * @param {String} p_sType String representing the name of the event that
3755 * was fired.
3756 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3758 _onHide: function (p_sType, p_aArgs) {
3760 if (this._nMaxHeight != -1) {
3762 this.cfg.setProperty("maxheight", this._nMaxHeight);
3764 this._nMaxHeight = -1;
3772 * @method _onParentMenuConfigChange
3773 * @description "configchange" event handler for a submenu.
3774 * @private
3775 * @param {String} p_sType String representing the name of the event that
3776 * was fired.
3777 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3778 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3779 * subscribed to the event.
3781 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
3783 var sPropertyName = p_aArgs[0][0],
3784 oPropertyValue = p_aArgs[0][1];
3786 switch(sPropertyName) {
3788 case "iframe":
3789 case "constraintoviewport":
3790 case "hidedelay":
3791 case "showdelay":
3792 case "submenuhidedelay":
3793 case "clicktohide":
3794 case "effect":
3795 case "classname":
3797 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
3799 break;
3807 * @method _onParentMenuRender
3808 * @description "render" event handler for a submenu. Renders a
3809 * submenu in response to the firing of its parent's "render" event.
3810 * @private
3811 * @param {String} p_sType String representing the name of the event that
3812 * was fired.
3813 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3814 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3815 * subscribed to the event.
3817 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
3819 var oParentMenu = p_oSubmenu.parent.parent,
3821 oConfig = {
3823 constraintoviewport:
3824 oParentMenu.cfg.getProperty("constraintoviewport"),
3826 xy: [0,0],
3828 clicktohide: oParentMenu.cfg.getProperty("clicktohide"),
3830 effect: oParentMenu.cfg.getProperty("effect"),
3832 showdelay: oParentMenu.cfg.getProperty("showdelay"),
3834 hidedelay: oParentMenu.cfg.getProperty("hidedelay"),
3836 submenuhidedelay: oParentMenu.cfg.getProperty("submenuhidedelay"),
3838 classname: oParentMenu.cfg.getProperty("classname")
3842 oLI;
3846 Only sync the "iframe" configuration property if the parent
3847 menu's "position" configuration is the same.
3850 if (this.cfg.getProperty("position") ==
3851 oParentMenu.cfg.getProperty("position")) {
3853 oConfig.iframe = oParentMenu.cfg.getProperty("iframe");
3858 p_oSubmenu.cfg.applyConfig(oConfig);
3861 if (!this.lazyLoad) {
3863 oLI = this.parent.element;
3865 if (this.element.parentNode == oLI) {
3867 this.render();
3870 else {
3872 this.render(oLI);
3882 * @method _onSubmenuBeforeShow
3883 * @description "beforeshow" event handler for a submenu.
3884 * @private
3885 * @param {String} p_sType String representing the name of the event that
3886 * was fired.
3887 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3889 _onSubmenuBeforeShow: function (p_sType, p_aArgs) {
3891 var oParent = this.parent,
3892 aAlignment = oParent.parent.cfg.getProperty("submenualignment");
3894 this.cfg.setProperty("context",
3895 [oParent.element, aAlignment[0], aAlignment[1]]);
3898 var nScrollTop = oParent.parent.body.scrollTop;
3900 if ((YAHOO.env.ua.gecko || YAHOO.env.ua.webkit) && nScrollTop > 0) {
3902 this.cfg.setProperty("y", (this.cfg.getProperty("y") - nScrollTop));
3910 * @method _onSubmenuShow
3911 * @description "show" event handler for a submenu.
3912 * @private
3913 * @param {String} p_sType String representing the name of the event that
3914 * was fired.
3915 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3917 _onSubmenuShow: function (p_sType, p_aArgs) {
3919 this.submenuIndicator.innerHTML = this.EXPANDED_SUBMENU_INDICATOR_TEXT;
3925 * @method _onSubmenuHide
3926 * @description "hide" Custom Event handler for a submenu.
3927 * @private
3928 * @param {String} p_sType String representing the name of the event that
3929 * was fired.
3930 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3932 _onSubmenuHide: function (p_sType, p_aArgs) {
3934 this.submenuIndicator.innerHTML = this.COLLAPSED_SUBMENU_INDICATOR_TEXT;
3940 * @method _onMenuItemFocus
3941 * @description "focus" event handler for the menu's items.
3942 * @private
3943 * @param {String} p_sType String representing the name of the event that
3944 * was fired.
3945 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3947 _onMenuItemFocus: function (p_sType, p_aArgs) {
3949 this.parent.focusEvent.fire(this);
3955 * @method _onMenuItemBlur
3956 * @description "blur" event handler for the menu's items.
3957 * @private
3958 * @param {String} p_sType String representing the name of the event
3959 * that was fired.
3960 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3962 _onMenuItemBlur: function (p_sType, p_aArgs) {
3964 this.parent.blurEvent.fire(this);
3970 * @method _onMenuItemConfigChange
3971 * @description "configchange" event handler for the menu's items.
3972 * @private
3973 * @param {String} p_sType String representing the name of the event that
3974 * was fired.
3975 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3976 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
3977 * that fired the event.
3979 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
3981 var sPropertyName = p_aArgs[0][0],
3982 oPropertyValue = p_aArgs[0][1],
3983 sWidth,
3984 oSubmenu;
3986 switch(sPropertyName) {
3988 case "selected":
3990 if (oPropertyValue === true) {
3992 this.activeItem = p_oItem;
3996 break;
3998 case "submenu":
4000 oSubmenu = p_aArgs[0][1];
4002 if (oSubmenu) {
4004 this._configureSubmenu(p_oItem);
4008 break;
4010 case "text":
4011 case "helptext":
4014 A change to an item's "text" or "helptext"
4015 configuration properties requires the width of the parent
4016 menu to be recalculated.
4019 if (this.element.style.width) {
4021 sWidth = this._getOffsetWidth() + "px";
4023 Dom.setStyle(this.element, "width", sWidth);
4027 break;
4035 // Public event handlers for configuration properties
4039 * @method enforceConstraints
4040 * @description The default event handler executed when the moveEvent is fired,
4041 * if the "constraintoviewport" configuration property is set to true.
4042 * @param {String} type The name of the event that was fired.
4043 * @param {Array} args Collection of arguments sent when the
4044 * event was fired.
4045 * @param {Array} obj Array containing the current Menu instance
4046 * and the item that fired the event.
4048 enforceConstraints: function (type, args, obj) {
4050 var oParentMenuItem = this.parent,
4051 oElement,
4052 oConfig,
4053 pos,
4056 offsetHeight,
4057 offsetWidth,
4058 viewPortWidth,
4059 viewPortHeight,
4060 scrollX,
4061 scrollY,
4062 nPadding,
4063 topConstraint,
4064 leftConstraint,
4065 bottomConstraint,
4066 rightConstraint,
4067 aContext,
4068 oContextElement;
4071 if (oParentMenuItem &&
4072 !(oParentMenuItem.parent instanceof YAHOO.widget.MenuBar)) {
4074 oElement = this.element;
4076 oConfig = this.cfg;
4077 pos = args[0];
4079 x = pos[0];
4080 y = pos[1];
4082 offsetHeight = oElement.offsetHeight;
4083 offsetWidth = oElement.offsetWidth;
4085 viewPortWidth = Dom.getViewportWidth();
4086 viewPortHeight = Dom.getViewportHeight();
4088 scrollX = Dom.getDocumentScrollLeft();
4089 scrollY = Dom.getDocumentScrollTop();
4091 nPadding =
4092 (oParentMenuItem.parent instanceof YAHOO.widget.MenuBar) ? 0 : 10;
4094 topConstraint = scrollY + nPadding;
4095 leftConstraint = scrollX + nPadding;
4097 bottomConstraint = scrollY + viewPortHeight - offsetHeight - nPadding;
4098 rightConstraint = scrollX + viewPortWidth - offsetWidth - nPadding;
4100 aContext = oConfig.getProperty("context");
4101 oContextElement = aContext ? aContext[0] : null;
4104 if (x < 10) {
4106 x = leftConstraint;
4108 } else if ((x + offsetWidth) > viewPortWidth) {
4110 if (oContextElement &&
4111 ((x - oContextElement.offsetWidth) > offsetWidth)) {
4113 x = (x - (oContextElement.offsetWidth + offsetWidth));
4116 else {
4118 x = rightConstraint;
4124 if (y < 10) {
4126 y = topConstraint;
4128 } else if (y > bottomConstraint) {
4130 if (oContextElement && (y > offsetHeight)) {
4132 y = ((y + oContextElement.offsetHeight) - offsetHeight);
4135 else {
4137 y = bottomConstraint;
4143 oConfig.setProperty("x", x, true);
4144 oConfig.setProperty("y", y, true);
4145 oConfig.setProperty("xy", [x,y], true);
4148 else if (this == this.getRoot() &&
4149 this.cfg.getProperty("position") == "dynamic") {
4151 Menu.superclass.enforceConstraints.call(this, type, args, obj);
4159 * @method configVisible
4160 * @description Event handler for when the "visible" configuration property
4161 * the menu changes.
4162 * @param {String} p_sType String representing the name of the event that
4163 * was fired.
4164 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4165 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4166 * fired the event.
4168 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4170 var bVisible,
4171 sDisplay;
4173 if (this.cfg.getProperty("position") == "dynamic") {
4175 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4178 else {
4180 bVisible = p_aArgs[0];
4181 sDisplay = Dom.getStyle(this.element, "display");
4183 if (bVisible) {
4185 if (sDisplay != "block") {
4186 this.beforeShowEvent.fire();
4187 Dom.setStyle(this.element, "display", "block");
4188 this.showEvent.fire();
4192 else {
4194 if (sDisplay == "block") {
4195 this.beforeHideEvent.fire();
4196 Dom.setStyle(this.element, "display", "none");
4197 this.hideEvent.fire();
4208 * @method configPosition
4209 * @description Event handler for when the "position" configuration property
4210 * of the menu changes.
4211 * @param {String} p_sType String representing the name of the event that
4212 * was fired.
4213 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4214 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4215 * fired the event.
4217 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4219 var oElement = this.element,
4220 sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute",
4221 sCurrentPosition = Dom.getStyle(oElement, "position"),
4222 oCfg = this.cfg,
4223 nZIndex;
4226 Dom.setStyle(this.element, "position", sCSSPosition);
4229 if (sCSSPosition == "static") {
4232 Remove the iframe for statically positioned menus since it will
4233 intercept mouse events.
4236 oCfg.setProperty("iframe", false);
4239 // Statically positioned menus are visible by default
4241 Dom.setStyle(this.element, "display", "block");
4243 oCfg.setProperty("visible", true);
4246 else {
4248 if (sCurrentPosition != "absolute") {
4250 oCfg.setProperty("iframe", (YAHOO.env.ua.ie == 6 ? true : false));
4255 Even though the "visible" property is queued to
4256 "false" by default, we need to set the "visibility" property to
4257 "hidden" since Overlay's "configVisible" implementation checks the
4258 element's "visibility" style property before deciding whether
4259 or not to show an Overlay instance.
4262 Dom.setStyle(this.element, "visibility", "hidden");
4267 if (sCSSPosition == "absolute") {
4269 nZIndex = oCfg.getProperty("zindex");
4271 if (!nZIndex || nZIndex === 0) {
4273 nZIndex = this.parent ?
4274 (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;
4276 oCfg.setProperty("zindex", nZIndex);
4286 * @method configIframe
4287 * @description Event handler for when the "iframe" configuration property of
4288 * the menu changes.
4289 * @param {String} p_sType String representing the name of the event that
4290 * was fired.
4291 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4292 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4293 * fired the event.
4295 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4297 if (this.cfg.getProperty("position") == "dynamic") {
4299 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4307 * @method configHideDelay
4308 * @description Event handler for when the "hidedelay" configuration property
4309 * of the menu changes.
4310 * @param {String} p_sType String representing the name of the event that
4311 * was fired.
4312 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4313 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4314 * fired the event.
4316 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4318 var nHideDelay = p_aArgs[0],
4319 oMouseOutEvent = this.mouseOutEvent,
4320 oMouseOverEvent = this.mouseOverEvent,
4321 oKeyDownEvent = this.keyDownEvent;
4323 if (nHideDelay > 0) {
4326 Only assign event handlers once. This way the user change
4327 the value for the hidedelay as many times as they want.
4330 if (!this._bHideDelayEventHandlersAssigned) {
4332 oMouseOutEvent.subscribe(this._execHideDelay);
4333 oMouseOverEvent.subscribe(this._cancelHideDelay);
4334 oKeyDownEvent.subscribe(this._cancelHideDelay);
4336 this._bHideDelayEventHandlersAssigned = true;
4341 else {
4343 oMouseOutEvent.unsubscribe(this._execHideDelay);
4344 oMouseOverEvent.unsubscribe(this._cancelHideDelay);
4345 oKeyDownEvent.unsubscribe(this._cancelHideDelay);
4347 this._bHideDelayEventHandlersAssigned = false;
4355 * @method configContainer
4356 * @description Event handler for when the "container" configuration property
4357 of the menu changes.
4358 * @param {String} p_sType String representing the name of the event that
4359 * was fired.
4360 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4361 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4362 * fired the event.
4364 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4366 var oElement = p_aArgs[0];
4368 if (typeof oElement == 'string') {
4370 this.cfg.setProperty("container", document.getElementById(oElement),
4371 true);
4379 * @method _setMaxHeight
4380 * @description "renderEvent" handler used to defer the setting of the
4381 * "maxheight" configuration property until the menu is rendered in lazy
4382 * load scenarios.
4383 * @param {String} p_sType The name of the event that was fired.
4384 * @param {Array} p_aArgs Collection of arguments sent when the event
4385 * was fired.
4386 * @param {Number} p_nMaxHeight Number representing the value to set for the
4387 * "maxheight" configuration property.
4388 * @private
4390 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4392 this.cfg.setProperty("maxheight", p_nMaxHeight);
4393 this.renderEvent.unsubscribe(this._setMaxHeight);
4399 * @method configMaxHeight
4400 * @description Event handler for when the "maxheight" configuration property of
4401 * a Menu changes.
4402 * @param {String} p_sType The name of the event that was fired.
4403 * @param {Array} p_aArgs Collection of arguments sent when the event
4404 * was fired.
4405 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4406 * the event.
4408 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4410 var nMaxHeight = p_aArgs[0],
4411 oBody = this.body,
4412 oHeader = this.header,
4413 oFooter = this.footer,
4414 fnMouseOver = this._onScrollTargetMouseOver,
4415 fnMouseOut = this._onScrollTargetMouseOut,
4416 nHeight;
4419 if (this.lazyLoad && !oBody) {
4421 this.renderEvent.unsubscribe(this._setMaxHeight);
4423 if (nMaxHeight > 0) {
4425 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4429 return;
4433 Dom.setStyle(oBody, "height", "auto");
4434 Dom.setStyle(oBody, "overflow", "visible");
4437 if ((nMaxHeight > 0) && (oBody.offsetHeight > nMaxHeight)) {
4439 if (!this.cfg.getProperty("width")) {
4441 this._setWidth();
4445 if (!oHeader && !oFooter) {
4447 this.setHeader("&#32;");
4448 this.setFooter("&#32;");
4450 oHeader = this.header;
4451 oFooter = this.footer;
4453 Dom.addClass(oHeader, "topscrollbar");
4454 Dom.addClass(oFooter, "bottomscrollbar");
4456 this.element.insertBefore(oHeader, oBody);
4457 this.element.appendChild(oFooter);
4459 Event.on(oHeader, "mouseover", fnMouseOver, this, true);
4460 Event.on(oHeader, "mouseout", fnMouseOut, this, true);
4461 Event.on(oFooter, "mouseover", fnMouseOver, this, true);
4462 Event.on(oFooter, "mouseout", fnMouseOut, this, true);
4466 nHeight = (nMaxHeight - (this.footer.offsetHeight +
4467 this.header.offsetHeight));
4469 Dom.setStyle(oBody, "height", (nHeight + "px"));
4470 Dom.setStyle(oBody, "overflow", "hidden");
4473 else if (oHeader && oFooter) {
4475 Dom.setStyle(oBody, "height", "auto");
4476 Dom.setStyle(oBody, "overflow", "visible");
4478 Event.removeListener(oHeader, "mouseover", fnMouseOver);
4479 Event.removeListener(oHeader, "mouseout", fnMouseOut);
4480 Event.removeListener(oFooter, "mouseover", fnMouseOver);
4481 Event.removeListener(oFooter, "mouseout", fnMouseOut);
4483 this.element.removeChild(oHeader);
4484 this.element.removeChild(oFooter);
4486 this.header = null;
4487 this.footer = null;
4491 this.cfg.refireEvent("iframe");
4497 * @method configClassName
4498 * @description Event handler for when the "classname" configuration property of
4499 * a menu changes.
4500 * @param {String} p_sType The name of the event that was fired.
4501 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4502 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4504 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4506 var sClassName = p_aArgs[0];
4508 if (this._sClassName) {
4510 Dom.removeClass(this.element, this._sClassName);
4514 Dom.addClass(this.element, sClassName);
4515 this._sClassName = sClassName;
4521 * @method _onItemAdded
4522 * @description "itemadded" event handler for a Menu instance.
4523 * @private
4524 * @param {String} p_sType The name of the event that was fired.
4525 * @param {Array} p_aArgs Collection of arguments sent when the event
4526 * was fired.
4528 _onItemAdded: function (p_sType, p_aArgs) {
4530 var oItem = p_aArgs[0];
4532 if (oItem) {
4534 oItem.cfg.setProperty("disabled", true);
4542 * @method configDisabled
4543 * @description Event handler for when the "disabled" configuration property of
4544 * a menu changes.
4545 * @param {String} p_sType The name of the event that was fired.
4546 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4547 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4549 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4551 var bDisabled = p_aArgs[0],
4552 aItems,
4553 nItems,
4556 if (this._bDisabled != bDisabled) {
4558 aItems = this.getItems();
4559 nItems = aItems.length;
4561 if (nItems > 0) {
4563 i = nItems - 1;
4565 do {
4567 aItems[i].cfg.setProperty("disabled", bDisabled);
4570 while (i--);
4574 Dom[(bDisabled ? "addClass" : "removeClass")](this.element, "disabled");
4576 this.itemAddedEvent[(bDisabled ? "subscribe" : "unsubscribe")](
4577 this._onItemAdded);
4579 this._bDisabled = bDisabled;
4587 * @method onRender
4588 * @description "render" event handler for the menu.
4589 * @param {String} p_sType String representing the name of the event that
4590 * was fired.
4591 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4593 onRender: function (p_sType, p_aArgs) {
4595 function sizeShadow() {
4597 var oElement = this.element,
4598 oShadow = this._shadow;
4600 if (oShadow) {
4602 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
4603 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
4610 function addShadowVisibleClass() {
4612 Dom.addClass(this._shadow, "yui-menu-shadow-visible");
4617 function removeShadowVisibleClass() {
4619 Dom.removeClass(this._shadow, "yui-menu-shadow-visible");
4624 function createShadow() {
4626 var oShadow = this._shadow,
4627 oElement,
4630 if (!oShadow) {
4632 oElement = this.element;
4633 me = this;
4635 if (!m_oShadowTemplate) {
4637 m_oShadowTemplate = document.createElement("div");
4638 m_oShadowTemplate.className = "yui-menu-shadow";
4642 oShadow = m_oShadowTemplate.cloneNode(false);
4644 oElement.appendChild(oShadow);
4646 this._shadow = oShadow;
4648 addShadowVisibleClass.call(this);
4650 this.beforeShowEvent.subscribe(addShadowVisibleClass);
4651 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
4653 if (YAHOO.env.ua.ie) {
4656 Need to call sizeShadow & syncIframe via setTimeout for
4657 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
4658 or the shadow and iframe shim will not be sized and
4659 positioned properly.
4662 window.setTimeout(function () {
4664 sizeShadow.call(me);
4665 me.syncIframe();
4667 }, 0);
4669 this.cfg.subscribeToConfigEvent("width", sizeShadow);
4670 this.cfg.subscribeToConfigEvent("height", sizeShadow);
4671 this.changeContentEvent.subscribe(sizeShadow);
4673 Module.textResizeEvent.subscribe(sizeShadow, me, true);
4675 this.destroyEvent.subscribe(function () {
4677 Module.textResizeEvent.unsubscribe(sizeShadow, me);
4688 function onBeforeShow() {
4690 createShadow.call(this);
4692 this.beforeShowEvent.unsubscribe(onBeforeShow);
4697 if (this.cfg.getProperty("position") == "dynamic") {
4699 if (this.cfg.getProperty("visible")) {
4701 createShadow.call(this);
4704 else {
4706 this.beforeShowEvent.subscribe(onBeforeShow);
4715 // Public methods
4719 * @method initEvents
4720 * @description Initializes the custom events for the menu.
4722 initEvents: function () {
4724 Menu.superclass.initEvents.call(this);
4726 // Create custom events
4728 var SIGNATURE = CustomEvent.LIST;
4730 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
4731 this.mouseOverEvent.signature = SIGNATURE;
4733 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
4734 this.mouseOutEvent.signature = SIGNATURE;
4736 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
4737 this.mouseDownEvent.signature = SIGNATURE;
4739 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
4740 this.mouseUpEvent.signature = SIGNATURE;
4742 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
4743 this.clickEvent.signature = SIGNATURE;
4745 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
4746 this.keyPressEvent.signature = SIGNATURE;
4748 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
4749 this.keyDownEvent.signature = SIGNATURE;
4751 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
4752 this.keyUpEvent.signature = SIGNATURE;
4754 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
4755 this.focusEvent.signature = SIGNATURE;
4757 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
4758 this.blurEvent.signature = SIGNATURE;
4760 this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED);
4761 this.itemAddedEvent.signature = SIGNATURE;
4763 this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED);
4764 this.itemRemovedEvent.signature = SIGNATURE;
4770 * @method getRoot
4771 * @description Finds the menu's root menu.
4773 getRoot: function () {
4775 var oItem = this.parent,
4776 oParentMenu;
4778 if (oItem) {
4780 oParentMenu = oItem.parent;
4782 return oParentMenu ? oParentMenu.getRoot() : this;
4785 else {
4787 return this;
4795 * @method toString
4796 * @description Returns a string representing the menu.
4797 * @return {String}
4799 toString: function () {
4801 var sReturnVal = "Menu",
4802 sId = this.id;
4804 if (sId) {
4806 sReturnVal += (" " + sId);
4810 return sReturnVal;
4816 * @method setItemGroupTitle
4817 * @description Sets the title of a group of menu items.
4818 * @param {String} p_sGroupTitle String specifying the title of the group.
4819 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
4820 * the title belongs.
4822 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
4824 var nGroupIndex,
4825 oTitle,
4827 nFirstIndex;
4829 if (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {
4831 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
4832 oTitle = this._aGroupTitleElements[nGroupIndex];
4835 if (oTitle) {
4837 oTitle.innerHTML = p_sGroupTitle;
4840 else {
4842 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
4844 oTitle.innerHTML = p_sGroupTitle;
4846 this._aGroupTitleElements[nGroupIndex] = oTitle;
4851 i = this._aGroupTitleElements.length - 1;
4853 do {
4855 if (this._aGroupTitleElements[i]) {
4857 Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");
4859 nFirstIndex = i;
4864 while(i--);
4867 if (nFirstIndex !== null) {
4869 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
4870 "first-of-type");
4874 this.changeContentEvent.fire();
4883 * @method addItem
4884 * @description Appends an item to the menu.
4885 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4886 * instance to be added to the menu.
4887 * @param {String} p_oItem String specifying the text of the item to be added
4888 * to the menu.
4889 * @param {Object} p_oItem Object literal containing a set of menu item
4890 * configuration properties.
4891 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
4892 * which the item belongs.
4893 * @return {YAHOO.widget.MenuItem}
4895 addItem: function (p_oItem, p_nGroupIndex) {
4897 if (p_oItem) {
4899 return this._addItemToGroup(p_nGroupIndex, p_oItem);
4907 * @method addItems
4908 * @description Adds an array of items to the menu.
4909 * @param {Array} p_aItems Array of items to be added to the menu. The array
4910 * can contain strings specifying the text for each item to be created, object
4911 * literals specifying each of the menu item configuration properties,
4912 * or MenuItem instances.
4913 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
4914 * which the items belongs.
4915 * @return {Array}
4917 addItems: function (p_aItems, p_nGroupIndex) {
4919 var nItems,
4920 aItems,
4921 oItem,
4924 if (Lang.isArray(p_aItems)) {
4926 nItems = p_aItems.length;
4927 aItems = [];
4929 for(i=0; i<nItems; i++) {
4931 oItem = p_aItems[i];
4933 if (oItem) {
4935 if (Lang.isArray(oItem)) {
4937 aItems[aItems.length] = this.addItems(oItem, i);
4940 else {
4942 aItems[aItems.length] =
4943 this._addItemToGroup(p_nGroupIndex, oItem);
4952 if (aItems.length) {
4954 return aItems;
4964 * @method insertItem
4965 * @description Inserts an item into the menu at the specified index.
4966 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4967 * instance to be added to the menu.
4968 * @param {String} p_oItem String specifying the text of the item to be added
4969 * to the menu.
4970 * @param {Object} p_oItem Object literal containing a set of menu item
4971 * configuration properties.
4972 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
4973 * the item should be added.
4974 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
4975 * the item belongs.
4976 * @return {YAHOO.widget.MenuItem}
4978 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
4980 if (p_oItem) {
4982 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
4990 * @method removeItem
4991 * @description Removes the specified item from the menu.
4992 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
4993 * instance to be removed from the menu.
4994 * @param {Number} p_oObject Number specifying the index of the item
4995 * to be removed.
4996 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
4997 * which the item belongs.
4998 * @return {YAHOO.widget.MenuItem}
5000 removeItem: function (p_oObject, p_nGroupIndex) {
5002 var oItem;
5004 if (typeof p_oObject != "undefined") {
5006 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5008 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5011 else if (typeof p_oObject == "number") {
5013 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5017 if (oItem) {
5019 oItem.destroy();
5022 return oItem;
5032 * @method getItems
5033 * @description Returns an array of all of the items in the menu.
5034 * @return {Array}
5036 getItems: function () {
5038 var aGroups = this._aItemGroups,
5039 nGroups = aGroups.length;
5041 return ((nGroups == 1) ? aGroups[0] :
5042 (Array.prototype.concat.apply([], aGroups)));
5048 * @method getItemGroups
5049 * @description Multi-dimensional Array representing the menu items as they
5050 * are grouped in the menu.
5051 * @return {Array}
5053 getItemGroups: function () {
5055 return this._aItemGroups;
5061 * @method getItem
5062 * @description Returns the item at the specified index.
5063 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5064 * item to be retrieved.
5065 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5066 * the item belongs.
5067 * @return {YAHOO.widget.MenuItem}
5069 getItem: function (p_nItemIndex, p_nGroupIndex) {
5071 var aGroup;
5073 if (typeof p_nItemIndex == "number") {
5075 aGroup = this._getItemGroup(p_nGroupIndex);
5077 if (aGroup) {
5079 return aGroup[p_nItemIndex];
5089 * @method getSubmenus
5090 * @description Returns an array of all of the submenus that are immediate
5091 * children of the menu.
5092 * @return {Array}
5094 getSubmenus: function () {
5096 var aItems = this.getItems(),
5097 nItems = aItems.length,
5098 aSubmenus,
5099 oSubmenu,
5100 oItem,
5104 if (nItems > 0) {
5106 aSubmenus = [];
5108 for(i=0; i<nItems; i++) {
5110 oItem = aItems[i];
5112 if (oItem) {
5114 oSubmenu = oItem.cfg.getProperty("submenu");
5116 if (oSubmenu) {
5118 aSubmenus[aSubmenus.length] = oSubmenu;
5128 return aSubmenus;
5133 * @method clearContent
5134 * @description Removes all of the content from the menu, including the menu
5135 * items, group titles, header and footer.
5137 clearContent: function () {
5139 var aItems = this.getItems(),
5140 nItems = aItems.length,
5141 oElement = this.element,
5142 oBody = this.body,
5143 oHeader = this.header,
5144 oFooter = this.footer,
5145 oItem,
5146 oSubmenu,
5150 if (nItems > 0) {
5152 i = nItems - 1;
5154 do {
5156 oItem = aItems[i];
5158 if (oItem) {
5160 oSubmenu = oItem.cfg.getProperty("submenu");
5162 if (oSubmenu) {
5164 this.cfg.configChangedEvent.unsubscribe(
5165 this._onParentMenuConfigChange, oSubmenu);
5167 this.renderEvent.unsubscribe(this._onParentMenuRender,
5168 oSubmenu);
5172 this.removeItem(oItem);
5177 while(i--);
5182 if (oHeader) {
5184 Event.purgeElement(oHeader);
5185 oElement.removeChild(oHeader);
5190 if (oFooter) {
5192 Event.purgeElement(oFooter);
5193 oElement.removeChild(oFooter);
5197 if (oBody) {
5199 Event.purgeElement(oBody);
5201 oBody.innerHTML = "";
5206 this._aItemGroups = [];
5207 this._aListElements = [];
5208 this._aGroupTitleElements = [];
5210 this.cfg.setProperty("width", null);
5216 * @method destroy
5217 * @description Removes the menu's <code>&#60;div&#62;</code> element
5218 * (and accompanying child nodes) from the document.
5220 destroy: function () {
5222 Module.textResizeEvent.unsubscribe(this._onTextResize, this);
5225 // Remove all items
5227 this.clearContent();
5229 this._aItemGroups = null;
5230 this._aListElements = null;
5231 this._aGroupTitleElements = null;
5234 // Continue with the superclass implementation of this method
5236 Menu.superclass.destroy.call(this);
5243 * @method setInitialFocus
5244 * @description Sets focus to the menu's first enabled item.
5246 setInitialFocus: function () {
5248 var oItem = this._getFirstEnabledItem();
5250 if (oItem) {
5252 oItem.focus();
5260 * @method setInitialSelection
5261 * @description Sets the "selected" configuration property of the menu's first
5262 * enabled item to "true."
5264 setInitialSelection: function () {
5266 var oItem = this._getFirstEnabledItem();
5268 if (oItem) {
5270 oItem.cfg.setProperty("selected", true);
5277 * @method clearActiveItem
5278 * @description Sets the "selected" configuration property of the menu's active
5279 * item to "false" and hides the item's submenu.
5280 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5281 * should be blurred.
5283 clearActiveItem: function (p_bBlur) {
5285 if (this.cfg.getProperty("showdelay") > 0) {
5287 this._cancelShowDelay();
5292 var oActiveItem = this.activeItem,
5293 oConfig,
5294 oSubmenu;
5296 if (oActiveItem) {
5298 oConfig = oActiveItem.cfg;
5300 if (p_bBlur) {
5302 oActiveItem.blur();
5306 oConfig.setProperty("selected", false);
5308 oSubmenu = oConfig.getProperty("submenu");
5310 if (oSubmenu) {
5312 oSubmenu.hide();
5316 this.activeItem = null;
5324 * @method focus
5325 * @description Causes the menu to receive focus and fires the "focus" event.
5327 focus: function () {
5329 if (!this.hasFocus()) {
5331 this.setInitialFocus();
5339 * @method blur
5340 * @description Causes the menu to lose focus and fires the "blur" event.
5342 blur: function () {
5344 var oItem;
5346 if (this.hasFocus()) {
5348 oItem = MenuManager.getFocusedMenuItem();
5350 if (oItem) {
5352 oItem.blur();
5362 * @method hasFocus
5363 * @description Returns a boolean indicating whether or not the menu has focus.
5364 * @return {Boolean}
5366 hasFocus: function () {
5368 return (MenuManager.getFocusedMenu() == this.getRoot());
5374 * Adds the specified CustomEvent subscriber to the menu and each of
5375 * its submenus.
5376 * @method subscribe
5377 * @param p_type {string} the type, or name of the event
5378 * @param p_fn {function} the function to exectute when the event fires
5379 * @param p_obj {Object} An object to be passed along when the event
5380 * fires
5381 * @param p_override {boolean} If true, the obj passed in becomes the
5382 * execution scope of the listener
5384 subscribe: function () {
5386 function onItemAdded(p_sType, p_aArgs, p_oObject) {
5388 var oItem = p_aArgs[0],
5389 oSubmenu = oItem.cfg.getProperty("submenu");
5391 if (oSubmenu) {
5393 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5400 Menu.superclass.subscribe.apply(this, arguments);
5401 Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments);
5404 var aSubmenus = this.getSubmenus(),
5405 nSubmenus,
5406 oSubmenu,
5409 if (aSubmenus) {
5411 nSubmenus = aSubmenus.length;
5413 if (nSubmenus > 0) {
5415 i = nSubmenus - 1;
5417 do {
5419 oSubmenu = aSubmenus[i];
5421 oSubmenu.subscribe.apply(oSubmenu, arguments);
5424 while(i--);
5434 * @description Initializes the class's configurable properties which can be
5435 * changed using the menu's Config object ("cfg").
5436 * @method initDefaultConfig
5438 initDefaultConfig: function () {
5440 Menu.superclass.initDefaultConfig.call(this);
5442 var oConfig = this.cfg;
5444 // Add configuration attributes
5447 Change the default value for the "visible" configuration
5448 property to "false" by re-adding the property.
5452 * @config visible
5453 * @description Boolean indicating whether or not the menu is visible. If
5454 * the menu's "position" configuration property is set to "dynamic" (the
5455 * default), this property toggles the menu's <code>&#60;div&#62;</code>
5456 * element's "visibility" style property between "visible" (true) or
5457 * "hidden" (false). If the menu's "position" configuration property is
5458 * set to "static" this property toggles the menu's
5459 * <code>&#60;div&#62;</code> element's "display" style property
5460 * between "block" (true) or "none" (false).
5461 * @default false
5462 * @type Boolean
5464 oConfig.addProperty(
5465 DEFAULT_CONFIG.VISIBLE.key,
5467 handler: this.configVisible,
5468 value: DEFAULT_CONFIG.VISIBLE.value,
5469 validator: DEFAULT_CONFIG.VISIBLE.validator
5475 Change the default value for the "constraintoviewport" configuration
5476 property to "true" by re-adding the property.
5480 * @config constraintoviewport
5481 * @description Boolean indicating if the menu will try to remain inside
5482 * the boundaries of the size of viewport.
5483 * @default true
5484 * @type Boolean
5486 oConfig.addProperty(
5487 DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key,
5489 handler: this.configConstrainToViewport,
5490 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
5491 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
5492 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
5498 * @config position
5499 * @description String indicating how a menu should be positioned on the
5500 * screen. Possible values are "static" and "dynamic." Static menus are
5501 * visible by default and reside in the normal flow of the document
5502 * (CSS position: static). Dynamic menus are hidden by default, reside
5503 * out of the normal flow of the document (CSS position: absolute), and
5504 * can overlay other elements on the screen.
5505 * @default dynamic
5506 * @type String
5508 oConfig.addProperty(
5509 DEFAULT_CONFIG.POSITION.key,
5511 handler: this.configPosition,
5512 value: DEFAULT_CONFIG.POSITION.value,
5513 validator: DEFAULT_CONFIG.POSITION.validator,
5514 supercedes: DEFAULT_CONFIG.POSITION.supercedes
5520 * @config submenualignment
5521 * @description Array defining how submenus should be aligned to their
5522 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
5523 * a submenu's top left corner is aligned to its parent menu item's top
5524 * right corner.
5525 * @default ["tl","tr"]
5526 * @type Array
5528 oConfig.addProperty(
5529 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
5531 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value
5537 * @config autosubmenudisplay
5538 * @description Boolean indicating if submenus are automatically made
5539 * visible when the user mouses over the menu's items.
5540 * @default true
5541 * @type Boolean
5543 oConfig.addProperty(
5544 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
5546 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
5547 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator
5553 * @config showdelay
5554 * @description Number indicating the time (in milliseconds) that should
5555 * expire before a submenu is made visible when the user mouses over
5556 * the menu's items.
5557 * @default 250
5558 * @type Number
5560 oConfig.addProperty(
5561 DEFAULT_CONFIG.SHOW_DELAY.key,
5563 value: DEFAULT_CONFIG.SHOW_DELAY.value,
5564 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5570 * @config hidedelay
5571 * @description Number indicating the time (in milliseconds) that should
5572 * expire before the menu is hidden.
5573 * @default 0
5574 * @type Number
5576 oConfig.addProperty(
5577 DEFAULT_CONFIG.HIDE_DELAY.key,
5579 handler: this.configHideDelay,
5580 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5581 validator: DEFAULT_CONFIG.HIDE_DELAY.validator,
5582 suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.suppressEvent
5588 * @config submenuhidedelay
5589 * @description Number indicating the time (in milliseconds) that should
5590 * expire before a submenu is hidden when the user mouses out of a menu item
5591 * heading in the direction of a submenu. The value must be greater than or
5592 * equal to the value specified for the "showdelay" configuration property.
5593 * @default 250
5594 * @type Number
5596 oConfig.addProperty(
5597 DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key,
5599 value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value,
5600 validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator
5606 * @config clicktohide
5607 * @description Boolean indicating if the menu will automatically be
5608 * hidden if the user clicks outside of it.
5609 * @default true
5610 * @type Boolean
5612 oConfig.addProperty(
5613 DEFAULT_CONFIG.CLICK_TO_HIDE.key,
5615 value: DEFAULT_CONFIG.CLICK_TO_HIDE.value,
5616 validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator
5622 * @config container
5623 * @description HTML element reference or string specifying the id
5624 * attribute of the HTML element that the menu's markup should be
5625 * rendered into.
5626 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
5627 * level-one-html.html#ID-58190037">HTMLElement</a>|String
5628 * @default document.body
5630 oConfig.addProperty(
5631 DEFAULT_CONFIG.CONTAINER.key,
5633 handler: this.configContainer,
5634 value: document.body
5640 * @config maxheight
5641 * @description Defines the maximum height (in pixels) for a menu before the
5642 * contents of the body are scrolled.
5643 * @default 0
5644 * @type Number
5646 oConfig.addProperty(
5647 DEFAULT_CONFIG.MAX_HEIGHT.key,
5649 handler: this.configMaxHeight,
5650 value: DEFAULT_CONFIG.MAX_HEIGHT.value,
5651 validator: DEFAULT_CONFIG.MAX_HEIGHT.validator
5657 * @config classname
5658 * @description CSS class to be applied to the menu's root
5659 * <code>&#60;div&#62;</code> element. The specified class(es) are
5660 * appended in addition to the default class as specified by the menu's
5661 * CSS_CLASS_NAME constant.
5662 * @default null
5663 * @type String
5665 oConfig.addProperty(
5666 DEFAULT_CONFIG.CLASS_NAME.key,
5668 handler: this.configClassName,
5669 value: DEFAULT_CONFIG.CLASS_NAME.value,
5670 validator: DEFAULT_CONFIG.CLASS_NAME.validator
5676 * @config disabled
5677 * @description Boolean indicating if the menu should be disabled.
5678 * Disabling a menu disables each of its items. (Disabled menu items are
5679 * dimmed and will not respond to user input or fire events.) Disabled
5680 * menus have a corresponding "disabled" CSS class applied to their root
5681 * <code>&#60;div&#62;</code> element.
5682 * @default false
5683 * @type Boolean
5685 oConfig.addProperty(
5686 DEFAULT_CONFIG.DISABLED.key,
5688 handler: this.configDisabled,
5689 value: DEFAULT_CONFIG.DISABLED.value,
5690 validator: DEFAULT_CONFIG.DISABLED.validator
5696 }); // END YAHOO.lang.extend
5698 })();
5702 (function() {
5706 * Creates an item for a menu.
5708 * @param {String} p_oObject String specifying the text of the menu item.
5709 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5710 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
5711 * the <code>&#60;li&#62;</code> element of the menu item.
5712 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5713 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
5714 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
5715 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5716 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
5717 * specifying the <code>&#60;option&#62;</code> element of the menu item.
5718 * @param {Object} p_oConfig Optional. Object literal specifying the
5719 * configuration for the menu item. See configuration class documentation
5720 * for more details.
5721 * @class MenuItem
5722 * @constructor
5724 YAHOO.widget.MenuItem = function(p_oObject, p_oConfig) {
5726 if(p_oObject) {
5728 if(p_oConfig) {
5730 this.parent = p_oConfig.parent;
5731 this.value = p_oConfig.value;
5732 this.id = p_oConfig.id;
5736 this.init(p_oObject, p_oConfig);
5742 var Dom = YAHOO.util.Dom,
5743 Module = YAHOO.widget.Module,
5744 Menu = YAHOO.widget.Menu,
5745 MenuItem = YAHOO.widget.MenuItem,
5746 CustomEvent = YAHOO.util.CustomEvent,
5747 Lang = YAHOO.lang,
5749 m_oMenuItemTemplate,
5752 * Constant representing the name of the MenuItem's events
5753 * @property EVENT_TYPES
5754 * @private
5755 * @final
5756 * @type Object
5758 EVENT_TYPES = {
5760 "MOUSE_OVER": "mouseover",
5761 "MOUSE_OUT": "mouseout",
5762 "MOUSE_DOWN": "mousedown",
5763 "MOUSE_UP": "mouseup",
5764 "CLICK": "click",
5765 "KEY_PRESS": "keypress",
5766 "KEY_DOWN": "keydown",
5767 "KEY_UP": "keyup",
5768 "ITEM_ADDED": "itemAdded",
5769 "ITEM_REMOVED": "itemRemoved",
5770 "FOCUS": "focus",
5771 "BLUR": "blur",
5772 "DESTROY": "destroy"
5777 * Constant representing the MenuItem's configuration properties
5778 * @property DEFAULT_CONFIG
5779 * @private
5780 * @final
5781 * @type Object
5783 DEFAULT_CONFIG = {
5785 "TEXT": {
5786 key: "text",
5787 value: "",
5788 validator: Lang.isString,
5789 suppressEvent: true
5792 "HELP_TEXT": {
5793 key: "helptext",
5794 supercedes: ["text"]
5797 "URL": {
5798 key: "url",
5799 value: "#",
5800 suppressEvent: true
5803 "TARGET": {
5804 key: "target",
5805 suppressEvent: true
5808 "EMPHASIS": {
5809 key: "emphasis",
5810 value: false,
5811 validator: Lang.isBoolean,
5812 suppressEvent: true,
5813 supercedes: ["text"]
5816 "STRONG_EMPHASIS": {
5817 key: "strongemphasis",
5818 value: false,
5819 validator: Lang.isBoolean,
5820 suppressEvent: true,
5821 supercedes: ["text"]
5824 "CHECKED": {
5825 key: "checked",
5826 value: false,
5827 validator: Lang.isBoolean,
5828 suppressEvent: true,
5829 supercedes: ["text"]
5832 "DISABLED": {
5833 key: "disabled",
5834 value: false,
5835 validator: Lang.isBoolean,
5836 suppressEvent: true,
5837 supercedes: ["text"]
5840 "SELECTED": {
5841 key: "selected",
5842 value: false,
5843 validator: Lang.isBoolean,
5844 suppressEvent: true
5847 "SUBMENU": {
5848 key: "submenu",
5849 supercedes: ["text"]
5852 "ONCLICK": {
5853 key: "onclick"
5856 "CLASS_NAME": {
5857 key: "classname",
5858 value: null,
5859 validator: Lang.isString
5865 MenuItem.prototype = {
5867 // Constants
5870 * @property COLLAPSED_SUBMENU_INDICATOR_TEXT
5871 * @description String representing the text for the <code>&#60;em&#62;</code>
5872 * element used for the submenu arrow indicator.
5873 * @default "Submenu collapsed. Click to expand submenu."
5874 * @final
5875 * @type String
5877 COLLAPSED_SUBMENU_INDICATOR_TEXT:
5878 "Submenu collapsed. Click to expand submenu.",
5882 * @property EXPANDED_SUBMENU_INDICATOR_TEXT
5883 * @description String representing the text for the submenu arrow indicator
5884 * element (<code>&#60;em&#62;</code>) when the submenu is visible.
5885 * @default "Submenu expanded. Click to collapse submenu."
5886 * @final
5887 * @type String
5889 EXPANDED_SUBMENU_INDICATOR_TEXT:
5890 "Submenu expanded. Click to collapse submenu.",
5894 * @property DISABLED_SUBMENU_INDICATOR_TEXT
5895 * @description String representing the text for the submenu arrow indicator
5896 * element (<code>&#60;em&#62;</code>) when the menu item is disabled.
5897 * @default "Submenu collapsed. (Item disabled.)."
5898 * @final
5899 * @type String
5901 DISABLED_SUBMENU_INDICATOR_TEXT: "Submenu collapsed. (Item disabled.)",
5905 * @property CHECKED_TEXT
5906 * @description String representing the text to be used for the checked
5907 * indicator element (<code>&#60;em&#62;</code>).
5908 * @default "Checked."
5909 * @final
5910 * @type String
5912 CHECKED_TEXT: "Menu item checked.",
5916 * @property DISABLED_CHECKED_TEXT
5917 * @description String representing the text to be used for the checked
5918 * indicator element (<code>&#60;em&#62;</code>) when the menu item
5919 * is disabled.
5920 * @default "Checked. (Item disabled.)"
5921 * @final
5922 * @type String
5924 DISABLED_CHECKED_TEXT: "Checked. (Item disabled.)",
5928 * @property CSS_CLASS_NAME
5929 * @description String representing the CSS class(es) to be applied to the
5930 * <code>&#60;li&#62;</code> element of the menu item.
5931 * @default "yuimenuitem"
5932 * @final
5933 * @type String
5935 CSS_CLASS_NAME: "yuimenuitem",
5939 * @property CSS_LABEL_CLASS_NAME
5940 * @description String representing the CSS class(es) to be applied to the
5941 * menu item's <code>&#60;a&#62;</code> element.
5942 * @default "yuimenuitemlabel"
5943 * @final
5944 * @type String
5946 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
5950 * @property SUBMENU_TYPE
5951 * @description Object representing the type of menu to instantiate and
5952 * add when parsing the child nodes of the menu item's source HTML element.
5953 * @final
5954 * @type YAHOO.widget.Menu
5956 SUBMENU_TYPE: null,
5960 // Private member variables
5964 * @property _oAnchor
5965 * @description Object reference to the menu item's
5966 * <code>&#60;a&#62;</code> element.
5967 * @default null
5968 * @private
5969 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5970 * one-html.html#ID-48250443">HTMLAnchorElement</a>
5972 _oAnchor: null,
5976 * @property _oHelpTextEM
5977 * @description Object reference to the menu item's help text
5978 * <code>&#60;em&#62;</code> element.
5979 * @default null
5980 * @private
5981 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5982 * one-html.html#ID-58190037">HTMLElement</a>
5984 _oHelpTextEM: null,
5988 * @property _oSubmenu
5989 * @description Object reference to the menu item's submenu.
5990 * @default null
5991 * @private
5992 * @type YAHOO.widget.Menu
5994 _oSubmenu: null,
5998 * @property _oCheckedIndicator
5999 * @description Object reference to the menu item's checkmark image.
6000 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6001 * level-one-html.html#ID-58190037">HTMLElement</a>
6002 * @private
6003 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6004 * level-one-html.html#ID-58190037">HTMLElement</a>
6006 _oCheckedIndicator: null,
6009 /**
6010 * @property _oOnclickAttributeValue
6011 * @description Object reference to the menu item's current value for the
6012 * "onclick" configuration attribute.
6013 * @default null
6014 * @private
6015 * @type Object
6017 _oOnclickAttributeValue: null,
6021 * @property _sClassName
6022 * @description The current value of the "classname" configuration attribute.
6023 * @default null
6024 * @private
6025 * @type String
6027 _sClassName: null,
6031 // Public properties
6035 * @property constructor
6036 * @description Object reference to the menu item's constructor function.
6037 * @default YAHOO.widget.MenuItem
6038 * @type YAHOO.widget.MenuItem
6040 constructor: MenuItem,
6044 * @property index
6045 * @description Number indicating the ordinal position of the menu item in
6046 * its group.
6047 * @default null
6048 * @type Number
6050 index: null,
6054 * @property groupIndex
6055 * @description Number indicating the index of the group to which the menu
6056 * item belongs.
6057 * @default null
6058 * @type Number
6060 groupIndex: null,
6064 * @property parent
6065 * @description Object reference to the menu item's parent menu.
6066 * @default null
6067 * @type YAHOO.widget.Menu
6069 parent: null,
6073 * @property element
6074 * @description Object reference to the menu item's
6075 * <code>&#60;li&#62;</code> element.
6076 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6077 * -one-html.html#ID-74680021">HTMLLIElement</a>
6078 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6079 * one-html.html#ID-74680021">HTMLLIElement</a>
6081 element: null,
6085 * @property srcElement
6086 * @description Object reference to the HTML element (either
6087 * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
6088 * <code>&#60;option&#62;</code>) used create the menu item.
6089 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6090 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6091 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6092 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6093 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6094 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6095 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6096 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6097 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6098 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6100 srcElement: null,
6104 * @property value
6105 * @description Object reference to the menu item's value.
6106 * @default null
6107 * @type Object
6109 value: null,
6113 * @property submenuIndicator
6114 * @description Object reference to the <code>&#60;em&#62;</code> element
6115 * used to create the submenu indicator for the menu item.
6116 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6117 * level-one-html.html#ID-58190037">HTMLElement</a>
6118 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6119 * level-one-html.html#ID-58190037">HTMLElement</a>
6121 submenuIndicator: null,
6125 * @property browser
6126 * @deprecated Use YAHOO.env.ua
6127 * @description String representing the browser.
6128 * @type String
6130 browser: Module.prototype.browser,
6134 * @property id
6135 * @description Id of the menu item's root <code>&#60;li&#62;</code>
6136 * element. This property should be set via the constructor using the
6137 * configuration object literal. If an id is not specified, then one will
6138 * be created using the "generateId" method of the Dom utility.
6139 * @default null
6140 * @type String
6142 id: null,
6146 // Events
6150 * @event destroyEvent
6151 * @description Fires when the menu item's <code>&#60;li&#62;</code>
6152 * element is removed from its parent <code>&#60;ul&#62;</code> element.
6153 * @type YAHOO.util.CustomEvent
6155 destroyEvent: null,
6159 * @event mouseOverEvent
6160 * @description Fires when the mouse has entered the menu item. Passes
6161 * back the DOM Event object as an argument.
6162 * @type YAHOO.util.CustomEvent
6164 mouseOverEvent: null,
6168 * @event mouseOutEvent
6169 * @description Fires when the mouse has left the menu item. Passes back
6170 * the DOM Event object as an argument.
6171 * @type YAHOO.util.CustomEvent
6173 mouseOutEvent: null,
6177 * @event mouseDownEvent
6178 * @description Fires when the user mouses down on the menu item. Passes
6179 * back the DOM Event object as an argument.
6180 * @type YAHOO.util.CustomEvent
6182 mouseDownEvent: null,
6186 * @event mouseUpEvent
6187 * @description Fires when the user releases a mouse button while the mouse
6188 * is over the menu item. Passes back the DOM Event object as an argument.
6189 * @type YAHOO.util.CustomEvent
6191 mouseUpEvent: null,
6195 * @event clickEvent
6196 * @description Fires when the user clicks the on the menu item. Passes
6197 * back the DOM Event object as an argument.
6198 * @type YAHOO.util.CustomEvent
6200 clickEvent: null,
6204 * @event keyPressEvent
6205 * @description Fires when the user presses an alphanumeric key when the
6206 * menu item has focus. Passes back the DOM Event object as an argument.
6207 * @type YAHOO.util.CustomEvent
6209 keyPressEvent: null,
6213 * @event keyDownEvent
6214 * @description Fires when the user presses a key when the menu item has
6215 * focus. Passes back the DOM Event object as an argument.
6216 * @type YAHOO.util.CustomEvent
6218 keyDownEvent: null,
6222 * @event keyUpEvent
6223 * @description Fires when the user releases a key when the menu item has
6224 * focus. Passes back the DOM Event object as an argument.
6225 * @type YAHOO.util.CustomEvent
6227 keyUpEvent: null,
6231 * @event focusEvent
6232 * @description Fires when the menu item receives focus.
6233 * @type YAHOO.util.CustomEvent
6235 focusEvent: null,
6239 * @event blurEvent
6240 * @description Fires when the menu item loses the input focus.
6241 * @type YAHOO.util.CustomEvent
6243 blurEvent: null,
6247 * @method init
6248 * @description The MenuItem class's initialization method. This method is
6249 * automatically called by the constructor, and sets up all DOM references
6250 * for pre-existing markup, and creates required markup if it is not
6251 * already present.
6252 * @param {String} p_oObject String specifying the text of the menu item.
6253 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6254 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6255 * the <code>&#60;li&#62;</code> element of the menu item.
6256 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6257 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6258 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6259 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6260 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6261 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6262 * @param {Object} p_oConfig Optional. Object literal specifying the
6263 * configuration for the menu item. See configuration class documentation
6264 * for more details.
6266 init: function(p_oObject, p_oConfig) {
6269 if(!this.SUBMENU_TYPE) {
6271 this.SUBMENU_TYPE = Menu;
6276 // Create the config object
6278 this.cfg = new YAHOO.util.Config(this);
6280 this.initDefaultConfig();
6282 var SIGNATURE = CustomEvent.LIST,
6283 oConfig = this.cfg,
6284 sURL = "#",
6285 oAnchor,
6286 sTarget,
6287 sText,
6288 sId;
6291 if(Lang.isString(p_oObject)) {
6293 this._createRootNodeStructure();
6295 oConfig.queueProperty("text", p_oObject);
6298 else if(p_oObject && p_oObject.tagName) {
6300 switch(p_oObject.tagName.toUpperCase()) {
6302 case "OPTION":
6304 this._createRootNodeStructure();
6306 oConfig.queueProperty("text", p_oObject.text);
6308 this.srcElement = p_oObject;
6310 break;
6312 case "OPTGROUP":
6314 this._createRootNodeStructure();
6316 oConfig.queueProperty("text", p_oObject.label);
6318 this.srcElement = p_oObject;
6320 this._initSubTree();
6322 break;
6324 case "LI":
6326 // Get the anchor node (if it exists)
6328 oAnchor = Dom.getFirstChild(p_oObject);
6331 // Capture the "text" and/or the "URL"
6333 if(oAnchor) {
6335 sURL = oAnchor.getAttribute("href");
6336 sTarget = oAnchor.getAttribute("target");
6337 sText = oAnchor.innerHTML;
6341 this.srcElement = p_oObject;
6342 this.element = p_oObject;
6343 this._oAnchor = oAnchor;
6346 Set these properties silently to sync up the
6347 configuration object without making changes to the
6348 element's DOM
6351 oConfig.setProperty("text", sText, true);
6352 oConfig.setProperty("url", sURL, true);
6353 oConfig.setProperty("target", sTarget, true);
6355 this._initSubTree();
6357 break;
6364 if(this.element) {
6366 sId = this.element.id;
6368 if(!sId) {
6370 sId = this.id || Dom.generateId();
6372 this.element.id = sId;
6376 this.id = sId;
6379 Dom.addClass(this.element, this.CSS_CLASS_NAME);
6380 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
6383 // Create custom events
6385 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
6386 this.mouseOverEvent.signature = SIGNATURE;
6388 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
6389 this.mouseOutEvent.signature = SIGNATURE;
6391 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
6392 this.mouseDownEvent.signature = SIGNATURE;
6394 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
6395 this.mouseUpEvent.signature = SIGNATURE;
6397 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
6398 this.clickEvent.signature = SIGNATURE;
6400 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
6401 this.keyPressEvent.signature = SIGNATURE;
6403 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
6404 this.keyDownEvent.signature = SIGNATURE;
6406 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
6407 this.keyUpEvent.signature = SIGNATURE;
6409 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
6410 this.focusEvent.signature = SIGNATURE;
6412 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
6413 this.blurEvent.signature = SIGNATURE;
6415 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
6416 this.destroyEvent.signature = SIGNATURE;
6418 if(p_oConfig) {
6420 oConfig.applyConfig(p_oConfig);
6424 oConfig.fireQueue();
6432 // Private methods
6436 * @method _createRootNodeStructure
6437 * @description Creates the core DOM structure for the menu item.
6438 * @private
6440 _createRootNodeStructure: function () {
6442 var oElement,
6443 oAnchor;
6445 if(!m_oMenuItemTemplate) {
6447 m_oMenuItemTemplate = document.createElement("li");
6448 m_oMenuItemTemplate.innerHTML = "<a href=\"#\"></a>";
6452 oElement = m_oMenuItemTemplate.cloneNode(true);
6453 oElement.className = this.CSS_CLASS_NAME;
6455 oAnchor = oElement.firstChild;
6456 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
6458 this.element = oElement;
6459 this._oAnchor = oAnchor;
6465 * @method _initSubTree
6466 * @description Iterates the source element's childNodes collection and uses
6467 * the child nodes to instantiate other menus.
6468 * @private
6470 _initSubTree: function() {
6472 var oSrcEl = this.srcElement,
6473 oConfig = this.cfg,
6474 oNode,
6475 aOptions,
6476 nOptions,
6477 oMenu,
6481 if(oSrcEl.childNodes.length > 0) {
6483 if(this.parent.lazyLoad && this.parent.srcElement &&
6484 this.parent.srcElement.tagName.toUpperCase() == "SELECT") {
6486 oConfig.setProperty(
6487 "submenu",
6488 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
6492 else {
6494 oNode = oSrcEl.firstChild;
6495 aOptions = [];
6497 do {
6499 if(oNode && oNode.tagName) {
6501 switch(oNode.tagName.toUpperCase()) {
6503 case "DIV":
6505 oConfig.setProperty("submenu", oNode);
6507 break;
6509 case "OPTION":
6511 aOptions[aOptions.length] = oNode;
6513 break;
6520 while((oNode = oNode.nextSibling));
6523 nOptions = aOptions.length;
6525 if(nOptions > 0) {
6527 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
6529 oConfig.setProperty("submenu", oMenu);
6531 for(n=0; n<nOptions; n++) {
6533 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
6547 // Event handlers for configuration properties
6551 * @method configText
6552 * @description Event handler for when the "text" configuration property of
6553 * the menu item changes.
6554 * @param {String} p_sType String representing the name of the event that
6555 * was fired.
6556 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6557 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6558 * that fired the event.
6560 configText: function(p_sType, p_aArgs, p_oItem) {
6562 var sText = p_aArgs[0],
6563 oConfig = this.cfg,
6564 oAnchor = this._oAnchor,
6565 sHelpText = oConfig.getProperty("helptext"),
6566 sHelpTextHTML = "",
6567 sCheckHTML = "",
6568 oSubmenu = oConfig.getProperty("submenu"),
6569 sSubmenuIndicatorHTML = "",
6570 sEmphasisStartTag = "",
6571 sEmphasisEndTag = "";
6574 if (sText) {
6577 if (sHelpText) {
6579 sHelpTextHTML = "<em class=\"helptext\">" + sHelpText + "</em>";
6584 if (oConfig.getProperty("checked")) {
6586 sCheckHTML = "<em class=\"checkedindicator\">" +
6587 this.CHECKED_TEXT + "</em>";
6592 if (oSubmenu) {
6594 sSubmenuIndicatorHTML = "<em class=\"submenuindicator\">" +
6595 ((oSubmenu instanceof Menu &&
6596 oSubmenu.cfg.getProperty("visible")) ?
6597 this.EXPANDED_SUBMENU_INDICATOR_TEXT :
6598 this.COLLAPSED_SUBMENU_INDICATOR_TEXT) + "</em>";
6603 if (oConfig.getProperty("emphasis")) {
6605 sEmphasisStartTag = "<em>";
6606 sEmphasisEndTag = "</em>";
6611 if (oConfig.getProperty("strongemphasis")) {
6613 sEmphasisStartTag = "<strong>";
6614 sEmphasisEndTag = "</strong>";
6619 oAnchor.innerHTML = (sEmphasisStartTag + sText +
6620 sEmphasisEndTag + sHelpTextHTML +
6621 sCheckHTML + sSubmenuIndicatorHTML);
6624 if (oSubmenu) {
6626 this.submenuIndicator = oAnchor.lastChild;
6636 * @method configHelpText
6637 * @description Event handler for when the "helptext" configuration property
6638 * of the menu item changes.
6639 * @param {String} p_sType String representing the name of the event that
6640 * was fired.
6641 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6642 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6643 * that fired the event.
6645 configHelpText: function(p_sType, p_aArgs, p_oItem) {
6647 var sHelpText = p_aArgs[0],
6648 oAnchor = this._oAnchor;
6650 if (sHelpText) {
6652 Dom.addClass(oAnchor, "hashelptext");
6655 else {
6657 Dom.removeClass(oAnchor, "hashelptext");
6661 this.cfg.refireEvent("text");
6667 * @method configURL
6668 * @description Event handler for when the "url" configuration property of
6669 * the menu item changes.
6670 * @param {String} p_sType String representing the name of the event that
6671 * was fired.
6672 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6673 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6674 * that fired the event.
6676 configURL: function(p_sType, p_aArgs, p_oItem) {
6678 var sURL = p_aArgs[0];
6680 if(!sURL) {
6682 sURL = "#";
6686 this._oAnchor.setAttribute("href", sURL);
6692 * @method configTarget
6693 * @description Event handler for when the "target" configuration property
6694 * of the menu item changes.
6695 * @param {String} p_sType String representing the name of the event that
6696 * was fired.
6697 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6698 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6699 * that fired the event.
6701 configTarget: function(p_sType, p_aArgs, p_oItem) {
6703 var sTarget = p_aArgs[0],
6704 oAnchor = this._oAnchor;
6706 if(sTarget && sTarget.length > 0) {
6708 oAnchor.setAttribute("target", sTarget);
6711 else {
6713 oAnchor.removeAttribute("target");
6721 * @method configEmphasis
6722 * @description Event handler for when the "emphasis" configuration property
6723 * of the menu item changes.
6724 * @param {String} p_sType String representing the name of the event that
6725 * was fired.
6726 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6727 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6728 * that fired the event.
6730 configEmphasis: function(p_sType, p_aArgs, p_oItem) {
6732 var bEmphasis = p_aArgs[0],
6733 oConfig = this.cfg;
6736 if(bEmphasis && oConfig.getProperty("strongemphasis")) {
6738 oConfig.setProperty("strongemphasis", false);
6743 oConfig.refireEvent("text");
6749 * @method configStrongEmphasis
6750 * @description Event handler for when the "strongemphasis" configuration
6751 * property of the menu item changes.
6752 * @param {String} p_sType String representing the name of the event that
6753 * was fired.
6754 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6755 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6756 * that fired the event.
6758 configStrongEmphasis: function(p_sType, p_aArgs, p_oItem) {
6760 var bStrongEmphasis = p_aArgs[0],
6761 oConfig = this.cfg;
6764 if(bStrongEmphasis && oConfig.getProperty("emphasis")) {
6766 oConfig.setProperty("emphasis", false);
6770 oConfig.refireEvent("text");
6776 * @method configChecked
6777 * @description Event handler for when the "checked" configuration property
6778 * of the menu item changes.
6779 * @param {String} p_sType String representing the name of the event that
6780 * was fired.
6781 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6782 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6783 * that fired the event.
6785 configChecked: function(p_sType, p_aArgs, p_oItem) {
6787 var bChecked = p_aArgs[0],
6788 oAnchor = this._oAnchor;
6790 if (bChecked) {
6792 Dom.addClass(oAnchor, "checked");
6795 else {
6797 Dom.removeClass(oAnchor, "checked");
6801 this.cfg.refireEvent("text");
6808 * @method configDisabled
6809 * @description Event handler for when the "disabled" configuration property
6810 * of the menu item changes.
6811 * @param {String} p_sType String representing the name of the event that
6812 * was fired.
6813 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6814 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6815 * that fired the event.
6817 configDisabled: function(p_sType, p_aArgs, p_oItem) {
6819 var bDisabled = p_aArgs[0],
6820 oConfig = this.cfg,
6821 oAnchor = this._oAnchor;
6824 if(bDisabled) {
6826 if(oConfig.getProperty("selected")) {
6828 oConfig.setProperty("selected", false);
6832 oAnchor.removeAttribute("href");
6834 Dom.addClass(oAnchor, "disabled");
6837 else {
6839 oAnchor.setAttribute("href", oConfig.getProperty("url"));
6841 Dom.removeClass(oAnchor, "disabled");
6849 * @method configSelected
6850 * @description Event handler for when the "selected" configuration property
6851 * of the menu item changes.
6852 * @param {String} p_sType String representing the name of the event that
6853 * was fired.
6854 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6855 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6856 * that fired the event.
6858 configSelected: function(p_sType, p_aArgs, p_oItem) {
6860 var bSelected,
6861 oAnchor;
6863 if(!this.cfg.getProperty("disabled")) {
6865 bSelected = p_aArgs[0];
6866 oAnchor = this._oAnchor;
6869 if(bSelected) {
6871 Dom.addClass(oAnchor, "selected");
6874 else {
6876 Dom.removeClass(oAnchor, "selected");
6886 * @method configSubmenu
6887 * @description Event handler for when the "submenu" configuration property
6888 * of the menu item changes.
6889 * @param {String} p_sType String representing the name of the event that
6890 * was fired.
6891 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6892 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6893 * that fired the event.
6895 configSubmenu: function(p_sType, p_aArgs, p_oItem) {
6897 var oAnchor = this._oAnchor,
6898 oSubmenu = p_aArgs[0],
6899 oSubmenuIndicator = this.submenuIndicator,
6900 oConfig = this.cfg,
6901 bLazyLoad = this.parent && this.parent.lazyLoad,
6902 oMenu,
6903 sSubmenuId,
6904 oSubmenuConfig;
6907 if(oSubmenu) {
6909 if(oSubmenu instanceof Menu) {
6911 oMenu = oSubmenu;
6912 oMenu.parent = this;
6913 oMenu.lazyLoad = bLazyLoad;
6916 else if(typeof oSubmenu == "object" && oSubmenu.id &&
6917 !oSubmenu.nodeType) {
6919 sSubmenuId = oSubmenu.id;
6920 oSubmenuConfig = oSubmenu;
6922 oSubmenuConfig.lazyload = bLazyLoad;
6923 oSubmenuConfig.parent = this;
6925 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
6928 // Set the value of the property to the Menu instance
6930 this.cfg.setProperty("submenu", oMenu, true);
6933 else {
6935 oMenu = new this.SUBMENU_TYPE(oSubmenu,
6936 { lazyload: bLazyLoad, parent: this });
6939 // Set the value of the property to the Menu instance
6941 this.cfg.setProperty("submenu", oMenu, true);
6946 if(oMenu) {
6948 Dom.addClass(oAnchor, "hassubmenu");
6950 this._oSubmenu = oMenu;
6955 else {
6957 Dom.removeClass(oAnchor, "hassubmenu");
6959 if(oSubmenuIndicator) {
6961 oAnchor.removeChild(oSubmenuIndicator);
6965 if(this._oSubmenu) {
6967 this._oSubmenu.destroy();
6973 oConfig.refireEvent("text");
6979 * @method configOnClick
6980 * @description Event handler for when the "onclick" configuration property
6981 * of the menu item changes.
6982 * @param {String} p_sType String representing the name of the event that
6983 * was fired.
6984 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6985 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6986 * that fired the event.
6988 configOnClick: function(p_sType, p_aArgs, p_oItem) {
6990 var oObject = p_aArgs[0];
6993 Remove any existing listeners if a "click" event handler has
6994 already been specified.
6997 if(this._oOnclickAttributeValue &&
6998 (this._oOnclickAttributeValue != oObject)) {
7000 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7001 this._oOnclickAttributeValue.obj);
7003 this._oOnclickAttributeValue = null;
7008 if(!this._oOnclickAttributeValue && typeof oObject == "object" &&
7009 typeof oObject.fn == "function") {
7011 this.clickEvent.subscribe(oObject.fn,
7012 ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this),
7013 oObject.scope);
7015 this._oOnclickAttributeValue = oObject;
7023 * @method configClassName
7024 * @description Event handler for when the "classname" configuration
7025 * property of a menu item changes.
7026 * @param {String} p_sType String representing the name of the event that
7027 * was fired.
7028 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7029 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7030 * that fired the event.
7032 configClassName: function(p_sType, p_aArgs, p_oItem) {
7034 var sClassName = p_aArgs[0];
7036 if(this._sClassName) {
7038 Dom.removeClass(this.element, this._sClassName);
7042 Dom.addClass(this.element, sClassName);
7043 this._sClassName = sClassName;
7049 // Public methods
7053 * @method initDefaultConfig
7054 * @description Initializes an item's configurable properties.
7056 initDefaultConfig : function() {
7058 var oConfig = this.cfg;
7061 // Define the configuration attributes
7064 * @config text
7065 * @description String specifying the text label for the menu item.
7066 * When building a menu from existing HTML the value of this property
7067 * will be interpreted from the menu's markup.
7068 * @default ""
7069 * @type String
7071 oConfig.addProperty(
7072 DEFAULT_CONFIG.TEXT.key,
7074 handler: this.configText,
7075 value: DEFAULT_CONFIG.TEXT.value,
7076 validator: DEFAULT_CONFIG.TEXT.validator,
7077 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
7083 * @config helptext
7084 * @description String specifying additional instructional text to
7085 * accompany the text for the menu item.
7086 * @deprecated Use "text" configuration property to add help text markup.
7087 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em
7088 * class=\"helptext\"&#62;Ctrl + C&#60;/em&#60;");</code>
7089 * @default null
7090 * @type String|<a href="http://www.w3.org/TR/
7091 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7092 * HTMLElement</a>
7094 oConfig.addProperty(
7095 DEFAULT_CONFIG.HELP_TEXT.key,
7096 { handler: this.configHelpText }
7101 * @config url
7102 * @description String specifying the URL for the menu item's anchor's
7103 * "href" attribute. When building a menu from existing HTML the value
7104 * of this property will be interpreted from the menu's markup.
7105 * @default "#"
7106 * @type String
7108 oConfig.addProperty(
7109 DEFAULT_CONFIG.URL.key,
7111 handler: this.configURL,
7112 value: DEFAULT_CONFIG.URL.value,
7113 suppressEvent: DEFAULT_CONFIG.URL.suppressEvent
7119 * @config target
7120 * @description String specifying the value for the "target" attribute
7121 * of the menu item's anchor element. <strong>Specifying a target will
7122 * require the user to click directly on the menu item's anchor node in
7123 * order to cause the browser to navigate to the specified URL.</strong>
7124 * When building a menu from existing HTML the value of this property
7125 * will be interpreted from the menu's markup.
7126 * @default null
7127 * @type String
7129 oConfig.addProperty(
7130 DEFAULT_CONFIG.TARGET.key,
7132 handler: this.configTarget,
7133 suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent
7139 * @config emphasis
7140 * @description Boolean indicating if the text of the menu item will be
7141 * rendered with emphasis.
7142 * @deprecated Use "text" configuration property to add emphasis.
7143 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some
7144 * Text&#60;/em&#60;");</code>
7145 * @default false
7146 * @type Boolean
7148 oConfig.addProperty(
7149 DEFAULT_CONFIG.EMPHASIS.key,
7151 handler: this.configEmphasis,
7152 value: DEFAULT_CONFIG.EMPHASIS.value,
7153 validator: DEFAULT_CONFIG.EMPHASIS.validator,
7154 suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent
7160 * @config strongemphasis
7161 * @description Boolean indicating if the text of the menu item will be
7162 * rendered with strong emphasis.
7163 * @deprecated Use "text" configuration property to add strong emphasis.
7164 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62;
7165 * Some Text&#60;/strong&#60;");</code>
7166 * @default false
7167 * @type Boolean
7169 oConfig.addProperty(
7170 DEFAULT_CONFIG.STRONG_EMPHASIS.key,
7172 handler: this.configStrongEmphasis,
7173 value: DEFAULT_CONFIG.STRONG_EMPHASIS.value,
7174 validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator,
7175 suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent
7181 * @config checked
7182 * @description Boolean indicating if the menu item should be rendered
7183 * with a checkmark.
7184 * @default false
7185 * @type Boolean
7187 oConfig.addProperty(
7188 DEFAULT_CONFIG.CHECKED.key,
7190 handler: this.configChecked,
7191 value: DEFAULT_CONFIG.CHECKED.value,
7192 validator: DEFAULT_CONFIG.CHECKED.validator,
7193 suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent,
7194 supercedes: DEFAULT_CONFIG.CHECKED.supercedes
7200 * @config disabled
7201 * @description Boolean indicating if the menu item should be disabled.
7202 * (Disabled menu items are dimmed and will not respond to user input
7203 * or fire events.)
7204 * @default false
7205 * @type Boolean
7207 oConfig.addProperty(
7208 DEFAULT_CONFIG.DISABLED.key,
7210 handler: this.configDisabled,
7211 value: DEFAULT_CONFIG.DISABLED.value,
7212 validator: DEFAULT_CONFIG.DISABLED.validator,
7213 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
7219 * @config selected
7220 * @description Boolean indicating if the menu item should
7221 * be highlighted.
7222 * @default false
7223 * @type Boolean
7225 oConfig.addProperty(
7226 DEFAULT_CONFIG.SELECTED.key,
7228 handler: this.configSelected,
7229 value: DEFAULT_CONFIG.SELECTED.value,
7230 validator: DEFAULT_CONFIG.SELECTED.validator,
7231 suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent
7237 * @config submenu
7238 * @description Object specifying the submenu to be appended to the
7239 * menu item. The value can be one of the following: <ul><li>Object
7240 * specifying a Menu instance.</li><li>Object literal specifying the
7241 * menu to be created. Format: <code>{ id: [menu id], itemdata:
7242 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
7243 * items</a>] }</code>.</li><li>String specifying the id attribute
7244 * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
7245 * Object specifying the <code>&#60;div&#62;</code> element of the
7246 * menu.</li></ul>
7247 * @default null
7248 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
7249 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7250 * HTMLElement</a>
7252 oConfig.addProperty(
7253 DEFAULT_CONFIG.SUBMENU.key,
7254 { handler: this.configSubmenu }
7259 * @config onclick
7260 * @description Object literal representing the code to be executed when
7261 * the item is clicked. Format:<br> <code> {<br>
7262 * <strong>fn:</strong> Function, &#47;&#47; The handler to call when
7263 * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An
7264 * object to pass back to the handler.<br> <strong>scope:</strong>
7265 * Object &#47;&#47; The object to use for the scope of the handler.
7266 * <br> } </code>
7267 * @type Object
7268 * @default null
7270 oConfig.addProperty(
7271 DEFAULT_CONFIG.ONCLICK.key,
7272 { handler: this.configOnClick }
7277 * @config classname
7278 * @description CSS class to be applied to the menu item's root
7279 * <code>&#60;li&#62;</code> element. The specified class(es) are
7280 * appended in addition to the default class as specified by the menu
7281 * item's CSS_CLASS_NAME constant.
7282 * @default null
7283 * @type String
7285 oConfig.addProperty(
7286 DEFAULT_CONFIG.CLASS_NAME.key,
7288 handler: this.configClassName,
7289 value: DEFAULT_CONFIG.CLASS_NAME.value,
7290 validator: DEFAULT_CONFIG.CLASS_NAME.validator
7298 * @method getNextEnabledSibling
7299 * @description Finds the menu item's next enabled sibling.
7300 * @return YAHOO.widget.MenuItem
7302 getNextEnabledSibling: function() {
7304 var nGroupIndex,
7305 aItemGroups,
7306 oNextItem,
7307 nNextGroupIndex,
7308 aNextGroup;
7310 function getNextArrayItem(p_aArray, p_nStartIndex) {
7312 return p_aArray[p_nStartIndex] ||
7313 getNextArrayItem(p_aArray, (p_nStartIndex+1));
7317 if(this.parent instanceof Menu) {
7319 nGroupIndex = this.groupIndex;
7321 aItemGroups = this.parent.getItemGroups();
7323 if(this.index < (aItemGroups[nGroupIndex].length - 1)) {
7325 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
7326 (this.index+1));
7329 else {
7331 if(nGroupIndex < (aItemGroups.length - 1)) {
7333 nNextGroupIndex = nGroupIndex + 1;
7336 else {
7338 nNextGroupIndex = 0;
7342 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
7344 // Retrieve the first menu item in the next group
7346 oNextItem = getNextArrayItem(aNextGroup, 0);
7350 return (oNextItem.cfg.getProperty("disabled") ||
7351 oNextItem.element.style.display == "none") ?
7352 oNextItem.getNextEnabledSibling() : oNextItem;
7360 * @method getPreviousEnabledSibling
7361 * @description Finds the menu item's previous enabled sibling.
7362 * @return {YAHOO.widget.MenuItem}
7364 getPreviousEnabledSibling: function() {
7366 var nGroupIndex,
7367 aItemGroups,
7368 oPreviousItem,
7369 nPreviousGroupIndex,
7370 aPreviousGroup;
7372 function getPreviousArrayItem(p_aArray, p_nStartIndex) {
7374 return p_aArray[p_nStartIndex] ||
7375 getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
7379 function getFirstItemIndex(p_aArray, p_nStartIndex) {
7381 return p_aArray[p_nStartIndex] ? p_nStartIndex :
7382 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
7386 if(this.parent instanceof Menu) {
7388 nGroupIndex = this.groupIndex;
7389 aItemGroups = this.parent.getItemGroups();
7392 if(this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
7394 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
7395 (this.index-1));
7398 else {
7400 if(nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
7402 nPreviousGroupIndex = nGroupIndex - 1;
7405 else {
7407 nPreviousGroupIndex = aItemGroups.length - 1;
7411 aPreviousGroup = getPreviousArrayItem(aItemGroups,
7412 nPreviousGroupIndex);
7414 oPreviousItem = getPreviousArrayItem(aPreviousGroup,
7415 (aPreviousGroup.length - 1));
7419 return (oPreviousItem.cfg.getProperty("disabled") ||
7420 oPreviousItem.element.style.display == "none") ?
7421 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
7429 * @method focus
7430 * @description Causes the menu item to receive the focus and fires the
7431 * focus event.
7433 focus: function() {
7435 var oParent = this.parent,
7436 oAnchor = this._oAnchor,
7437 oActiveItem = oParent.activeItem,
7438 me = this;
7441 function setFocus() {
7443 try {
7445 if (YAHOO.env.ua.ie && !document.hasFocus()) {
7447 return;
7451 oAnchor.focus();
7454 catch(e) {
7461 if(!this.cfg.getProperty("disabled") && oParent &&
7462 oParent.cfg.getProperty("visible") &&
7463 this.element.style.display != "none") {
7465 if(oActiveItem) {
7467 oActiveItem.blur();
7473 Setting focus via a timer fixes a race condition in Firefox, IE
7474 and Opera where the browser viewport jumps as it trys to
7475 position and focus the menu.
7478 window.setTimeout(setFocus, 0);
7480 this.focusEvent.fire();
7488 * @method blur
7489 * @description Causes the menu item to lose focus and fires the
7490 * blur event.
7492 blur: function() {
7494 var oParent = this.parent;
7496 if(!this.cfg.getProperty("disabled") && oParent &&
7497 oParent.cfg.getProperty("visible")) {
7499 this._oAnchor.blur();
7501 this.blurEvent.fire();
7509 * @method hasFocus
7510 * @description Returns a boolean indicating whether or not the menu item
7511 * has focus.
7512 * @return {Boolean}
7514 hasFocus: function() {
7516 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
7522 * @method destroy
7523 * @description Removes the menu item's <code>&#60;li&#62;</code> element
7524 * from its parent <code>&#60;ul&#62;</code> element.
7526 destroy: function() {
7528 var oEl = this.element,
7529 oSubmenu,
7530 oParentNode;
7532 if(oEl) {
7535 // If the item has a submenu, destroy it first
7537 oSubmenu = this.cfg.getProperty("submenu");
7539 if(oSubmenu) {
7541 oSubmenu.destroy();
7546 // Remove CustomEvent listeners
7548 this.mouseOverEvent.unsubscribeAll();
7549 this.mouseOutEvent.unsubscribeAll();
7550 this.mouseDownEvent.unsubscribeAll();
7551 this.mouseUpEvent.unsubscribeAll();
7552 this.clickEvent.unsubscribeAll();
7553 this.keyPressEvent.unsubscribeAll();
7554 this.keyDownEvent.unsubscribeAll();
7555 this.keyUpEvent.unsubscribeAll();
7556 this.focusEvent.unsubscribeAll();
7557 this.blurEvent.unsubscribeAll();
7558 this.cfg.configChangedEvent.unsubscribeAll();
7561 // Remove the element from the parent node
7563 oParentNode = oEl.parentNode;
7565 if(oParentNode) {
7567 oParentNode.removeChild(oEl);
7569 this.destroyEvent.fire();
7573 this.destroyEvent.unsubscribeAll();
7581 * @method toString
7582 * @description Returns a string representing the menu item.
7583 * @return {String}
7585 toString: function() {
7587 var sReturnVal = "MenuItem",
7588 sId = this.id;
7590 if(sId) {
7592 sReturnVal += (" " + sId);
7596 return sReturnVal;
7602 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
7604 })();
7605 (function () {
7609 * Creates a list of options or commands which are made visible in response to
7610 * an HTML element's "contextmenu" event ("mousedown" for Opera).
7612 * @param {String} p_oElement String specifying the id attribute of the
7613 * <code>&#60;div&#62;</code> element of the context menu.
7614 * @param {String} p_oElement String specifying the id attribute of the
7615 * <code>&#60;select&#62;</code> element to be used as the data source for the
7616 * context menu.
7617 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7618 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7619 * <code>&#60;div&#62;</code> element of the context menu.
7620 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7621 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7622 * the <code>&#60;select&#62;</code> element to be used as the data source for
7623 * the context menu.
7624 * @param {Object} p_oConfig Optional. Object literal specifying the
7625 * configuration for the context menu. See configuration class documentation
7626 * for more details.
7627 * @class ContextMenu
7628 * @constructor
7629 * @extends YAHOO.widget.Menu
7630 * @namespace YAHOO.widget
7632 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
7634 YAHOO.widget.ContextMenu.superclass.constructor.call(this,
7635 p_oElement, p_oConfig);
7639 var Event = YAHOO.util.Event,
7640 ContextMenu = YAHOO.widget.ContextMenu,
7643 * Constant representing the name of the ContextMenu's events
7644 * @property EVENT_TYPES
7645 * @private
7646 * @final
7647 * @type Object
7649 EVENT_TYPES = {
7651 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
7652 "CONTEXT_MENU": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"),
7653 "CLICK": "click"
7659 * Constant representing the ContextMenu's configuration properties
7660 * @property DEFAULT_CONFIG
7661 * @private
7662 * @final
7663 * @type Object
7665 DEFAULT_CONFIG = {
7667 "TRIGGER": {
7668 key: "trigger"
7674 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
7678 // Private properties
7682 * @property _oTrigger
7683 * @description Object reference to the current value of the "trigger"
7684 * configuration property.
7685 * @default null
7686 * @private
7687 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
7688 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
7690 _oTrigger: null,
7694 * @property _bCancelled
7695 * @description Boolean indicating if the display of the context menu should
7696 * be cancelled.
7697 * @default false
7698 * @private
7699 * @type Boolean
7701 _bCancelled: false,
7705 // Public properties
7709 * @property contextEventTarget
7710 * @description Object reference for the HTML element that was the target of the
7711 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
7712 * the context menu.
7713 * @default null
7714 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7715 * html.html#ID-58190037">HTMLElement</a>
7717 contextEventTarget: null,
7721 // Events
7725 * @event triggerContextMenuEvent
7726 * @description Custom Event wrapper for the "contextmenu" DOM event
7727 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
7728 * the context menu.
7730 triggerContextMenuEvent: null,
7735 * @method init
7736 * @description The ContextMenu class's initialization method. This method is
7737 * automatically called by the constructor, and sets up all DOM references for
7738 * pre-existing markup, and creates required markup if it is not already present.
7739 * @param {String} p_oElement String specifying the id attribute of the
7740 * <code>&#60;div&#62;</code> element of the context menu.
7741 * @param {String} p_oElement String specifying the id attribute of the
7742 * <code>&#60;select&#62;</code> element to be used as the data source for
7743 * the context menu.
7744 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7745 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7746 * <code>&#60;div&#62;</code> element of the context menu.
7747 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7748 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7749 * the <code>&#60;select&#62;</code> element to be used as the data source for
7750 * the context menu.
7751 * @param {Object} p_oConfig Optional. Object literal specifying the
7752 * configuration for the context menu. See configuration class documentation
7753 * for more details.
7755 init: function(p_oElement, p_oConfig) {
7757 if(!this.ITEM_TYPE) {
7759 this.ITEM_TYPE = YAHOO.widget.ContextMenuItem;
7764 // Call the init of the superclass (YAHOO.widget.Menu)
7766 ContextMenu.superclass.init.call(this, p_oElement);
7769 this.beforeInitEvent.fire(ContextMenu);
7772 if(p_oConfig) {
7774 this.cfg.applyConfig(p_oConfig, true);
7779 this.initEvent.fire(ContextMenu);
7785 * @method initEvents
7786 * @description Initializes the custom events for the context menu.
7788 initEvents: function() {
7790 ContextMenu.superclass.initEvents.call(this);
7792 // Create custom events
7794 this.triggerContextMenuEvent =
7795 this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
7797 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
7803 * @method cancel
7804 * @description Cancels the display of the context menu.
7806 cancel: function() {
7808 this._bCancelled = true;
7814 // Private methods
7818 * @method _removeEventHandlers
7819 * @description Removes all of the DOM event handlers from the HTML element(s)
7820 * whose "context menu" event ("click" for Opera) trigger the display of
7821 * the context menu.
7822 * @private
7824 _removeEventHandlers: function() {
7826 var oTrigger = this._oTrigger;
7829 // Remove the event handlers from the trigger(s)
7831 if (oTrigger) {
7833 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU,
7834 this._onTriggerContextMenu);
7836 if(YAHOO.env.ua.opera) {
7838 Event.removeListener(oTrigger, EVENT_TYPES.CLICK,
7839 this._onTriggerClick);
7849 // Private event handlers
7853 * @method _onTriggerClick
7854 * @description "click" event handler for the HTML element(s) identified as the
7855 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
7856 * @private
7857 * @param {Event} p_oEvent Object representing the DOM event object passed back
7858 * by the event utility (YAHOO.util.Event).
7859 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
7860 * menu that is handling the event.
7862 _onTriggerClick: function(p_oEvent, p_oMenu) {
7864 if(p_oEvent.ctrlKey) {
7866 Event.stopEvent(p_oEvent);
7874 * @method _onTriggerContextMenu
7875 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
7876 * element(s) that trigger the display of the context menu.
7877 * @private
7878 * @param {Event} p_oEvent Object representing the DOM event object passed back
7879 * by the event utility (YAHOO.util.Event).
7880 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
7881 * menu that is handling the event.
7883 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
7885 if(p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {
7887 return;
7893 Prevent the browser's default context menu from appearing and
7894 stop the propagation of the "contextmenu" event so that
7895 other ContextMenu instances are not displayed.
7898 Event.stopEvent(p_oEvent);
7901 // Hide any other ContextMenu instances that might be visible
7903 YAHOO.widget.MenuManager.hideVisible();
7906 this.contextEventTarget = Event.getTarget(p_oEvent);
7908 this.triggerContextMenuEvent.fire(p_oEvent);
7911 if(!this._bCancelled) {
7913 // Position and display the context menu
7915 this.cfg.setProperty("xy", Event.getXY(p_oEvent));
7917 this.show();
7921 this._bCancelled = false;
7927 // Public methods
7931 * @method toString
7932 * @description Returns a string representing the context menu.
7933 * @return {String}
7935 toString: function() {
7937 var sReturnVal = "ContextMenu",
7938 sId = this.id;
7940 if(sId) {
7942 sReturnVal += (" " + sId);
7946 return sReturnVal;
7952 * @method initDefaultConfig
7953 * @description Initializes the class's configurable properties which can be
7954 * changed using the context menu's Config object ("cfg").
7956 initDefaultConfig: function() {
7958 ContextMenu.superclass.initDefaultConfig.call(this);
7961 * @config trigger
7962 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
7963 * for Opera) trigger the display of the context menu. Can be a string
7964 * representing the id attribute of the HTML element, an object reference
7965 * for the HTML element, or an array of strings or HTML element references.
7966 * @default null
7967 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7968 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
7970 this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key,
7971 { handler: this.configTrigger });
7977 * @method destroy
7978 * @description Removes the context menu's <code>&#60;div&#62;</code> element
7979 * (and accompanying child nodes) from the document.
7981 destroy: function() {
7983 // Remove the DOM event handlers from the current trigger(s)
7985 this._removeEventHandlers();
7988 // Continue with the superclass implementation of this method
7990 ContextMenu.superclass.destroy.call(this);
7996 // Public event handlers for configuration properties
8000 * @method configTrigger
8001 * @description Event handler for when the value of the "trigger" configuration
8002 * property changes.
8003 * @param {String} p_sType String representing the name of the event that
8004 * was fired.
8005 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8006 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8007 * menu that fired the event.
8009 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8011 var oTrigger = p_aArgs[0];
8013 if(oTrigger) {
8016 If there is a current "trigger" - remove the event handlers
8017 from that element(s) before assigning new ones
8020 if(this._oTrigger) {
8022 this._removeEventHandlers();
8026 this._oTrigger = oTrigger;
8030 Listen for the "mousedown" event in Opera b/c it does not
8031 support the "contextmenu" event
8034 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8035 this._onTriggerContextMenu, this, true);
8039 Assign a "click" event handler to the trigger element(s) for
8040 Opera to prevent default browser behaviors.
8043 if(YAHOO.env.ua.opera) {
8045 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick,
8046 this, true);
8051 else {
8053 this._removeEventHandlers();
8059 }); // END YAHOO.lang.extend
8061 }());
8066 * Creates an item for a context menu.
8068 * @param {String} p_oObject String specifying the text of the context menu item.
8069 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8070 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8071 * <code>&#60;li&#62;</code> element of the context menu item.
8072 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8073 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8074 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8075 * menu item.
8076 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8077 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8078 * the <code>&#60;option&#62;</code> element of the context menu item.
8079 * @param {Object} p_oConfig Optional. Object literal specifying the
8080 * configuration for the context menu item. See configuration class
8081 * documentation for more details.
8082 * @class ContextMenuItem
8083 * @constructor
8084 * @extends YAHOO.widget.MenuItem
8086 YAHOO.widget.ContextMenuItem = function(p_oObject, p_oConfig) {
8088 YAHOO.widget.ContextMenuItem.superclass.constructor.call(this,
8089 p_oObject, p_oConfig);
8093 YAHOO.lang.extend(YAHOO.widget.ContextMenuItem, YAHOO.widget.MenuItem, {
8097 * @method init
8098 * @description The ContextMenuItem class's initialization method. This method
8099 * is automatically called by the constructor, and sets up all DOM references
8100 * for pre-existing markup, and creates required markup if it is not
8101 * already present.
8102 * @param {String} p_oObject String specifying the text of the context menu item.
8103 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8104 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8105 * <code>&#60;li&#62;</code> element of the context menu item.
8106 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8107 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8108 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8109 * menu item.
8110 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8111 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8112 * the <code>&#60;option&#62;</code> element of the context menu item.
8113 * @param {Object} p_oConfig Optional. Object literal specifying the
8114 * configuration for the context menu item. See configuration class
8115 * documentation for more details.
8117 init: function(p_oObject, p_oConfig) {
8119 if(!this.SUBMENU_TYPE) {
8121 this.SUBMENU_TYPE = YAHOO.widget.ContextMenu;
8127 Call the init of the superclass (YAHOO.widget.MenuItem)
8128 Note: We don't pass the user config in here yet
8129 because we only want it executed once, at the lowest
8130 subclass level.
8133 YAHOO.widget.ContextMenuItem.superclass.init.call(this, p_oObject);
8135 var oConfig = this.cfg;
8137 if(p_oConfig) {
8139 oConfig.applyConfig(p_oConfig, true);
8143 oConfig.fireQueue();
8149 // Public methods
8153 * @method toString
8154 * @description Returns a string representing the context menu item.
8155 * @return {String}
8157 toString: function() {
8159 var sReturnVal = "ContextMenuItem";
8161 if(this.cfg && this.cfg.getProperty("text")) {
8163 sReturnVal += (": " + this.cfg.getProperty("text"));
8167 return sReturnVal;
8171 }); // END YAHOO.lang.extend
8172 (function () {
8176 * Horizontal collection of items, each of which can contain a submenu.
8178 * @param {String} p_oElement String specifying the id attribute of the
8179 * <code>&#60;div&#62;</code> element of the menu bar.
8180 * @param {String} p_oElement String specifying the id attribute of the
8181 * <code>&#60;select&#62;</code> element to be used as the data source for the
8182 * menu bar.
8183 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8184 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8185 * the <code>&#60;div&#62;</code> element of the menu bar.
8186 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8187 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8188 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8189 * source for the menu bar.
8190 * @param {Object} p_oConfig Optional. Object literal specifying the
8191 * configuration for the menu bar. See configuration class documentation for
8192 * more details.
8193 * @class MenuBar
8194 * @constructor
8195 * @extends YAHOO.widget.Menu
8196 * @namespace YAHOO.widget
8198 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
8200 YAHOO.widget.MenuBar.superclass.constructor.call(this,
8201 p_oElement, p_oConfig);
8207 * @method checkPosition
8208 * @description Checks to make sure that the value of the "position" property
8209 * is one of the supported strings. Returns true if the position is supported.
8210 * @private
8211 * @param {Object} p_sPosition String specifying the position of the menu.
8212 * @return {Boolean}
8214 function checkPosition(p_sPosition) {
8216 if (typeof p_sPosition == "string") {
8218 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
8225 var Event = YAHOO.util.Event,
8226 Dom = YAHOO.util.Dom,
8227 MenuBar = YAHOO.widget.MenuBar,
8230 * Constant representing the MenuBar's configuration properties
8231 * @property DEFAULT_CONFIG
8232 * @private
8233 * @final
8234 * @type Object
8236 DEFAULT_CONFIG = {
8238 "POSITION": {
8239 key: "position",
8240 value: "static",
8241 validator: checkPosition,
8242 supercedes: ["visible"]
8245 "SUBMENU_ALIGNMENT": {
8246 key: "submenualignment",
8247 value: ["tl","bl"]
8250 "AUTO_SUBMENU_DISPLAY": {
8251 key: "autosubmenudisplay",
8252 value: false,
8253 validator: YAHOO.lang.isBoolean
8260 YAHOO.lang.extend(MenuBar, YAHOO.widget.Menu, {
8263 * @method init
8264 * @description The MenuBar class's initialization method. This method is
8265 * automatically called by the constructor, and sets up all DOM references for
8266 * pre-existing markup, and creates required markup if it is not already present.
8267 * @param {String} p_oElement String specifying the id attribute of the
8268 * <code>&#60;div&#62;</code> element of the menu bar.
8269 * @param {String} p_oElement String specifying the id attribute of the
8270 * <code>&#60;select&#62;</code> element to be used as the data source for the
8271 * menu bar.
8272 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8273 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8274 * the <code>&#60;div&#62;</code> element of the menu bar.
8275 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8276 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8277 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8278 * source for the menu bar.
8279 * @param {Object} p_oConfig Optional. Object literal specifying the
8280 * configuration for the menu bar. See configuration class documentation for
8281 * more details.
8283 init: function(p_oElement, p_oConfig) {
8285 if(!this.ITEM_TYPE) {
8287 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
8292 // Call the init of the superclass (YAHOO.widget.Menu)
8294 MenuBar.superclass.init.call(this, p_oElement);
8297 this.beforeInitEvent.fire(MenuBar);
8300 if(p_oConfig) {
8302 this.cfg.applyConfig(p_oConfig, true);
8306 this.initEvent.fire(MenuBar);
8312 // Constants
8316 * @property CSS_CLASS_NAME
8317 * @description String representing the CSS class(es) to be applied to the menu
8318 * bar's <code>&#60;div&#62;</code> element.
8319 * @default "yuimenubar"
8320 * @final
8321 * @type String
8323 CSS_CLASS_NAME: "yuimenubar",
8327 // Protected event handlers
8331 * @method _onKeyDown
8332 * @description "keydown" Custom Event handler for the menu bar.
8333 * @private
8334 * @param {String} p_sType String representing the name of the event that
8335 * was fired.
8336 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8337 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8338 * that fired the event.
8340 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
8342 var oEvent = p_aArgs[0],
8343 oItem = p_aArgs[1],
8344 oSubmenu,
8345 oItemCfg,
8346 oNextItem;
8349 if(oItem && !oItem.cfg.getProperty("disabled")) {
8351 oItemCfg = oItem.cfg;
8353 switch(oEvent.keyCode) {
8355 case 37: // Left arrow
8356 case 39: // Right arrow
8358 if(oItem == this.activeItem &&
8359 !oItemCfg.getProperty("selected")) {
8361 oItemCfg.setProperty("selected", true);
8364 else {
8366 oNextItem = (oEvent.keyCode == 37) ?
8367 oItem.getPreviousEnabledSibling() :
8368 oItem.getNextEnabledSibling();
8370 if(oNextItem) {
8372 this.clearActiveItem();
8374 oNextItem.cfg.setProperty("selected", true);
8377 if(this.cfg.getProperty("autosubmenudisplay")) {
8379 oSubmenu = oNextItem.cfg.getProperty("submenu");
8381 if(oSubmenu) {
8383 oSubmenu.show();
8389 oNextItem.focus();
8395 Event.preventDefault(oEvent);
8397 break;
8399 case 40: // Down arrow
8401 if(this.activeItem != oItem) {
8403 this.clearActiveItem();
8405 oItemCfg.setProperty("selected", true);
8406 oItem.focus();
8410 oSubmenu = oItemCfg.getProperty("submenu");
8412 if(oSubmenu) {
8414 if(oSubmenu.cfg.getProperty("visible")) {
8416 oSubmenu.setInitialSelection();
8417 oSubmenu.setInitialFocus();
8420 else {
8422 oSubmenu.show();
8428 Event.preventDefault(oEvent);
8430 break;
8437 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
8439 oSubmenu = this.activeItem.cfg.getProperty("submenu");
8441 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
8443 oSubmenu.hide();
8444 this.activeItem.focus();
8447 else {
8449 this.activeItem.cfg.setProperty("selected", false);
8450 this.activeItem.blur();
8454 Event.preventDefault(oEvent);
8462 * @method _onClick
8463 * @description "click" event handler for the menu bar.
8464 * @protected
8465 * @param {String} p_sType String representing the name of the event that
8466 * was fired.
8467 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8468 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8469 * that fired the event.
8471 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
8473 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
8475 var oItem = p_aArgs[1],
8476 oEvent,
8477 oTarget,
8478 oActiveItem,
8479 oConfig,
8480 oSubmenu;
8483 if(oItem && !oItem.cfg.getProperty("disabled")) {
8485 oEvent = p_aArgs[0];
8486 oTarget = Event.getTarget(oEvent);
8487 oActiveItem = this.activeItem;
8488 oConfig = this.cfg;
8491 // Hide any other submenus that might be visible
8493 if(oActiveItem && oActiveItem != oItem) {
8495 this.clearActiveItem();
8500 oItem.cfg.setProperty("selected", true);
8503 // Show the submenu for the item
8505 oSubmenu = oItem.cfg.getProperty("submenu");
8508 if(oSubmenu && oTarget != oItem.submenuIndicator) {
8510 if(oSubmenu.cfg.getProperty("visible")) {
8512 oSubmenu.hide();
8515 else {
8517 oSubmenu.show();
8529 // Public methods
8533 * @method toString
8534 * @description Returns a string representing the menu bar.
8535 * @return {String}
8537 toString: function() {
8539 var sReturnVal = "MenuBar",
8540 sId = this.id;
8542 if(sId) {
8544 sReturnVal += (" " + sId);
8548 return sReturnVal;
8554 * @description Initializes the class's configurable properties which can be
8555 * changed using the menu bar's Config object ("cfg").
8556 * @method initDefaultConfig
8558 initDefaultConfig: function() {
8560 MenuBar.superclass.initDefaultConfig.call(this);
8562 var oConfig = this.cfg;
8564 // Add configuration properties
8568 Set the default value for the "position" configuration property
8569 to "static" by re-adding the property.
8574 * @config position
8575 * @description String indicating how a menu bar should be positioned on the
8576 * screen. Possible values are "static" and "dynamic." Static menu bars
8577 * are visible by default and reside in the normal flow of the document
8578 * (CSS position: static). Dynamic menu bars are hidden by default, reside
8579 * out of the normal flow of the document (CSS position: absolute), and can
8580 * overlay other elements on the screen.
8581 * @default static
8582 * @type String
8584 oConfig.addProperty(
8585 DEFAULT_CONFIG.POSITION.key,
8587 handler: this.configPosition,
8588 value: DEFAULT_CONFIG.POSITION.value,
8589 validator: DEFAULT_CONFIG.POSITION.validator,
8590 supercedes: DEFAULT_CONFIG.POSITION.supercedes
8596 Set the default value for the "submenualignment" configuration property
8597 to ["tl","bl"] by re-adding the property.
8601 * @config submenualignment
8602 * @description Array defining how submenus should be aligned to their
8603 * parent menu bar item. The format is: [itemCorner, submenuCorner].
8604 * @default ["tl","bl"]
8605 * @type Array
8607 oConfig.addProperty(
8608 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
8610 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value
8616 Change the default value for the "autosubmenudisplay" configuration
8617 property to "false" by re-adding the property.
8621 * @config autosubmenudisplay
8622 * @description Boolean indicating if submenus are automatically made
8623 * visible when the user mouses over the menu bar's items.
8624 * @default false
8625 * @type Boolean
8627 oConfig.addProperty(
8628 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
8630 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
8631 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator
8637 }); // END YAHOO.lang.extend
8639 }());
8644 * Creates an item for a menu bar.
8646 * @param {String} p_oObject String specifying the text of the menu bar item.
8647 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8648 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8649 * <code>&#60;li&#62;</code> element of the menu bar item.
8650 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8651 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8652 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8653 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8654 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8655 * the <code>&#60;option&#62;</code> element of the menu bar item.
8656 * @param {Object} p_oConfig Optional. Object literal specifying the
8657 * configuration for the menu bar item. See configuration class documentation
8658 * for more details.
8659 * @class MenuBarItem
8660 * @constructor
8661 * @extends YAHOO.widget.MenuItem
8663 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
8665 YAHOO.widget.MenuBarItem.superclass.constructor.call(this,
8666 p_oObject, p_oConfig);
8670 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
8675 * @method init
8676 * @description The MenuBarItem class's initialization method. This method is
8677 * automatically called by the constructor, and sets up all DOM references for
8678 * pre-existing markup, and creates required markup if it is not already present.
8679 * @param {String} p_oObject String specifying the text of the menu bar item.
8680 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8681 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8682 * <code>&#60;li&#62;</code> element of the menu bar item.
8683 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8684 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8685 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8686 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8687 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8688 * the <code>&#60;option&#62;</code> element of the menu bar item.
8689 * @param {Object} p_oConfig Optional. Object literal specifying the
8690 * configuration for the menu bar item. See configuration class documentation
8691 * for more details.
8693 init: function(p_oObject, p_oConfig) {
8695 if(!this.SUBMENU_TYPE) {
8697 this.SUBMENU_TYPE = YAHOO.widget.Menu;
8703 Call the init of the superclass (YAHOO.widget.MenuItem)
8704 Note: We don't pass the user config in here yet
8705 because we only want it executed once, at the lowest
8706 subclass level.
8709 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
8712 var oConfig = this.cfg;
8714 if(p_oConfig) {
8716 oConfig.applyConfig(p_oConfig, true);
8720 oConfig.fireQueue();
8726 // Constants
8730 * @property CSS_CLASS_NAME
8731 * @description String representing the CSS class(es) to be applied to the
8732 * <code>&#60;li&#62;</code> element of the menu bar item.
8733 * @default "yuimenubaritem"
8734 * @final
8735 * @type String
8737 CSS_CLASS_NAME: "yuimenubaritem",
8741 * @property CSS_LABEL_CLASS_NAME
8742 * @description String representing the CSS class(es) to be applied to the
8743 * menu bar item's <code>&#60;a&#62;</code> element.
8744 * @default "yuimenubaritemlabel"
8745 * @final
8746 * @type String
8748 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
8752 // Public methods
8756 * @method toString
8757 * @description Returns a string representing the menu bar item.
8758 * @return {String}
8760 toString: function() {
8762 var sReturnVal = "MenuBarItem";
8764 if(this.cfg && this.cfg.getProperty("text")) {
8766 sReturnVal += (": " + this.cfg.getProperty("text"));
8770 return sReturnVal;
8774 }); // END YAHOO.lang.extend
8775 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.3.0", build: "442"});