Merge commit 'catalyst/MOODLE_19_STABLE' into mdl19-linuxchix
[moodle-linuxchix.git] / lib / yui / menu / menu-debug.js
blob5a57fa14912068c0e8a6b3b8ca0374f1aa591b4c
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;
86 var m_oLogger = new YAHOO.widget.LogWriter("MenuManager");
90 // Private methods
93 /**
94 * @method getMenuRootElement
95 * @description Finds the root DIV node of a menu or the root LI node of
96 * a menu item.
97 * @private
98 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
99 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
100 * specifying an HTML element.
102 function getMenuRootElement(p_oElement) {
104 var oParentNode;
106 if (p_oElement && p_oElement.tagName) {
108 switch (p_oElement.tagName.toUpperCase()) {
110 case "DIV":
112 oParentNode = p_oElement.parentNode;
114 // Check if the DIV is the inner "body" node of a menu
116 if (
118 Dom.hasClass(p_oElement, "hd") ||
119 Dom.hasClass(p_oElement, "bd") ||
120 Dom.hasClass(p_oElement, "ft")
121 ) &&
122 oParentNode &&
123 oParentNode.tagName &&
124 oParentNode.tagName.toUpperCase() == "DIV")
127 return oParentNode;
130 else {
132 return p_oElement;
136 break;
138 case "LI":
140 return p_oElement;
142 default:
144 oParentNode = p_oElement.parentNode;
146 if (oParentNode) {
148 return getMenuRootElement(oParentNode);
152 break;
162 // Private event handlers
166 * @method onDOMEvent
167 * @description Generic, global event handler for all of a menu's
168 * DOM-based events. This listens for events against the document
169 * object. If the target of a given event is a member of a menu or
170 * menu item's DOM, the instance's corresponding Custom Event is fired.
171 * @private
172 * @param {Event} p_oEvent Object representing the DOM event object
173 * passed back by the event utility (YAHOO.util.Event).
175 function onDOMEvent(p_oEvent) {
177 // Get the target node of the DOM event
179 var oTarget = Event.getTarget(p_oEvent),
181 // See if the target of the event was a menu, or a menu item
183 oElement = getMenuRootElement(oTarget),
184 sCustomEventType,
185 sTagName,
186 sId,
187 oMenuItem,
188 oMenu;
191 if (oElement) {
193 sTagName = oElement.tagName.toUpperCase();
195 if (sTagName == "LI") {
197 sId = oElement.id;
199 if (sId && m_oItems[sId]) {
201 oMenuItem = m_oItems[sId];
202 oMenu = oMenuItem.parent;
207 else if (sTagName == "DIV") {
209 if (oElement.id) {
211 oMenu = m_oMenus[oElement.id];
220 if (oMenu) {
222 sCustomEventType = m_oEventTypes[p_oEvent.type];
225 // Fire the Custom Event that corresponds the current DOM event
227 if (oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
229 oMenuItem[sCustomEventType].fire(p_oEvent);
232 if (
233 p_oEvent.type == "keyup" ||
234 p_oEvent.type == "mousedown")
237 if (m_oFocusedMenuItem != oMenuItem) {
239 if (m_oFocusedMenuItem) {
241 m_oFocusedMenuItem.blurEvent.fire();
245 oMenuItem.focusEvent.fire();
253 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
256 else if (p_oEvent.type == "mousedown") {
258 if (m_oFocusedMenuItem) {
260 m_oFocusedMenuItem.blurEvent.fire();
262 m_oFocusedMenuItem = null;
268 If the target of the event wasn't a menu, hide all
269 dynamically positioned menus
272 for (var i in m_oVisibleMenus) {
274 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
276 oMenu = m_oVisibleMenus[i];
278 if (oMenu.cfg.getProperty("clicktohide") &&
279 !(oMenu instanceof YAHOO.widget.MenuBar) &&
280 oMenu.cfg.getProperty("position") == "dynamic") {
282 oMenu.hide();
285 else {
287 if (oMenu.cfg.getProperty("showdelay") > 0) {
289 oMenu._cancelShowDelay();
294 if (oMenu.activeItem) {
296 oMenu.activeItem.blur();
297 oMenu.activeItem.cfg.setProperty("selected", false);
299 oMenu.activeItem = null;
310 else if (p_oEvent.type == "keyup") {
312 if (m_oFocusedMenuItem) {
314 m_oFocusedMenuItem.blurEvent.fire();
316 m_oFocusedMenuItem = null;
326 * @method onMenuDestroy
327 * @description "destroy" event handler for a menu.
328 * @private
329 * @param {String} p_sType String representing the name of the event
330 * that was fired.
331 * @param {Array} p_aArgs Array of arguments sent when the event
332 * was fired.
333 * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
335 function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
337 if (m_oMenus[p_oMenu.id]) {
339 this.removeMenu(p_oMenu);
347 * @method onMenuFocus
348 * @description "focus" event handler for a MenuItem instance.
349 * @private
350 * @param {String} p_sType String representing the name of the event
351 * that was fired.
352 * @param {Array} p_aArgs Array of arguments sent when the event
353 * was fired.
355 function onMenuFocus(p_sType, p_aArgs) {
357 var oItem = p_aArgs[0];
359 if (oItem) {
361 m_oFocusedMenuItem = oItem;
369 * @method onMenuBlur
370 * @description "blur" event handler for a MenuItem instance.
371 * @private
372 * @param {String} p_sType String representing the name of the event
373 * that was fired.
374 * @param {Array} p_aArgs Array of arguments sent when the event
375 * was fired.
377 function onMenuBlur(p_sType, p_aArgs) {
379 m_oFocusedMenuItem = null;
386 * @method onMenuVisibleConfigChange
387 * @description Event handler for when the "visible" configuration
388 * property of a Menu instance changes.
389 * @private
390 * @param {String} p_sType String representing the name of the event
391 * that was fired.
392 * @param {Array} p_aArgs Array of arguments sent when the event
393 * was fired.
395 function onMenuVisibleConfigChange(p_sType, p_aArgs) {
397 var bVisible = p_aArgs[0],
398 sId = this.id;
400 if (bVisible) {
402 m_oVisibleMenus[sId] = this;
404 m_oLogger.log(
405 this +
406 " added to the collection of visible menus.");
409 else if (m_oVisibleMenus[sId]) {
411 delete m_oVisibleMenus[sId];
413 m_oLogger.log(
414 this +
415 " removed from the collection of visible menus.");
423 * @method onItemDestroy
424 * @description "destroy" event handler for a MenuItem instance.
425 * @private
426 * @param {String} p_sType String representing the name of the event
427 * that was fired.
428 * @param {Array} p_aArgs Array of arguments sent when the event
429 * was fired.
431 function onItemDestroy(p_sType, p_aArgs) {
433 removeItem(this);
438 function removeItem(p_oMenuItem) {
440 var sId = p_oMenuItem.id;
442 if (sId && m_oItems[sId]) {
444 if (m_oFocusedMenuItem == p_oMenuItem) {
446 m_oFocusedMenuItem = null;
450 delete m_oItems[sId];
452 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
454 m_oLogger.log(p_oMenuItem + " successfully unregistered.");
462 * @method onItemAdded
463 * @description "itemadded" event handler for a Menu instance.
464 * @private
465 * @param {String} p_sType String representing the name of the event
466 * that was fired.
467 * @param {Array} p_aArgs Array of arguments sent when the event
468 * was fired.
470 function onItemAdded(p_sType, p_aArgs) {
472 var oItem = p_aArgs[0],
473 sId;
475 if (oItem instanceof YAHOO.widget.MenuItem) {
477 sId = oItem.id;
479 if (!m_oItems[sId]) {
481 m_oItems[sId] = oItem;
483 oItem.destroyEvent.subscribe(onItemDestroy);
485 m_oLogger.log(oItem + " successfully registered.");
494 return {
496 // Privileged methods
500 * @method addMenu
501 * @description Adds a menu to the collection of known menus.
502 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
503 * instance to be added.
505 addMenu: function (p_oMenu) {
507 var oDoc;
509 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
510 !m_oMenus[p_oMenu.id]) {
512 m_oMenus[p_oMenu.id] = p_oMenu;
515 if (!m_bInitializedEventHandlers) {
517 oDoc = document;
519 Event.on(oDoc, "mouseover", onDOMEvent, this, true);
520 Event.on(oDoc, "mouseout", onDOMEvent, this, true);
521 Event.on(oDoc, "mousedown", onDOMEvent, this, true);
522 Event.on(oDoc, "mouseup", onDOMEvent, this, true);
523 Event.on(oDoc, "click", onDOMEvent, this, true);
524 Event.on(oDoc, "keydown", onDOMEvent, this, true);
525 Event.on(oDoc, "keyup", onDOMEvent, this, true);
526 Event.on(oDoc, "keypress", onDOMEvent, this, true);
529 m_bInitializedEventHandlers = true;
531 m_oLogger.log("DOM event handlers initialized.");
535 p_oMenu.cfg.subscribeToConfigEvent("visible",
536 onMenuVisibleConfigChange);
538 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu,
539 this);
541 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
542 p_oMenu.focusEvent.subscribe(onMenuFocus);
543 p_oMenu.blurEvent.subscribe(onMenuBlur);
545 m_oLogger.log(p_oMenu + " successfully registered.");
553 * @method removeMenu
554 * @description Removes a menu from the collection of known menus.
555 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
556 * instance to be removed.
558 removeMenu: function (p_oMenu) {
560 var sId,
561 aItems,
564 if (p_oMenu) {
566 sId = p_oMenu.id;
568 if (m_oMenus[sId] == p_oMenu) {
570 // Unregister each menu item
572 aItems = p_oMenu.getItems();
574 if (aItems && aItems.length > 0) {
576 i = aItems.length - 1;
578 do {
580 removeItem(aItems[i]);
583 while (i--);
588 // Unregister the menu
590 delete m_oMenus[sId];
592 m_oLogger.log(p_oMenu + " successfully unregistered.");
596 Unregister the menu from the collection of
597 visible menus
600 if (m_oVisibleMenus[sId] == p_oMenu) {
602 delete m_oVisibleMenus[sId];
604 m_oLogger.log(p_oMenu + " unregistered from the" +
605 " collection of visible menus.");
610 // Unsubscribe event listeners
612 if (p_oMenu.cfg) {
614 p_oMenu.cfg.unsubscribeFromConfigEvent("visible",
615 onMenuVisibleConfigChange);
619 p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
620 p_oMenu);
622 p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
623 p_oMenu.focusEvent.unsubscribe(onMenuFocus);
624 p_oMenu.blurEvent.unsubscribe(onMenuBlur);
634 * @method hideVisible
635 * @description Hides all visible, dynamically positioned menus
636 * (excluding instances of YAHOO.widget.MenuBar).
638 hideVisible: function () {
640 var oMenu;
642 for (var i in m_oVisibleMenus) {
644 if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
646 oMenu = m_oVisibleMenus[i];
648 if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
649 oMenu.cfg.getProperty("position") == "dynamic") {
651 oMenu.hide();
663 * @method getVisible
664 * @description Returns a collection of all visible menus registered
665 * with the menu manger.
666 * @return {Array}
668 getVisible: function () {
670 return m_oVisibleMenus;
676 * @method getMenus
677 * @description Returns a collection of all menus registered with the
678 * menu manger.
679 * @return {Array}
681 getMenus: function () {
683 return m_oMenus;
689 * @method getMenu
690 * @description Returns a menu with the specified id.
691 * @param {String} p_sId String specifying the id of the
692 * <code>&#60;div&#62;</code> element representing the menu to
693 * be retrieved.
694 * @return {YAHOO.widget.Menu}
696 getMenu: function (p_sId) {
698 var oMenu = m_oMenus[p_sId];
700 if (oMenu) {
702 return oMenu;
710 * @method getMenuItem
711 * @description Returns a menu item with the specified id.
712 * @param {String} p_sId String specifying the id of the
713 * <code>&#60;li&#62;</code> element representing the menu item to
714 * be retrieved.
715 * @return {YAHOO.widget.MenuItem}
717 getMenuItem: function (p_sId) {
719 var oItem = m_oItems[p_sId];
721 if (oItem) {
723 return oItem;
731 * @method getMenuItemGroup
732 * @description Returns an array of menu item instances whose
733 * corresponding <code>&#60;li&#62;</code> elements are child
734 * nodes of the <code>&#60;ul&#62;</code> element with the
735 * specified id.
736 * @param {String} p_sId String specifying the id of the
737 * <code>&#60;ul&#62;</code> element representing the group of
738 * menu items to be retrieved.
739 * @return {Array}
741 getMenuItemGroup: function (p_sId) {
743 var oUL = Dom.get(p_sId),
744 aItems,
745 oNode,
746 oItem,
747 sId;
750 if (oUL && oUL.tagName &&
751 oUL.tagName.toUpperCase() == "UL") {
753 oNode = oUL.firstChild;
755 if (oNode) {
757 aItems = [];
759 do {
761 sId = oNode.id;
763 if (sId) {
765 oItem = this.getMenuItem(sId);
767 if (oItem) {
769 aItems[aItems.length] = oItem;
776 while ((oNode = oNode.nextSibling));
779 if (aItems.length > 0) {
781 return aItems;
793 * @method getFocusedMenuItem
794 * @description Returns a reference to the menu item that currently
795 * has focus.
796 * @return {YAHOO.widget.MenuItem}
798 getFocusedMenuItem: function () {
800 return m_oFocusedMenuItem;
806 * @method getFocusedMenu
807 * @description Returns a reference to the menu that currently
808 * has focus.
809 * @return {YAHOO.widget.Menu}
811 getFocusedMenu: function () {
813 if (m_oFocusedMenuItem) {
815 return (m_oFocusedMenuItem.parent.getRoot());
823 * @method toString
824 * @description Returns a string representing the menu manager.
825 * @return {String}
827 toString: function () {
829 return "MenuManager";
835 }();
837 })();
841 (function () {
845 * The Menu class creates a container that holds a vertical list representing
846 * a set of options or commands. Menu is the base class for all
847 * menu containers.
848 * @param {String} p_oElement String specifying the id attribute of the
849 * <code>&#60;div&#62;</code> element of the menu.
850 * @param {String} p_oElement String specifying the id attribute of the
851 * <code>&#60;select&#62;</code> element to be used as the data source
852 * for the menu.
853 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
854 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
855 * specifying the <code>&#60;div&#62;</code> element of the menu.
856 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
857 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
858 * Object specifying the <code>&#60;select&#62;</code> element to be used as
859 * the data source for the menu.
860 * @param {Object} p_oConfig Optional. Object literal specifying the
861 * configuration for the menu. See configuration class documentation for
862 * more details.
863 * @namespace YAHOO.widget
864 * @class Menu
865 * @constructor
866 * @extends YAHOO.widget.Overlay
868 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
870 if (p_oConfig) {
872 this.parent = p_oConfig.parent;
873 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
874 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
879 YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
886 * @method checkPosition
887 * @description Checks to make sure that the value of the "position" property
888 * is one of the supported strings. Returns true if the position is supported.
889 * @private
890 * @param {Object} p_sPosition String specifying the position of the menu.
891 * @return {Boolean}
893 function checkPosition(p_sPosition) {
895 if (typeof p_sPosition == "string") {
897 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
904 var Dom = YAHOO.util.Dom,
905 Event = YAHOO.util.Event,
906 Module = YAHOO.widget.Module,
907 Overlay = YAHOO.widget.Overlay,
908 Menu = YAHOO.widget.Menu,
909 MenuManager = YAHOO.widget.MenuManager,
910 CustomEvent = YAHOO.util.CustomEvent,
911 Lang = YAHOO.lang,
912 UA = YAHOO.env.ua,
914 m_oShadowTemplate,
917 * Constant representing the name of the Menu's events
918 * @property EVENT_TYPES
919 * @private
920 * @final
921 * @type Object
923 EVENT_TYPES = {
925 "MOUSE_OVER": "mouseover",
926 "MOUSE_OUT": "mouseout",
927 "MOUSE_DOWN": "mousedown",
928 "MOUSE_UP": "mouseup",
929 "CLICK": "click",
930 "KEY_PRESS": "keypress",
931 "KEY_DOWN": "keydown",
932 "KEY_UP": "keyup",
933 "FOCUS": "focus",
934 "BLUR": "blur",
935 "ITEM_ADDED": "itemAdded",
936 "ITEM_REMOVED": "itemRemoved"
942 * Constant representing the Menu's configuration properties
943 * @property DEFAULT_CONFIG
944 * @private
945 * @final
946 * @type Object
948 DEFAULT_CONFIG = {
950 "VISIBLE": {
951 key: "visible",
952 value: false,
953 validator: Lang.isBoolean
956 "CONSTRAIN_TO_VIEWPORT": {
957 key: "constraintoviewport",
958 value: true,
959 validator: Lang.isBoolean,
960 supercedes: ["iframe","x","y","xy"]
963 "POSITION": {
964 key: "position",
965 value: "dynamic",
966 validator: checkPosition,
967 supercedes: ["visible", "iframe"]
970 "SUBMENU_ALIGNMENT": {
971 key: "submenualignment",
972 value: ["tl","tr"],
973 suppressEvent: true
976 "AUTO_SUBMENU_DISPLAY": {
977 key: "autosubmenudisplay",
978 value: true,
979 validator: Lang.isBoolean,
980 suppressEvent: true
983 "SHOW_DELAY": {
984 key: "showdelay",
985 value: 250,
986 validator: Lang.isNumber,
987 suppressEvent: true
990 "HIDE_DELAY": {
991 key: "hidedelay",
992 value: 0,
993 validator: Lang.isNumber,
994 suppressEvent: true
997 "SUBMENU_HIDE_DELAY": {
998 key: "submenuhidedelay",
999 value: 250,
1000 validator: Lang.isNumber,
1001 suppressEvent: true
1004 "CLICK_TO_HIDE": {
1005 key: "clicktohide",
1006 value: true,
1007 validator: Lang.isBoolean,
1008 suppressEvent: true
1011 "CONTAINER": {
1012 key: "container",
1013 suppressEvent: true
1016 "SCROLL_INCREMENT": {
1017 key: "scrollincrement",
1018 value: 1,
1019 validator: Lang.isNumber,
1020 supercedes: ["maxheight"],
1021 suppressEvent: true
1024 "MIN_SCROLL_HEIGHT": {
1025 key: "minscrollheight",
1026 value: 90,
1027 validator: Lang.isNumber,
1028 supercedes: ["maxheight"],
1029 suppressEvent: true
1032 "MAX_HEIGHT": {
1033 key: "maxheight",
1034 value: 0,
1035 validator: Lang.isNumber,
1036 supercedes: ["iframe"],
1037 suppressEvent: true
1040 "CLASS_NAME": {
1041 key: "classname",
1042 value: null,
1043 validator: Lang.isString,
1044 suppressEvent: true
1047 "DISABLED": {
1048 key: "disabled",
1049 value: false,
1050 validator: Lang.isBoolean,
1051 suppressEvent: true
1058 YAHOO.lang.extend(Menu, Overlay, {
1061 // Constants
1065 * @property CSS_CLASS_NAME
1066 * @description String representing the CSS class(es) to be applied to the
1067 * menu's <code>&#60;div&#62;</code> element.
1068 * @default "yuimenu"
1069 * @final
1070 * @type String
1072 CSS_CLASS_NAME: "yuimenu",
1076 * @property ITEM_TYPE
1077 * @description Object representing the type of menu item to instantiate and
1078 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
1079 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
1080 * of the menu's source HTML element.
1081 * @default YAHOO.widget.MenuItem
1082 * @final
1083 * @type YAHOO.widget.MenuItem
1085 ITEM_TYPE: null,
1089 * @property GROUP_TITLE_TAG_NAME
1090 * @description String representing the tagname of the HTML element used to
1091 * title the menu's item groups.
1092 * @default H6
1093 * @final
1094 * @type String
1096 GROUP_TITLE_TAG_NAME: "h6",
1100 * @property OFF_SCREEN_POSITION
1101 * @description Array representing the default x and y position that a menu
1102 * should have when it is positioned outside the viewport by the
1103 * "poistionOffScreen" method.
1104 * @default [-10000, -10000]
1105 * @final
1106 * @type Array
1108 OFF_SCREEN_POSITION: [-10000, -10000],
1111 // Private properties
1114 /**
1115 * @property _nHideDelayId
1116 * @description Number representing the time-out setting used to cancel the
1117 * hiding of a menu.
1118 * @default null
1119 * @private
1120 * @type Number
1122 _nHideDelayId: null,
1125 /**
1126 * @property _nShowDelayId
1127 * @description Number representing the time-out setting used to cancel the
1128 * showing of a menu.
1129 * @default null
1130 * @private
1131 * @type Number
1133 _nShowDelayId: null,
1136 /**
1137 * @property _nSubmenuHideDelayId
1138 * @description Number representing the time-out setting used to cancel the
1139 * hiding of a submenu.
1140 * @default null
1141 * @private
1142 * @type Number
1144 _nSubmenuHideDelayId: null,
1147 /**
1148 * @property _nBodyScrollId
1149 * @description Number representing the time-out setting used to cancel the
1150 * scrolling of the menu's body element.
1151 * @default null
1152 * @private
1153 * @type Number
1155 _nBodyScrollId: null,
1158 /**
1159 * @property _bHideDelayEventHandlersAssigned
1160 * @description Boolean indicating if the "mouseover" and "mouseout" event
1161 * handlers used for hiding the menu via a call to "window.setTimeout" have
1162 * already been assigned.
1163 * @default false
1164 * @private
1165 * @type Boolean
1167 _bHideDelayEventHandlersAssigned: false,
1171 * @property _bHandledMouseOverEvent
1172 * @description Boolean indicating the current state of the menu's
1173 * "mouseover" event.
1174 * @default false
1175 * @private
1176 * @type Boolean
1178 _bHandledMouseOverEvent: false,
1182 * @property _bHandledMouseOutEvent
1183 * @description Boolean indicating the current state of the menu's
1184 * "mouseout" event.
1185 * @default false
1186 * @private
1187 * @type Boolean
1189 _bHandledMouseOutEvent: false,
1193 * @property _aGroupTitleElements
1194 * @description Array of HTML element used to title groups of menu items.
1195 * @default []
1196 * @private
1197 * @type Array
1199 _aGroupTitleElements: null,
1203 * @property _aItemGroups
1204 * @description Multi-dimensional Array representing the menu items as they
1205 * are grouped in the menu.
1206 * @default []
1207 * @private
1208 * @type Array
1210 _aItemGroups: null,
1214 * @property _aListElements
1215 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is
1216 * the parent node for each item's <code>&#60;li&#62;</code> element.
1217 * @default []
1218 * @private
1219 * @type Array
1221 _aListElements: null,
1225 * @property _nCurrentMouseX
1226 * @description The current x coordinate of the mouse inside the area of
1227 * the menu.
1228 * @default 0
1229 * @private
1230 * @type Number
1232 _nCurrentMouseX: 0,
1236 * @property _bStopMouseEventHandlers
1237 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
1238 * from executing.
1239 * @default false
1240 * @private
1241 * @type Boolean
1243 _bStopMouseEventHandlers: false,
1247 * @property _sClassName
1248 * @description The current value of the "classname" configuration attribute.
1249 * @default null
1250 * @private
1251 * @type String
1253 _sClassName: null,
1257 // Public properties
1261 * @property lazyLoad
1262 * @description Boolean indicating if the menu's "lazy load" feature is
1263 * enabled. If set to "true," initialization and rendering of the menu's
1264 * items will be deferred until the first time it is made visible. This
1265 * property should be set via the constructor using the configuration
1266 * object literal.
1267 * @default false
1268 * @type Boolean
1270 lazyLoad: false,
1274 * @property itemData
1275 * @description Array of items to be added to the menu. The array can contain
1276 * strings representing the text for each item to be created, object literals
1277 * representing the menu item configuration properties, or MenuItem instances.
1278 * This property should be set via the constructor using the configuration
1279 * object literal.
1280 * @default null
1281 * @type Array
1283 itemData: null,
1287 * @property activeItem
1288 * @description Object reference to the item in the menu that has is selected.
1289 * @default null
1290 * @type YAHOO.widget.MenuItem
1292 activeItem: null,
1296 * @property parent
1297 * @description Object reference to the menu's parent menu or menu item.
1298 * This property can be set via the constructor using the configuration
1299 * object literal.
1300 * @default null
1301 * @type YAHOO.widget.MenuItem
1303 parent: null,
1307 * @property srcElement
1308 * @description Object reference to the HTML element (either
1309 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
1310 * create the menu.
1311 * @default null
1312 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1313 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
1314 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1315 * html#ID-22445964">HTMLDivElement</a>
1317 srcElement: null,
1321 // Events
1325 * @event mouseOverEvent
1326 * @description Fires when the mouse has entered the menu. Passes back
1327 * the DOM Event object as an argument.
1329 mouseOverEvent: null,
1333 * @event mouseOutEvent
1334 * @description Fires when the mouse has left the menu. Passes back the DOM
1335 * Event object as an argument.
1336 * @type YAHOO.util.CustomEvent
1338 mouseOutEvent: null,
1342 * @event mouseDownEvent
1343 * @description Fires when the user mouses down on the menu. Passes back the
1344 * DOM Event object as an argument.
1345 * @type YAHOO.util.CustomEvent
1347 mouseDownEvent: null,
1351 * @event mouseUpEvent
1352 * @description Fires when the user releases a mouse button while the mouse is
1353 * over the menu. Passes back the DOM Event object as an argument.
1354 * @type YAHOO.util.CustomEvent
1356 mouseUpEvent: null,
1360 * @event clickEvent
1361 * @description Fires when the user clicks the on the menu. Passes back the
1362 * DOM Event object as an argument.
1363 * @type YAHOO.util.CustomEvent
1365 clickEvent: null,
1369 * @event keyPressEvent
1370 * @description Fires when the user presses an alphanumeric key when one of the
1371 * menu's items has focus. Passes back the DOM Event object as an argument.
1372 * @type YAHOO.util.CustomEvent
1374 keyPressEvent: null,
1378 * @event keyDownEvent
1379 * @description Fires when the user presses a key when one of the menu's items
1380 * has focus. Passes back the DOM Event object as an argument.
1381 * @type YAHOO.util.CustomEvent
1383 keyDownEvent: null,
1387 * @event keyUpEvent
1388 * @description Fires when the user releases a key when one of the menu's items
1389 * has focus. Passes back the DOM Event object as an argument.
1390 * @type YAHOO.util.CustomEvent
1392 keyUpEvent: null,
1396 * @event itemAddedEvent
1397 * @description Fires when an item is added to the menu.
1398 * @type YAHOO.util.CustomEvent
1400 itemAddedEvent: null,
1404 * @event itemRemovedEvent
1405 * @description Fires when an item is removed to the menu.
1406 * @type YAHOO.util.CustomEvent
1408 itemRemovedEvent: null,
1412 * @method init
1413 * @description The Menu class's initialization method. This method is
1414 * automatically called by the constructor, and sets up all DOM references
1415 * for pre-existing markup, and creates required markup if it is not
1416 * already present.
1417 * @param {String} p_oElement String specifying the id attribute of the
1418 * <code>&#60;div&#62;</code> element of the menu.
1419 * @param {String} p_oElement String specifying the id attribute of the
1420 * <code>&#60;select&#62;</code> element to be used as the data source
1421 * for the menu.
1422 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1423 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
1424 * specifying the <code>&#60;div&#62;</code> element of the menu.
1425 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1426 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
1427 * Object specifying the <code>&#60;select&#62;</code> element to be used as
1428 * the data source for the menu.
1429 * @param {Object} p_oConfig Optional. Object literal specifying the
1430 * configuration for the menu. See configuration class documentation for
1431 * more details.
1433 init: function (p_oElement, p_oConfig) {
1435 this._aItemGroups = [];
1436 this._aListElements = [];
1437 this._aGroupTitleElements = [];
1439 if (!this.ITEM_TYPE) {
1441 this.ITEM_TYPE = YAHOO.widget.MenuItem;
1446 var oElement;
1448 if (typeof p_oElement == "string") {
1450 oElement = document.getElementById(p_oElement);
1453 else if (p_oElement.tagName) {
1455 oElement = p_oElement;
1460 if (oElement && oElement.tagName) {
1462 switch(oElement.tagName.toUpperCase()) {
1464 case "DIV":
1466 this.srcElement = oElement;
1468 if (!oElement.id) {
1470 oElement.setAttribute("id", Dom.generateId());
1476 Note: we don't pass the user config in here yet
1477 because we only want it executed once, at the lowest
1478 subclass level.
1481 Menu.superclass.init.call(this, oElement);
1483 this.beforeInitEvent.fire(Menu);
1485 this.logger = new YAHOO.widget.LogWriter(this.toString());
1487 this.logger.log("Source element: " + this.srcElement.tagName);
1489 break;
1491 case "SELECT":
1493 this.srcElement = oElement;
1497 The source element is not something that we can use
1498 outright, so we need to create a new Overlay
1500 Note: we don't pass the user config in here yet
1501 because we only want it executed once, at the lowest
1502 subclass level.
1505 Menu.superclass.init.call(this, Dom.generateId());
1507 this.beforeInitEvent.fire(Menu);
1509 this.logger = new YAHOO.widget.LogWriter(this.toString());
1511 this.logger.log("Source element: " + this.srcElement.tagName);
1513 break;
1518 else {
1521 Note: we don't pass the user config in here yet
1522 because we only want it executed once, at the lowest
1523 subclass level.
1526 Menu.superclass.init.call(this, p_oElement);
1528 this.beforeInitEvent.fire(Menu);
1530 this.logger = new YAHOO.widget.LogWriter(this.toString());
1532 this.logger.log("No source element found. " +
1533 "Created element with id: " + this.id);
1538 if (this.element) {
1540 Dom.addClass(this.element, this.CSS_CLASS_NAME);
1543 // Subscribe to Custom Events
1545 this.initEvent.subscribe(this._onInit);
1546 this.beforeRenderEvent.subscribe(this._onBeforeRender);
1547 this.renderEvent.subscribe(this._onRender);
1548 this.renderEvent.subscribe(this.onRender);
1549 this.beforeShowEvent.subscribe(this._onBeforeShow);
1550 this.hideEvent.subscribe(this.positionOffScreen);
1551 this.showEvent.subscribe(this._onShow);
1552 this.beforeHideEvent.subscribe(this._onBeforeHide);
1553 this.mouseOverEvent.subscribe(this._onMouseOver);
1554 this.mouseOutEvent.subscribe(this._onMouseOut);
1555 this.clickEvent.subscribe(this._onClick);
1556 this.keyDownEvent.subscribe(this._onKeyDown);
1557 this.keyPressEvent.subscribe(this._onKeyPress);
1560 if (UA.gecko || UA.webkit) {
1562 this.cfg.subscribeToConfigEvent("y", this._onYChange);
1567 if (p_oConfig) {
1569 this.cfg.applyConfig(p_oConfig, true);
1574 // Register the Menu instance with the MenuManager
1576 MenuManager.addMenu(this);
1579 this.initEvent.fire(Menu);
1587 // Private methods
1591 * @method _initSubTree
1592 * @description Iterates the childNodes of the source element to find nodes
1593 * used to instantiate menu and menu items.
1594 * @private
1596 _initSubTree: function () {
1598 var oSrcElement = this.srcElement,
1599 sSrcElementTagName,
1600 nGroup,
1601 sGroupTitleTagName,
1602 oNode,
1603 aListElements,
1604 nListElements,
1608 if (oSrcElement) {
1610 sSrcElementTagName =
1611 (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1614 if (sSrcElementTagName == "DIV") {
1616 // Populate the collection of item groups and item group titles
1618 oNode = this.body.firstChild;
1621 if (oNode) {
1623 nGroup = 0;
1624 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1626 do {
1629 if (oNode && oNode.tagName) {
1631 switch (oNode.tagName.toUpperCase()) {
1633 case sGroupTitleTagName:
1635 this._aGroupTitleElements[nGroup] = oNode;
1637 break;
1639 case "UL":
1641 this._aListElements[nGroup] = oNode;
1642 this._aItemGroups[nGroup] = [];
1643 nGroup++;
1645 break;
1652 while ((oNode = oNode.nextSibling));
1656 Apply the "first-of-type" class to the first UL to mimic
1657 the "first-of-type" CSS3 psuedo class.
1660 if (this._aListElements[0]) {
1662 Dom.addClass(this._aListElements[0], "first-of-type");
1671 oNode = null;
1673 this.logger.log("Searching DOM for items to initialize.");
1676 if (sSrcElementTagName) {
1678 switch (sSrcElementTagName) {
1680 case "DIV":
1682 aListElements = this._aListElements;
1683 nListElements = aListElements.length;
1685 if (nListElements > 0) {
1687 this.logger.log("Found " + nListElements +
1688 " item groups to initialize.");
1690 i = nListElements - 1;
1692 do {
1694 oNode = aListElements[i].firstChild;
1696 if (oNode) {
1698 this.logger.log("Scanning " +
1699 aListElements[i].childNodes.length +
1700 " child nodes for items to initialize.");
1702 do {
1704 if (oNode && oNode.tagName &&
1705 oNode.tagName.toUpperCase() == "LI") {
1707 this.logger.log("Initializing " +
1708 oNode.tagName + " node.");
1710 this.addItem(new this.ITEM_TYPE(oNode,
1711 { parent: this }), i);
1716 while ((oNode = oNode.nextSibling));
1721 while (i--);
1725 break;
1727 case "SELECT":
1729 this.logger.log("Scanning " +
1730 oSrcElement.childNodes.length +
1731 " child nodes for items to initialize.");
1733 oNode = oSrcElement.firstChild;
1735 do {
1737 if (oNode && oNode.tagName) {
1739 switch (oNode.tagName.toUpperCase()) {
1741 case "OPTGROUP":
1742 case "OPTION":
1744 this.logger.log("Initializing " +
1745 oNode.tagName + " node.");
1747 this.addItem(
1748 new this.ITEM_TYPE(
1749 oNode,
1750 { parent: this }
1754 break;
1761 while ((oNode = oNode.nextSibling));
1763 break;
1775 * @method _getFirstEnabledItem
1776 * @description Returns the first enabled item in the menu.
1777 * @return {YAHOO.widget.MenuItem}
1778 * @private
1780 _getFirstEnabledItem: function () {
1782 var aItems = this.getItems(),
1783 nItems = aItems.length,
1784 oItem;
1786 for(var i=0; i<nItems; i++) {
1788 oItem = aItems[i];
1790 if (oItem && !oItem.cfg.getProperty("disabled") &&
1791 oItem.element.style.display != "none") {
1793 return oItem;
1803 * @method _addItemToGroup
1804 * @description Adds a menu item to a group.
1805 * @private
1806 * @param {Number} p_nGroupIndex Number indicating the group to which the
1807 * item belongs.
1808 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1809 * instance to be added to the menu.
1810 * @param {String} p_oItem String specifying the text of the item to be added
1811 * to the menu.
1812 * @param {Object} p_oItem Object literal containing a set of menu item
1813 * configuration properties.
1814 * @param {Number} p_nItemIndex Optional. Number indicating the index at
1815 * which the menu item should be added.
1816 * @return {YAHOO.widget.MenuItem}
1818 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1820 var oItem,
1821 nGroupIndex,
1822 aGroup,
1823 oGroupItem,
1824 bAppend,
1825 oNextItemSibling,
1826 nItemIndex;
1828 function getNextItemSibling(p_aArray, p_nStartIndex) {
1830 return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray,
1831 (p_nStartIndex+1)));
1835 if (p_oItem instanceof this.ITEM_TYPE) {
1837 oItem = p_oItem;
1838 oItem.parent = this;
1841 else if (typeof p_oItem == "string") {
1843 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1846 else if (typeof p_oItem == "object") {
1848 p_oItem.parent = this;
1850 oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1855 if (oItem) {
1857 if (oItem.cfg.getProperty("selected")) {
1859 this.activeItem = oItem;
1864 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1865 aGroup = this._getItemGroup(nGroupIndex);
1869 if (!aGroup) {
1871 aGroup = this._createItemGroup(nGroupIndex);
1876 if (typeof p_nItemIndex == "number") {
1878 bAppend = (p_nItemIndex >= aGroup.length);
1881 if (aGroup[p_nItemIndex]) {
1883 aGroup.splice(p_nItemIndex, 0, oItem);
1886 else {
1888 aGroup[p_nItemIndex] = oItem;
1893 oGroupItem = aGroup[p_nItemIndex];
1895 if (oGroupItem) {
1897 if (bAppend && (!oGroupItem.element.parentNode ||
1898 oGroupItem.element.parentNode.nodeType == 11)) {
1900 this._aListElements[nGroupIndex].appendChild(
1901 oGroupItem.element);
1904 else {
1906 oNextItemSibling = getNextItemSibling(aGroup,
1907 (p_nItemIndex+1));
1909 if (oNextItemSibling && (!oGroupItem.element.parentNode ||
1910 oGroupItem.element.parentNode.nodeType == 11)) {
1912 this._aListElements[nGroupIndex].insertBefore(
1913 oGroupItem.element,
1914 oNextItemSibling.element);
1921 oGroupItem.parent = this;
1923 this._subscribeToItemEvents(oGroupItem);
1925 this._configureSubmenu(oGroupItem);
1927 this._updateItemProperties(nGroupIndex);
1929 this.logger.log("Item inserted." +
1930 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
1931 " Index: " + oGroupItem.index + ", " +
1932 " Group Index: " + oGroupItem.groupIndex);
1934 this.itemAddedEvent.fire(oGroupItem);
1935 this.changeContentEvent.fire();
1937 return oGroupItem;
1942 else {
1944 nItemIndex = aGroup.length;
1946 aGroup[nItemIndex] = oItem;
1948 oGroupItem = aGroup[nItemIndex];
1951 if (oGroupItem) {
1953 if (!Dom.isAncestor(this._aListElements[nGroupIndex],
1954 oGroupItem.element)) {
1956 this._aListElements[nGroupIndex].appendChild(
1957 oGroupItem.element);
1961 oGroupItem.element.setAttribute("groupindex", nGroupIndex);
1962 oGroupItem.element.setAttribute("index", nItemIndex);
1964 oGroupItem.parent = this;
1966 oGroupItem.index = nItemIndex;
1967 oGroupItem.groupIndex = nGroupIndex;
1969 this._subscribeToItemEvents(oGroupItem);
1971 this._configureSubmenu(oGroupItem);
1973 if (nItemIndex === 0) {
1975 Dom.addClass(oGroupItem.element, "first-of-type");
1979 this.logger.log("Item added." +
1980 " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
1981 " Index: " + oGroupItem.index + ", " +
1982 " Group Index: " + oGroupItem.groupIndex);
1985 this.itemAddedEvent.fire(oGroupItem);
1986 this.changeContentEvent.fire();
1988 return oGroupItem;
2000 * @method _removeItemFromGroupByIndex
2001 * @description Removes a menu item from a group by index. Returns the menu
2002 * item that was removed.
2003 * @private
2004 * @param {Number} p_nGroupIndex Number indicating the group to which the menu
2005 * item belongs.
2006 * @param {Number} p_nItemIndex Number indicating the index of the menu item
2007 * to be removed.
2008 * @return {YAHOO.widget.MenuItem}
2010 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2012 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0,
2013 aGroup = this._getItemGroup(nGroupIndex),
2014 aArray,
2015 oItem,
2016 oUL;
2018 if (aGroup) {
2020 aArray = aGroup.splice(p_nItemIndex, 1);
2021 oItem = aArray[0];
2023 if (oItem) {
2025 // Update the index and className properties of each member
2027 this._updateItemProperties(nGroupIndex);
2029 if (aGroup.length === 0) {
2031 // Remove the UL
2033 oUL = this._aListElements[nGroupIndex];
2035 if (this.body && oUL) {
2037 this.body.removeChild(oUL);
2041 // Remove the group from the array of items
2043 this._aItemGroups.splice(nGroupIndex, 1);
2046 // Remove the UL from the array of ULs
2048 this._aListElements.splice(nGroupIndex, 1);
2052 Assign the "first-of-type" class to the new first UL
2053 in the collection
2056 oUL = this._aListElements[0];
2058 if (oUL) {
2060 Dom.addClass(oUL, "first-of-type");
2067 this.itemRemovedEvent.fire(oItem);
2068 this.changeContentEvent.fire();
2071 // Return a reference to the item that was removed
2073 return oItem;
2083 * @method _removeItemFromGroupByValue
2084 * @description Removes a menu item from a group by reference. Returns the
2085 * menu item that was removed.
2086 * @private
2087 * @param {Number} p_nGroupIndex Number indicating the group to which the
2088 * menu item belongs.
2089 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2090 * instance to be removed.
2091 * @return {YAHOO.widget.MenuItem}
2093 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2095 var aGroup = this._getItemGroup(p_nGroupIndex),
2096 nItems,
2097 nItemIndex,
2100 if (aGroup) {
2102 nItems = aGroup.length;
2103 nItemIndex = -1;
2105 if (nItems > 0) {
2107 i = nItems-1;
2109 do {
2111 if (aGroup[i] == p_oItem) {
2113 nItemIndex = i;
2114 break;
2119 while(i--);
2121 if (nItemIndex > -1) {
2123 return (this._removeItemFromGroupByIndex(p_nGroupIndex,
2124 nItemIndex));
2136 * @method _updateItemProperties
2137 * @description Updates the "index," "groupindex," and "className" properties
2138 * of the menu items in the specified group.
2139 * @private
2140 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2142 _updateItemProperties: function (p_nGroupIndex) {
2144 var aGroup = this._getItemGroup(p_nGroupIndex),
2145 nItems = aGroup.length,
2146 oItem,
2147 oLI,
2151 if (nItems > 0) {
2153 i = nItems - 1;
2155 // Update the index and className properties of each member
2157 do {
2159 oItem = aGroup[i];
2161 if (oItem) {
2163 oLI = oItem.element;
2165 oItem.index = i;
2166 oItem.groupIndex = p_nGroupIndex;
2168 oLI.setAttribute("groupindex", p_nGroupIndex);
2169 oLI.setAttribute("index", i);
2171 Dom.removeClass(oLI, "first-of-type");
2176 while(i--);
2179 if (oLI) {
2181 Dom.addClass(oLI, "first-of-type");
2191 * @method _createItemGroup
2192 * @description Creates a new menu item group (array) and its associated
2193 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2194 * @private
2195 * @param {Number} p_nIndex Number indicating the group to create.
2196 * @return {Array}
2198 _createItemGroup: function (p_nIndex) {
2200 var oUL;
2202 if (!this._aItemGroups[p_nIndex]) {
2204 this._aItemGroups[p_nIndex] = [];
2206 oUL = document.createElement("ul");
2208 this._aListElements[p_nIndex] = oUL;
2210 return this._aItemGroups[p_nIndex];
2218 * @method _getItemGroup
2219 * @description Returns the menu item group at the specified index.
2220 * @private
2221 * @param {Number} p_nIndex Number indicating the index of the menu item group
2222 * to be retrieved.
2223 * @return {Array}
2225 _getItemGroup: function (p_nIndex) {
2227 var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);
2229 return this._aItemGroups[nIndex];
2235 * @method _configureSubmenu
2236 * @description Subscribes the menu item's submenu to its parent menu's events.
2237 * @private
2238 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2239 * instance with the submenu to be configured.
2241 _configureSubmenu: function (p_oItem) {
2243 var oSubmenu = p_oItem.cfg.getProperty("submenu");
2245 if (oSubmenu) {
2248 Listen for configuration changes to the parent menu
2249 so they they can be applied to the submenu.
2252 this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange,
2253 oSubmenu, true);
2255 this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2257 oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow);
2267 * @method _subscribeToItemEvents
2268 * @description Subscribes a menu to a menu item's event.
2269 * @private
2270 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
2271 * instance whose events should be subscribed to.
2273 _subscribeToItemEvents: function (p_oItem) {
2275 p_oItem.focusEvent.subscribe(this._onMenuItemFocus);
2277 p_oItem.blurEvent.subscribe(this._onMenuItemBlur);
2279 p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2281 p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,
2282 p_oItem, this);
2288 * @method _onVisibleChange
2289 * @description Change event handler for the the menu's "visible" configuration
2290 * property.
2291 * @private
2292 * @param {String} p_sType String representing the name of the event that
2293 * was fired.
2294 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2296 _onVisibleChange: function (p_sType, p_aArgs) {
2298 var bVisible = p_aArgs[0];
2300 if (bVisible) {
2302 Dom.addClass(this.element, "visible");
2305 else {
2307 Dom.removeClass(this.element, "visible");
2315 * @method _cancelHideDelay
2316 * @description Cancels the call to "hideMenu."
2317 * @private
2319 _cancelHideDelay: function () {
2321 var oRoot = this.getRoot();
2323 if (oRoot._nHideDelayId) {
2325 window.clearTimeout(oRoot._nHideDelayId);
2333 * @method _execHideDelay
2334 * @description Hides the menu after the number of milliseconds specified by
2335 * the "hidedelay" configuration property.
2336 * @private
2338 _execHideDelay: function () {
2340 this._cancelHideDelay();
2342 var oRoot = this.getRoot(),
2343 me = this;
2345 function hideMenu() {
2347 if (oRoot.activeItem) {
2349 oRoot.clearActiveItem();
2353 if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) &&
2354 me.cfg.getProperty("position") == "dynamic") {
2356 me.hide();
2363 oRoot._nHideDelayId =
2364 window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));
2370 * @method _cancelShowDelay
2371 * @description Cancels the call to the "showMenu."
2372 * @private
2374 _cancelShowDelay: function () {
2376 var oRoot = this.getRoot();
2378 if (oRoot._nShowDelayId) {
2380 window.clearTimeout(oRoot._nShowDelayId);
2388 * @method _execShowDelay
2389 * @description Shows the menu after the number of milliseconds specified by
2390 * the "showdelay" configuration property have ellapsed.
2391 * @private
2392 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should
2393 * be made visible.
2395 _execShowDelay: function (p_oMenu) {
2397 var oRoot = this.getRoot();
2399 function showMenu() {
2401 if (p_oMenu.parent.cfg.getProperty("selected")) {
2403 p_oMenu.show();
2410 oRoot._nShowDelayId =
2411 window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));
2417 * @method _execSubmenuHideDelay
2418 * @description Hides a submenu after the number of milliseconds specified by
2419 * the "submenuhidedelay" configuration property have ellapsed.
2420 * @private
2421 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
2422 * should be hidden.
2423 * @param {Number} p_nMouseX The x coordinate of the mouse when it left
2424 * the specified submenu's parent menu item.
2425 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2426 * before the submenu is hidden.
2428 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2430 var me = this;
2432 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2434 if (me._nCurrentMouseX > (p_nMouseX + 10)) {
2436 p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
2438 p_oSubmenu.hide();
2440 }, p_nHideDelay);
2443 else {
2445 p_oSubmenu.hide();
2449 }, 50);
2455 // Protected methods
2459 * @method _disableScrollHeader
2460 * @description Disables the header used for scrolling the body of the menu.
2461 * @protected
2463 _disableScrollHeader: function () {
2465 if (!this._bHeaderDisabled) {
2467 Dom.addClass(this.header, "topscrollbar_disabled");
2468 this._bHeaderDisabled = true;
2476 * @method _disableScrollFooter
2477 * @description Disables the footer used for scrolling the body of the menu.
2478 * @protected
2480 _disableScrollFooter: function () {
2482 if (!this._bFooterDisabled) {
2484 Dom.addClass(this.footer, "bottomscrollbar_disabled");
2485 this._bFooterDisabled = true;
2493 * @method _enableScrollHeader
2494 * @description Enables the header used for scrolling the body of the menu.
2495 * @protected
2497 _enableScrollHeader: function () {
2499 if (this._bHeaderDisabled) {
2501 Dom.removeClass(this.header, "topscrollbar_disabled");
2502 this._bHeaderDisabled = false;
2510 * @method _enableScrollFooter
2511 * @description Enables the footer used for scrolling the body of the menu.
2512 * @protected
2514 _enableScrollFooter: function () {
2516 if (this._bFooterDisabled) {
2518 Dom.removeClass(this.footer, "bottomscrollbar_disabled");
2519 this._bFooterDisabled = false;
2527 * @method _onMouseOver
2528 * @description "mouseover" event handler for the menu.
2529 * @protected
2530 * @param {String} p_sType String representing the name of the event that
2531 * was fired.
2532 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2534 _onMouseOver: function (p_sType, p_aArgs) {
2536 if (this._bStopMouseEventHandlers) {
2538 return false;
2543 var oEvent = p_aArgs[0],
2544 oItem = p_aArgs[1],
2545 oTarget = Event.getTarget(oEvent),
2546 oParentMenu,
2547 nShowDelay,
2548 bShowDelay,
2549 oActiveItem,
2550 oItemCfg,
2551 oSubmenu;
2554 if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
2555 Dom.isAncestor(this.element, oTarget))) {
2557 // Menu mouseover logic
2559 this._nCurrentMouseX = 0;
2561 Event.on(this.element, "mousemove", this._onMouseMove, this, true);
2563 this.clearActiveItem();
2566 if (this.parent && this._nSubmenuHideDelayId) {
2568 window.clearTimeout(this._nSubmenuHideDelayId);
2570 this.parent.cfg.setProperty("selected", true);
2572 oParentMenu = this.parent.parent;
2574 oParentMenu._bHandledMouseOutEvent = true;
2575 oParentMenu._bHandledMouseOverEvent = false;
2580 this._bHandledMouseOverEvent = true;
2581 this._bHandledMouseOutEvent = false;
2586 if (oItem && !oItem.handledMouseOverEvent &&
2587 !oItem.cfg.getProperty("disabled") &&
2588 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2590 // Menu Item mouseover logic
2592 nShowDelay = this.cfg.getProperty("showdelay");
2593 bShowDelay = (nShowDelay > 0);
2596 if (bShowDelay) {
2598 this._cancelShowDelay();
2603 oActiveItem = this.activeItem;
2605 if (oActiveItem) {
2607 oActiveItem.cfg.setProperty("selected", false);
2612 oItemCfg = oItem.cfg;
2614 // Select and focus the current menu item
2616 oItemCfg.setProperty("selected", true);
2619 if (this.hasFocus()) {
2621 oItem.focus();
2626 if (this.cfg.getProperty("autosubmenudisplay")) {
2628 // Show the submenu this menu item
2630 oSubmenu = oItemCfg.getProperty("submenu");
2632 if (oSubmenu) {
2634 if (bShowDelay) {
2636 this._execShowDelay(oSubmenu);
2639 else {
2641 oSubmenu.show();
2649 oItem.handledMouseOverEvent = true;
2650 oItem.handledMouseOutEvent = false;
2658 * @method _onMouseOut
2659 * @description "mouseout" event handler for the menu.
2660 * @protected
2661 * @param {String} p_sType String representing the name of the event that
2662 * was fired.
2663 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2665 _onMouseOut: function (p_sType, p_aArgs) {
2667 if (this._bStopMouseEventHandlers) {
2669 return false;
2674 var oEvent = p_aArgs[0],
2675 oItem = p_aArgs[1],
2676 oRelatedTarget = Event.getRelatedTarget(oEvent),
2677 bMovingToSubmenu = false,
2678 oItemCfg,
2679 oSubmenu,
2680 nSubmenuHideDelay,
2681 nShowDelay;
2684 if (oItem && !oItem.cfg.getProperty("disabled")) {
2686 oItemCfg = oItem.cfg;
2687 oSubmenu = oItemCfg.getProperty("submenu");
2690 if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2691 Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2693 bMovingToSubmenu = true;
2698 if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
2699 !Dom.isAncestor(oItem.element, oRelatedTarget)) ||
2700 bMovingToSubmenu)) {
2702 // Menu Item mouseout logic
2704 if (!bMovingToSubmenu) {
2706 oItem.cfg.setProperty("selected", false);
2709 if (oSubmenu) {
2711 nSubmenuHideDelay =
2712 this.cfg.getProperty("submenuhidedelay");
2714 nShowDelay = this.cfg.getProperty("showdelay");
2716 if (!(this instanceof YAHOO.widget.MenuBar) &&
2717 nSubmenuHideDelay > 0 &&
2718 nShowDelay >= nSubmenuHideDelay) {
2720 this._execSubmenuHideDelay(oSubmenu,
2721 Event.getPageX(oEvent),
2722 nSubmenuHideDelay);
2725 else {
2727 oSubmenu.hide();
2736 oItem.handledMouseOutEvent = true;
2737 oItem.handledMouseOverEvent = false;
2744 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
2745 !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2747 // Menu mouseout logic
2749 Event.removeListener(this.element, "mousemove", this._onMouseMove);
2751 this._nCurrentMouseX = Event.getPageX(oEvent);
2753 this._bHandledMouseOutEvent = true;
2754 this._bHandledMouseOverEvent = false;
2762 * @method _onMouseMove
2763 * @description "click" event handler for the menu.
2764 * @protected
2765 * @param {Event} p_oEvent Object representing the DOM event object passed
2766 * back by the event utility (YAHOO.util.Event).
2767 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2768 * fired the event.
2770 _onMouseMove: function (p_oEvent, p_oMenu) {
2772 if (this._bStopMouseEventHandlers) {
2774 return false;
2778 this._nCurrentMouseX = Event.getPageX(p_oEvent);
2784 * @method _onClick
2785 * @description "click" event handler for the menu.
2786 * @protected
2787 * @param {String} p_sType String representing the name of the event that
2788 * was fired.
2789 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2791 _onClick: function (p_sType, p_aArgs) {
2793 var oEvent = p_aArgs[0],
2794 oItem = p_aArgs[1],
2795 bInMenuAnchor = false,
2796 oSubmenu,
2797 oRoot,
2798 sId,
2799 sURL,
2800 nHashPos,
2801 nLen;
2804 if (oItem) {
2806 if (oItem.cfg.getProperty("disabled")) {
2808 Event.preventDefault(oEvent);
2811 else {
2813 oSubmenu = oItem.cfg.getProperty("submenu");
2817 Check if the URL of the anchor is pointing to an element that is
2818 a child of the menu.
2821 sURL = oItem.cfg.getProperty("url");
2824 if (sURL) {
2826 nHashPos = sURL.indexOf("#");
2828 nLen = sURL.length;
2831 if (nHashPos != -1) {
2833 sURL = sURL.substr(nHashPos, nLen);
2835 nLen = sURL.length;
2838 if (nLen > 1) {
2840 sId = sURL.substr(1, nLen);
2842 bInMenuAnchor = Dom.isAncestor(this.element, sId);
2845 else if (nLen === 1) {
2847 bInMenuAnchor = true;
2857 if (bInMenuAnchor && !oItem.cfg.getProperty("target")) {
2859 Event.preventDefault(oEvent);
2862 if (UA.webkit) {
2864 oItem.focus();
2867 else {
2869 oItem.focusEvent.fire();
2876 if (!oSubmenu) {
2879 There is an inconsistency between Firefox 2 for Mac OS X and Firefox 2 Windows
2880 regarding the triggering of the display of the browser's context menu and the
2881 subsequent firing of the "click" event. In Firefox for Windows, when the user
2882 triggers the display of the browser's context menu the "click" event also fires
2883 for the document object, even though the "click" event did not fire for the
2884 element that was the original target of the "contextmenu" event. This is unique
2885 to Firefox on Windows. For all other A-Grade browsers, including Firefox 2 for
2886 Mac OS X, the "click" event doesn't fire for the document object.
2888 This bug in Firefox 2 for Windows affects Menu as Menu instances listen for
2889 events at the document level and have an internal "click" event handler they
2890 use to hide themselves when clicked. As a result, in Firefox for Windows a
2891 Menu will hide when the user right clicks on a MenuItem to raise the browser's
2892 default context menu, because its internal "click" event handler ends up
2893 getting called. The following line fixes this bug.
2896 if ((UA.gecko && this.platform == "windows") && oEvent.button > 0) {
2898 return;
2902 oRoot = this.getRoot();
2904 if (oRoot instanceof YAHOO.widget.MenuBar ||
2905 oRoot.cfg.getProperty("position") == "static") {
2907 oRoot.clearActiveItem();
2910 else {
2912 oRoot.hide();
2926 * @method _onKeyDown
2927 * @description "keydown" event handler for the menu.
2928 * @protected
2929 * @param {String} p_sType String representing the name of the event that
2930 * was fired.
2931 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2933 _onKeyDown: function (p_sType, p_aArgs) {
2935 var oEvent = p_aArgs[0],
2936 oItem = p_aArgs[1],
2937 me = this,
2938 oSubmenu,
2939 oItemCfg,
2940 oParentItem,
2941 oRoot,
2942 oNextItem,
2943 oBody,
2944 nBodyScrollTop,
2945 nBodyOffsetHeight,
2946 aItems,
2947 nItems,
2948 nNextItemOffsetTop,
2949 nScrollTarget,
2950 oParentMenu;
2954 This function is called to prevent a bug in Firefox. In Firefox,
2955 moving a DOM element into a stationary mouse pointer will cause the
2956 browser to fire mouse events. This can result in the menu mouse
2957 event handlers being called uncessarily, especially when menus are
2958 moved into a stationary mouse pointer as a result of a
2959 key event handler.
2961 function stopMouseEventHandlers() {
2963 me._bStopMouseEventHandlers = true;
2965 window.setTimeout(function () {
2967 me._bStopMouseEventHandlers = false;
2969 }, 10);
2974 if (oItem && !oItem.cfg.getProperty("disabled")) {
2976 oItemCfg = oItem.cfg;
2977 oParentItem = this.parent;
2979 switch(oEvent.keyCode) {
2981 case 38: // Up arrow
2982 case 40: // Down arrow
2984 oNextItem = (oEvent.keyCode == 38) ?
2985 oItem.getPreviousEnabledSibling() :
2986 oItem.getNextEnabledSibling();
2988 if (oNextItem) {
2990 this.clearActiveItem();
2992 oNextItem.cfg.setProperty("selected", true);
2993 oNextItem.focus();
2996 if (this.cfg.getProperty("maxheight") > 0) {
2998 oBody = this.body;
2999 nBodyScrollTop = oBody.scrollTop;
3000 nBodyOffsetHeight = oBody.offsetHeight;
3001 aItems = this.getItems();
3002 nItems = aItems.length - 1;
3003 nNextItemOffsetTop = oNextItem.element.offsetTop;
3006 if (oEvent.keyCode == 40 ) { // Down
3008 if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3010 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3013 else if (nNextItemOffsetTop <= nBodyScrollTop) {
3015 oBody.scrollTop = 0;
3020 if (oNextItem == aItems[nItems]) {
3022 oBody.scrollTop = oNextItem.element.offsetTop;
3027 else { // Up
3029 if (nNextItemOffsetTop <= nBodyScrollTop) {
3031 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3034 else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3036 oBody.scrollTop = nNextItemOffsetTop;
3041 if (oNextItem == aItems[0]) {
3043 oBody.scrollTop = 0;
3050 nBodyScrollTop = oBody.scrollTop;
3051 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3053 if (nBodyScrollTop === 0) {
3055 this._disableScrollHeader();
3056 this._enableScrollFooter();
3059 else if (nBodyScrollTop == nScrollTarget) {
3061 this._enableScrollHeader();
3062 this._disableScrollFooter();
3065 else {
3067 this._enableScrollHeader();
3068 this._enableScrollFooter();
3077 Event.preventDefault(oEvent);
3079 stopMouseEventHandlers();
3081 break;
3084 case 39: // Right arrow
3086 oSubmenu = oItemCfg.getProperty("submenu");
3088 if (oSubmenu) {
3090 if (!oItemCfg.getProperty("selected")) {
3092 oItemCfg.setProperty("selected", true);
3096 oSubmenu.show();
3097 oSubmenu.setInitialFocus();
3098 oSubmenu.setInitialSelection();
3101 else {
3103 oRoot = this.getRoot();
3105 if (oRoot instanceof YAHOO.widget.MenuBar) {
3107 oNextItem = oRoot.activeItem.getNextEnabledSibling();
3109 if (oNextItem) {
3111 oRoot.clearActiveItem();
3113 oNextItem.cfg.setProperty("selected", true);
3115 oSubmenu = oNextItem.cfg.getProperty("submenu");
3117 if (oSubmenu) {
3119 oSubmenu.show();
3123 oNextItem.focus();
3132 Event.preventDefault(oEvent);
3134 stopMouseEventHandlers();
3136 break;
3139 case 37: // Left arrow
3141 if (oParentItem) {
3143 oParentMenu = oParentItem.parent;
3145 if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3147 oNextItem =
3148 oParentMenu.activeItem.getPreviousEnabledSibling();
3150 if (oNextItem) {
3152 oParentMenu.clearActiveItem();
3154 oNextItem.cfg.setProperty("selected", true);
3156 oSubmenu = oNextItem.cfg.getProperty("submenu");
3158 if (oSubmenu) {
3160 oSubmenu.show();
3164 oNextItem.focus();
3169 else {
3171 this.hide();
3173 oParentItem.focus();
3179 Event.preventDefault(oEvent);
3181 stopMouseEventHandlers();
3183 break;
3191 if (oEvent.keyCode == 27) { // Esc key
3193 if (this.cfg.getProperty("position") == "dynamic") {
3195 this.hide();
3197 if (this.parent) {
3199 this.parent.focus();
3204 else if (this.activeItem) {
3206 oSubmenu = this.activeItem.cfg.getProperty("submenu");
3208 if (oSubmenu && oSubmenu.cfg.getProperty("visible")) {
3210 oSubmenu.hide();
3211 this.activeItem.focus();
3214 else {
3216 this.activeItem.blur();
3217 this.activeItem.cfg.setProperty("selected", false);
3224 Event.preventDefault(oEvent);
3232 * @method _onKeyPress
3233 * @description "keypress" event handler for a Menu instance.
3234 * @protected
3235 * @param {String} p_sType The name of the event that was fired.
3236 * @param {Array} p_aArgs Collection of arguments sent when the event
3237 * was fired.
3239 _onKeyPress: function (p_sType, p_aArgs) {
3241 var oEvent = p_aArgs[0];
3244 if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3246 Event.preventDefault(oEvent);
3254 * @method _onYChange
3255 * @description "y" event handler for a Menu instance.
3256 * @protected
3257 * @param {String} p_sType The name of the event that was fired.
3258 * @param {Array} p_aArgs Collection of arguments sent when the event
3259 * was fired.
3261 _onYChange: function (p_sType, p_aArgs) {
3263 var oParent = this.parent,
3264 nScrollTop,
3265 oIFrame,
3269 if (oParent) {
3271 nScrollTop = oParent.parent.body.scrollTop;
3274 if (nScrollTop > 0) {
3276 nY = (this.cfg.getProperty("y") - nScrollTop);
3278 Dom.setY(this.element, nY);
3280 oIFrame = this.iframe;
3283 if (oIFrame) {
3285 Dom.setY(oIFrame, nY);
3289 this.cfg.setProperty("y", nY, true);
3299 * @method _onScrollTargetMouseOver
3300 * @description "mouseover" event handler for the menu's "header" and "footer"
3301 * elements. Used to scroll the body of the menu up and down when the
3302 * menu's "maxheight" configuration property is set to a value greater than 0.
3303 * @protected
3304 * @param {Event} p_oEvent Object representing the DOM event object passed
3305 * back by the event utility (YAHOO.util.Event).
3306 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3307 * fired the event.
3309 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3311 this._cancelHideDelay();
3313 var oTarget = Event.getTarget(p_oEvent),
3314 oBody = this.body,
3315 me = this,
3316 nScrollIncrement = this.cfg.getProperty("scrollincrement"),
3317 nScrollTarget,
3318 fnScrollFunction;
3321 function scrollBodyDown() {
3323 var nScrollTop = oBody.scrollTop;
3326 if (nScrollTop < nScrollTarget) {
3328 oBody.scrollTop = (nScrollTop + nScrollIncrement);
3330 me._enableScrollHeader();
3333 else {
3335 oBody.scrollTop = nScrollTarget;
3337 window.clearInterval(me._nBodyScrollId);
3339 me._disableScrollFooter();
3346 function scrollBodyUp() {
3348 var nScrollTop = oBody.scrollTop;
3351 if (nScrollTop > 0) {
3353 oBody.scrollTop = (nScrollTop - nScrollIncrement);
3355 me._enableScrollFooter();
3358 else {
3360 oBody.scrollTop = 0;
3362 window.clearInterval(me._nBodyScrollId);
3364 me._disableScrollHeader();
3371 if (Dom.hasClass(oTarget, "hd")) {
3373 fnScrollFunction = scrollBodyUp;
3376 else {
3378 nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3380 fnScrollFunction = scrollBodyDown;
3385 this._nBodyScrollId = window.setInterval(fnScrollFunction, 10);
3391 * @method _onScrollTargetMouseOut
3392 * @description "mouseout" event handler for the menu's "header" and "footer"
3393 * elements. Used to stop scrolling the body of the menu up and down when the
3394 * menu's "maxheight" configuration property is set to a value greater than 0.
3395 * @protected
3396 * @param {Event} p_oEvent Object representing the DOM event object passed
3397 * back by the event utility (YAHOO.util.Event).
3398 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3399 * fired the event.
3401 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3403 window.clearInterval(this._nBodyScrollId);
3405 this._cancelHideDelay();
3411 // Private methods
3415 * @method _onInit
3416 * @description "init" event handler for the menu.
3417 * @private
3418 * @param {String} p_sType String representing the name of the event that
3419 * was fired.
3420 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3422 _onInit: function (p_sType, p_aArgs) {
3424 this.cfg.subscribeToConfigEvent("visible", this._onVisibleChange);
3426 var bRootMenu = !this.parent,
3427 bLazyLoad = this.lazyLoad;
3431 Automatically initialize a menu's subtree if:
3433 1) This is the root menu and lazyload is off
3435 2) This is the root menu, lazyload is on, but the menu is
3436 already visible
3438 3) This menu is a submenu and lazyload is off
3443 if (((bRootMenu && !bLazyLoad) ||
3444 (bRootMenu && (this.cfg.getProperty("visible") ||
3445 this.cfg.getProperty("position") == "static")) ||
3446 (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3448 if (this.srcElement) {
3450 this._initSubTree();
3455 if (this.itemData) {
3457 this.addItems(this.itemData);
3462 else if (bLazyLoad) {
3464 this.cfg.fireQueue();
3472 * @method _onBeforeRender
3473 * @description "beforerender" event handler for the menu. Appends all of the
3474 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
3475 * title elements to the body element of the menu.
3476 * @private
3477 * @param {String} p_sType String representing the name of the event that
3478 * was fired.
3479 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3481 _onBeforeRender: function (p_sType, p_aArgs) {
3483 var oEl = this.element,
3484 nListElements = this._aListElements.length,
3485 bFirstList = true,
3486 i = 0,
3487 oUL,
3488 oGroupTitle;
3490 if (nListElements > 0) {
3492 do {
3494 oUL = this._aListElements[i];
3496 if (oUL) {
3498 if (bFirstList) {
3500 Dom.addClass(oUL, "first-of-type");
3501 bFirstList = false;
3506 if (!Dom.isAncestor(oEl, oUL)) {
3508 this.appendToBody(oUL);
3513 oGroupTitle = this._aGroupTitleElements[i];
3515 if (oGroupTitle) {
3517 if (!Dom.isAncestor(oEl, oGroupTitle)) {
3519 oUL.parentNode.insertBefore(oGroupTitle, oUL);
3524 Dom.addClass(oUL, "hastitle");
3530 i++;
3533 while(i < nListElements);
3541 * @method _onRender
3542 * @description "render" event handler for the menu.
3543 * @private
3544 * @param {String} p_sType String representing the name of the event that
3545 * was fired.
3546 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3548 _onRender: function (p_sType, p_aArgs) {
3550 if (this.cfg.getProperty("position") == "dynamic") {
3552 if (!this.cfg.getProperty("visible")) {
3554 this.positionOffScreen();
3567 * @method _onBeforeShow
3568 * @description "beforeshow" event handler for the menu.
3569 * @private
3570 * @param {String} p_sType String representing the name of the event that
3571 * was fired.
3572 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3574 _onBeforeShow: function (p_sType, p_aArgs) {
3576 var nOptions,
3578 nViewportHeight,
3579 oRegion,
3580 oSrcElement;
3583 if (this.lazyLoad && this.getItemGroups().length === 0) {
3585 if (this.srcElement) {
3587 this._initSubTree();
3592 if (this.itemData) {
3594 if (this.parent && this.parent.parent &&
3595 this.parent.parent.srcElement &&
3596 this.parent.parent.srcElement.tagName.toUpperCase() ==
3597 "SELECT") {
3599 nOptions = this.itemData.length;
3601 for(n=0; n<nOptions; n++) {
3603 if (this.itemData[n].tagName) {
3605 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3612 else {
3614 this.addItems(this.itemData);
3621 oSrcElement = this.srcElement;
3623 if (oSrcElement) {
3625 if (oSrcElement.tagName.toUpperCase() == "SELECT") {
3627 if (Dom.inDocument(oSrcElement)) {
3629 this.render(oSrcElement.parentNode);
3632 else {
3634 this.render(this.cfg.getProperty("container"));
3639 else {
3641 this.render();
3646 else {
3648 if (this.parent) {
3650 this.render(this.parent.element);
3653 else {
3655 this.render(this.cfg.getProperty("container"));
3664 var nMaxHeight = this.cfg.getProperty("maxheight"),
3665 nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
3666 bDynamicPos = this.cfg.getProperty("position") == "dynamic";
3669 if (!this.parent && bDynamicPos) {
3671 this.cfg.refireEvent("xy");
3676 function clearMaxHeight() {
3678 this.cfg.setProperty("maxheight", 0);
3680 this.hideEvent.unsubscribe(clearMaxHeight);
3685 if (!(this instanceof YAHOO.widget.MenuBar) && bDynamicPos) {
3688 if (nMaxHeight === 0) {
3690 nViewportHeight = Dom.getViewportHeight();
3693 if (this.parent &&
3694 this.parent.parent instanceof YAHOO.widget.MenuBar) {
3696 oRegion = YAHOO.util.Region.getRegion(this.parent.element);
3698 nViewportHeight = (nViewportHeight - oRegion.bottom);
3703 if (this.element.offsetHeight >= nViewportHeight) {
3705 nMaxHeight = (nViewportHeight - (Overlay.VIEWPORT_OFFSET * 2));
3707 if (nMaxHeight < nMinScrollHeight) {
3709 nMaxHeight = nMinScrollHeight;
3713 this.cfg.setProperty("maxheight", nMaxHeight);
3715 this.hideEvent.subscribe(clearMaxHeight);
3727 * @method _onShow
3728 * @description "show" event handler for the menu.
3729 * @private
3730 * @param {String} p_sType String representing the name of the event that
3731 * was fired.
3732 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3734 _onShow: function (p_sType, p_aArgs) {
3736 var oParent = this.parent,
3737 oParentMenu,
3738 aParentAlignment,
3739 aAlignment;
3742 function disableAutoSubmenuDisplay(p_oEvent) {
3744 var oTarget;
3746 if (p_oEvent.type == "mousedown" || (p_oEvent.type == "keydown" &&
3747 p_oEvent.keyCode == 27)) {
3750 Set the "autosubmenudisplay" to "false" if the user
3751 clicks outside the menu bar.
3754 oTarget = Event.getTarget(p_oEvent);
3756 if (oTarget != oParentMenu.element ||
3757 !Dom.isAncestor(oParentMenu.element, oTarget)) {
3759 oParentMenu.cfg.setProperty("autosubmenudisplay", false);
3761 Event.removeListener(document, "mousedown",
3762 disableAutoSubmenuDisplay);
3764 Event.removeListener(document, "keydown",
3765 disableAutoSubmenuDisplay);
3774 if (oParent) {
3776 oParentMenu = oParent.parent;
3777 aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
3778 aAlignment = this.cfg.getProperty("submenualignment");
3781 if ((aParentAlignment[0] != aAlignment[0]) &&
3782 (aParentAlignment[1] != aAlignment[1])) {
3784 this.cfg.setProperty("submenualignment",
3785 [aParentAlignment[0], aParentAlignment[1]]);
3790 if (!oParentMenu.cfg.getProperty("autosubmenudisplay") &&
3791 (oParentMenu instanceof YAHOO.widget.MenuBar ||
3792 oParentMenu.cfg.getProperty("position") == "static")) {
3794 oParentMenu.cfg.setProperty("autosubmenudisplay", true);
3796 Event.on(document, "mousedown", disableAutoSubmenuDisplay);
3797 Event.on(document, "keydown", disableAutoSubmenuDisplay);
3807 * @method _onBeforeHide
3808 * @description "beforehide" event handler for the menu.
3809 * @private
3810 * @param {String} p_sType String representing the name of the event that
3811 * was fired.
3812 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3814 _onBeforeHide: function (p_sType, p_aArgs) {
3816 var oActiveItem = this.activeItem,
3817 oConfig,
3818 oSubmenu;
3820 if (oActiveItem) {
3822 oConfig = oActiveItem.cfg;
3824 oConfig.setProperty("selected", false);
3826 oSubmenu = oConfig.getProperty("submenu");
3828 if (oSubmenu) {
3830 oSubmenu.hide();
3836 if (this.getRoot() == this) {
3838 this.blur();
3846 * @method _onParentMenuConfigChange
3847 * @description "configchange" event handler for a submenu.
3848 * @private
3849 * @param {String} p_sType String representing the name of the event that
3850 * was fired.
3851 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3852 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3853 * subscribed to the event.
3855 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
3857 var sPropertyName = p_aArgs[0][0],
3858 oPropertyValue = p_aArgs[0][1];
3860 switch(sPropertyName) {
3862 case "iframe":
3863 case "constraintoviewport":
3864 case "hidedelay":
3865 case "showdelay":
3866 case "submenuhidedelay":
3867 case "clicktohide":
3868 case "effect":
3869 case "classname":
3870 case "scrollincrement":
3871 case "minscrollheight":
3873 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
3875 break;
3883 * @method _onParentMenuRender
3884 * @description "render" event handler for a submenu. Renders a
3885 * submenu in response to the firing of its parent's "render" event.
3886 * @private
3887 * @param {String} p_sType String representing the name of the event that
3888 * was fired.
3889 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3890 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
3891 * subscribed to the event.
3893 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
3895 var oParentCfg = p_oSubmenu.parent.parent.cfg,
3897 oConfig = {
3899 constraintoviewport: oParentCfg.getProperty("constraintoviewport"),
3901 xy: [0,0],
3903 clicktohide: oParentCfg.getProperty("clicktohide"),
3905 effect: oParentCfg.getProperty("effect"),
3907 showdelay: oParentCfg.getProperty("showdelay"),
3909 hidedelay: oParentCfg.getProperty("hidedelay"),
3911 submenuhidedelay: oParentCfg.getProperty("submenuhidedelay"),
3913 classname: oParentCfg.getProperty("classname"),
3915 scrollincrement: oParentCfg.getProperty("scrollincrement"),
3917 minscrollheight: oParentCfg.getProperty("minscrollheight"),
3919 iframe: oParentCfg.getProperty("iframe")
3923 oLI;
3926 p_oSubmenu.cfg.applyConfig(oConfig);
3929 if (!this.lazyLoad) {
3931 oLI = this.parent.element;
3933 if (this.element.parentNode == oLI) {
3935 this.render();
3938 else {
3940 this.render(oLI);
3950 * @method _onSubmenuBeforeShow
3951 * @description "beforeshow" event handler for a submenu.
3952 * @private
3953 * @param {String} p_sType String representing the name of the event that
3954 * was fired.
3955 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3957 _onSubmenuBeforeShow: function (p_sType, p_aArgs) {
3959 var oParent = this.parent,
3960 aAlignment = oParent.parent.cfg.getProperty("submenualignment");
3963 if (!this.cfg.getProperty("context")) {
3965 this.cfg.setProperty("context",
3966 [oParent.element, aAlignment[0], aAlignment[1]]);
3969 else {
3971 this.align();
3979 * @method _onMenuItemFocus
3980 * @description "focus" event handler for the menu's items.
3981 * @private
3982 * @param {String} p_sType String representing the name of the event that
3983 * was fired.
3984 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3986 _onMenuItemFocus: function (p_sType, p_aArgs) {
3988 this.parent.focusEvent.fire(this);
3994 * @method _onMenuItemBlur
3995 * @description "blur" event handler for the menu's items.
3996 * @private
3997 * @param {String} p_sType String representing the name of the event
3998 * that was fired.
3999 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4001 _onMenuItemBlur: function (p_sType, p_aArgs) {
4003 this.parent.blurEvent.fire(this);
4009 * @method _onMenuItemDestroy
4010 * @description "destroy" event handler for the menu's items.
4011 * @private
4012 * @param {String} p_sType String representing the name of the event
4013 * that was fired.
4014 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4015 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4016 * that fired the event.
4018 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4020 this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4026 * @method _onMenuItemConfigChange
4027 * @description "configchange" event handler for the menu's items.
4028 * @private
4029 * @param {String} p_sType String representing the name of the event that
4030 * was fired.
4031 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4032 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4033 * that fired the event.
4035 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4037 var sPropertyName = p_aArgs[0][0],
4038 oPropertyValue = p_aArgs[0][1],
4039 oSubmenu;
4042 switch(sPropertyName) {
4044 case "selected":
4046 if (oPropertyValue === true) {
4048 this.activeItem = p_oItem;
4052 break;
4054 case "submenu":
4056 oSubmenu = p_aArgs[0][1];
4058 if (oSubmenu) {
4060 this._configureSubmenu(p_oItem);
4064 break;
4072 // Public event handlers for configuration properties
4076 * @method enforceConstraints
4077 * @description The default event handler executed when the moveEvent is fired,
4078 * if the "constraintoviewport" configuration property is set to true.
4079 * @param {String} type The name of the event that was fired.
4080 * @param {Array} args Collection of arguments sent when the
4081 * event was fired.
4082 * @param {Array} obj Array containing the current Menu instance
4083 * and the item that fired the event.
4085 enforceConstraints: function (type, args, obj) {
4087 YAHOO.widget.Menu.superclass.enforceConstraints.apply(this, arguments);
4089 var oParent = this.parent,
4090 oParentMenu,
4091 nParentMenuX,
4092 nNewX,
4096 if (oParent) {
4098 oParentMenu = oParent.parent;
4100 if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4102 nParentMenuX = oParentMenu.cfg.getProperty("x");
4103 nX = this.cfg.getProperty("x");
4106 if (nX < (nParentMenuX + oParent.element.offsetWidth)) {
4108 nNewX = (nParentMenuX - this.element.offsetWidth);
4110 this.cfg.setProperty("x", nNewX, true);
4111 this.cfg.setProperty("xy", [nNewX, (this.cfg.getProperty("y"))], true);
4123 * @method configVisible
4124 * @description Event handler for when the "visible" configuration property
4125 * the menu changes.
4126 * @param {String} p_sType String representing the name of the event that
4127 * was fired.
4128 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4129 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4130 * fired the event.
4132 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4134 var bVisible,
4135 sDisplay;
4137 if (this.cfg.getProperty("position") == "dynamic") {
4139 Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4142 else {
4144 bVisible = p_aArgs[0];
4145 sDisplay = Dom.getStyle(this.element, "display");
4147 Dom.setStyle(this.element, "visibility", "visible");
4149 if (bVisible) {
4151 if (sDisplay != "block") {
4152 this.beforeShowEvent.fire();
4153 Dom.setStyle(this.element, "display", "block");
4154 this.showEvent.fire();
4158 else {
4160 if (sDisplay == "block") {
4161 this.beforeHideEvent.fire();
4162 Dom.setStyle(this.element, "display", "none");
4163 this.hideEvent.fire();
4174 * @method configPosition
4175 * @description Event handler for when the "position" configuration property
4176 * of the menu changes.
4177 * @param {String} p_sType String representing the name of the event that
4178 * was fired.
4179 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4180 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4181 * fired the event.
4183 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4185 var oElement = this.element,
4186 sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute",
4187 oCfg = this.cfg,
4188 nZIndex;
4191 Dom.setStyle(oElement, "position", sCSSPosition);
4194 if (sCSSPosition == "static") {
4196 // Statically positioned menus are visible by default
4198 Dom.setStyle(oElement, "display", "block");
4200 oCfg.setProperty("visible", true);
4203 else {
4206 Even though the "visible" property is queued to
4207 "false" by default, we need to set the "visibility" property to
4208 "hidden" since Overlay's "configVisible" implementation checks the
4209 element's "visibility" style property before deciding whether
4210 or not to show an Overlay instance.
4213 Dom.setStyle(oElement, "visibility", "hidden");
4218 if (sCSSPosition == "absolute") {
4220 nZIndex = oCfg.getProperty("zindex");
4222 if (!nZIndex || nZIndex === 0) {
4224 nZIndex = this.parent ?
4225 (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;
4227 oCfg.setProperty("zindex", nZIndex);
4237 * @method configIframe
4238 * @description Event handler for when the "iframe" configuration property of
4239 * the menu changes.
4240 * @param {String} p_sType String representing the name of the event that
4241 * was fired.
4242 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4243 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4244 * fired the event.
4246 configIframe: function (p_sType, p_aArgs, p_oMenu) {
4248 if (this.cfg.getProperty("position") == "dynamic") {
4250 Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4258 * @method configHideDelay
4259 * @description Event handler for when the "hidedelay" configuration property
4260 * of the menu changes.
4261 * @param {String} p_sType String representing the name of the event that
4262 * was fired.
4263 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4264 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4265 * fired the event.
4267 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4269 var nHideDelay = p_aArgs[0],
4270 oMouseOutEvent = this.mouseOutEvent,
4271 oMouseOverEvent = this.mouseOverEvent,
4272 oKeyDownEvent = this.keyDownEvent;
4274 if (nHideDelay > 0) {
4277 Only assign event handlers once. This way the user change
4278 the value for the hidedelay as many times as they want.
4281 if (!this._bHideDelayEventHandlersAssigned) {
4283 oMouseOutEvent.subscribe(this._execHideDelay);
4284 oMouseOverEvent.subscribe(this._cancelHideDelay);
4285 oKeyDownEvent.subscribe(this._cancelHideDelay);
4287 this._bHideDelayEventHandlersAssigned = true;
4292 else {
4294 oMouseOutEvent.unsubscribe(this._execHideDelay);
4295 oMouseOverEvent.unsubscribe(this._cancelHideDelay);
4296 oKeyDownEvent.unsubscribe(this._cancelHideDelay);
4298 this._bHideDelayEventHandlersAssigned = false;
4306 * @method configContainer
4307 * @description Event handler for when the "container" configuration property
4308 * of the menu changes.
4309 * @param {String} p_sType String representing the name of the event that
4310 * was fired.
4311 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4312 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
4313 * fired the event.
4315 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4317 var oElement = p_aArgs[0];
4319 if (typeof oElement == 'string') {
4321 this.cfg.setProperty("container", document.getElementById(oElement),
4322 true);
4330 * @method _setMaxHeight
4331 * @description "renderEvent" handler used to defer the setting of the
4332 * "maxheight" configuration property until the menu is rendered in lazy
4333 * load scenarios.
4334 * @param {String} p_sType The name of the event that was fired.
4335 * @param {Array} p_aArgs Collection of arguments sent when the event
4336 * was fired.
4337 * @param {Number} p_nMaxHeight Number representing the value to set for the
4338 * "maxheight" configuration property.
4339 * @private
4341 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4343 this.cfg.setProperty("maxheight", p_nMaxHeight);
4344 this.renderEvent.unsubscribe(this._setMaxHeight);
4350 * @method configMaxHeight
4351 * @description Event handler for when the "maxheight" configuration property of
4352 * a Menu changes.
4353 * @param {String} p_sType The name of the event that was fired.
4354 * @param {Array} p_aArgs Collection of arguments sent when the event
4355 * was fired.
4356 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4357 * the event.
4359 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4361 var nMaxHeight = p_aArgs[0],
4362 oElement = this.element,
4363 oBody = this.body,
4364 oHeader = this.header,
4365 oFooter = this.footer,
4366 fnMouseOver = this._onScrollTargetMouseOver,
4367 fnMouseOut = this._onScrollTargetMouseOut,
4368 nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
4369 nHeight,
4370 nOffsetWidth,
4371 sWidth;
4374 if (nMaxHeight !== 0 && nMaxHeight < nMinScrollHeight) {
4376 nMaxHeight = nMinScrollHeight;
4381 if (this.lazyLoad && !oBody) {
4383 this.renderEvent.unsubscribe(this._setMaxHeight);
4385 if (nMaxHeight > 0) {
4387 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4391 return;
4396 Dom.setStyle(oBody, "height", "");
4397 Dom.removeClass(oBody, "yui-menu-body-scrolled");
4401 There is a bug in gecko-based browsers where an element whose
4402 "position" property is set to "absolute" and "overflow" property is set
4403 to "hidden" will not render at the correct width when its
4404 offsetParent's "position" property is also set to "absolute." It is
4405 possible to work around this bug by specifying a value for the width
4406 property in addition to overflow.
4408 In IE it is also necessary to give the Menu a width when the scrollbars are
4409 rendered to prevent the Menu from rendering with a width that is 100% of
4410 the browser viewport.
4413 var bSetWidth = ((UA.gecko && this.parent && this.parent.parent &&
4414 this.parent.parent.cfg.getProperty("position") == "dynamic") || UA.ie);
4417 if (bSetWidth) {
4419 if (!this.cfg.getProperty("width")) {
4421 nOffsetWidth = oElement.offsetWidth;
4424 Measuring the difference of the offsetWidth before and after
4425 setting the "width" style attribute allows us to compute the
4426 about of padding and borders applied to the element, which in
4427 turn allows us to set the "width" property correctly.
4430 oElement.style.width = nOffsetWidth + "px";
4432 sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + "px";
4434 this.cfg.setProperty("width", sWidth);
4441 if (!oHeader && !oFooter) {
4443 this.setHeader("&#32;");
4444 this.setFooter("&#32;");
4446 oHeader = this.header;
4447 oFooter = this.footer;
4449 Dom.addClass(oHeader, "topscrollbar");
4450 Dom.addClass(oFooter, "bottomscrollbar");
4452 oElement.insertBefore(oHeader, oBody);
4453 oElement.appendChild(oFooter);
4458 nHeight = (nMaxHeight - (oHeader.offsetHeight + oHeader.offsetHeight));
4461 if (nHeight > 0 && (oBody.offsetHeight > nMaxHeight)) {
4463 Dom.addClass(oBody, "yui-menu-body-scrolled");
4464 Dom.setStyle(oBody, "height", (nHeight + "px"));
4466 Event.on(oHeader, "mouseover", fnMouseOver, this, true);
4467 Event.on(oHeader, "mouseout", fnMouseOut, this, true);
4468 Event.on(oFooter, "mouseover", fnMouseOver, this, true);
4469 Event.on(oFooter, "mouseout", fnMouseOut, this, true);
4471 this._disableScrollHeader();
4472 this._enableScrollFooter();
4475 else if (oHeader && oFooter) {
4477 if (bSetWidth) {
4479 this.cfg.setProperty("width", "");
4484 this._enableScrollHeader();
4485 this._enableScrollFooter();
4487 Event.removeListener(oHeader, "mouseover", fnMouseOver);
4488 Event.removeListener(oHeader, "mouseout", fnMouseOut);
4489 Event.removeListener(oFooter, "mouseover", fnMouseOver);
4490 Event.removeListener(oFooter, "mouseout", fnMouseOut);
4492 oElement.removeChild(oHeader);
4493 oElement.removeChild(oFooter);
4495 this.header = null;
4496 this.footer = null;
4500 this.cfg.refireEvent("iframe");
4506 * @method configClassName
4507 * @description Event handler for when the "classname" configuration property of
4508 * a menu changes.
4509 * @param {String} p_sType The name of the event that was fired.
4510 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4511 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4513 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4515 var sClassName = p_aArgs[0];
4517 if (this._sClassName) {
4519 Dom.removeClass(this.element, this._sClassName);
4523 Dom.addClass(this.element, sClassName);
4524 this._sClassName = sClassName;
4530 * @method _onItemAdded
4531 * @description "itemadded" event handler for a Menu instance.
4532 * @private
4533 * @param {String} p_sType The name of the event that was fired.
4534 * @param {Array} p_aArgs Collection of arguments sent when the event
4535 * was fired.
4537 _onItemAdded: function (p_sType, p_aArgs) {
4539 var oItem = p_aArgs[0];
4541 if (oItem) {
4543 oItem.cfg.setProperty("disabled", true);
4551 * @method configDisabled
4552 * @description Event handler for when the "disabled" configuration property of
4553 * a menu changes.
4554 * @param {String} p_sType The name of the event that was fired.
4555 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4556 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4558 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4560 var bDisabled = p_aArgs[0],
4561 aItems = this.getItems(),
4562 nItems,
4565 if (Lang.isArray(aItems)) {
4567 nItems = aItems.length;
4569 if (nItems > 0) {
4571 i = nItems - 1;
4573 do {
4575 aItems[i].cfg.setProperty("disabled", bDisabled);
4578 while (i--);
4583 if (bDisabled) {
4585 this.clearActiveItem(true);
4587 Dom.addClass(this.element, "disabled");
4589 this.itemAddedEvent.subscribe(this._onItemAdded);
4592 else {
4594 Dom.removeClass(this.element, "disabled");
4596 this.itemAddedEvent.unsubscribe(this._onItemAdded);
4606 * @method onRender
4607 * @description "render" event handler for the menu.
4608 * @param {String} p_sType String representing the name of the event that
4609 * was fired.
4610 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4612 onRender: function (p_sType, p_aArgs) {
4614 function sizeShadow() {
4616 var oElement = this.element,
4617 oShadow = this._shadow;
4619 if (oShadow && oElement) {
4621 // Clear the previous width
4623 if (oShadow.style.width && oShadow.style.height) {
4625 oShadow.style.width = "";
4626 oShadow.style.height = "";
4630 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
4631 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
4638 function replaceShadow() {
4640 this.element.appendChild(this._shadow);
4645 function addShadowVisibleClass() {
4647 Dom.addClass(this._shadow, "yui-menu-shadow-visible");
4652 function removeShadowVisibleClass() {
4654 Dom.removeClass(this._shadow, "yui-menu-shadow-visible");
4659 function createShadow() {
4661 var oShadow = this._shadow,
4662 oElement,
4665 if (!oShadow) {
4667 oElement = this.element;
4668 me = this;
4670 if (!m_oShadowTemplate) {
4672 m_oShadowTemplate = document.createElement("div");
4673 m_oShadowTemplate.className =
4674 "yui-menu-shadow yui-menu-shadow-visible";
4678 oShadow = m_oShadowTemplate.cloneNode(false);
4680 oElement.appendChild(oShadow);
4682 this._shadow = oShadow;
4684 this.beforeShowEvent.subscribe(addShadowVisibleClass);
4685 this.beforeHideEvent.subscribe(removeShadowVisibleClass);
4687 if (UA.ie) {
4690 Need to call sizeShadow & syncIframe via setTimeout for
4691 IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
4692 or the shadow and iframe shim will not be sized and
4693 positioned properly.
4696 window.setTimeout(function () {
4698 sizeShadow.call(me);
4699 me.syncIframe();
4701 }, 0);
4703 this.cfg.subscribeToConfigEvent("width", sizeShadow);
4704 this.cfg.subscribeToConfigEvent("height", sizeShadow);
4705 this.cfg.subscribeToConfigEvent("maxheight", sizeShadow);
4706 this.changeContentEvent.subscribe(sizeShadow);
4708 Module.textResizeEvent.subscribe(sizeShadow, me, true);
4710 this.destroyEvent.subscribe(function () {
4712 Module.textResizeEvent.unsubscribe(sizeShadow, me);
4718 this.cfg.subscribeToConfigEvent("maxheight", replaceShadow);
4725 function onBeforeShow() {
4727 createShadow.call(this);
4729 this.beforeShowEvent.unsubscribe(onBeforeShow);
4734 if (this.cfg.getProperty("position") == "dynamic") {
4736 if (this.cfg.getProperty("visible")) {
4738 createShadow.call(this);
4741 else {
4743 this.beforeShowEvent.subscribe(onBeforeShow);
4752 // Public methods
4756 * @method initEvents
4757 * @description Initializes the custom events for the menu.
4759 initEvents: function () {
4761 Menu.superclass.initEvents.call(this);
4763 // Create custom events
4765 var SIGNATURE = CustomEvent.LIST;
4767 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
4768 this.mouseOverEvent.signature = SIGNATURE;
4770 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
4771 this.mouseOutEvent.signature = SIGNATURE;
4773 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
4774 this.mouseDownEvent.signature = SIGNATURE;
4776 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
4777 this.mouseUpEvent.signature = SIGNATURE;
4779 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
4780 this.clickEvent.signature = SIGNATURE;
4782 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
4783 this.keyPressEvent.signature = SIGNATURE;
4785 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
4786 this.keyDownEvent.signature = SIGNATURE;
4788 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
4789 this.keyUpEvent.signature = SIGNATURE;
4791 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
4792 this.focusEvent.signature = SIGNATURE;
4794 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
4795 this.blurEvent.signature = SIGNATURE;
4797 this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED);
4798 this.itemAddedEvent.signature = SIGNATURE;
4800 this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED);
4801 this.itemRemovedEvent.signature = SIGNATURE;
4807 * @method positionOffScreen
4808 * @description Positions the menu outside of the boundaries of the browser's
4809 * viewport. Called automatically when a menu is hidden to ensure that
4810 * it doesn't force the browser to render uncessary scrollbars.
4812 positionOffScreen: function () {
4814 var oIFrame = this.iframe,
4815 aPos = this.OFF_SCREEN_POSITION;
4817 Dom.setXY(this.element, aPos);
4819 if (oIFrame) {
4821 Dom.setXY(oIFrame, aPos);
4829 * @method getRoot
4830 * @description Finds the menu's root menu.
4832 getRoot: function () {
4834 var oItem = this.parent,
4835 oParentMenu;
4837 if (oItem) {
4839 oParentMenu = oItem.parent;
4841 return oParentMenu ? oParentMenu.getRoot() : this;
4844 else {
4846 return this;
4854 * @method toString
4855 * @description Returns a string representing the menu.
4856 * @return {String}
4858 toString: function () {
4860 var sReturnVal = "Menu",
4861 sId = this.id;
4863 if (sId) {
4865 sReturnVal += (" " + sId);
4869 return sReturnVal;
4875 * @method setItemGroupTitle
4876 * @description Sets the title of a group of menu items.
4877 * @param {String} p_sGroupTitle String specifying the title of the group.
4878 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
4879 * the title belongs.
4881 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
4883 var nGroupIndex,
4884 oTitle,
4886 nFirstIndex;
4888 if (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {
4890 nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
4891 oTitle = this._aGroupTitleElements[nGroupIndex];
4894 if (oTitle) {
4896 oTitle.innerHTML = p_sGroupTitle;
4899 else {
4901 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
4903 oTitle.innerHTML = p_sGroupTitle;
4905 this._aGroupTitleElements[nGroupIndex] = oTitle;
4910 i = this._aGroupTitleElements.length - 1;
4912 do {
4914 if (this._aGroupTitleElements[i]) {
4916 Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");
4918 nFirstIndex = i;
4923 while(i--);
4926 if (nFirstIndex !== null) {
4928 Dom.addClass(this._aGroupTitleElements[nFirstIndex],
4929 "first-of-type");
4933 this.changeContentEvent.fire();
4942 * @method addItem
4943 * @description Appends an item to the menu.
4944 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
4945 * instance to be added to the menu.
4946 * @param {String} p_oItem String specifying the text of the item to be added
4947 * to the menu.
4948 * @param {Object} p_oItem Object literal containing a set of menu item
4949 * configuration properties.
4950 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
4951 * which the item belongs.
4952 * @return {YAHOO.widget.MenuItem}
4954 addItem: function (p_oItem, p_nGroupIndex) {
4956 if (p_oItem) {
4958 return this._addItemToGroup(p_nGroupIndex, p_oItem);
4966 * @method addItems
4967 * @description Adds an array of items to the menu.
4968 * @param {Array} p_aItems Array of items to be added to the menu. The array
4969 * can contain strings specifying the text for each item to be created, object
4970 * literals specifying each of the menu item configuration properties,
4971 * or MenuItem instances.
4972 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
4973 * which the items belongs.
4974 * @return {Array}
4976 addItems: function (p_aItems, p_nGroupIndex) {
4978 var nItems,
4979 aItems,
4980 oItem,
4983 if (Lang.isArray(p_aItems)) {
4985 nItems = p_aItems.length;
4986 aItems = [];
4988 for(i=0; i<nItems; i++) {
4990 oItem = p_aItems[i];
4992 if (oItem) {
4994 if (Lang.isArray(oItem)) {
4996 aItems[aItems.length] = this.addItems(oItem, i);
4999 else {
5001 aItems[aItems.length] =
5002 this._addItemToGroup(p_nGroupIndex, oItem);
5011 if (aItems.length) {
5013 return aItems;
5023 * @method insertItem
5024 * @description Inserts an item into the menu at the specified index.
5025 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
5026 * instance to be added to the menu.
5027 * @param {String} p_oItem String specifying the text of the item to be added
5028 * to the menu.
5029 * @param {Object} p_oItem Object literal containing a set of menu item
5030 * configuration properties.
5031 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5032 * the item should be added.
5033 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5034 * the item belongs.
5035 * @return {YAHOO.widget.MenuItem}
5037 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5039 if (p_oItem) {
5041 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5049 * @method removeItem
5050 * @description Removes the specified item from the menu.
5051 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
5052 * instance to be removed from the menu.
5053 * @param {Number} p_oObject Number specifying the index of the item
5054 * to be removed.
5055 * @param {Number} p_nGroupIndex Optional. Number specifying the group to
5056 * which the item belongs.
5057 * @return {YAHOO.widget.MenuItem}
5059 removeItem: function (p_oObject, p_nGroupIndex) {
5061 var oItem;
5063 if (typeof p_oObject != "undefined") {
5065 if (p_oObject instanceof YAHOO.widget.MenuItem) {
5067 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
5070 else if (typeof p_oObject == "number") {
5072 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5076 if (oItem) {
5078 oItem.destroy();
5080 this.logger.log("Item removed." +
5081 " Text: " + oItem.cfg.getProperty("text") + ", " +
5082 " Index: " + oItem.index + ", " +
5083 " Group Index: " + oItem.groupIndex);
5085 return oItem;
5095 * @method getItems
5096 * @description Returns an array of all of the items in the menu.
5097 * @return {Array}
5099 getItems: function () {
5101 var aGroups = this._aItemGroups,
5102 nGroups,
5103 aItems = [];
5105 if (Lang.isArray(aGroups)) {
5107 nGroups = aGroups.length;
5109 return ((nGroups == 1) ? aGroups[0] :
5110 (Array.prototype.concat.apply(aItems, aGroups)));
5118 * @method getItemGroups
5119 * @description Multi-dimensional Array representing the menu items as they
5120 * are grouped in the menu.
5121 * @return {Array}
5123 getItemGroups: function () {
5125 return this._aItemGroups;
5131 * @method getItem
5132 * @description Returns the item at the specified index.
5133 * @param {Number} p_nItemIndex Number indicating the ordinal position of the
5134 * item to be retrieved.
5135 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
5136 * the item belongs.
5137 * @return {YAHOO.widget.MenuItem}
5139 getItem: function (p_nItemIndex, p_nGroupIndex) {
5141 var aGroup;
5143 if (typeof p_nItemIndex == "number") {
5145 aGroup = this._getItemGroup(p_nGroupIndex);
5147 if (aGroup) {
5149 return aGroup[p_nItemIndex];
5159 * @method getSubmenus
5160 * @description Returns an array of all of the submenus that are immediate
5161 * children of the menu.
5162 * @return {Array}
5164 getSubmenus: function () {
5166 var aItems = this.getItems(),
5167 nItems = aItems.length,
5168 aSubmenus,
5169 oSubmenu,
5170 oItem,
5174 if (nItems > 0) {
5176 aSubmenus = [];
5178 for(i=0; i<nItems; i++) {
5180 oItem = aItems[i];
5182 if (oItem) {
5184 oSubmenu = oItem.cfg.getProperty("submenu");
5186 if (oSubmenu) {
5188 aSubmenus[aSubmenus.length] = oSubmenu;
5198 return aSubmenus;
5204 * @method clearContent
5205 * @description Removes all of the content from the menu, including the menu
5206 * items, group titles, header and footer.
5208 clearContent: function () {
5210 var aItems = this.getItems(),
5211 nItems = aItems.length,
5212 oElement = this.element,
5213 oBody = this.body,
5214 oHeader = this.header,
5215 oFooter = this.footer,
5216 oItem,
5217 oSubmenu,
5221 if (nItems > 0) {
5223 i = nItems - 1;
5225 do {
5227 oItem = aItems[i];
5229 if (oItem) {
5231 oSubmenu = oItem.cfg.getProperty("submenu");
5233 if (oSubmenu) {
5235 this.cfg.configChangedEvent.unsubscribe(
5236 this._onParentMenuConfigChange, oSubmenu);
5238 this.renderEvent.unsubscribe(this._onParentMenuRender,
5239 oSubmenu);
5243 this.removeItem(oItem);
5248 while(i--);
5253 if (oHeader) {
5255 Event.purgeElement(oHeader);
5256 oElement.removeChild(oHeader);
5261 if (oFooter) {
5263 Event.purgeElement(oFooter);
5264 oElement.removeChild(oFooter);
5268 if (oBody) {
5270 Event.purgeElement(oBody);
5272 oBody.innerHTML = "";
5276 this.activeItem = null;
5278 this._aItemGroups = [];
5279 this._aListElements = [];
5280 this._aGroupTitleElements = [];
5282 this.cfg.setProperty("width", null);
5288 * @method destroy
5289 * @description Removes the menu's <code>&#60;div&#62;</code> element
5290 * (and accompanying child nodes) from the document.
5292 destroy: function () {
5294 // Remove all items
5296 this.clearContent();
5298 this._aItemGroups = null;
5299 this._aListElements = null;
5300 this._aGroupTitleElements = null;
5303 // Continue with the superclass implementation of this method
5305 Menu.superclass.destroy.call(this);
5307 this.logger.log("Destroyed.");
5313 * @method setInitialFocus
5314 * @description Sets focus to the menu's first enabled item.
5316 setInitialFocus: function () {
5318 var oItem = this._getFirstEnabledItem();
5320 if (oItem) {
5322 oItem.focus();
5330 * @method setInitialSelection
5331 * @description Sets the "selected" configuration property of the menu's first
5332 * enabled item to "true."
5334 setInitialSelection: function () {
5336 var oItem = this._getFirstEnabledItem();
5338 if (oItem) {
5340 oItem.cfg.setProperty("selected", true);
5347 * @method clearActiveItem
5348 * @description Sets the "selected" configuration property of the menu's active
5349 * item to "false" and hides the item's submenu.
5350 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
5351 * should be blurred.
5353 clearActiveItem: function (p_bBlur) {
5355 if (this.cfg.getProperty("showdelay") > 0) {
5357 this._cancelShowDelay();
5362 var oActiveItem = this.activeItem,
5363 oConfig,
5364 oSubmenu;
5366 if (oActiveItem) {
5368 oConfig = oActiveItem.cfg;
5370 if (p_bBlur) {
5372 oActiveItem.blur();
5376 oConfig.setProperty("selected", false);
5378 oSubmenu = oConfig.getProperty("submenu");
5380 if (oSubmenu) {
5382 oSubmenu.hide();
5386 this.activeItem = null;
5394 * @method focus
5395 * @description Causes the menu to receive focus and fires the "focus" event.
5397 focus: function () {
5399 if (!this.hasFocus()) {
5401 this.setInitialFocus();
5409 * @method blur
5410 * @description Causes the menu to lose focus and fires the "blur" event.
5412 blur: function () {
5414 var oItem;
5416 if (this.hasFocus()) {
5418 oItem = MenuManager.getFocusedMenuItem();
5420 if (oItem) {
5422 oItem.blur();
5432 * @method hasFocus
5433 * @description Returns a boolean indicating whether or not the menu has focus.
5434 * @return {Boolean}
5436 hasFocus: function () {
5438 return (MenuManager.getFocusedMenu() == this.getRoot());
5444 * Adds the specified CustomEvent subscriber to the menu and each of
5445 * its submenus.
5446 * @method subscribe
5447 * @param p_type {string} the type, or name of the event
5448 * @param p_fn {function} the function to exectute when the event fires
5449 * @param p_obj {Object} An object to be passed along when the event
5450 * fires
5451 * @param p_override {boolean} If true, the obj passed in becomes the
5452 * execution scope of the listener
5454 subscribe: function () {
5456 function onItemAdded(p_sType, p_aArgs, p_oObject) {
5458 var oItem = p_aArgs[0],
5459 oSubmenu = oItem.cfg.getProperty("submenu");
5461 if (oSubmenu) {
5463 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5470 function onSubmenuAdded(p_sType, p_aArgs, p_oObject) {
5472 var oSubmenu = this.cfg.getProperty("submenu");
5474 if (oSubmenu) {
5476 oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5483 Menu.superclass.subscribe.apply(this, arguments);
5484 Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments);
5487 var aItems = this.getItems(),
5488 nItems,
5489 oItem,
5490 oSubmenu,
5494 if (aItems) {
5496 nItems = aItems.length;
5498 if (nItems > 0) {
5500 i = nItems - 1;
5502 do {
5504 oItem = aItems[i];
5506 oSubmenu = oItem.cfg.getProperty("submenu");
5508 if (oSubmenu) {
5510 oSubmenu.subscribe.apply(oSubmenu, arguments);
5513 else {
5515 oItem.cfg.subscribeToConfigEvent("submenu", onSubmenuAdded, arguments);
5520 while (i--);
5530 * @description Initializes the class's configurable properties which can be
5531 * changed using the menu's Config object ("cfg").
5532 * @method initDefaultConfig
5534 initDefaultConfig: function () {
5536 Menu.superclass.initDefaultConfig.call(this);
5538 var oConfig = this.cfg;
5541 // Module documentation overrides
5544 * @config effect
5545 * @description Object or array of objects representing the ContainerEffect
5546 * classes that are active for animating the container. When set this
5547 * property is automatically applied to all submenus.
5548 * @type Object
5549 * @default null
5552 // Overlay documentation overrides
5556 * @config x
5557 * @description Number representing the absolute x-coordinate position of
5558 * the Menu. This property is only applied when the "position"
5559 * configuration property is set to dynamic.
5560 * @type Number
5561 * @default null
5566 * @config y
5567 * @description Number representing the absolute y-coordinate position of
5568 * the Menu. This property is only applied when the "position"
5569 * configuration property is set to dynamic.
5570 * @type Number
5571 * @default null
5576 * @description Array of the absolute x and y positions of the Menu. This
5577 * property is only applied when the "position" configuration property is
5578 * set to dynamic.
5579 * @config xy
5580 * @type Number[]
5581 * @default null
5586 * @config context
5587 * @description Array of context arguments for context-sensitive positioning.
5588 * The format is: [id or element, element corner, context corner].
5589 * For example, setting this property to ["img1", "tl", "bl"] would
5590 * align the Mnu's top left corner to the context element's
5591 * bottom left corner. This property is only applied when the "position"
5592 * configuration property is set to dynamic.
5593 * @type Array
5594 * @default null
5599 * @config fixedcenter
5600 * @description Boolean indicating if the Menu should be anchored to the
5601 * center of the viewport. This property is only applied when the
5602 * "position" configuration property is set to dynamic.
5603 * @type Boolean
5604 * @default false
5609 * @config zindex
5610 * @description Number representing the CSS z-index of the Menu. This
5611 * property is only applied when the "position" configuration property is
5612 * set to dynamic.
5613 * @type Number
5614 * @default null
5619 * @config iframe
5620 * @description Boolean indicating whether or not the Menu should
5621 * have an IFRAME shim; used to prevent SELECT elements from
5622 * poking through an Overlay instance in IE6. When set to "true",
5623 * the iframe shim is created when the Menu instance is intially
5624 * made visible. This property is only applied when the "position"
5625 * configuration property is set to dynamic and is automatically applied
5626 * to all submenus.
5627 * @type Boolean
5628 * @default true for IE6 and below, false for all other browsers.
5632 // Add configuration attributes
5635 Change the default value for the "visible" configuration
5636 property to "false" by re-adding the property.
5640 * @config visible
5641 * @description Boolean indicating whether or not the menu is visible. If
5642 * the menu's "position" configuration property is set to "dynamic" (the
5643 * default), this property toggles the menu's <code>&#60;div&#62;</code>
5644 * element's "visibility" style property between "visible" (true) or
5645 * "hidden" (false). If the menu's "position" configuration property is
5646 * set to "static" this property toggles the menu's
5647 * <code>&#60;div&#62;</code> element's "display" style property
5648 * between "block" (true) or "none" (false).
5649 * @default false
5650 * @type Boolean
5652 oConfig.addProperty(
5653 DEFAULT_CONFIG.VISIBLE.key,
5655 handler: this.configVisible,
5656 value: DEFAULT_CONFIG.VISIBLE.value,
5657 validator: DEFAULT_CONFIG.VISIBLE.validator
5663 Change the default value for the "constraintoviewport" configuration
5664 property to "true" by re-adding the property.
5668 * @config constraintoviewport
5669 * @description Boolean indicating if the menu will try to remain inside
5670 * the boundaries of the size of viewport. This property is only applied
5671 * when the "position" configuration property is set to dynamic and is
5672 * automatically applied to all submenus.
5673 * @default true
5674 * @type Boolean
5676 oConfig.addProperty(
5677 DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key,
5679 handler: this.configConstrainToViewport,
5680 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
5681 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
5682 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
5688 * @config position
5689 * @description String indicating how a menu should be positioned on the
5690 * screen. Possible values are "static" and "dynamic." Static menus are
5691 * visible by default and reside in the normal flow of the document
5692 * (CSS position: static). Dynamic menus are hidden by default, reside
5693 * out of the normal flow of the document (CSS position: absolute), and
5694 * can overlay other elements on the screen.
5695 * @default dynamic
5696 * @type String
5698 oConfig.addProperty(
5699 DEFAULT_CONFIG.POSITION.key,
5701 handler: this.configPosition,
5702 value: DEFAULT_CONFIG.POSITION.value,
5703 validator: DEFAULT_CONFIG.POSITION.validator,
5704 supercedes: DEFAULT_CONFIG.POSITION.supercedes
5710 * @config submenualignment
5711 * @description Array defining how submenus should be aligned to their
5712 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
5713 * a submenu's top left corner is aligned to its parent menu item's top
5714 * right corner.
5715 * @default ["tl","tr"]
5716 * @type Array
5718 oConfig.addProperty(
5719 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
5721 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
5722 suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
5728 * @config autosubmenudisplay
5729 * @description Boolean indicating if submenus are automatically made
5730 * visible when the user mouses over the menu's items.
5731 * @default true
5732 * @type Boolean
5734 oConfig.addProperty(
5735 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
5737 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
5738 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
5739 suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
5745 * @config showdelay
5746 * @description Number indicating the time (in milliseconds) that should
5747 * expire before a submenu is made visible when the user mouses over
5748 * the menu's items. This property is only applied when the "position"
5749 * configuration property is set to dynamic and is automatically applied
5750 * to all submenus.
5751 * @default 250
5752 * @type Number
5754 oConfig.addProperty(
5755 DEFAULT_CONFIG.SHOW_DELAY.key,
5757 value: DEFAULT_CONFIG.SHOW_DELAY.value,
5758 validator: DEFAULT_CONFIG.SHOW_DELAY.validator,
5759 suppressEvent: DEFAULT_CONFIG.SHOW_DELAY.suppressEvent
5765 * @config hidedelay
5766 * @description Number indicating the time (in milliseconds) that should
5767 * expire before the menu is hidden. This property is only applied when
5768 * the "position" configuration property is set to dynamic and is
5769 * automatically applied to all submenus.
5770 * @default 0
5771 * @type Number
5773 oConfig.addProperty(
5774 DEFAULT_CONFIG.HIDE_DELAY.key,
5776 handler: this.configHideDelay,
5777 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5778 validator: DEFAULT_CONFIG.HIDE_DELAY.validator,
5779 suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.suppressEvent
5785 * @config submenuhidedelay
5786 * @description Number indicating the time (in milliseconds) that should
5787 * expire before a submenu is hidden when the user mouses out of a menu item
5788 * heading in the direction of a submenu. The value must be greater than or
5789 * equal to the value specified for the "showdelay" configuration property.
5790 * This property is only applied when the "position" configuration property
5791 * is set to dynamic and is automatically applied to all submenus.
5792 * @default 250
5793 * @type Number
5795 oConfig.addProperty(
5796 DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key,
5798 value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value,
5799 validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator,
5800 suppressEvent: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.suppressEvent
5806 * @config clicktohide
5807 * @description Boolean indicating if the menu will automatically be
5808 * hidden if the user clicks outside of it. This property is only
5809 * applied when the "position" configuration property is set to dynamic
5810 * and is automatically applied to all submenus.
5811 * @default true
5812 * @type Boolean
5814 oConfig.addProperty(
5815 DEFAULT_CONFIG.CLICK_TO_HIDE.key,
5817 value: DEFAULT_CONFIG.CLICK_TO_HIDE.value,
5818 validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator,
5819 suppressEvent: DEFAULT_CONFIG.CLICK_TO_HIDE.suppressEvent
5825 * @config container
5826 * @description HTML element reference or string specifying the id
5827 * attribute of the HTML element that the menu's markup should be
5828 * rendered into.
5829 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
5830 * level-one-html.html#ID-58190037">HTMLElement</a>|String
5831 * @default document.body
5833 oConfig.addProperty(
5834 DEFAULT_CONFIG.CONTAINER.key,
5836 handler: this.configContainer,
5837 value: document.body,
5838 suppressEvent: DEFAULT_CONFIG.CONTAINER.suppressEvent
5844 * @config scrollincrement
5845 * @description Number used to control the scroll speed of a menu. Used to
5846 * increment the "scrollTop" property of the menu's body by when a menu's
5847 * content is scrolling. When set this property is automatically applied
5848 * to all submenus.
5849 * @default 1
5850 * @type Number
5852 oConfig.addProperty(
5853 DEFAULT_CONFIG.SCROLL_INCREMENT.key,
5855 value: DEFAULT_CONFIG.SCROLL_INCREMENT.value,
5856 validator: DEFAULT_CONFIG.SCROLL_INCREMENT.validator,
5857 supercedes: DEFAULT_CONFIG.SCROLL_INCREMENT.supercedes,
5858 suppressEvent: DEFAULT_CONFIG.SCROLL_INCREMENT.suppressEvent
5864 * @config minscrollheight
5865 * @description Number defining the minimum threshold for the "maxheight"
5866 * configuration property. When set this property is automatically applied
5867 * to all submenus.
5868 * @default 90
5869 * @type Number
5871 oConfig.addProperty(
5872 DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.key,
5874 value: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.value,
5875 validator: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.validator,
5876 supercedes: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.supercedes,
5877 suppressEvent: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.suppressEvent
5883 * @config maxheight
5884 * @description Number defining the maximum height (in pixels) for a menu's
5885 * body element (<code>&#60;div class="bd"&#60;</code>). Once a menu's body
5886 * exceeds this height, the contents of the body are scrolled to maintain
5887 * this value. This value cannot be set lower than the value of the
5888 * "minscrollheight" configuration property.
5889 * @default 0
5890 * @type Number
5892 oConfig.addProperty(
5893 DEFAULT_CONFIG.MAX_HEIGHT.key,
5895 handler: this.configMaxHeight,
5896 value: DEFAULT_CONFIG.MAX_HEIGHT.value,
5897 validator: DEFAULT_CONFIG.MAX_HEIGHT.validator,
5898 suppressEvent: DEFAULT_CONFIG.MAX_HEIGHT.suppressEvent,
5899 supercedes: DEFAULT_CONFIG.MAX_HEIGHT.supercedes
5905 * @config classname
5906 * @description String representing the CSS class to be applied to the
5907 * menu's root <code>&#60;div&#62;</code> element. The specified class(es)
5908 * are appended in addition to the default class as specified by the menu's
5909 * CSS_CLASS_NAME constant. When set this property is automatically
5910 * applied to all submenus.
5911 * @default null
5912 * @type String
5914 oConfig.addProperty(
5915 DEFAULT_CONFIG.CLASS_NAME.key,
5917 handler: this.configClassName,
5918 value: DEFAULT_CONFIG.CLASS_NAME.value,
5919 validator: DEFAULT_CONFIG.CLASS_NAME.validator,
5920 supercedes: DEFAULT_CONFIG.CLASS_NAME.supercedes
5926 * @config disabled
5927 * @description Boolean indicating if the menu should be disabled.
5928 * Disabling a menu disables each of its items. (Disabled menu items are
5929 * dimmed and will not respond to user input or fire events.) Disabled
5930 * menus have a corresponding "disabled" CSS class applied to their root
5931 * <code>&#60;div&#62;</code> element.
5932 * @default false
5933 * @type Boolean
5935 oConfig.addProperty(
5936 DEFAULT_CONFIG.DISABLED.key,
5938 handler: this.configDisabled,
5939 value: DEFAULT_CONFIG.DISABLED.value,
5940 validator: DEFAULT_CONFIG.DISABLED.validator,
5941 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5947 }); // END YAHOO.lang.extend
5949 })();
5953 (function () {
5957 * Creates an item for a menu.
5959 * @param {String} p_oObject String specifying the text of the menu item.
5960 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5961 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
5962 * the <code>&#60;li&#62;</code> element of the menu item.
5963 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5964 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
5965 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
5966 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
5967 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
5968 * specifying the <code>&#60;option&#62;</code> element of the menu item.
5969 * @param {Object} p_oConfig Optional. Object literal specifying the
5970 * configuration for the menu item. See configuration class documentation
5971 * for more details.
5972 * @class MenuItem
5973 * @constructor
5975 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
5977 if (p_oObject) {
5979 if (p_oConfig) {
5981 this.parent = p_oConfig.parent;
5982 this.value = p_oConfig.value;
5983 this.id = p_oConfig.id;
5987 this.init(p_oObject, p_oConfig);
5994 var Dom = YAHOO.util.Dom,
5995 Module = YAHOO.widget.Module,
5996 Menu = YAHOO.widget.Menu,
5997 MenuItem = YAHOO.widget.MenuItem,
5998 CustomEvent = YAHOO.util.CustomEvent,
5999 Lang = YAHOO.lang,
6001 m_oMenuItemTemplate,
6004 * Constant representing the name of the MenuItem's events
6005 * @property EVENT_TYPES
6006 * @private
6007 * @final
6008 * @type Object
6010 EVENT_TYPES = {
6012 "MOUSE_OVER": "mouseover",
6013 "MOUSE_OUT": "mouseout",
6014 "MOUSE_DOWN": "mousedown",
6015 "MOUSE_UP": "mouseup",
6016 "CLICK": "click",
6017 "KEY_PRESS": "keypress",
6018 "KEY_DOWN": "keydown",
6019 "KEY_UP": "keyup",
6020 "ITEM_ADDED": "itemAdded",
6021 "ITEM_REMOVED": "itemRemoved",
6022 "FOCUS": "focus",
6023 "BLUR": "blur",
6024 "DESTROY": "destroy"
6029 * Constant representing the MenuItem's configuration properties
6030 * @property DEFAULT_CONFIG
6031 * @private
6032 * @final
6033 * @type Object
6035 DEFAULT_CONFIG = {
6037 "TEXT": {
6038 key: "text",
6039 value: "",
6040 validator: Lang.isString,
6041 suppressEvent: true
6044 "HELP_TEXT": {
6045 key: "helptext",
6046 supercedes: ["text"],
6047 suppressEvent: true
6050 "URL": {
6051 key: "url",
6052 value: "#",
6053 suppressEvent: true
6056 "TARGET": {
6057 key: "target",
6058 suppressEvent: true
6061 "EMPHASIS": {
6062 key: "emphasis",
6063 value: false,
6064 validator: Lang.isBoolean,
6065 suppressEvent: true,
6066 supercedes: ["text"]
6069 "STRONG_EMPHASIS": {
6070 key: "strongemphasis",
6071 value: false,
6072 validator: Lang.isBoolean,
6073 suppressEvent: true,
6074 supercedes: ["text"]
6077 "CHECKED": {
6078 key: "checked",
6079 value: false,
6080 validator: Lang.isBoolean,
6081 suppressEvent: true,
6082 supercedes: ["disabled", "selected"]
6085 "SUBMENU": {
6086 key: "submenu",
6087 suppressEvent: true,
6088 supercedes: ["disabled", "selected"]
6091 "DISABLED": {
6092 key: "disabled",
6093 value: false,
6094 validator: Lang.isBoolean,
6095 suppressEvent: true,
6096 supercedes: ["text", "selected"]
6099 "SELECTED": {
6100 key: "selected",
6101 value: false,
6102 validator: Lang.isBoolean,
6103 suppressEvent: true
6106 "ONCLICK": {
6107 key: "onclick",
6108 suppressEvent: true
6111 "CLASS_NAME": {
6112 key: "classname",
6113 value: null,
6114 validator: Lang.isString,
6115 suppressEvent: true
6121 MenuItem.prototype = {
6124 * @property CSS_CLASS_NAME
6125 * @description String representing the CSS class(es) to be applied to the
6126 * <code>&#60;li&#62;</code> element of the menu item.
6127 * @default "yuimenuitem"
6128 * @final
6129 * @type String
6131 CSS_CLASS_NAME: "yuimenuitem",
6135 * @property CSS_LABEL_CLASS_NAME
6136 * @description String representing the CSS class(es) to be applied to the
6137 * menu item's <code>&#60;a&#62;</code> element.
6138 * @default "yuimenuitemlabel"
6139 * @final
6140 * @type String
6142 CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6146 * @property SUBMENU_TYPE
6147 * @description Object representing the type of menu to instantiate and
6148 * add when parsing the child nodes of the menu item's source HTML element.
6149 * @final
6150 * @type YAHOO.widget.Menu
6152 SUBMENU_TYPE: null,
6156 // Private member variables
6160 * @property _oAnchor
6161 * @description Object reference to the menu item's
6162 * <code>&#60;a&#62;</code> element.
6163 * @default null
6164 * @private
6165 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6166 * one-html.html#ID-48250443">HTMLAnchorElement</a>
6168 _oAnchor: null,
6172 * @property _oHelpTextEM
6173 * @description Object reference to the menu item's help text
6174 * <code>&#60;em&#62;</code> element.
6175 * @default null
6176 * @private
6177 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6178 * one-html.html#ID-58190037">HTMLElement</a>
6180 _oHelpTextEM: null,
6184 * @property _oSubmenu
6185 * @description Object reference to the menu item's submenu.
6186 * @default null
6187 * @private
6188 * @type YAHOO.widget.Menu
6190 _oSubmenu: null,
6193 /**
6194 * @property _oOnclickAttributeValue
6195 * @description Object reference to the menu item's current value for the
6196 * "onclick" configuration attribute.
6197 * @default null
6198 * @private
6199 * @type Object
6201 _oOnclickAttributeValue: null,
6205 * @property _sClassName
6206 * @description The current value of the "classname" configuration attribute.
6207 * @default null
6208 * @private
6209 * @type String
6211 _sClassName: null,
6215 // Public properties
6219 * @property constructor
6220 * @description Object reference to the menu item's constructor function.
6221 * @default YAHOO.widget.MenuItem
6222 * @type YAHOO.widget.MenuItem
6224 constructor: MenuItem,
6228 * @property index
6229 * @description Number indicating the ordinal position of the menu item in
6230 * its group.
6231 * @default null
6232 * @type Number
6234 index: null,
6238 * @property groupIndex
6239 * @description Number indicating the index of the group to which the menu
6240 * item belongs.
6241 * @default null
6242 * @type Number
6244 groupIndex: null,
6248 * @property parent
6249 * @description Object reference to the menu item's parent menu.
6250 * @default null
6251 * @type YAHOO.widget.Menu
6253 parent: null,
6257 * @property element
6258 * @description Object reference to the menu item's
6259 * <code>&#60;li&#62;</code> element.
6260 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6261 * -one-html.html#ID-74680021">HTMLLIElement</a>
6262 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6263 * one-html.html#ID-74680021">HTMLLIElement</a>
6265 element: null,
6269 * @property srcElement
6270 * @description Object reference to the HTML element (either
6271 * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
6272 * <code>&#60;option&#62;</code>) used create the menu item.
6273 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6274 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6275 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6276 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6277 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6278 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6279 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6280 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6281 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6282 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6284 srcElement: null,
6288 * @property value
6289 * @description Object reference to the menu item's value.
6290 * @default null
6291 * @type Object
6293 value: null,
6297 * @property browser
6298 * @deprecated Use YAHOO.env.ua
6299 * @description String representing the browser.
6300 * @type String
6302 browser: Module.prototype.browser,
6306 * @property id
6307 * @description Id of the menu item's root <code>&#60;li&#62;</code>
6308 * element. This property should be set via the constructor using the
6309 * configuration object literal. If an id is not specified, then one will
6310 * be created using the "generateId" method of the Dom utility.
6311 * @default null
6312 * @type String
6314 id: null,
6318 // Events
6322 * @event destroyEvent
6323 * @description Fires when the menu item's <code>&#60;li&#62;</code>
6324 * element is removed from its parent <code>&#60;ul&#62;</code> element.
6325 * @type YAHOO.util.CustomEvent
6327 destroyEvent: null,
6331 * @event mouseOverEvent
6332 * @description Fires when the mouse has entered the menu item. Passes
6333 * back the DOM Event object as an argument.
6334 * @type YAHOO.util.CustomEvent
6336 mouseOverEvent: null,
6340 * @event mouseOutEvent
6341 * @description Fires when the mouse has left the menu item. Passes back
6342 * the DOM Event object as an argument.
6343 * @type YAHOO.util.CustomEvent
6345 mouseOutEvent: null,
6349 * @event mouseDownEvent
6350 * @description Fires when the user mouses down on the menu item. Passes
6351 * back the DOM Event object as an argument.
6352 * @type YAHOO.util.CustomEvent
6354 mouseDownEvent: null,
6358 * @event mouseUpEvent
6359 * @description Fires when the user releases a mouse button while the mouse
6360 * is over the menu item. Passes back the DOM Event object as an argument.
6361 * @type YAHOO.util.CustomEvent
6363 mouseUpEvent: null,
6367 * @event clickEvent
6368 * @description Fires when the user clicks the on the menu item. Passes
6369 * back the DOM Event object as an argument.
6370 * @type YAHOO.util.CustomEvent
6372 clickEvent: null,
6376 * @event keyPressEvent
6377 * @description Fires when the user presses an alphanumeric key when the
6378 * menu item has focus. Passes back the DOM Event object as an argument.
6379 * @type YAHOO.util.CustomEvent
6381 keyPressEvent: null,
6385 * @event keyDownEvent
6386 * @description Fires when the user presses a key when the menu item has
6387 * focus. Passes back the DOM Event object as an argument.
6388 * @type YAHOO.util.CustomEvent
6390 keyDownEvent: null,
6394 * @event keyUpEvent
6395 * @description Fires when the user releases a key when the menu item has
6396 * focus. Passes back the DOM Event object as an argument.
6397 * @type YAHOO.util.CustomEvent
6399 keyUpEvent: null,
6403 * @event focusEvent
6404 * @description Fires when the menu item receives focus.
6405 * @type YAHOO.util.CustomEvent
6407 focusEvent: null,
6411 * @event blurEvent
6412 * @description Fires when the menu item loses the input focus.
6413 * @type YAHOO.util.CustomEvent
6415 blurEvent: null,
6419 * @method init
6420 * @description The MenuItem class's initialization method. This method is
6421 * automatically called by the constructor, and sets up all DOM references
6422 * for pre-existing markup, and creates required markup if it is not
6423 * already present.
6424 * @param {String} p_oObject String specifying the text of the menu item.
6425 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6426 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
6427 * the <code>&#60;li&#62;</code> element of the menu item.
6428 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6429 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6430 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6431 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6432 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
6433 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6434 * @param {Object} p_oConfig Optional. Object literal specifying the
6435 * configuration for the menu item. See configuration class documentation
6436 * for more details.
6438 init: function (p_oObject, p_oConfig) {
6441 if (!this.SUBMENU_TYPE) {
6443 this.SUBMENU_TYPE = Menu;
6448 // Create the config object
6450 this.cfg = new YAHOO.util.Config(this);
6452 this.initDefaultConfig();
6454 var SIGNATURE = CustomEvent.LIST,
6455 oConfig = this.cfg,
6456 sURL = "#",
6457 oAnchor,
6458 sTarget,
6459 sText,
6460 sId;
6463 if (Lang.isString(p_oObject)) {
6465 this._createRootNodeStructure();
6467 oConfig.queueProperty("text", p_oObject);
6470 else if (p_oObject && p_oObject.tagName) {
6472 switch(p_oObject.tagName.toUpperCase()) {
6474 case "OPTION":
6476 this._createRootNodeStructure();
6478 oConfig.queueProperty("text", p_oObject.text);
6479 oConfig.queueProperty("disabled", p_oObject.disabled);
6481 this.value = p_oObject.value;
6483 this.srcElement = p_oObject;
6485 break;
6487 case "OPTGROUP":
6489 this._createRootNodeStructure();
6491 oConfig.queueProperty("text", p_oObject.label);
6492 oConfig.queueProperty("disabled", p_oObject.disabled);
6494 this.srcElement = p_oObject;
6496 this._initSubTree();
6498 break;
6500 case "LI":
6502 // Get the anchor node (if it exists)
6504 oAnchor = Dom.getFirstChild(p_oObject);
6507 // Capture the "text" and/or the "URL"
6509 if (oAnchor) {
6511 sURL = oAnchor.getAttribute("href", 2);
6512 sTarget = oAnchor.getAttribute("target");
6514 sText = oAnchor.innerHTML;
6518 this.srcElement = p_oObject;
6519 this.element = p_oObject;
6520 this._oAnchor = oAnchor;
6523 Set these properties silently to sync up the
6524 configuration object without making changes to the
6525 element's DOM
6528 oConfig.setProperty("text", sText, true);
6529 oConfig.setProperty("url", sURL, true);
6530 oConfig.setProperty("target", sTarget, true);
6532 this._initSubTree();
6534 break;
6541 if (this.element) {
6543 sId = (this.srcElement || this.element).id;
6545 if (!sId) {
6547 sId = this.id || Dom.generateId();
6549 this.element.id = sId;
6553 this.id = sId;
6556 Dom.addClass(this.element, this.CSS_CLASS_NAME);
6557 Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
6560 // Create custom events
6562 this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
6563 this.mouseOverEvent.signature = SIGNATURE;
6565 this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
6566 this.mouseOutEvent.signature = SIGNATURE;
6568 this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
6569 this.mouseDownEvent.signature = SIGNATURE;
6571 this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
6572 this.mouseUpEvent.signature = SIGNATURE;
6574 this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
6575 this.clickEvent.signature = SIGNATURE;
6577 this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
6578 this.keyPressEvent.signature = SIGNATURE;
6580 this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
6581 this.keyDownEvent.signature = SIGNATURE;
6583 this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
6584 this.keyUpEvent.signature = SIGNATURE;
6586 this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
6587 this.focusEvent.signature = SIGNATURE;
6589 this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
6590 this.blurEvent.signature = SIGNATURE;
6592 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
6593 this.destroyEvent.signature = SIGNATURE;
6595 if (p_oConfig) {
6597 oConfig.applyConfig(p_oConfig);
6601 oConfig.fireQueue();
6609 // Private methods
6613 * @method _createRootNodeStructure
6614 * @description Creates the core DOM structure for the menu item.
6615 * @private
6617 _createRootNodeStructure: function () {
6619 var oElement,
6620 oAnchor;
6622 if (!m_oMenuItemTemplate) {
6624 m_oMenuItemTemplate = document.createElement("li");
6625 m_oMenuItemTemplate.innerHTML = "<a href=\"#\"></a>";
6629 oElement = m_oMenuItemTemplate.cloneNode(true);
6630 oElement.className = this.CSS_CLASS_NAME;
6632 oAnchor = oElement.firstChild;
6633 oAnchor.className = this.CSS_LABEL_CLASS_NAME;
6635 this.element = oElement;
6636 this._oAnchor = oAnchor;
6642 * @method _initSubTree
6643 * @description Iterates the source element's childNodes collection and uses
6644 * the child nodes to instantiate other menus.
6645 * @private
6647 _initSubTree: function () {
6649 var oSrcEl = this.srcElement,
6650 oConfig = this.cfg,
6651 oNode,
6652 aOptions,
6653 nOptions,
6654 oMenu,
6658 if (oSrcEl.childNodes.length > 0) {
6660 if (this.parent.lazyLoad && this.parent.srcElement &&
6661 this.parent.srcElement.tagName.toUpperCase() == "SELECT") {
6663 oConfig.setProperty(
6664 "submenu",
6665 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
6669 else {
6671 oNode = oSrcEl.firstChild;
6672 aOptions = [];
6674 do {
6676 if (oNode && oNode.tagName) {
6678 switch(oNode.tagName.toUpperCase()) {
6680 case "DIV":
6682 oConfig.setProperty("submenu", oNode);
6684 break;
6686 case "OPTION":
6688 aOptions[aOptions.length] = oNode;
6690 break;
6697 while((oNode = oNode.nextSibling));
6700 nOptions = aOptions.length;
6702 if (nOptions > 0) {
6704 oMenu = new this.SUBMENU_TYPE(Dom.generateId());
6706 oConfig.setProperty("submenu", oMenu);
6708 for(n=0; n<nOptions; n++) {
6710 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
6724 // Event handlers for configuration properties
6728 * @method configText
6729 * @description Event handler for when the "text" configuration property of
6730 * the menu item changes.
6731 * @param {String} p_sType String representing the name of the event that
6732 * was fired.
6733 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6734 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6735 * that fired the event.
6737 configText: function (p_sType, p_aArgs, p_oItem) {
6739 var sText = p_aArgs[0],
6740 oConfig = this.cfg,
6741 oAnchor = this._oAnchor,
6742 sHelpText = oConfig.getProperty("helptext"),
6743 sHelpTextHTML = "",
6744 sEmphasisStartTag = "",
6745 sEmphasisEndTag = "";
6748 if (sText) {
6751 if (sHelpText) {
6753 sHelpTextHTML = "<em class=\"helptext\">" + sHelpText + "</em>";
6758 if (oConfig.getProperty("emphasis")) {
6760 sEmphasisStartTag = "<em>";
6761 sEmphasisEndTag = "</em>";
6766 if (oConfig.getProperty("strongemphasis")) {
6768 sEmphasisStartTag = "<strong>";
6769 sEmphasisEndTag = "</strong>";
6774 oAnchor.innerHTML = (sEmphasisStartTag + sText +
6775 sEmphasisEndTag + sHelpTextHTML);
6783 * @method configHelpText
6784 * @description Event handler for when the "helptext" configuration property
6785 * of the menu item changes.
6786 * @param {String} p_sType String representing the name of the event that
6787 * was fired.
6788 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6789 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6790 * that fired the event.
6792 configHelpText: function (p_sType, p_aArgs, p_oItem) {
6794 this.cfg.refireEvent("text");
6800 * @method configURL
6801 * @description Event handler for when the "url" configuration property of
6802 * the menu item changes.
6803 * @param {String} p_sType String representing the name of the event that
6804 * was fired.
6805 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6806 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6807 * that fired the event.
6809 configURL: function (p_sType, p_aArgs, p_oItem) {
6811 var sURL = p_aArgs[0];
6813 if (!sURL) {
6815 sURL = "#";
6819 var oAnchor = this._oAnchor;
6821 if (YAHOO.env.ua.opera) {
6823 oAnchor.removeAttribute("href");
6827 oAnchor.setAttribute("href", sURL);
6833 * @method configTarget
6834 * @description Event handler for when the "target" configuration property
6835 * of the menu item changes.
6836 * @param {String} p_sType String representing the name of the event that
6837 * was fired.
6838 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6839 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6840 * that fired the event.
6842 configTarget: function (p_sType, p_aArgs, p_oItem) {
6844 var sTarget = p_aArgs[0],
6845 oAnchor = this._oAnchor;
6847 if (sTarget && sTarget.length > 0) {
6849 oAnchor.setAttribute("target", sTarget);
6852 else {
6854 oAnchor.removeAttribute("target");
6862 * @method configEmphasis
6863 * @description Event handler for when the "emphasis" configuration property
6864 * of the menu item changes.
6865 * @param {String} p_sType String representing the name of the event that
6866 * was fired.
6867 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6868 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6869 * that fired the event.
6871 configEmphasis: function (p_sType, p_aArgs, p_oItem) {
6873 var bEmphasis = p_aArgs[0],
6874 oConfig = this.cfg;
6877 if (bEmphasis && oConfig.getProperty("strongemphasis")) {
6879 oConfig.setProperty("strongemphasis", false);
6884 oConfig.refireEvent("text");
6890 * @method configStrongEmphasis
6891 * @description Event handler for when the "strongemphasis" configuration
6892 * property of the menu item changes.
6893 * @param {String} p_sType String representing the name of the event that
6894 * was fired.
6895 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6896 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6897 * that fired the event.
6899 configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
6901 var bStrongEmphasis = p_aArgs[0],
6902 oConfig = this.cfg;
6905 if (bStrongEmphasis && oConfig.getProperty("emphasis")) {
6907 oConfig.setProperty("emphasis", false);
6911 oConfig.refireEvent("text");
6917 * @method configChecked
6918 * @description Event handler for when the "checked" configuration property
6919 * of the menu item changes.
6920 * @param {String} p_sType String representing the name of the event that
6921 * was fired.
6922 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6923 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6924 * that fired the event.
6926 configChecked: function (p_sType, p_aArgs, p_oItem) {
6928 var bChecked = p_aArgs[0],
6929 oElement = this.element,
6930 oAnchor = this._oAnchor,
6931 oConfig = this.cfg,
6932 sState = "-checked",
6933 sClassName = this.CSS_CLASS_NAME + sState,
6934 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState;
6937 if (bChecked) {
6939 Dom.addClass(oElement, sClassName);
6940 Dom.addClass(oAnchor, sLabelClassName);
6943 else {
6945 Dom.removeClass(oElement, sClassName);
6946 Dom.removeClass(oAnchor, sLabelClassName);
6951 oConfig.refireEvent("text");
6954 if (oConfig.getProperty("disabled")) {
6956 oConfig.refireEvent("disabled");
6961 if (oConfig.getProperty("selected")) {
6963 oConfig.refireEvent("selected");
6972 * @method configDisabled
6973 * @description Event handler for when the "disabled" configuration property
6974 * of the menu item changes.
6975 * @param {String} p_sType String representing the name of the event that
6976 * was fired.
6977 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
6978 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
6979 * that fired the event.
6981 configDisabled: function (p_sType, p_aArgs, p_oItem) {
6983 var bDisabled = p_aArgs[0],
6984 oConfig = this.cfg,
6985 oSubmenu = oConfig.getProperty("submenu"),
6986 bChecked = oConfig.getProperty("checked"),
6987 oElement = this.element,
6988 oAnchor = this._oAnchor,
6989 sState = "-disabled",
6990 sCheckedState = "-checked" + sState,
6991 sSubmenuState = "-hassubmenu" + sState,
6992 sClassName = this.CSS_CLASS_NAME + sState,
6993 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
6994 sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
6995 sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
6996 sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
6997 sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;
7000 if (bDisabled) {
7002 if (oConfig.getProperty("selected")) {
7004 oConfig.setProperty("selected", false);
7008 Dom.addClass(oElement, sClassName);
7009 Dom.addClass(oAnchor, sLabelClassName);
7012 if (oSubmenu) {
7014 Dom.addClass(oElement, sSubmenuClassName);
7015 Dom.addClass(oAnchor, sLabelSubmenuClassName);
7020 if (bChecked) {
7022 Dom.addClass(oElement, sCheckedClassName);
7023 Dom.addClass(oAnchor, sLabelCheckedClassName);
7028 else {
7030 Dom.removeClass(oElement, sClassName);
7031 Dom.removeClass(oAnchor, sLabelClassName);
7034 if (oSubmenu) {
7036 Dom.removeClass(oElement, sSubmenuClassName);
7037 Dom.removeClass(oAnchor, sLabelSubmenuClassName);
7042 if (bChecked) {
7044 Dom.removeClass(oElement, sCheckedClassName);
7045 Dom.removeClass(oAnchor, sLabelCheckedClassName);
7055 * @method configSelected
7056 * @description Event handler for when the "selected" configuration property
7057 * of the menu item changes.
7058 * @param {String} p_sType String representing the name of the event that
7059 * was fired.
7060 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7061 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7062 * that fired the event.
7064 configSelected: function (p_sType, p_aArgs, p_oItem) {
7066 var oConfig = this.cfg,
7067 bSelected = p_aArgs[0],
7068 oElement = this.element,
7069 oAnchor = this._oAnchor,
7070 bChecked = oConfig.getProperty("checked"),
7071 oSubmenu = oConfig.getProperty("submenu"),
7072 sState = "-selected",
7073 sCheckedState = "-checked" + sState,
7074 sSubmenuState = "-hassubmenu" + sState,
7075 sClassName = this.CSS_CLASS_NAME + sState,
7076 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
7077 sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
7078 sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
7079 sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
7080 sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;
7083 if (YAHOO.env.ua.opera) {
7085 oAnchor.blur();
7090 if (bSelected && !oConfig.getProperty("disabled")) {
7092 Dom.addClass(oElement, sClassName);
7093 Dom.addClass(oAnchor, sLabelClassName);
7096 if (oSubmenu) {
7098 Dom.addClass(oElement, sSubmenuClassName);
7099 Dom.addClass(oAnchor, sLabelSubmenuClassName);
7104 if (bChecked) {
7106 Dom.addClass(oElement, sCheckedClassName);
7107 Dom.addClass(oAnchor, sLabelCheckedClassName);
7112 else {
7114 Dom.removeClass(oElement, sClassName);
7115 Dom.removeClass(oAnchor, sLabelClassName);
7118 if (oSubmenu) {
7120 Dom.removeClass(oElement, sSubmenuClassName);
7121 Dom.removeClass(oAnchor, sLabelSubmenuClassName);
7126 if (bChecked) {
7128 Dom.removeClass(oElement, sCheckedClassName);
7129 Dom.removeClass(oAnchor, sLabelCheckedClassName);
7136 if (this.hasFocus() && YAHOO.env.ua.opera) {
7138 oAnchor.focus();
7146 * @method _onSubmenuBeforeHide
7147 * @description "beforehide" Custom Event handler for a submenu.
7148 * @private
7149 * @param {String} p_sType String representing the name of the event that
7150 * was fired.
7151 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7153 _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7155 var oItem = this.parent,
7156 oMenu;
7158 function onHide() {
7160 oItem._oAnchor.blur();
7161 oMenu.beforeHideEvent.unsubscribe(onHide);
7166 if (oItem.hasFocus()) {
7168 oMenu = oItem.parent;
7170 oMenu.beforeHideEvent.subscribe(onHide);
7178 * @method configSubmenu
7179 * @description Event handler for when the "submenu" configuration property
7180 * of the menu item changes.
7181 * @param {String} p_sType String representing the name of the event that
7182 * was fired.
7183 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7184 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7185 * that fired the event.
7187 configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7189 var oSubmenu = p_aArgs[0],
7190 oConfig = this.cfg,
7191 oElement = this.element,
7192 oAnchor = this._oAnchor,
7193 bLazyLoad = this.parent && this.parent.lazyLoad,
7194 sState = "-hassubmenu",
7195 sClassName = this.CSS_CLASS_NAME + sState,
7196 sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
7197 oMenu,
7198 sSubmenuId,
7199 oSubmenuConfig;
7202 if (oSubmenu) {
7204 if (oSubmenu instanceof Menu) {
7206 oMenu = oSubmenu;
7207 oMenu.parent = this;
7208 oMenu.lazyLoad = bLazyLoad;
7211 else if (typeof oSubmenu == "object" && oSubmenu.id &&
7212 !oSubmenu.nodeType) {
7214 sSubmenuId = oSubmenu.id;
7215 oSubmenuConfig = oSubmenu;
7217 oSubmenuConfig.lazyload = bLazyLoad;
7218 oSubmenuConfig.parent = this;
7220 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7223 // Set the value of the property to the Menu instance
7225 oConfig.setProperty("submenu", oMenu, true);
7228 else {
7230 oMenu = new this.SUBMENU_TYPE(oSubmenu,
7231 { lazyload: bLazyLoad, parent: this });
7234 // Set the value of the property to the Menu instance
7236 oConfig.setProperty("submenu", oMenu, true);
7241 if (oMenu) {
7243 Dom.addClass(oElement, sClassName);
7244 Dom.addClass(oAnchor, sLabelClassName);
7246 this._oSubmenu = oMenu;
7248 if (YAHOO.env.ua.opera) {
7250 oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
7257 else {
7259 Dom.removeClass(oElement, sClassName);
7260 Dom.removeClass(oAnchor, sLabelClassName);
7262 if (this._oSubmenu) {
7264 this._oSubmenu.destroy();
7271 if (oConfig.getProperty("disabled")) {
7273 oConfig.refireEvent("disabled");
7278 if (oConfig.getProperty("selected")) {
7280 oConfig.refireEvent("selected");
7288 * @method configOnClick
7289 * @description Event handler for when the "onclick" configuration property
7290 * of the menu item changes.
7291 * @param {String} p_sType String representing the name of the event that
7292 * was fired.
7293 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7294 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7295 * that fired the event.
7297 configOnClick: function (p_sType, p_aArgs, p_oItem) {
7299 var oObject = p_aArgs[0];
7302 Remove any existing listeners if a "click" event handler has
7303 already been specified.
7306 if (this._oOnclickAttributeValue &&
7307 (this._oOnclickAttributeValue != oObject)) {
7309 this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
7310 this._oOnclickAttributeValue.obj);
7312 this._oOnclickAttributeValue = null;
7317 if (!this._oOnclickAttributeValue && typeof oObject == "object" &&
7318 typeof oObject.fn == "function") {
7320 this.clickEvent.subscribe(oObject.fn,
7321 ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this),
7322 oObject.scope);
7324 this._oOnclickAttributeValue = oObject;
7332 * @method configClassName
7333 * @description Event handler for when the "classname" configuration
7334 * property of a menu item changes.
7335 * @param {String} p_sType String representing the name of the event that
7336 * was fired.
7337 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7338 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7339 * that fired the event.
7341 configClassName: function (p_sType, p_aArgs, p_oItem) {
7343 var sClassName = p_aArgs[0];
7345 if (this._sClassName) {
7347 Dom.removeClass(this.element, this._sClassName);
7351 Dom.addClass(this.element, sClassName);
7352 this._sClassName = sClassName;
7358 // Public methods
7362 * @method initDefaultConfig
7363 * @description Initializes an item's configurable properties.
7365 initDefaultConfig : function () {
7367 var oConfig = this.cfg;
7370 // Define the configuration attributes
7373 * @config text
7374 * @description String specifying the text label for the menu item.
7375 * When building a menu from existing HTML the value of this property
7376 * will be interpreted from the menu's markup.
7377 * @default ""
7378 * @type String
7380 oConfig.addProperty(
7381 DEFAULT_CONFIG.TEXT.key,
7383 handler: this.configText,
7384 value: DEFAULT_CONFIG.TEXT.value,
7385 validator: DEFAULT_CONFIG.TEXT.validator,
7386 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
7392 * @config helptext
7393 * @description String specifying additional instructional text to
7394 * accompany the text for the menu item.
7395 * @deprecated Use "text" configuration property to add help text markup.
7396 * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em
7397 * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
7398 * @default null
7399 * @type String|<a href="http://www.w3.org/TR/
7400 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7401 * HTMLElement</a>
7403 oConfig.addProperty(
7404 DEFAULT_CONFIG.HELP_TEXT.key,
7406 handler: this.configHelpText,
7407 supercedes: DEFAULT_CONFIG.HELP_TEXT.supercedes,
7408 suppressEvent: DEFAULT_CONFIG.HELP_TEXT.suppressEvent
7414 * @config url
7415 * @description String specifying the URL for the menu item's anchor's
7416 * "href" attribute. When building a menu from existing HTML the value
7417 * of this property will be interpreted from the menu's markup.
7418 * @default "#"
7419 * @type String
7421 oConfig.addProperty(
7422 DEFAULT_CONFIG.URL.key,
7424 handler: this.configURL,
7425 value: DEFAULT_CONFIG.URL.value,
7426 suppressEvent: DEFAULT_CONFIG.URL.suppressEvent
7432 * @config target
7433 * @description String specifying the value for the "target" attribute
7434 * of the menu item's anchor element. <strong>Specifying a target will
7435 * require the user to click directly on the menu item's anchor node in
7436 * order to cause the browser to navigate to the specified URL.</strong>
7437 * When building a menu from existing HTML the value of this property
7438 * will be interpreted from the menu's markup.
7439 * @default null
7440 * @type String
7442 oConfig.addProperty(
7443 DEFAULT_CONFIG.TARGET.key,
7445 handler: this.configTarget,
7446 suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent
7452 * @config emphasis
7453 * @description Boolean indicating if the text of the menu item will be
7454 * rendered with emphasis.
7455 * @deprecated Use "text" configuration property to add emphasis.
7456 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some
7457 * Text&#60;/em&#62;");</code>
7458 * @default false
7459 * @type Boolean
7461 oConfig.addProperty(
7462 DEFAULT_CONFIG.EMPHASIS.key,
7464 handler: this.configEmphasis,
7465 value: DEFAULT_CONFIG.EMPHASIS.value,
7466 validator: DEFAULT_CONFIG.EMPHASIS.validator,
7467 suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent,
7468 supercedes: DEFAULT_CONFIG.EMPHASIS.supercedes
7474 * @config strongemphasis
7475 * @description Boolean indicating if the text of the menu item will be
7476 * rendered with strong emphasis.
7477 * @deprecated Use "text" configuration property to add strong emphasis.
7478 * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62;
7479 * Some Text&#60;/strong&#62;");</code>
7480 * @default false
7481 * @type Boolean
7483 oConfig.addProperty(
7484 DEFAULT_CONFIG.STRONG_EMPHASIS.key,
7486 handler: this.configStrongEmphasis,
7487 value: DEFAULT_CONFIG.STRONG_EMPHASIS.value,
7488 validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator,
7489 suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent,
7490 supercedes: DEFAULT_CONFIG.STRONG_EMPHASIS.supercedes
7496 * @config checked
7497 * @description Boolean indicating if the menu item should be rendered
7498 * with a checkmark.
7499 * @default false
7500 * @type Boolean
7502 oConfig.addProperty(
7503 DEFAULT_CONFIG.CHECKED.key,
7505 handler: this.configChecked,
7506 value: DEFAULT_CONFIG.CHECKED.value,
7507 validator: DEFAULT_CONFIG.CHECKED.validator,
7508 suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent,
7509 supercedes: DEFAULT_CONFIG.CHECKED.supercedes
7515 * @config disabled
7516 * @description Boolean indicating if the menu item should be disabled.
7517 * (Disabled menu items are dimmed and will not respond to user input
7518 * or fire events.)
7519 * @default false
7520 * @type Boolean
7522 oConfig.addProperty(
7523 DEFAULT_CONFIG.DISABLED.key,
7525 handler: this.configDisabled,
7526 value: DEFAULT_CONFIG.DISABLED.value,
7527 validator: DEFAULT_CONFIG.DISABLED.validator,
7528 suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
7534 * @config selected
7535 * @description Boolean indicating if the menu item should
7536 * be highlighted.
7537 * @default false
7538 * @type Boolean
7540 oConfig.addProperty(
7541 DEFAULT_CONFIG.SELECTED.key,
7543 handler: this.configSelected,
7544 value: DEFAULT_CONFIG.SELECTED.value,
7545 validator: DEFAULT_CONFIG.SELECTED.validator,
7546 suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent
7552 * @config submenu
7553 * @description Object specifying the submenu to be appended to the
7554 * menu item. The value can be one of the following: <ul><li>Object
7555 * specifying a Menu instance.</li><li>Object literal specifying the
7556 * menu to be created. Format: <code>{ id: [menu id], itemdata:
7557 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
7558 * items</a>] }</code>.</li><li>String specifying the id attribute
7559 * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
7560 * Object specifying the <code>&#60;div&#62;</code> element of the
7561 * menu.</li></ul>
7562 * @default null
7563 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
7564 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7565 * HTMLElement</a>
7567 oConfig.addProperty(
7568 DEFAULT_CONFIG.SUBMENU.key,
7570 handler: this.configSubmenu,
7571 supercedes: DEFAULT_CONFIG.SUBMENU.supercedes,
7572 suppressEvent: DEFAULT_CONFIG.SUBMENU.suppressEvent
7578 * @config onclick
7579 * @description Object literal representing the code to be executed when
7580 * the item is clicked. Format:<br> <code> {<br>
7581 * <strong>fn:</strong> Function, &#47;&#47; The handler to call when
7582 * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An
7583 * object to pass back to the handler.<br> <strong>scope:</strong>
7584 * Object &#47;&#47; The object to use for the scope of the handler.
7585 * <br> } </code>
7586 * @type Object
7587 * @default null
7589 oConfig.addProperty(
7590 DEFAULT_CONFIG.ONCLICK.key,
7592 handler: this.configOnClick,
7593 suppressEvent: DEFAULT_CONFIG.ONCLICK.suppressEvent
7599 * @config classname
7600 * @description CSS class to be applied to the menu item's root
7601 * <code>&#60;li&#62;</code> element. The specified class(es) are
7602 * appended in addition to the default class as specified by the menu
7603 * item's CSS_CLASS_NAME constant.
7604 * @default null
7605 * @type String
7607 oConfig.addProperty(
7608 DEFAULT_CONFIG.CLASS_NAME.key,
7610 handler: this.configClassName,
7611 value: DEFAULT_CONFIG.CLASS_NAME.value,
7612 validator: DEFAULT_CONFIG.CLASS_NAME.validator,
7613 suppressEvent: DEFAULT_CONFIG.CLASS_NAME.suppressEvent
7621 * @method getNextEnabledSibling
7622 * @description Finds the menu item's next enabled sibling.
7623 * @return YAHOO.widget.MenuItem
7625 getNextEnabledSibling: function () {
7627 var nGroupIndex,
7628 aItemGroups,
7629 oNextItem,
7630 nNextGroupIndex,
7631 aNextGroup;
7633 function getNextArrayItem(p_aArray, p_nStartIndex) {
7635 return p_aArray[p_nStartIndex] ||
7636 getNextArrayItem(p_aArray, (p_nStartIndex+1));
7640 if (this.parent instanceof Menu) {
7642 nGroupIndex = this.groupIndex;
7644 aItemGroups = this.parent.getItemGroups();
7646 if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
7648 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex],
7649 (this.index+1));
7652 else {
7654 if (nGroupIndex < (aItemGroups.length - 1)) {
7656 nNextGroupIndex = nGroupIndex + 1;
7659 else {
7661 nNextGroupIndex = 0;
7665 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
7667 // Retrieve the first menu item in the next group
7669 oNextItem = getNextArrayItem(aNextGroup, 0);
7673 return (oNextItem.cfg.getProperty("disabled") ||
7674 oNextItem.element.style.display == "none") ?
7675 oNextItem.getNextEnabledSibling() : oNextItem;
7683 * @method getPreviousEnabledSibling
7684 * @description Finds the menu item's previous enabled sibling.
7685 * @return {YAHOO.widget.MenuItem}
7687 getPreviousEnabledSibling: function () {
7689 var nGroupIndex,
7690 aItemGroups,
7691 oPreviousItem,
7692 nPreviousGroupIndex,
7693 aPreviousGroup;
7695 function getPreviousArrayItem(p_aArray, p_nStartIndex) {
7697 return p_aArray[p_nStartIndex] ||
7698 getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
7702 function getFirstItemIndex(p_aArray, p_nStartIndex) {
7704 return p_aArray[p_nStartIndex] ? p_nStartIndex :
7705 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
7709 if (this.parent instanceof Menu) {
7711 nGroupIndex = this.groupIndex;
7712 aItemGroups = this.parent.getItemGroups();
7715 if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
7717 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex],
7718 (this.index-1));
7721 else {
7723 if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
7725 nPreviousGroupIndex = nGroupIndex - 1;
7728 else {
7730 nPreviousGroupIndex = aItemGroups.length - 1;
7734 aPreviousGroup = getPreviousArrayItem(aItemGroups,
7735 nPreviousGroupIndex);
7737 oPreviousItem = getPreviousArrayItem(aPreviousGroup,
7738 (aPreviousGroup.length - 1));
7742 return (oPreviousItem.cfg.getProperty("disabled") ||
7743 oPreviousItem.element.style.display == "none") ?
7744 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
7752 * @method focus
7753 * @description Causes the menu item to receive the focus and fires the
7754 * focus event.
7756 focus: function () {
7758 var oParent = this.parent,
7759 oAnchor = this._oAnchor,
7760 oActiveItem = oParent.activeItem,
7761 me = this;
7764 function setFocus() {
7766 try {
7768 if (YAHOO.env.ua.ie && !document.hasFocus()) {
7770 return;
7774 if (oActiveItem) {
7776 oActiveItem.blurEvent.fire();
7780 oAnchor.focus();
7782 me.focusEvent.fire();
7785 catch(e) {
7792 if (!this.cfg.getProperty("disabled") && oParent &&
7793 oParent.cfg.getProperty("visible") &&
7794 this.element.style.display != "none") {
7798 Setting focus via a timer fixes a race condition in Firefox, IE
7799 and Opera where the browser viewport jumps as it trys to
7800 position and focus the menu.
7803 window.setTimeout(setFocus, 0);
7811 * @method blur
7812 * @description Causes the menu item to lose focus and fires the
7813 * blur event.
7815 blur: function () {
7817 var oParent = this.parent;
7819 if (!this.cfg.getProperty("disabled") && oParent &&
7820 oParent.cfg.getProperty("visible")) {
7823 var me = this;
7825 window.setTimeout(function () {
7827 try {
7829 me._oAnchor.blur();
7830 me.blurEvent.fire();
7833 catch (e) {
7837 }, 0);
7845 * @method hasFocus
7846 * @description Returns a boolean indicating whether or not the menu item
7847 * has focus.
7848 * @return {Boolean}
7850 hasFocus: function () {
7852 return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
7858 * @method destroy
7859 * @description Removes the menu item's <code>&#60;li&#62;</code> element
7860 * from its parent <code>&#60;ul&#62;</code> element.
7862 destroy: function () {
7864 var oEl = this.element,
7865 oSubmenu,
7866 oParentNode;
7868 if (oEl) {
7871 // If the item has a submenu, destroy it first
7873 oSubmenu = this.cfg.getProperty("submenu");
7875 if (oSubmenu) {
7877 oSubmenu.destroy();
7882 // Remove CustomEvent listeners
7884 this.mouseOverEvent.unsubscribeAll();
7885 this.mouseOutEvent.unsubscribeAll();
7886 this.mouseDownEvent.unsubscribeAll();
7887 this.mouseUpEvent.unsubscribeAll();
7888 this.clickEvent.unsubscribeAll();
7889 this.keyPressEvent.unsubscribeAll();
7890 this.keyDownEvent.unsubscribeAll();
7891 this.keyUpEvent.unsubscribeAll();
7892 this.focusEvent.unsubscribeAll();
7893 this.blurEvent.unsubscribeAll();
7894 this.cfg.configChangedEvent.unsubscribeAll();
7897 // Remove the element from the parent node
7899 oParentNode = oEl.parentNode;
7901 if (oParentNode) {
7903 oParentNode.removeChild(oEl);
7905 this.destroyEvent.fire();
7909 this.destroyEvent.unsubscribeAll();
7917 * @method toString
7918 * @description Returns a string representing the menu item.
7919 * @return {String}
7921 toString: function () {
7923 var sReturnVal = "MenuItem",
7924 sId = this.id;
7926 if (sId) {
7928 sReturnVal += (" " + sId);
7932 return sReturnVal;
7938 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
7940 })();
7941 (function () {
7945 * Creates a list of options or commands which are made visible in response to
7946 * an HTML element's "contextmenu" event ("mousedown" for Opera).
7948 * @param {String} p_oElement String specifying the id attribute of the
7949 * <code>&#60;div&#62;</code> element of the context menu.
7950 * @param {String} p_oElement String specifying the id attribute of the
7951 * <code>&#60;select&#62;</code> element to be used as the data source for the
7952 * context menu.
7953 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7954 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
7955 * <code>&#60;div&#62;</code> element of the context menu.
7956 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
7957 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
7958 * the <code>&#60;select&#62;</code> element to be used as the data source for
7959 * the context menu.
7960 * @param {Object} p_oConfig Optional. Object literal specifying the
7961 * configuration for the context menu. See configuration class documentation
7962 * for more details.
7963 * @class ContextMenu
7964 * @constructor
7965 * @extends YAHOO.widget.Menu
7966 * @namespace YAHOO.widget
7968 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
7970 YAHOO.widget.ContextMenu.superclass.constructor.call(this,
7971 p_oElement, p_oConfig);
7976 var Event = YAHOO.util.Event,
7977 ContextMenu = YAHOO.widget.ContextMenu,
7982 * Constant representing the name of the ContextMenu's events
7983 * @property EVENT_TYPES
7984 * @private
7985 * @final
7986 * @type Object
7988 EVENT_TYPES = {
7990 "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
7991 "CONTEXT_MENU": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"),
7992 "CLICK": "click"
7998 * Constant representing the ContextMenu's configuration properties
7999 * @property DEFAULT_CONFIG
8000 * @private
8001 * @final
8002 * @type Object
8004 DEFAULT_CONFIG = {
8006 "TRIGGER": {
8007 key: "trigger",
8008 suppressEvent: true
8015 * @method position
8016 * @description "beforeShow" event handler used to position the contextmenu.
8017 * @private
8018 * @param {String} p_sType String representing the name of the event that
8019 * was fired.
8020 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8021 * @param {Array} p_aPos Array representing the xy position for the context menu.
8023 function position(p_sType, p_aArgs, p_aPos) {
8025 this.cfg.setProperty("xy", p_aPos);
8027 this.beforeShowEvent.unsubscribe(position, p_aPos);
8032 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8036 // Private properties
8040 * @property _oTrigger
8041 * @description Object reference to the current value of the "trigger"
8042 * configuration property.
8043 * @default null
8044 * @private
8045 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8046 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8048 _oTrigger: null,
8052 * @property _bCancelled
8053 * @description Boolean indicating if the display of the context menu should
8054 * be cancelled.
8055 * @default false
8056 * @private
8057 * @type Boolean
8059 _bCancelled: false,
8063 // Public properties
8067 * @property contextEventTarget
8068 * @description Object reference for the HTML element that was the target of the
8069 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
8070 * the context menu.
8071 * @default null
8072 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8073 * html.html#ID-58190037">HTMLElement</a>
8075 contextEventTarget: null,
8079 // Events
8083 * @event triggerContextMenuEvent
8084 * @description Custom Event wrapper for the "contextmenu" DOM event
8085 * ("mousedown" for Opera) fired by the element(s) that trigger the display of
8086 * the context menu.
8088 triggerContextMenuEvent: null,
8093 * @method init
8094 * @description The ContextMenu class's initialization method. This method is
8095 * automatically called by the constructor, and sets up all DOM references for
8096 * pre-existing markup, and creates required markup if it is not already present.
8097 * @param {String} p_oElement String specifying the id attribute of the
8098 * <code>&#60;div&#62;</code> element of the context menu.
8099 * @param {String} p_oElement String specifying the id attribute of the
8100 * <code>&#60;select&#62;</code> element to be used as the data source for
8101 * the context menu.
8102 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8103 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
8104 * <code>&#60;div&#62;</code> element of the context menu.
8105 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8106 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
8107 * the <code>&#60;select&#62;</code> element to be used as the data source for
8108 * the context menu.
8109 * @param {Object} p_oConfig Optional. Object literal specifying the
8110 * configuration for the context menu. See configuration class documentation
8111 * for more details.
8113 init: function(p_oElement, p_oConfig) {
8116 // Call the init of the superclass (YAHOO.widget.Menu)
8118 ContextMenu.superclass.init.call(this, p_oElement);
8121 this.beforeInitEvent.fire(ContextMenu);
8124 if(p_oConfig) {
8126 this.cfg.applyConfig(p_oConfig, true);
8131 this.initEvent.fire(ContextMenu);
8137 * @method initEvents
8138 * @description Initializes the custom events for the context menu.
8140 initEvents: function() {
8142 ContextMenu.superclass.initEvents.call(this);
8144 // Create custom events
8146 this.triggerContextMenuEvent =
8147 this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8149 this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8155 * @method cancel
8156 * @description Cancels the display of the context menu.
8158 cancel: function() {
8160 this._bCancelled = true;
8166 // Private methods
8170 * @method _removeEventHandlers
8171 * @description Removes all of the DOM event handlers from the HTML element(s)
8172 * whose "context menu" event ("click" for Opera) trigger the display of
8173 * the context menu.
8174 * @private
8176 _removeEventHandlers: function() {
8178 var oTrigger = this._oTrigger;
8181 // Remove the event handlers from the trigger(s)
8183 if (oTrigger) {
8185 Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8186 this._onTriggerContextMenu);
8188 if(YAHOO.env.ua.opera) {
8190 Event.removeListener(oTrigger, EVENT_TYPES.CLICK,
8191 this._onTriggerClick);
8201 // Private event handlers
8206 * @method _onTriggerClick
8207 * @description "click" event handler for the HTML element(s) identified as the
8208 * "trigger" for the context menu. Used to cancel default behaviors in Opera.
8209 * @private
8210 * @param {Event} p_oEvent Object representing the DOM event object passed back
8211 * by the event utility (YAHOO.util.Event).
8212 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8213 * menu that is handling the event.
8215 _onTriggerClick: function(p_oEvent, p_oMenu) {
8217 if(p_oEvent.ctrlKey) {
8219 Event.stopEvent(p_oEvent);
8227 * @method _onTriggerContextMenu
8228 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
8229 * element(s) that trigger the display of the context menu.
8230 * @private
8231 * @param {Event} p_oEvent Object representing the DOM event object passed back
8232 * by the event utility (YAHOO.util.Event).
8233 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8234 * menu that is handling the event.
8236 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8238 if (p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {
8240 return;
8245 var aXY;
8249 Prevent the browser's default context menu from appearing and
8250 stop the propagation of the "contextmenu" event so that
8251 other ContextMenu instances are not displayed.
8254 Event.stopEvent(p_oEvent);
8257 this.contextEventTarget = Event.getTarget(p_oEvent);
8259 this.triggerContextMenuEvent.fire(p_oEvent);
8262 // Hide any other Menu instances that might be visible
8264 YAHOO.widget.MenuManager.hideVisible();
8268 if(!this._bCancelled) {
8270 // Position and display the context menu
8272 aXY = Event.getXY(p_oEvent);
8275 if (!YAHOO.util.Dom.inDocument(this.element)) {
8277 this.beforeShowEvent.subscribe(position, aXY);
8280 else {
8282 this.cfg.setProperty("xy", aXY);
8287 this.show();
8291 this._bCancelled = false;
8297 // Public methods
8301 * @method toString
8302 * @description Returns a string representing the context menu.
8303 * @return {String}
8305 toString: function() {
8307 var sReturnVal = "ContextMenu",
8308 sId = this.id;
8310 if(sId) {
8312 sReturnVal += (" " + sId);
8316 return sReturnVal;
8322 * @method initDefaultConfig
8323 * @description Initializes the class's configurable properties which can be
8324 * changed using the context menu's Config object ("cfg").
8326 initDefaultConfig: function() {
8328 ContextMenu.superclass.initDefaultConfig.call(this);
8331 * @config trigger
8332 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
8333 * for Opera) trigger the display of the context menu. Can be a string
8334 * representing the id attribute of the HTML element, an object reference
8335 * for the HTML element, or an array of strings or HTML element references.
8336 * @default null
8337 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8338 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8340 this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key,
8342 handler: this.configTrigger,
8343 suppressEvent: DEFAULT_CONFIG.TRIGGER.suppressEvent
8351 * @method destroy
8352 * @description Removes the context menu's <code>&#60;div&#62;</code> element
8353 * (and accompanying child nodes) from the document.
8355 destroy: function() {
8357 // Remove the DOM event handlers from the current trigger(s)
8359 this._removeEventHandlers();
8362 // Continue with the superclass implementation of this method
8364 ContextMenu.superclass.destroy.call(this);
8370 // Public event handlers for configuration properties
8374 * @method configTrigger
8375 * @description Event handler for when the value of the "trigger" configuration
8376 * property changes.
8377 * @param {String} p_sType String representing the name of the event that
8378 * was fired.
8379 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8380 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
8381 * menu that fired the event.
8383 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8385 var oTrigger = p_aArgs[0];
8387 if(oTrigger) {
8390 If there is a current "trigger" - remove the event handlers
8391 from that element(s) before assigning new ones
8394 if(this._oTrigger) {
8396 this._removeEventHandlers();
8400 this._oTrigger = oTrigger;
8404 Listen for the "mousedown" event in Opera b/c it does not
8405 support the "contextmenu" event
8408 Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU,
8409 this._onTriggerContextMenu, this, true);
8413 Assign a "click" event handler to the trigger element(s) for
8414 Opera to prevent default browser behaviors.
8417 if(YAHOO.env.ua.opera) {
8419 Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick,
8420 this, true);
8425 else {
8427 this._removeEventHandlers();
8433 }); // END YAHOO.lang.extend
8435 }());
8440 * Creates an item for a context menu.
8442 * @param {String} p_oObject String specifying the text of the context menu item.
8443 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8444 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8445 * <code>&#60;li&#62;</code> element of the context menu item.
8446 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8447 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8448 * specifying the <code>&#60;optgroup&#62;</code> element of the context
8449 * menu item.
8450 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8451 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8452 * the <code>&#60;option&#62;</code> element of the context menu item.
8453 * @param {Object} p_oConfig Optional. Object literal specifying the
8454 * configuration for the context menu item. See configuration class
8455 * documentation for more details.
8456 * @class ContextMenuItem
8457 * @constructor
8458 * @extends YAHOO.widget.MenuItem
8459 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
8460 * are of type YAHOO.widget.MenuItem.
8462 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
8463 (function () {
8467 * Horizontal collection of items, each of which can contain a submenu.
8469 * @param {String} p_oElement String specifying the id attribute of the
8470 * <code>&#60;div&#62;</code> element of the menu bar.
8471 * @param {String} p_oElement String specifying the id attribute of the
8472 * <code>&#60;select&#62;</code> element to be used as the data source for the
8473 * menu bar.
8474 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8475 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8476 * the <code>&#60;div&#62;</code> element of the menu bar.
8477 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8478 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8479 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8480 * source for the menu bar.
8481 * @param {Object} p_oConfig Optional. Object literal specifying the
8482 * configuration for the menu bar. See configuration class documentation for
8483 * more details.
8484 * @class MenuBar
8485 * @constructor
8486 * @extends YAHOO.widget.Menu
8487 * @namespace YAHOO.widget
8489 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
8491 YAHOO.widget.MenuBar.superclass.constructor.call(this,
8492 p_oElement, p_oConfig);
8498 * @method checkPosition
8499 * @description Checks to make sure that the value of the "position" property
8500 * is one of the supported strings. Returns true if the position is supported.
8501 * @private
8502 * @param {Object} p_sPosition String specifying the position of the menu.
8503 * @return {Boolean}
8505 function checkPosition(p_sPosition) {
8507 if (typeof p_sPosition == "string") {
8509 return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);
8516 var Event = YAHOO.util.Event,
8517 MenuBar = YAHOO.widget.MenuBar,
8520 * Constant representing the MenuBar's configuration properties
8521 * @property DEFAULT_CONFIG
8522 * @private
8523 * @final
8524 * @type Object
8526 DEFAULT_CONFIG = {
8528 "POSITION": {
8529 key: "position",
8530 value: "static",
8531 validator: checkPosition,
8532 supercedes: ["visible"]
8535 "SUBMENU_ALIGNMENT": {
8536 key: "submenualignment",
8537 value: ["tl","bl"],
8538 suppressEvent: true
8541 "AUTO_SUBMENU_DISPLAY": {
8542 key: "autosubmenudisplay",
8543 value: false,
8544 validator: YAHOO.lang.isBoolean,
8545 suppressEvent: true
8552 YAHOO.lang.extend(MenuBar, YAHOO.widget.Menu, {
8555 * @method init
8556 * @description The MenuBar class's initialization method. This method is
8557 * automatically called by the constructor, and sets up all DOM references for
8558 * pre-existing markup, and creates required markup if it is not already present.
8559 * @param {String} p_oElement String specifying the id attribute of the
8560 * <code>&#60;div&#62;</code> element of the menu bar.
8561 * @param {String} p_oElement String specifying the id attribute of the
8562 * <code>&#60;select&#62;</code> element to be used as the data source for the
8563 * menu bar.
8564 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8565 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
8566 * the <code>&#60;div&#62;</code> element of the menu bar.
8567 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8568 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
8569 * specifying the <code>&#60;select&#62;</code> element to be used as the data
8570 * source for the menu bar.
8571 * @param {Object} p_oConfig Optional. Object literal specifying the
8572 * configuration for the menu bar. See configuration class documentation for
8573 * more details.
8575 init: function(p_oElement, p_oConfig) {
8577 if(!this.ITEM_TYPE) {
8579 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
8584 // Call the init of the superclass (YAHOO.widget.Menu)
8586 MenuBar.superclass.init.call(this, p_oElement);
8589 this.beforeInitEvent.fire(MenuBar);
8592 if(p_oConfig) {
8594 this.cfg.applyConfig(p_oConfig, true);
8598 this.initEvent.fire(MenuBar);
8604 // Constants
8608 * @property CSS_CLASS_NAME
8609 * @description String representing the CSS class(es) to be applied to the menu
8610 * bar's <code>&#60;div&#62;</code> element.
8611 * @default "yuimenubar"
8612 * @final
8613 * @type String
8615 CSS_CLASS_NAME: "yuimenubar",
8619 // Protected event handlers
8623 * @method _onKeyDown
8624 * @description "keydown" Custom Event handler for the menu bar.
8625 * @private
8626 * @param {String} p_sType String representing the name of the event that
8627 * was fired.
8628 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8629 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8630 * that fired the event.
8632 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
8634 var oEvent = p_aArgs[0],
8635 oItem = p_aArgs[1],
8636 oSubmenu,
8637 oItemCfg,
8638 oNextItem;
8641 if(oItem && !oItem.cfg.getProperty("disabled")) {
8643 oItemCfg = oItem.cfg;
8645 switch(oEvent.keyCode) {
8647 case 37: // Left arrow
8648 case 39: // Right arrow
8650 if(oItem == this.activeItem &&
8651 !oItemCfg.getProperty("selected")) {
8653 oItemCfg.setProperty("selected", true);
8656 else {
8658 oNextItem = (oEvent.keyCode == 37) ?
8659 oItem.getPreviousEnabledSibling() :
8660 oItem.getNextEnabledSibling();
8662 if(oNextItem) {
8664 this.clearActiveItem();
8666 oNextItem.cfg.setProperty("selected", true);
8669 if(this.cfg.getProperty("autosubmenudisplay")) {
8671 oSubmenu = oNextItem.cfg.getProperty("submenu");
8673 if(oSubmenu) {
8675 oSubmenu.show();
8681 oNextItem.focus();
8687 Event.preventDefault(oEvent);
8689 break;
8691 case 40: // Down arrow
8693 if(this.activeItem != oItem) {
8695 this.clearActiveItem();
8697 oItemCfg.setProperty("selected", true);
8698 oItem.focus();
8702 oSubmenu = oItemCfg.getProperty("submenu");
8704 if(oSubmenu) {
8706 if(oSubmenu.cfg.getProperty("visible")) {
8708 oSubmenu.setInitialSelection();
8709 oSubmenu.setInitialFocus();
8712 else {
8714 oSubmenu.show();
8720 Event.preventDefault(oEvent);
8722 break;
8729 if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
8731 oSubmenu = this.activeItem.cfg.getProperty("submenu");
8733 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
8735 oSubmenu.hide();
8736 this.activeItem.focus();
8739 else {
8741 this.activeItem.cfg.setProperty("selected", false);
8742 this.activeItem.blur();
8746 Event.preventDefault(oEvent);
8754 * @method _onClick
8755 * @description "click" event handler for the menu bar.
8756 * @protected
8757 * @param {String} p_sType String representing the name of the event that
8758 * was fired.
8759 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8760 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
8761 * that fired the event.
8763 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
8765 MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
8767 var oItem = p_aArgs[1],
8768 oEvent,
8769 oTarget,
8770 oActiveItem,
8771 oConfig,
8772 oSubmenu;
8775 if(oItem && !oItem.cfg.getProperty("disabled")) {
8777 oEvent = p_aArgs[0];
8778 oTarget = Event.getTarget(oEvent);
8779 oActiveItem = this.activeItem;
8780 oConfig = this.cfg;
8783 // Hide any other submenus that might be visible
8785 if(oActiveItem && oActiveItem != oItem) {
8787 this.clearActiveItem();
8792 oItem.cfg.setProperty("selected", true);
8795 // Show the submenu for the item
8797 oSubmenu = oItem.cfg.getProperty("submenu");
8800 if(oSubmenu) {
8802 if(oSubmenu.cfg.getProperty("visible")) {
8804 oSubmenu.hide();
8807 else {
8809 oSubmenu.show();
8821 // Public methods
8825 * @method toString
8826 * @description Returns a string representing the menu bar.
8827 * @return {String}
8829 toString: function() {
8831 var sReturnVal = "MenuBar",
8832 sId = this.id;
8834 if(sId) {
8836 sReturnVal += (" " + sId);
8840 return sReturnVal;
8846 * @description Initializes the class's configurable properties which can be
8847 * changed using the menu bar's Config object ("cfg").
8848 * @method initDefaultConfig
8850 initDefaultConfig: function() {
8852 MenuBar.superclass.initDefaultConfig.call(this);
8854 var oConfig = this.cfg;
8856 // Add configuration properties
8860 Set the default value for the "position" configuration property
8861 to "static" by re-adding the property.
8866 * @config position
8867 * @description String indicating how a menu bar should be positioned on the
8868 * screen. Possible values are "static" and "dynamic." Static menu bars
8869 * are visible by default and reside in the normal flow of the document
8870 * (CSS position: static). Dynamic menu bars are hidden by default, reside
8871 * out of the normal flow of the document (CSS position: absolute), and can
8872 * overlay other elements on the screen.
8873 * @default static
8874 * @type String
8876 oConfig.addProperty(
8877 DEFAULT_CONFIG.POSITION.key,
8879 handler: this.configPosition,
8880 value: DEFAULT_CONFIG.POSITION.value,
8881 validator: DEFAULT_CONFIG.POSITION.validator,
8882 supercedes: DEFAULT_CONFIG.POSITION.supercedes
8888 Set the default value for the "submenualignment" configuration property
8889 to ["tl","bl"] by re-adding the property.
8893 * @config submenualignment
8894 * @description Array defining how submenus should be aligned to their
8895 * parent menu bar item. The format is: [itemCorner, submenuCorner].
8896 * @default ["tl","bl"]
8897 * @type Array
8899 oConfig.addProperty(
8900 DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key,
8902 value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
8903 suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
8909 Change the default value for the "autosubmenudisplay" configuration
8910 property to "false" by re-adding the property.
8914 * @config autosubmenudisplay
8915 * @description Boolean indicating if submenus are automatically made
8916 * visible when the user mouses over the menu bar's items.
8917 * @default false
8918 * @type Boolean
8920 oConfig.addProperty(
8921 DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key,
8923 value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value,
8924 validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
8925 suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
8931 }); // END YAHOO.lang.extend
8933 }());
8938 * Creates an item for a menu bar.
8940 * @param {String} p_oObject String specifying the text of the menu bar item.
8941 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8942 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8943 * <code>&#60;li&#62;</code> element of the menu bar item.
8944 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8945 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8946 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8947 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8948 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8949 * the <code>&#60;option&#62;</code> element of the menu bar item.
8950 * @param {Object} p_oConfig Optional. Object literal specifying the
8951 * configuration for the menu bar item. See configuration class documentation
8952 * for more details.
8953 * @class MenuBarItem
8954 * @constructor
8955 * @extends YAHOO.widget.MenuItem
8957 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
8959 YAHOO.widget.MenuBarItem.superclass.constructor.call(this,
8960 p_oObject, p_oConfig);
8964 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
8969 * @method init
8970 * @description The MenuBarItem class's initialization method. This method is
8971 * automatically called by the constructor, and sets up all DOM references for
8972 * pre-existing markup, and creates required markup if it is not already present.
8973 * @param {String} p_oObject String specifying the text of the menu bar item.
8974 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8975 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
8976 * <code>&#60;li&#62;</code> element of the menu bar item.
8977 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8978 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
8979 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
8980 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8981 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
8982 * the <code>&#60;option&#62;</code> element of the menu bar item.
8983 * @param {Object} p_oConfig Optional. Object literal specifying the
8984 * configuration for the menu bar item. See configuration class documentation
8985 * for more details.
8987 init: function(p_oObject, p_oConfig) {
8989 if(!this.SUBMENU_TYPE) {
8991 this.SUBMENU_TYPE = YAHOO.widget.Menu;
8997 Call the init of the superclass (YAHOO.widget.MenuItem)
8998 Note: We don't pass the user config in here yet
8999 because we only want it executed once, at the lowest
9000 subclass level.
9003 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
9006 var oConfig = this.cfg;
9008 if(p_oConfig) {
9010 oConfig.applyConfig(p_oConfig, true);
9014 oConfig.fireQueue();
9020 // Constants
9024 * @property CSS_CLASS_NAME
9025 * @description String representing the CSS class(es) to be applied to the
9026 * <code>&#60;li&#62;</code> element of the menu bar item.
9027 * @default "yuimenubaritem"
9028 * @final
9029 * @type String
9031 CSS_CLASS_NAME: "yuimenubaritem",
9035 * @property CSS_LABEL_CLASS_NAME
9036 * @description String representing the CSS class(es) to be applied to the
9037 * menu bar item's <code>&#60;a&#62;</code> element.
9038 * @default "yuimenubaritemlabel"
9039 * @final
9040 * @type String
9042 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9046 // Public methods
9050 * @method toString
9051 * @description Returns a string representing the menu bar item.
9052 * @return {String}
9054 toString: function() {
9056 var sReturnVal = "MenuBarItem";
9058 if(this.cfg && this.cfg.getProperty("text")) {
9060 sReturnVal += (": " + this.cfg.getProperty("text"));
9064 return sReturnVal;
9068 }); // END YAHOO.lang.extend
9069 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.5.2", build: "1076"});