Merge commit 'catalyst/MOODLE_19_STABLE' into mdl19-linuxchix
[moodle-linuxchix.git] / lib / yui / menu / menu.js
bloba3d4549c24ec6d0f6de42ec435f4cd221cc874fb
1 /*
2 Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.5.2
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>Keyboard and mouse navigation.</li>
18 * <li>A rich event model that provides access to all of a menu's
19 * interesting moments.</li>
20 * <li>Support for
21 * <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
22 * Enhancement</a>; Menus can be created from simple,
23 * semantic markup on the page or purely through JavaScript.</li>
24 * </ul>
25 * @title Menu
26 * @namespace YAHOO.widget
27 * @requires Event, Dom, Container
29 (function () {
31 var Dom = YAHOO.util.Dom,
32 Event = YAHOO.util.Event;
35 /**
36 * Singleton that manages a collection of all menus and menu items. Listens
37 * for DOM events at the document level and dispatches the events to the
38 * corresponding menu or menu item.
40 * @namespace YAHOO.widget
41 * @class MenuManager
42 * @static
44 YAHOO.widget.MenuManager = function () {
46 // Private member variables
49 // Flag indicating if the DOM event handlers have been attached
51 var m_bInitializedEventHandlers = false,
54 // Collection of menus
56 m_oMenus = {},
59 // Collection of visible menus
61 m_oVisibleMenus = {},
64 // Collection of menu items
66 m_oItems = {},
69 // Map of DOM event types to their equivalent CustomEvent types
71 m_oEventTypes = {
72 "click": "clickEvent",
73 "mousedown": "mouseDownEvent",
74 "mouseup": "mouseUpEvent",
75 "mouseover": "mouseOverEvent",
76 "mouseout": "mouseOutEvent",
77 "keydown": "keyDownEvent",
78 "keyup": "keyUpEvent",
79 "keypress": "keyPressEvent"
83 m_oFocusedMenuItem = null;
89 // Private methods
92 /**
93 * @method getMenuRootElement
94 * @description Finds the root DIV node of a menu or the root LI node of
95 * a menu item.
96 * @private
97 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
98 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
99 * specifying an HTML element.
101 function getMenuRootElement(p_oElement) {
103 var oParentNode;
105 if (p_oElement && p_oElement.tagName) {
107 switch (p_oElement.tagName.toUpperCase()) {
109 case "DIV":
111 oParentNode = p_oElement.parentNode;
113 // Check if the DIV is the inner "body" node of a menu
115 if (
117 Dom.hasClass(p_oElement, "hd") ||
118 Dom.hasClass(p_oElement, "bd") ||
119 Dom.hasClass(p_oElement, "ft")
120 ) &&
121 oParentNode &&
122 oParentNode.tagName &&
123 oParentNode.tagName.toUpperCase() == "DIV")
126 return oParentNode;
129 else {
131 return p_oElement;
135 break;
137 case "LI":
139 return p_oElement;
141 default:
143 oParentNode = p_oElement.parentNode;
145 if (oParentNode) {
147 return getMenuRootElement(oParentNode);
151 break;
161 // Private event handlers
165 * @method onDOMEvent
166 * @description Generic, global event handler for all of a menu's
167 * DOM-based events. This listens for events against the document
168 * object. If the target of a given event is a member of a menu or
169 * menu item's DOM, the instance's corresponding Custom Event is fired.
170 * @private
171 * @param {Event} p_oEvent Object representing the DOM event object
172 * passed back by the event utility (YAHOO.util.Event).
174 function onDOMEvent(p_oEvent) {
176 // Get the target node of the DOM event
178 var oTarget = Event.getTarget(p_oEvent),
180 // See if the target of the event was a menu, or a menu item
182 oElement = getMenuRootElement(oTarget),
183 sCustomEventType,
184 sTagName,
185 sId,
186 oMenuItem,
187 oMenu;
190 if (oElement) {
192 sTagName = oElement.tagName.toUpperCase();
194 if (sTagName == "LI") {
196 sId = oElement.id;
198 if (sId && m_oItems[sId]) {
200 oMenuItem = m_oItems[sId];
201 oMenu = oMenuItem.parent;
206 else if (sTagName == "DIV") {
208 if (oElement.id) {
210 oMenu = m_oMenus[oElement.id];
219 if (oMenu) {
221 sCustomEventType = m_oEventTypes[p_oEvent.type];
224 // Fire the Custom Event that corresponds the current DOM event
226 if (oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
228 oMenuItem[sCustomEventType].fire(p_oEvent);
231 if (
232 p_oEvent.type == "keyup" ||
233 p_oEvent.type == "mousedown")
236 if (m_oFocusedMenuItem != oMenuItem) {
238 if (m_oFocusedMenuItem) {
240 m_oFocusedMenuItem.blurEvent.fire();
244 oMenuItem.focusEvent.fire();
252 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
255 else if (p_oEvent.type == "mousedown") {
257 if (m_oFocusedMenuItem) {
259 m_oFocusedMenuItem.blurEvent.fire();
261 m_oFocusedMenuItem = null;
267 If the target of the event wasn't a menu, hide all
268 dynamically positioned menus
271 for (var i in m_oVisibleMenus) {
273 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
275 oMenu = m_oVisibleMenus[i];
277 if (oMenu.cfg.getProperty("clicktohide") &&
278 !(oMenu instanceof YAHOO.widget.MenuBar) &&
279 oMenu.cfg.getProperty("position") == "dynamic") {
281 oMenu.hide();
284 else {
286 if (oMenu.cfg.getProperty("showdelay") > 0) {
288 oMenu._cancelShowDelay();
293 if (oMenu.activeItem) {
295 oMenu.activeItem.blur();
296 oMenu.activeItem.cfg.setProperty("selected", false);
298 oMenu.activeItem = null;
309 else if (p_oEvent.type == "keyup") {
311 if (m_oFocusedMenuItem) {
313 m_oFocusedMenuItem.blurEvent.fire();
315 m_oFocusedMenuItem = null;
325 * @method onMenuDestroy
326 * @description "destroy" event handler for a menu.
327 * @private
328 * @param {String} p_sType String representing the name of the event
329 * that was fired.
330 * @param {Array} p_aArgs Array of arguments sent when the event
331 * was fired.
332 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
334 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
336 if (m_oMenus[p_oMenu.id]) {
338 this.removeMenu(p_oMenu);
346 * @method onMenuFocus
347 * @description "focus" event handler for a MenuItem instance.
348 * @private
349 * @param {String} p_sType String representing the name of the event
350 * that was fired.
351 * @param {Array} p_aArgs Array of arguments sent when the event
352 * was fired.
354 function onMenuFocus(p_sType, p_aArgs) {
356 var oItem = p_aArgs[0];
358 if (oItem) {
360 m_oFocusedMenuItem = oItem;
368 * @method onMenuBlur
369 * @description "blur" event handler for a MenuItem instance.
370 * @private
371 * @param {String} p_sType String representing the name of the event
372 * that was fired.
373 * @param {Array} p_aArgs Array of arguments sent when the event
374 * was fired.
376 function onMenuBlur(p_sType, p_aArgs) {
378 m_oFocusedMenuItem = null;
385 * @method onMenuVisibleConfigChange
386 * @description Event handler for when the "visible" configuration
387 * property of a Menu instance changes.
388 * @private
389 * @param {String} p_sType String representing the name of the event
390 * that was fired.
391 * @param {Array} p_aArgs Array of arguments sent when the event
392 * was fired.
394 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
396 var bVisible = p_aArgs[0],
397 sId = this.id;
399 if (bVisible) {
401 m_oVisibleMenus[sId] = this;
405 else if (m_oVisibleMenus[sId]) {
407 delete m_oVisibleMenus[sId];
416 * @method onItemDestroy
417 * @description "destroy" event handler for a MenuItem instance.
418 * @private
419 * @param {String} p_sType String representing the name of the event
420 * that was fired.
421 * @param {Array} p_aArgs Array of arguments sent when the event
422 * was fired.
424 function onItemDestroy(p_sType, p_aArgs) {
426 removeItem(this);
431 function removeItem(p_oMenuItem) {
433 var sId = p_oMenuItem.id;
435 if (sId && m_oItems[sId]) {
437 if (m_oFocusedMenuItem == p_oMenuItem) {
439 m_oFocusedMenuItem = null;
443 delete m_oItems[sId];
445 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
454 * @method onItemAdded
455 * @description "itemadded" event handler for a Menu instance.
456 * @private
457 * @param {String} p_sType String representing the name of the event
458 * that was fired.
459 * @param {Array} p_aArgs Array of arguments sent when the event
460 * was fired.
462 function onItemAdded(p_sType, p_aArgs) {
464 var oItem = p_aArgs[0],
465 sId;
467 if (oItem instanceof YAHOO.widget.MenuItem) {
469 sId = oItem.id;
471 if (!m_oItems[sId]) {
473 m_oItems[sId] = oItem;
475 oItem.destroyEvent.subscribe(onItemDestroy);
485 return {
487 // Privileged methods
491 * @method addMenu
492 * @description Adds a menu to the collection of known menus.
493 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
494 * instance to be added.
496 addMenu: function (p_oMenu) {
498 var oDoc;
500 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
501 !m_oMenus[p_oMenu.id]) {
503 m_oMenus[p_oMenu.id] = p_oMenu;
506 if (!m_bInitializedEventHandlers) {
508 oDoc = document;
510 Event.on(oDoc, "mouseover", onDOMEvent, this, true);
511 Event.on(oDoc, "mouseout", onDOMEvent, this, true);
512 Event.on(oDoc, "mousedown", onDOMEvent, this, true);
513 Event.on(oDoc, "mouseup", onDOMEvent, this, true);
514 Event.on(oDoc, "click", onDOMEvent, this, true);
515 Event.on(oDoc, "keydown", onDOMEvent, this, true);
516 Event.on(oDoc, "keyup", onDOMEvent, this, true);
517 Event.on(oDoc, "keypress", onDOMEvent, this, true);
520 m_bInitializedEventHandlers = true;
525 p_oMenu.cfg.subscribeToConfigEvent("visible",
526 onMenuVisibleConfigChange);
528 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu,
529 this);
531 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
532 p_oMenu.focusEvent.subscribe(onMenuFocus);
533 p_oMenu.blurEvent.subscribe(onMenuBlur);
542 * @method removeMenu
543 * @description Removes a menu from the collection of known menus.
544 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
545 * instance to be removed.
547 removeMenu: function (p_oMenu) {
549 var sId,
550 aItems,
553 if (p_oMenu) {
555 sId = p_oMenu.id;
557 if (m_oMenus[sId] == p_oMenu) {
559 // Unregister each menu item
561 aItems = p_oMenu.getItems();
563 if (aItems && aItems.length > 0) {
565 i = aItems.length - 1;
567 do {
569 removeItem(aItems[i]);
572 while (i--);
577 // Unregister the menu
579 delete m_oMenus[sId];
584 Unregister the menu from the collection of
585 visible menus
588 if (m_oVisibleMenus[sId] == p_oMenu) {
590 delete m_oVisibleMenus[sId];
596 // Unsubscribe event listeners
598 if (p_oMenu.cfg) {
600 p_oMenu.cfg.unsubscribeFromConfigEvent("visible",
601 onMenuVisibleConfigChange);
605 p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
606 p_oMenu);
608 p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
609 p_oMenu.focusEvent.unsubscribe(onMenuFocus);
610 p_oMenu.blurEvent.unsubscribe(onMenuBlur);
620 * @method hideVisible
621 * @description Hides all visible, dynamically positioned menus
622 * (excluding instances of YAHOO.widget.MenuBar).
624 hideVisible: function () {
626 var oMenu;
628 for (var i in m_oVisibleMenus) {
630 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
632 oMenu = m_oVisibleMenus[i];
634 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
635 oMenu.cfg.getProperty("position") == "dynamic") {
637 oMenu.hide();
649 * @method getVisible
650 * @description Returns a collection of all visible menus registered
651 * with the menu manger.
652 * @return {Array}
654 getVisible: function () {
656 return m_oVisibleMenus;
662 * @method getMenus
663 * @description Returns a collection of all menus registered with the
664 * menu manger.
665 * @return {Array}
667 getMenus: function () {
669 return m_oMenus;
675 * @method getMenu
676 * @description Returns a menu with the specified id.
677 * @param {String} p_sId String specifying the id of the
678 * <code>&#60;div&#62;</code> element representing the menu to
679 * be retrieved.
680 * @return {YAHOO.widget.Menu}
682 getMenu: function (p_sId) {
684 var oMenu = m_oMenus[p_sId];
686 if (oMenu) {
688 return oMenu;
696 * @method getMenuItem
697 * @description Returns a menu item with the specified id.
698 * @param {String} p_sId String specifying the id of the
699 * <code>&#60;li&#62;</code> element representing the menu item to
700 * be retrieved.
701 * @return {YAHOO.widget.MenuItem}
703 getMenuItem: function (p_sId) {
705 var oItem = m_oItems[p_sId];
707 if (oItem) {
709 return oItem;
717 * @method getMenuItemGroup
718 * @description Returns an array of menu item instances whose
719 * corresponding <code>&#60;li&#62;</code> elements are child
720 * nodes of the <code>&#60;ul&#62;</code> element with the
721 * specified id.
722 * @param {String} p_sId String specifying the id of the
723 * <code>&#60;ul&#62;</code> element representing the group of
724 * menu items to be retrieved.
725 * @return {Array}
727 getMenuItemGroup: function (p_sId) {
729 var oUL = Dom.get(p_sId),
730 aItems,
731 oNode,
732 oItem,
733 sId;
736 if (oUL && oUL.tagName &&
737 oUL.tagName.toUpperCase() == "UL") {
739 oNode = oUL.firstChild;
741 if (oNode) {
743 aItems = [];
745 do {
747 sId = oNode.id;
749 if (sId) {
751 oItem = this.getMenuItem(sId);
753 if (oItem) {
755 aItems[aItems.length] = oItem;
762 while ((oNode = oNode.nextSibling));
765 if (aItems.length > 0) {
767 return aItems;
779 * @method getFocusedMenuItem
780 * @description Returns a reference to the menu item that currently
781 * has focus.
782 * @return {YAHOO.widget.MenuItem}
784 getFocusedMenuItem: function () {
786 return m_oFocusedMenuItem;
792 * @method getFocusedMenu
793 * @description Returns a reference to the menu that currently
794 * has focus.
795 * @return {YAHOO.widget.Menu}
797 getFocusedMenu: function () {
799 if (m_oFocusedMenuItem) {
801 return (m_oFocusedMenuItem.parent.getRoot());
809 * @method toString
810 * @description Returns a string representing the menu manager.
811 * @return {String}
813 toString: function () {
815 return "MenuManager";
821 }();
823 })();
827 (function () {
831 * The Menu class creates a container that holds a vertical list representing
832 * a set of options or commands. Menu is the base class for all
833 * menu containers.
834 * @param {String} p_oElement String specifying the id attribute of the
835 * <code>&#60;div&#62;</code> element of the menu.
836 * @param {String} p_oElement String specifying the id attribute of the
837 * <code>&#60;select&#62;</code> element to be used as the data source
838 * for the menu.
839 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
840 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
841 * specifying the <code>&#60;div&#62;</code> element of the menu.
842 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
843 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
844 * Object specifying the <code>&#60;select&#62;</code> element to be used as
845 * the data source for the menu.
846 * @param {Object} p_oConfig Optional. Object literal specifying the
847 * configuration for the menu. See configuration class documentation for
848 * more details.
849 * @namespace YAHOO.widget
850 * @class Menu
851 * @constructor
852 * @extends YAHOO.widget.Overlay
854 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
856 if (p_oConfig) {
858 this.parent = p_oConfig.parent;
859 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
860 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
865 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
872 * @method checkPosition
873 * @description Checks to make sure that the value of the "position" property
874 * is one of the supported strings. Returns true if the position is supported.
875 * @private
876 * @param {Object} p_sPosition String specifying the position of the menu.
877 * @return {Boolean}
879 function checkPosition(p_sPosition) {
881 if (typeof p_sPosition == "string") {
883 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
890 var Dom = YAHOO.util.Dom,
891 Event = YAHOO.util.Event,
892 Module = YAHOO.widget.Module,
893 Overlay = YAHOO.widget.Overlay,
894 Menu = YAHOO.widget.Menu,
895 MenuManager = YAHOO.widget.MenuManager,
896 CustomEvent = YAHOO.util.CustomEvent,
897 Lang = YAHOO.lang,
898 UA = YAHOO.env.ua,
900 m_oShadowTemplate,
903 * Constant representing the name of the Menu's events
904 * @property EVENT_TYPES
905 * @private
906 * @final
907 * @type Object
909 EVENT_TYPES = {
911 "MOUSE_OVER": "mouseover",
912 "MOUSE_OUT": "mouseout",
913 "MOUSE_DOWN": "mousedown",
914 "MOUSE_UP": "mouseup",
915 "CLICK": "click",
916 "KEY_PRESS": "keypress",
917 "KEY_DOWN": "keydown",
918 "KEY_UP": "keyup",
919 "FOCUS": "focus",
920 "BLUR": "blur",
921 "ITEM_ADDED": "itemAdded",
922 "ITEM_REMOVED": "itemRemoved"
928 * Constant representing the Menu's configuration properties
929 * @property DEFAULT_CONFIG
930 * @private
931 * @final
932 * @type Object
934 DEFAULT_CONFIG = {
936 "VISIBLE": {
937 key: "visible",
938 value: false,
939 validator: Lang.isBoolean
942 "CONSTRAIN_TO_VIEWPORT": {
943 key: "constraintoviewport",
944 value: true,
945 validator: Lang.isBoolean,
946 supercedes: ["iframe","x","y","xy"]
949 "POSITION": {
950 key: "position",
951 value: "dynamic",
952 validator: checkPosition,
953 supercedes: ["visible", "iframe"]
956 "SUBMENU_ALIGNMENT": {
957 key: "submenualignment",
958 value: ["tl","tr"],
959 suppressEvent: true
962 "AUTO_SUBMENU_DISPLAY": {
963 key: "autosubmenudisplay",
964 value: true,
965 validator: Lang.isBoolean,
966 suppressEvent: true
969 "SHOW_DELAY": {
970 key: "showdelay",
971 value: 250,
972 validator: Lang.isNumber,
973 suppressEvent: true
976 "HIDE_DELAY": {
977 key: "hidedelay",
978 value: 0,
979 validator: Lang.isNumber,
980 suppressEvent: true
983 "SUBMENU_HIDE_DELAY": {
984 key: "submenuhidedelay",
985 value: 250,
986 validator: Lang.isNumber,
987 suppressEvent: true
990 "CLICK_TO_HIDE": {
991 key: "clicktohide",
992 value: true,
993 validator: Lang.isBoolean,
994 suppressEvent: true
997 "CONTAINER": {
998 key: "container",
999 suppressEvent: true
1002 "SCROLL_INCREMENT": {
1003 key: "scrollincrement",
1004 value: 1,
1005 validator: Lang.isNumber,
1006 supercedes: ["maxheight"],
1007 suppressEvent: true
1010 "MIN_SCROLL_HEIGHT": {
1011 key: "minscrollheight",
1012 value: 90,
1013 validator: Lang.isNumber,
1014 supercedes: ["maxheight"],
1015 suppressEvent: true
1018 "MAX_HEIGHT": {
1019 key: "maxheight",
1020 value: 0,
1021 validator: Lang.isNumber,
1022 supercedes: ["iframe"],
1023 suppressEvent: true
1026 "CLASS_NAME": {
1027 key: "classname",
1028 value: null,
1029 validator: Lang.isString,
1030 suppressEvent: true
1033 "DISABLED": {
1034 key: "disabled",
1035 value: false,
1036 validator: Lang.isBoolean,
1037 suppressEvent: true
1044 YAHOO.lang.extend(Menu, Overlay, {
1047 // Constants
1051 * @property CSS_CLASS_NAME
1052 * @description String representing the CSS class(es) to be applied to the
1053 * menu's <code>&#60;div&#62;</code> element.
1054 * @default "yuimenu"
1055 * @final
1056 * @type String
1058 CSS_CLASS_NAME: "yuimenu",
1062 * @property ITEM_TYPE
1063 * @description Object representing the type of menu item to instantiate and
1064 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
1065 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
1066 * of the menu's source HTML element.
1067 * @default YAHOO.widget.MenuItem
1068 * @final
1069 * @type YAHOO.widget.MenuItem
1071 ITEM_TYPE: null,
1075 * @property GROUP_TITLE_TAG_NAME
1076 * @description String representing the tagname of the HTML element used to
1077 * title the menu's item groups.
1078 * @default H6
1079 * @final
1080 * @type String
1082 GROUP_TITLE_TAG_NAME: "h6",
1086 * @property OFF_SCREEN_POSITION
1087 * @description Array representing the default x and y position that a menu
1088 * should have when it is positioned outside the viewport by the
1089 * "poistionOffScreen" method.
1090 * @default [-10000, -10000]
1091 * @final
1092 * @type Array
1094 OFF_SCREEN_POSITION: [-10000, -10000],
1097 // Private properties
1100 /**
1101 * @property _nHideDelayId
1102 * @description Number representing the time-out setting used to cancel the
1103 * hiding of a menu.
1104 * @default null
1105 * @private
1106 * @type Number
1108 _nHideDelayId: null,
1111 /**
1112 * @property _nShowDelayId
1113 * @description Number representing the time-out setting used to cancel the
1114 * showing of a menu.
1115 * @default null
1116 * @private
1117 * @type Number
1119 _nShowDelayId: null,
1122 /**
1123 * @property _nSubmenuHideDelayId
1124 * @description Number representing the time-out setting used to cancel the
1125 * hiding of a submenu.
1126 * @default null
1127 * @private
1128 * @type Number
1130 _nSubmenuHideDelayId: null,
1133 /**
1134 * @property _nBodyScrollId
1135 * @description Number representing the time-out setting used to cancel the
1136 * scrolling of the menu's body element.
1137 * @default null
1138 * @private
1139 * @type Number
1141 _nBodyScrollId: null,
1144 /**
1145 * @property _bHideDelayEventHandlersAssigned
1146 * @description Boolean indicating if the "mouseover" and "mouseout" event
1147 * handlers used for hiding the menu via a call to "window.setTimeout" have
1148 * already been assigned.
1149 * @default false
1150 * @private
1151 * @type Boolean
1153 _bHideDelayEventHandlersAssigned: false,
1157 * @property _bHandledMouseOverEvent
1158 * @description Boolean indicating the current state of the menu's
1159 * "mouseover" event.
1160 * @default false
1161 * @private
1162 * @type Boolean
1164 _bHandledMouseOverEvent: false,
1168 * @property _bHandledMouseOutEvent
1169 * @description Boolean indicating the current state of the menu's
1170 * "mouseout" event.
1171 * @default false
1172 * @private
1173 * @type Boolean
1175 _bHandledMouseOutEvent: false,
1179 * @property _aGroupTitleElements
1180 * @description Array of HTML element used to title groups of menu items.
1181 * @default []
1182 * @private
1183 * @type Array
1185 _aGroupTitleElements: null,
1189 * @property _aItemGroups
1190 * @description Multi-dimensional Array representing the menu items as they
1191 * are grouped in the menu.
1192 * @default []
1193 * @private
1194 * @type Array
1196 _aItemGroups: null,
1200 * @property _aListElements
1201 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is
1202 * the parent node for each item's <code>&#60;li&#62;</code> element.
1203 * @default []
1204 * @private
1205 * @type Array
1207 _aListElements: null,
1211 * @property _nCurrentMouseX
1212 * @description The current x coordinate of the mouse inside the area of
1213 * the menu.
1214 * @default 0
1215 * @private
1216 * @type Number
1218 _nCurrentMouseX: 0,
1222 * @property _bStopMouseEventHandlers
1223 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1224 * from executing.
1225 * @default false
1226 * @private
1227 * @type Boolean
1229 _bStopMouseEventHandlers: false,
1233 * @property _sClassName
1234 * @description The current value of the "classname" configuration attribute.
1235 * @default null
1236 * @private
1237 * @type String
1239 _sClassName: null,
1243 // Public properties
1247 * @property lazyLoad
1248 * @description Boolean indicating if the menu's "lazy load" feature is
1249 * enabled. If set to "true," initialization and rendering of the menu's
1250 * items will be deferred until the first time it is made visible. This
1251 * property should be set via the constructor using the configuration
1252 * object literal.
1253 * @default false
1254 * @type Boolean
1256 lazyLoad: false,
1260 * @property itemData
1261 * @description Array of items to be added to the menu. The array can contain
1262 * strings representing the text for each item to be created, object literals
1263 * representing the menu item configuration properties, or MenuItem instances.
1264 * This property should be set via the constructor using the configuration
1265 * object literal.
1266 * @default null
1267 * @type Array
1269 itemData: null,
1273 * @property activeItem
1274 * @description Object reference to the item in the menu that has is selected.
1275 * @default null
1276 * @type YAHOO.widget.MenuItem
1278 activeItem: null,
1282 * @property parent
1283 * @description Object reference to the menu's parent menu or menu item.
1284 * This property can be set via the constructor using the configuration
1285 * object literal.
1286 * @default null
1287 * @type YAHOO.widget.MenuItem
1289 parent: null,
1293 * @property srcElement
1294 * @description Object reference to the HTML element (either
1295 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
1296 * create the menu.
1297 * @default null
1298 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1299 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1300 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1301 * html#ID-22445964">HTMLDivElement</a>
1303 srcElement: null,
1307 // Events
1311 * @event mouseOverEvent
1312 * @description Fires when the mouse has entered the menu. Passes back
1313 * the DOM Event object as an argument.
1315 mouseOverEvent: null,
1319 * @event mouseOutEvent
1320 * @description Fires when the mouse has left the menu. Passes back the DOM
1321 * Event object as an argument.
1322 * @type YAHOO.util.CustomEvent
1324 mouseOutEvent: null,
1328 * @event mouseDownEvent
1329 * @description Fires when the user mouses down on the menu. Passes back the
1330 * DOM Event object as an argument.
1331 * @type YAHOO.util.CustomEvent
1333 mouseDownEvent: null,
1337 * @event mouseUpEvent
1338 * @description Fires when the user releases a mouse button while the mouse is
1339 * over the menu. Passes back the DOM Event object as an argument.
1340 * @type YAHOO.util.CustomEvent
1342 mouseUpEvent: null,
1346 * @event clickEvent
1347 * @description Fires when the user clicks the on the menu. Passes back the
1348 * DOM Event object as an argument.
1349 * @type YAHOO.util.CustomEvent
1351 clickEvent: null,
1355 * @event keyPressEvent
1356 * @description Fires when the user presses an alphanumeric key when one of the
1357 * menu's items has focus. Passes back the DOM Event object as an argument.
1358 * @type YAHOO.util.CustomEvent
1360 keyPressEvent: null,
1364 * @event keyDownEvent
1365 * @description Fires when the user presses a key when one of the menu's items
1366 * has focus. Passes back the DOM Event object as an argument.
1367 * @type YAHOO.util.CustomEvent
1369 keyDownEvent: null,
1373 * @event keyUpEvent
1374 * @description Fires when the user releases a key when one of the menu's items
1375 * has focus. Passes back the DOM Event object as an argument.
1376 * @type YAHOO.util.CustomEvent
1378 keyUpEvent: null,
1382 * @event itemAddedEvent
1383 * @description Fires when an item is added to the menu.
1384 * @type YAHOO.util.CustomEvent
1386 itemAddedEvent: null,
1390 * @event itemRemovedEvent
1391 * @description Fires when an item is removed to the menu.
1392 * @type YAHOO.util.CustomEvent
1394 itemRemovedEvent: null,
1398 * @method init
1399 * @description The Menu class's initialization method. This method is
1400 * automatically called by the constructor, and sets up all DOM references
1401 * for pre-existing markup, and creates required markup if it is not
1402 * already present.
1403 * @param {String} p_oElement String specifying the id attribute of the
1404 * <code>&#60;div&#62;</code> element of the menu.
1405 * @param {String} p_oElement String specifying the id attribute of the
1406 * <code>&#60;select&#62;</code> element to be used as the data source
1407 * for the menu.
1408 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1409 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1410 * specifying the <code>&#60;div&#62;</code> element of the menu.
1411 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1412 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1413 * Object specifying the <code>&#60;select&#62;</code> element to be used as
1414 * the data source for the menu.
1415 * @param {Object} p_oConfig Optional. Object literal specifying the
1416 * configuration for the menu. See configuration class documentation for
1417 * more details.
1419 init: function (p_oElement, p_oConfig) {
1421 this._aItemGroups = [];
1422 this._aListElements = [];
1423 this._aGroupTitleElements = [];
1425 if (!this.ITEM_TYPE) {
1427 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1432 var oElement;
1434 if (typeof p_oElement == "string") {
1436 oElement = document.getElementById(p_oElement);
1439 else if (p_oElement.tagName) {
1441 oElement = p_oElement;
1446 if (oElement && oElement.tagName) {
1448 switch(oElement.tagName.toUpperCase()) {
1450 case "DIV":
1452 this.srcElement = oElement;
1454 if (!oElement.id) {
1456 oElement.setAttribute("id", Dom.generateId());
1462 Note: we don't pass the user config in here yet
1463 because we only want it executed once, at the lowest
1464 subclass level.
1467 Menu.superclass.init.call(this, oElement);
1469 this.beforeInitEvent.fire(Menu);
1473 break;
1475 case "SELECT":
1477 this.srcElement = oElement;
1481 The source element is not something that we can use
1482 outright, so we need to create a new Overlay
1484 Note: we don't pass the user config in here yet
1485 because we only want it executed once, at the lowest
1486 subclass level.
1489 Menu.superclass.init.call(this, Dom.generateId());
1491 this.beforeInitEvent.fire(Menu);
1495 break;
1500 else {
1503 Note: we don't pass the user config in here yet
1504 because we only want it executed once, at the lowest
1505 subclass level.
1508 Menu.superclass.init.call(this, p_oElement);
1510 this.beforeInitEvent.fire(Menu);
1517 if (this.element) {
1519 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1522 // Subscribe to Custom Events
1524 this.initEvent.subscribe(this._onInit);
1525 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1526 this.renderEvent.subscribe(this._onRender);
1527 this.renderEvent.subscribe(this.onRender);
1528 this.beforeShowEvent.subscribe(this._onBeforeShow);
1529 this.hideEvent.subscribe(this.positionOffScreen);
1530 this.showEvent.subscribe(this._onShow);
1531 this.beforeHideEvent.subscribe(this._onBeforeHide);
1532 this.mouseOverEvent.subscribe(this._onMouseOver);
1533 this.mouseOutEvent.subscribe(this._onMouseOut);
1534 this.clickEvent.subscribe(this._onClick);
1535 this.keyDownEvent.subscribe(this._onKeyDown);
1536 this.keyPressEvent.subscribe(this._onKeyPress);
1539 if (UA.gecko || UA.webkit) {
1541 this.cfg.subscribeToConfigEvent("y", this._onYChange);
1546 if (p_oConfig) {
1548 this.cfg.applyConfig(p_oConfig, true);
1553 // Register the Menu instance with the MenuManager
1555 MenuManager.addMenu(this);
1558 this.initEvent.fire(Menu);
1566 // Private methods
1570 * @method _initSubTree
1571 * @description Iterates the childNodes of the source element to find nodes
1572 * used to instantiate menu and menu items.
1573 * @private
1575 _initSubTree: function () {
1577 var oSrcElement = this.srcElement,
1578 sSrcElementTagName,
1579 nGroup,
1580 sGroupTitleTagName,
1581 oNode,
1582 aListElements,
1583 nListElements,
1587 if (oSrcElement) {
1589 sSrcElementTagName =
1590 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1593 if (sSrcElementTagName == "DIV") {
1595 // Populate the collection of item groups and item group titles
1597 oNode = this.body.firstChild;
1600 if (oNode) {
1602 nGroup = 0;
1603 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1605 do {
1608 if (oNode && oNode.tagName) {
1610 switch (oNode.tagName.toUpperCase()) {
1612 case sGroupTitleTagName:
1614 this._aGroupTitleElements[nGroup] = oNode;
1616 break;
1618 case "UL":
1620 this._aListElements[nGroup] = oNode;
1621 this._aItemGroups[nGroup] = [];
1622 nGroup++;
1624 break;
1631 while ((oNode = oNode.nextSibling));
1635 Apply the "first-of-type" class to the first UL to mimic
1636 the "first-of-type" CSS3 psuedo class.
1639 if (this._aListElements[0]) {
1641 Dom.addClass(this._aListElements[0], "first-of-type");
1650 oNode = null;
1654 if (sSrcElementTagName) {
1656 switch (sSrcElementTagName) {
1658 case "DIV":
1660 aListElements = this._aListElements;
1661 nListElements = aListElements.length;
1663 if (nListElements > 0) {
1666 i = nListElements - 1;
1668 do {
1670 oNode = aListElements[i].firstChild;
1672 if (oNode) {
1675 do {
1677 if (oNode && oNode.tagName &&
1678 oNode.tagName.toUpperCase() == "LI") {
1681 this.addItem(new this.ITEM_TYPE(oNode,
1682 { parent: this }), i);
1687 while ((oNode = oNode.nextSibling));
1692 while (i--);
1696 break;
1698 case "SELECT":
1701 oNode = oSrcElement.firstChild;
1703 do {
1705 if (oNode && oNode.tagName) {
1707 switch (oNode.tagName.toUpperCase()) {
1709 case "OPTGROUP":
1710 case "OPTION":
1713 this.addItem(
1714 new this.ITEM_TYPE(
1715 oNode,
1716 { parent: this }
1720 break;
1727 while ((oNode = oNode.nextSibling));
1729 break;
1741 * @method _getFirstEnabledItem
1742 * @description Returns the first enabled item in the menu.
1743 * @return {YAHOO.widget.MenuItem}
1744 * @private
1746 _getFirstEnabledItem: function () {
1748 var aItems = this.getItems(),
1749 nItems = aItems.length,
1750 oItem;
1752 for(var i=0; i<nItems; i++) {
1754 oItem = aItems[i];
1756 if (oItem && !oItem.cfg.getProperty("disabled") &&
1757 oItem.element.style.display != "none") {
1759 return oItem;
1769 * @method _addItemToGroup
1770 * @description Adds a menu item to a group.
1771 * @private
1772 * @param {Number} p_nGroupIndex Number indicating the group to which the
1773 * item belongs.
1774 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1775 * instance to be added to the menu.
1776 * @param {String} p_oItem String specifying the text of the item to be added
1777 * to the menu.
1778 * @param {Object} p_oItem Object literal containing a set of menu item
1779 * configuration properties.
1780 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1781 * which the menu item should be added.
1782 * @return {YAHOO.widget.MenuItem}
1784 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1786 var oItem,
1787 nGroupIndex,
1788 aGroup,
1789 oGroupItem,
1790 bAppend,
1791 oNextItemSibling,
1792 nItemIndex;
1794 function getNextItemSibling(p_aArray, p_nStartIndex) {
1796 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray,
1797 (p_nStartIndex+1)));
1801 if (p_oItem instanceof this.ITEM_TYPE) {
1803 oItem = p_oItem;
1804 oItem.parent = this;
1807 else if (typeof p_oItem == "string") {
1809 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1812 else if (typeof p_oItem == "object") {
1814 p_oItem.parent = this;
1816 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1821 if (oItem) {
1823 if (oItem.cfg.getProperty("selected")) {
1825 this.activeItem = oItem;
1830 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1831 aGroup = this._getItemGroup(nGroupIndex);
1835 if (!aGroup) {
1837 aGroup = this._createItemGroup(nGroupIndex);
1842 if (typeof p_nItemIndex == "number") {
1844 bAppend = (p_nItemIndex >= aGroup.length);
1847 if (aGroup[p_nItemIndex]) {
1849 aGroup.splice(p_nItemIndex, 0, oItem);
1852 else {
1854 aGroup[p_nItemIndex] = oItem;
1859 oGroupItem = aGroup[p_nItemIndex];
1861 if (oGroupItem) {
1863 if (bAppend && (!oGroupItem.element.parentNode ||
1864 oGroupItem.element.parentNode.nodeType == 11)) {
1866 this._aListElements[nGroupIndex].appendChild(
1867 oGroupItem.element);
1870 else {
1872 oNextItemSibling = getNextItemSibling(aGroup,
1873 (p_nItemIndex+1));
1875 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
1876 oGroupItem.element.parentNode.nodeType == 11)) {
1878 this._aListElements[nGroupIndex].insertBefore(
1879 oGroupItem.element,
1880 oNextItemSibling.element);
1887 oGroupItem.parent = this;
1889 this._subscribeToItemEvents(oGroupItem);
1891 this._configureSubmenu(oGroupItem);
1893 this._updateItemProperties(nGroupIndex);
1896 this.itemAddedEvent.fire(oGroupItem);
1897 this.changeContentEvent.fire();
1899 return oGroupItem;
1904 else {
1906 nItemIndex = aGroup.length;
1908 aGroup[nItemIndex] = oItem;
1910 oGroupItem = aGroup[nItemIndex];
1913 if (oGroupItem) {
1915 if (!Dom.isAncestor(this._aListElements[nGroupIndex],
1916 oGroupItem.element)) {
1918 this._aListElements[nGroupIndex].appendChild(
1919 oGroupItem.element);
1923 oGroupItem.element.setAttribute("groupindex", nGroupIndex);
1924 oGroupItem.element.setAttribute("index", nItemIndex);
1926 oGroupItem.parent = this;
1928 oGroupItem.index = nItemIndex;
1929 oGroupItem.groupIndex = nGroupIndex;
1931 this._subscribeToItemEvents(oGroupItem);
1933 this._configureSubmenu(oGroupItem);
1935 if (nItemIndex === 0) {
1937 Dom.addClass(oGroupItem.element, "first-of-type");
1943 this.itemAddedEvent.fire(oGroupItem);
1944 this.changeContentEvent.fire();
1946 return oGroupItem;
1958 * @method _removeItemFromGroupByIndex
1959 * @description Removes a menu item from a group by index. Returns the menu
1960 * item that was removed.
1961 * @private
1962 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
1963 * item belongs.
1964 * @param {Number} p_nItemIndex Number indicating the index of the menu item
1965 * to be removed.
1966 * @return {YAHOO.widget.MenuItem}
1968 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
1970 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0,
1971 aGroup = this._getItemGroup(nGroupIndex),
1972 aArray,
1973 oItem,
1974 oUL;
1976 if (aGroup) {
1978 aArray = aGroup.splice(p_nItemIndex, 1);
1979 oItem = aArray[0];
1981 if (oItem) {
1983 // Update the index and className properties of each member
1985 this._updateItemProperties(nGroupIndex);
1987 if (aGroup.length === 0) {
1989 // Remove the UL
1991 oUL = this._aListElements[nGroupIndex];
1993 if (this.body && oUL) {
1995 this.body.removeChild(oUL);
1999 // Remove the group from the array of items
2001 this._aItemGroups.splice(nGroupIndex, 1);
2004 // Remove the UL from the array of ULs
2006 this._aListElements.splice(nGroupIndex, 1);
2010 Assign the "first-of-type" class to the new first UL
2011 in the collection
2014 oUL = this._aListElements[0];
2016 if (oUL) {
2018 Dom.addClass(oUL, "first-of-type");
2025 this.itemRemovedEvent.fire(oItem);
2026 this.changeContentEvent.fire();
2029 // Return a reference to the item that was removed
2031 return oItem;
2041 * @method _removeItemFromGroupByValue
2042 * @description Removes a menu item from a group by reference. Returns the
2043 * menu item that was removed.
2044 * @private
2045 * @param {Number} p_nGroupIndex Number indicating the group to which the
2046 * menu item belongs.
2047 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2048 * instance to be removed.
2049 * @return {YAHOO.widget.MenuItem}
2051 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2053 var aGroup = this._getItemGroup(p_nGroupIndex),
2054 nItems,
2055 nItemIndex,
2058 if (aGroup) {
2060 nItems = aGroup.length;
2061 nItemIndex = -1;
2063 if (nItems > 0) {
2065 i = nItems-1;
2067 do {
2069 if (aGroup[i] == p_oItem) {
2071 nItemIndex = i;
2072 break;
2077 while(i--);
2079 if (nItemIndex > -1) {
2081 return (this._removeItemFromGroupByIndex(p_nGroupIndex,
2082 nItemIndex));
2094 * @method _updateItemProperties
2095 * @description Updates the "index," "groupindex," and "className" properties
2096 * of the menu items in the specified group.
2097 * @private
2098 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2100 _updateItemProperties: function (p_nGroupIndex) {
2102 var aGroup = this._getItemGroup(p_nGroupIndex),
2103 nItems = aGroup.length,
2104 oItem,
2105 oLI,
2109 if (nItems > 0) {
2111 i = nItems - 1;
2113 // Update the index and className properties of each member
2115 do {
2117 oItem = aGroup[i];
2119 if (oItem) {
2121 oLI = oItem.element;
2123 oItem.index = i;
2124 oItem.groupIndex = p_nGroupIndex;
2126 oLI.setAttribute("groupindex", p_nGroupIndex);
2127 oLI.setAttribute("index", i);
2129 Dom.removeClass(oLI, "first-of-type");
2134 while(i--);
2137 if (oLI) {
2139 Dom.addClass(oLI, "first-of-type");
2149 * @method _createItemGroup
2150 * @description Creates a new menu item group (array) and its associated
2151 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2152 * @private
2153 * @param {Number} p_nIndex Number indicating the group to create.
2154 * @return {Array}
2156 _createItemGroup: function (p_nIndex) {
2158 var oUL;
2160 if (!this._aItemGroups[p_nIndex]) {
2162 this._aItemGroups[p_nIndex] = [];
2164 oUL = document.createElement("ul");
2166 this._aListElements[p_nIndex] = oUL;
2168 return this._aItemGroups[p_nIndex];
2176 * @method _getItemGroup
2177 * @description Returns the menu item group at the specified index.
2178 * @private
2179 * @param {Number} p_nIndex Number indicating the index of the menu item group
2180 * to be retrieved.
2181 * @return {Array}
2183 _getItemGroup: function (p_nIndex) {
2185 var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);
2187 return this._aItemGroups[nIndex];
2193 * @method _configureSubmenu
2194 * @description Subscribes the menu item's submenu to its parent menu's events.
2195 * @private
2196 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2197 * instance with the submenu to be configured.
2199 _configureSubmenu: function (p_oItem) {
2201 var oSubmenu = p_oItem.cfg.getProperty("submenu");
2203 if (oSubmenu) {
2206 Listen for configuration changes to the parent menu
2207 so they they can be applied to the submenu.
2210 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange,
2211 oSubmenu, true);
2213 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2215 oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow);
2225 * @method _subscribeToItemEvents
2226 * @description Subscribes a menu to a menu item's event.
2227 * @private
2228 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2229 * instance whose events should be subscribed to.
2231 _subscribeToItemEvents: function (p_oItem) {
2233 p_oItem.focusEvent.subscribe(this._onMenuItemFocus);
2235 p_oItem.blurEvent.subscribe(this._onMenuItemBlur);
2237 p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2239 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,
2240 p_oItem, this);
2246 * @method _onVisibleChange
2247 * @description Change event handler for the the menu's "visible" configuration
2248 * property.
2249 * @private
2250 * @param {String} p_sType String representing the name of the event that
2251 * was fired.
2252 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2254 _onVisibleChange: function (p_sType, p_aArgs) {
2256 var bVisible = p_aArgs[0];
2258 if (bVisible) {
2260 Dom.addClass(this.element, "visible");
2263 else {
2265 Dom.removeClass(this.element, "visible");
2273 * @method _cancelHideDelay
2274 * @description Cancels the call to "hideMenu."
2275 * @private
2277 _cancelHideDelay: function () {
2279 var oRoot = this.getRoot();
2281 if (oRoot._nHideDelayId) {
2283 window.clearTimeout(oRoot._nHideDelayId);
2291 * @method _execHideDelay
2292 * @description Hides the menu after the number of milliseconds specified by
2293 * the "hidedelay" configuration property.
2294 * @private
2296 _execHideDelay: function () {
2298 this._cancelHideDelay();
2300 var oRoot = this.getRoot(),
2301 me = this;
2303 function hideMenu() {
2305 if (oRoot.activeItem) {
2307 oRoot.clearActiveItem();
2311 if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) &&
2312 me.cfg.getProperty("position") == "dynamic") {
2314 me.hide();
2321 oRoot._nHideDelayId =
2322 window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));
2328 * @method _cancelShowDelay
2329 * @description Cancels the call to the "showMenu."
2330 * @private
2332 _cancelShowDelay: function () {
2334 var oRoot = this.getRoot();
2336 if (oRoot._nShowDelayId) {
2338 window.clearTimeout(oRoot._nShowDelayId);
2346 * @method _execShowDelay
2347 * @description Shows the menu after the number of milliseconds specified by
2348 * the "showdelay" configuration property have ellapsed.
2349 * @private
2350 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should
2351 * be made visible.
2353 _execShowDelay: function (p_oMenu) {
2355 var oRoot = this.getRoot();
2357 function showMenu() {
2359 if (p_oMenu.parent.cfg.getProperty("selected")) {
2361 p_oMenu.show();
2368 oRoot._nShowDelayId =
2369 window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));
2375 * @method _execSubmenuHideDelay
2376 * @description Hides a submenu after the number of milliseconds specified by
2377 * the "submenuhidedelay" configuration property have ellapsed.
2378 * @private
2379 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2380 * should be hidden.
2381 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2382 * the specified submenu's parent menu item.
2383 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2384 * before the submenu is hidden.
2386 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2388 var me = this;
2390 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2392 if (me._nCurrentMouseX > (p_nMouseX + 10)) {
2394 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2396 p_oSubmenu.hide();
2398 }, p_nHideDelay);
2401 else {
2403 p_oSubmenu.hide();
2407 }, 50);
2413 // Protected methods
2417 * @method _disableScrollHeader
2418 * @description Disables the header used for scrolling the body of the menu.
2419 * @protected
2421 _disableScrollHeader: function () {
2423 if (!this._bHeaderDisabled) {
2425 Dom.addClass(this.header, "topscrollbar_disabled");
2426 this._bHeaderDisabled = true;
2434 * @method _disableScrollFooter
2435 * @description Disables the footer used for scrolling the body of the menu.
2436 * @protected
2438 _disableScrollFooter: function () {
2440 if (!this._bFooterDisabled) {
2442 Dom.addClass(this.footer, "bottomscrollbar_disabled");
2443 this._bFooterDisabled = true;
2451 * @method _enableScrollHeader
2452 * @description Enables the header used for scrolling the body of the menu.
2453 * @protected
2455 _enableScrollHeader: function () {
2457 if (this._bHeaderDisabled) {
2459 Dom.removeClass(this.header, "topscrollbar_disabled");
2460 this._bHeaderDisabled = false;
2468 * @method _enableScrollFooter
2469 * @description Enables the footer used for scrolling the body of the menu.
2470 * @protected
2472 _enableScrollFooter: function () {
2474 if (this._bFooterDisabled) {
2476 Dom.removeClass(this.footer, "bottomscrollbar_disabled");
2477 this._bFooterDisabled = false;
2485 * @method _onMouseOver
2486 * @description "mouseover" event handler for the menu.
2487 * @protected
2488 * @param {String} p_sType String representing the name of the event that
2489 * was fired.
2490 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2492 _onMouseOver: function (p_sType, p_aArgs) {
2494 if (this._bStopMouseEventHandlers) {
2496 return false;
2501 var oEvent = p_aArgs[0],
2502 oItem = p_aArgs[1],
2503 oTarget = Event.getTarget(oEvent),
2504 oParentMenu,
2505 nShowDelay,
2506 bShowDelay,
2507 oActiveItem,
2508 oItemCfg,
2509 oSubmenu;
2512 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2513 Dom.isAncestor(this.element, oTarget))) {
2515 // Menu mouseover logic
2517 this._nCurrentMouseX = 0;
2519 Event.on(this.element, "mousemove", this._onMouseMove, this, true);
2521 this.clearActiveItem();
2524 if (this.parent && this._nSubmenuHideDelayId) {
2526 window.clearTimeout(this._nSubmenuHideDelayId);
2528 this.parent.cfg.setProperty("selected", true);
2530 oParentMenu = this.parent.parent;
2532 oParentMenu._bHandledMouseOutEvent = true;
2533 oParentMenu._bHandledMouseOverEvent = false;
2538 this._bHandledMouseOverEvent = true;
2539 this._bHandledMouseOutEvent = false;
2544 if (oItem && !oItem.handledMouseOverEvent &&
2545 !oItem.cfg.getProperty("disabled") &&
2546 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2548 // Menu Item mouseover logic
2550 nShowDelay = this.cfg.getProperty("showdelay");
2551 bShowDelay = (nShowDelay > 0);
2554 if (bShowDelay) {
2556 this._cancelShowDelay();
2561 oActiveItem = this.activeItem;
2563 if (oActiveItem) {
2565 oActiveItem.cfg.setProperty("selected", false);
2570 oItemCfg = oItem.cfg;
2572 // Select and focus the current menu item
2574 oItemCfg.setProperty("selected", true);
2577 if (this.hasFocus()) {
2579 oItem.focus();
2584 if (this.cfg.getProperty("autosubmenudisplay")) {
2586 // Show the submenu this menu item
2588 oSubmenu = oItemCfg.getProperty("submenu");
2590 if (oSubmenu) {
2592 if (bShowDelay) {
2594 this._execShowDelay(oSubmenu);
2597 else {
2599 oSubmenu.show();
2607 oItem.handledMouseOverEvent = true;
2608 oItem.handledMouseOutEvent = false;
2616 * @method _onMouseOut
2617 * @description "mouseout" event handler for the menu.
2618 * @protected
2619 * @param {String} p_sType String representing the name of the event that
2620 * was fired.
2621 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2623 _onMouseOut: function (p_sType, p_aArgs) {
2625 if (this._bStopMouseEventHandlers) {
2627 return false;
2632 var oEvent = p_aArgs[0],
2633 oItem = p_aArgs[1],
2634 oRelatedTarget = Event.getRelatedTarget(oEvent),
2635 bMovingToSubmenu = false,
2636 oItemCfg,
2637 oSubmenu,
2638 nSubmenuHideDelay,
2639 nShowDelay;
2642 if (oItem && !oItem.cfg.getProperty("disabled")) {
2644 oItemCfg = oItem.cfg;
2645 oSubmenu = oItemCfg.getProperty("submenu");
2648 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2649 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2651 bMovingToSubmenu = true;
2656 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2657 !Dom.isAncestor(oItem.element, oRelatedTarget)) ||
2658 bMovingToSubmenu)) {
2660 // Menu Item mouseout logic
2662 if (!bMovingToSubmenu) {
2664 oItem.cfg.setProperty("selected", false);
2667 if (oSubmenu) {
2669 nSubmenuHideDelay =
2670 this.cfg.getProperty("submenuhidedelay");
2672 nShowDelay = this.cfg.getProperty("showdelay");
2674 if (!(this instanceof YAHOO.widget.MenuBar) &&
2675 nSubmenuHideDelay > 0 &&
2676 nShowDelay >= nSubmenuHideDelay) {
2678 this._execSubmenuHideDelay(oSubmenu,
2679 Event.getPageX(oEvent),
2680 nSubmenuHideDelay);
2683 else {
2685 oSubmenu.hide();
2694 oItem.handledMouseOutEvent = true;
2695 oItem.handledMouseOverEvent = false;
2702 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2703 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2705 // Menu mouseout logic
2707 Event.removeListener(this.element, "mousemove", this._onMouseMove);
2709 this._nCurrentMouseX = Event.getPageX(oEvent);
2711 this._bHandledMouseOutEvent = true;
2712 this._bHandledMouseOverEvent = false;
2720 * @method _onMouseMove
2721 * @description "click" event handler for the menu.
2722 * @protected
2723 * @param {Event} p_oEvent Object representing the DOM event object passed
2724 * back by the event utility (YAHOO.util.Event).
2725 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2726 * fired the event.
2728 _onMouseMove: function (p_oEvent, p_oMenu) {
2730 if (this._bStopMouseEventHandlers) {
2732 return false;
2736 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2742 * @method _onClick
2743 * @description "click" event handler for the menu.
2744 * @protected
2745 * @param {String} p_sType String representing the name of the event that
2746 * was fired.
2747 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2749 _onClick: function (p_sType, p_aArgs) {
2751 var oEvent = p_aArgs[0],
2752 oItem = p_aArgs[1],
2753 bInMenuAnchor = false,
2754 oSubmenu,
2755 oRoot,
2756 sId,
2757 sURL,
2758 nHashPos,
2759 nLen;
2762 if (oItem) {
2764 if (oItem.cfg.getProperty("disabled")) {
2766 Event.preventDefault(oEvent);
2769 else {
2771 oSubmenu = oItem.cfg.getProperty("submenu");
2775 Check if the URL of the anchor is pointing to an element that is
2776 a child of the menu.
2779 sURL = oItem.cfg.getProperty("url");
2782 if (sURL) {
2784 nHashPos = sURL.indexOf("#");
2786 nLen = sURL.length;
2789 if (nHashPos != -1) {
2791 sURL = sURL.substr(nHashPos, nLen);
2793 nLen = sURL.length;
2796 if (nLen > 1) {
2798 sId = sURL.substr(1, nLen);
2800 bInMenuAnchor = Dom.isAncestor(this.element, sId);
2803 else if (nLen === 1) {
2805 bInMenuAnchor = true;
2815 if (bInMenuAnchor && !oItem.cfg.getProperty("target")) {
2817 Event.preventDefault(oEvent);
2820 if (UA.webkit) {
2822 oItem.focus();
2825 else {
2827 oItem.focusEvent.fire();
2834 if (!oSubmenu) {
2837 There is an inconsistency between Firefox 2 for Mac OS X and Firefox 2 Windows
2838 regarding the triggering of the display of the browser's context menu and the
2839 subsequent firing of the "click" event. In Firefox for Windows, when the user
2840 triggers the display of the browser's context menu the "click" event also fires
2841 for the document object, even though the "click" event did not fire for the
2842 element that was the original target of the "contextmenu" event. This is unique
2843 to Firefox on Windows. For all other A-Grade browsers, including Firefox 2 for
2844 Mac OS X, the "click" event doesn't fire for the document object.
2846 This bug in Firefox 2 for Windows affects Menu as Menu instances listen for
2847 events at the document level and have an internal "click" event handler they
2848 use to hide themselves when clicked. As a result, in Firefox for Windows a
2849 Menu will hide when the user right clicks on a MenuItem to raise the browser's
2850 default context menu, because its internal "click" event handler ends up
2851 getting called. The following line fixes this bug.
2854 if ((UA.gecko && this.platform == "windows") && oEvent.button > 0) {
2856 return;
2860 oRoot = this.getRoot();
2862 if (oRoot instanceof YAHOO.widget.MenuBar ||
2863 oRoot.cfg.getProperty("position") == "static") {
2865 oRoot.clearActiveItem();
2868 else {
2870 oRoot.hide();
2884 * @method _onKeyDown
2885 * @description "keydown" event handler for the menu.
2886 * @protected
2887 * @param {String} p_sType String representing the name of the event that
2888 * was fired.
2889 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2891 _onKeyDown: function (p_sType, p_aArgs) {
2893 var oEvent = p_aArgs[0],
2894 oItem = p_aArgs[1],
2895 me = this,
2896 oSubmenu,
2897 oItemCfg,
2898 oParentItem,
2899 oRoot,
2900 oNextItem,
2901 oBody,
2902 nBodyScrollTop,
2903 nBodyOffsetHeight,
2904 aItems,
2905 nItems,
2906 nNextItemOffsetTop,
2907 nScrollTarget,
2908 oParentMenu;
2912 This function is called to prevent a bug in Firefox. In Firefox,
2913 moving a DOM element into a stationary mouse pointer will cause the
2914 browser to fire mouse events. This can result in the menu mouse
2915 event handlers being called uncessarily, especially when menus are
2916 moved into a stationary mouse pointer as a result of a
2917 key event handler.
2919 function stopMouseEventHandlers() {
2921 me._bStopMouseEventHandlers = true;
2923 window.setTimeout(function () {
2925 me._bStopMouseEventHandlers = false;
2927 }, 10);
2932 if (oItem && !oItem.cfg.getProperty("disabled")) {
2934 oItemCfg = oItem.cfg;
2935 oParentItem = this.parent;
2937 switch(oEvent.keyCode) {
2939 case 38: // Up arrow
2940 case 40: // Down arrow
2942 oNextItem = (oEvent.keyCode == 38) ?
2943 oItem.getPreviousEnabledSibling() :
2944 oItem.getNextEnabledSibling();
2946 if (oNextItem) {
2948 this.clearActiveItem();
2950 oNextItem.cfg.setProperty("selected", true);
2951 oNextItem.focus();
2954 if (this.cfg.getProperty("maxheight") > 0) {
2956 oBody = this.body;
2957 nBodyScrollTop = oBody.scrollTop;
2958 nBodyOffsetHeight = oBody.offsetHeight;
2959 aItems = this.getItems();
2960 nItems = aItems.length - 1;
2961 nNextItemOffsetTop = oNextItem.element.offsetTop;
2964 if (oEvent.keyCode == 40 ) { // Down
2966 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
2968 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
2971 else if (nNextItemOffsetTop <= nBodyScrollTop) {
2973 oBody.scrollTop = 0;
2978 if (oNextItem == aItems[nItems]) {
2980 oBody.scrollTop = oNextItem.element.offsetTop;
2985 else { // Up
2987 if (nNextItemOffsetTop <= nBodyScrollTop) {
2989 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
2992 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
2994 oBody.scrollTop = nNextItemOffsetTop;
2999 if (oNextItem == aItems[0]) {
3001 oBody.scrollTop = 0;
3008 nBodyScrollTop = oBody.scrollTop;
3009 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3011 if (nBodyScrollTop === 0) {
3013 this._disableScrollHeader();
3014 this._enableScrollFooter();
3017 else if (nBodyScrollTop == nScrollTarget) {
3019 this._enableScrollHeader();
3020 this._disableScrollFooter();
3023 else {
3025 this._enableScrollHeader();
3026 this._enableScrollFooter();
3035 Event.preventDefault(oEvent);
3037 stopMouseEventHandlers();
3039 break;
3042 case 39: // Right arrow
3044 oSubmenu = oItemCfg.getProperty("submenu");
3046 if (oSubmenu) {
3048 if (!oItemCfg.getProperty("selected")) {
3050 oItemCfg.setProperty("selected", true);
3054 oSubmenu.show();
3055 oSubmenu.setInitialFocus();
3056 oSubmenu.setInitialSelection();
3059 else {
3061 oRoot = this.getRoot();
3063 if (oRoot instanceof YAHOO.widget.MenuBar) {
3065 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3067 if (oNextItem) {
3069 oRoot.clearActiveItem();
3071 oNextItem.cfg.setProperty("selected", true);
3073 oSubmenu = oNextItem.cfg.getProperty("submenu");
3075 if (oSubmenu) {
3077 oSubmenu.show();
3081 oNextItem.focus();
3090 Event.preventDefault(oEvent);
3092 stopMouseEventHandlers();
3094 break;
3097 case 37: // Left arrow
3099 if (oParentItem) {
3101 oParentMenu = oParentItem.parent;
3103 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3105 oNextItem =
3106 oParentMenu.activeItem.getPreviousEnabledSibling();
3108 if (oNextItem) {
3110 oParentMenu.clearActiveItem();
3112 oNextItem.cfg.setProperty("selected", true);
3114 oSubmenu = oNextItem.cfg.getProperty("submenu");
3116 if (oSubmenu) {
3118 oSubmenu.show();
3122 oNextItem.focus();
3127 else {
3129 this.hide();
3131 oParentItem.focus();
3137 Event.preventDefault(oEvent);
3139 stopMouseEventHandlers();
3141 break;
3149 if (oEvent.keyCode == 27) { // Esc key
3151 if (this.cfg.getProperty("position") == "dynamic") {
3153 this.hide();
3155 if (this.parent) {
3157 this.parent.focus();
3162 else if (this.activeItem) {
3164 oSubmenu = this.activeItem.cfg.getProperty("submenu");
3166 if (oSubmenu && oSubmenu.cfg.getProperty("visible")) {
3168 oSubmenu.hide();
3169 this.activeItem.focus();
3172 else {
3174 this.activeItem.blur();
3175 this.activeItem.cfg.setProperty("selected", false);
3182 Event.preventDefault(oEvent);
3190 * @method _onKeyPress
3191 * @description "keypress" event handler for a Menu instance.
3192 * @protected
3193 * @param {String} p_sType The name of the event that was fired.
3194 * @param {Array} p_aArgs Collection of arguments sent when the event
3195 * was fired.
3197 _onKeyPress: function (p_sType, p_aArgs) {
3199 var oEvent = p_aArgs[0];
3202 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3204 Event.preventDefault(oEvent);
3212 * @method _onYChange
3213 * @description "y" event handler for a Menu instance.
3214 * @protected
3215 * @param {String} p_sType The name of the event that was fired.
3216 * @param {Array} p_aArgs Collection of arguments sent when the event
3217 * was fired.
3219 _onYChange: function (p_sType, p_aArgs) {
3221 var oParent = this.parent,
3222 nScrollTop,
3223 oIFrame,
3227 if (oParent) {
3229 nScrollTop = oParent.parent.body.scrollTop;
3232 if (nScrollTop > 0) {
3234 nY = (this.cfg.getProperty("y") - nScrollTop);
3236 Dom.setY(this.element, nY);
3238 oIFrame = this.iframe;
3241 if (oIFrame) {
3243 Dom.setY(oIFrame, nY);
3247 this.cfg.setProperty("y", nY, true);
3257 * @method _onScrollTargetMouseOver
3258 * @description "mouseover" event handler for the menu's "header" and "footer"
3259 * elements. Used to scroll the body of the menu up and down when the
3260 * menu's "maxheight" configuration property is set to a value greater than 0.
3261 * @protected
3262 * @param {Event} p_oEvent Object representing the DOM event object passed
3263 * back by the event utility (YAHOO.util.Event).
3264 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3265 * fired the event.
3267 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3269 this._cancelHideDelay();
3271 var oTarget = Event.getTarget(p_oEvent),
3272 oBody = this.body,
3273 me = this,
3274 nScrollIncrement = this.cfg.getProperty("scrollincrement"),
3275 nScrollTarget,
3276 fnScrollFunction;
3279 function scrollBodyDown() {
3281 var nScrollTop = oBody.scrollTop;
3284 if (nScrollTop < nScrollTarget) {
3286 oBody.scrollTop = (nScrollTop + nScrollIncrement);
3288 me._enableScrollHeader();
3291 else {
3293 oBody.scrollTop = nScrollTarget;
3295 window.clearInterval(me._nBodyScrollId);
3297 me._disableScrollFooter();
3304 function scrollBodyUp() {
3306 var nScrollTop = oBody.scrollTop;
3309 if (nScrollTop > 0) {
3311 oBody.scrollTop = (nScrollTop - nScrollIncrement);
3313 me._enableScrollFooter();
3316 else {
3318 oBody.scrollTop = 0;
3320 window.clearInterval(me._nBodyScrollId);
3322 me._disableScrollHeader();
3329 if (Dom.hasClass(oTarget, "hd")) {
3331 fnScrollFunction = scrollBodyUp;
3334 else {
3336 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3338 fnScrollFunction = scrollBodyDown;
3343 this._nBodyScrollId = window.setInterval(fnScrollFunction, 10);
3349 * @method _onScrollTargetMouseOut
3350 * @description "mouseout" event handler for the menu's "header" and "footer"
3351 * elements. Used to stop scrolling the body of the menu up and down when the
3352 * menu's "maxheight" configuration property is set to a value greater than 0.
3353 * @protected
3354 * @param {Event} p_oEvent Object representing the DOM event object passed
3355 * back by the event utility (YAHOO.util.Event).
3356 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3357 * fired the event.
3359 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3361 window.clearInterval(this._nBodyScrollId);
3363 this._cancelHideDelay();
3369 // Private methods
3373 * @method _onInit
3374 * @description "init" event handler for the menu.
3375 * @private
3376 * @param {String} p_sType String representing the name of the event that
3377 * was fired.
3378 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3380 _onInit: function (p_sType, p_aArgs) {
3382 this.cfg.subscribeToConfigEvent("visible", this._onVisibleChange);
3384 var bRootMenu = !this.parent,
3385 bLazyLoad = this.lazyLoad;
3389 Automatically initialize a menu's subtree if:
3391 1) This is the root menu and lazyload is off
3393 2) This is the root menu, lazyload is on, but the menu is
3394 already visible
3396 3) This menu is a submenu and lazyload is off
3401 if (((bRootMenu && !bLazyLoad) ||
3402 (bRootMenu && (this.cfg.getProperty("visible") ||
3403 this.cfg.getProperty("position") == "static")) ||
3404 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3406 if (this.srcElement) {
3408 this._initSubTree();
3413 if (this.itemData) {
3415 this.addItems(this.itemData);
3420 else if (bLazyLoad) {
3422 this.cfg.fireQueue();
3430 * @method _onBeforeRender
3431 * @description "beforerender" event handler for the menu. Appends all of the
3432 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
3433 * title elements to the body element of the menu.
3434 * @private
3435 * @param {String} p_sType String representing the name of the event that
3436 * was fired.
3437 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3439 _onBeforeRender: function (p_sType, p_aArgs) {
3441 var oEl = this.element,
3442 nListElements = this._aListElements.length,
3443 bFirstList = true,
3444 i = 0,
3445 oUL,
3446 oGroupTitle;
3448 if (nListElements > 0) {
3450 do {
3452 oUL = this._aListElements[i];
3454 if (oUL) {
3456 if (bFirstList) {
3458 Dom.addClass(oUL, "first-of-type");
3459 bFirstList = false;
3464 if (!Dom.isAncestor(oEl, oUL)) {
3466 this.appendToBody(oUL);
3471 oGroupTitle = this._aGroupTitleElements[i];
3473 if (oGroupTitle) {
3475 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3477 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3482 Dom.addClass(oUL, "hastitle");
3488 i++;
3491 while(i < nListElements);
3499 * @method _onRender
3500 * @description "render" event handler for the menu.
3501 * @private
3502 * @param {String} p_sType String representing the name of the event that
3503 * was fired.
3504 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3506 _onRender: function (p_sType, p_aArgs) {
3508 if (this.cfg.getProperty("position") == "dynamic") {
3510 if (!this.cfg.getProperty("visible")) {
3512 this.positionOffScreen();
3525 * @method _onBeforeShow
3526 * @description "beforeshow" event handler for the menu.
3527 * @private
3528 * @param {String} p_sType String representing the name of the event that
3529 * was fired.
3530 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3532 _onBeforeShow: function (p_sType, p_aArgs) {
3534 var nOptions,
3536 nViewportHeight,
3537 oRegion,
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"));
3622 var nMaxHeight = this.cfg.getProperty("maxheight"),
3623 nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
3624 bDynamicPos = this.cfg.getProperty("position") == "dynamic";
3627 if (!this.parent && bDynamicPos) {
3629 this.cfg.refireEvent("xy");
3634 function clearMaxHeight() {
3636 this.cfg.setProperty("maxheight", 0);
3638 this.hideEvent.unsubscribe(clearMaxHeight);
3643 if (!(this instanceof YAHOO.widget.MenuBar) && bDynamicPos) {
3646 if (nMaxHeight === 0) {
3648 nViewportHeight = Dom.getViewportHeight();
3651 if (this.parent &&
3652 this.parent.parent instanceof YAHOO.widget.MenuBar) {
3654 oRegion = YAHOO.util.Region.getRegion(this.parent.element);
3656 nViewportHeight = (nViewportHeight - oRegion.bottom);
3661 if (this.element.offsetHeight >= nViewportHeight) {
3663 nMaxHeight = (nViewportHeight - (Overlay.VIEWPORT_OFFSET * 2));
3665 if (nMaxHeight < nMinScrollHeight) {
3667 nMaxHeight = nMinScrollHeight;
3671 this.cfg.setProperty("maxheight", nMaxHeight);
3673 this.hideEvent.subscribe(clearMaxHeight);
3685 * @method _onShow
3686 * @description "show" event handler for the menu.
3687 * @private
3688 * @param {String} p_sType String representing the name of the event that
3689 * was fired.
3690 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3692 _onShow: function (p_sType, p_aArgs) {
3694 var oParent = this.parent,
3695 oParentMenu,
3696 aParentAlignment,
3697 aAlignment;
3700 function disableAutoSubmenuDisplay(p_oEvent) {
3702 var oTarget;
3704 if (p_oEvent.type == "mousedown" || (p_oEvent.type == "keydown" &&
3705 p_oEvent.keyCode == 27)) {
3708 Set the "autosubmenudisplay" to "false" if the user
3709 clicks outside the menu bar.
3712 oTarget = Event.getTarget(p_oEvent);
3714 if (oTarget != oParentMenu.element ||
3715 !Dom.isAncestor(oParentMenu.element, oTarget)) {
3717 oParentMenu.cfg.setProperty("autosubmenudisplay", false);
3719 Event.removeListener(document, "mousedown",
3720 disableAutoSubmenuDisplay);
3722 Event.removeListener(document, "keydown",
3723 disableAutoSubmenuDisplay);
3732 if (oParent) {
3734 oParentMenu = oParent.parent;
3735 aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
3736 aAlignment = this.cfg.getProperty("submenualignment");
3739 if ((aParentAlignment[0] != aAlignment[0]) &&
3740 (aParentAlignment[1] != aAlignment[1])) {
3742 this.cfg.setProperty("submenualignment",
3743 [aParentAlignment[0], aParentAlignment[1]]);
3748 if (!oParentMenu.cfg.getProperty("autosubmenudisplay") &&
3749 (oParentMenu instanceof YAHOO.widget.MenuBar ||
3750 oParentMenu.cfg.getProperty("position") == "static")) {
3752 oParentMenu.cfg.setProperty("autosubmenudisplay", true);
3754 Event.on(document, "mousedown", disableAutoSubmenuDisplay);
3755 Event.on(document, "keydown", disableAutoSubmenuDisplay);
3765 * @method _onBeforeHide
3766 * @description "beforehide" event handler for the menu.
3767 * @private
3768 * @param {String} p_sType String representing the name of the event that
3769 * was fired.
3770 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3772 _onBeforeHide: function (p_sType, p_aArgs) {
3774 var oActiveItem = this.activeItem,
3775 oConfig,
3776 oSubmenu;
3778 if (oActiveItem) {
3780 oConfig = oActiveItem.cfg;
3782 oConfig.setProperty("selected", false);
3784 oSubmenu = oConfig.getProperty("submenu");
3786 if (oSubmenu) {
3788 oSubmenu.hide();
3794 if (this.getRoot() == this) {
3796 this.blur();
3804 * @method _onParentMenuConfigChange
3805 * @description "configchange" event handler for a submenu.
3806 * @private
3807 * @param {String} p_sType String representing the name of the event that
3808 * was fired.
3809 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3810 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3811 * subscribed to the event.
3813 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
3815 var sPropertyName = p_aArgs[0][0],
3816 oPropertyValue = p_aArgs[0][1];
3818 switch(sPropertyName) {
3820 case "iframe":
3821 case "constraintoviewport":
3822 case "hidedelay":
3823 case "showdelay":
3824 case "submenuhidedelay":
3825 case "clicktohide":
3826 case "effect":
3827 case "classname":
3828 case "scrollincrement":
3829 case "minscrollheight":
3831 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
3833 break;
3841 * @method _onParentMenuRender
3842 * @description "render" event handler for a submenu. Renders a
3843 * submenu in response to the firing of its parent's "render" event.
3844 * @private
3845 * @param {String} p_sType String representing the name of the event that
3846 * was fired.
3847 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3848 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3849 * subscribed to the event.
3851 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
3853 var oParentCfg = p_oSubmenu.parent.parent.cfg,
3855 oConfig = {
3857 constraintoviewport: oParentCfg.getProperty("constraintoviewport"),
3859 xy: [0,0],
3861 clicktohide: oParentCfg.getProperty("clicktohide"),
3863 effect: oParentCfg.getProperty("effect"),
3865 showdelay: oParentCfg.getProperty("showdelay"),
3867 hidedelay: oParentCfg.getProperty("hidedelay"),
3869 submenuhidedelay: oParentCfg.getProperty("submenuhidedelay"),
3871 classname: oParentCfg.getProperty("classname"),
3873 scrollincrement: oParentCfg.getProperty("scrollincrement"),
3875 minscrollheight: oParentCfg.getProperty("minscrollheight"),
3877 iframe: oParentCfg.getProperty("iframe")
3881 oLI;
3884 p_oSubmenu.cfg.applyConfig(oConfig);
3887 if (!this.lazyLoad) {
3889 oLI = this.parent.element;
3891 if (this.element.parentNode == oLI) {
3893 this.render();
3896 else {
3898 this.render(oLI);
3908 * @method _onSubmenuBeforeShow
3909 * @description "beforeshow" event handler for a submenu.
3910 * @private
3911 * @param {String} p_sType String representing the name of the event that
3912 * was fired.
3913 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3915 _onSubmenuBeforeShow: function (p_sType, p_aArgs) {
3917 var oParent = this.parent,
3918 aAlignment = oParent.parent.cfg.getProperty("submenualignment");
3921 if (!this.cfg.getProperty("context")) {
3923 this.cfg.setProperty("context",
3924 [oParent.element, aAlignment[0], aAlignment[1]]);
3927 else {
3929 this.align();
3937 * @method _onMenuItemFocus
3938 * @description "focus" event handler for the menu's items.
3939 * @private
3940 * @param {String} p_sType String representing the name of the event that
3941 * was fired.
3942 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3944 _onMenuItemFocus: function (p_sType, p_aArgs) {
3946 this.parent.focusEvent.fire(this);
3952 * @method _onMenuItemBlur
3953 * @description "blur" event handler for the menu's items.
3954 * @private
3955 * @param {String} p_sType String representing the name of the event
3956 * that was fired.
3957 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3959 _onMenuItemBlur: function (p_sType, p_aArgs) {
3961 this.parent.blurEvent.fire(this);
3967 * @method _onMenuItemDestroy
3968 * @description "destroy" event handler for the menu's items.
3969 * @private
3970 * @param {String} p_sType String representing the name of the event
3971 * that was fired.
3972 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3973 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
3974 * that fired the event.
3976 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
3978 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
3984 * @method _onMenuItemConfigChange
3985 * @description "configchange" 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.
3990 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
3991 * that fired the event.
3993 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
3995 var sPropertyName = p_aArgs[0][0],
3996 oPropertyValue = p_aArgs[0][1],
3997 oSubmenu;
4000 switch(sPropertyName) {
4002 case "selected":
4004 if (oPropertyValue === true) {
4006 this.activeItem = p_oItem;
4010 break;
4012 case "submenu":
4014 oSubmenu = p_aArgs[0][1];
4016 if (oSubmenu) {
4018 this._configureSubmenu(p_oItem);
4022 break;
4030 // Public event handlers for configuration properties
4034 * @method enforceConstraints
4035 * @description The default event handler executed when the moveEvent is fired,
4036 * if the "constraintoviewport" configuration property is set to true.
4037 * @param {String} type The name of the event that was fired.
4038 * @param {Array} args Collection of arguments sent when the
4039 * event was fired.
4040 * @param {Array} obj Array containing the current Menu instance
4041 * and the item that fired the event.
4043 enforceConstraints: function (type, args, obj) {
4045 YAHOO.widget.Menu.superclass.enforceConstraints.apply(this, arguments);
4047 var oParent = this.parent,
4048 oParentMenu,
4049 nParentMenuX,
4050 nNewX,
4054 if (oParent) {
4056 oParentMenu = oParent.parent;
4058 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4060 nParentMenuX = oParentMenu.cfg.getProperty("x");
4061 nX = this.cfg.getProperty("x");
4064 if (nX < (nParentMenuX + oParent.element.offsetWidth)) {
4066 nNewX = (nParentMenuX - this.element.offsetWidth);
4068 this.cfg.setProperty("x", nNewX, true);
4069 this.cfg.setProperty("xy", [nNewX, (this.cfg.getProperty("y"))], true);
4081 * @method configVisible
4082 * @description Event handler for when the "visible" configuration property
4083 * the menu changes.
4084 * @param {String} p_sType String representing the name of the event that
4085 * was fired.
4086 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4087 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4088 * fired the event.
4090 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4092 var bVisible,
4093 sDisplay;
4095 if (this.cfg.getProperty("position") == "dynamic") {
4097 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4100 else {
4102 bVisible = p_aArgs[0];
4103 sDisplay = Dom.getStyle(this.element, "display");
4105 Dom.setStyle(this.element, "visibility", "visible");
4107 if (bVisible) {
4109 if (sDisplay != "block") {
4110 this.beforeShowEvent.fire();
4111 Dom.setStyle(this.element, "display", "block");
4112 this.showEvent.fire();
4116 else {
4118 if (sDisplay == "block") {
4119 this.beforeHideEvent.fire();
4120 Dom.setStyle(this.element, "display", "none");
4121 this.hideEvent.fire();
4132 * @method configPosition
4133 * @description Event handler for when the "position" configuration property
4134 * of the menu changes.
4135 * @param {String} p_sType String representing the name of the event that
4136 * was fired.
4137 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4138 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4139 * fired the event.
4141 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4143 var oElement = this.element,
4144 sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute",
4145 oCfg = this.cfg,
4146 nZIndex;
4149 Dom.setStyle(oElement, "position", sCSSPosition);
4152 if (sCSSPosition == "static") {
4154 // Statically positioned menus are visible by default
4156 Dom.setStyle(oElement, "display", "block");
4158 oCfg.setProperty("visible", true);
4161 else {
4164 Even though the "visible" property is queued to
4165 "false" by default, we need to set the "visibility" property to
4166 "hidden" since Overlay's "configVisible" implementation checks the
4167 element's "visibility" style property before deciding whether
4168 or not to show an Overlay instance.
4171 Dom.setStyle(oElement, "visibility", "hidden");
4176 if (sCSSPosition == "absolute") {
4178 nZIndex = oCfg.getProperty("zindex");
4180 if (!nZIndex || nZIndex === 0) {
4182 nZIndex = this.parent ?
4183 (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;
4185 oCfg.setProperty("zindex", nZIndex);
4195 * @method configIframe
4196 * @description Event handler for when the "iframe" configuration property of
4197 * the menu changes.
4198 * @param {String} p_sType String representing the name of the event that
4199 * was fired.
4200 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4201 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4202 * fired the event.
4204 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4206 if (this.cfg.getProperty("position") == "dynamic") {
4208 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4216 * @method configHideDelay
4217 * @description Event handler for when the "hidedelay" configuration property
4218 * of the menu changes.
4219 * @param {String} p_sType String representing the name of the event that
4220 * was fired.
4221 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4222 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4223 * fired the event.
4225 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4227 var nHideDelay = p_aArgs[0],
4228 oMouseOutEvent = this.mouseOutEvent,
4229 oMouseOverEvent = this.mouseOverEvent,
4230 oKeyDownEvent = this.keyDownEvent;
4232 if (nHideDelay > 0) {
4235 Only assign event handlers once. This way the user change
4236 the value for the hidedelay as many times as they want.
4239 if (!this._bHideDelayEventHandlersAssigned) {
4241 oMouseOutEvent.subscribe(this._execHideDelay);
4242 oMouseOverEvent.subscribe(this._cancelHideDelay);
4243 oKeyDownEvent.subscribe(this._cancelHideDelay);
4245 this._bHideDelayEventHandlersAssigned = true;
4250 else {
4252 oMouseOutEvent.unsubscribe(this._execHideDelay);
4253 oMouseOverEvent.unsubscribe(this._cancelHideDelay);
4254 oKeyDownEvent.unsubscribe(this._cancelHideDelay);
4256 this._bHideDelayEventHandlersAssigned = false;
4264 * @method configContainer
4265 * @description Event handler for when the "container" configuration property
4266 * of the menu changes.
4267 * @param {String} p_sType String representing the name of the event that
4268 * was fired.
4269 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4270 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4271 * fired the event.
4273 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4275 var oElement = p_aArgs[0];
4277 if (typeof oElement == 'string') {
4279 this.cfg.setProperty("container", document.getElementById(oElement),
4280 true);
4288 * @method _setMaxHeight
4289 * @description "renderEvent" handler used to defer the setting of the
4290 * "maxheight" configuration property until the menu is rendered in lazy
4291 * load scenarios.
4292 * @param {String} p_sType The name of the event that was fired.
4293 * @param {Array} p_aArgs Collection of arguments sent when the event
4294 * was fired.
4295 * @param {Number} p_nMaxHeight Number representing the value to set for the
4296 * "maxheight" configuration property.
4297 * @private
4299 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4301 this.cfg.setProperty("maxheight", p_nMaxHeight);
4302 this.renderEvent.unsubscribe(this._setMaxHeight);
4308 * @method configMaxHeight
4309 * @description Event handler for when the "maxheight" configuration property of
4310 * a Menu changes.
4311 * @param {String} p_sType The name of the event that was fired.
4312 * @param {Array} p_aArgs Collection of arguments sent when the event
4313 * was fired.
4314 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4315 * the event.
4317 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4319 var nMaxHeight = p_aArgs[0],
4320 oElement = this.element,
4321 oBody = this.body,
4322 oHeader = this.header,
4323 oFooter = this.footer,
4324 fnMouseOver = this._onScrollTargetMouseOver,
4325 fnMouseOut = this._onScrollTargetMouseOut,
4326 nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
4327 nHeight,
4328 nOffsetWidth,
4329 sWidth;
4332 if (nMaxHeight !== 0 && nMaxHeight < nMinScrollHeight) {
4334 nMaxHeight = nMinScrollHeight;
4339 if (this.lazyLoad && !oBody) {
4341 this.renderEvent.unsubscribe(this._setMaxHeight);
4343 if (nMaxHeight > 0) {
4345 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4349 return;
4354 Dom.setStyle(oBody, "height", "");
4355 Dom.removeClass(oBody, "yui-menu-body-scrolled");
4359 There is a bug in gecko-based browsers where an element whose
4360 "position" property is set to "absolute" and "overflow" property is set
4361 to "hidden" will not render at the correct width when its
4362 offsetParent's "position" property is also set to "absolute." It is
4363 possible to work around this bug by specifying a value for the width
4364 property in addition to overflow.
4366 In IE it is also necessary to give the Menu a width when the scrollbars are
4367 rendered to prevent the Menu from rendering with a width that is 100% of
4368 the browser viewport.
4371 var bSetWidth = ((UA.gecko && this.parent && this.parent.parent &&
4372 this.parent.parent.cfg.getProperty("position") == "dynamic") || UA.ie);
4375 if (bSetWidth) {
4377 if (!this.cfg.getProperty("width")) {
4379 nOffsetWidth = oElement.offsetWidth;
4382 Measuring the difference of the offsetWidth before and after
4383 setting the "width" style attribute allows us to compute the
4384 about of padding and borders applied to the element, which in
4385 turn allows us to set the "width" property correctly.
4388 oElement.style.width = nOffsetWidth + "px";
4390 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + "px";
4392 this.cfg.setProperty("width", sWidth);
4399 if (!oHeader && !oFooter) {
4401 this.setHeader("&#32;");
4402 this.setFooter("&#32;");
4404 oHeader = this.header;
4405 oFooter = this.footer;
4407 Dom.addClass(oHeader, "topscrollbar");
4408 Dom.addClass(oFooter, "bottomscrollbar");
4410 oElement.insertBefore(oHeader, oBody);
4411 oElement.appendChild(oFooter);
4416 nHeight = (nMaxHeight - (oHeader.offsetHeight + oHeader.offsetHeight));
4419 if (nHeight > 0 && (oBody.offsetHeight > nMaxHeight)) {
4421 Dom.addClass(oBody, "yui-menu-body-scrolled");
4422 Dom.setStyle(oBody, "height", (nHeight + "px"));
4424 Event.on(oHeader, "mouseover", fnMouseOver, this, true);
4425 Event.on(oHeader, "mouseout", fnMouseOut, this, true);
4426 Event.on(oFooter, "mouseover", fnMouseOver, this, true);
4427 Event.on(oFooter, "mouseout", fnMouseOut, this, true);
4429 this._disableScrollHeader();
4430 this._enableScrollFooter();
4433 else if (oHeader && oFooter) {
4435 if (bSetWidth) {
4437 this.cfg.setProperty("width", "");
4442 this._enableScrollHeader();
4443 this._enableScrollFooter();
4445 Event.removeListener(oHeader, "mouseover", fnMouseOver);
4446 Event.removeListener(oHeader, "mouseout", fnMouseOut);
4447 Event.removeListener(oFooter, "mouseover", fnMouseOver);
4448 Event.removeListener(oFooter, "mouseout", fnMouseOut);
4450 oElement.removeChild(oHeader);
4451 oElement.removeChild(oFooter);
4453 this.header = null;
4454 this.footer = null;
4458 this.cfg.refireEvent("iframe");
4464 * @method configClassName
4465 * @description Event handler for when the "classname" configuration property of
4466 * a menu changes.
4467 * @param {String} p_sType The name of the event that was fired.
4468 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4469 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4471 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4473 var sClassName = p_aArgs[0];
4475 if (this._sClassName) {
4477 Dom.removeClass(this.element, this._sClassName);
4481 Dom.addClass(this.element, sClassName);
4482 this._sClassName = sClassName;
4488 * @method _onItemAdded
4489 * @description "itemadded" event handler for a Menu instance.
4490 * @private
4491 * @param {String} p_sType The name of the event that was fired.
4492 * @param {Array} p_aArgs Collection of arguments sent when the event
4493 * was fired.
4495 _onItemAdded: function (p_sType, p_aArgs) {
4497 var oItem = p_aArgs[0];
4499 if (oItem) {
4501 oItem.cfg.setProperty("disabled", true);
4509 * @method configDisabled
4510 * @description Event handler for when the "disabled" configuration property of
4511 * a menu changes.
4512 * @param {String} p_sType The name of the event that was fired.
4513 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4514 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4516 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4518 var bDisabled = p_aArgs[0],
4519 aItems = this.getItems(),
4520 nItems,
4523 if (Lang.isArray(aItems)) {
4525 nItems = aItems.length;
4527 if (nItems > 0) {
4529 i = nItems - 1;
4531 do {
4533 aItems[i].cfg.setProperty("disabled", bDisabled);
4536 while (i--);
4541 if (bDisabled) {
4543 this.clearActiveItem(true);
4545 Dom.addClass(this.element, "disabled");
4547 this.itemAddedEvent.subscribe(this._onItemAdded);
4550 else {
4552 Dom.removeClass(this.element, "disabled");
4554 this.itemAddedEvent.unsubscribe(this._onItemAdded);
4564 * @method onRender
4565 * @description "render" event handler for the menu.
4566 * @param {String} p_sType String representing the name of the event that
4567 * was fired.
4568 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4570 onRender: function (p_sType, p_aArgs) {
4572 function sizeShadow() {
4574 var oElement = this.element,
4575 oShadow = this._shadow;
4577 if (oShadow && oElement) {
4579 // Clear the previous width
4581 if (oShadow.style.width && oShadow.style.height) {
4583 oShadow.style.width = "";
4584 oShadow.style.height = "";
4588 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
4589 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
4596 function replaceShadow() {
4598 this.element.appendChild(this._shadow);
4603 function addShadowVisibleClass() {
4605 Dom.addClass(this._shadow, "yui-menu-shadow-visible");
4610 function removeShadowVisibleClass() {
4612 Dom.removeClass(this._shadow, "yui-menu-shadow-visible");
4617 function createShadow() {
4619 var oShadow = this._shadow,
4620 oElement,
4623 if (!oShadow) {
4625 oElement = this.element;
4626 me = this;
4628 if (!m_oShadowTemplate) {
4630 m_oShadowTemplate = document.createElement("div");
4631 m_oShadowTemplate.className =
4632 "yui-menu-shadow yui-menu-shadow-visible";
4636 oShadow = m_oShadowTemplate.cloneNode(false);
4638 oElement.appendChild(oShadow);
4640 this._shadow = oShadow;
4642 this.beforeShowEvent.subscribe(addShadowVisibleClass);
4643 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
4645 if (UA.ie) {
4648 Need to call sizeShadow & syncIframe via setTimeout for
4649 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
4650 or the shadow and iframe shim will not be sized and
4651 positioned properly.
4654 window.setTimeout(function () {
4656 sizeShadow.call(me);
4657 me.syncIframe();
4659 }, 0);
4661 this.cfg.subscribeToConfigEvent("width", sizeShadow);
4662 this.cfg.subscribeToConfigEvent("height", sizeShadow);
4663 this.cfg.subscribeToConfigEvent("maxheight", sizeShadow);
4664 this.changeContentEvent.subscribe(sizeShadow);
4666 Module.textResizeEvent.subscribe(sizeShadow, me, true);
4668 this.destroyEvent.subscribe(function () {
4670 Module.textResizeEvent.unsubscribe(sizeShadow, me);
4676 this.cfg.subscribeToConfigEvent("maxheight", replaceShadow);
4683 function onBeforeShow() {
4685 createShadow.call(this);
4687 this.beforeShowEvent.unsubscribe(onBeforeShow);
4692 if (this.cfg.getProperty("position") == "dynamic") {
4694 if (this.cfg.getProperty("visible")) {
4696 createShadow.call(this);
4699 else {
4701 this.beforeShowEvent.subscribe(onBeforeShow);
4710 // Public methods
4714 * @method initEvents
4715 * @description Initializes the custom events for the menu.
4717 initEvents: function () {
4719 Menu.superclass.initEvents.call(this);
4721 // Create custom events
4723 var SIGNATURE = CustomEvent.LIST;
4725 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
4726 this.mouseOverEvent.signature = SIGNATURE;
4728 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
4729 this.mouseOutEvent.signature = SIGNATURE;
4731 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
4732 this.mouseDownEvent.signature = SIGNATURE;
4734 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
4735 this.mouseUpEvent.signature = SIGNATURE;
4737 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
4738 this.clickEvent.signature = SIGNATURE;
4740 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
4741 this.keyPressEvent.signature = SIGNATURE;
4743 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
4744 this.keyDownEvent.signature = SIGNATURE;
4746 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
4747 this.keyUpEvent.signature = SIGNATURE;
4749 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
4750 this.focusEvent.signature = SIGNATURE;
4752 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
4753 this.blurEvent.signature = SIGNATURE;
4755 this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED);
4756 this.itemAddedEvent.signature = SIGNATURE;
4758 this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED);
4759 this.itemRemovedEvent.signature = SIGNATURE;
4765 * @method positionOffScreen
4766 * @description Positions the menu outside of the boundaries of the browser's
4767 * viewport. Called automatically when a menu is hidden to ensure that
4768 * it doesn't force the browser to render uncessary scrollbars.
4770 positionOffScreen: function () {
4772 var oIFrame = this.iframe,
4773 aPos = this.OFF_SCREEN_POSITION;
4775 Dom.setXY(this.element, aPos);
4777 if (oIFrame) {
4779 Dom.setXY(oIFrame, aPos);
4787 * @method getRoot
4788 * @description Finds the menu's root menu.
4790 getRoot: function () {
4792 var oItem = this.parent,
4793 oParentMenu;
4795 if (oItem) {
4797 oParentMenu = oItem.parent;
4799 return oParentMenu ? oParentMenu.getRoot() : this;
4802 else {
4804 return this;
4812 * @method toString
4813 * @description Returns a string representing the menu.
4814 * @return {String}
4816 toString: function () {
4818 var sReturnVal = "Menu",
4819 sId = this.id;
4821 if (sId) {
4823 sReturnVal += (" " + sId);
4827 return sReturnVal;
4833 * @method setItemGroupTitle
4834 * @description Sets the title of a group of menu items.
4835 * @param {String} p_sGroupTitle String specifying the title of the group.
4836 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
4837 * the title belongs.
4839 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
4841 var nGroupIndex,
4842 oTitle,
4844 nFirstIndex;
4846 if (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {
4848 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
4849 oTitle = this._aGroupTitleElements[nGroupIndex];
4852 if (oTitle) {
4854 oTitle.innerHTML = p_sGroupTitle;
4857 else {
4859 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
4861 oTitle.innerHTML = p_sGroupTitle;
4863 this._aGroupTitleElements[nGroupIndex] = oTitle;
4868 i = this._aGroupTitleElements.length - 1;
4870 do {
4872 if (this._aGroupTitleElements[i]) {
4874 Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");
4876 nFirstIndex = i;
4881 while(i--);
4884 if (nFirstIndex !== null) {
4886 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
4887 "first-of-type");
4891 this.changeContentEvent.fire();
4900 * @method addItem
4901 * @description Appends an item to the menu.
4902 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4903 * instance to be added to the menu.
4904 * @param {String} p_oItem String specifying the text of the item to be added
4905 * to the menu.
4906 * @param {Object} p_oItem Object literal containing a set of menu item
4907 * configuration properties.
4908 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
4909 * which the item belongs.
4910 * @return {YAHOO.widget.MenuItem}
4912 addItem: function (p_oItem, p_nGroupIndex) {
4914 if (p_oItem) {
4916 return this._addItemToGroup(p_nGroupIndex, p_oItem);
4924 * @method addItems
4925 * @description Adds an array of items to the menu.
4926 * @param {Array} p_aItems Array of items to be added to the menu. The array
4927 * can contain strings specifying the text for each item to be created, object
4928 * literals specifying each of the menu item configuration properties,
4929 * or MenuItem instances.
4930 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
4931 * which the items belongs.
4932 * @return {Array}
4934 addItems: function (p_aItems, p_nGroupIndex) {
4936 var nItems,
4937 aItems,
4938 oItem,
4941 if (Lang.isArray(p_aItems)) {
4943 nItems = p_aItems.length;
4944 aItems = [];
4946 for(i=0; i<nItems; i++) {
4948 oItem = p_aItems[i];
4950 if (oItem) {
4952 if (Lang.isArray(oItem)) {
4954 aItems[aItems.length] = this.addItems(oItem, i);
4957 else {
4959 aItems[aItems.length] =
4960 this._addItemToGroup(p_nGroupIndex, oItem);
4969 if (aItems.length) {
4971 return aItems;
4981 * @method insertItem
4982 * @description Inserts an item into the menu at the specified index.
4983 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4984 * instance to be added to the menu.
4985 * @param {String} p_oItem String specifying the text of the item to be added
4986 * to the menu.
4987 * @param {Object} p_oItem Object literal containing a set of menu item
4988 * configuration properties.
4989 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
4990 * the item should be added.
4991 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
4992 * the item belongs.
4993 * @return {YAHOO.widget.MenuItem}
4995 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
4997 if (p_oItem) {
4999 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5007 * @method removeItem
5008 * @description Removes the specified item from the menu.
5009 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5010 * instance to be removed from the menu.
5011 * @param {Number} p_oObject Number specifying the index of the item
5012 * to be removed.
5013 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5014 * which the item belongs.
5015 * @return {YAHOO.widget.MenuItem}
5017 removeItem: function (p_oObject, p_nGroupIndex) {
5019 var oItem;
5021 if (typeof p_oObject != "undefined") {
5023 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5025 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5028 else if (typeof p_oObject == "number") {
5030 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5034 if (oItem) {
5036 oItem.destroy();
5039 return oItem;
5049 * @method getItems
5050 * @description Returns an array of all of the items in the menu.
5051 * @return {Array}
5053 getItems: function () {
5055 var aGroups = this._aItemGroups,
5056 nGroups,
5057 aItems = [];
5059 if (Lang.isArray(aGroups)) {
5061 nGroups = aGroups.length;
5063 return ((nGroups == 1) ? aGroups[0] :
5064 (Array.prototype.concat.apply(aItems, aGroups)));
5072 * @method getItemGroups
5073 * @description Multi-dimensional Array representing the menu items as they
5074 * are grouped in the menu.
5075 * @return {Array}
5077 getItemGroups: function () {
5079 return this._aItemGroups;
5085 * @method getItem
5086 * @description Returns the item at the specified index.
5087 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5088 * item to be retrieved.
5089 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5090 * the item belongs.
5091 * @return {YAHOO.widget.MenuItem}
5093 getItem: function (p_nItemIndex, p_nGroupIndex) {
5095 var aGroup;
5097 if (typeof p_nItemIndex == "number") {
5099 aGroup = this._getItemGroup(p_nGroupIndex);
5101 if (aGroup) {
5103 return aGroup[p_nItemIndex];
5113 * @method getSubmenus
5114 * @description Returns an array of all of the submenus that are immediate
5115 * children of the menu.
5116 * @return {Array}
5118 getSubmenus: function () {
5120 var aItems = this.getItems(),
5121 nItems = aItems.length,
5122 aSubmenus,
5123 oSubmenu,
5124 oItem,
5128 if (nItems > 0) {
5130 aSubmenus = [];
5132 for(i=0; i<nItems; i++) {
5134 oItem = aItems[i];
5136 if (oItem) {
5138 oSubmenu = oItem.cfg.getProperty("submenu");
5140 if (oSubmenu) {
5142 aSubmenus[aSubmenus.length] = oSubmenu;
5152 return aSubmenus;
5158 * @method clearContent
5159 * @description Removes all of the content from the menu, including the menu
5160 * items, group titles, header and footer.
5162 clearContent: function () {
5164 var aItems = this.getItems(),
5165 nItems = aItems.length,
5166 oElement = this.element,
5167 oBody = this.body,
5168 oHeader = this.header,
5169 oFooter = this.footer,
5170 oItem,
5171 oSubmenu,
5175 if (nItems > 0) {
5177 i = nItems - 1;
5179 do {
5181 oItem = aItems[i];
5183 if (oItem) {
5185 oSubmenu = oItem.cfg.getProperty("submenu");
5187 if (oSubmenu) {
5189 this.cfg.configChangedEvent.unsubscribe(
5190 this._onParentMenuConfigChange, oSubmenu);
5192 this.renderEvent.unsubscribe(this._onParentMenuRender,
5193 oSubmenu);
5197 this.removeItem(oItem);
5202 while(i--);
5207 if (oHeader) {
5209 Event.purgeElement(oHeader);
5210 oElement.removeChild(oHeader);
5215 if (oFooter) {
5217 Event.purgeElement(oFooter);
5218 oElement.removeChild(oFooter);
5222 if (oBody) {
5224 Event.purgeElement(oBody);
5226 oBody.innerHTML = "";
5230 this.activeItem = null;
5232 this._aItemGroups = [];
5233 this._aListElements = [];
5234 this._aGroupTitleElements = [];
5236 this.cfg.setProperty("width", null);
5242 * @method destroy
5243 * @description Removes the menu's <code>&#60;div&#62;</code> element
5244 * (and accompanying child nodes) from the document.
5246 destroy: function () {
5248 // Remove all items
5250 this.clearContent();
5252 this._aItemGroups = null;
5253 this._aListElements = null;
5254 this._aGroupTitleElements = null;
5257 // Continue with the superclass implementation of this method
5259 Menu.superclass.destroy.call(this);
5266 * @method setInitialFocus
5267 * @description Sets focus to the menu's first enabled item.
5269 setInitialFocus: function () {
5271 var oItem = this._getFirstEnabledItem();
5273 if (oItem) {
5275 oItem.focus();
5283 * @method setInitialSelection
5284 * @description Sets the "selected" configuration property of the menu's first
5285 * enabled item to "true."
5287 setInitialSelection: function () {
5289 var oItem = this._getFirstEnabledItem();
5291 if (oItem) {
5293 oItem.cfg.setProperty("selected", true);
5300 * @method clearActiveItem
5301 * @description Sets the "selected" configuration property of the menu's active
5302 * item to "false" and hides the item's submenu.
5303 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5304 * should be blurred.
5306 clearActiveItem: function (p_bBlur) {
5308 if (this.cfg.getProperty("showdelay") > 0) {
5310 this._cancelShowDelay();
5315 var oActiveItem = this.activeItem,
5316 oConfig,
5317 oSubmenu;
5319 if (oActiveItem) {
5321 oConfig = oActiveItem.cfg;
5323 if (p_bBlur) {
5325 oActiveItem.blur();
5329 oConfig.setProperty("selected", false);
5331 oSubmenu = oConfig.getProperty("submenu");
5333 if (oSubmenu) {
5335 oSubmenu.hide();
5339 this.activeItem = null;
5347 * @method focus
5348 * @description Causes the menu to receive focus and fires the "focus" event.
5350 focus: function () {
5352 if (!this.hasFocus()) {
5354 this.setInitialFocus();
5362 * @method blur
5363 * @description Causes the menu to lose focus and fires the "blur" event.
5365 blur: function () {
5367 var oItem;
5369 if (this.hasFocus()) {
5371 oItem = MenuManager.getFocusedMenuItem();
5373 if (oItem) {
5375 oItem.blur();
5385 * @method hasFocus
5386 * @description Returns a boolean indicating whether or not the menu has focus.
5387 * @return {Boolean}
5389 hasFocus: function () {
5391 return (MenuManager.getFocusedMenu() == this.getRoot());
5397 * Adds the specified CustomEvent subscriber to the menu and each of
5398 * its submenus.
5399 * @method subscribe
5400 * @param p_type {string} the type, or name of the event
5401 * @param p_fn {function} the function to exectute when the event fires
5402 * @param p_obj {Object} An object to be passed along when the event
5403 * fires
5404 * @param p_override {boolean} If true, the obj passed in becomes the
5405 * execution scope of the listener
5407 subscribe: function () {
5409 function onItemAdded(p_sType, p_aArgs, p_oObject) {
5411 var oItem = p_aArgs[0],
5412 oSubmenu = oItem.cfg.getProperty("submenu");
5414 if (oSubmenu) {
5416 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5423 function onSubmenuAdded(p_sType, p_aArgs, p_oObject) {
5425 var oSubmenu = this.cfg.getProperty("submenu");
5427 if (oSubmenu) {
5429 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5436 Menu.superclass.subscribe.apply(this, arguments);
5437 Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments);
5440 var aItems = this.getItems(),
5441 nItems,
5442 oItem,
5443 oSubmenu,
5447 if (aItems) {
5449 nItems = aItems.length;
5451 if (nItems > 0) {
5453 i = nItems - 1;
5455 do {
5457 oItem = aItems[i];
5459 oSubmenu = oItem.cfg.getProperty("submenu");
5461 if (oSubmenu) {
5463 oSubmenu.subscribe.apply(oSubmenu, arguments);
5466 else {
5468 oItem.cfg.subscribeToConfigEvent("submenu", onSubmenuAdded, 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;
5494 // Module documentation overrides
5497 * @config effect
5498 * @description Object or array of objects representing the ContainerEffect
5499 * classes that are active for animating the container. When set this
5500 * property is automatically applied to all submenus.
5501 * @type Object
5502 * @default null
5505 // Overlay documentation overrides
5509 * @config x
5510 * @description Number representing the absolute x-coordinate position of
5511 * the Menu. This property is only applied when the "position"
5512 * configuration property is set to dynamic.
5513 * @type Number
5514 * @default null
5519 * @config y
5520 * @description Number representing the absolute y-coordinate position of
5521 * the Menu. This property is only applied when the "position"
5522 * configuration property is set to dynamic.
5523 * @type Number
5524 * @default null
5529 * @description Array of the absolute x and y positions of the Menu. This
5530 * property is only applied when the "position" configuration property is
5531 * set to dynamic.
5532 * @config xy
5533 * @type Number[]
5534 * @default null
5539 * @config context
5540 * @description Array of context arguments for context-sensitive positioning.
5541 * The format is: [id or element, element corner, context corner].
5542 * For example, setting this property to ["img1", "tl", "bl"] would
5543 * align the Mnu's top left corner to the context element's
5544 * bottom left corner. This property is only applied when the "position"
5545 * configuration property is set to dynamic.
5546 * @type Array
5547 * @default null
5552 * @config fixedcenter
5553 * @description Boolean indicating if the Menu should be anchored to the
5554 * center of the viewport. This property is only applied when the
5555 * "position" configuration property is set to dynamic.
5556 * @type Boolean
5557 * @default false
5562 * @config zindex
5563 * @description Number representing the CSS z-index of the Menu. This
5564 * property is only applied when the "position" configuration property is
5565 * set to dynamic.
5566 * @type Number
5567 * @default null
5572 * @config iframe
5573 * @description Boolean indicating whether or not the Menu should
5574 * have an IFRAME shim; used to prevent SELECT elements from
5575 * poking through an Overlay instance in IE6. When set to "true",
5576 * the iframe shim is created when the Menu instance is intially
5577 * made visible. This property is only applied when the "position"
5578 * configuration property is set to dynamic and is automatically applied
5579 * to all submenus.
5580 * @type Boolean
5581 * @default true for IE6 and below, false for all other browsers.
5585 // Add configuration attributes
5588 Change the default value for the "visible" configuration
5589 property to "false" by re-adding the property.
5593 * @config visible
5594 * @description Boolean indicating whether or not the menu is visible. If
5595 * the menu's "position" configuration property is set to "dynamic" (the
5596 * default), this property toggles the menu's <code>&#60;div&#62;</code>
5597 * element's "visibility" style property between "visible" (true) or
5598 * "hidden" (false). If the menu's "position" configuration property is
5599 * set to "static" this property toggles the menu's
5600 * <code>&#60;div&#62;</code> element's "display" style property
5601 * between "block" (true) or "none" (false).
5602 * @default false
5603 * @type Boolean
5605 oConfig.addProperty(
5606 DEFAULT_CONFIG.VISIBLE.key,
5608 handler: this.configVisible,
5609 value: DEFAULT_CONFIG.VISIBLE.value,
5610 validator: DEFAULT_CONFIG.VISIBLE.validator
5616 Change the default value for the "constraintoviewport" configuration
5617 property to "true" by re-adding the property.
5621 * @config constraintoviewport
5622 * @description Boolean indicating if the menu will try to remain inside
5623 * the boundaries of the size of viewport. This property is only applied
5624 * when the "position" configuration property is set to dynamic and is
5625 * automatically applied to all submenus.
5626 * @default true
5627 * @type Boolean
5629 oConfig.addProperty(
5630 DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key,
5632 handler: this.configConstrainToViewport,
5633 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
5634 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
5635 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
5641 * @config position
5642 * @description String indicating how a menu should be positioned on the
5643 * screen. Possible values are "static" and "dynamic." Static menus are
5644 * visible by default and reside in the normal flow of the document
5645 * (CSS position: static). Dynamic menus are hidden by default, reside
5646 * out of the normal flow of the document (CSS position: absolute), and
5647 * can overlay other elements on the screen.
5648 * @default dynamic
5649 * @type String
5651 oConfig.addProperty(
5652 DEFAULT_CONFIG.POSITION.key,
5654 handler: this.configPosition,
5655 value: DEFAULT_CONFIG.POSITION.value,
5656 validator: DEFAULT_CONFIG.POSITION.validator,
5657 supercedes: DEFAULT_CONFIG.POSITION.supercedes
5663 * @config submenualignment
5664 * @description Array defining how submenus should be aligned to their
5665 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
5666 * a submenu's top left corner is aligned to its parent menu item's top
5667 * right corner.
5668 * @default ["tl","tr"]
5669 * @type Array
5671 oConfig.addProperty(
5672 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
5674 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
5675 suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
5681 * @config autosubmenudisplay
5682 * @description Boolean indicating if submenus are automatically made
5683 * visible when the user mouses over the menu's items.
5684 * @default true
5685 * @type Boolean
5687 oConfig.addProperty(
5688 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
5690 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
5691 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
5692 suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
5698 * @config showdelay
5699 * @description Number indicating the time (in milliseconds) that should
5700 * expire before a submenu is made visible when the user mouses over
5701 * the menu's items. This property is only applied when the "position"
5702 * configuration property is set to dynamic and is automatically applied
5703 * to all submenus.
5704 * @default 250
5705 * @type Number
5707 oConfig.addProperty(
5708 DEFAULT_CONFIG.SHOW_DELAY.key,
5710 value: DEFAULT_CONFIG.SHOW_DELAY.value,
5711 validator: DEFAULT_CONFIG.SHOW_DELAY.validator,
5712 suppressEvent: DEFAULT_CONFIG.SHOW_DELAY.suppressEvent
5718 * @config hidedelay
5719 * @description Number indicating the time (in milliseconds) that should
5720 * expire before the menu is hidden. This property is only applied when
5721 * the "position" configuration property is set to dynamic and is
5722 * automatically applied to all submenus.
5723 * @default 0
5724 * @type Number
5726 oConfig.addProperty(
5727 DEFAULT_CONFIG.HIDE_DELAY.key,
5729 handler: this.configHideDelay,
5730 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5731 validator: DEFAULT_CONFIG.HIDE_DELAY.validator,
5732 suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.suppressEvent
5738 * @config submenuhidedelay
5739 * @description Number indicating the time (in milliseconds) that should
5740 * expire before a submenu is hidden when the user mouses out of a menu item
5741 * heading in the direction of a submenu. The value must be greater than or
5742 * equal to the value specified for the "showdelay" configuration property.
5743 * This property is only applied when the "position" configuration property
5744 * is set to dynamic and is automatically applied to all submenus.
5745 * @default 250
5746 * @type Number
5748 oConfig.addProperty(
5749 DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key,
5751 value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value,
5752 validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator,
5753 suppressEvent: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.suppressEvent
5759 * @config clicktohide
5760 * @description Boolean indicating if the menu will automatically be
5761 * hidden if the user clicks outside of it. This property is only
5762 * applied when the "position" configuration property is set to dynamic
5763 * and is automatically applied to all submenus.
5764 * @default true
5765 * @type Boolean
5767 oConfig.addProperty(
5768 DEFAULT_CONFIG.CLICK_TO_HIDE.key,
5770 value: DEFAULT_CONFIG.CLICK_TO_HIDE.value,
5771 validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator,
5772 suppressEvent: DEFAULT_CONFIG.CLICK_TO_HIDE.suppressEvent
5778 * @config container
5779 * @description HTML element reference or string specifying the id
5780 * attribute of the HTML element that the menu's markup should be
5781 * rendered into.
5782 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
5783 * level-one-html.html#ID-58190037">HTMLElement</a>|String
5784 * @default document.body
5786 oConfig.addProperty(
5787 DEFAULT_CONFIG.CONTAINER.key,
5789 handler: this.configContainer,
5790 value: document.body,
5791 suppressEvent: DEFAULT_CONFIG.CONTAINER.suppressEvent
5797 * @config scrollincrement
5798 * @description Number used to control the scroll speed of a menu. Used to
5799 * increment the "scrollTop" property of the menu's body by when a menu's
5800 * content is scrolling. When set this property is automatically applied
5801 * to all submenus.
5802 * @default 1
5803 * @type Number
5805 oConfig.addProperty(
5806 DEFAULT_CONFIG.SCROLL_INCREMENT.key,
5808 value: DEFAULT_CONFIG.SCROLL_INCREMENT.value,
5809 validator: DEFAULT_CONFIG.SCROLL_INCREMENT.validator,
5810 supercedes: DEFAULT_CONFIG.SCROLL_INCREMENT.supercedes,
5811 suppressEvent: DEFAULT_CONFIG.SCROLL_INCREMENT.suppressEvent
5817 * @config minscrollheight
5818 * @description Number defining the minimum threshold for the "maxheight"
5819 * configuration property. When set this property is automatically applied
5820 * to all submenus.
5821 * @default 90
5822 * @type Number
5824 oConfig.addProperty(
5825 DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.key,
5827 value: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.value,
5828 validator: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.validator,
5829 supercedes: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.supercedes,
5830 suppressEvent: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.suppressEvent
5836 * @config maxheight
5837 * @description Number defining the maximum height (in pixels) for a menu's
5838 * body element (<code>&#60;div class="bd"&#60;</code>). Once a menu's body
5839 * exceeds this height, the contents of the body are scrolled to maintain
5840 * this value. This value cannot be set lower than the value of the
5841 * "minscrollheight" configuration property.
5842 * @default 0
5843 * @type Number
5845 oConfig.addProperty(
5846 DEFAULT_CONFIG.MAX_HEIGHT.key,
5848 handler: this.configMaxHeight,
5849 value: DEFAULT_CONFIG.MAX_HEIGHT.value,
5850 validator: DEFAULT_CONFIG.MAX_HEIGHT.validator,
5851 suppressEvent: DEFAULT_CONFIG.MAX_HEIGHT.suppressEvent,
5852 supercedes: DEFAULT_CONFIG.MAX_HEIGHT.supercedes
5858 * @config classname
5859 * @description String representing the CSS class to be applied to the
5860 * menu's root <code>&#60;div&#62;</code> element. The specified class(es)
5861 * are appended in addition to the default class as specified by the menu's
5862 * CSS_CLASS_NAME constant. When set this property is automatically
5863 * applied to all submenus.
5864 * @default null
5865 * @type String
5867 oConfig.addProperty(
5868 DEFAULT_CONFIG.CLASS_NAME.key,
5870 handler: this.configClassName,
5871 value: DEFAULT_CONFIG.CLASS_NAME.value,
5872 validator: DEFAULT_CONFIG.CLASS_NAME.validator,
5873 supercedes: DEFAULT_CONFIG.CLASS_NAME.supercedes
5879 * @config disabled
5880 * @description Boolean indicating if the menu should be disabled.
5881 * Disabling a menu disables each of its items. (Disabled menu items are
5882 * dimmed and will not respond to user input or fire events.) Disabled
5883 * menus have a corresponding "disabled" CSS class applied to their root
5884 * <code>&#60;div&#62;</code> element.
5885 * @default false
5886 * @type Boolean
5888 oConfig.addProperty(
5889 DEFAULT_CONFIG.DISABLED.key,
5891 handler: this.configDisabled,
5892 value: DEFAULT_CONFIG.DISABLED.value,
5893 validator: DEFAULT_CONFIG.DISABLED.validator,
5894 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5900 }); // END YAHOO.lang.extend
5902 })();
5906 (function () {
5910 * Creates an item for a menu.
5912 * @param {String} p_oObject String specifying the text of the menu item.
5913 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5914 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
5915 * the <code>&#60;li&#62;</code> element of the menu item.
5916 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5917 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
5918 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
5919 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5920 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
5921 * specifying the <code>&#60;option&#62;</code> element of the menu item.
5922 * @param {Object} p_oConfig Optional. Object literal specifying the
5923 * configuration for the menu item. See configuration class documentation
5924 * for more details.
5925 * @class MenuItem
5926 * @constructor
5928 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
5930 if (p_oObject) {
5932 if (p_oConfig) {
5934 this.parent = p_oConfig.parent;
5935 this.value = p_oConfig.value;
5936 this.id = p_oConfig.id;
5940 this.init(p_oObject, p_oConfig);
5947 var Dom = YAHOO.util.Dom,
5948 Module = YAHOO.widget.Module,
5949 Menu = YAHOO.widget.Menu,
5950 MenuItem = YAHOO.widget.MenuItem,
5951 CustomEvent = YAHOO.util.CustomEvent,
5952 Lang = YAHOO.lang,
5954 m_oMenuItemTemplate,
5957 * Constant representing the name of the MenuItem's events
5958 * @property EVENT_TYPES
5959 * @private
5960 * @final
5961 * @type Object
5963 EVENT_TYPES = {
5965 "MOUSE_OVER": "mouseover",
5966 "MOUSE_OUT": "mouseout",
5967 "MOUSE_DOWN": "mousedown",
5968 "MOUSE_UP": "mouseup",
5969 "CLICK": "click",
5970 "KEY_PRESS": "keypress",
5971 "KEY_DOWN": "keydown",
5972 "KEY_UP": "keyup",
5973 "ITEM_ADDED": "itemAdded",
5974 "ITEM_REMOVED": "itemRemoved",
5975 "FOCUS": "focus",
5976 "BLUR": "blur",
5977 "DESTROY": "destroy"
5982 * Constant representing the MenuItem's configuration properties
5983 * @property DEFAULT_CONFIG
5984 * @private
5985 * @final
5986 * @type Object
5988 DEFAULT_CONFIG = {
5990 "TEXT": {
5991 key: "text",
5992 value: "",
5993 validator: Lang.isString,
5994 suppressEvent: true
5997 "HELP_TEXT": {
5998 key: "helptext",
5999 supercedes: ["text"],
6000 suppressEvent: true
6003 "URL": {
6004 key: "url",
6005 value: "#",
6006 suppressEvent: true
6009 "TARGET": {
6010 key: "target",
6011 suppressEvent: true
6014 "EMPHASIS": {
6015 key: "emphasis",
6016 value: false,
6017 validator: Lang.isBoolean,
6018 suppressEvent: true,
6019 supercedes: ["text"]
6022 "STRONG_EMPHASIS": {
6023 key: "strongemphasis",
6024 value: false,
6025 validator: Lang.isBoolean,
6026 suppressEvent: true,
6027 supercedes: ["text"]
6030 "CHECKED": {
6031 key: "checked",
6032 value: false,
6033 validator: Lang.isBoolean,
6034 suppressEvent: true,
6035 supercedes: ["disabled", "selected"]
6038 "SUBMENU": {
6039 key: "submenu",
6040 suppressEvent: true,
6041 supercedes: ["disabled", "selected"]
6044 "DISABLED": {
6045 key: "disabled",
6046 value: false,
6047 validator: Lang.isBoolean,
6048 suppressEvent: true,
6049 supercedes: ["text", "selected"]
6052 "SELECTED": {
6053 key: "selected",
6054 value: false,
6055 validator: Lang.isBoolean,
6056 suppressEvent: true
6059 "ONCLICK": {
6060 key: "onclick",
6061 suppressEvent: true
6064 "CLASS_NAME": {
6065 key: "classname",
6066 value: null,
6067 validator: Lang.isString,
6068 suppressEvent: true
6074 MenuItem.prototype = {
6077 * @property CSS_CLASS_NAME
6078 * @description String representing the CSS class(es) to be applied to the
6079 * <code>&#60;li&#62;</code> element of the menu item.
6080 * @default "yuimenuitem"
6081 * @final
6082 * @type String
6084 CSS_CLASS_NAME: "yuimenuitem",
6088 * @property CSS_LABEL_CLASS_NAME
6089 * @description String representing the CSS class(es) to be applied to the
6090 * menu item's <code>&#60;a&#62;</code> element.
6091 * @default "yuimenuitemlabel"
6092 * @final
6093 * @type String
6095 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6099 * @property SUBMENU_TYPE
6100 * @description Object representing the type of menu to instantiate and
6101 * add when parsing the child nodes of the menu item's source HTML element.
6102 * @final
6103 * @type YAHOO.widget.Menu
6105 SUBMENU_TYPE: null,
6109 // Private member variables
6113 * @property _oAnchor
6114 * @description Object reference to the menu item's
6115 * <code>&#60;a&#62;</code> element.
6116 * @default null
6117 * @private
6118 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6119 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6121 _oAnchor: null,
6125 * @property _oHelpTextEM
6126 * @description Object reference to the menu item's help text
6127 * <code>&#60;em&#62;</code> element.
6128 * @default null
6129 * @private
6130 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6131 * one-html.html#ID-58190037">HTMLElement</a>
6133 _oHelpTextEM: null,
6137 * @property _oSubmenu
6138 * @description Object reference to the menu item's submenu.
6139 * @default null
6140 * @private
6141 * @type YAHOO.widget.Menu
6143 _oSubmenu: null,
6146 /**
6147 * @property _oOnclickAttributeValue
6148 * @description Object reference to the menu item's current value for the
6149 * "onclick" configuration attribute.
6150 * @default null
6151 * @private
6152 * @type Object
6154 _oOnclickAttributeValue: null,
6158 * @property _sClassName
6159 * @description The current value of the "classname" configuration attribute.
6160 * @default null
6161 * @private
6162 * @type String
6164 _sClassName: null,
6168 // Public properties
6172 * @property constructor
6173 * @description Object reference to the menu item's constructor function.
6174 * @default YAHOO.widget.MenuItem
6175 * @type YAHOO.widget.MenuItem
6177 constructor: MenuItem,
6181 * @property index
6182 * @description Number indicating the ordinal position of the menu item in
6183 * its group.
6184 * @default null
6185 * @type Number
6187 index: null,
6191 * @property groupIndex
6192 * @description Number indicating the index of the group to which the menu
6193 * item belongs.
6194 * @default null
6195 * @type Number
6197 groupIndex: null,
6201 * @property parent
6202 * @description Object reference to the menu item's parent menu.
6203 * @default null
6204 * @type YAHOO.widget.Menu
6206 parent: null,
6210 * @property element
6211 * @description Object reference to the menu item's
6212 * <code>&#60;li&#62;</code> element.
6213 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6214 * -one-html.html#ID-74680021">HTMLLIElement</a>
6215 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6216 * one-html.html#ID-74680021">HTMLLIElement</a>
6218 element: null,
6222 * @property srcElement
6223 * @description Object reference to the HTML element (either
6224 * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
6225 * <code>&#60;option&#62;</code>) used create the menu item.
6226 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6227 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6228 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6229 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6230 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6231 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6232 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6233 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6234 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6235 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6237 srcElement: null,
6241 * @property value
6242 * @description Object reference to the menu item's value.
6243 * @default null
6244 * @type Object
6246 value: null,
6250 * @property browser
6251 * @deprecated Use YAHOO.env.ua
6252 * @description String representing the browser.
6253 * @type String
6255 browser: Module.prototype.browser,
6259 * @property id
6260 * @description Id of the menu item's root <code>&#60;li&#62;</code>
6261 * element. This property should be set via the constructor using the
6262 * configuration object literal. If an id is not specified, then one will
6263 * be created using the "generateId" method of the Dom utility.
6264 * @default null
6265 * @type String
6267 id: null,
6271 // Events
6275 * @event destroyEvent
6276 * @description Fires when the menu item's <code>&#60;li&#62;</code>
6277 * element is removed from its parent <code>&#60;ul&#62;</code> element.
6278 * @type YAHOO.util.CustomEvent
6280 destroyEvent: null,
6284 * @event mouseOverEvent
6285 * @description Fires when the mouse has entered the menu item. Passes
6286 * back the DOM Event object as an argument.
6287 * @type YAHOO.util.CustomEvent
6289 mouseOverEvent: null,
6293 * @event mouseOutEvent
6294 * @description Fires when the mouse has left the menu item. Passes back
6295 * the DOM Event object as an argument.
6296 * @type YAHOO.util.CustomEvent
6298 mouseOutEvent: null,
6302 * @event mouseDownEvent
6303 * @description Fires when the user mouses down on the menu item. Passes
6304 * back the DOM Event object as an argument.
6305 * @type YAHOO.util.CustomEvent
6307 mouseDownEvent: null,
6311 * @event mouseUpEvent
6312 * @description Fires when the user releases a mouse button while the mouse
6313 * is over the menu item. Passes back the DOM Event object as an argument.
6314 * @type YAHOO.util.CustomEvent
6316 mouseUpEvent: null,
6320 * @event clickEvent
6321 * @description Fires when the user clicks the on the menu item. Passes
6322 * back the DOM Event object as an argument.
6323 * @type YAHOO.util.CustomEvent
6325 clickEvent: null,
6329 * @event keyPressEvent
6330 * @description Fires when the user presses an alphanumeric key when the
6331 * menu item has focus. Passes back the DOM Event object as an argument.
6332 * @type YAHOO.util.CustomEvent
6334 keyPressEvent: null,
6338 * @event keyDownEvent
6339 * @description Fires when the user presses a key when the menu item has
6340 * focus. Passes back the DOM Event object as an argument.
6341 * @type YAHOO.util.CustomEvent
6343 keyDownEvent: null,
6347 * @event keyUpEvent
6348 * @description Fires when the user releases a key when the menu item has
6349 * focus. Passes back the DOM Event object as an argument.
6350 * @type YAHOO.util.CustomEvent
6352 keyUpEvent: null,
6356 * @event focusEvent
6357 * @description Fires when the menu item receives focus.
6358 * @type YAHOO.util.CustomEvent
6360 focusEvent: null,
6364 * @event blurEvent
6365 * @description Fires when the menu item loses the input focus.
6366 * @type YAHOO.util.CustomEvent
6368 blurEvent: null,
6372 * @method init
6373 * @description The MenuItem class's initialization method. This method is
6374 * automatically called by the constructor, and sets up all DOM references
6375 * for pre-existing markup, and creates required markup if it is not
6376 * already present.
6377 * @param {String} p_oObject String specifying the text of the menu item.
6378 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6379 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6380 * the <code>&#60;li&#62;</code> element of the menu item.
6381 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6382 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6383 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6384 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6385 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6386 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6387 * @param {Object} p_oConfig Optional. Object literal specifying the
6388 * configuration for the menu item. See configuration class documentation
6389 * for more details.
6391 init: function (p_oObject, p_oConfig) {
6394 if (!this.SUBMENU_TYPE) {
6396 this.SUBMENU_TYPE = Menu;
6401 // Create the config object
6403 this.cfg = new YAHOO.util.Config(this);
6405 this.initDefaultConfig();
6407 var SIGNATURE = CustomEvent.LIST,
6408 oConfig = this.cfg,
6409 sURL = "#",
6410 oAnchor,
6411 sTarget,
6412 sText,
6413 sId;
6416 if (Lang.isString(p_oObject)) {
6418 this._createRootNodeStructure();
6420 oConfig.queueProperty("text", p_oObject);
6423 else if (p_oObject && p_oObject.tagName) {
6425 switch(p_oObject.tagName.toUpperCase()) {
6427 case "OPTION":
6429 this._createRootNodeStructure();
6431 oConfig.queueProperty("text", p_oObject.text);
6432 oConfig.queueProperty("disabled", p_oObject.disabled);
6434 this.value = p_oObject.value;
6436 this.srcElement = p_oObject;
6438 break;
6440 case "OPTGROUP":
6442 this._createRootNodeStructure();
6444 oConfig.queueProperty("text", p_oObject.label);
6445 oConfig.queueProperty("disabled", p_oObject.disabled);
6447 this.srcElement = p_oObject;
6449 this._initSubTree();
6451 break;
6453 case "LI":
6455 // Get the anchor node (if it exists)
6457 oAnchor = Dom.getFirstChild(p_oObject);
6460 // Capture the "text" and/or the "URL"
6462 if (oAnchor) {
6464 sURL = oAnchor.getAttribute("href", 2);
6465 sTarget = oAnchor.getAttribute("target");
6467 sText = oAnchor.innerHTML;
6471 this.srcElement = p_oObject;
6472 this.element = p_oObject;
6473 this._oAnchor = oAnchor;
6476 Set these properties silently to sync up the
6477 configuration object without making changes to the
6478 element's DOM
6481 oConfig.setProperty("text", sText, true);
6482 oConfig.setProperty("url", sURL, true);
6483 oConfig.setProperty("target", sTarget, true);
6485 this._initSubTree();
6487 break;
6494 if (this.element) {
6496 sId = (this.srcElement || this.element).id;
6498 if (!sId) {
6500 sId = this.id || Dom.generateId();
6502 this.element.id = sId;
6506 this.id = sId;
6509 Dom.addClass(this.element, this.CSS_CLASS_NAME);
6510 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
6513 // Create custom events
6515 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
6516 this.mouseOverEvent.signature = SIGNATURE;
6518 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
6519 this.mouseOutEvent.signature = SIGNATURE;
6521 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
6522 this.mouseDownEvent.signature = SIGNATURE;
6524 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
6525 this.mouseUpEvent.signature = SIGNATURE;
6527 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
6528 this.clickEvent.signature = SIGNATURE;
6530 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
6531 this.keyPressEvent.signature = SIGNATURE;
6533 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
6534 this.keyDownEvent.signature = SIGNATURE;
6536 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
6537 this.keyUpEvent.signature = SIGNATURE;
6539 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
6540 this.focusEvent.signature = SIGNATURE;
6542 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
6543 this.blurEvent.signature = SIGNATURE;
6545 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
6546 this.destroyEvent.signature = SIGNATURE;
6548 if (p_oConfig) {
6550 oConfig.applyConfig(p_oConfig);
6554 oConfig.fireQueue();
6562 // Private methods
6566 * @method _createRootNodeStructure
6567 * @description Creates the core DOM structure for the menu item.
6568 * @private
6570 _createRootNodeStructure: function () {
6572 var oElement,
6573 oAnchor;
6575 if (!m_oMenuItemTemplate) {
6577 m_oMenuItemTemplate = document.createElement("li");
6578 m_oMenuItemTemplate.innerHTML = "<a href=\"#\"></a>";
6582 oElement = m_oMenuItemTemplate.cloneNode(true);
6583 oElement.className = this.CSS_CLASS_NAME;
6585 oAnchor = oElement.firstChild;
6586 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
6588 this.element = oElement;
6589 this._oAnchor = oAnchor;
6595 * @method _initSubTree
6596 * @description Iterates the source element's childNodes collection and uses
6597 * the child nodes to instantiate other menus.
6598 * @private
6600 _initSubTree: function () {
6602 var oSrcEl = this.srcElement,
6603 oConfig = this.cfg,
6604 oNode,
6605 aOptions,
6606 nOptions,
6607 oMenu,
6611 if (oSrcEl.childNodes.length > 0) {
6613 if (this.parent.lazyLoad && this.parent.srcElement &&
6614 this.parent.srcElement.tagName.toUpperCase() == "SELECT") {
6616 oConfig.setProperty(
6617 "submenu",
6618 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
6622 else {
6624 oNode = oSrcEl.firstChild;
6625 aOptions = [];
6627 do {
6629 if (oNode && oNode.tagName) {
6631 switch(oNode.tagName.toUpperCase()) {
6633 case "DIV":
6635 oConfig.setProperty("submenu", oNode);
6637 break;
6639 case "OPTION":
6641 aOptions[aOptions.length] = oNode;
6643 break;
6650 while((oNode = oNode.nextSibling));
6653 nOptions = aOptions.length;
6655 if (nOptions > 0) {
6657 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
6659 oConfig.setProperty("submenu", oMenu);
6661 for(n=0; n<nOptions; n++) {
6663 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
6677 // Event handlers for configuration properties
6681 * @method configText
6682 * @description Event handler for when the "text" configuration property of
6683 * the menu item changes.
6684 * @param {String} p_sType String representing the name of the event that
6685 * was fired.
6686 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6687 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6688 * that fired the event.
6690 configText: function (p_sType, p_aArgs, p_oItem) {
6692 var sText = p_aArgs[0],
6693 oConfig = this.cfg,
6694 oAnchor = this._oAnchor,
6695 sHelpText = oConfig.getProperty("helptext"),
6696 sHelpTextHTML = "",
6697 sEmphasisStartTag = "",
6698 sEmphasisEndTag = "";
6701 if (sText) {
6704 if (sHelpText) {
6706 sHelpTextHTML = "<em class=\"helptext\">" + sHelpText + "</em>";
6711 if (oConfig.getProperty("emphasis")) {
6713 sEmphasisStartTag = "<em>";
6714 sEmphasisEndTag = "</em>";
6719 if (oConfig.getProperty("strongemphasis")) {
6721 sEmphasisStartTag = "<strong>";
6722 sEmphasisEndTag = "</strong>";
6727 oAnchor.innerHTML = (sEmphasisStartTag + sText +
6728 sEmphasisEndTag + sHelpTextHTML);
6736 * @method configHelpText
6737 * @description Event handler for when the "helptext" configuration property
6738 * of the menu item changes.
6739 * @param {String} p_sType String representing the name of the event that
6740 * was fired.
6741 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6742 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6743 * that fired the event.
6745 configHelpText: function (p_sType, p_aArgs, p_oItem) {
6747 this.cfg.refireEvent("text");
6753 * @method configURL
6754 * @description Event handler for when the "url" configuration property of
6755 * the menu item changes.
6756 * @param {String} p_sType String representing the name of the event that
6757 * was fired.
6758 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6759 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6760 * that fired the event.
6762 configURL: function (p_sType, p_aArgs, p_oItem) {
6764 var sURL = p_aArgs[0];
6766 if (!sURL) {
6768 sURL = "#";
6772 var oAnchor = this._oAnchor;
6774 if (YAHOO.env.ua.opera) {
6776 oAnchor.removeAttribute("href");
6780 oAnchor.setAttribute("href", sURL);
6786 * @method configTarget
6787 * @description Event handler for when the "target" configuration property
6788 * of the menu item changes.
6789 * @param {String} p_sType String representing the name of the event that
6790 * was fired.
6791 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6792 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6793 * that fired the event.
6795 configTarget: function (p_sType, p_aArgs, p_oItem) {
6797 var sTarget = p_aArgs[0],
6798 oAnchor = this._oAnchor;
6800 if (sTarget && sTarget.length > 0) {
6802 oAnchor.setAttribute("target", sTarget);
6805 else {
6807 oAnchor.removeAttribute("target");
6815 * @method configEmphasis
6816 * @description Event handler for when the "emphasis" configuration property
6817 * of the menu item changes.
6818 * @param {String} p_sType String representing the name of the event that
6819 * was fired.
6820 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6821 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6822 * that fired the event.
6824 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
6826 var bEmphasis = p_aArgs[0],
6827 oConfig = this.cfg;
6830 if (bEmphasis && oConfig.getProperty("strongemphasis")) {
6832 oConfig.setProperty("strongemphasis", false);
6837 oConfig.refireEvent("text");
6843 * @method configStrongEmphasis
6844 * @description Event handler for when the "strongemphasis" configuration
6845 * property of the menu item changes.
6846 * @param {String} p_sType String representing the name of the event that
6847 * was fired.
6848 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6849 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6850 * that fired the event.
6852 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
6854 var bStrongEmphasis = p_aArgs[0],
6855 oConfig = this.cfg;
6858 if (bStrongEmphasis && oConfig.getProperty("emphasis")) {
6860 oConfig.setProperty("emphasis", false);
6864 oConfig.refireEvent("text");
6870 * @method configChecked
6871 * @description Event handler for when the "checked" configuration property
6872 * of the menu item changes.
6873 * @param {String} p_sType String representing the name of the event that
6874 * was fired.
6875 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6876 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6877 * that fired the event.
6879 configChecked: function (p_sType, p_aArgs, p_oItem) {
6881 var bChecked = p_aArgs[0],
6882 oElement = this.element,
6883 oAnchor = this._oAnchor,
6884 oConfig = this.cfg,
6885 sState = "-checked",
6886 sClassName = this.CSS_CLASS_NAME + sState,
6887 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState;
6890 if (bChecked) {
6892 Dom.addClass(oElement, sClassName);
6893 Dom.addClass(oAnchor, sLabelClassName);
6896 else {
6898 Dom.removeClass(oElement, sClassName);
6899 Dom.removeClass(oAnchor, sLabelClassName);
6904 oConfig.refireEvent("text");
6907 if (oConfig.getProperty("disabled")) {
6909 oConfig.refireEvent("disabled");
6914 if (oConfig.getProperty("selected")) {
6916 oConfig.refireEvent("selected");
6925 * @method configDisabled
6926 * @description Event handler for when the "disabled" configuration property
6927 * of the menu item changes.
6928 * @param {String} p_sType String representing the name of the event that
6929 * was fired.
6930 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6931 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6932 * that fired the event.
6934 configDisabled: function (p_sType, p_aArgs, p_oItem) {
6936 var bDisabled = p_aArgs[0],
6937 oConfig = this.cfg,
6938 oSubmenu = oConfig.getProperty("submenu"),
6939 bChecked = oConfig.getProperty("checked"),
6940 oElement = this.element,
6941 oAnchor = this._oAnchor,
6942 sState = "-disabled",
6943 sCheckedState = "-checked" + sState,
6944 sSubmenuState = "-hassubmenu" + sState,
6945 sClassName = this.CSS_CLASS_NAME + sState,
6946 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
6947 sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
6948 sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
6949 sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
6950 sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;
6953 if (bDisabled) {
6955 if (oConfig.getProperty("selected")) {
6957 oConfig.setProperty("selected", false);
6961 Dom.addClass(oElement, sClassName);
6962 Dom.addClass(oAnchor, sLabelClassName);
6965 if (oSubmenu) {
6967 Dom.addClass(oElement, sSubmenuClassName);
6968 Dom.addClass(oAnchor, sLabelSubmenuClassName);
6973 if (bChecked) {
6975 Dom.addClass(oElement, sCheckedClassName);
6976 Dom.addClass(oAnchor, sLabelCheckedClassName);
6981 else {
6983 Dom.removeClass(oElement, sClassName);
6984 Dom.removeClass(oAnchor, sLabelClassName);
6987 if (oSubmenu) {
6989 Dom.removeClass(oElement, sSubmenuClassName);
6990 Dom.removeClass(oAnchor, sLabelSubmenuClassName);
6995 if (bChecked) {
6997 Dom.removeClass(oElement, sCheckedClassName);
6998 Dom.removeClass(oAnchor, sLabelCheckedClassName);
7008 * @method configSelected
7009 * @description Event handler for when the "selected" configuration property
7010 * of the menu item changes.
7011 * @param {String} p_sType String representing the name of the event that
7012 * was fired.
7013 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7014 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7015 * that fired the event.
7017 configSelected: function (p_sType, p_aArgs, p_oItem) {
7019 var oConfig = this.cfg,
7020 bSelected = p_aArgs[0],
7021 oElement = this.element,
7022 oAnchor = this._oAnchor,
7023 bChecked = oConfig.getProperty("checked"),
7024 oSubmenu = oConfig.getProperty("submenu"),
7025 sState = "-selected",
7026 sCheckedState = "-checked" + sState,
7027 sSubmenuState = "-hassubmenu" + sState,
7028 sClassName = this.CSS_CLASS_NAME + sState,
7029 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
7030 sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
7031 sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
7032 sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
7033 sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;
7036 if (YAHOO.env.ua.opera) {
7038 oAnchor.blur();
7043 if (bSelected && !oConfig.getProperty("disabled")) {
7045 Dom.addClass(oElement, sClassName);
7046 Dom.addClass(oAnchor, sLabelClassName);
7049 if (oSubmenu) {
7051 Dom.addClass(oElement, sSubmenuClassName);
7052 Dom.addClass(oAnchor, sLabelSubmenuClassName);
7057 if (bChecked) {
7059 Dom.addClass(oElement, sCheckedClassName);
7060 Dom.addClass(oAnchor, sLabelCheckedClassName);
7065 else {
7067 Dom.removeClass(oElement, sClassName);
7068 Dom.removeClass(oAnchor, sLabelClassName);
7071 if (oSubmenu) {
7073 Dom.removeClass(oElement, sSubmenuClassName);
7074 Dom.removeClass(oAnchor, sLabelSubmenuClassName);
7079 if (bChecked) {
7081 Dom.removeClass(oElement, sCheckedClassName);
7082 Dom.removeClass(oAnchor, sLabelCheckedClassName);
7089 if (this.hasFocus() && YAHOO.env.ua.opera) {
7091 oAnchor.focus();
7099 * @method _onSubmenuBeforeHide
7100 * @description "beforehide" Custom Event handler for a submenu.
7101 * @private
7102 * @param {String} p_sType String representing the name of the event that
7103 * was fired.
7104 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7106 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7108 var oItem = this.parent,
7109 oMenu;
7111 function onHide() {
7113 oItem._oAnchor.blur();
7114 oMenu.beforeHideEvent.unsubscribe(onHide);
7119 if (oItem.hasFocus()) {
7121 oMenu = oItem.parent;
7123 oMenu.beforeHideEvent.subscribe(onHide);
7131 * @method configSubmenu
7132 * @description Event handler for when the "submenu" configuration property
7133 * of the menu item changes.
7134 * @param {String} p_sType String representing the name of the event that
7135 * was fired.
7136 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7137 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7138 * that fired the event.
7140 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7142 var oSubmenu = p_aArgs[0],
7143 oConfig = this.cfg,
7144 oElement = this.element,
7145 oAnchor = this._oAnchor,
7146 bLazyLoad = this.parent && this.parent.lazyLoad,
7147 sState = "-hassubmenu",
7148 sClassName = this.CSS_CLASS_NAME + sState,
7149 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
7150 oMenu,
7151 sSubmenuId,
7152 oSubmenuConfig;
7155 if (oSubmenu) {
7157 if (oSubmenu instanceof Menu) {
7159 oMenu = oSubmenu;
7160 oMenu.parent = this;
7161 oMenu.lazyLoad = bLazyLoad;
7164 else if (typeof oSubmenu == "object" && oSubmenu.id &&
7165 !oSubmenu.nodeType) {
7167 sSubmenuId = oSubmenu.id;
7168 oSubmenuConfig = oSubmenu;
7170 oSubmenuConfig.lazyload = bLazyLoad;
7171 oSubmenuConfig.parent = this;
7173 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7176 // Set the value of the property to the Menu instance
7178 oConfig.setProperty("submenu", oMenu, true);
7181 else {
7183 oMenu = new this.SUBMENU_TYPE(oSubmenu,
7184 { lazyload: bLazyLoad, parent: this });
7187 // Set the value of the property to the Menu instance
7189 oConfig.setProperty("submenu", oMenu, true);
7194 if (oMenu) {
7196 Dom.addClass(oElement, sClassName);
7197 Dom.addClass(oAnchor, sLabelClassName);
7199 this._oSubmenu = oMenu;
7201 if (YAHOO.env.ua.opera) {
7203 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7210 else {
7212 Dom.removeClass(oElement, sClassName);
7213 Dom.removeClass(oAnchor, sLabelClassName);
7215 if (this._oSubmenu) {
7217 this._oSubmenu.destroy();
7224 if (oConfig.getProperty("disabled")) {
7226 oConfig.refireEvent("disabled");
7231 if (oConfig.getProperty("selected")) {
7233 oConfig.refireEvent("selected");
7241 * @method configOnClick
7242 * @description Event handler for when the "onclick" configuration property
7243 * of the menu item changes.
7244 * @param {String} p_sType String representing the name of the event that
7245 * was fired.
7246 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7247 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7248 * that fired the event.
7250 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7252 var oObject = p_aArgs[0];
7255 Remove any existing listeners if a "click" event handler has
7256 already been specified.
7259 if (this._oOnclickAttributeValue &&
7260 (this._oOnclickAttributeValue != oObject)) {
7262 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7263 this._oOnclickAttributeValue.obj);
7265 this._oOnclickAttributeValue = null;
7270 if (!this._oOnclickAttributeValue && typeof oObject == "object" &&
7271 typeof oObject.fn == "function") {
7273 this.clickEvent.subscribe(oObject.fn,
7274 ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this),
7275 oObject.scope);
7277 this._oOnclickAttributeValue = oObject;
7285 * @method configClassName
7286 * @description Event handler for when the "classname" configuration
7287 * property of a menu item changes.
7288 * @param {String} p_sType String representing the name of the event that
7289 * was fired.
7290 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7291 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7292 * that fired the event.
7294 configClassName: function (p_sType, p_aArgs, p_oItem) {
7296 var sClassName = p_aArgs[0];
7298 if (this._sClassName) {
7300 Dom.removeClass(this.element, this._sClassName);
7304 Dom.addClass(this.element, sClassName);
7305 this._sClassName = sClassName;
7311 // Public methods
7315 * @method initDefaultConfig
7316 * @description Initializes an item's configurable properties.
7318 initDefaultConfig : function () {
7320 var oConfig = this.cfg;
7323 // Define the configuration attributes
7326 * @config text
7327 * @description String specifying the text label for the menu item.
7328 * When building a menu from existing HTML the value of this property
7329 * will be interpreted from the menu's markup.
7330 * @default ""
7331 * @type String
7333 oConfig.addProperty(
7334 DEFAULT_CONFIG.TEXT.key,
7336 handler: this.configText,
7337 value: DEFAULT_CONFIG.TEXT.value,
7338 validator: DEFAULT_CONFIG.TEXT.validator,
7339 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
7345 * @config helptext
7346 * @description String specifying additional instructional text to
7347 * accompany the text for the menu item.
7348 * @deprecated Use "text" configuration property to add help text markup.
7349 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em
7350 * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
7351 * @default null
7352 * @type String|<a href="http://www.w3.org/TR/
7353 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7354 * HTMLElement</a>
7356 oConfig.addProperty(
7357 DEFAULT_CONFIG.HELP_TEXT.key,
7359 handler: this.configHelpText,
7360 supercedes: DEFAULT_CONFIG.HELP_TEXT.supercedes,
7361 suppressEvent: DEFAULT_CONFIG.HELP_TEXT.suppressEvent
7367 * @config url
7368 * @description String specifying the URL for the menu item's anchor's
7369 * "href" attribute. When building a menu from existing HTML the value
7370 * of this property will be interpreted from the menu's markup.
7371 * @default "#"
7372 * @type String
7374 oConfig.addProperty(
7375 DEFAULT_CONFIG.URL.key,
7377 handler: this.configURL,
7378 value: DEFAULT_CONFIG.URL.value,
7379 suppressEvent: DEFAULT_CONFIG.URL.suppressEvent
7385 * @config target
7386 * @description String specifying the value for the "target" attribute
7387 * of the menu item's anchor element. <strong>Specifying a target will
7388 * require the user to click directly on the menu item's anchor node in
7389 * order to cause the browser to navigate to the specified URL.</strong>
7390 * When building a menu from existing HTML the value of this property
7391 * will be interpreted from the menu's markup.
7392 * @default null
7393 * @type String
7395 oConfig.addProperty(
7396 DEFAULT_CONFIG.TARGET.key,
7398 handler: this.configTarget,
7399 suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent
7405 * @config emphasis
7406 * @description Boolean indicating if the text of the menu item will be
7407 * rendered with emphasis.
7408 * @deprecated Use "text" configuration property to add emphasis.
7409 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some
7410 * Text&#60;/em&#62;");</code>
7411 * @default false
7412 * @type Boolean
7414 oConfig.addProperty(
7415 DEFAULT_CONFIG.EMPHASIS.key,
7417 handler: this.configEmphasis,
7418 value: DEFAULT_CONFIG.EMPHASIS.value,
7419 validator: DEFAULT_CONFIG.EMPHASIS.validator,
7420 suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent,
7421 supercedes: DEFAULT_CONFIG.EMPHASIS.supercedes
7427 * @config strongemphasis
7428 * @description Boolean indicating if the text of the menu item will be
7429 * rendered with strong emphasis.
7430 * @deprecated Use "text" configuration property to add strong emphasis.
7431 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62;
7432 * Some Text&#60;/strong&#62;");</code>
7433 * @default false
7434 * @type Boolean
7436 oConfig.addProperty(
7437 DEFAULT_CONFIG.STRONG_EMPHASIS.key,
7439 handler: this.configStrongEmphasis,
7440 value: DEFAULT_CONFIG.STRONG_EMPHASIS.value,
7441 validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator,
7442 suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent,
7443 supercedes: DEFAULT_CONFIG.STRONG_EMPHASIS.supercedes
7449 * @config checked
7450 * @description Boolean indicating if the menu item should be rendered
7451 * with a checkmark.
7452 * @default false
7453 * @type Boolean
7455 oConfig.addProperty(
7456 DEFAULT_CONFIG.CHECKED.key,
7458 handler: this.configChecked,
7459 value: DEFAULT_CONFIG.CHECKED.value,
7460 validator: DEFAULT_CONFIG.CHECKED.validator,
7461 suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent,
7462 supercedes: DEFAULT_CONFIG.CHECKED.supercedes
7468 * @config disabled
7469 * @description Boolean indicating if the menu item should be disabled.
7470 * (Disabled menu items are dimmed and will not respond to user input
7471 * or fire events.)
7472 * @default false
7473 * @type Boolean
7475 oConfig.addProperty(
7476 DEFAULT_CONFIG.DISABLED.key,
7478 handler: this.configDisabled,
7479 value: DEFAULT_CONFIG.DISABLED.value,
7480 validator: DEFAULT_CONFIG.DISABLED.validator,
7481 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
7487 * @config selected
7488 * @description Boolean indicating if the menu item should
7489 * be highlighted.
7490 * @default false
7491 * @type Boolean
7493 oConfig.addProperty(
7494 DEFAULT_CONFIG.SELECTED.key,
7496 handler: this.configSelected,
7497 value: DEFAULT_CONFIG.SELECTED.value,
7498 validator: DEFAULT_CONFIG.SELECTED.validator,
7499 suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent
7505 * @config submenu
7506 * @description Object specifying the submenu to be appended to the
7507 * menu item. The value can be one of the following: <ul><li>Object
7508 * specifying a Menu instance.</li><li>Object literal specifying the
7509 * menu to be created. Format: <code>{ id: [menu id], itemdata:
7510 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
7511 * items</a>] }</code>.</li><li>String specifying the id attribute
7512 * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
7513 * Object specifying the <code>&#60;div&#62;</code> element of the
7514 * menu.</li></ul>
7515 * @default null
7516 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
7517 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7518 * HTMLElement</a>
7520 oConfig.addProperty(
7521 DEFAULT_CONFIG.SUBMENU.key,
7523 handler: this.configSubmenu,
7524 supercedes: DEFAULT_CONFIG.SUBMENU.supercedes,
7525 suppressEvent: DEFAULT_CONFIG.SUBMENU.suppressEvent
7531 * @config onclick
7532 * @description Object literal representing the code to be executed when
7533 * the item is clicked. Format:<br> <code> {<br>
7534 * <strong>fn:</strong> Function, &#47;&#47; The handler to call when
7535 * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An
7536 * object to pass back to the handler.<br> <strong>scope:</strong>
7537 * Object &#47;&#47; The object to use for the scope of the handler.
7538 * <br> } </code>
7539 * @type Object
7540 * @default null
7542 oConfig.addProperty(
7543 DEFAULT_CONFIG.ONCLICK.key,
7545 handler: this.configOnClick,
7546 suppressEvent: DEFAULT_CONFIG.ONCLICK.suppressEvent
7552 * @config classname
7553 * @description CSS class to be applied to the menu item's root
7554 * <code>&#60;li&#62;</code> element. The specified class(es) are
7555 * appended in addition to the default class as specified by the menu
7556 * item's CSS_CLASS_NAME constant.
7557 * @default null
7558 * @type String
7560 oConfig.addProperty(
7561 DEFAULT_CONFIG.CLASS_NAME.key,
7563 handler: this.configClassName,
7564 value: DEFAULT_CONFIG.CLASS_NAME.value,
7565 validator: DEFAULT_CONFIG.CLASS_NAME.validator,
7566 suppressEvent: DEFAULT_CONFIG.CLASS_NAME.suppressEvent
7574 * @method getNextEnabledSibling
7575 * @description Finds the menu item's next enabled sibling.
7576 * @return YAHOO.widget.MenuItem
7578 getNextEnabledSibling: function () {
7580 var nGroupIndex,
7581 aItemGroups,
7582 oNextItem,
7583 nNextGroupIndex,
7584 aNextGroup;
7586 function getNextArrayItem(p_aArray, p_nStartIndex) {
7588 return p_aArray[p_nStartIndex] ||
7589 getNextArrayItem(p_aArray, (p_nStartIndex+1));
7593 if (this.parent instanceof Menu) {
7595 nGroupIndex = this.groupIndex;
7597 aItemGroups = this.parent.getItemGroups();
7599 if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
7601 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
7602 (this.index+1));
7605 else {
7607 if (nGroupIndex < (aItemGroups.length - 1)) {
7609 nNextGroupIndex = nGroupIndex + 1;
7612 else {
7614 nNextGroupIndex = 0;
7618 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
7620 // Retrieve the first menu item in the next group
7622 oNextItem = getNextArrayItem(aNextGroup, 0);
7626 return (oNextItem.cfg.getProperty("disabled") ||
7627 oNextItem.element.style.display == "none") ?
7628 oNextItem.getNextEnabledSibling() : oNextItem;
7636 * @method getPreviousEnabledSibling
7637 * @description Finds the menu item's previous enabled sibling.
7638 * @return {YAHOO.widget.MenuItem}
7640 getPreviousEnabledSibling: function () {
7642 var nGroupIndex,
7643 aItemGroups,
7644 oPreviousItem,
7645 nPreviousGroupIndex,
7646 aPreviousGroup;
7648 function getPreviousArrayItem(p_aArray, p_nStartIndex) {
7650 return p_aArray[p_nStartIndex] ||
7651 getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
7655 function getFirstItemIndex(p_aArray, p_nStartIndex) {
7657 return p_aArray[p_nStartIndex] ? p_nStartIndex :
7658 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
7662 if (this.parent instanceof Menu) {
7664 nGroupIndex = this.groupIndex;
7665 aItemGroups = this.parent.getItemGroups();
7668 if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
7670 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
7671 (this.index-1));
7674 else {
7676 if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
7678 nPreviousGroupIndex = nGroupIndex - 1;
7681 else {
7683 nPreviousGroupIndex = aItemGroups.length - 1;
7687 aPreviousGroup = getPreviousArrayItem(aItemGroups,
7688 nPreviousGroupIndex);
7690 oPreviousItem = getPreviousArrayItem(aPreviousGroup,
7691 (aPreviousGroup.length - 1));
7695 return (oPreviousItem.cfg.getProperty("disabled") ||
7696 oPreviousItem.element.style.display == "none") ?
7697 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
7705 * @method focus
7706 * @description Causes the menu item to receive the focus and fires the
7707 * focus event.
7709 focus: function () {
7711 var oParent = this.parent,
7712 oAnchor = this._oAnchor,
7713 oActiveItem = oParent.activeItem,
7714 me = this;
7717 function setFocus() {
7719 try {
7721 if (YAHOO.env.ua.ie && !document.hasFocus()) {
7723 return;
7727 if (oActiveItem) {
7729 oActiveItem.blurEvent.fire();
7733 oAnchor.focus();
7735 me.focusEvent.fire();
7738 catch(e) {
7745 if (!this.cfg.getProperty("disabled") && oParent &&
7746 oParent.cfg.getProperty("visible") &&
7747 this.element.style.display != "none") {
7751 Setting focus via a timer fixes a race condition in Firefox, IE
7752 and Opera where the browser viewport jumps as it trys to
7753 position and focus the menu.
7756 window.setTimeout(setFocus, 0);
7764 * @method blur
7765 * @description Causes the menu item to lose focus and fires the
7766 * blur event.
7768 blur: function () {
7770 var oParent = this.parent;
7772 if (!this.cfg.getProperty("disabled") && oParent &&
7773 oParent.cfg.getProperty("visible")) {
7776 var me = this;
7778 window.setTimeout(function () {
7780 try {
7782 me._oAnchor.blur();
7783 me.blurEvent.fire();
7786 catch (e) {
7790 }, 0);
7798 * @method hasFocus
7799 * @description Returns a boolean indicating whether or not the menu item
7800 * has focus.
7801 * @return {Boolean}
7803 hasFocus: function () {
7805 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
7811 * @method destroy
7812 * @description Removes the menu item's <code>&#60;li&#62;</code> element
7813 * from its parent <code>&#60;ul&#62;</code> element.
7815 destroy: function () {
7817 var oEl = this.element,
7818 oSubmenu,
7819 oParentNode;
7821 if (oEl) {
7824 // If the item has a submenu, destroy it first
7826 oSubmenu = this.cfg.getProperty("submenu");
7828 if (oSubmenu) {
7830 oSubmenu.destroy();
7835 // Remove CustomEvent listeners
7837 this.mouseOverEvent.unsubscribeAll();
7838 this.mouseOutEvent.unsubscribeAll();
7839 this.mouseDownEvent.unsubscribeAll();
7840 this.mouseUpEvent.unsubscribeAll();
7841 this.clickEvent.unsubscribeAll();
7842 this.keyPressEvent.unsubscribeAll();
7843 this.keyDownEvent.unsubscribeAll();
7844 this.keyUpEvent.unsubscribeAll();
7845 this.focusEvent.unsubscribeAll();
7846 this.blurEvent.unsubscribeAll();
7847 this.cfg.configChangedEvent.unsubscribeAll();
7850 // Remove the element from the parent node
7852 oParentNode = oEl.parentNode;
7854 if (oParentNode) {
7856 oParentNode.removeChild(oEl);
7858 this.destroyEvent.fire();
7862 this.destroyEvent.unsubscribeAll();
7870 * @method toString
7871 * @description Returns a string representing the menu item.
7872 * @return {String}
7874 toString: function () {
7876 var sReturnVal = "MenuItem",
7877 sId = this.id;
7879 if (sId) {
7881 sReturnVal += (" " + sId);
7885 return sReturnVal;
7891 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
7893 })();
7894 (function () {
7898 * Creates a list of options or commands which are made visible in response to
7899 * an HTML element's "contextmenu" event ("mousedown" for Opera).
7901 * @param {String} p_oElement String specifying the id attribute of the
7902 * <code>&#60;div&#62;</code> element of the context menu.
7903 * @param {String} p_oElement String specifying the id attribute of the
7904 * <code>&#60;select&#62;</code> element to be used as the data source for the
7905 * context menu.
7906 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7907 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7908 * <code>&#60;div&#62;</code> element of the context menu.
7909 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7910 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7911 * the <code>&#60;select&#62;</code> element to be used as the data source for
7912 * the context menu.
7913 * @param {Object} p_oConfig Optional. Object literal specifying the
7914 * configuration for the context menu. See configuration class documentation
7915 * for more details.
7916 * @class ContextMenu
7917 * @constructor
7918 * @extends YAHOO.widget.Menu
7919 * @namespace YAHOO.widget
7921 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
7923 YAHOO.widget.ContextMenu.superclass.constructor.call(this,
7924 p_oElement, p_oConfig);
7929 var Event = YAHOO.util.Event,
7930 ContextMenu = YAHOO.widget.ContextMenu,
7935 * Constant representing the name of the ContextMenu's events
7936 * @property EVENT_TYPES
7937 * @private
7938 * @final
7939 * @type Object
7941 EVENT_TYPES = {
7943 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
7944 "CONTEXT_MENU": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"),
7945 "CLICK": "click"
7951 * Constant representing the ContextMenu's configuration properties
7952 * @property DEFAULT_CONFIG
7953 * @private
7954 * @final
7955 * @type Object
7957 DEFAULT_CONFIG = {
7959 "TRIGGER": {
7960 key: "trigger",
7961 suppressEvent: true
7968 * @method position
7969 * @description "beforeShow" event handler used to position the contextmenu.
7970 * @private
7971 * @param {String} p_sType String representing the name of the event that
7972 * was fired.
7973 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7974 * @param {Array} p_aPos Array representing the xy position for the context menu.
7976 function position(p_sType, p_aArgs, p_aPos) {
7978 this.cfg.setProperty("xy", p_aPos);
7980 this.beforeShowEvent.unsubscribe(position, p_aPos);
7985 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
7989 // Private properties
7993 * @property _oTrigger
7994 * @description Object reference to the current value of the "trigger"
7995 * configuration property.
7996 * @default null
7997 * @private
7998 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
7999 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8001 _oTrigger: null,
8005 * @property _bCancelled
8006 * @description Boolean indicating if the display of the context menu should
8007 * be cancelled.
8008 * @default false
8009 * @private
8010 * @type Boolean
8012 _bCancelled: false,
8016 // Public properties
8020 * @property contextEventTarget
8021 * @description Object reference for the HTML element that was the target of the
8022 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8023 * the context menu.
8024 * @default null
8025 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8026 * html.html#ID-58190037">HTMLElement</a>
8028 contextEventTarget: null,
8032 // Events
8036 * @event triggerContextMenuEvent
8037 * @description Custom Event wrapper for the "contextmenu" DOM event
8038 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8039 * the context menu.
8041 triggerContextMenuEvent: null,
8046 * @method init
8047 * @description The ContextMenu class's initialization method. This method is
8048 * automatically called by the constructor, and sets up all DOM references for
8049 * pre-existing markup, and creates required markup if it is not already present.
8050 * @param {String} p_oElement String specifying the id attribute of the
8051 * <code>&#60;div&#62;</code> element of the context menu.
8052 * @param {String} p_oElement String specifying the id attribute of the
8053 * <code>&#60;select&#62;</code> element to be used as the data source for
8054 * the context menu.
8055 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8056 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8057 * <code>&#60;div&#62;</code> element of the context menu.
8058 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8059 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8060 * the <code>&#60;select&#62;</code> element to be used as the data source for
8061 * the context menu.
8062 * @param {Object} p_oConfig Optional. Object literal specifying the
8063 * configuration for the context menu. See configuration class documentation
8064 * for more details.
8066 init: function(p_oElement, p_oConfig) {
8069 // Call the init of the superclass (YAHOO.widget.Menu)
8071 ContextMenu.superclass.init.call(this, p_oElement);
8074 this.beforeInitEvent.fire(ContextMenu);
8077 if(p_oConfig) {
8079 this.cfg.applyConfig(p_oConfig, true);
8084 this.initEvent.fire(ContextMenu);
8090 * @method initEvents
8091 * @description Initializes the custom events for the context menu.
8093 initEvents: function() {
8095 ContextMenu.superclass.initEvents.call(this);
8097 // Create custom events
8099 this.triggerContextMenuEvent =
8100 this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8102 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8108 * @method cancel
8109 * @description Cancels the display of the context menu.
8111 cancel: function() {
8113 this._bCancelled = true;
8119 // Private methods
8123 * @method _removeEventHandlers
8124 * @description Removes all of the DOM event handlers from the HTML element(s)
8125 * whose "context menu" event ("click" for Opera) trigger the display of
8126 * the context menu.
8127 * @private
8129 _removeEventHandlers: function() {
8131 var oTrigger = this._oTrigger;
8134 // Remove the event handlers from the trigger(s)
8136 if (oTrigger) {
8138 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8139 this._onTriggerContextMenu);
8141 if(YAHOO.env.ua.opera) {
8143 Event.removeListener(oTrigger, EVENT_TYPES.CLICK,
8144 this._onTriggerClick);
8154 // Private event handlers
8159 * @method _onTriggerClick
8160 * @description "click" event handler for the HTML element(s) identified as the
8161 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8162 * @private
8163 * @param {Event} p_oEvent Object representing the DOM event object passed back
8164 * by the event utility (YAHOO.util.Event).
8165 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8166 * menu that is handling the event.
8168 _onTriggerClick: function(p_oEvent, p_oMenu) {
8170 if(p_oEvent.ctrlKey) {
8172 Event.stopEvent(p_oEvent);
8180 * @method _onTriggerContextMenu
8181 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8182 * element(s) that trigger the display of the context menu.
8183 * @private
8184 * @param {Event} p_oEvent Object representing the DOM event object passed back
8185 * by the event utility (YAHOO.util.Event).
8186 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8187 * menu that is handling the event.
8189 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8191 if (p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {
8193 return;
8198 var aXY;
8202 Prevent the browser's default context menu from appearing and
8203 stop the propagation of the "contextmenu" event so that
8204 other ContextMenu instances are not displayed.
8207 Event.stopEvent(p_oEvent);
8210 this.contextEventTarget = Event.getTarget(p_oEvent);
8212 this.triggerContextMenuEvent.fire(p_oEvent);
8215 // Hide any other Menu instances that might be visible
8217 YAHOO.widget.MenuManager.hideVisible();
8221 if(!this._bCancelled) {
8223 // Position and display the context menu
8225 aXY = Event.getXY(p_oEvent);
8228 if (!YAHOO.util.Dom.inDocument(this.element)) {
8230 this.beforeShowEvent.subscribe(position, aXY);
8233 else {
8235 this.cfg.setProperty("xy", aXY);
8240 this.show();
8244 this._bCancelled = false;
8250 // Public methods
8254 * @method toString
8255 * @description Returns a string representing the context menu.
8256 * @return {String}
8258 toString: function() {
8260 var sReturnVal = "ContextMenu",
8261 sId = this.id;
8263 if(sId) {
8265 sReturnVal += (" " + sId);
8269 return sReturnVal;
8275 * @method initDefaultConfig
8276 * @description Initializes the class's configurable properties which can be
8277 * changed using the context menu's Config object ("cfg").
8279 initDefaultConfig: function() {
8281 ContextMenu.superclass.initDefaultConfig.call(this);
8284 * @config trigger
8285 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
8286 * for Opera) trigger the display of the context menu. Can be a string
8287 * representing the id attribute of the HTML element, an object reference
8288 * for the HTML element, or an array of strings or HTML element references.
8289 * @default null
8290 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8291 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8293 this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key,
8295 handler: this.configTrigger,
8296 suppressEvent: DEFAULT_CONFIG.TRIGGER.suppressEvent
8304 * @method destroy
8305 * @description Removes the context menu's <code>&#60;div&#62;</code> element
8306 * (and accompanying child nodes) from the document.
8308 destroy: function() {
8310 // Remove the DOM event handlers from the current trigger(s)
8312 this._removeEventHandlers();
8315 // Continue with the superclass implementation of this method
8317 ContextMenu.superclass.destroy.call(this);
8323 // Public event handlers for configuration properties
8327 * @method configTrigger
8328 * @description Event handler for when the value of the "trigger" configuration
8329 * property changes.
8330 * @param {String} p_sType String representing the name of the event that
8331 * was fired.
8332 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8333 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8334 * menu that fired the event.
8336 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8338 var oTrigger = p_aArgs[0];
8340 if(oTrigger) {
8343 If there is a current "trigger" - remove the event handlers
8344 from that element(s) before assigning new ones
8347 if(this._oTrigger) {
8349 this._removeEventHandlers();
8353 this._oTrigger = oTrigger;
8357 Listen for the "mousedown" event in Opera b/c it does not
8358 support the "contextmenu" event
8361 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8362 this._onTriggerContextMenu, this, true);
8366 Assign a "click" event handler to the trigger element(s) for
8367 Opera to prevent default browser behaviors.
8370 if(YAHOO.env.ua.opera) {
8372 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick,
8373 this, true);
8378 else {
8380 this._removeEventHandlers();
8386 }); // END YAHOO.lang.extend
8388 }());
8393 * Creates an item for a context menu.
8395 * @param {String} p_oObject String specifying the text of the context menu item.
8396 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8397 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8398 * <code>&#60;li&#62;</code> element of the context menu item.
8399 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8400 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8401 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8402 * menu item.
8403 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8404 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8405 * the <code>&#60;option&#62;</code> element of the context menu item.
8406 * @param {Object} p_oConfig Optional. Object literal specifying the
8407 * configuration for the context menu item. See configuration class
8408 * documentation for more details.
8409 * @class ContextMenuItem
8410 * @constructor
8411 * @extends YAHOO.widget.MenuItem
8412 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
8413 * are of type YAHOO.widget.MenuItem.
8415 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
8416 (function () {
8420 * Horizontal collection of items, each of which can contain a submenu.
8422 * @param {String} p_oElement String specifying the id attribute of the
8423 * <code>&#60;div&#62;</code> element of the menu bar.
8424 * @param {String} p_oElement String specifying the id attribute of the
8425 * <code>&#60;select&#62;</code> element to be used as the data source for the
8426 * menu bar.
8427 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8428 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8429 * the <code>&#60;div&#62;</code> element of the menu bar.
8430 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8431 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8432 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8433 * source for the menu bar.
8434 * @param {Object} p_oConfig Optional. Object literal specifying the
8435 * configuration for the menu bar. See configuration class documentation for
8436 * more details.
8437 * @class MenuBar
8438 * @constructor
8439 * @extends YAHOO.widget.Menu
8440 * @namespace YAHOO.widget
8442 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
8444 YAHOO.widget.MenuBar.superclass.constructor.call(this,
8445 p_oElement, p_oConfig);
8451 * @method checkPosition
8452 * @description Checks to make sure that the value of the "position" property
8453 * is one of the supported strings. Returns true if the position is supported.
8454 * @private
8455 * @param {Object} p_sPosition String specifying the position of the menu.
8456 * @return {Boolean}
8458 function checkPosition(p_sPosition) {
8460 if (typeof p_sPosition == "string") {
8462 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
8469 var Event = YAHOO.util.Event,
8470 MenuBar = YAHOO.widget.MenuBar,
8473 * Constant representing the MenuBar's configuration properties
8474 * @property DEFAULT_CONFIG
8475 * @private
8476 * @final
8477 * @type Object
8479 DEFAULT_CONFIG = {
8481 "POSITION": {
8482 key: "position",
8483 value: "static",
8484 validator: checkPosition,
8485 supercedes: ["visible"]
8488 "SUBMENU_ALIGNMENT": {
8489 key: "submenualignment",
8490 value: ["tl","bl"],
8491 suppressEvent: true
8494 "AUTO_SUBMENU_DISPLAY": {
8495 key: "autosubmenudisplay",
8496 value: false,
8497 validator: YAHOO.lang.isBoolean,
8498 suppressEvent: true
8505 YAHOO.lang.extend(MenuBar, YAHOO.widget.Menu, {
8508 * @method init
8509 * @description The MenuBar class's initialization method. This method is
8510 * automatically called by the constructor, and sets up all DOM references for
8511 * pre-existing markup, and creates required markup if it is not already present.
8512 * @param {String} p_oElement String specifying the id attribute of the
8513 * <code>&#60;div&#62;</code> element of the menu bar.
8514 * @param {String} p_oElement String specifying the id attribute of the
8515 * <code>&#60;select&#62;</code> element to be used as the data source for the
8516 * menu bar.
8517 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8518 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8519 * the <code>&#60;div&#62;</code> element of the menu bar.
8520 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8521 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8522 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8523 * source for the menu bar.
8524 * @param {Object} p_oConfig Optional. Object literal specifying the
8525 * configuration for the menu bar. See configuration class documentation for
8526 * more details.
8528 init: function(p_oElement, p_oConfig) {
8530 if(!this.ITEM_TYPE) {
8532 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
8537 // Call the init of the superclass (YAHOO.widget.Menu)
8539 MenuBar.superclass.init.call(this, p_oElement);
8542 this.beforeInitEvent.fire(MenuBar);
8545 if(p_oConfig) {
8547 this.cfg.applyConfig(p_oConfig, true);
8551 this.initEvent.fire(MenuBar);
8557 // Constants
8561 * @property CSS_CLASS_NAME
8562 * @description String representing the CSS class(es) to be applied to the menu
8563 * bar's <code>&#60;div&#62;</code> element.
8564 * @default "yuimenubar"
8565 * @final
8566 * @type String
8568 CSS_CLASS_NAME: "yuimenubar",
8572 // Protected event handlers
8576 * @method _onKeyDown
8577 * @description "keydown" Custom Event handler for the menu bar.
8578 * @private
8579 * @param {String} p_sType String representing the name of the event that
8580 * was fired.
8581 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8582 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8583 * that fired the event.
8585 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
8587 var oEvent = p_aArgs[0],
8588 oItem = p_aArgs[1],
8589 oSubmenu,
8590 oItemCfg,
8591 oNextItem;
8594 if(oItem && !oItem.cfg.getProperty("disabled")) {
8596 oItemCfg = oItem.cfg;
8598 switch(oEvent.keyCode) {
8600 case 37: // Left arrow
8601 case 39: // Right arrow
8603 if(oItem == this.activeItem &&
8604 !oItemCfg.getProperty("selected")) {
8606 oItemCfg.setProperty("selected", true);
8609 else {
8611 oNextItem = (oEvent.keyCode == 37) ?
8612 oItem.getPreviousEnabledSibling() :
8613 oItem.getNextEnabledSibling();
8615 if(oNextItem) {
8617 this.clearActiveItem();
8619 oNextItem.cfg.setProperty("selected", true);
8622 if(this.cfg.getProperty("autosubmenudisplay")) {
8624 oSubmenu = oNextItem.cfg.getProperty("submenu");
8626 if(oSubmenu) {
8628 oSubmenu.show();
8634 oNextItem.focus();
8640 Event.preventDefault(oEvent);
8642 break;
8644 case 40: // Down arrow
8646 if(this.activeItem != oItem) {
8648 this.clearActiveItem();
8650 oItemCfg.setProperty("selected", true);
8651 oItem.focus();
8655 oSubmenu = oItemCfg.getProperty("submenu");
8657 if(oSubmenu) {
8659 if(oSubmenu.cfg.getProperty("visible")) {
8661 oSubmenu.setInitialSelection();
8662 oSubmenu.setInitialFocus();
8665 else {
8667 oSubmenu.show();
8673 Event.preventDefault(oEvent);
8675 break;
8682 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
8684 oSubmenu = this.activeItem.cfg.getProperty("submenu");
8686 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
8688 oSubmenu.hide();
8689 this.activeItem.focus();
8692 else {
8694 this.activeItem.cfg.setProperty("selected", false);
8695 this.activeItem.blur();
8699 Event.preventDefault(oEvent);
8707 * @method _onClick
8708 * @description "click" event handler for the menu bar.
8709 * @protected
8710 * @param {String} p_sType String representing the name of the event that
8711 * was fired.
8712 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8713 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8714 * that fired the event.
8716 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
8718 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
8720 var oItem = p_aArgs[1],
8721 oEvent,
8722 oTarget,
8723 oActiveItem,
8724 oConfig,
8725 oSubmenu;
8728 if(oItem && !oItem.cfg.getProperty("disabled")) {
8730 oEvent = p_aArgs[0];
8731 oTarget = Event.getTarget(oEvent);
8732 oActiveItem = this.activeItem;
8733 oConfig = this.cfg;
8736 // Hide any other submenus that might be visible
8738 if(oActiveItem && oActiveItem != oItem) {
8740 this.clearActiveItem();
8745 oItem.cfg.setProperty("selected", true);
8748 // Show the submenu for the item
8750 oSubmenu = oItem.cfg.getProperty("submenu");
8753 if(oSubmenu) {
8755 if(oSubmenu.cfg.getProperty("visible")) {
8757 oSubmenu.hide();
8760 else {
8762 oSubmenu.show();
8774 // Public methods
8778 * @method toString
8779 * @description Returns a string representing the menu bar.
8780 * @return {String}
8782 toString: function() {
8784 var sReturnVal = "MenuBar",
8785 sId = this.id;
8787 if(sId) {
8789 sReturnVal += (" " + sId);
8793 return sReturnVal;
8799 * @description Initializes the class's configurable properties which can be
8800 * changed using the menu bar's Config object ("cfg").
8801 * @method initDefaultConfig
8803 initDefaultConfig: function() {
8805 MenuBar.superclass.initDefaultConfig.call(this);
8807 var oConfig = this.cfg;
8809 // Add configuration properties
8813 Set the default value for the "position" configuration property
8814 to "static" by re-adding the property.
8819 * @config position
8820 * @description String indicating how a menu bar should be positioned on the
8821 * screen. Possible values are "static" and "dynamic." Static menu bars
8822 * are visible by default and reside in the normal flow of the document
8823 * (CSS position: static). Dynamic menu bars are hidden by default, reside
8824 * out of the normal flow of the document (CSS position: absolute), and can
8825 * overlay other elements on the screen.
8826 * @default static
8827 * @type String
8829 oConfig.addProperty(
8830 DEFAULT_CONFIG.POSITION.key,
8832 handler: this.configPosition,
8833 value: DEFAULT_CONFIG.POSITION.value,
8834 validator: DEFAULT_CONFIG.POSITION.validator,
8835 supercedes: DEFAULT_CONFIG.POSITION.supercedes
8841 Set the default value for the "submenualignment" configuration property
8842 to ["tl","bl"] by re-adding the property.
8846 * @config submenualignment
8847 * @description Array defining how submenus should be aligned to their
8848 * parent menu bar item. The format is: [itemCorner, submenuCorner].
8849 * @default ["tl","bl"]
8850 * @type Array
8852 oConfig.addProperty(
8853 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
8855 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
8856 suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
8862 Change the default value for the "autosubmenudisplay" configuration
8863 property to "false" by re-adding the property.
8867 * @config autosubmenudisplay
8868 * @description Boolean indicating if submenus are automatically made
8869 * visible when the user mouses over the menu bar's items.
8870 * @default false
8871 * @type Boolean
8873 oConfig.addProperty(
8874 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
8876 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
8877 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
8878 suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
8884 }); // END YAHOO.lang.extend
8886 }());
8891 * Creates an item for a menu bar.
8893 * @param {String} p_oObject String specifying the text of the menu bar item.
8894 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8895 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8896 * <code>&#60;li&#62;</code> element of the menu bar item.
8897 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8898 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8899 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8900 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8901 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8902 * the <code>&#60;option&#62;</code> element of the menu bar item.
8903 * @param {Object} p_oConfig Optional. Object literal specifying the
8904 * configuration for the menu bar item. See configuration class documentation
8905 * for more details.
8906 * @class MenuBarItem
8907 * @constructor
8908 * @extends YAHOO.widget.MenuItem
8910 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
8912 YAHOO.widget.MenuBarItem.superclass.constructor.call(this,
8913 p_oObject, p_oConfig);
8917 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
8922 * @method init
8923 * @description The MenuBarItem class's initialization method. This method is
8924 * automatically called by the constructor, and sets up all DOM references for
8925 * pre-existing markup, and creates required markup if it is not already present.
8926 * @param {String} p_oObject String specifying the text of the menu bar item.
8927 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8928 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8929 * <code>&#60;li&#62;</code> element of the menu bar item.
8930 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8931 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8932 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8933 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8934 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8935 * the <code>&#60;option&#62;</code> element of the menu bar item.
8936 * @param {Object} p_oConfig Optional. Object literal specifying the
8937 * configuration for the menu bar item. See configuration class documentation
8938 * for more details.
8940 init: function(p_oObject, p_oConfig) {
8942 if(!this.SUBMENU_TYPE) {
8944 this.SUBMENU_TYPE = YAHOO.widget.Menu;
8950 Call the init of the superclass (YAHOO.widget.MenuItem)
8951 Note: We don't pass the user config in here yet
8952 because we only want it executed once, at the lowest
8953 subclass level.
8956 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
8959 var oConfig = this.cfg;
8961 if(p_oConfig) {
8963 oConfig.applyConfig(p_oConfig, true);
8967 oConfig.fireQueue();
8973 // Constants
8977 * @property CSS_CLASS_NAME
8978 * @description String representing the CSS class(es) to be applied to the
8979 * <code>&#60;li&#62;</code> element of the menu bar item.
8980 * @default "yuimenubaritem"
8981 * @final
8982 * @type String
8984 CSS_CLASS_NAME: "yuimenubaritem",
8988 * @property CSS_LABEL_CLASS_NAME
8989 * @description String representing the CSS class(es) to be applied to the
8990 * menu bar item's <code>&#60;a&#62;</code> element.
8991 * @default "yuimenubaritemlabel"
8992 * @final
8993 * @type String
8995 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
8999 // Public methods
9003 * @method toString
9004 * @description Returns a string representing the menu bar item.
9005 * @return {String}
9007 toString: function() {
9009 var sReturnVal = "MenuBarItem";
9011 if(this.cfg && this.cfg.getProperty("text")) {
9013 sReturnVal += (": " + this.cfg.getProperty("text"));
9017 return sReturnVal;
9021 }); // END YAHOO.lang.extend
9022 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.5.2", build: "1076"});