Deleting the check_defaults test from 19_STABLE. MDL-14854
[moodle-linuxchix.git] / lib / yui / menu / menu-debug.js
blob44fdcfe426f5b9966c2a125f704412b51e401fbb
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;
87 var m_oLogger = new YAHOO.widget.LogWriter("MenuManager");
91 // Private methods
94 /**
95 * @method getMenuRootElement
96 * @description Finds the root DIV node of a menu or the root LI node of
97 * a menu item.
98 * @private
99 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
100 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
101 * specifying an HTML element.
103 function getMenuRootElement(p_oElement) {
105 var oParentNode;
107 if (p_oElement && p_oElement.tagName) {
109 switch (p_oElement.tagName.toUpperCase()) {
111 case "DIV":
113 oParentNode = p_oElement.parentNode;
115 // Check if the DIV is the inner "body" node of a menu
117 if (
119 Dom.hasClass(p_oElement, "hd") ||
120 Dom.hasClass(p_oElement, "bd") ||
121 Dom.hasClass(p_oElement, "ft")
122 ) &&
123 oParentNode &&
124 oParentNode.tagName &&
125 oParentNode.tagName.toUpperCase() == "DIV")
128 return oParentNode;
131 else {
133 return p_oElement;
137 break;
139 case "LI":
141 return p_oElement;
143 default:
145 oParentNode = p_oElement.parentNode;
147 if (oParentNode) {
149 return getMenuRootElement(oParentNode);
153 break;
163 // Private event handlers
167 * @method onDOMEvent
168 * @description Generic, global event handler for all of a menu's
169 * DOM-based events. This listens for events against the document
170 * object. If the target of a given event is a member of a menu or
171 * menu item's DOM, the instance's corresponding Custom Event is fired.
172 * @private
173 * @param {Event} p_oEvent Object representing the DOM event object
174 * passed back by the event utility (YAHOO.util.Event).
176 function onDOMEvent(p_oEvent) {
178 // Get the target node of the DOM event
180 var oTarget = Event.getTarget(p_oEvent),
182 // See if the target of the event was a menu, or a menu item
184 oElement = getMenuRootElement(oTarget),
185 sCustomEventType,
186 sTagName,
187 sId,
188 oMenuItem,
189 oMenu;
192 if (oElement) {
194 sTagName = oElement.tagName.toUpperCase();
196 if (sTagName == "LI") {
198 sId = oElement.id;
200 if (sId && m_oItems[sId]) {
202 oMenuItem = m_oItems[sId];
203 oMenu = oMenuItem.parent;
208 else if (sTagName == "DIV") {
210 if (oElement.id) {
212 oMenu = m_oMenus[oElement.id];
221 if (oMenu) {
223 sCustomEventType = m_oEventTypes[p_oEvent.type];
226 // Fire the Custom Event that corresponds the current DOM event
228 if (oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
230 oMenuItem[sCustomEventType].fire(p_oEvent);
233 if (
234 p_oEvent.type == "keyup" ||
235 p_oEvent.type == "mousedown")
238 if (m_oFocusedMenuItem != oMenuItem) {
240 if (m_oFocusedMenuItem) {
242 m_oFocusedMenuItem.blurEvent.fire();
246 oMenuItem.focusEvent.fire();
254 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
257 else if (p_oEvent.type == "mousedown") {
259 if (m_oFocusedMenuItem) {
261 m_oFocusedMenuItem.blurEvent.fire();
263 m_oFocusedMenuItem = null;
269 If the target of the event wasn't a menu, hide all
270 dynamically positioned menus
273 for (var i in m_oMenus) {
275 if (YAHOO.lang.hasOwnProperty(m_oMenus,i)) {
277 oMenu = m_oMenus[i];
279 if (oMenu.cfg.getProperty("clicktohide") &&
280 !(oMenu instanceof YAHOO.widget.MenuBar) &&
281 oMenu.cfg.getProperty("position") == "dynamic") {
283 oMenu.hide();
286 else {
288 oMenu.clearActiveItem(true);
297 else if (p_oEvent.type == "keyup") {
299 if (m_oFocusedMenuItem) {
301 m_oFocusedMenuItem.blurEvent.fire();
303 m_oFocusedMenuItem = null;
313 * @method onMenuDestroy
314 * @description "destroy" event handler for a menu.
315 * @private
316 * @param {String} p_sType String representing the name of the event
317 * that was fired.
318 * @param {Array} p_aArgs Array of arguments sent when the event
319 * was fired.
320 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
322 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
324 if (m_oMenus[p_oMenu.id]) {
326 this.removeMenu(p_oMenu);
334 * @method onMenuFocus
335 * @description "focus" event handler for a MenuItem instance.
336 * @private
337 * @param {String} p_sType String representing the name of the event
338 * that was fired.
339 * @param {Array} p_aArgs Array of arguments sent when the event
340 * was fired.
342 function onMenuFocus(p_sType, p_aArgs) {
344 var oItem = p_aArgs[0];
346 if (oItem) {
348 m_oFocusedMenuItem = oItem;
356 * @method onMenuBlur
357 * @description "blur" event handler for a MenuItem instance.
358 * @private
359 * @param {String} p_sType String representing the name of the event
360 * that was fired.
361 * @param {Array} p_aArgs Array of arguments sent when the event
362 * was fired.
364 function onMenuBlur(p_sType, p_aArgs) {
366 m_oFocusedMenuItem = null;
373 * @method onMenuVisibleConfigChange
374 * @description Event handler for when the "visible" configuration
375 * property of a Menu instance changes.
376 * @private
377 * @param {String} p_sType String representing the name of the event
378 * that was fired.
379 * @param {Array} p_aArgs Array of arguments sent when the event
380 * was fired.
382 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
384 var bVisible = p_aArgs[0],
385 sId = this.id;
387 if (bVisible) {
389 m_oVisibleMenus[sId] = this;
391 m_oLogger.log(
392 this +
393 " added to the collection of visible menus.");
396 else if (m_oVisibleMenus[sId]) {
398 delete m_oVisibleMenus[sId];
400 m_oLogger.log(
401 this +
402 " removed from the collection of visible menus.");
410 * @method onItemDestroy
411 * @description "destroy" event handler for a MenuItem instance.
412 * @private
413 * @param {String} p_sType String representing the name of the event
414 * that was fired.
415 * @param {Array} p_aArgs Array of arguments sent when the event
416 * was fired.
418 function onItemDestroy(p_sType, p_aArgs) {
420 var sId = this.id;
422 if (sId && m_oItems[sId]) {
424 if (m_oFocusedMenuItem == this) {
426 m_oFocusedMenuItem = null;
430 delete m_oItems[sId];
432 m_oLogger.log(this + " successfully unregistered.");
440 * @method onItemAdded
441 * @description "itemadded" event handler for a Menu instance.
442 * @private
443 * @param {String} p_sType String representing the name of the event
444 * that was fired.
445 * @param {Array} p_aArgs Array of arguments sent when the event
446 * was fired.
448 function onItemAdded(p_sType, p_aArgs) {
450 var oItem = p_aArgs[0],
451 sId;
453 if (oItem instanceof YAHOO.widget.MenuItem) {
455 sId = oItem.id;
457 if (!m_oItems[sId]) {
459 m_oItems[sId] = oItem;
461 oItem.destroyEvent.subscribe(onItemDestroy);
463 m_oLogger.log(oItem + " successfully registered.");
472 return {
474 // Privileged methods
478 * @method addMenu
479 * @description Adds a menu to the collection of known menus.
480 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
481 * instance to be added.
483 addMenu: function (p_oMenu) {
485 var oDoc;
487 if (
488 p_oMenu instanceof YAHOO.widget.Menu &&
489 p_oMenu.id &&
490 !m_oMenus[p_oMenu.id]
493 m_oMenus[p_oMenu.id] = p_oMenu;
496 if (!m_bInitializedEventHandlers) {
498 oDoc = document;
500 Event.on(oDoc, "mouseover", onDOMEvent, this, true);
501 Event.on(oDoc, "mouseout", onDOMEvent, this, true);
502 Event.on(oDoc, "mousedown", onDOMEvent, this, true);
503 Event.on(oDoc, "mouseup", onDOMEvent, this, true);
504 Event.on(oDoc, "click", onDOMEvent, this, true);
505 Event.on(oDoc, "keydown", onDOMEvent, this, true);
506 Event.on(oDoc, "keyup", onDOMEvent, this, true);
507 Event.on(oDoc, "keypress", onDOMEvent, this, true);
510 m_bInitializedEventHandlers = true;
512 m_oLogger.log("DOM event handlers initialized.");
516 p_oMenu.destroyEvent.subscribe(
517 onMenuDestroy,
518 p_oMenu,
519 this);
521 p_oMenu.cfg.subscribeToConfigEvent(
522 "visible",
523 onMenuVisibleConfigChange);
525 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
526 p_oMenu.focusEvent.subscribe(onMenuFocus);
527 p_oMenu.blurEvent.subscribe(onMenuBlur);
529 m_oLogger.log(p_oMenu + " successfully registered.");
537 * @method removeMenu
538 * @description Removes a menu from the collection of known menus.
539 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
540 * instance to be removed.
542 removeMenu: function (p_oMenu) {
544 var sId;
546 if (p_oMenu) {
548 sId = p_oMenu.id;
550 if (m_oMenus[sId] == p_oMenu) {
552 delete m_oMenus[sId];
554 m_oLogger.log(p_oMenu + " successfully unregistered.");
557 if (m_oVisibleMenus[sId] == p_oMenu) {
559 delete m_oVisibleMenus[sId];
561 m_oLogger.log(
562 p_oMenu +
563 " unregistered from the" +
564 " collection of visible menus.");
576 * @method hideVisible
577 * @description Hides all visible, dynamically positioned menus
578 * (excluding instances of YAHOO.widget.MenuBar).
580 hideVisible: function () {
582 var oMenu;
584 for (var i in m_oVisibleMenus) {
586 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus,i)) {
588 oMenu = m_oVisibleMenus[i];
590 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
591 oMenu.cfg.getProperty("position") == "dynamic") {
593 oMenu.hide();
605 * @method getMenus
606 * @description Returns an array of all menus registered with the
607 * menu manger.
608 * @return {Array}
610 getMenus: function () {
612 return m_oMenus;
618 * @method getMenu
619 * @description Returns a menu with the specified id.
620 * @param {String} p_sId String specifying the id of the
621 * <code>&#60;div&#62;</code> element representing the menu to
622 * be retrieved.
623 * @return {YAHOO.widget.Menu}
625 getMenu: function (p_sId) {
627 var oMenu = m_oMenus[p_sId];
629 if (oMenu) {
631 return oMenu;
639 * @method getMenuItem
640 * @description Returns a menu item with the specified id.
641 * @param {String} p_sId String specifying the id of the
642 * <code>&#60;li&#62;</code> element representing the menu item to
643 * be retrieved.
644 * @return {YAHOO.widget.MenuItem}
646 getMenuItem: function (p_sId) {
648 var oItem = m_oItems[p_sId];
650 if (oItem) {
652 return oItem;
660 * @method getMenuItemGroup
661 * @description Returns an array of menu item instances whose
662 * corresponding <code>&#60;li&#62;</code> elements are child
663 * nodes of the <code>&#60;ul&#62;</code> element with the
664 * specified id.
665 * @param {String} p_sId String specifying the id of the
666 * <code>&#60;ul&#62;</code> element representing the group of
667 * menu items to be retrieved.
668 * @return {Array}
670 getMenuItemGroup: function (p_sId) {
672 var oUL = Dom.get(p_sId),
673 aItems,
674 oNode,
675 oItem,
676 sId;
679 if (oUL && oUL.tagName &&
680 oUL.tagName.toUpperCase() == "UL") {
682 oNode = oUL.firstChild;
684 if (oNode) {
686 aItems = [];
688 do {
690 sId = oNode.id;
692 if (sId) {
694 oItem = this.getMenuItem(sId);
696 if (oItem) {
698 aItems[aItems.length] = oItem;
705 while ((oNode = oNode.nextSibling));
708 if (aItems.length > 0) {
710 return aItems;
722 * @method getFocusedMenuItem
723 * @description Returns a reference to the menu item that currently
724 * has focus.
725 * @return {YAHOO.widget.MenuItem}
727 getFocusedMenuItem: function () {
729 return m_oFocusedMenuItem;
735 * @method getFocusedMenu
736 * @description Returns a reference to the menu that currently
737 * has focus.
738 * @return {YAHOO.widget.Menu}
740 getFocusedMenu: function () {
742 if (m_oFocusedMenuItem) {
744 return (m_oFocusedMenuItem.parent.getRoot());
752 * @method toString
753 * @description Returns a string representing the menu manager.
754 * @return {String}
756 toString: function () {
758 return "MenuManager";
764 }();
766 })();
770 (function () {
774 * The Menu class creates a container that holds a vertical list representing
775 * a set of options or commands. Menu is the base class for all
776 * menu containers.
777 * @param {String} p_oElement String specifying the id attribute of the
778 * <code>&#60;div&#62;</code> element of the menu.
779 * @param {String} p_oElement String specifying the id attribute of the
780 * <code>&#60;select&#62;</code> element to be used as the data source
781 * for the menu.
782 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
783 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
784 * specifying the <code>&#60;div&#62;</code> element of the menu.
785 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
786 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
787 * Object specifying the <code>&#60;select&#62;</code> element to be used as
788 * the data source for the menu.
789 * @param {Object} p_oConfig Optional. Object literal specifying the
790 * configuration for the menu. See configuration class documentation for
791 * more details.
792 * @namespace YAHOO.widget
793 * @class Menu
794 * @constructor
795 * @extends YAHOO.widget.Overlay
797 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
799 if (p_oConfig) {
801 this.parent = p_oConfig.parent;
802 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
803 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
808 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
815 * @method checkPosition
816 * @description Checks to make sure that the value of the "position" property
817 * is one of the supported strings. Returns true if the position is supported.
818 * @private
819 * @param {Object} p_sPosition String specifying the position of the menu.
820 * @return {Boolean}
822 function checkPosition(p_sPosition) {
824 if (typeof p_sPosition == "string") {
826 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
833 var Dom = YAHOO.util.Dom,
834 Event = YAHOO.util.Event,
835 Module = YAHOO.widget.Module,
836 Overlay = YAHOO.widget.Overlay,
837 Menu = YAHOO.widget.Menu,
838 MenuManager = YAHOO.widget.MenuManager,
839 CustomEvent = YAHOO.util.CustomEvent,
840 Lang = YAHOO.lang,
842 m_oShadowTemplate,
845 * Constant representing the name of the Menu's events
846 * @property EVENT_TYPES
847 * @private
848 * @final
849 * @type Object
851 EVENT_TYPES = {
853 "MOUSE_OVER": "mouseover",
854 "MOUSE_OUT": "mouseout",
855 "MOUSE_DOWN": "mousedown",
856 "MOUSE_UP": "mouseup",
857 "CLICK": "click",
858 "KEY_PRESS": "keypress",
859 "KEY_DOWN": "keydown",
860 "KEY_UP": "keyup",
861 "FOCUS": "focus",
862 "BLUR": "blur",
863 "ITEM_ADDED": "itemAdded",
864 "ITEM_REMOVED": "itemRemoved"
870 * Constant representing the Menu's configuration properties
871 * @property DEFAULT_CONFIG
872 * @private
873 * @final
874 * @type Object
876 DEFAULT_CONFIG = {
878 "VISIBLE": {
879 key: "visible",
880 value: false,
881 validator: Lang.isBoolean
884 "CONSTRAIN_TO_VIEWPORT": {
885 key: "constraintoviewport",
886 value: true,
887 validator: Lang.isBoolean,
888 supercedes: ["iframe","x","y","xy"]
891 "POSITION": {
892 key: "position",
893 value: "dynamic",
894 validator: checkPosition,
895 supercedes: ["visible", "iframe"]
898 "SUBMENU_ALIGNMENT": {
899 key: "submenualignment",
900 value: ["tl","tr"]
903 "AUTO_SUBMENU_DISPLAY": {
904 key: "autosubmenudisplay",
905 value: true,
906 validator: Lang.isBoolean
909 "SHOW_DELAY": {
910 key: "showdelay",
911 value: 250,
912 validator: Lang.isNumber
915 "HIDE_DELAY": {
916 key: "hidedelay",
917 value: 0,
918 validator: Lang.isNumber,
919 suppressEvent: true
922 "SUBMENU_HIDE_DELAY": {
923 key: "submenuhidedelay",
924 value: 250,
925 validator: Lang.isNumber
928 "CLICK_TO_HIDE": {
929 key: "clicktohide",
930 value: true,
931 validator: Lang.isBoolean
934 "CONTAINER": {
935 key: "container"
938 "MAX_HEIGHT": {
939 key: "maxheight",
940 value: 0,
941 validator: Lang.isNumber,
942 supercedes: ["iframe"]
945 "CLASS_NAME": {
946 key: "classname",
947 value: null,
948 validator: Lang.isString
951 "DISABLED": {
952 key: "disabled",
953 value: false,
954 validator: Lang.isBoolean
961 YAHOO.lang.extend(Menu, Overlay, {
964 // Constants
968 * @property CSS_CLASS_NAME
969 * @description String representing the CSS class(es) to be applied to the
970 * menu's <code>&#60;div&#62;</code> element.
971 * @default "yuimenu"
972 * @final
973 * @type String
975 CSS_CLASS_NAME: "yuimenu",
979 * @property ITEM_TYPE
980 * @description Object representing the type of menu item to instantiate and
981 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
982 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
983 * of the menu's source HTML element.
984 * @default YAHOO.widget.MenuItem
985 * @final
986 * @type YAHOO.widget.MenuItem
988 ITEM_TYPE: null,
992 * @property GROUP_TITLE_TAG_NAME
993 * @description String representing the tagname of the HTML element used to
994 * title the menu's item groups.
995 * @default H6
996 * @final
997 * @type String
999 GROUP_TITLE_TAG_NAME: "h6",
1003 // Private properties
1006 /**
1007 * @property _nHideDelayId
1008 * @description Number representing the time-out setting used to cancel the
1009 * hiding of a menu.
1010 * @default null
1011 * @private
1012 * @type Number
1014 _nHideDelayId: null,
1017 /**
1018 * @property _nShowDelayId
1019 * @description Number representing the time-out setting used to cancel the
1020 * showing of a menu.
1021 * @default null
1022 * @private
1023 * @type Number
1025 _nShowDelayId: null,
1028 /**
1029 * @property _nSubmenuHideDelayId
1030 * @description Number representing the time-out setting used to cancel the
1031 * hiding of a submenu.
1032 * @default null
1033 * @private
1034 * @type Number
1036 _nSubmenuHideDelayId: null,
1039 /**
1040 * @property _nBodyScrollId
1041 * @description Number representing the time-out setting used to cancel the
1042 * scrolling of the menu's body element.
1043 * @default null
1044 * @private
1045 * @type Number
1047 _nBodyScrollId: null,
1050 /**
1051 * @property _bHideDelayEventHandlersAssigned
1052 * @description Boolean indicating if the "mouseover" and "mouseout" event
1053 * handlers used for hiding the menu via a call to "window.setTimeout" have
1054 * already been assigned.
1055 * @default false
1056 * @private
1057 * @type Boolean
1059 _bHideDelayEventHandlersAssigned: false,
1063 * @property _bHandledMouseOverEvent
1064 * @description Boolean indicating the current state of the menu's
1065 * "mouseover" event.
1066 * @default false
1067 * @private
1068 * @type Boolean
1070 _bHandledMouseOverEvent: false,
1074 * @property _bHandledMouseOutEvent
1075 * @description Boolean indicating the current state of the menu's
1076 * "mouseout" event.
1077 * @default false
1078 * @private
1079 * @type Boolean
1081 _bHandledMouseOutEvent: false,
1085 * @property _aGroupTitleElements
1086 * @description Array of HTML element used to title groups of menu items.
1087 * @default []
1088 * @private
1089 * @type Array
1091 _aGroupTitleElements: null,
1095 * @property _aItemGroups
1096 * @description Multi-dimensional Array representing the menu items as they
1097 * are grouped in the menu.
1098 * @default []
1099 * @private
1100 * @type Array
1102 _aItemGroups: null,
1106 * @property _aListElements
1107 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is
1108 * the parent node for each item's <code>&#60;li&#62;</code> element.
1109 * @default []
1110 * @private
1111 * @type Array
1113 _aListElements: null,
1117 * @property _nCurrentMouseX
1118 * @description The current x coordinate of the mouse inside the area of
1119 * the menu.
1120 * @default 0
1121 * @private
1122 * @type Number
1124 _nCurrentMouseX: 0,
1128 * @property _nMaxHeight
1129 * @description The original value of the "maxheight" configuration property
1130 * as set by the user.
1131 * @default -1
1132 * @private
1133 * @type Number
1135 _nMaxHeight: -1,
1139 * @property _bStopMouseEventHandlers
1140 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1141 * from executing.
1142 * @default false
1143 * @private
1144 * @type Boolean
1146 _bStopMouseEventHandlers: false,
1150 * @property _sClassName
1151 * @description The current value of the "classname" configuration attribute.
1152 * @default null
1153 * @private
1154 * @type String
1156 _sClassName: null,
1160 * @property _bDisabled
1161 * @description The current value of the "disabled" configuration attribute.
1162 * @default false
1163 * @private
1164 * @type Boolean
1166 _bDisabled: false,
1169 // Public properties
1173 * @property lazyLoad
1174 * @description Boolean indicating if the menu's "lazy load" feature is
1175 * enabled. If set to "true," initialization and rendering of the menu's
1176 * items will be deferred until the first time it is made visible. This
1177 * property should be set via the constructor using the configuration
1178 * object literal.
1179 * @default false
1180 * @type Boolean
1182 lazyLoad: false,
1186 * @property itemData
1187 * @description Array of items to be added to the menu. The array can contain
1188 * strings representing the text for each item to be created, object literals
1189 * representing the menu item configuration properties, or MenuItem instances.
1190 * This property should be set via the constructor using the configuration
1191 * object literal.
1192 * @default null
1193 * @type Array
1195 itemData: null,
1199 * @property activeItem
1200 * @description Object reference to the item in the menu that has is selected.
1201 * @default null
1202 * @type YAHOO.widget.MenuItem
1204 activeItem: null,
1208 * @property parent
1209 * @description Object reference to the menu's parent menu or menu item.
1210 * This property can be set via the constructor using the configuration
1211 * object literal.
1212 * @default null
1213 * @type YAHOO.widget.MenuItem
1215 parent: null,
1219 * @property srcElement
1220 * @description Object reference to the HTML element (either
1221 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
1222 * create the menu.
1223 * @default null
1224 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1225 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1226 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1227 * html#ID-22445964">HTMLDivElement</a>
1229 srcElement: null,
1233 // Events
1237 * @event mouseOverEvent
1238 * @description Fires when the mouse has entered the menu. Passes back
1239 * the DOM Event object as an argument.
1241 mouseOverEvent: null,
1245 * @event mouseOutEvent
1246 * @description Fires when the mouse has left the menu. Passes back the DOM
1247 * Event object as an argument.
1248 * @type YAHOO.util.CustomEvent
1250 mouseOutEvent: null,
1254 * @event mouseDownEvent
1255 * @description Fires when the user mouses down on the menu. Passes back the
1256 * DOM Event object as an argument.
1257 * @type YAHOO.util.CustomEvent
1259 mouseDownEvent: null,
1263 * @event mouseUpEvent
1264 * @description Fires when the user releases a mouse button while the mouse is
1265 * over the menu. Passes back the DOM Event object as an argument.
1266 * @type YAHOO.util.CustomEvent
1268 mouseUpEvent: null,
1272 * @event clickEvent
1273 * @description Fires when the user clicks the on the menu. Passes back the
1274 * DOM Event object as an argument.
1275 * @type YAHOO.util.CustomEvent
1277 clickEvent: null,
1281 * @event keyPressEvent
1282 * @description Fires when the user presses an alphanumeric key when one of the
1283 * menu's items has focus. Passes back the DOM Event object as an argument.
1284 * @type YAHOO.util.CustomEvent
1286 keyPressEvent: null,
1290 * @event keyDownEvent
1291 * @description Fires when the user presses a key when one of the menu's items
1292 * has focus. Passes back the DOM Event object as an argument.
1293 * @type YAHOO.util.CustomEvent
1295 keyDownEvent: null,
1299 * @event keyUpEvent
1300 * @description Fires when the user releases a key when one of the menu's items
1301 * has focus. Passes back the DOM Event object as an argument.
1302 * @type YAHOO.util.CustomEvent
1304 keyUpEvent: null,
1308 * @event itemAddedEvent
1309 * @description Fires when an item is added to the menu.
1310 * @type YAHOO.util.CustomEvent
1312 itemAddedEvent: null,
1316 * @event itemRemovedEvent
1317 * @description Fires when an item is removed to the menu.
1318 * @type YAHOO.util.CustomEvent
1320 itemRemovedEvent: null,
1324 * @method init
1325 * @description The Menu class's initialization method. This method is
1326 * automatically called by the constructor, and sets up all DOM references
1327 * for pre-existing markup, and creates required markup if it is not
1328 * already present.
1329 * @param {String} p_oElement String specifying the id attribute of the
1330 * <code>&#60;div&#62;</code> element of the menu.
1331 * @param {String} p_oElement String specifying the id attribute of the
1332 * <code>&#60;select&#62;</code> element to be used as the data source
1333 * for the menu.
1334 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1335 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1336 * specifying the <code>&#60;div&#62;</code> element of the menu.
1337 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1338 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1339 * Object specifying the <code>&#60;select&#62;</code> element to be used as
1340 * the data source for the menu.
1341 * @param {Object} p_oConfig Optional. Object literal specifying the
1342 * configuration for the menu. See configuration class documentation for
1343 * more details.
1345 init: function (p_oElement, p_oConfig) {
1347 this._aItemGroups = [];
1348 this._aListElements = [];
1349 this._aGroupTitleElements = [];
1351 if (!this.ITEM_TYPE) {
1353 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1358 var oElement;
1360 if (typeof p_oElement == "string") {
1362 oElement = document.getElementById(p_oElement);
1365 else if (p_oElement.tagName) {
1367 oElement = p_oElement;
1372 if (oElement && oElement.tagName) {
1374 switch(oElement.tagName.toUpperCase()) {
1376 case "DIV":
1378 this.srcElement = oElement;
1380 if (!oElement.id) {
1382 oElement.setAttribute("id", Dom.generateId());
1388 Note: we don't pass the user config in here yet
1389 because we only want it executed once, at the lowest
1390 subclass level.
1393 Menu.superclass.init.call(this, oElement);
1395 this.beforeInitEvent.fire(Menu);
1397 this.logger = new YAHOO.widget.LogWriter(this.toString());
1399 this.logger.log("Source element: " + this.srcElement.tagName);
1401 break;
1403 case "SELECT":
1405 this.srcElement = oElement;
1409 The source element is not something that we can use
1410 outright, so we need to create a new Overlay
1412 Note: we don't pass the user config in here yet
1413 because we only want it executed once, at the lowest
1414 subclass level.
1417 Menu.superclass.init.call(this, Dom.generateId());
1419 this.beforeInitEvent.fire(Menu);
1421 this.logger = new YAHOO.widget.LogWriter(this.toString());
1423 this.logger.log("Source element: " + this.srcElement.tagName);
1425 break;
1430 else {
1433 Note: we don't pass the user config in here yet
1434 because we only want it executed once, at the lowest
1435 subclass level.
1438 Menu.superclass.init.call(this, p_oElement);
1440 this.beforeInitEvent.fire(Menu);
1442 this.logger = new YAHOO.widget.LogWriter(this.toString());
1444 this.logger.log("No source element found. " +
1445 "Created element with id: " + this.id);
1450 if (this.element) {
1452 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1455 // Subscribe to Custom Events
1457 this.initEvent.subscribe(this._onInit);
1458 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1459 this.renderEvent.subscribe(this._onRender);
1460 this.renderEvent.subscribe(this.onRender);
1461 this.beforeShowEvent.subscribe(this._onBeforeShow);
1462 this.showEvent.subscribe(this._onShow);
1463 this.beforeHideEvent.subscribe(this._onBeforeHide);
1464 this.hideEvent.subscribe(this._onHide);
1465 this.mouseOverEvent.subscribe(this._onMouseOver);
1466 this.mouseOutEvent.subscribe(this._onMouseOut);
1467 this.clickEvent.subscribe(this._onClick);
1468 this.keyDownEvent.subscribe(this._onKeyDown);
1469 this.keyPressEvent.subscribe(this._onKeyPress);
1471 Module.textResizeEvent.subscribe(this._onTextResize, this, true);
1474 if (p_oConfig) {
1476 this.cfg.applyConfig(p_oConfig, true);
1481 // Register the Menu instance with the MenuManager
1483 MenuManager.addMenu(this);
1486 this.initEvent.fire(Menu);
1494 // Private methods
1498 * @method _initSubTree
1499 * @description Iterates the childNodes of the source element to find nodes
1500 * used to instantiate menu and menu items.
1501 * @private
1503 _initSubTree: function () {
1505 var oSrcElement = this.srcElement,
1506 sSrcElementTagName,
1507 nGroup,
1508 sGroupTitleTagName,
1509 oNode,
1510 aListElements,
1511 nListElements,
1515 if (oSrcElement) {
1517 sSrcElementTagName =
1518 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1521 if (sSrcElementTagName == "DIV") {
1523 // Populate the collection of item groups and item group titles
1525 oNode = this.body.firstChild;
1528 if (oNode) {
1530 nGroup = 0;
1531 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1533 do {
1536 if (oNode && oNode.tagName) {
1538 switch (oNode.tagName.toUpperCase()) {
1540 case sGroupTitleTagName:
1542 this._aGroupTitleElements[nGroup] = oNode;
1544 break;
1546 case "UL":
1548 this._aListElements[nGroup] = oNode;
1549 this._aItemGroups[nGroup] = [];
1550 nGroup++;
1552 break;
1559 while ((oNode = oNode.nextSibling));
1563 Apply the "first-of-type" class to the first UL to mimic
1564 the "first-of-type" CSS3 psuedo class.
1567 if (this._aListElements[0]) {
1569 Dom.addClass(this._aListElements[0], "first-of-type");
1578 oNode = null;
1580 this.logger.log("Searching DOM for items to initialize.");
1583 if (sSrcElementTagName) {
1585 switch (sSrcElementTagName) {
1587 case "DIV":
1589 aListElements = this._aListElements;
1590 nListElements = aListElements.length;
1592 if (nListElements > 0) {
1594 this.logger.log("Found " + nListElements +
1595 " item groups to initialize.");
1597 i = nListElements - 1;
1599 do {
1601 oNode = aListElements[i].firstChild;
1603 if (oNode) {
1605 this.logger.log("Scanning " +
1606 aListElements[i].childNodes.length +
1607 " child nodes for items to initialize.");
1609 do {
1611 if (oNode && oNode.tagName &&
1612 oNode.tagName.toUpperCase() == "LI") {
1614 this.logger.log("Initializing " +
1615 oNode.tagName + " node.");
1617 this.addItem(new this.ITEM_TYPE(oNode,
1618 { parent: this }), i);
1623 while ((oNode = oNode.nextSibling));
1628 while (i--);
1632 break;
1634 case "SELECT":
1636 this.logger.log("Scanning " +
1637 oSrcElement.childNodes.length +
1638 " child nodes for items to initialize.");
1640 oNode = oSrcElement.firstChild;
1642 do {
1644 if (oNode && oNode.tagName) {
1646 switch (oNode.tagName.toUpperCase()) {
1648 case "OPTGROUP":
1649 case "OPTION":
1651 this.logger.log("Initializing " +
1652 oNode.tagName + " node.");
1654 this.addItem(
1655 new this.ITEM_TYPE(
1656 oNode,
1657 { parent: this }
1661 break;
1668 while ((oNode = oNode.nextSibling));
1670 break;
1682 * @method _getFirstEnabledItem
1683 * @description Returns the first enabled item in the menu.
1684 * @return {YAHOO.widget.MenuItem}
1685 * @private
1687 _getFirstEnabledItem: function () {
1689 var aItems = this.getItems(),
1690 nItems = aItems.length,
1691 oItem;
1693 for(var i=0; i<nItems; i++) {
1695 oItem = aItems[i];
1697 if (oItem && !oItem.cfg.getProperty("disabled") &&
1698 oItem.element.style.display != "none") {
1700 return oItem;
1710 * @method _addItemToGroup
1711 * @description Adds a menu item to a group.
1712 * @private
1713 * @param {Number} p_nGroupIndex Number indicating the group to which the
1714 * item belongs.
1715 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1716 * instance to be added to the menu.
1717 * @param {String} p_oItem String specifying the text of the item to be added
1718 * to the menu.
1719 * @param {Object} p_oItem Object literal containing a set of menu item
1720 * configuration properties.
1721 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1722 * which the menu item should be added.
1723 * @return {YAHOO.widget.MenuItem}
1725 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1727 var oItem,
1728 bDisabled = this.cfg.getProperty("disabled"),
1729 nGroupIndex,
1730 aGroup,
1731 oGroupItem,
1732 bAppend,
1733 oNextItemSibling,
1734 nItemIndex;
1736 function getNextItemSibling(p_aArray, p_nStartIndex) {
1738 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray,
1739 (p_nStartIndex+1)));
1743 if (p_oItem instanceof this.ITEM_TYPE) {
1745 oItem = p_oItem;
1746 oItem.parent = this;
1749 else if (typeof p_oItem == "string") {
1751 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1754 else if (typeof p_oItem == "object") {
1756 p_oItem.parent = this;
1758 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1763 if (oItem) {
1765 if (oItem.cfg.getProperty("selected")) {
1767 this.activeItem = oItem;
1772 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1773 aGroup = this._getItemGroup(nGroupIndex);
1777 if (!aGroup) {
1779 aGroup = this._createItemGroup(nGroupIndex);
1784 if (typeof p_nItemIndex == "number") {
1786 bAppend = (p_nItemIndex >= aGroup.length);
1789 if (aGroup[p_nItemIndex]) {
1791 aGroup.splice(p_nItemIndex, 0, oItem);
1794 else {
1796 aGroup[p_nItemIndex] = oItem;
1801 oGroupItem = aGroup[p_nItemIndex];
1803 if (oGroupItem) {
1805 if (bAppend && (!oGroupItem.element.parentNode ||
1806 oGroupItem.element.parentNode.nodeType == 11)) {
1808 this._aListElements[nGroupIndex].appendChild(
1809 oGroupItem.element);
1812 else {
1814 oNextItemSibling = getNextItemSibling(aGroup,
1815 (p_nItemIndex+1));
1817 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
1818 oGroupItem.element.parentNode.nodeType == 11)) {
1820 this._aListElements[nGroupIndex].insertBefore(
1821 oGroupItem.element,
1822 oNextItemSibling.element);
1829 oGroupItem.parent = this;
1831 this._subscribeToItemEvents(oGroupItem);
1833 this._configureSubmenu(oGroupItem);
1835 this._updateItemProperties(nGroupIndex);
1837 this.logger.log("Item inserted." +
1838 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
1839 " Index: " + oGroupItem.index + ", " +
1840 " Group Index: " + oGroupItem.groupIndex);
1842 this.itemAddedEvent.fire(oGroupItem);
1843 this.changeContentEvent.fire();
1845 return oGroupItem;
1850 else {
1852 nItemIndex = aGroup.length;
1854 aGroup[nItemIndex] = oItem;
1856 oGroupItem = aGroup[nItemIndex];
1859 if (oGroupItem) {
1861 if (!Dom.isAncestor(this._aListElements[nGroupIndex],
1862 oGroupItem.element)) {
1864 this._aListElements[nGroupIndex].appendChild(
1865 oGroupItem.element);
1869 oGroupItem.element.setAttribute("groupindex", nGroupIndex);
1870 oGroupItem.element.setAttribute("index", nItemIndex);
1872 oGroupItem.parent = this;
1874 oGroupItem.index = nItemIndex;
1875 oGroupItem.groupIndex = nGroupIndex;
1877 this._subscribeToItemEvents(oGroupItem);
1879 this._configureSubmenu(oGroupItem);
1881 if (nItemIndex === 0) {
1883 Dom.addClass(oGroupItem.element, "first-of-type");
1887 this.logger.log("Item added." +
1888 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
1889 " Index: " + oGroupItem.index + ", " +
1890 " Group Index: " + oGroupItem.groupIndex);
1893 this.itemAddedEvent.fire(oGroupItem);
1894 this.changeContentEvent.fire();
1896 return oGroupItem;
1908 * @method _removeItemFromGroupByIndex
1909 * @description Removes a menu item from a group by index. Returns the menu
1910 * item that was removed.
1911 * @private
1912 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
1913 * item belongs.
1914 * @param {Number} p_nItemIndex Number indicating the index of the menu item
1915 * to be removed.
1916 * @return {YAHOO.widget.MenuItem}
1918 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
1920 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0,
1921 aGroup = this._getItemGroup(nGroupIndex),
1922 aArray,
1923 oItem,
1924 oUL;
1926 if (aGroup) {
1928 aArray = aGroup.splice(p_nItemIndex, 1);
1929 oItem = aArray[0];
1931 if (oItem) {
1933 // Update the index and className properties of each member
1935 this._updateItemProperties(nGroupIndex);
1937 if (aGroup.length === 0) {
1939 // Remove the UL
1941 oUL = this._aListElements[nGroupIndex];
1943 if (this.body && oUL) {
1945 this.body.removeChild(oUL);
1949 // Remove the group from the array of items
1951 this._aItemGroups.splice(nGroupIndex, 1);
1954 // Remove the UL from the array of ULs
1956 this._aListElements.splice(nGroupIndex, 1);
1960 Assign the "first-of-type" class to the new first UL
1961 in the collection
1964 oUL = this._aListElements[0];
1966 if (oUL) {
1968 Dom.addClass(oUL, "first-of-type");
1975 this.itemRemovedEvent.fire(oItem);
1976 this.changeContentEvent.fire();
1979 // Return a reference to the item that was removed
1981 return oItem;
1991 * @method _removeItemFromGroupByValue
1992 * @description Removes a menu item from a group by reference. Returns the
1993 * menu item that was removed.
1994 * @private
1995 * @param {Number} p_nGroupIndex Number indicating the group to which the
1996 * menu item belongs.
1997 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1998 * instance to be removed.
1999 * @return {YAHOO.widget.MenuItem}
2001 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2003 var aGroup = this._getItemGroup(p_nGroupIndex),
2004 nItems,
2005 nItemIndex,
2008 if (aGroup) {
2010 nItems = aGroup.length;
2011 nItemIndex = -1;
2013 if (nItems > 0) {
2015 i = nItems-1;
2017 do {
2019 if (aGroup[i] == p_oItem) {
2021 nItemIndex = i;
2022 break;
2027 while(i--);
2029 if (nItemIndex > -1) {
2031 return (this._removeItemFromGroupByIndex(p_nGroupIndex,
2032 nItemIndex));
2044 * @method _updateItemProperties
2045 * @description Updates the "index," "groupindex," and "className" properties
2046 * of the menu items in the specified group.
2047 * @private
2048 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2050 _updateItemProperties: function (p_nGroupIndex) {
2052 var aGroup = this._getItemGroup(p_nGroupIndex),
2053 nItems = aGroup.length,
2054 oItem,
2055 oLI,
2059 if (nItems > 0) {
2061 i = nItems - 1;
2063 // Update the index and className properties of each member
2065 do {
2067 oItem = aGroup[i];
2069 if (oItem) {
2071 oLI = oItem.element;
2073 oItem.index = i;
2074 oItem.groupIndex = p_nGroupIndex;
2076 oLI.setAttribute("groupindex", p_nGroupIndex);
2077 oLI.setAttribute("index", i);
2079 Dom.removeClass(oLI, "first-of-type");
2084 while(i--);
2087 if (oLI) {
2089 Dom.addClass(oLI, "first-of-type");
2099 * @method _createItemGroup
2100 * @description Creates a new menu item group (array) and its associated
2101 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2102 * @private
2103 * @param {Number} p_nIndex Number indicating the group to create.
2104 * @return {Array}
2106 _createItemGroup: function (p_nIndex) {
2108 var oUL;
2110 if (!this._aItemGroups[p_nIndex]) {
2112 this._aItemGroups[p_nIndex] = [];
2114 oUL = document.createElement("ul");
2116 this._aListElements[p_nIndex] = oUL;
2118 return this._aItemGroups[p_nIndex];
2126 * @method _getItemGroup
2127 * @description Returns the menu item group at the specified index.
2128 * @private
2129 * @param {Number} p_nIndex Number indicating the index of the menu item group
2130 * to be retrieved.
2131 * @return {Array}
2133 _getItemGroup: function (p_nIndex) {
2135 var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);
2137 return this._aItemGroups[nIndex];
2143 * @method _configureSubmenu
2144 * @description Subscribes the menu item's submenu to its parent menu's events.
2145 * @private
2146 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2147 * instance with the submenu to be configured.
2149 _configureSubmenu: function (p_oItem) {
2151 var oSubmenu = p_oItem.cfg.getProperty("submenu");
2153 if (oSubmenu) {
2156 Listen for configuration changes to the parent menu
2157 so they they can be applied to the submenu.
2160 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange,
2161 oSubmenu, true);
2163 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2165 oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow, null,
2166 oSubmenu);
2168 oSubmenu.showEvent.subscribe(this._onSubmenuShow, null, p_oItem);
2169 oSubmenu.hideEvent.subscribe(this._onSubmenuHide, null, p_oItem);
2177 * @method _subscribeToItemEvents
2178 * @description Subscribes a menu to a menu item's event.
2179 * @private
2180 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2181 * instance whose events should be subscribed to.
2183 _subscribeToItemEvents: function (p_oItem) {
2185 p_oItem.focusEvent.subscribe(this._onMenuItemFocus);
2187 p_oItem.blurEvent.subscribe(this._onMenuItemBlur);
2189 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,
2190 p_oItem, this);
2196 * @method _getOffsetWidth
2197 * @description Returns the offset width of the menu's
2198 * <code>&#60;div&#62;</code> element.
2199 * @private
2201 _getOffsetWidth: function () {
2203 var oClone = this.element.cloneNode(true);
2205 Dom.removeClass(oClone, "visible");
2207 Dom.setStyle(oClone, "width", "");
2209 document.body.appendChild(oClone);
2211 var sWidth = oClone.offsetWidth;
2213 document.body.removeChild(oClone);
2215 return sWidth;
2221 * @method _setWidth
2222 * @description Sets the width of the menu's root <code>&#60;div&#62;</code>
2223 * element to its offsetWidth.
2224 * @private
2226 _setWidth: function () {
2228 var oElement = this.element,
2229 bVisible = false,
2230 sWidth;
2232 if (oElement.parentNode.tagName.toUpperCase() == "BODY") {
2234 if (YAHOO.env.ua.opera) {
2236 sWidth = this._getOffsetWidth();
2239 else {
2241 if (Dom.hasClass(oElement, "visible")) {
2243 bVisible = true;
2245 Dom.removeClass(oElement, "visible");
2249 Dom.setStyle(oElement, "width", "auto");
2251 sWidth = oElement.offsetWidth;
2256 else {
2258 sWidth = this._getOffsetWidth();
2262 this.cfg.setProperty("width", (sWidth + "px"));
2265 if (bVisible) {
2267 Dom.addClass(oElement, "visible");
2275 * @method _onWidthChange
2276 * @description Change event handler for the the menu's "width" configuration
2277 * property.
2278 * @private
2279 * @param {String} p_sType String representing the name of the event that
2280 * was fired.
2281 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2283 _onWidthChange: function (p_sType, p_aArgs) {
2285 var sWidth = p_aArgs[0];
2287 if (sWidth && !this._hasSetWidthHandlers) {
2289 this.itemAddedEvent.subscribe(this._setWidth);
2290 this.itemRemovedEvent.subscribe(this._setWidth);
2292 this._hasSetWidthHandlers = true;
2295 else if (this._hasSetWidthHandlers) {
2297 this.itemAddedEvent.unsubscribe(this._setWidth);
2298 this.itemRemovedEvent.unsubscribe(this._setWidth);
2300 this._hasSetWidthHandlers = false;
2308 * @method _onVisibleChange
2309 * @description Change event handler for the the menu's "visible" configuration
2310 * property.
2311 * @private
2312 * @param {String} p_sType String representing the name of the event that
2313 * was fired.
2314 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2316 _onVisibleChange: function (p_sType, p_aArgs) {
2318 var bVisible = p_aArgs[0];
2320 if (bVisible) {
2322 Dom.addClass(this.element, "visible");
2325 else {
2327 Dom.removeClass(this.element, "visible");
2335 * @method _cancelHideDelay
2336 * @description Cancels the call to "hideMenu."
2337 * @private
2339 _cancelHideDelay: function () {
2341 var oRoot = this.getRoot();
2343 if (oRoot._nHideDelayId) {
2345 window.clearTimeout(oRoot._nHideDelayId);
2353 * @method _execHideDelay
2354 * @description Hides the menu after the number of milliseconds specified by
2355 * the "hidedelay" configuration property.
2356 * @private
2358 _execHideDelay: function () {
2360 this._cancelHideDelay();
2362 var oRoot = this.getRoot(),
2363 me = this;
2365 function hideMenu() {
2367 if (oRoot.activeItem) {
2369 oRoot.clearActiveItem();
2373 if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) &&
2374 me.cfg.getProperty("position") == "dynamic") {
2376 me.hide();
2383 oRoot._nHideDelayId =
2384 window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));
2390 * @method _cancelShowDelay
2391 * @description Cancels the call to the "showMenu."
2392 * @private
2394 _cancelShowDelay: function () {
2396 var oRoot = this.getRoot();
2398 if (oRoot._nShowDelayId) {
2400 window.clearTimeout(oRoot._nShowDelayId);
2408 * @method _execShowDelay
2409 * @description Shows the menu after the number of milliseconds specified by
2410 * the "showdelay" configuration property have ellapsed.
2411 * @private
2412 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should
2413 * be made visible.
2415 _execShowDelay: function (p_oMenu) {
2417 var oRoot = this.getRoot();
2419 function showMenu() {
2421 if (p_oMenu.parent.cfg.getProperty("selected")) {
2423 p_oMenu.show();
2430 oRoot._nShowDelayId =
2431 window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));
2437 * @method _execSubmenuHideDelay
2438 * @description Hides a submenu after the number of milliseconds specified by
2439 * the "submenuhidedelay" configuration property have ellapsed.
2440 * @private
2441 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2442 * should be hidden.
2443 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2444 * the specified submenu's parent menu item.
2445 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2446 * before the submenu is hidden.
2448 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2450 var me = this;
2452 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2454 if (me._nCurrentMouseX > (p_nMouseX + 10)) {
2456 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2458 p_oSubmenu.hide();
2460 }, p_nHideDelay);
2463 else {
2465 p_oSubmenu.hide();
2469 }, 50);
2475 // Protected methods
2479 * @method _disableScrollHeader
2480 * @description Disables the header used for scrolling the body of the menu.
2481 * @protected
2483 _disableScrollHeader: function () {
2485 if (!this._bHeaderDisabled) {
2487 Dom.addClass(this.header, "topscrollbar_disabled");
2488 this._bHeaderDisabled = true;
2496 * @method _disableScrollFooter
2497 * @description Disables the footer used for scrolling the body of the menu.
2498 * @protected
2500 _disableScrollFooter: function () {
2502 if (!this._bFooterDisabled) {
2504 Dom.addClass(this.footer, "bottomscrollbar_disabled");
2505 this._bFooterDisabled = true;
2513 * @method _enableScrollHeader
2514 * @description Enables the header used for scrolling the body of the menu.
2515 * @protected
2517 _enableScrollHeader: function () {
2519 if (this._bHeaderDisabled) {
2521 Dom.removeClass(this.header, "topscrollbar_disabled");
2522 this._bHeaderDisabled = false;
2530 * @method _enableScrollFooter
2531 * @description Enables the footer used for scrolling the body of the menu.
2532 * @protected
2534 _enableScrollFooter: function () {
2536 if (this._bFooterDisabled) {
2538 Dom.removeClass(this.footer, "bottomscrollbar_disabled");
2539 this._bFooterDisabled = false;
2547 * @method _onMouseOver
2548 * @description "mouseover" event handler for the menu.
2549 * @protected
2550 * @param {String} p_sType String representing the name of the event that
2551 * was fired.
2552 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2554 _onMouseOver: function (p_sType, p_aArgs) {
2556 if (this._bStopMouseEventHandlers) {
2558 return false;
2563 var oEvent = p_aArgs[0],
2564 oItem = p_aArgs[1],
2565 oTarget = Event.getTarget(oEvent),
2566 oParentMenu,
2567 nShowDelay,
2568 bShowDelay,
2569 oActiveItem,
2570 oItemCfg,
2571 oSubmenu;
2574 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2575 Dom.isAncestor(this.element, oTarget))) {
2577 // Menu mouseover logic
2579 this._nCurrentMouseX = 0;
2581 Event.on(this.element, "mousemove", this._onMouseMove, this, true);
2584 this.clearActiveItem();
2587 if (this.parent && this._nSubmenuHideDelayId) {
2589 window.clearTimeout(this._nSubmenuHideDelayId);
2591 this.parent.cfg.setProperty("selected", true);
2593 oParentMenu = this.parent.parent;
2595 oParentMenu._bHandledMouseOutEvent = true;
2596 oParentMenu._bHandledMouseOverEvent = false;
2601 this._bHandledMouseOverEvent = true;
2602 this._bHandledMouseOutEvent = false;
2607 if (oItem && !oItem.handledMouseOverEvent &&
2608 !oItem.cfg.getProperty("disabled") &&
2609 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2611 // Menu Item mouseover logic
2613 nShowDelay = this.cfg.getProperty("showdelay");
2614 bShowDelay = (nShowDelay > 0);
2617 if (bShowDelay) {
2619 this._cancelShowDelay();
2624 oActiveItem = this.activeItem;
2626 if (oActiveItem) {
2628 oActiveItem.cfg.setProperty("selected", false);
2633 oItemCfg = oItem.cfg;
2635 // Select and focus the current menu item
2637 oItemCfg.setProperty("selected", true);
2640 if (this.hasFocus()) {
2642 oItem.focus();
2647 if (this.cfg.getProperty("autosubmenudisplay")) {
2649 // Show the submenu this menu item
2651 oSubmenu = oItemCfg.getProperty("submenu");
2653 if (oSubmenu) {
2655 if (bShowDelay) {
2657 this._execShowDelay(oSubmenu);
2660 else {
2662 oSubmenu.show();
2670 oItem.handledMouseOverEvent = true;
2671 oItem.handledMouseOutEvent = false;
2679 * @method _onMouseOut
2680 * @description "mouseout" event handler for the menu.
2681 * @protected
2682 * @param {String} p_sType String representing the name of the event that
2683 * was fired.
2684 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2686 _onMouseOut: function (p_sType, p_aArgs) {
2688 if (this._bStopMouseEventHandlers) {
2690 return false;
2695 var oEvent = p_aArgs[0],
2696 oItem = p_aArgs[1],
2697 oRelatedTarget = Event.getRelatedTarget(oEvent),
2698 bMovingToSubmenu = false,
2699 oItemCfg,
2700 oSubmenu,
2701 nSubmenuHideDelay,
2702 nShowDelay;
2705 if (oItem && !oItem.cfg.getProperty("disabled")) {
2707 oItemCfg = oItem.cfg;
2708 oSubmenu = oItemCfg.getProperty("submenu");
2711 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2712 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2714 bMovingToSubmenu = true;
2719 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2720 !Dom.isAncestor(oItem.element, oRelatedTarget)) ||
2721 bMovingToSubmenu)) {
2723 // Menu Item mouseout logic
2725 if (!bMovingToSubmenu) {
2727 oItem.cfg.setProperty("selected", false);
2730 if (oSubmenu) {
2732 nSubmenuHideDelay =
2733 this.cfg.getProperty("submenuhidedelay");
2735 nShowDelay = this.cfg.getProperty("showdelay");
2737 if (!(this instanceof YAHOO.widget.MenuBar) &&
2738 nSubmenuHideDelay > 0 &&
2739 nShowDelay >= nSubmenuHideDelay) {
2741 this._execSubmenuHideDelay(oSubmenu,
2742 Event.getPageX(oEvent),
2743 nSubmenuHideDelay);
2746 else {
2748 oSubmenu.hide();
2757 oItem.handledMouseOutEvent = true;
2758 oItem.handledMouseOverEvent = false;
2765 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2766 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2768 // Menu mouseout logic
2770 Event.removeListener(this.element, "mousemove", this._onMouseMove);
2772 this._nCurrentMouseX = Event.getPageX(oEvent);
2774 this._bHandledMouseOutEvent = true;
2775 this._bHandledMouseOverEvent = false;
2783 * @method _onMouseMove
2784 * @description "click" event handler for the menu.
2785 * @protected
2786 * @param {Event} p_oEvent Object representing the DOM event object passed
2787 * back by the event utility (YAHOO.util.Event).
2788 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2789 * fired the event.
2791 _onMouseMove: function (p_oEvent, p_oMenu) {
2793 if (this._bStopMouseEventHandlers) {
2795 return false;
2799 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2805 * @method _onClick
2806 * @description "click" event handler for the menu.
2807 * @protected
2808 * @param {String} p_sType String representing the name of the event that
2809 * was fired.
2810 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2812 _onClick: function (p_sType, p_aArgs) {
2814 var oEvent = p_aArgs[0],
2815 oItem = p_aArgs[1],
2816 oTarget,
2817 oItemCfg,
2818 oSubmenu,
2819 sURL,
2820 oRoot;
2823 if (oItem && !oItem.cfg.getProperty("disabled")) {
2825 oTarget = Event.getTarget(oEvent);
2826 oItemCfg = oItem.cfg;
2827 oSubmenu = oItemCfg.getProperty("submenu");
2831 ACCESSIBILITY FEATURE FOR SCREEN READERS:
2832 Expand/collapse the submenu when the user clicks
2833 on the submenu indicator image.
2836 if (oTarget == oItem.submenuIndicator && oSubmenu) {
2838 if (oSubmenu.cfg.getProperty("visible")) {
2840 oSubmenu.hide();
2842 oSubmenu.parent.focus();
2845 else {
2847 this.clearActiveItem();
2849 oItemCfg.setProperty("selected", true);
2851 oSubmenu.show();
2853 oSubmenu.setInitialFocus();
2857 Event.preventDefault(oEvent);
2860 else {
2862 sURL = oItemCfg.getProperty("url");
2864 // Prevent the browser from following links equal to "#"
2866 if ((sURL.substr((sURL.length-1),1) == "#")) {
2868 Event.preventDefault(oEvent);
2870 oItem.focus();
2875 if (!oSubmenu) {
2877 oRoot = this.getRoot();
2879 if (oRoot instanceof YAHOO.widget.MenuBar ||
2880 oRoot.cfg.getProperty("position") == "static") {
2882 oRoot.clearActiveItem();
2885 else if (oRoot.cfg.getProperty("clicktohide")) {
2887 oRoot.hide();
2901 * @method _onKeyDown
2902 * @description "keydown" event handler for the menu.
2903 * @protected
2904 * @param {String} p_sType String representing the name of the event that
2905 * was fired.
2906 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2908 _onKeyDown: function (p_sType, p_aArgs) {
2910 var oEvent = p_aArgs[0],
2911 oItem = p_aArgs[1],
2912 me = this,
2913 oSubmenu,
2914 oItemCfg,
2915 oParentItem,
2916 oRoot,
2917 oNextItem,
2918 oBody,
2919 nBodyScrollTop,
2920 nBodyOffsetHeight,
2921 aItems,
2922 nItems,
2923 nNextItemOffsetTop,
2924 nScrollTarget,
2925 oParentMenu;
2929 This function is called to prevent a bug in Firefox. In Firefox,
2930 moving a DOM element into a stationary mouse pointer will cause the
2931 browser to fire mouse events. This can result in the menu mouse
2932 event handlers being called uncessarily, especially when menus are
2933 moved into a stationary mouse pointer as a result of a
2934 key event handler.
2936 function stopMouseEventHandlers() {
2938 me._bStopMouseEventHandlers = true;
2940 window.setTimeout(function () {
2942 me._bStopMouseEventHandlers = false;
2944 }, 10);
2949 if (oItem && !oItem.cfg.getProperty("disabled")) {
2951 oItemCfg = oItem.cfg;
2952 oParentItem = this.parent;
2954 switch(oEvent.keyCode) {
2956 case 38: // Up arrow
2957 case 40: // Down arrow
2959 oNextItem = (oEvent.keyCode == 38) ?
2960 oItem.getPreviousEnabledSibling() :
2961 oItem.getNextEnabledSibling();
2963 if (oNextItem) {
2965 this.clearActiveItem();
2967 oNextItem.cfg.setProperty("selected", true);
2968 oNextItem.focus();
2971 if (this.cfg.getProperty("maxheight") > 0) {
2973 oBody = this.body;
2974 nBodyScrollTop = oBody.scrollTop;
2975 nBodyOffsetHeight = oBody.offsetHeight;
2976 aItems = this.getItems();
2977 nItems = aItems.length - 1;
2978 nNextItemOffsetTop = oNextItem.element.offsetTop;
2981 if (oEvent.keyCode == 40 ) { // Down
2983 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
2985 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
2988 else if (nNextItemOffsetTop <= nBodyScrollTop) {
2990 oBody.scrollTop = 0;
2995 if (oNextItem == aItems[nItems]) {
2997 oBody.scrollTop = oNextItem.element.offsetTop;
3002 else { // Up
3004 if (nNextItemOffsetTop <= nBodyScrollTop) {
3006 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3009 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3011 oBody.scrollTop = nNextItemOffsetTop;
3016 if (oNextItem == aItems[0]) {
3018 oBody.scrollTop = 0;
3025 nBodyScrollTop = oBody.scrollTop;
3026 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3028 if (nBodyScrollTop === 0) {
3030 this._disableScrollHeader();
3031 this._enableScrollFooter();
3034 else if (nBodyScrollTop == nScrollTarget) {
3036 this._enableScrollHeader();
3037 this._disableScrollFooter();
3040 else {
3042 this._enableScrollHeader();
3043 this._enableScrollFooter();
3052 Event.preventDefault(oEvent);
3054 stopMouseEventHandlers();
3056 break;
3059 case 39: // Right arrow
3061 oSubmenu = oItemCfg.getProperty("submenu");
3063 if (oSubmenu) {
3065 if (!oItemCfg.getProperty("selected")) {
3067 oItemCfg.setProperty("selected", true);
3071 oSubmenu.show();
3072 oSubmenu.setInitialFocus();
3073 oSubmenu.setInitialSelection();
3076 else {
3078 oRoot = this.getRoot();
3080 if (oRoot instanceof YAHOO.widget.MenuBar) {
3082 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3084 if (oNextItem) {
3086 oRoot.clearActiveItem();
3088 oNextItem.cfg.setProperty("selected", true);
3090 oSubmenu = oNextItem.cfg.getProperty("submenu");
3092 if (oSubmenu) {
3094 oSubmenu.show();
3098 oNextItem.focus();
3107 Event.preventDefault(oEvent);
3109 stopMouseEventHandlers();
3111 break;
3114 case 37: // Left arrow
3116 if (oParentItem) {
3118 oParentMenu = oParentItem.parent;
3120 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3122 oNextItem =
3123 oParentMenu.activeItem.getPreviousEnabledSibling();
3125 if (oNextItem) {
3127 oParentMenu.clearActiveItem();
3129 oNextItem.cfg.setProperty("selected", true);
3131 oSubmenu = oNextItem.cfg.getProperty("submenu");
3133 if (oSubmenu) {
3135 oSubmenu.show();
3139 oNextItem.focus();
3144 else {
3146 this.hide();
3148 oParentItem.focus();
3154 Event.preventDefault(oEvent);
3156 stopMouseEventHandlers();
3158 break;
3166 if (oEvent.keyCode == 27) { // Esc key
3168 if (this.cfg.getProperty("position") == "dynamic") {
3170 this.hide();
3172 if (this.parent) {
3174 this.parent.focus();
3179 else if (this.activeItem) {
3181 oSubmenu = this.activeItem.cfg.getProperty("submenu");
3183 if (oSubmenu && oSubmenu.cfg.getProperty("visible")) {
3185 oSubmenu.hide();
3186 this.activeItem.focus();
3189 else {
3191 this.activeItem.blur();
3192 this.activeItem.cfg.setProperty("selected", false);
3199 Event.preventDefault(oEvent);
3207 * @method _onKeyPress
3208 * @description "keypress" event handler for a Menu instance.
3209 * @protected
3210 * @param {String} p_sType The name of the event that was fired.
3211 * @param {Array} p_aArgs Collection of arguments sent when the event
3212 * was fired.
3214 _onKeyPress: function (p_sType, p_aArgs) {
3216 var oEvent = p_aArgs[0];
3219 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3221 Event.preventDefault(oEvent);
3229 * @method _onTextResize
3230 * @description "textresize" event handler for the menu.
3231 * @protected
3232 * @param {String} p_sType String representing the name of the event that
3233 * was fired.
3234 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3235 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3236 * fired the event.
3238 _onTextResize: function (p_sType, p_aArgs, p_oMenu) {
3240 if (YAHOO.env.ua.gecko && !this._handleResize) {
3242 this._handleResize = true;
3243 return;
3248 var oConfig = this.cfg;
3250 if (oConfig.getProperty("position") == "dynamic") {
3252 oConfig.setProperty("width", (this._getOffsetWidth() + "px"));
3260 * @method _onScrollTargetMouseOver
3261 * @description "mouseover" event handler for the menu's "header" and "footer"
3262 * elements. Used to scroll the body of the menu up and down when the
3263 * menu's "maxheight" configuration property is set to a value greater than 0.
3264 * @protected
3265 * @param {Event} p_oEvent Object representing the DOM event object passed
3266 * back by the event utility (YAHOO.util.Event).
3267 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3268 * fired the event.
3270 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3272 this._cancelHideDelay();
3274 var oTarget = Event.getTarget(p_oEvent),
3275 oBody = this.body,
3276 me = this,
3277 nScrollTarget,
3278 fnScrollFunction;
3281 function scrollBodyDown() {
3283 var nScrollTop = oBody.scrollTop;
3286 if (nScrollTop < nScrollTarget) {
3288 oBody.scrollTop = (nScrollTop + 1);
3290 me._enableScrollHeader();
3293 else {
3295 oBody.scrollTop = nScrollTarget;
3297 window.clearInterval(me._nBodyScrollId);
3299 me._disableScrollFooter();
3306 function scrollBodyUp() {
3308 var nScrollTop = oBody.scrollTop;
3311 if (nScrollTop > 0) {
3313 oBody.scrollTop = (nScrollTop - 1);
3315 me._enableScrollFooter();
3318 else {
3320 oBody.scrollTop = 0;
3322 window.clearInterval(me._nBodyScrollId);
3324 me._disableScrollHeader();
3331 if (Dom.hasClass(oTarget, "hd")) {
3333 fnScrollFunction = scrollBodyUp;
3336 else {
3338 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3340 fnScrollFunction = scrollBodyDown;
3345 this._nBodyScrollId = window.setInterval(fnScrollFunction, 10);
3351 * @method _onScrollTargetMouseOut
3352 * @description "mouseout" event handler for the menu's "header" and "footer"
3353 * elements. Used to stop scrolling the body of the menu up and down when the
3354 * menu's "maxheight" configuration property is set to a value greater than 0.
3355 * @protected
3356 * @param {Event} p_oEvent Object representing the DOM event object passed
3357 * back by the event utility (YAHOO.util.Event).
3358 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3359 * fired the event.
3361 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3363 window.clearInterval(this._nBodyScrollId);
3365 this._cancelHideDelay();
3371 // Private methods
3375 * @method _onInit
3376 * @description "init" event handler for the menu.
3377 * @private
3378 * @param {String} p_sType String representing the name of the event that
3379 * was fired.
3380 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3382 _onInit: function (p_sType, p_aArgs) {
3384 this.cfg.subscribeToConfigEvent("width", this._onWidthChange);
3385 this.cfg.subscribeToConfigEvent("visible", this._onVisibleChange);
3387 var bRootMenu = !this.parent,
3388 bLazyLoad = this.lazyLoad;
3392 Automatically initialize a menu's subtree if:
3394 1) This is the root menu and lazyload is off
3396 2) This is the root menu, lazyload is on, but the menu is
3397 already visible
3399 3) This menu is a submenu and lazyload is off
3404 if (((bRootMenu && !bLazyLoad) ||
3405 (bRootMenu && (this.cfg.getProperty("visible") ||
3406 this.cfg.getProperty("position") == "static")) ||
3407 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3409 if (this.srcElement) {
3411 this._initSubTree();
3416 if (this.itemData) {
3418 this.addItems(this.itemData);
3423 else if (bLazyLoad) {
3425 this.cfg.fireQueue();
3433 * @method _onBeforeRender
3434 * @description "beforerender" event handler for the menu. Appends all of the
3435 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
3436 * title elements to the body element of the menu.
3437 * @private
3438 * @param {String} p_sType String representing the name of the event that
3439 * was fired.
3440 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3442 _onBeforeRender: function (p_sType, p_aArgs) {
3444 var oConfig = this.cfg,
3445 oEl = this.element,
3446 nListElements = this._aListElements.length,
3447 bFirstList = true,
3448 i = 0,
3449 oUL,
3450 oGroupTitle;
3452 if (nListElements > 0) {
3454 do {
3456 oUL = this._aListElements[i];
3458 if (oUL) {
3460 if (bFirstList) {
3462 Dom.addClass(oUL, "first-of-type");
3463 bFirstList = false;
3468 if (!Dom.isAncestor(oEl, oUL)) {
3470 this.appendToBody(oUL);
3475 oGroupTitle = this._aGroupTitleElements[i];
3477 if (oGroupTitle) {
3479 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3481 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3486 Dom.addClass(oUL, "hastitle");
3492 i++;
3495 while(i < nListElements);
3503 * @method _onRender
3504 * @description "render" event handler for the menu.
3505 * @private
3506 * @param {String} p_sType String representing the name of the event that
3507 * was fired.
3508 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3510 _onRender: function (p_sType, p_aArgs) {
3512 if (this.cfg.getProperty("position") == "dynamic" &&
3513 !this.cfg.getProperty("width")) {
3515 this._setWidth();
3523 * @method _onBeforeShow
3524 * @description "beforeshow" event handler for the menu.
3525 * @private
3526 * @param {String} p_sType String representing the name of the event that
3527 * was fired.
3528 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3530 _onBeforeShow: function (p_sType, p_aArgs) {
3532 var nOptions,
3534 nViewportHeight,
3535 oRegion,
3536 nMaxHeight,
3537 oBody,
3538 oSrcElement;
3541 if (this.lazyLoad && this.getItemGroups().length === 0) {
3543 if (this.srcElement) {
3545 this._initSubTree();
3550 if (this.itemData) {
3552 if (this.parent && this.parent.parent &&
3553 this.parent.parent.srcElement &&
3554 this.parent.parent.srcElement.tagName.toUpperCase() ==
3555 "SELECT") {
3557 nOptions = this.itemData.length;
3559 for(n=0; n<nOptions; n++) {
3561 if (this.itemData[n].tagName) {
3563 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3570 else {
3572 this.addItems(this.itemData);
3579 oSrcElement = this.srcElement;
3581 if (oSrcElement) {
3583 if (oSrcElement.tagName.toUpperCase() == "SELECT") {
3585 if (Dom.inDocument(oSrcElement)) {
3587 this.render(oSrcElement.parentNode);
3590 else {
3592 this.render(this.cfg.getProperty("container"));
3597 else {
3599 this.render();
3604 else {
3606 if (this.parent) {
3608 this.render(this.parent.element);
3611 else {
3613 this.render(this.cfg.getProperty("container"));
3614 this.cfg.refireEvent("xy");
3623 if (!(this instanceof YAHOO.widget.MenuBar) &&
3624 this.cfg.getProperty("position") == "dynamic") {
3626 nViewportHeight = Dom.getViewportHeight();
3629 if (this.parent && this.parent.parent instanceof YAHOO.widget.MenuBar) {
3631 oRegion = YAHOO.util.Region.getRegion(this.parent.element);
3633 nViewportHeight = (nViewportHeight - oRegion.bottom);
3638 if (this.element.offsetHeight >= nViewportHeight) {
3640 nMaxHeight = this.cfg.getProperty("maxheight");
3643 Cache the original value for the "maxheight" configuration
3644 property so that we can set it back when the menu is hidden.
3647 this._nMaxHeight = nMaxHeight;
3649 this.cfg.setProperty("maxheight", (nViewportHeight - 20));
3654 if (this.cfg.getProperty("maxheight") > 0) {
3656 oBody = this.body;
3658 if (oBody.scrollTop > 0) {
3660 oBody.scrollTop = 0;
3664 this._disableScrollHeader();
3665 this._enableScrollFooter();
3676 * @method _onShow
3677 * @description "show" event handler for the menu.
3678 * @private
3679 * @param {String} p_sType String representing the name of the event that
3680 * was fired.
3681 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3683 _onShow: function (p_sType, p_aArgs) {
3685 var oParent = this.parent,
3686 oParentMenu,
3687 aParentAlignment,
3688 aAlignment;
3691 function disableAutoSubmenuDisplay(p_oEvent) {
3693 var oTarget;
3695 if (p_oEvent.type == "mousedown" || (p_oEvent.type == "keydown" &&
3696 p_oEvent.keyCode == 27)) {
3699 Set the "autosubmenudisplay" to "false" if the user
3700 clicks outside the menu bar.
3703 oTarget = Event.getTarget(p_oEvent);
3705 if (oTarget != oParentMenu.element ||
3706 !Dom.isAncestor(oParentMenu.element, oTarget)) {
3708 oParentMenu.cfg.setProperty("autosubmenudisplay", false);
3710 Event.removeListener(document, "mousedown",
3711 disableAutoSubmenuDisplay);
3713 Event.removeListener(document, "keydown",
3714 disableAutoSubmenuDisplay);
3723 if (oParent) {
3725 oParentMenu = oParent.parent;
3726 aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
3727 aAlignment = this.cfg.getProperty("submenualignment");
3730 if ((aParentAlignment[0] != aAlignment[0]) &&
3731 (aParentAlignment[1] != aAlignment[1])) {
3733 this.cfg.setProperty("submenualignment",
3734 [aParentAlignment[0], aParentAlignment[1]]);
3739 if (!oParentMenu.cfg.getProperty("autosubmenudisplay") &&
3740 (oParentMenu instanceof YAHOO.widget.MenuBar ||
3741 oParentMenu.cfg.getProperty("position") == "static")) {
3743 oParentMenu.cfg.setProperty("autosubmenudisplay", true);
3745 Event.on(document, "mousedown", disableAutoSubmenuDisplay);
3746 Event.on(document, "keydown", disableAutoSubmenuDisplay);
3756 * @method _onBeforeHide
3757 * @description "beforehide" event handler for the menu.
3758 * @private
3759 * @param {String} p_sType String representing the name of the event that
3760 * was fired.
3761 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3763 _onBeforeHide: function (p_sType, p_aArgs) {
3765 var oActiveItem = this.activeItem,
3766 oConfig,
3767 oSubmenu;
3769 if (oActiveItem) {
3771 oConfig = oActiveItem.cfg;
3773 oConfig.setProperty("selected", false);
3775 oSubmenu = oConfig.getProperty("submenu");
3777 if (oSubmenu) {
3779 oSubmenu.hide();
3785 if (this.getRoot() == this) {
3787 this.blur();
3795 * @method _onHide
3796 * @description "hide" event handler for the menu.
3797 * @private
3798 * @param {String} p_sType String representing the name of the event that
3799 * was fired.
3800 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3802 _onHide: function (p_sType, p_aArgs) {
3804 if (this._nMaxHeight != -1) {
3806 this.cfg.setProperty("maxheight", this._nMaxHeight);
3808 this._nMaxHeight = -1;
3816 * @method _onParentMenuConfigChange
3817 * @description "configchange" event handler for a submenu.
3818 * @private
3819 * @param {String} p_sType String representing the name of the event that
3820 * was fired.
3821 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3822 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3823 * subscribed to the event.
3825 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
3827 var sPropertyName = p_aArgs[0][0],
3828 oPropertyValue = p_aArgs[0][1];
3830 switch(sPropertyName) {
3832 case "iframe":
3833 case "constraintoviewport":
3834 case "hidedelay":
3835 case "showdelay":
3836 case "submenuhidedelay":
3837 case "clicktohide":
3838 case "effect":
3839 case "classname":
3841 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
3843 break;
3851 * @method _onParentMenuRender
3852 * @description "render" event handler for a submenu. Renders a
3853 * submenu in response to the firing of its parent's "render" event.
3854 * @private
3855 * @param {String} p_sType String representing the name of the event that
3856 * was fired.
3857 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3858 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3859 * subscribed to the event.
3861 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
3863 var oParentMenu = p_oSubmenu.parent.parent,
3865 oConfig = {
3867 constraintoviewport:
3868 oParentMenu.cfg.getProperty("constraintoviewport"),
3870 xy: [0,0],
3872 clicktohide: oParentMenu.cfg.getProperty("clicktohide"),
3874 effect: oParentMenu.cfg.getProperty("effect"),
3876 showdelay: oParentMenu.cfg.getProperty("showdelay"),
3878 hidedelay: oParentMenu.cfg.getProperty("hidedelay"),
3880 submenuhidedelay: oParentMenu.cfg.getProperty("submenuhidedelay"),
3882 classname: oParentMenu.cfg.getProperty("classname")
3886 oLI;
3890 Only sync the "iframe" configuration property if the parent
3891 menu's "position" configuration is the same.
3894 if (this.cfg.getProperty("position") ==
3895 oParentMenu.cfg.getProperty("position")) {
3897 oConfig.iframe = oParentMenu.cfg.getProperty("iframe");
3902 p_oSubmenu.cfg.applyConfig(oConfig);
3905 if (!this.lazyLoad) {
3907 oLI = this.parent.element;
3909 if (this.element.parentNode == oLI) {
3911 this.render();
3914 else {
3916 this.render(oLI);
3926 * @method _onSubmenuBeforeShow
3927 * @description "beforeshow" event handler for a submenu.
3928 * @private
3929 * @param {String} p_sType String representing the name of the event that
3930 * was fired.
3931 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3933 _onSubmenuBeforeShow: function (p_sType, p_aArgs) {
3935 var oParent = this.parent,
3936 aAlignment = oParent.parent.cfg.getProperty("submenualignment");
3938 this.cfg.setProperty("context",
3939 [oParent.element, aAlignment[0], aAlignment[1]]);
3942 var nScrollTop = oParent.parent.body.scrollTop;
3944 if ((YAHOO.env.ua.gecko || YAHOO.env.ua.webkit) && nScrollTop > 0) {
3946 this.cfg.setProperty("y", (this.cfg.getProperty("y") - nScrollTop));
3954 * @method _onSubmenuShow
3955 * @description "show" event handler for a submenu.
3956 * @private
3957 * @param {String} p_sType String representing the name of the event that
3958 * was fired.
3959 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3961 _onSubmenuShow: function (p_sType, p_aArgs) {
3963 this.submenuIndicator.innerHTML = this.EXPANDED_SUBMENU_INDICATOR_TEXT;
3969 * @method _onSubmenuHide
3970 * @description "hide" Custom Event handler for a submenu.
3971 * @private
3972 * @param {String} p_sType String representing the name of the event that
3973 * was fired.
3974 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3976 _onSubmenuHide: function (p_sType, p_aArgs) {
3978 this.submenuIndicator.innerHTML = this.COLLAPSED_SUBMENU_INDICATOR_TEXT;
3984 * @method _onMenuItemFocus
3985 * @description "focus" event handler for the menu's items.
3986 * @private
3987 * @param {String} p_sType String representing the name of the event that
3988 * was fired.
3989 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3991 _onMenuItemFocus: function (p_sType, p_aArgs) {
3993 this.parent.focusEvent.fire(this);
3999 * @method _onMenuItemBlur
4000 * @description "blur" event handler for the menu's items.
4001 * @private
4002 * @param {String} p_sType String representing the name of the event
4003 * that was fired.
4004 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4006 _onMenuItemBlur: function (p_sType, p_aArgs) {
4008 this.parent.blurEvent.fire(this);
4014 * @method _onMenuItemConfigChange
4015 * @description "configchange" event handler for the menu's items.
4016 * @private
4017 * @param {String} p_sType String representing the name of the event that
4018 * was fired.
4019 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4020 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4021 * that fired the event.
4023 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4025 var sPropertyName = p_aArgs[0][0],
4026 oPropertyValue = p_aArgs[0][1],
4027 sWidth,
4028 oSubmenu;
4030 switch(sPropertyName) {
4032 case "selected":
4034 if (oPropertyValue === true) {
4036 this.activeItem = p_oItem;
4040 break;
4042 case "submenu":
4044 oSubmenu = p_aArgs[0][1];
4046 if (oSubmenu) {
4048 this._configureSubmenu(p_oItem);
4052 break;
4054 case "text":
4055 case "helptext":
4058 A change to an item's "text" or "helptext"
4059 configuration properties requires the width of the parent
4060 menu to be recalculated.
4063 if (this.element.style.width) {
4065 sWidth = this._getOffsetWidth() + "px";
4067 Dom.setStyle(this.element, "width", sWidth);
4071 break;
4079 // Public event handlers for configuration properties
4083 * @method enforceConstraints
4084 * @description The default event handler executed when the moveEvent is fired,
4085 * if the "constraintoviewport" configuration property is set to true.
4086 * @param {String} type The name of the event that was fired.
4087 * @param {Array} args Collection of arguments sent when the
4088 * event was fired.
4089 * @param {Array} obj Array containing the current Menu instance
4090 * and the item that fired the event.
4092 enforceConstraints: function (type, args, obj) {
4094 var oParentMenuItem = this.parent,
4095 oElement,
4096 oConfig,
4097 pos,
4100 offsetHeight,
4101 offsetWidth,
4102 viewPortWidth,
4103 viewPortHeight,
4104 scrollX,
4105 scrollY,
4106 nPadding,
4107 topConstraint,
4108 leftConstraint,
4109 bottomConstraint,
4110 rightConstraint,
4111 aContext,
4112 oContextElement;
4115 if (oParentMenuItem &&
4116 !(oParentMenuItem.parent instanceof YAHOO.widget.MenuBar)) {
4118 oElement = this.element;
4120 oConfig = this.cfg;
4121 pos = args[0];
4123 x = pos[0];
4124 y = pos[1];
4126 offsetHeight = oElement.offsetHeight;
4127 offsetWidth = oElement.offsetWidth;
4129 viewPortWidth = Dom.getViewportWidth();
4130 viewPortHeight = Dom.getViewportHeight();
4132 scrollX = Dom.getDocumentScrollLeft();
4133 scrollY = Dom.getDocumentScrollTop();
4135 nPadding =
4136 (oParentMenuItem.parent instanceof YAHOO.widget.MenuBar) ? 0 : 10;
4138 topConstraint = scrollY + nPadding;
4139 leftConstraint = scrollX + nPadding;
4141 bottomConstraint = scrollY + viewPortHeight - offsetHeight - nPadding;
4142 rightConstraint = scrollX + viewPortWidth - offsetWidth - nPadding;
4144 aContext = oConfig.getProperty("context");
4145 oContextElement = aContext ? aContext[0] : null;
4148 if (x < 10) {
4150 x = leftConstraint;
4152 } else if ((x + offsetWidth) > viewPortWidth) {
4154 if (oContextElement &&
4155 ((x - oContextElement.offsetWidth) > offsetWidth)) {
4157 x = (x - (oContextElement.offsetWidth + offsetWidth));
4160 else {
4162 x = rightConstraint;
4168 if (y < 10) {
4170 y = topConstraint;
4172 } else if (y > bottomConstraint) {
4174 if (oContextElement && (y > offsetHeight)) {
4176 y = ((y + oContextElement.offsetHeight) - offsetHeight);
4179 else {
4181 y = bottomConstraint;
4187 oConfig.setProperty("x", x, true);
4188 oConfig.setProperty("y", y, true);
4189 oConfig.setProperty("xy", [x,y], true);
4192 else if (this == this.getRoot() &&
4193 this.cfg.getProperty("position") == "dynamic") {
4195 Menu.superclass.enforceConstraints.call(this, type, args, obj);
4203 * @method configVisible
4204 * @description Event handler for when the "visible" configuration property
4205 * the menu changes.
4206 * @param {String} p_sType String representing the name of the event that
4207 * was fired.
4208 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4209 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4210 * fired the event.
4212 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4214 var bVisible,
4215 sDisplay;
4217 if (this.cfg.getProperty("position") == "dynamic") {
4219 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4222 else {
4224 bVisible = p_aArgs[0];
4225 sDisplay = Dom.getStyle(this.element, "display");
4227 if (bVisible) {
4229 if (sDisplay != "block") {
4230 this.beforeShowEvent.fire();
4231 Dom.setStyle(this.element, "display", "block");
4232 this.showEvent.fire();
4236 else {
4238 if (sDisplay == "block") {
4239 this.beforeHideEvent.fire();
4240 Dom.setStyle(this.element, "display", "none");
4241 this.hideEvent.fire();
4252 * @method configPosition
4253 * @description Event handler for when the "position" configuration property
4254 * of the menu changes.
4255 * @param {String} p_sType String representing the name of the event that
4256 * was fired.
4257 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4258 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4259 * fired the event.
4261 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4263 var oElement = this.element,
4264 sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute",
4265 sCurrentPosition = Dom.getStyle(oElement, "position"),
4266 oCfg = this.cfg,
4267 nZIndex;
4270 Dom.setStyle(this.element, "position", sCSSPosition);
4273 if (sCSSPosition == "static") {
4276 Remove the iframe for statically positioned menus since it will
4277 intercept mouse events.
4280 oCfg.setProperty("iframe", false);
4283 // Statically positioned menus are visible by default
4285 Dom.setStyle(this.element, "display", "block");
4287 oCfg.setProperty("visible", true);
4290 else {
4292 if (sCurrentPosition != "absolute") {
4294 oCfg.setProperty("iframe", (YAHOO.env.ua.ie == 6 ? true : false));
4299 Even though the "visible" property is queued to
4300 "false" by default, we need to set the "visibility" property to
4301 "hidden" since Overlay's "configVisible" implementation checks the
4302 element's "visibility" style property before deciding whether
4303 or not to show an Overlay instance.
4306 Dom.setStyle(this.element, "visibility", "hidden");
4311 if (sCSSPosition == "absolute") {
4313 nZIndex = oCfg.getProperty("zindex");
4315 if (!nZIndex || nZIndex === 0) {
4317 nZIndex = this.parent ?
4318 (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;
4320 oCfg.setProperty("zindex", nZIndex);
4330 * @method configIframe
4331 * @description Event handler for when the "iframe" configuration property of
4332 * the menu changes.
4333 * @param {String} p_sType String representing the name of the event that
4334 * was fired.
4335 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4336 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4337 * fired the event.
4339 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4341 if (this.cfg.getProperty("position") == "dynamic") {
4343 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4351 * @method configHideDelay
4352 * @description Event handler for when the "hidedelay" configuration property
4353 * of the menu changes.
4354 * @param {String} p_sType String representing the name of the event that
4355 * was fired.
4356 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4357 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4358 * fired the event.
4360 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4362 var nHideDelay = p_aArgs[0],
4363 oMouseOutEvent = this.mouseOutEvent,
4364 oMouseOverEvent = this.mouseOverEvent,
4365 oKeyDownEvent = this.keyDownEvent;
4367 if (nHideDelay > 0) {
4370 Only assign event handlers once. This way the user change
4371 the value for the hidedelay as many times as they want.
4374 if (!this._bHideDelayEventHandlersAssigned) {
4376 oMouseOutEvent.subscribe(this._execHideDelay);
4377 oMouseOverEvent.subscribe(this._cancelHideDelay);
4378 oKeyDownEvent.subscribe(this._cancelHideDelay);
4380 this._bHideDelayEventHandlersAssigned = true;
4385 else {
4387 oMouseOutEvent.unsubscribe(this._execHideDelay);
4388 oMouseOverEvent.unsubscribe(this._cancelHideDelay);
4389 oKeyDownEvent.unsubscribe(this._cancelHideDelay);
4391 this._bHideDelayEventHandlersAssigned = false;
4399 * @method configContainer
4400 * @description Event handler for when the "container" configuration property
4401 of the menu changes.
4402 * @param {String} p_sType String representing the name of the event that
4403 * was fired.
4404 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4405 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4406 * fired the event.
4408 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4410 var oElement = p_aArgs[0];
4412 if (typeof oElement == 'string') {
4414 this.cfg.setProperty("container", document.getElementById(oElement),
4415 true);
4423 * @method _setMaxHeight
4424 * @description "renderEvent" handler used to defer the setting of the
4425 * "maxheight" configuration property until the menu is rendered in lazy
4426 * load scenarios.
4427 * @param {String} p_sType The name of the event that was fired.
4428 * @param {Array} p_aArgs Collection of arguments sent when the event
4429 * was fired.
4430 * @param {Number} p_nMaxHeight Number representing the value to set for the
4431 * "maxheight" configuration property.
4432 * @private
4434 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4436 this.cfg.setProperty("maxheight", p_nMaxHeight);
4437 this.renderEvent.unsubscribe(this._setMaxHeight);
4443 * @method configMaxHeight
4444 * @description Event handler for when the "maxheight" configuration property of
4445 * a Menu changes.
4446 * @param {String} p_sType The name of the event that was fired.
4447 * @param {Array} p_aArgs Collection of arguments sent when the event
4448 * was fired.
4449 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4450 * the event.
4452 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4454 var nMaxHeight = p_aArgs[0],
4455 oBody = this.body,
4456 oHeader = this.header,
4457 oFooter = this.footer,
4458 fnMouseOver = this._onScrollTargetMouseOver,
4459 fnMouseOut = this._onScrollTargetMouseOut,
4460 nHeight;
4463 if (this.lazyLoad && !oBody) {
4465 this.renderEvent.unsubscribe(this._setMaxHeight);
4467 if (nMaxHeight > 0) {
4469 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4473 return;
4477 Dom.setStyle(oBody, "height", "auto");
4478 Dom.setStyle(oBody, "overflow", "visible");
4481 if ((nMaxHeight > 0) && (oBody.offsetHeight > nMaxHeight)) {
4483 if (!this.cfg.getProperty("width")) {
4485 this._setWidth();
4489 if (!oHeader && !oFooter) {
4491 this.setHeader("&#32;");
4492 this.setFooter("&#32;");
4494 oHeader = this.header;
4495 oFooter = this.footer;
4497 Dom.addClass(oHeader, "topscrollbar");
4498 Dom.addClass(oFooter, "bottomscrollbar");
4500 this.element.insertBefore(oHeader, oBody);
4501 this.element.appendChild(oFooter);
4503 Event.on(oHeader, "mouseover", fnMouseOver, this, true);
4504 Event.on(oHeader, "mouseout", fnMouseOut, this, true);
4505 Event.on(oFooter, "mouseover", fnMouseOver, this, true);
4506 Event.on(oFooter, "mouseout", fnMouseOut, this, true);
4510 nHeight = (nMaxHeight - (this.footer.offsetHeight +
4511 this.header.offsetHeight));
4513 Dom.setStyle(oBody, "height", (nHeight + "px"));
4514 Dom.setStyle(oBody, "overflow", "hidden");
4517 else if (oHeader && oFooter) {
4519 Dom.setStyle(oBody, "height", "auto");
4520 Dom.setStyle(oBody, "overflow", "visible");
4522 Event.removeListener(oHeader, "mouseover", fnMouseOver);
4523 Event.removeListener(oHeader, "mouseout", fnMouseOut);
4524 Event.removeListener(oFooter, "mouseover", fnMouseOver);
4525 Event.removeListener(oFooter, "mouseout", fnMouseOut);
4527 this.element.removeChild(oHeader);
4528 this.element.removeChild(oFooter);
4530 this.header = null;
4531 this.footer = null;
4535 this.cfg.refireEvent("iframe");
4541 * @method configClassName
4542 * @description Event handler for when the "classname" configuration property of
4543 * a menu changes.
4544 * @param {String} p_sType The name of the event that was fired.
4545 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4546 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4548 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4550 var sClassName = p_aArgs[0];
4552 if (this._sClassName) {
4554 Dom.removeClass(this.element, this._sClassName);
4558 Dom.addClass(this.element, sClassName);
4559 this._sClassName = sClassName;
4565 * @method _onItemAdded
4566 * @description "itemadded" event handler for a Menu instance.
4567 * @private
4568 * @param {String} p_sType The name of the event that was fired.
4569 * @param {Array} p_aArgs Collection of arguments sent when the event
4570 * was fired.
4572 _onItemAdded: function (p_sType, p_aArgs) {
4574 var oItem = p_aArgs[0];
4576 if (oItem) {
4578 oItem.cfg.setProperty("disabled", true);
4586 * @method configDisabled
4587 * @description Event handler for when the "disabled" configuration property of
4588 * a menu changes.
4589 * @param {String} p_sType The name of the event that was fired.
4590 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4591 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4593 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4595 var bDisabled = p_aArgs[0],
4596 aItems,
4597 nItems,
4600 if (this._bDisabled != bDisabled) {
4602 aItems = this.getItems();
4603 nItems = aItems.length;
4605 if (nItems > 0) {
4607 i = nItems - 1;
4609 do {
4611 aItems[i].cfg.setProperty("disabled", bDisabled);
4614 while (i--);
4618 Dom[(bDisabled ? "addClass" : "removeClass")](this.element, "disabled");
4620 this.itemAddedEvent[(bDisabled ? "subscribe" : "unsubscribe")](
4621 this._onItemAdded);
4623 this._bDisabled = bDisabled;
4631 * @method onRender
4632 * @description "render" event handler for the menu.
4633 * @param {String} p_sType String representing the name of the event that
4634 * was fired.
4635 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4637 onRender: function (p_sType, p_aArgs) {
4639 function sizeShadow() {
4641 var oElement = this.element,
4642 oShadow = this._shadow;
4644 if (oShadow) {
4646 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
4647 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
4654 function addShadowVisibleClass() {
4656 Dom.addClass(this._shadow, "yui-menu-shadow-visible");
4661 function removeShadowVisibleClass() {
4663 Dom.removeClass(this._shadow, "yui-menu-shadow-visible");
4668 function createShadow() {
4670 var oShadow = this._shadow,
4671 oElement,
4674 if (!oShadow) {
4676 oElement = this.element;
4677 me = this;
4679 if (!m_oShadowTemplate) {
4681 m_oShadowTemplate = document.createElement("div");
4682 m_oShadowTemplate.className = "yui-menu-shadow";
4686 oShadow = m_oShadowTemplate.cloneNode(false);
4688 oElement.appendChild(oShadow);
4690 this._shadow = oShadow;
4692 addShadowVisibleClass.call(this);
4694 this.beforeShowEvent.subscribe(addShadowVisibleClass);
4695 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
4697 if (YAHOO.env.ua.ie) {
4700 Need to call sizeShadow & syncIframe via setTimeout for
4701 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
4702 or the shadow and iframe shim will not be sized and
4703 positioned properly.
4706 window.setTimeout(function () {
4708 sizeShadow.call(me);
4709 me.syncIframe();
4711 }, 0);
4713 this.cfg.subscribeToConfigEvent("width", sizeShadow);
4714 this.cfg.subscribeToConfigEvent("height", sizeShadow);
4715 this.changeContentEvent.subscribe(sizeShadow);
4717 Module.textResizeEvent.subscribe(sizeShadow, me, true);
4719 this.destroyEvent.subscribe(function () {
4721 Module.textResizeEvent.unsubscribe(sizeShadow, me);
4732 function onBeforeShow() {
4734 createShadow.call(this);
4736 this.beforeShowEvent.unsubscribe(onBeforeShow);
4741 if (this.cfg.getProperty("position") == "dynamic") {
4743 if (this.cfg.getProperty("visible")) {
4745 createShadow.call(this);
4748 else {
4750 this.beforeShowEvent.subscribe(onBeforeShow);
4759 // Public methods
4763 * @method initEvents
4764 * @description Initializes the custom events for the menu.
4766 initEvents: function () {
4768 Menu.superclass.initEvents.call(this);
4770 // Create custom events
4772 var SIGNATURE = CustomEvent.LIST;
4774 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
4775 this.mouseOverEvent.signature = SIGNATURE;
4777 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
4778 this.mouseOutEvent.signature = SIGNATURE;
4780 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
4781 this.mouseDownEvent.signature = SIGNATURE;
4783 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
4784 this.mouseUpEvent.signature = SIGNATURE;
4786 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
4787 this.clickEvent.signature = SIGNATURE;
4789 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
4790 this.keyPressEvent.signature = SIGNATURE;
4792 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
4793 this.keyDownEvent.signature = SIGNATURE;
4795 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
4796 this.keyUpEvent.signature = SIGNATURE;
4798 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
4799 this.focusEvent.signature = SIGNATURE;
4801 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
4802 this.blurEvent.signature = SIGNATURE;
4804 this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED);
4805 this.itemAddedEvent.signature = SIGNATURE;
4807 this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED);
4808 this.itemRemovedEvent.signature = SIGNATURE;
4814 * @method getRoot
4815 * @description Finds the menu's root menu.
4817 getRoot: function () {
4819 var oItem = this.parent,
4820 oParentMenu;
4822 if (oItem) {
4824 oParentMenu = oItem.parent;
4826 return oParentMenu ? oParentMenu.getRoot() : this;
4829 else {
4831 return this;
4839 * @method toString
4840 * @description Returns a string representing the menu.
4841 * @return {String}
4843 toString: function () {
4845 var sReturnVal = "Menu",
4846 sId = this.id;
4848 if (sId) {
4850 sReturnVal += (" " + sId);
4854 return sReturnVal;
4860 * @method setItemGroupTitle
4861 * @description Sets the title of a group of menu items.
4862 * @param {String} p_sGroupTitle String specifying the title of the group.
4863 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
4864 * the title belongs.
4866 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
4868 var nGroupIndex,
4869 oTitle,
4871 nFirstIndex;
4873 if (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {
4875 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
4876 oTitle = this._aGroupTitleElements[nGroupIndex];
4879 if (oTitle) {
4881 oTitle.innerHTML = p_sGroupTitle;
4884 else {
4886 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
4888 oTitle.innerHTML = p_sGroupTitle;
4890 this._aGroupTitleElements[nGroupIndex] = oTitle;
4895 i = this._aGroupTitleElements.length - 1;
4897 do {
4899 if (this._aGroupTitleElements[i]) {
4901 Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");
4903 nFirstIndex = i;
4908 while(i--);
4911 if (nFirstIndex !== null) {
4913 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
4914 "first-of-type");
4918 this.changeContentEvent.fire();
4927 * @method addItem
4928 * @description Appends an item to the menu.
4929 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4930 * instance to be added to the menu.
4931 * @param {String} p_oItem String specifying the text of the item to be added
4932 * to the menu.
4933 * @param {Object} p_oItem Object literal containing a set of menu item
4934 * configuration properties.
4935 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
4936 * which the item belongs.
4937 * @return {YAHOO.widget.MenuItem}
4939 addItem: function (p_oItem, p_nGroupIndex) {
4941 if (p_oItem) {
4943 return this._addItemToGroup(p_nGroupIndex, p_oItem);
4951 * @method addItems
4952 * @description Adds an array of items to the menu.
4953 * @param {Array} p_aItems Array of items to be added to the menu. The array
4954 * can contain strings specifying the text for each item to be created, object
4955 * literals specifying each of the menu item configuration properties,
4956 * or MenuItem instances.
4957 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
4958 * which the items belongs.
4959 * @return {Array}
4961 addItems: function (p_aItems, p_nGroupIndex) {
4963 var nItems,
4964 aItems,
4965 oItem,
4968 if (Lang.isArray(p_aItems)) {
4970 nItems = p_aItems.length;
4971 aItems = [];
4973 for(i=0; i<nItems; i++) {
4975 oItem = p_aItems[i];
4977 if (oItem) {
4979 if (Lang.isArray(oItem)) {
4981 aItems[aItems.length] = this.addItems(oItem, i);
4984 else {
4986 aItems[aItems.length] =
4987 this._addItemToGroup(p_nGroupIndex, oItem);
4996 if (aItems.length) {
4998 return aItems;
5008 * @method insertItem
5009 * @description Inserts an item into the menu at the specified index.
5010 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5011 * instance to be added to the menu.
5012 * @param {String} p_oItem String specifying the text of the item to be added
5013 * to the menu.
5014 * @param {Object} p_oItem Object literal containing a set of menu item
5015 * configuration properties.
5016 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5017 * the item should be added.
5018 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5019 * the item belongs.
5020 * @return {YAHOO.widget.MenuItem}
5022 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5024 if (p_oItem) {
5026 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5034 * @method removeItem
5035 * @description Removes the specified item from the menu.
5036 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5037 * instance to be removed from the menu.
5038 * @param {Number} p_oObject Number specifying the index of the item
5039 * to be removed.
5040 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5041 * which the item belongs.
5042 * @return {YAHOO.widget.MenuItem}
5044 removeItem: function (p_oObject, p_nGroupIndex) {
5046 var oItem;
5048 if (typeof p_oObject != "undefined") {
5050 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5052 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5055 else if (typeof p_oObject == "number") {
5057 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5061 if (oItem) {
5063 oItem.destroy();
5065 this.logger.log("Item removed." +
5066 " Text: " + oItem.cfg.getProperty("text") + ", " +
5067 " Index: " + oItem.index + ", " +
5068 " Group Index: " + oItem.groupIndex);
5070 return oItem;
5080 * @method getItems
5081 * @description Returns an array of all of the items in the menu.
5082 * @return {Array}
5084 getItems: function () {
5086 var aGroups = this._aItemGroups,
5087 nGroups = aGroups.length;
5089 return ((nGroups == 1) ? aGroups[0] :
5090 (Array.prototype.concat.apply([], aGroups)));
5096 * @method getItemGroups
5097 * @description Multi-dimensional Array representing the menu items as they
5098 * are grouped in the menu.
5099 * @return {Array}
5101 getItemGroups: function () {
5103 return this._aItemGroups;
5109 * @method getItem
5110 * @description Returns the item at the specified index.
5111 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5112 * item to be retrieved.
5113 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5114 * the item belongs.
5115 * @return {YAHOO.widget.MenuItem}
5117 getItem: function (p_nItemIndex, p_nGroupIndex) {
5119 var aGroup;
5121 if (typeof p_nItemIndex == "number") {
5123 aGroup = this._getItemGroup(p_nGroupIndex);
5125 if (aGroup) {
5127 return aGroup[p_nItemIndex];
5137 * @method getSubmenus
5138 * @description Returns an array of all of the submenus that are immediate
5139 * children of the menu.
5140 * @return {Array}
5142 getSubmenus: function () {
5144 var aItems = this.getItems(),
5145 nItems = aItems.length,
5146 aSubmenus,
5147 oSubmenu,
5148 oItem,
5152 if (nItems > 0) {
5154 aSubmenus = [];
5156 for(i=0; i<nItems; i++) {
5158 oItem = aItems[i];
5160 if (oItem) {
5162 oSubmenu = oItem.cfg.getProperty("submenu");
5164 if (oSubmenu) {
5166 aSubmenus[aSubmenus.length] = oSubmenu;
5176 return aSubmenus;
5181 * @method clearContent
5182 * @description Removes all of the content from the menu, including the menu
5183 * items, group titles, header and footer.
5185 clearContent: function () {
5187 var aItems = this.getItems(),
5188 nItems = aItems.length,
5189 oElement = this.element,
5190 oBody = this.body,
5191 oHeader = this.header,
5192 oFooter = this.footer,
5193 oItem,
5194 oSubmenu,
5198 if (nItems > 0) {
5200 i = nItems - 1;
5202 do {
5204 oItem = aItems[i];
5206 if (oItem) {
5208 oSubmenu = oItem.cfg.getProperty("submenu");
5210 if (oSubmenu) {
5212 this.cfg.configChangedEvent.unsubscribe(
5213 this._onParentMenuConfigChange, oSubmenu);
5215 this.renderEvent.unsubscribe(this._onParentMenuRender,
5216 oSubmenu);
5220 this.removeItem(oItem);
5225 while(i--);
5230 if (oHeader) {
5232 Event.purgeElement(oHeader);
5233 oElement.removeChild(oHeader);
5238 if (oFooter) {
5240 Event.purgeElement(oFooter);
5241 oElement.removeChild(oFooter);
5245 if (oBody) {
5247 Event.purgeElement(oBody);
5249 oBody.innerHTML = "";
5254 this._aItemGroups = [];
5255 this._aListElements = [];
5256 this._aGroupTitleElements = [];
5258 this.cfg.setProperty("width", null);
5264 * @method destroy
5265 * @description Removes the menu's <code>&#60;div&#62;</code> element
5266 * (and accompanying child nodes) from the document.
5268 destroy: function () {
5270 Module.textResizeEvent.unsubscribe(this._onTextResize, this);
5273 // Remove all items
5275 this.clearContent();
5277 this._aItemGroups = null;
5278 this._aListElements = null;
5279 this._aGroupTitleElements = null;
5282 // Continue with the superclass implementation of this method
5284 Menu.superclass.destroy.call(this);
5286 this.logger.log("Destroyed.");
5292 * @method setInitialFocus
5293 * @description Sets focus to the menu's first enabled item.
5295 setInitialFocus: function () {
5297 var oItem = this._getFirstEnabledItem();
5299 if (oItem) {
5301 oItem.focus();
5309 * @method setInitialSelection
5310 * @description Sets the "selected" configuration property of the menu's first
5311 * enabled item to "true."
5313 setInitialSelection: function () {
5315 var oItem = this._getFirstEnabledItem();
5317 if (oItem) {
5319 oItem.cfg.setProperty("selected", true);
5326 * @method clearActiveItem
5327 * @description Sets the "selected" configuration property of the menu's active
5328 * item to "false" and hides the item's submenu.
5329 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5330 * should be blurred.
5332 clearActiveItem: function (p_bBlur) {
5334 if (this.cfg.getProperty("showdelay") > 0) {
5336 this._cancelShowDelay();
5341 var oActiveItem = this.activeItem,
5342 oConfig,
5343 oSubmenu;
5345 if (oActiveItem) {
5347 oConfig = oActiveItem.cfg;
5349 if (p_bBlur) {
5351 oActiveItem.blur();
5355 oConfig.setProperty("selected", false);
5357 oSubmenu = oConfig.getProperty("submenu");
5359 if (oSubmenu) {
5361 oSubmenu.hide();
5365 this.activeItem = null;
5373 * @method focus
5374 * @description Causes the menu to receive focus and fires the "focus" event.
5376 focus: function () {
5378 if (!this.hasFocus()) {
5380 this.setInitialFocus();
5388 * @method blur
5389 * @description Causes the menu to lose focus and fires the "blur" event.
5391 blur: function () {
5393 var oItem;
5395 if (this.hasFocus()) {
5397 oItem = MenuManager.getFocusedMenuItem();
5399 if (oItem) {
5401 oItem.blur();
5411 * @method hasFocus
5412 * @description Returns a boolean indicating whether or not the menu has focus.
5413 * @return {Boolean}
5415 hasFocus: function () {
5417 return (MenuManager.getFocusedMenu() == this.getRoot());
5423 * Adds the specified CustomEvent subscriber to the menu and each of
5424 * its submenus.
5425 * @method subscribe
5426 * @param p_type {string} the type, or name of the event
5427 * @param p_fn {function} the function to exectute when the event fires
5428 * @param p_obj {Object} An object to be passed along when the event
5429 * fires
5430 * @param p_override {boolean} If true, the obj passed in becomes the
5431 * execution scope of the listener
5433 subscribe: function () {
5435 function onItemAdded(p_sType, p_aArgs, p_oObject) {
5437 var oItem = p_aArgs[0],
5438 oSubmenu = oItem.cfg.getProperty("submenu");
5440 if (oSubmenu) {
5442 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5449 Menu.superclass.subscribe.apply(this, arguments);
5450 Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments);
5453 var aSubmenus = this.getSubmenus(),
5454 nSubmenus,
5455 oSubmenu,
5458 if (aSubmenus) {
5460 nSubmenus = aSubmenus.length;
5462 if (nSubmenus > 0) {
5464 i = nSubmenus - 1;
5466 do {
5468 oSubmenu = aSubmenus[i];
5470 oSubmenu.subscribe.apply(oSubmenu, arguments);
5473 while(i--);
5483 * @description Initializes the class's configurable properties which can be
5484 * changed using the menu's Config object ("cfg").
5485 * @method initDefaultConfig
5487 initDefaultConfig: function () {
5489 Menu.superclass.initDefaultConfig.call(this);
5491 var oConfig = this.cfg;
5493 // Add configuration attributes
5496 Change the default value for the "visible" configuration
5497 property to "false" by re-adding the property.
5501 * @config visible
5502 * @description Boolean indicating whether or not the menu is visible. If
5503 * the menu's "position" configuration property is set to "dynamic" (the
5504 * default), this property toggles the menu's <code>&#60;div&#62;</code>
5505 * element's "visibility" style property between "visible" (true) or
5506 * "hidden" (false). If the menu's "position" configuration property is
5507 * set to "static" this property toggles the menu's
5508 * <code>&#60;div&#62;</code> element's "display" style property
5509 * between "block" (true) or "none" (false).
5510 * @default false
5511 * @type Boolean
5513 oConfig.addProperty(
5514 DEFAULT_CONFIG.VISIBLE.key,
5516 handler: this.configVisible,
5517 value: DEFAULT_CONFIG.VISIBLE.value,
5518 validator: DEFAULT_CONFIG.VISIBLE.validator
5524 Change the default value for the "constraintoviewport" configuration
5525 property to "true" by re-adding the property.
5529 * @config constraintoviewport
5530 * @description Boolean indicating if the menu will try to remain inside
5531 * the boundaries of the size of viewport.
5532 * @default true
5533 * @type Boolean
5535 oConfig.addProperty(
5536 DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key,
5538 handler: this.configConstrainToViewport,
5539 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
5540 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
5541 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
5547 * @config position
5548 * @description String indicating how a menu should be positioned on the
5549 * screen. Possible values are "static" and "dynamic." Static menus are
5550 * visible by default and reside in the normal flow of the document
5551 * (CSS position: static). Dynamic menus are hidden by default, reside
5552 * out of the normal flow of the document (CSS position: absolute), and
5553 * can overlay other elements on the screen.
5554 * @default dynamic
5555 * @type String
5557 oConfig.addProperty(
5558 DEFAULT_CONFIG.POSITION.key,
5560 handler: this.configPosition,
5561 value: DEFAULT_CONFIG.POSITION.value,
5562 validator: DEFAULT_CONFIG.POSITION.validator,
5563 supercedes: DEFAULT_CONFIG.POSITION.supercedes
5569 * @config submenualignment
5570 * @description Array defining how submenus should be aligned to their
5571 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
5572 * a submenu's top left corner is aligned to its parent menu item's top
5573 * right corner.
5574 * @default ["tl","tr"]
5575 * @type Array
5577 oConfig.addProperty(
5578 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
5580 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value
5586 * @config autosubmenudisplay
5587 * @description Boolean indicating if submenus are automatically made
5588 * visible when the user mouses over the menu's items.
5589 * @default true
5590 * @type Boolean
5592 oConfig.addProperty(
5593 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
5595 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
5596 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator
5602 * @config showdelay
5603 * @description Number indicating the time (in milliseconds) that should
5604 * expire before a submenu is made visible when the user mouses over
5605 * the menu's items.
5606 * @default 250
5607 * @type Number
5609 oConfig.addProperty(
5610 DEFAULT_CONFIG.SHOW_DELAY.key,
5612 value: DEFAULT_CONFIG.SHOW_DELAY.value,
5613 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5619 * @config hidedelay
5620 * @description Number indicating the time (in milliseconds) that should
5621 * expire before the menu is hidden.
5622 * @default 0
5623 * @type Number
5625 oConfig.addProperty(
5626 DEFAULT_CONFIG.HIDE_DELAY.key,
5628 handler: this.configHideDelay,
5629 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5630 validator: DEFAULT_CONFIG.HIDE_DELAY.validator,
5631 suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.suppressEvent
5637 * @config submenuhidedelay
5638 * @description Number indicating the time (in milliseconds) that should
5639 * expire before a submenu is hidden when the user mouses out of a menu item
5640 * heading in the direction of a submenu. The value must be greater than or
5641 * equal to the value specified for the "showdelay" configuration property.
5642 * @default 250
5643 * @type Number
5645 oConfig.addProperty(
5646 DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key,
5648 value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value,
5649 validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator
5655 * @config clicktohide
5656 * @description Boolean indicating if the menu will automatically be
5657 * hidden if the user clicks outside of it.
5658 * @default true
5659 * @type Boolean
5661 oConfig.addProperty(
5662 DEFAULT_CONFIG.CLICK_TO_HIDE.key,
5664 value: DEFAULT_CONFIG.CLICK_TO_HIDE.value,
5665 validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator
5671 * @config container
5672 * @description HTML element reference or string specifying the id
5673 * attribute of the HTML element that the menu's markup should be
5674 * rendered into.
5675 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
5676 * level-one-html.html#ID-58190037">HTMLElement</a>|String
5677 * @default document.body
5679 oConfig.addProperty(
5680 DEFAULT_CONFIG.CONTAINER.key,
5682 handler: this.configContainer,
5683 value: document.body
5689 * @config maxheight
5690 * @description Defines the maximum height (in pixels) for a menu before the
5691 * contents of the body are scrolled.
5692 * @default 0
5693 * @type Number
5695 oConfig.addProperty(
5696 DEFAULT_CONFIG.MAX_HEIGHT.key,
5698 handler: this.configMaxHeight,
5699 value: DEFAULT_CONFIG.MAX_HEIGHT.value,
5700 validator: DEFAULT_CONFIG.MAX_HEIGHT.validator
5706 * @config classname
5707 * @description CSS class to be applied to the menu's root
5708 * <code>&#60;div&#62;</code> element. The specified class(es) are
5709 * appended in addition to the default class as specified by the menu's
5710 * CSS_CLASS_NAME constant.
5711 * @default null
5712 * @type String
5714 oConfig.addProperty(
5715 DEFAULT_CONFIG.CLASS_NAME.key,
5717 handler: this.configClassName,
5718 value: DEFAULT_CONFIG.CLASS_NAME.value,
5719 validator: DEFAULT_CONFIG.CLASS_NAME.validator
5725 * @config disabled
5726 * @description Boolean indicating if the menu should be disabled.
5727 * Disabling a menu disables each of its items. (Disabled menu items are
5728 * dimmed and will not respond to user input or fire events.) Disabled
5729 * menus have a corresponding "disabled" CSS class applied to their root
5730 * <code>&#60;div&#62;</code> element.
5731 * @default false
5732 * @type Boolean
5734 oConfig.addProperty(
5735 DEFAULT_CONFIG.DISABLED.key,
5737 handler: this.configDisabled,
5738 value: DEFAULT_CONFIG.DISABLED.value,
5739 validator: DEFAULT_CONFIG.DISABLED.validator
5745 }); // END YAHOO.lang.extend
5747 })();
5751 (function() {
5755 * Creates an item for a menu.
5757 * @param {String} p_oObject String specifying the text of the menu item.
5758 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5759 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
5760 * the <code>&#60;li&#62;</code> element of the menu item.
5761 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5762 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
5763 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
5764 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5765 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
5766 * specifying the <code>&#60;option&#62;</code> element of the menu item.
5767 * @param {Object} p_oConfig Optional. Object literal specifying the
5768 * configuration for the menu item. See configuration class documentation
5769 * for more details.
5770 * @class MenuItem
5771 * @constructor
5773 YAHOO.widget.MenuItem = function(p_oObject, p_oConfig) {
5775 if(p_oObject) {
5777 if(p_oConfig) {
5779 this.parent = p_oConfig.parent;
5780 this.value = p_oConfig.value;
5781 this.id = p_oConfig.id;
5785 this.init(p_oObject, p_oConfig);
5791 var Dom = YAHOO.util.Dom,
5792 Module = YAHOO.widget.Module,
5793 Menu = YAHOO.widget.Menu,
5794 MenuItem = YAHOO.widget.MenuItem,
5795 CustomEvent = YAHOO.util.CustomEvent,
5796 Lang = YAHOO.lang,
5798 m_oMenuItemTemplate,
5801 * Constant representing the name of the MenuItem's events
5802 * @property EVENT_TYPES
5803 * @private
5804 * @final
5805 * @type Object
5807 EVENT_TYPES = {
5809 "MOUSE_OVER": "mouseover",
5810 "MOUSE_OUT": "mouseout",
5811 "MOUSE_DOWN": "mousedown",
5812 "MOUSE_UP": "mouseup",
5813 "CLICK": "click",
5814 "KEY_PRESS": "keypress",
5815 "KEY_DOWN": "keydown",
5816 "KEY_UP": "keyup",
5817 "ITEM_ADDED": "itemAdded",
5818 "ITEM_REMOVED": "itemRemoved",
5819 "FOCUS": "focus",
5820 "BLUR": "blur",
5821 "DESTROY": "destroy"
5826 * Constant representing the MenuItem's configuration properties
5827 * @property DEFAULT_CONFIG
5828 * @private
5829 * @final
5830 * @type Object
5832 DEFAULT_CONFIG = {
5834 "TEXT": {
5835 key: "text",
5836 value: "",
5837 validator: Lang.isString,
5838 suppressEvent: true
5841 "HELP_TEXT": {
5842 key: "helptext",
5843 supercedes: ["text"]
5846 "URL": {
5847 key: "url",
5848 value: "#",
5849 suppressEvent: true
5852 "TARGET": {
5853 key: "target",
5854 suppressEvent: true
5857 "EMPHASIS": {
5858 key: "emphasis",
5859 value: false,
5860 validator: Lang.isBoolean,
5861 suppressEvent: true,
5862 supercedes: ["text"]
5865 "STRONG_EMPHASIS": {
5866 key: "strongemphasis",
5867 value: false,
5868 validator: Lang.isBoolean,
5869 suppressEvent: true,
5870 supercedes: ["text"]
5873 "CHECKED": {
5874 key: "checked",
5875 value: false,
5876 validator: Lang.isBoolean,
5877 suppressEvent: true,
5878 supercedes: ["text"]
5881 "DISABLED": {
5882 key: "disabled",
5883 value: false,
5884 validator: Lang.isBoolean,
5885 suppressEvent: true,
5886 supercedes: ["text"]
5889 "SELECTED": {
5890 key: "selected",
5891 value: false,
5892 validator: Lang.isBoolean,
5893 suppressEvent: true
5896 "SUBMENU": {
5897 key: "submenu",
5898 supercedes: ["text"]
5901 "ONCLICK": {
5902 key: "onclick"
5905 "CLASS_NAME": {
5906 key: "classname",
5907 value: null,
5908 validator: Lang.isString
5914 MenuItem.prototype = {
5916 // Constants
5919 * @property COLLAPSED_SUBMENU_INDICATOR_TEXT
5920 * @description String representing the text for the <code>&#60;em&#62;</code>
5921 * element used for the submenu arrow indicator.
5922 * @default "Submenu collapsed. Click to expand submenu."
5923 * @final
5924 * @type String
5926 COLLAPSED_SUBMENU_INDICATOR_TEXT:
5927 "Submenu collapsed. Click to expand submenu.",
5931 * @property EXPANDED_SUBMENU_INDICATOR_TEXT
5932 * @description String representing the text for the submenu arrow indicator
5933 * element (<code>&#60;em&#62;</code>) when the submenu is visible.
5934 * @default "Submenu expanded. Click to collapse submenu."
5935 * @final
5936 * @type String
5938 EXPANDED_SUBMENU_INDICATOR_TEXT:
5939 "Submenu expanded. Click to collapse submenu.",
5943 * @property DISABLED_SUBMENU_INDICATOR_TEXT
5944 * @description String representing the text for the submenu arrow indicator
5945 * element (<code>&#60;em&#62;</code>) when the menu item is disabled.
5946 * @default "Submenu collapsed. (Item disabled.)."
5947 * @final
5948 * @type String
5950 DISABLED_SUBMENU_INDICATOR_TEXT: "Submenu collapsed. (Item disabled.)",
5954 * @property CHECKED_TEXT
5955 * @description String representing the text to be used for the checked
5956 * indicator element (<code>&#60;em&#62;</code>).
5957 * @default "Checked."
5958 * @final
5959 * @type String
5961 CHECKED_TEXT: "Menu item checked.",
5965 * @property DISABLED_CHECKED_TEXT
5966 * @description String representing the text to be used for the checked
5967 * indicator element (<code>&#60;em&#62;</code>) when the menu item
5968 * is disabled.
5969 * @default "Checked. (Item disabled.)"
5970 * @final
5971 * @type String
5973 DISABLED_CHECKED_TEXT: "Checked. (Item disabled.)",
5977 * @property CSS_CLASS_NAME
5978 * @description String representing the CSS class(es) to be applied to the
5979 * <code>&#60;li&#62;</code> element of the menu item.
5980 * @default "yuimenuitem"
5981 * @final
5982 * @type String
5984 CSS_CLASS_NAME: "yuimenuitem",
5988 * @property CSS_LABEL_CLASS_NAME
5989 * @description String representing the CSS class(es) to be applied to the
5990 * menu item's <code>&#60;a&#62;</code> element.
5991 * @default "yuimenuitemlabel"
5992 * @final
5993 * @type String
5995 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
5999 * @property SUBMENU_TYPE
6000 * @description Object representing the type of menu to instantiate and
6001 * add when parsing the child nodes of the menu item's source HTML element.
6002 * @final
6003 * @type YAHOO.widget.Menu
6005 SUBMENU_TYPE: null,
6009 // Private member variables
6013 * @property _oAnchor
6014 * @description Object reference to the menu item's
6015 * <code>&#60;a&#62;</code> element.
6016 * @default null
6017 * @private
6018 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6019 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6021 _oAnchor: null,
6025 * @property _oHelpTextEM
6026 * @description Object reference to the menu item's help text
6027 * <code>&#60;em&#62;</code> element.
6028 * @default null
6029 * @private
6030 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6031 * one-html.html#ID-58190037">HTMLElement</a>
6033 _oHelpTextEM: null,
6037 * @property _oSubmenu
6038 * @description Object reference to the menu item's submenu.
6039 * @default null
6040 * @private
6041 * @type YAHOO.widget.Menu
6043 _oSubmenu: null,
6047 * @property _oCheckedIndicator
6048 * @description Object reference to the menu item's checkmark image.
6049 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6050 * level-one-html.html#ID-58190037">HTMLElement</a>
6051 * @private
6052 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6053 * level-one-html.html#ID-58190037">HTMLElement</a>
6055 _oCheckedIndicator: null,
6058 /**
6059 * @property _oOnclickAttributeValue
6060 * @description Object reference to the menu item's current value for the
6061 * "onclick" configuration attribute.
6062 * @default null
6063 * @private
6064 * @type Object
6066 _oOnclickAttributeValue: null,
6070 * @property _sClassName
6071 * @description The current value of the "classname" configuration attribute.
6072 * @default null
6073 * @private
6074 * @type String
6076 _sClassName: null,
6080 // Public properties
6084 * @property constructor
6085 * @description Object reference to the menu item's constructor function.
6086 * @default YAHOO.widget.MenuItem
6087 * @type YAHOO.widget.MenuItem
6089 constructor: MenuItem,
6093 * @property index
6094 * @description Number indicating the ordinal position of the menu item in
6095 * its group.
6096 * @default null
6097 * @type Number
6099 index: null,
6103 * @property groupIndex
6104 * @description Number indicating the index of the group to which the menu
6105 * item belongs.
6106 * @default null
6107 * @type Number
6109 groupIndex: null,
6113 * @property parent
6114 * @description Object reference to the menu item's parent menu.
6115 * @default null
6116 * @type YAHOO.widget.Menu
6118 parent: null,
6122 * @property element
6123 * @description Object reference to the menu item's
6124 * <code>&#60;li&#62;</code> element.
6125 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6126 * -one-html.html#ID-74680021">HTMLLIElement</a>
6127 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6128 * one-html.html#ID-74680021">HTMLLIElement</a>
6130 element: null,
6134 * @property srcElement
6135 * @description Object reference to the HTML element (either
6136 * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
6137 * <code>&#60;option&#62;</code>) used create the menu item.
6138 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6139 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6140 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6141 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6142 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6143 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6144 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6145 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6146 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6147 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6149 srcElement: null,
6153 * @property value
6154 * @description Object reference to the menu item's value.
6155 * @default null
6156 * @type Object
6158 value: null,
6162 * @property submenuIndicator
6163 * @description Object reference to the <code>&#60;em&#62;</code> element
6164 * used to create the submenu indicator for the menu item.
6165 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6166 * level-one-html.html#ID-58190037">HTMLElement</a>
6167 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6168 * level-one-html.html#ID-58190037">HTMLElement</a>
6170 submenuIndicator: null,
6174 * @property browser
6175 * @deprecated Use YAHOO.env.ua
6176 * @description String representing the browser.
6177 * @type String
6179 browser: Module.prototype.browser,
6183 * @property id
6184 * @description Id of the menu item's root <code>&#60;li&#62;</code>
6185 * element. This property should be set via the constructor using the
6186 * configuration object literal. If an id is not specified, then one will
6187 * be created using the "generateId" method of the Dom utility.
6188 * @default null
6189 * @type String
6191 id: null,
6195 // Events
6199 * @event destroyEvent
6200 * @description Fires when the menu item's <code>&#60;li&#62;</code>
6201 * element is removed from its parent <code>&#60;ul&#62;</code> element.
6202 * @type YAHOO.util.CustomEvent
6204 destroyEvent: null,
6208 * @event mouseOverEvent
6209 * @description Fires when the mouse has entered the menu item. Passes
6210 * back the DOM Event object as an argument.
6211 * @type YAHOO.util.CustomEvent
6213 mouseOverEvent: null,
6217 * @event mouseOutEvent
6218 * @description Fires when the mouse has left the menu item. Passes back
6219 * the DOM Event object as an argument.
6220 * @type YAHOO.util.CustomEvent
6222 mouseOutEvent: null,
6226 * @event mouseDownEvent
6227 * @description Fires when the user mouses down on the menu item. Passes
6228 * back the DOM Event object as an argument.
6229 * @type YAHOO.util.CustomEvent
6231 mouseDownEvent: null,
6235 * @event mouseUpEvent
6236 * @description Fires when the user releases a mouse button while the mouse
6237 * is over the menu item. Passes back the DOM Event object as an argument.
6238 * @type YAHOO.util.CustomEvent
6240 mouseUpEvent: null,
6244 * @event clickEvent
6245 * @description Fires when the user clicks the on the menu item. Passes
6246 * back the DOM Event object as an argument.
6247 * @type YAHOO.util.CustomEvent
6249 clickEvent: null,
6253 * @event keyPressEvent
6254 * @description Fires when the user presses an alphanumeric key when the
6255 * menu item has focus. Passes back the DOM Event object as an argument.
6256 * @type YAHOO.util.CustomEvent
6258 keyPressEvent: null,
6262 * @event keyDownEvent
6263 * @description Fires when the user presses a key when the menu item has
6264 * focus. Passes back the DOM Event object as an argument.
6265 * @type YAHOO.util.CustomEvent
6267 keyDownEvent: null,
6271 * @event keyUpEvent
6272 * @description Fires when the user releases a key when the menu item has
6273 * focus. Passes back the DOM Event object as an argument.
6274 * @type YAHOO.util.CustomEvent
6276 keyUpEvent: null,
6280 * @event focusEvent
6281 * @description Fires when the menu item receives focus.
6282 * @type YAHOO.util.CustomEvent
6284 focusEvent: null,
6288 * @event blurEvent
6289 * @description Fires when the menu item loses the input focus.
6290 * @type YAHOO.util.CustomEvent
6292 blurEvent: null,
6296 * @method init
6297 * @description The MenuItem class's initialization method. This method is
6298 * automatically called by the constructor, and sets up all DOM references
6299 * for pre-existing markup, and creates required markup if it is not
6300 * already present.
6301 * @param {String} p_oObject String specifying the text of the menu item.
6302 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6303 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6304 * the <code>&#60;li&#62;</code> element of the menu item.
6305 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6306 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6307 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6308 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6309 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6310 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6311 * @param {Object} p_oConfig Optional. Object literal specifying the
6312 * configuration for the menu item. See configuration class documentation
6313 * for more details.
6315 init: function(p_oObject, p_oConfig) {
6318 if(!this.SUBMENU_TYPE) {
6320 this.SUBMENU_TYPE = Menu;
6325 // Create the config object
6327 this.cfg = new YAHOO.util.Config(this);
6329 this.initDefaultConfig();
6331 var SIGNATURE = CustomEvent.LIST,
6332 oConfig = this.cfg,
6333 sURL = "#",
6334 oAnchor,
6335 sTarget,
6336 sText,
6337 sId;
6340 if(Lang.isString(p_oObject)) {
6342 this._createRootNodeStructure();
6344 oConfig.queueProperty("text", p_oObject);
6347 else if(p_oObject && p_oObject.tagName) {
6349 switch(p_oObject.tagName.toUpperCase()) {
6351 case "OPTION":
6353 this._createRootNodeStructure();
6355 oConfig.queueProperty("text", p_oObject.text);
6357 this.srcElement = p_oObject;
6359 break;
6361 case "OPTGROUP":
6363 this._createRootNodeStructure();
6365 oConfig.queueProperty("text", p_oObject.label);
6367 this.srcElement = p_oObject;
6369 this._initSubTree();
6371 break;
6373 case "LI":
6375 // Get the anchor node (if it exists)
6377 oAnchor = Dom.getFirstChild(p_oObject);
6380 // Capture the "text" and/or the "URL"
6382 if(oAnchor) {
6384 sURL = oAnchor.getAttribute("href");
6385 sTarget = oAnchor.getAttribute("target");
6386 sText = oAnchor.innerHTML;
6390 this.srcElement = p_oObject;
6391 this.element = p_oObject;
6392 this._oAnchor = oAnchor;
6395 Set these properties silently to sync up the
6396 configuration object without making changes to the
6397 element's DOM
6400 oConfig.setProperty("text", sText, true);
6401 oConfig.setProperty("url", sURL, true);
6402 oConfig.setProperty("target", sTarget, true);
6404 this._initSubTree();
6406 break;
6413 if(this.element) {
6415 sId = this.element.id;
6417 if(!sId) {
6419 sId = this.id || Dom.generateId();
6421 this.element.id = sId;
6425 this.id = sId;
6428 Dom.addClass(this.element, this.CSS_CLASS_NAME);
6429 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
6432 // Create custom events
6434 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
6435 this.mouseOverEvent.signature = SIGNATURE;
6437 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
6438 this.mouseOutEvent.signature = SIGNATURE;
6440 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
6441 this.mouseDownEvent.signature = SIGNATURE;
6443 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
6444 this.mouseUpEvent.signature = SIGNATURE;
6446 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
6447 this.clickEvent.signature = SIGNATURE;
6449 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
6450 this.keyPressEvent.signature = SIGNATURE;
6452 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
6453 this.keyDownEvent.signature = SIGNATURE;
6455 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
6456 this.keyUpEvent.signature = SIGNATURE;
6458 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
6459 this.focusEvent.signature = SIGNATURE;
6461 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
6462 this.blurEvent.signature = SIGNATURE;
6464 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
6465 this.destroyEvent.signature = SIGNATURE;
6467 if(p_oConfig) {
6469 oConfig.applyConfig(p_oConfig);
6473 oConfig.fireQueue();
6481 // Private methods
6485 * @method _createRootNodeStructure
6486 * @description Creates the core DOM structure for the menu item.
6487 * @private
6489 _createRootNodeStructure: function () {
6491 var oElement,
6492 oAnchor;
6494 if(!m_oMenuItemTemplate) {
6496 m_oMenuItemTemplate = document.createElement("li");
6497 m_oMenuItemTemplate.innerHTML = "<a href=\"#\"></a>";
6501 oElement = m_oMenuItemTemplate.cloneNode(true);
6502 oElement.className = this.CSS_CLASS_NAME;
6504 oAnchor = oElement.firstChild;
6505 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
6507 this.element = oElement;
6508 this._oAnchor = oAnchor;
6514 * @method _initSubTree
6515 * @description Iterates the source element's childNodes collection and uses
6516 * the child nodes to instantiate other menus.
6517 * @private
6519 _initSubTree: function() {
6521 var oSrcEl = this.srcElement,
6522 oConfig = this.cfg,
6523 oNode,
6524 aOptions,
6525 nOptions,
6526 oMenu,
6530 if(oSrcEl.childNodes.length > 0) {
6532 if(this.parent.lazyLoad && this.parent.srcElement &&
6533 this.parent.srcElement.tagName.toUpperCase() == "SELECT") {
6535 oConfig.setProperty(
6536 "submenu",
6537 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
6541 else {
6543 oNode = oSrcEl.firstChild;
6544 aOptions = [];
6546 do {
6548 if(oNode && oNode.tagName) {
6550 switch(oNode.tagName.toUpperCase()) {
6552 case "DIV":
6554 oConfig.setProperty("submenu", oNode);
6556 break;
6558 case "OPTION":
6560 aOptions[aOptions.length] = oNode;
6562 break;
6569 while((oNode = oNode.nextSibling));
6572 nOptions = aOptions.length;
6574 if(nOptions > 0) {
6576 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
6578 oConfig.setProperty("submenu", oMenu);
6580 for(n=0; n<nOptions; n++) {
6582 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
6596 // Event handlers for configuration properties
6600 * @method configText
6601 * @description Event handler for when the "text" configuration property of
6602 * the menu item changes.
6603 * @param {String} p_sType String representing the name of the event that
6604 * was fired.
6605 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6606 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6607 * that fired the event.
6609 configText: function(p_sType, p_aArgs, p_oItem) {
6611 var sText = p_aArgs[0],
6612 oConfig = this.cfg,
6613 oAnchor = this._oAnchor,
6614 sHelpText = oConfig.getProperty("helptext"),
6615 sHelpTextHTML = "",
6616 sCheckHTML = "",
6617 oSubmenu = oConfig.getProperty("submenu"),
6618 sSubmenuIndicatorHTML = "",
6619 sEmphasisStartTag = "",
6620 sEmphasisEndTag = "";
6623 if (sText) {
6626 if (sHelpText) {
6628 sHelpTextHTML = "<em class=\"helptext\">" + sHelpText + "</em>";
6633 if (oConfig.getProperty("checked")) {
6635 sCheckHTML = "<em class=\"checkedindicator\">" +
6636 this.CHECKED_TEXT + "</em>";
6641 if (oSubmenu) {
6643 sSubmenuIndicatorHTML = "<em class=\"submenuindicator\">" +
6644 ((oSubmenu instanceof Menu &&
6645 oSubmenu.cfg.getProperty("visible")) ?
6646 this.EXPANDED_SUBMENU_INDICATOR_TEXT :
6647 this.COLLAPSED_SUBMENU_INDICATOR_TEXT) + "</em>";
6652 if (oConfig.getProperty("emphasis")) {
6654 sEmphasisStartTag = "<em>";
6655 sEmphasisEndTag = "</em>";
6660 if (oConfig.getProperty("strongemphasis")) {
6662 sEmphasisStartTag = "<strong>";
6663 sEmphasisEndTag = "</strong>";
6668 oAnchor.innerHTML = (sEmphasisStartTag + sText +
6669 sEmphasisEndTag + sHelpTextHTML +
6670 sCheckHTML + sSubmenuIndicatorHTML);
6673 if (oSubmenu) {
6675 this.submenuIndicator = oAnchor.lastChild;
6685 * @method configHelpText
6686 * @description Event handler for when the "helptext" configuration property
6687 * of the menu item changes.
6688 * @param {String} p_sType String representing the name of the event that
6689 * was fired.
6690 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6691 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6692 * that fired the event.
6694 configHelpText: function(p_sType, p_aArgs, p_oItem) {
6696 var sHelpText = p_aArgs[0],
6697 oAnchor = this._oAnchor;
6699 if (sHelpText) {
6701 Dom.addClass(oAnchor, "hashelptext");
6704 else {
6706 Dom.removeClass(oAnchor, "hashelptext");
6710 this.cfg.refireEvent("text");
6716 * @method configURL
6717 * @description Event handler for when the "url" configuration property of
6718 * the menu item changes.
6719 * @param {String} p_sType String representing the name of the event that
6720 * was fired.
6721 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6722 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6723 * that fired the event.
6725 configURL: function(p_sType, p_aArgs, p_oItem) {
6727 var sURL = p_aArgs[0];
6729 if(!sURL) {
6731 sURL = "#";
6735 this._oAnchor.setAttribute("href", sURL);
6741 * @method configTarget
6742 * @description Event handler for when the "target" configuration property
6743 * of the menu item changes.
6744 * @param {String} p_sType String representing the name of the event that
6745 * was fired.
6746 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6747 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6748 * that fired the event.
6750 configTarget: function(p_sType, p_aArgs, p_oItem) {
6752 var sTarget = p_aArgs[0],
6753 oAnchor = this._oAnchor;
6755 if(sTarget && sTarget.length > 0) {
6757 oAnchor.setAttribute("target", sTarget);
6760 else {
6762 oAnchor.removeAttribute("target");
6770 * @method configEmphasis
6771 * @description Event handler for when the "emphasis" configuration property
6772 * of the menu item changes.
6773 * @param {String} p_sType String representing the name of the event that
6774 * was fired.
6775 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6776 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6777 * that fired the event.
6779 configEmphasis: function(p_sType, p_aArgs, p_oItem) {
6781 var bEmphasis = p_aArgs[0],
6782 oConfig = this.cfg;
6785 if(bEmphasis && oConfig.getProperty("strongemphasis")) {
6787 oConfig.setProperty("strongemphasis", false);
6792 oConfig.refireEvent("text");
6798 * @method configStrongEmphasis
6799 * @description Event handler for when the "strongemphasis" configuration
6800 * property of the menu item changes.
6801 * @param {String} p_sType String representing the name of the event that
6802 * was fired.
6803 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6804 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6805 * that fired the event.
6807 configStrongEmphasis: function(p_sType, p_aArgs, p_oItem) {
6809 var bStrongEmphasis = p_aArgs[0],
6810 oConfig = this.cfg;
6813 if(bStrongEmphasis && oConfig.getProperty("emphasis")) {
6815 oConfig.setProperty("emphasis", false);
6819 oConfig.refireEvent("text");
6825 * @method configChecked
6826 * @description Event handler for when the "checked" configuration property
6827 * of the menu item changes.
6828 * @param {String} p_sType String representing the name of the event that
6829 * was fired.
6830 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6831 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6832 * that fired the event.
6834 configChecked: function(p_sType, p_aArgs, p_oItem) {
6836 var bChecked = p_aArgs[0],
6837 oAnchor = this._oAnchor;
6839 if (bChecked) {
6841 Dom.addClass(oAnchor, "checked");
6844 else {
6846 Dom.removeClass(oAnchor, "checked");
6850 this.cfg.refireEvent("text");
6857 * @method configDisabled
6858 * @description Event handler for when the "disabled" configuration property
6859 * of the menu item changes.
6860 * @param {String} p_sType String representing the name of the event that
6861 * was fired.
6862 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6863 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6864 * that fired the event.
6866 configDisabled: function(p_sType, p_aArgs, p_oItem) {
6868 var bDisabled = p_aArgs[0],
6869 oConfig = this.cfg,
6870 oAnchor = this._oAnchor;
6873 if(bDisabled) {
6875 if(oConfig.getProperty("selected")) {
6877 oConfig.setProperty("selected", false);
6881 oAnchor.removeAttribute("href");
6883 Dom.addClass(oAnchor, "disabled");
6886 else {
6888 oAnchor.setAttribute("href", oConfig.getProperty("url"));
6890 Dom.removeClass(oAnchor, "disabled");
6898 * @method configSelected
6899 * @description Event handler for when the "selected" configuration property
6900 * of the menu item changes.
6901 * @param {String} p_sType String representing the name of the event that
6902 * was fired.
6903 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6904 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6905 * that fired the event.
6907 configSelected: function(p_sType, p_aArgs, p_oItem) {
6909 var bSelected,
6910 oAnchor;
6912 if(!this.cfg.getProperty("disabled")) {
6914 bSelected = p_aArgs[0];
6915 oAnchor = this._oAnchor;
6918 if(bSelected) {
6920 Dom.addClass(oAnchor, "selected");
6923 else {
6925 Dom.removeClass(oAnchor, "selected");
6935 * @method configSubmenu
6936 * @description Event handler for when the "submenu" configuration property
6937 * of the menu item changes.
6938 * @param {String} p_sType String representing the name of the event that
6939 * was fired.
6940 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6941 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6942 * that fired the event.
6944 configSubmenu: function(p_sType, p_aArgs, p_oItem) {
6946 var oAnchor = this._oAnchor,
6947 oSubmenu = p_aArgs[0],
6948 oSubmenuIndicator = this.submenuIndicator,
6949 oConfig = this.cfg,
6950 bLazyLoad = this.parent && this.parent.lazyLoad,
6951 oMenu,
6952 sSubmenuId,
6953 oSubmenuConfig;
6956 if(oSubmenu) {
6958 if(oSubmenu instanceof Menu) {
6960 oMenu = oSubmenu;
6961 oMenu.parent = this;
6962 oMenu.lazyLoad = bLazyLoad;
6965 else if(typeof oSubmenu == "object" && oSubmenu.id &&
6966 !oSubmenu.nodeType) {
6968 sSubmenuId = oSubmenu.id;
6969 oSubmenuConfig = oSubmenu;
6971 oSubmenuConfig.lazyload = bLazyLoad;
6972 oSubmenuConfig.parent = this;
6974 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
6977 // Set the value of the property to the Menu instance
6979 this.cfg.setProperty("submenu", oMenu, true);
6982 else {
6984 oMenu = new this.SUBMENU_TYPE(oSubmenu,
6985 { lazyload: bLazyLoad, parent: this });
6988 // Set the value of the property to the Menu instance
6990 this.cfg.setProperty("submenu", oMenu, true);
6995 if(oMenu) {
6997 Dom.addClass(oAnchor, "hassubmenu");
6999 this._oSubmenu = oMenu;
7004 else {
7006 Dom.removeClass(oAnchor, "hassubmenu");
7008 if(oSubmenuIndicator) {
7010 oAnchor.removeChild(oSubmenuIndicator);
7014 if(this._oSubmenu) {
7016 this._oSubmenu.destroy();
7022 oConfig.refireEvent("text");
7028 * @method configOnClick
7029 * @description Event handler for when the "onclick" configuration property
7030 * of the menu item changes.
7031 * @param {String} p_sType String representing the name of the event that
7032 * was fired.
7033 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7034 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7035 * that fired the event.
7037 configOnClick: function(p_sType, p_aArgs, p_oItem) {
7039 var oObject = p_aArgs[0];
7042 Remove any existing listeners if a "click" event handler has
7043 already been specified.
7046 if(this._oOnclickAttributeValue &&
7047 (this._oOnclickAttributeValue != oObject)) {
7049 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7050 this._oOnclickAttributeValue.obj);
7052 this._oOnclickAttributeValue = null;
7057 if(!this._oOnclickAttributeValue && typeof oObject == "object" &&
7058 typeof oObject.fn == "function") {
7060 this.clickEvent.subscribe(oObject.fn,
7061 ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this),
7062 oObject.scope);
7064 this._oOnclickAttributeValue = oObject;
7072 * @method configClassName
7073 * @description Event handler for when the "classname" configuration
7074 * property of a menu item changes.
7075 * @param {String} p_sType String representing the name of the event that
7076 * was fired.
7077 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7078 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7079 * that fired the event.
7081 configClassName: function(p_sType, p_aArgs, p_oItem) {
7083 var sClassName = p_aArgs[0];
7085 if(this._sClassName) {
7087 Dom.removeClass(this.element, this._sClassName);
7091 Dom.addClass(this.element, sClassName);
7092 this._sClassName = sClassName;
7098 // Public methods
7102 * @method initDefaultConfig
7103 * @description Initializes an item's configurable properties.
7105 initDefaultConfig : function() {
7107 var oConfig = this.cfg;
7110 // Define the configuration attributes
7113 * @config text
7114 * @description String specifying the text label for the menu item.
7115 * When building a menu from existing HTML the value of this property
7116 * will be interpreted from the menu's markup.
7117 * @default ""
7118 * @type String
7120 oConfig.addProperty(
7121 DEFAULT_CONFIG.TEXT.key,
7123 handler: this.configText,
7124 value: DEFAULT_CONFIG.TEXT.value,
7125 validator: DEFAULT_CONFIG.TEXT.validator,
7126 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
7132 * @config helptext
7133 * @description String specifying additional instructional text to
7134 * accompany the text for the menu item.
7135 * @deprecated Use "text" configuration property to add help text markup.
7136 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em
7137 * class=\"helptext\"&#62;Ctrl + C&#60;/em&#60;");</code>
7138 * @default null
7139 * @type String|<a href="http://www.w3.org/TR/
7140 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7141 * HTMLElement</a>
7143 oConfig.addProperty(
7144 DEFAULT_CONFIG.HELP_TEXT.key,
7145 { handler: this.configHelpText }
7150 * @config url
7151 * @description String specifying the URL for the menu item's anchor's
7152 * "href" attribute. When building a menu from existing HTML the value
7153 * of this property will be interpreted from the menu's markup.
7154 * @default "#"
7155 * @type String
7157 oConfig.addProperty(
7158 DEFAULT_CONFIG.URL.key,
7160 handler: this.configURL,
7161 value: DEFAULT_CONFIG.URL.value,
7162 suppressEvent: DEFAULT_CONFIG.URL.suppressEvent
7168 * @config target
7169 * @description String specifying the value for the "target" attribute
7170 * of the menu item's anchor element. <strong>Specifying a target will
7171 * require the user to click directly on the menu item's anchor node in
7172 * order to cause the browser to navigate to the specified URL.</strong>
7173 * When building a menu from existing HTML the value of this property
7174 * will be interpreted from the menu's markup.
7175 * @default null
7176 * @type String
7178 oConfig.addProperty(
7179 DEFAULT_CONFIG.TARGET.key,
7181 handler: this.configTarget,
7182 suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent
7188 * @config emphasis
7189 * @description Boolean indicating if the text of the menu item will be
7190 * rendered with emphasis.
7191 * @deprecated Use "text" configuration property to add emphasis.
7192 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some
7193 * Text&#60;/em&#60;");</code>
7194 * @default false
7195 * @type Boolean
7197 oConfig.addProperty(
7198 DEFAULT_CONFIG.EMPHASIS.key,
7200 handler: this.configEmphasis,
7201 value: DEFAULT_CONFIG.EMPHASIS.value,
7202 validator: DEFAULT_CONFIG.EMPHASIS.validator,
7203 suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent
7209 * @config strongemphasis
7210 * @description Boolean indicating if the text of the menu item will be
7211 * rendered with strong emphasis.
7212 * @deprecated Use "text" configuration property to add strong emphasis.
7213 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62;
7214 * Some Text&#60;/strong&#60;");</code>
7215 * @default false
7216 * @type Boolean
7218 oConfig.addProperty(
7219 DEFAULT_CONFIG.STRONG_EMPHASIS.key,
7221 handler: this.configStrongEmphasis,
7222 value: DEFAULT_CONFIG.STRONG_EMPHASIS.value,
7223 validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator,
7224 suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent
7230 * @config checked
7231 * @description Boolean indicating if the menu item should be rendered
7232 * with a checkmark.
7233 * @default false
7234 * @type Boolean
7236 oConfig.addProperty(
7237 DEFAULT_CONFIG.CHECKED.key,
7239 handler: this.configChecked,
7240 value: DEFAULT_CONFIG.CHECKED.value,
7241 validator: DEFAULT_CONFIG.CHECKED.validator,
7242 suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent,
7243 supercedes: DEFAULT_CONFIG.CHECKED.supercedes
7249 * @config disabled
7250 * @description Boolean indicating if the menu item should be disabled.
7251 * (Disabled menu items are dimmed and will not respond to user input
7252 * or fire events.)
7253 * @default false
7254 * @type Boolean
7256 oConfig.addProperty(
7257 DEFAULT_CONFIG.DISABLED.key,
7259 handler: this.configDisabled,
7260 value: DEFAULT_CONFIG.DISABLED.value,
7261 validator: DEFAULT_CONFIG.DISABLED.validator,
7262 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
7268 * @config selected
7269 * @description Boolean indicating if the menu item should
7270 * be highlighted.
7271 * @default false
7272 * @type Boolean
7274 oConfig.addProperty(
7275 DEFAULT_CONFIG.SELECTED.key,
7277 handler: this.configSelected,
7278 value: DEFAULT_CONFIG.SELECTED.value,
7279 validator: DEFAULT_CONFIG.SELECTED.validator,
7280 suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent
7286 * @config submenu
7287 * @description Object specifying the submenu to be appended to the
7288 * menu item. The value can be one of the following: <ul><li>Object
7289 * specifying a Menu instance.</li><li>Object literal specifying the
7290 * menu to be created. Format: <code>{ id: [menu id], itemdata:
7291 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
7292 * items</a>] }</code>.</li><li>String specifying the id attribute
7293 * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
7294 * Object specifying the <code>&#60;div&#62;</code> element of the
7295 * menu.</li></ul>
7296 * @default null
7297 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
7298 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7299 * HTMLElement</a>
7301 oConfig.addProperty(
7302 DEFAULT_CONFIG.SUBMENU.key,
7303 { handler: this.configSubmenu }
7308 * @config onclick
7309 * @description Object literal representing the code to be executed when
7310 * the item is clicked. Format:<br> <code> {<br>
7311 * <strong>fn:</strong> Function, &#47;&#47; The handler to call when
7312 * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An
7313 * object to pass back to the handler.<br> <strong>scope:</strong>
7314 * Object &#47;&#47; The object to use for the scope of the handler.
7315 * <br> } </code>
7316 * @type Object
7317 * @default null
7319 oConfig.addProperty(
7320 DEFAULT_CONFIG.ONCLICK.key,
7321 { handler: this.configOnClick }
7326 * @config classname
7327 * @description CSS class to be applied to the menu item's root
7328 * <code>&#60;li&#62;</code> element. The specified class(es) are
7329 * appended in addition to the default class as specified by the menu
7330 * item's CSS_CLASS_NAME constant.
7331 * @default null
7332 * @type String
7334 oConfig.addProperty(
7335 DEFAULT_CONFIG.CLASS_NAME.key,
7337 handler: this.configClassName,
7338 value: DEFAULT_CONFIG.CLASS_NAME.value,
7339 validator: DEFAULT_CONFIG.CLASS_NAME.validator
7347 * @method getNextEnabledSibling
7348 * @description Finds the menu item's next enabled sibling.
7349 * @return YAHOO.widget.MenuItem
7351 getNextEnabledSibling: function() {
7353 var nGroupIndex,
7354 aItemGroups,
7355 oNextItem,
7356 nNextGroupIndex,
7357 aNextGroup;
7359 function getNextArrayItem(p_aArray, p_nStartIndex) {
7361 return p_aArray[p_nStartIndex] ||
7362 getNextArrayItem(p_aArray, (p_nStartIndex+1));
7366 if(this.parent instanceof Menu) {
7368 nGroupIndex = this.groupIndex;
7370 aItemGroups = this.parent.getItemGroups();
7372 if(this.index < (aItemGroups[nGroupIndex].length - 1)) {
7374 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
7375 (this.index+1));
7378 else {
7380 if(nGroupIndex < (aItemGroups.length - 1)) {
7382 nNextGroupIndex = nGroupIndex + 1;
7385 else {
7387 nNextGroupIndex = 0;
7391 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
7393 // Retrieve the first menu item in the next group
7395 oNextItem = getNextArrayItem(aNextGroup, 0);
7399 return (oNextItem.cfg.getProperty("disabled") ||
7400 oNextItem.element.style.display == "none") ?
7401 oNextItem.getNextEnabledSibling() : oNextItem;
7409 * @method getPreviousEnabledSibling
7410 * @description Finds the menu item's previous enabled sibling.
7411 * @return {YAHOO.widget.MenuItem}
7413 getPreviousEnabledSibling: function() {
7415 var nGroupIndex,
7416 aItemGroups,
7417 oPreviousItem,
7418 nPreviousGroupIndex,
7419 aPreviousGroup;
7421 function getPreviousArrayItem(p_aArray, p_nStartIndex) {
7423 return p_aArray[p_nStartIndex] ||
7424 getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
7428 function getFirstItemIndex(p_aArray, p_nStartIndex) {
7430 return p_aArray[p_nStartIndex] ? p_nStartIndex :
7431 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
7435 if(this.parent instanceof Menu) {
7437 nGroupIndex = this.groupIndex;
7438 aItemGroups = this.parent.getItemGroups();
7441 if(this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
7443 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
7444 (this.index-1));
7447 else {
7449 if(nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
7451 nPreviousGroupIndex = nGroupIndex - 1;
7454 else {
7456 nPreviousGroupIndex = aItemGroups.length - 1;
7460 aPreviousGroup = getPreviousArrayItem(aItemGroups,
7461 nPreviousGroupIndex);
7463 oPreviousItem = getPreviousArrayItem(aPreviousGroup,
7464 (aPreviousGroup.length - 1));
7468 return (oPreviousItem.cfg.getProperty("disabled") ||
7469 oPreviousItem.element.style.display == "none") ?
7470 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
7478 * @method focus
7479 * @description Causes the menu item to receive the focus and fires the
7480 * focus event.
7482 focus: function() {
7484 var oParent = this.parent,
7485 oAnchor = this._oAnchor,
7486 oActiveItem = oParent.activeItem,
7487 me = this;
7490 function setFocus() {
7492 try {
7494 if (YAHOO.env.ua.ie && !document.hasFocus()) {
7496 return;
7500 oAnchor.focus();
7503 catch(e) {
7510 if(!this.cfg.getProperty("disabled") && oParent &&
7511 oParent.cfg.getProperty("visible") &&
7512 this.element.style.display != "none") {
7514 if(oActiveItem) {
7516 oActiveItem.blur();
7522 Setting focus via a timer fixes a race condition in Firefox, IE
7523 and Opera where the browser viewport jumps as it trys to
7524 position and focus the menu.
7527 window.setTimeout(setFocus, 0);
7529 this.focusEvent.fire();
7537 * @method blur
7538 * @description Causes the menu item to lose focus and fires the
7539 * blur event.
7541 blur: function() {
7543 var oParent = this.parent;
7545 if(!this.cfg.getProperty("disabled") && oParent &&
7546 oParent.cfg.getProperty("visible")) {
7548 this._oAnchor.blur();
7550 this.blurEvent.fire();
7558 * @method hasFocus
7559 * @description Returns a boolean indicating whether or not the menu item
7560 * has focus.
7561 * @return {Boolean}
7563 hasFocus: function() {
7565 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
7571 * @method destroy
7572 * @description Removes the menu item's <code>&#60;li&#62;</code> element
7573 * from its parent <code>&#60;ul&#62;</code> element.
7575 destroy: function() {
7577 var oEl = this.element,
7578 oSubmenu,
7579 oParentNode;
7581 if(oEl) {
7584 // If the item has a submenu, destroy it first
7586 oSubmenu = this.cfg.getProperty("submenu");
7588 if(oSubmenu) {
7590 oSubmenu.destroy();
7595 // Remove CustomEvent listeners
7597 this.mouseOverEvent.unsubscribeAll();
7598 this.mouseOutEvent.unsubscribeAll();
7599 this.mouseDownEvent.unsubscribeAll();
7600 this.mouseUpEvent.unsubscribeAll();
7601 this.clickEvent.unsubscribeAll();
7602 this.keyPressEvent.unsubscribeAll();
7603 this.keyDownEvent.unsubscribeAll();
7604 this.keyUpEvent.unsubscribeAll();
7605 this.focusEvent.unsubscribeAll();
7606 this.blurEvent.unsubscribeAll();
7607 this.cfg.configChangedEvent.unsubscribeAll();
7610 // Remove the element from the parent node
7612 oParentNode = oEl.parentNode;
7614 if(oParentNode) {
7616 oParentNode.removeChild(oEl);
7618 this.destroyEvent.fire();
7622 this.destroyEvent.unsubscribeAll();
7630 * @method toString
7631 * @description Returns a string representing the menu item.
7632 * @return {String}
7634 toString: function() {
7636 var sReturnVal = "MenuItem",
7637 sId = this.id;
7639 if(sId) {
7641 sReturnVal += (" " + sId);
7645 return sReturnVal;
7651 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
7653 })();
7654 (function () {
7658 * Creates a list of options or commands which are made visible in response to
7659 * an HTML element's "contextmenu" event ("mousedown" for Opera).
7661 * @param {String} p_oElement String specifying the id attribute of the
7662 * <code>&#60;div&#62;</code> element of the context menu.
7663 * @param {String} p_oElement String specifying the id attribute of the
7664 * <code>&#60;select&#62;</code> element to be used as the data source for the
7665 * context menu.
7666 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7667 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7668 * <code>&#60;div&#62;</code> element of the context menu.
7669 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7670 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7671 * the <code>&#60;select&#62;</code> element to be used as the data source for
7672 * the context menu.
7673 * @param {Object} p_oConfig Optional. Object literal specifying the
7674 * configuration for the context menu. See configuration class documentation
7675 * for more details.
7676 * @class ContextMenu
7677 * @constructor
7678 * @extends YAHOO.widget.Menu
7679 * @namespace YAHOO.widget
7681 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
7683 YAHOO.widget.ContextMenu.superclass.constructor.call(this,
7684 p_oElement, p_oConfig);
7688 var Event = YAHOO.util.Event,
7689 ContextMenu = YAHOO.widget.ContextMenu,
7692 * Constant representing the name of the ContextMenu's events
7693 * @property EVENT_TYPES
7694 * @private
7695 * @final
7696 * @type Object
7698 EVENT_TYPES = {
7700 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
7701 "CONTEXT_MENU": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"),
7702 "CLICK": "click"
7708 * Constant representing the ContextMenu's configuration properties
7709 * @property DEFAULT_CONFIG
7710 * @private
7711 * @final
7712 * @type Object
7714 DEFAULT_CONFIG = {
7716 "TRIGGER": {
7717 key: "trigger"
7723 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
7727 // Private properties
7731 * @property _oTrigger
7732 * @description Object reference to the current value of the "trigger"
7733 * configuration property.
7734 * @default null
7735 * @private
7736 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
7737 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
7739 _oTrigger: null,
7743 * @property _bCancelled
7744 * @description Boolean indicating if the display of the context menu should
7745 * be cancelled.
7746 * @default false
7747 * @private
7748 * @type Boolean
7750 _bCancelled: false,
7754 // Public properties
7758 * @property contextEventTarget
7759 * @description Object reference for the HTML element that was the target of the
7760 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
7761 * the context menu.
7762 * @default null
7763 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7764 * html.html#ID-58190037">HTMLElement</a>
7766 contextEventTarget: null,
7770 // Events
7774 * @event triggerContextMenuEvent
7775 * @description Custom Event wrapper for the "contextmenu" DOM event
7776 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
7777 * the context menu.
7779 triggerContextMenuEvent: null,
7784 * @method init
7785 * @description The ContextMenu class's initialization method. This method is
7786 * automatically called by the constructor, and sets up all DOM references for
7787 * pre-existing markup, and creates required markup if it is not already present.
7788 * @param {String} p_oElement String specifying the id attribute of the
7789 * <code>&#60;div&#62;</code> element of the context menu.
7790 * @param {String} p_oElement String specifying the id attribute of the
7791 * <code>&#60;select&#62;</code> element to be used as the data source for
7792 * the context menu.
7793 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7794 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7795 * <code>&#60;div&#62;</code> element of the context menu.
7796 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7797 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7798 * the <code>&#60;select&#62;</code> element to be used as the data source for
7799 * the context menu.
7800 * @param {Object} p_oConfig Optional. Object literal specifying the
7801 * configuration for the context menu. See configuration class documentation
7802 * for more details.
7804 init: function(p_oElement, p_oConfig) {
7806 if(!this.ITEM_TYPE) {
7808 this.ITEM_TYPE = YAHOO.widget.ContextMenuItem;
7813 // Call the init of the superclass (YAHOO.widget.Menu)
7815 ContextMenu.superclass.init.call(this, p_oElement);
7818 this.beforeInitEvent.fire(ContextMenu);
7821 if(p_oConfig) {
7823 this.cfg.applyConfig(p_oConfig, true);
7828 this.initEvent.fire(ContextMenu);
7834 * @method initEvents
7835 * @description Initializes the custom events for the context menu.
7837 initEvents: function() {
7839 ContextMenu.superclass.initEvents.call(this);
7841 // Create custom events
7843 this.triggerContextMenuEvent =
7844 this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
7846 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
7852 * @method cancel
7853 * @description Cancels the display of the context menu.
7855 cancel: function() {
7857 this._bCancelled = true;
7863 // Private methods
7867 * @method _removeEventHandlers
7868 * @description Removes all of the DOM event handlers from the HTML element(s)
7869 * whose "context menu" event ("click" for Opera) trigger the display of
7870 * the context menu.
7871 * @private
7873 _removeEventHandlers: function() {
7875 var oTrigger = this._oTrigger;
7878 // Remove the event handlers from the trigger(s)
7880 if (oTrigger) {
7882 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU,
7883 this._onTriggerContextMenu);
7885 if(YAHOO.env.ua.opera) {
7887 Event.removeListener(oTrigger, EVENT_TYPES.CLICK,
7888 this._onTriggerClick);
7898 // Private event handlers
7902 * @method _onTriggerClick
7903 * @description "click" event handler for the HTML element(s) identified as the
7904 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
7905 * @private
7906 * @param {Event} p_oEvent Object representing the DOM event object passed back
7907 * by the event utility (YAHOO.util.Event).
7908 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
7909 * menu that is handling the event.
7911 _onTriggerClick: function(p_oEvent, p_oMenu) {
7913 if(p_oEvent.ctrlKey) {
7915 Event.stopEvent(p_oEvent);
7923 * @method _onTriggerContextMenu
7924 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
7925 * element(s) that trigger the display of the context menu.
7926 * @private
7927 * @param {Event} p_oEvent Object representing the DOM event object passed back
7928 * by the event utility (YAHOO.util.Event).
7929 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
7930 * menu that is handling the event.
7932 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
7934 if(p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {
7936 return;
7942 Prevent the browser's default context menu from appearing and
7943 stop the propagation of the "contextmenu" event so that
7944 other ContextMenu instances are not displayed.
7947 Event.stopEvent(p_oEvent);
7950 // Hide any other ContextMenu instances that might be visible
7952 YAHOO.widget.MenuManager.hideVisible();
7955 this.contextEventTarget = Event.getTarget(p_oEvent);
7957 this.triggerContextMenuEvent.fire(p_oEvent);
7960 if(!this._bCancelled) {
7962 // Position and display the context menu
7964 this.cfg.setProperty("xy", Event.getXY(p_oEvent));
7966 this.show();
7970 this._bCancelled = false;
7976 // Public methods
7980 * @method toString
7981 * @description Returns a string representing the context menu.
7982 * @return {String}
7984 toString: function() {
7986 var sReturnVal = "ContextMenu",
7987 sId = this.id;
7989 if(sId) {
7991 sReturnVal += (" " + sId);
7995 return sReturnVal;
8001 * @method initDefaultConfig
8002 * @description Initializes the class's configurable properties which can be
8003 * changed using the context menu's Config object ("cfg").
8005 initDefaultConfig: function() {
8007 ContextMenu.superclass.initDefaultConfig.call(this);
8010 * @config trigger
8011 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
8012 * for Opera) trigger the display of the context menu. Can be a string
8013 * representing the id attribute of the HTML element, an object reference
8014 * for the HTML element, or an array of strings or HTML element references.
8015 * @default null
8016 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8017 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8019 this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key,
8020 { handler: this.configTrigger });
8026 * @method destroy
8027 * @description Removes the context menu's <code>&#60;div&#62;</code> element
8028 * (and accompanying child nodes) from the document.
8030 destroy: function() {
8032 // Remove the DOM event handlers from the current trigger(s)
8034 this._removeEventHandlers();
8037 // Continue with the superclass implementation of this method
8039 ContextMenu.superclass.destroy.call(this);
8045 // Public event handlers for configuration properties
8049 * @method configTrigger
8050 * @description Event handler for when the value of the "trigger" configuration
8051 * property changes.
8052 * @param {String} p_sType String representing the name of the event that
8053 * was fired.
8054 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8055 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8056 * menu that fired the event.
8058 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8060 var oTrigger = p_aArgs[0];
8062 if(oTrigger) {
8065 If there is a current "trigger" - remove the event handlers
8066 from that element(s) before assigning new ones
8069 if(this._oTrigger) {
8071 this._removeEventHandlers();
8075 this._oTrigger = oTrigger;
8079 Listen for the "mousedown" event in Opera b/c it does not
8080 support the "contextmenu" event
8083 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8084 this._onTriggerContextMenu, this, true);
8088 Assign a "click" event handler to the trigger element(s) for
8089 Opera to prevent default browser behaviors.
8092 if(YAHOO.env.ua.opera) {
8094 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick,
8095 this, true);
8100 else {
8102 this._removeEventHandlers();
8108 }); // END YAHOO.lang.extend
8110 }());
8115 * Creates an item for a context menu.
8117 * @param {String} p_oObject String specifying the text of the context menu item.
8118 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8119 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8120 * <code>&#60;li&#62;</code> element of the context menu item.
8121 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8122 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8123 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8124 * menu item.
8125 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8126 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8127 * the <code>&#60;option&#62;</code> element of the context menu item.
8128 * @param {Object} p_oConfig Optional. Object literal specifying the
8129 * configuration for the context menu item. See configuration class
8130 * documentation for more details.
8131 * @class ContextMenuItem
8132 * @constructor
8133 * @extends YAHOO.widget.MenuItem
8135 YAHOO.widget.ContextMenuItem = function(p_oObject, p_oConfig) {
8137 YAHOO.widget.ContextMenuItem.superclass.constructor.call(this,
8138 p_oObject, p_oConfig);
8142 YAHOO.lang.extend(YAHOO.widget.ContextMenuItem, YAHOO.widget.MenuItem, {
8146 * @method init
8147 * @description The ContextMenuItem class's initialization method. This method
8148 * is automatically called by the constructor, and sets up all DOM references
8149 * for pre-existing markup, and creates required markup if it is not
8150 * already present.
8151 * @param {String} p_oObject String specifying the text of the context menu item.
8152 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8153 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8154 * <code>&#60;li&#62;</code> element of the context menu item.
8155 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8156 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8157 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8158 * menu item.
8159 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8160 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8161 * the <code>&#60;option&#62;</code> element of the context menu item.
8162 * @param {Object} p_oConfig Optional. Object literal specifying the
8163 * configuration for the context menu item. See configuration class
8164 * documentation for more details.
8166 init: function(p_oObject, p_oConfig) {
8168 if(!this.SUBMENU_TYPE) {
8170 this.SUBMENU_TYPE = YAHOO.widget.ContextMenu;
8176 Call the init of the superclass (YAHOO.widget.MenuItem)
8177 Note: We don't pass the user config in here yet
8178 because we only want it executed once, at the lowest
8179 subclass level.
8182 YAHOO.widget.ContextMenuItem.superclass.init.call(this, p_oObject);
8184 var oConfig = this.cfg;
8186 if(p_oConfig) {
8188 oConfig.applyConfig(p_oConfig, true);
8192 oConfig.fireQueue();
8198 // Public methods
8202 * @method toString
8203 * @description Returns a string representing the context menu item.
8204 * @return {String}
8206 toString: function() {
8208 var sReturnVal = "ContextMenuItem";
8210 if(this.cfg && this.cfg.getProperty("text")) {
8212 sReturnVal += (": " + this.cfg.getProperty("text"));
8216 return sReturnVal;
8220 }); // END YAHOO.lang.extend
8221 (function () {
8225 * Horizontal collection of items, each of which can contain a submenu.
8227 * @param {String} p_oElement String specifying the id attribute of the
8228 * <code>&#60;div&#62;</code> element of the menu bar.
8229 * @param {String} p_oElement String specifying the id attribute of the
8230 * <code>&#60;select&#62;</code> element to be used as the data source for the
8231 * menu bar.
8232 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8233 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8234 * the <code>&#60;div&#62;</code> element of the menu bar.
8235 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8236 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8237 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8238 * source for the menu bar.
8239 * @param {Object} p_oConfig Optional. Object literal specifying the
8240 * configuration for the menu bar. See configuration class documentation for
8241 * more details.
8242 * @class MenuBar
8243 * @constructor
8244 * @extends YAHOO.widget.Menu
8245 * @namespace YAHOO.widget
8247 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
8249 YAHOO.widget.MenuBar.superclass.constructor.call(this,
8250 p_oElement, p_oConfig);
8256 * @method checkPosition
8257 * @description Checks to make sure that the value of the "position" property
8258 * is one of the supported strings. Returns true if the position is supported.
8259 * @private
8260 * @param {Object} p_sPosition String specifying the position of the menu.
8261 * @return {Boolean}
8263 function checkPosition(p_sPosition) {
8265 if (typeof p_sPosition == "string") {
8267 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
8274 var Event = YAHOO.util.Event,
8275 Dom = YAHOO.util.Dom,
8276 MenuBar = YAHOO.widget.MenuBar,
8279 * Constant representing the MenuBar's configuration properties
8280 * @property DEFAULT_CONFIG
8281 * @private
8282 * @final
8283 * @type Object
8285 DEFAULT_CONFIG = {
8287 "POSITION": {
8288 key: "position",
8289 value: "static",
8290 validator: checkPosition,
8291 supercedes: ["visible"]
8294 "SUBMENU_ALIGNMENT": {
8295 key: "submenualignment",
8296 value: ["tl","bl"]
8299 "AUTO_SUBMENU_DISPLAY": {
8300 key: "autosubmenudisplay",
8301 value: false,
8302 validator: YAHOO.lang.isBoolean
8309 YAHOO.lang.extend(MenuBar, YAHOO.widget.Menu, {
8312 * @method init
8313 * @description The MenuBar class's initialization method. This method is
8314 * automatically called by the constructor, and sets up all DOM references for
8315 * pre-existing markup, and creates required markup if it is not already present.
8316 * @param {String} p_oElement String specifying the id attribute of the
8317 * <code>&#60;div&#62;</code> element of the menu bar.
8318 * @param {String} p_oElement String specifying the id attribute of the
8319 * <code>&#60;select&#62;</code> element to be used as the data source for the
8320 * menu bar.
8321 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8322 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8323 * the <code>&#60;div&#62;</code> element of the menu bar.
8324 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8325 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8326 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8327 * source for the menu bar.
8328 * @param {Object} p_oConfig Optional. Object literal specifying the
8329 * configuration for the menu bar. See configuration class documentation for
8330 * more details.
8332 init: function(p_oElement, p_oConfig) {
8334 if(!this.ITEM_TYPE) {
8336 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
8341 // Call the init of the superclass (YAHOO.widget.Menu)
8343 MenuBar.superclass.init.call(this, p_oElement);
8346 this.beforeInitEvent.fire(MenuBar);
8349 if(p_oConfig) {
8351 this.cfg.applyConfig(p_oConfig, true);
8355 this.initEvent.fire(MenuBar);
8361 // Constants
8365 * @property CSS_CLASS_NAME
8366 * @description String representing the CSS class(es) to be applied to the menu
8367 * bar's <code>&#60;div&#62;</code> element.
8368 * @default "yuimenubar"
8369 * @final
8370 * @type String
8372 CSS_CLASS_NAME: "yuimenubar",
8376 // Protected event handlers
8380 * @method _onKeyDown
8381 * @description "keydown" Custom Event handler for the menu bar.
8382 * @private
8383 * @param {String} p_sType String representing the name of the event that
8384 * was fired.
8385 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8386 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8387 * that fired the event.
8389 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
8391 var oEvent = p_aArgs[0],
8392 oItem = p_aArgs[1],
8393 oSubmenu,
8394 oItemCfg,
8395 oNextItem;
8398 if(oItem && !oItem.cfg.getProperty("disabled")) {
8400 oItemCfg = oItem.cfg;
8402 switch(oEvent.keyCode) {
8404 case 37: // Left arrow
8405 case 39: // Right arrow
8407 if(oItem == this.activeItem &&
8408 !oItemCfg.getProperty("selected")) {
8410 oItemCfg.setProperty("selected", true);
8413 else {
8415 oNextItem = (oEvent.keyCode == 37) ?
8416 oItem.getPreviousEnabledSibling() :
8417 oItem.getNextEnabledSibling();
8419 if(oNextItem) {
8421 this.clearActiveItem();
8423 oNextItem.cfg.setProperty("selected", true);
8426 if(this.cfg.getProperty("autosubmenudisplay")) {
8428 oSubmenu = oNextItem.cfg.getProperty("submenu");
8430 if(oSubmenu) {
8432 oSubmenu.show();
8438 oNextItem.focus();
8444 Event.preventDefault(oEvent);
8446 break;
8448 case 40: // Down arrow
8450 if(this.activeItem != oItem) {
8452 this.clearActiveItem();
8454 oItemCfg.setProperty("selected", true);
8455 oItem.focus();
8459 oSubmenu = oItemCfg.getProperty("submenu");
8461 if(oSubmenu) {
8463 if(oSubmenu.cfg.getProperty("visible")) {
8465 oSubmenu.setInitialSelection();
8466 oSubmenu.setInitialFocus();
8469 else {
8471 oSubmenu.show();
8477 Event.preventDefault(oEvent);
8479 break;
8486 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
8488 oSubmenu = this.activeItem.cfg.getProperty("submenu");
8490 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
8492 oSubmenu.hide();
8493 this.activeItem.focus();
8496 else {
8498 this.activeItem.cfg.setProperty("selected", false);
8499 this.activeItem.blur();
8503 Event.preventDefault(oEvent);
8511 * @method _onClick
8512 * @description "click" event handler for the menu bar.
8513 * @protected
8514 * @param {String} p_sType String representing the name of the event that
8515 * was fired.
8516 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8517 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8518 * that fired the event.
8520 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
8522 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
8524 var oItem = p_aArgs[1],
8525 oEvent,
8526 oTarget,
8527 oActiveItem,
8528 oConfig,
8529 oSubmenu;
8532 if(oItem && !oItem.cfg.getProperty("disabled")) {
8534 oEvent = p_aArgs[0];
8535 oTarget = Event.getTarget(oEvent);
8536 oActiveItem = this.activeItem;
8537 oConfig = this.cfg;
8540 // Hide any other submenus that might be visible
8542 if(oActiveItem && oActiveItem != oItem) {
8544 this.clearActiveItem();
8549 oItem.cfg.setProperty("selected", true);
8552 // Show the submenu for the item
8554 oSubmenu = oItem.cfg.getProperty("submenu");
8557 if(oSubmenu && oTarget != oItem.submenuIndicator) {
8559 if(oSubmenu.cfg.getProperty("visible")) {
8561 oSubmenu.hide();
8564 else {
8566 oSubmenu.show();
8578 // Public methods
8582 * @method toString
8583 * @description Returns a string representing the menu bar.
8584 * @return {String}
8586 toString: function() {
8588 var sReturnVal = "MenuBar",
8589 sId = this.id;
8591 if(sId) {
8593 sReturnVal += (" " + sId);
8597 return sReturnVal;
8603 * @description Initializes the class's configurable properties which can be
8604 * changed using the menu bar's Config object ("cfg").
8605 * @method initDefaultConfig
8607 initDefaultConfig: function() {
8609 MenuBar.superclass.initDefaultConfig.call(this);
8611 var oConfig = this.cfg;
8613 // Add configuration properties
8617 Set the default value for the "position" configuration property
8618 to "static" by re-adding the property.
8623 * @config position
8624 * @description String indicating how a menu bar should be positioned on the
8625 * screen. Possible values are "static" and "dynamic." Static menu bars
8626 * are visible by default and reside in the normal flow of the document
8627 * (CSS position: static). Dynamic menu bars are hidden by default, reside
8628 * out of the normal flow of the document (CSS position: absolute), and can
8629 * overlay other elements on the screen.
8630 * @default static
8631 * @type String
8633 oConfig.addProperty(
8634 DEFAULT_CONFIG.POSITION.key,
8636 handler: this.configPosition,
8637 value: DEFAULT_CONFIG.POSITION.value,
8638 validator: DEFAULT_CONFIG.POSITION.validator,
8639 supercedes: DEFAULT_CONFIG.POSITION.supercedes
8645 Set the default value for the "submenualignment" configuration property
8646 to ["tl","bl"] by re-adding the property.
8650 * @config submenualignment
8651 * @description Array defining how submenus should be aligned to their
8652 * parent menu bar item. The format is: [itemCorner, submenuCorner].
8653 * @default ["tl","bl"]
8654 * @type Array
8656 oConfig.addProperty(
8657 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
8659 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value
8665 Change the default value for the "autosubmenudisplay" configuration
8666 property to "false" by re-adding the property.
8670 * @config autosubmenudisplay
8671 * @description Boolean indicating if submenus are automatically made
8672 * visible when the user mouses over the menu bar's items.
8673 * @default false
8674 * @type Boolean
8676 oConfig.addProperty(
8677 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
8679 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
8680 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator
8686 }); // END YAHOO.lang.extend
8688 }());
8693 * Creates an item for a menu bar.
8695 * @param {String} p_oObject String specifying the text of the menu bar item.
8696 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8697 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8698 * <code>&#60;li&#62;</code> element of the menu bar item.
8699 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8700 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8701 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8702 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8703 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8704 * the <code>&#60;option&#62;</code> element of the menu bar item.
8705 * @param {Object} p_oConfig Optional. Object literal specifying the
8706 * configuration for the menu bar item. See configuration class documentation
8707 * for more details.
8708 * @class MenuBarItem
8709 * @constructor
8710 * @extends YAHOO.widget.MenuItem
8712 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
8714 YAHOO.widget.MenuBarItem.superclass.constructor.call(this,
8715 p_oObject, p_oConfig);
8719 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
8724 * @method init
8725 * @description The MenuBarItem class's initialization method. This method is
8726 * automatically called by the constructor, and sets up all DOM references for
8727 * pre-existing markup, and creates required markup if it is not already present.
8728 * @param {String} p_oObject String specifying the text of the menu bar item.
8729 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8730 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8731 * <code>&#60;li&#62;</code> element of the menu bar item.
8732 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8733 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8734 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8735 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8736 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8737 * the <code>&#60;option&#62;</code> element of the menu bar item.
8738 * @param {Object} p_oConfig Optional. Object literal specifying the
8739 * configuration for the menu bar item. See configuration class documentation
8740 * for more details.
8742 init: function(p_oObject, p_oConfig) {
8744 if(!this.SUBMENU_TYPE) {
8746 this.SUBMENU_TYPE = YAHOO.widget.Menu;
8752 Call the init of the superclass (YAHOO.widget.MenuItem)
8753 Note: We don't pass the user config in here yet
8754 because we only want it executed once, at the lowest
8755 subclass level.
8758 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
8761 var oConfig = this.cfg;
8763 if(p_oConfig) {
8765 oConfig.applyConfig(p_oConfig, true);
8769 oConfig.fireQueue();
8775 // Constants
8779 * @property CSS_CLASS_NAME
8780 * @description String representing the CSS class(es) to be applied to the
8781 * <code>&#60;li&#62;</code> element of the menu bar item.
8782 * @default "yuimenubaritem"
8783 * @final
8784 * @type String
8786 CSS_CLASS_NAME: "yuimenubaritem",
8790 * @property CSS_LABEL_CLASS_NAME
8791 * @description String representing the CSS class(es) to be applied to the
8792 * menu bar item's <code>&#60;a&#62;</code> element.
8793 * @default "yuimenubaritemlabel"
8794 * @final
8795 * @type String
8797 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
8801 // Public methods
8805 * @method toString
8806 * @description Returns a string representing the menu bar item.
8807 * @return {String}
8809 toString: function() {
8811 var sReturnVal = "MenuBarItem";
8813 if(this.cfg && this.cfg.getProperty("text")) {
8815 sReturnVal += (": " + this.cfg.getProperty("text"));
8819 return sReturnVal;
8823 }); // END YAHOO.lang.extend
8824 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.3.0", build: "442"});