MDL-26502 check browser - fix for Symbian (backported)
[moodle.git] / lib / yui / menu / menu-debug.js
blobda55e5ebdf15ffb669d7817cfd50dcefd5a6a5f5
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.6.0
6 */
9 /**
10 * @module menu
11 * @description <p>The Menu family of components features a collection of 
12 * controls that make it easy to add menus to your website or web application.  
13 * With the Menu Controls you can create website fly-out menus, customized 
14 * context menus, or application-style menu bars with just a small amount of 
15 * scripting.</p><p>The Menu family of controls features:</p>
16 * <ul>
17 *    <li>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 _DIV = "DIV",
32         _HD = "hd",
33         _BD = "bd",
34         _FT = "ft",
35         _LI = "LI",
36         _DISABLED = "disabled",
37                 _MOUSEOVER = "mouseover",
38                 _MOUSEOUT = "mouseout",
39                 _MOUSEDOWN = "mousedown",
40                 _MOUSEUP = "mouseup",
41                 _FOCUS = YAHOO.env.ua.ie ? "focusin" : "focus",         
42                 _CLICK = "click",
43                 _KEYDOWN = "keydown",
44                 _KEYUP = "keyup",
45                 _KEYPRESS = "keypress",
46                 _CLICK_TO_HIDE = "clicktohide",
47                 _POSITION = "position", 
48                 _DYNAMIC = "dynamic",
49                 _SHOW_DELAY = "showdelay",
50                 _SELECTED = "selected",
51                 _VISIBLE = "visible",
52                 _UL = "UL",
53                 _MENUMANAGER = "MenuManager",
54         
55     
56         Dom = YAHOO.util.Dom,
57         Event = YAHOO.util.Event,
58         Lang = YAHOO.lang;
61     /**
62     * Singleton that manages a collection of all menus and menu items.  Listens 
63     * for DOM events at the document level and dispatches the events to the 
64     * corresponding menu or menu item.
65     *
66     * @namespace YAHOO.widget
67     * @class MenuManager
68     * @static
69     */
70     YAHOO.widget.MenuManager = function () {
71     
72         // Private member variables
73     
74     
75         // Flag indicating if the DOM event handlers have been attached
76     
77         var m_bInitializedEventHandlers = false,
78     
79     
80         // Collection of menus
82         m_oMenus = {},
85         // Collection of visible menus
86     
87         m_oVisibleMenus = {},
88     
89     
90         //  Collection of menu items 
92         m_oItems = {},
95         // Map of DOM event types to their equivalent CustomEvent types
96         
97         m_oEventTypes = {
98             "click": "clickEvent",
99             "mousedown": "mouseDownEvent",
100             "mouseup": "mouseUpEvent",
101             "mouseover": "mouseOverEvent",
102             "mouseout": "mouseOutEvent",
103             "keydown": "keyDownEvent",
104             "keyup": "keyUpEvent",
105             "keypress": "keyPressEvent",
106             "focus": "focusEvent",
107             "focusin": "focusEvent",
108             "blur": "blurEvent",
109             "focusout": "blurEvent"
110         },
113         // The element in the DOM that currently has focus
114     
115                 m_oFocusedElement = null,
116     
117     
118         m_oFocusedMenuItem = null;
119     
120     
121     
122         // Private methods
123     
124     
125         /**
126         * @method getMenuRootElement
127         * @description Finds the root DIV node of a menu or the root LI node of 
128         * a menu item.
129         * @private
130         * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
131         * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object 
132         * specifying an HTML element.
133         */
134         function getMenuRootElement(p_oElement) {
135         
136             var oParentNode,
137                 returnVal;
138     
139             if (p_oElement && p_oElement.tagName) {
140             
141                 switch (p_oElement.tagName.toUpperCase()) {
142                         
143                 case _DIV:
144     
145                     oParentNode = p_oElement.parentNode;
146     
147                     // Check if the DIV is the inner "body" node of a menu
149                     if ((
150                             Dom.hasClass(p_oElement, _HD) ||
151                             Dom.hasClass(p_oElement, _BD) ||
152                             Dom.hasClass(p_oElement, _FT)
153                         ) && 
154                         oParentNode && 
155                         oParentNode.tagName && 
156                         oParentNode.tagName.toUpperCase() == _DIV) {
157                     
158                         returnVal = oParentNode;
159                     
160                     }
161                     else {
162                     
163                         returnVal = p_oElement;
164                     
165                     }
166                 
167                     break;
169                 case _LI:
170     
171                     returnVal = p_oElement;
172                     
173                     break;
175                 default:
176     
177                     oParentNode = p_oElement.parentNode;
178     
179                     if (oParentNode) {
180                     
181                         returnVal = getMenuRootElement(oParentNode);
182                     
183                     }
184                 
185                     break;
186                 
187                 }
188     
189             }
190             
191             return returnVal;
192             
193         }
194     
195     
196     
197         // Private event handlers
198     
199     
200         /**
201         * @method onDOMEvent
202         * @description Generic, global event handler for all of a menu's 
203         * DOM-based events.  This listens for events against the document 
204         * object.  If the target of a given event is a member of a menu or 
205         * menu item's DOM, the instance's corresponding Custom Event is fired.
206         * @private
207         * @param {Event} p_oEvent Object representing the DOM event object  
208         * passed back by the event utility (YAHOO.util.Event).
209         */
210         function onDOMEvent(p_oEvent) {
211     
212             // Get the target node of the DOM event
213         
214             var oTarget = Event.getTarget(p_oEvent),
215                 
216             // See if the target of the event was a menu, or a menu item
217     
218             oElement = getMenuRootElement(oTarget),
219             sCustomEventType,
220             sTagName,
221             sId,
222             oMenuItem,
223             oMenu; 
224     
225     
226             if (oElement) {
227     
228                 sTagName = oElement.tagName.toUpperCase();
229         
230                 if (sTagName == _LI) {
231             
232                     sId = oElement.id;
233             
234                     if (sId && m_oItems[sId]) {
235             
236                         oMenuItem = m_oItems[sId];
237                         oMenu = oMenuItem.parent;
238             
239                     }
240                 
241                 }
242                 else if (sTagName == _DIV) {
243                 
244                     if (oElement.id) {
245                     
246                         oMenu = m_oMenus[oElement.id];
247                     
248                     }
249                 
250                 }
251     
252             }
253     
254     
255             if (oMenu) {
256     
257                 sCustomEventType = m_oEventTypes[p_oEvent.type];
258     
259     
260                 // Fire the Custom Event that corresponds the current DOM event    
261         
262                 if (oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
263     
264                     oMenuItem[sCustomEventType].fire(p_oEvent);                   
265     
266                 }
267         
268                 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
269             
270             }
271             else if (p_oEvent.type == _MOUSEDOWN) {
272     
273                 /*
274                     If the target of the event wasn't a menu, hide all 
275                     dynamically positioned menus
276                 */
277                 
278                 for (var i in m_oVisibleMenus) {
279         
280                     if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
281         
282                         oMenu = m_oVisibleMenus[i];
284                         if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) && 
285                             !(oMenu instanceof YAHOO.widget.MenuBar) && 
286                             oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
287         
288                             oMenu.hide();
289         
290                         }
291                         else {
292                             
293                                                         if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
294                                                         
295                                                                 oMenu._cancelShowDelay();
296                                                         
297                                                         }
300                                                         if (oMenu.activeItem) {
301                                                 
302                                                                 oMenu.activeItem.blur();
303                                                                 oMenu.activeItem.cfg.setProperty(_SELECTED, false);
304                                                 
305                                                                 oMenu.activeItem = null;            
306                                                 
307                                                         }
308         
309                         }
310         
311                     }
312         
313                 } 
314     
315             }
316             else if (p_oEvent.type == _FOCUS) {
317             
318                 m_oFocusedElement = oTarget;
319             
320             }
321             
322         }
323     
324     
325         /**
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.
334         */
335         function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
336     
337             if (m_oMenus[p_oMenu.id]) {
338     
339                 this.removeMenu(p_oMenu);
340     
341             }
342     
343         }
344     
345     
346         /**
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.
354         */
355         function onMenuFocus(p_sType, p_aArgs) {
356     
357             var oItem = p_aArgs[1];
358     
359             if (oItem) {
360     
361                 m_oFocusedMenuItem = oItem;
362             
363             }
364     
365         }
366     
367     
368         /**
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.
376         */
377         function onMenuBlur(p_sType, p_aArgs) {
378     
379             m_oFocusedMenuItem = null;
380     
381         }
382     
384         /**
385         * @method onMenuHide
386         * @description "hide" event handler for a Menu instance.
387         * @private
388         * @param {String} p_sType String representing the name of the event  
389         * that was fired.
390         * @param {Array} p_aArgs Array of arguments sent when the event 
391         * was fired.
392                 * @param <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
393                 * level-one-html.html#ID-58190037">p_oFocusedElement</a> The HTML element that had focus
394                 * prior to the Menu being made visible
395         */    
396         function onMenuHide(p_sType, p_aArgs, p_oFocusedElement) {
398                         /*
399                                 Restore focus to the element in the DOM that had focus prior to the Menu 
400                                 being made visible
401                         */
403                         if (p_oFocusedElement && p_oFocusedElement.focus) {
404                         
405                                 try {
406                                         p_oFocusedElement.focus();
407                                 }
408                                 catch(ex) {
409                                 }
410                         
411                         }
412                         
413                 this.hideEvent.unsubscribe(onMenuHide, p_oFocusedElement);
414         
415         }
416     
418         /**
419         * @method onMenuShow
420         * @description "show" event handler for a MenuItem instance.
421         * @private
422         * @param {String} p_sType String representing the name of the event  
423         * that was fired.
424         * @param {Array} p_aArgs Array of arguments sent when the event 
425         * was fired.
426         */      
427         function onMenuShow(p_sType, p_aArgs) {
429                         /*
430                                 Dynamically positioned, root Menus focus themselves when visible, and will then, 
431                                 when hidden, restore focus to the UI control that had focus before the Menu was 
432                                 made visible
433                         */ 
435                         if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
436         
437                                 this.hideEvent.subscribe(onMenuHide, m_oFocusedElement);
438                                 this.focus();
439                         
440                         }
441         
442         }    
443     
444     
445         /**
446         * @method onMenuVisibleConfigChange
447         * @description Event handler for when the "visible" configuration  
448         * property of a Menu instance changes.
449         * @private
450         * @param {String} p_sType String representing the name of the event  
451         * that was fired.
452         * @param {Array} p_aArgs Array of arguments sent when the event 
453         * was fired.
454         */
455         function onMenuVisibleConfigChange(p_sType, p_aArgs) {
456     
457             var bVisible = p_aArgs[0],
458                 sId = this.id;
459             
460             if (bVisible) {
461     
462                 m_oVisibleMenus[sId] = this;
463                 
464                 YAHOO.log(this + " added to the collection of visible menus.", 
465                         "info", _MENUMANAGER);
466             
467             }
468             else if (m_oVisibleMenus[sId]) {
469             
470                 delete m_oVisibleMenus[sId];
471                 
472                 YAHOO.log(this + " removed from the collection of visible menus.", 
473                         "info", _MENUMANAGER);
474             
475             }
476         
477         }
478     
479     
480         /**
481         * @method onItemDestroy
482         * @description "destroy" event handler for a MenuItem instance.
483         * @private
484         * @param {String} p_sType String representing the name of the event  
485         * that was fired.
486         * @param {Array} p_aArgs Array of arguments sent when the event 
487         * was fired.
488         */
489         function onItemDestroy(p_sType, p_aArgs) {
490     
491             removeItem(this);
492     
493         }
496         /**
497         * @method removeItem
498         * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
499         * @private
500         * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
501         */    
502         function removeItem(p_oMenuItem) {
504             var sId = p_oMenuItem.id;
505     
506             if (sId && m_oItems[sId]) {
507     
508                 if (m_oFocusedMenuItem == p_oMenuItem) {
509     
510                     m_oFocusedMenuItem = null;
511     
512                 }
513     
514                 delete m_oItems[sId];
515                 
516                 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
517     
518                 YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
519     
520             }
522         }
523     
524     
525         /**
526         * @method onItemAdded
527         * @description "itemadded" event handler for a Menu instance.
528         * @private
529         * @param {String} p_sType String representing the name of the event  
530         * that was fired.
531         * @param {Array} p_aArgs Array of arguments sent when the event 
532         * was fired.
533         */
534         function onItemAdded(p_sType, p_aArgs) {
535     
536             var oItem = p_aArgs[0],
537                 sId;
538     
539             if (oItem instanceof YAHOO.widget.MenuItem) { 
540     
541                 sId = oItem.id;
542         
543                 if (!m_oItems[sId]) {
544             
545                     m_oItems[sId] = oItem;
546         
547                     oItem.destroyEvent.subscribe(onItemDestroy);
548         
549                     YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
550         
551                 }
552     
553             }
554         
555         }
556     
557     
558         return {
559     
560             // Privileged methods
561     
562     
563             /**
564             * @method addMenu
565             * @description Adds a menu to the collection of known menus.
566             * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
567             * instance to be added.
568             */
569             addMenu: function (p_oMenu) {
570     
571                 var oDoc;
572     
573                 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id && 
574                     !m_oMenus[p_oMenu.id]) {
575         
576                     m_oMenus[p_oMenu.id] = p_oMenu;
577                 
578             
579                     if (!m_bInitializedEventHandlers) {
580             
581                         oDoc = document;
582                 
583                         Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
584                         Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
585                         Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
586                         Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
587                         Event.on(oDoc, _CLICK, onDOMEvent, this, true);
588                         Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
589                         Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
590                         Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
591     
592                                                 Event.onFocus(oDoc, onDOMEvent, this, true);
593                                                 Event.onBlur(oDoc, onDOMEvent, this, true);                                             
594     
595                         m_bInitializedEventHandlers = true;
596                         
597                         YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
598             
599                     }
600             
601                     p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
602                     p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
603                     p_oMenu.itemAddedEvent.subscribe(onItemAdded);
604                     p_oMenu.focusEvent.subscribe(onMenuFocus);
605                     p_oMenu.blurEvent.subscribe(onMenuBlur);
606                     p_oMenu.showEvent.subscribe(onMenuShow);
607         
608                     YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
609         
610                 }
611         
612             },
613     
614         
615             /**
616             * @method removeMenu
617             * @description Removes a menu from the collection of known menus.
618             * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
619             * instance to be removed.
620             */
621             removeMenu: function (p_oMenu) {
622     
623                 var sId,
624                     aItems,
625                     i;
626         
627                 if (p_oMenu) {
628     
629                     sId = p_oMenu.id;
630         
631                     if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
633                         // Unregister each menu item
635                         aItems = p_oMenu.getItems();
637                         if (aItems && aItems.length > 0) {
639                             i = aItems.length - 1;
641                             do {
643                                 removeItem(aItems[i]);
645                             }
646                             while (i--);
648                         }
651                         // Unregister the menu
653                         delete m_oMenus[sId];
654             
655                         YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
656         
658                         /*
659                              Unregister the menu from the collection of 
660                              visible menus
661                         */
663                         if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
664             
665                             delete m_oVisibleMenus[sId];
666                             
667                             YAHOO.log(p_oMenu + " unregistered from the" + 
668                                         " collection of visible menus.", "info", _MENUMANAGER);
669        
670                         }
673                         // Unsubscribe event listeners
675                         if (p_oMenu.cfg) {
677                             p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE, 
678                                 onMenuVisibleConfigChange);
679                             
680                         }
682                         p_oMenu.destroyEvent.unsubscribe(onMenuDestroy, 
683                             p_oMenu);
684                 
685                         p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
686                         p_oMenu.focusEvent.unsubscribe(onMenuFocus);
687                         p_oMenu.blurEvent.unsubscribe(onMenuBlur);
689                     }
690                 
691                 }
692     
693             },
694         
695         
696             /**
697             * @method hideVisible
698             * @description Hides all visible, dynamically positioned menus 
699             * (excluding instances of YAHOO.widget.MenuBar).
700             */
701             hideVisible: function () {
702         
703                 var oMenu;
704         
705                 for (var i in m_oVisibleMenus) {
706         
707                     if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
708         
709                         oMenu = m_oVisibleMenus[i];
710         
711                         if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
712                             oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
713         
714                             oMenu.hide();
715         
716                         }
717         
718                     }
719         
720                 }        
721     
722             },
725             /**
726             * @method getVisible
727             * @description Returns a collection of all visible menus registered
728             * with the menu manger.
729             * @return {Object}
730             */
731             getVisible: function () {
732             
733                 return m_oVisibleMenus;
734             
735             },
737     
738             /**
739             * @method getMenus
740             * @description Returns a collection of all menus registered with the 
741             * menu manger.
742             * @return {Object}
743             */
744             getMenus: function () {
745     
746                 return m_oMenus;
747             
748             },
749     
750     
751             /**
752             * @method getMenu
753             * @description Returns a menu with the specified id.
754             * @param {String} p_sId String specifying the id of the 
755             * <code>&#60;div&#62;</code> element representing the menu to
756             * be retrieved.
757             * @return {YAHOO.widget.Menu}
758             */
759             getMenu: function (p_sId) {
760                 
761                 var returnVal;
762                 
763                 if (p_sId in m_oMenus) {
764                 
765                                         returnVal = m_oMenus[p_sId];
766                                 
767                                 }
768             
769                 return returnVal;
770             
771             },
772     
773     
774             /**
775             * @method getMenuItem
776             * @description Returns a menu item with the specified id.
777             * @param {String} p_sId String specifying the id of the 
778             * <code>&#60;li&#62;</code> element representing the menu item to
779             * be retrieved.
780             * @return {YAHOO.widget.MenuItem}
781             */
782             getMenuItem: function (p_sId) {
783     
784                         var returnVal;
785     
786                         if (p_sId in m_oItems) {
787     
788                                         returnVal = m_oItems[p_sId];
789                                 
790                                 }
791                                 
792                                 return returnVal;
793             
794             },
797             /**
798             * @method getMenuItemGroup
799             * @description Returns an array of menu item instances whose 
800             * corresponding <code>&#60;li&#62;</code> elements are child 
801             * nodes of the <code>&#60;ul&#62;</code> element with the 
802             * specified id.
803             * @param {String} p_sId String specifying the id of the 
804             * <code>&#60;ul&#62;</code> element representing the group of 
805             * menu items to be retrieved.
806             * @return {Array}
807             */
808             getMenuItemGroup: function (p_sId) {
810                 var oUL = Dom.get(p_sId),
811                     aItems,
812                     oNode,
813                     oItem,
814                     sId,
815                     returnVal;
816     
818                 if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
820                     oNode = oUL.firstChild;
822                     if (oNode) {
824                         aItems = [];
825                         
826                         do {
828                             sId = oNode.id;
830                             if (sId) {
831                             
832                                 oItem = this.getMenuItem(sId);
833                                 
834                                 if (oItem) {
835                                 
836                                     aItems[aItems.length] = oItem;
837                                 
838                                 }
839                             
840                             }
841                         
842                         }
843                         while ((oNode = oNode.nextSibling));
846                         if (aItems.length > 0) {
848                             returnVal = aItems;
849                         
850                         }
852                     }
853                 
854                 }
856                                 return returnVal;
857             
858             },
860     
861             /**
862             * @method getFocusedMenuItem
863             * @description Returns a reference to the menu item that currently 
864             * has focus.
865             * @return {YAHOO.widget.MenuItem}
866             */
867             getFocusedMenuItem: function () {
868     
869                 return m_oFocusedMenuItem;
870     
871             },
872     
873     
874             /**
875             * @method getFocusedMenu
876             * @description Returns a reference to the menu that currently 
877             * has focus.
878             * @return {YAHOO.widget.Menu}
879             */
880             getFocusedMenu: function () {
882                                 var returnVal;
883     
884                 if (m_oFocusedMenuItem) {
885     
886                     returnVal = m_oFocusedMenuItem.parent.getRoot();
887                 
888                 }
889     
890                         return returnVal;
891     
892             },
893     
894         
895             /**
896             * @method toString
897             * @description Returns a string representing the menu manager.
898             * @return {String}
899             */
900             toString: function () {
901             
902                 return _MENUMANAGER;
903             
904             }
905     
906         };
907     
908     }();
910 })();
914 (function () {
916         var Lang = YAHOO.lang,
918         // String constants
919         
920                 _MENU = "Menu",
921                 _DIV_UPPERCASE = "DIV",
922                 _DIV_LOWERCASE = "div",
923                 _ID = "id",
924                 _SELECT = "SELECT",
925                 _XY = "xy",
926                 _Y = "y",
927                 _UL_UPPERCASE = "UL",
928                 _UL_LOWERCASE = "ul",
929                 _FIRST_OF_TYPE = "first-of-type",
930                 _LI = "LI",
931                 _OPTGROUP = "OPTGROUP",
932                 _OPTION = "OPTION",
933                 _DISABLED = "disabled",
934                 _NONE = "none",
935                 _SELECTED = "selected",
936                 _GROUP_INDEX = "groupindex",
937                 _INDEX = "index",
938                 _SUBMENU = "submenu",
939                 _VISIBLE = "visible",
940                 _HIDE_DELAY = "hidedelay",
941                 _POSITION = "position",
942                 _DYNAMIC = "dynamic",
943                 _STATIC = "static",
944                 _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
945                 _WINDOWS = "windows",
946                 _URL = "url",
947                 _HASH = "#",
948                 _TARGET = "target",
949                 _MAX_HEIGHT = "maxheight",
950         _TOP_SCROLLBAR = "topscrollbar",
951         _BOTTOM_SCROLLBAR = "bottomscrollbar",
952         _UNDERSCORE = "_",
953                 _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
954                 _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
955                 _MOUSEMOVE = "mousemove",
956                 _SHOW_DELAY = "showdelay",
957                 _SUBMENU_HIDE_DELAY = "submenuhidedelay",
958                 _IFRAME = "iframe",
959                 _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
960                 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
961                 _SUBMENU_ALIGNMENT = "submenualignment",
962                 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
963                 _CLICK_TO_HIDE = "clicktohide",
964                 _CONTAINER = "container",
965                 _SCROLL_INCREMENT = "scrollincrement",
966                 _MIN_SCROLL_HEIGHT = "minscrollheight",
967                 _CLASSNAME = "classname",
968                 _SHADOW = "shadow",
969                 _KEEP_OPEN = "keepopen",
970                 _HD = "hd",
971                 _HAS_TITLE = "hastitle",
972                 _CONTEXT = "context",
973                 _EMPTY_STRING = "",
974                 _MOUSEDOWN = "mousedown",
975                 _KEYDOWN = "keydown",
976                 _HEIGHT = "height",
977                 _WIDTH = "width",
978                 _PX = "px",
979                 _EFFECT = "effect",
980                 _MONITOR_RESIZE = "monitorresize",
981                 _DISPLAY = "display",
982                 _BLOCK = "block",
983                 _VISIBILITY = "visibility",
984                 _ABSOLUTE = "absolute",
985                 _ZINDEX = "zindex",
986                 _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
987                 _NON_BREAKING_SPACE = "&#32;",
988                 _SPACE = " ",
989                 _MOUSEOVER = "mouseover",
990                 _MOUSEOUT = "mouseout",
991         _ITEM_ADDED = "itemAdded",
992         _ITEM_REMOVED = "itemRemoved",
993         _HIDDEN = "hidden",
994         _YUI_MENU_SHADOW = "yui-menu-shadow",
995         _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
996         _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
1000 * The Menu class creates a container that holds a vertical list representing 
1001 * a set of options or commands.  Menu is the base class for all 
1002 * menu containers. 
1003 * @param {String} p_oElement String specifying the id attribute of the 
1004 * <code>&#60;div&#62;</code> element of the menu.
1005 * @param {String} p_oElement String specifying the id attribute of the 
1006 * <code>&#60;select&#62;</code> element to be used as the data source 
1007 * for the menu.
1008 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1009 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
1010 * specifying the <code>&#60;div&#62;</code> element of the menu.
1011 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1012 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
1013 * Object specifying the <code>&#60;select&#62;</code> element to be used as 
1014 * the data source for the menu.
1015 * @param {Object} p_oConfig Optional. Object literal specifying the 
1016 * configuration for the menu. See configuration class documentation for 
1017 * more details.
1018 * @namespace YAHOO.widget
1019 * @class Menu
1020 * @constructor
1021 * @extends YAHOO.widget.Overlay
1023 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
1025     if (p_oConfig) {
1027         this.parent = p_oConfig.parent;
1028         this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
1029         this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
1031     }
1034     YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1041 * @method checkPosition
1042 * @description Checks to make sure that the value of the "position" property 
1043 * is one of the supported strings. Returns true if the position is supported.
1044 * @private
1045 * @param {Object} p_sPosition String specifying the position of the menu.
1046 * @return {Boolean}
1048 function checkPosition(p_sPosition) {
1050         var returnVal = false;
1052     if (Lang.isString(p_sPosition)) {
1054         returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1056     }
1058         return returnVal;
1063 var Dom = YAHOO.util.Dom,
1064     Event = YAHOO.util.Event,
1065     Module = YAHOO.widget.Module,
1066     Overlay = YAHOO.widget.Overlay,
1067     Menu = YAHOO.widget.Menu,
1068     MenuManager = YAHOO.widget.MenuManager,
1069     CustomEvent = YAHOO.util.CustomEvent,
1070     UA = YAHOO.env.ua,
1071     
1072     m_oShadowTemplate,
1074         EVENT_TYPES = [
1075     
1076                 ["mouseOverEvent", _MOUSEOVER],
1077                 ["mouseOutEvent", _MOUSEOUT],
1078                 ["mouseDownEvent", _MOUSEDOWN],
1079                 ["mouseUpEvent", "mouseup"],
1080                 ["clickEvent", "click"],
1081                 ["keyPressEvent", "keypress"],
1082                 ["keyDownEvent", _KEYDOWN],
1083                 ["keyUpEvent", "keyup"],
1084                 ["focusEvent", "focus"],
1085                 ["blurEvent", "blur"],
1086                 ["itemAddedEvent", _ITEM_ADDED],
1087                 ["itemRemovedEvent", _ITEM_REMOVED]
1089         ],
1091         VISIBLE_CONFIG =  { 
1092                 key: _VISIBLE, 
1093                 value: false, 
1094                 validator: Lang.isBoolean
1095         }, 
1097         CONSTRAIN_TO_VIEWPORT_CONFIG =  {
1098                 key: _CONSTRAIN_TO_VIEWPORT, 
1099                 value: true, 
1100                 validator: Lang.isBoolean, 
1101                 supercedes: [_IFRAME,"x",_Y,_XY]
1102         }, 
1104         PREVENT_CONTEXT_OVERLAP_CONFIG =  {
1105                 key: _PREVENT_CONTEXT_OVERLAP,
1106                 value: true,
1107                 validator: Lang.isBoolean,  
1108                 supercedes: [_CONSTRAIN_TO_VIEWPORT]
1109         },
1111         POSITION_CONFIG =  { 
1112                 key: _POSITION, 
1113                 value: _DYNAMIC, 
1114                 validator: checkPosition, 
1115                 supercedes: [_VISIBLE, _IFRAME]
1116         }, 
1118         SUBMENU_ALIGNMENT_CONFIG =  { 
1119                 key: _SUBMENU_ALIGNMENT, 
1120                 value: ["tl","tr"]
1121         },
1123         AUTO_SUBMENU_DISPLAY_CONFIG =  { 
1124                 key: _AUTO_SUBMENU_DISPLAY, 
1125                 value: true, 
1126                 validator: Lang.isBoolean,
1127                 suppressEvent: true
1128         }, 
1130         SHOW_DELAY_CONFIG =  { 
1131                 key: _SHOW_DELAY, 
1132                 value: 250, 
1133                 validator: Lang.isNumber, 
1134                 suppressEvent: true
1135         }, 
1137         HIDE_DELAY_CONFIG =  { 
1138                 key: _HIDE_DELAY, 
1139                 value: 0, 
1140                 validator: Lang.isNumber, 
1141                 suppressEvent: true
1142         }, 
1144         SUBMENU_HIDE_DELAY_CONFIG =  { 
1145                 key: _SUBMENU_HIDE_DELAY, 
1146                 value: 250, 
1147                 validator: Lang.isNumber,
1148                 suppressEvent: true
1149         }, 
1151         CLICK_TO_HIDE_CONFIG =  { 
1152                 key: _CLICK_TO_HIDE, 
1153                 value: true, 
1154                 validator: Lang.isBoolean,
1155                 suppressEvent: true
1156         },
1158         CONTAINER_CONFIG =  { 
1159                 key: _CONTAINER,
1160                 suppressEvent: true
1161         }, 
1163         SCROLL_INCREMENT_CONFIG =  { 
1164                 key: _SCROLL_INCREMENT, 
1165                 value: 1, 
1166                 validator: Lang.isNumber,
1167                 supercedes: [_MAX_HEIGHT],
1168                 suppressEvent: true
1169         },
1171         MIN_SCROLL_HEIGHT_CONFIG =  { 
1172                 key: _MIN_SCROLL_HEIGHT, 
1173                 value: 90, 
1174                 validator: Lang.isNumber,
1175                 supercedes: [_MAX_HEIGHT],
1176                 suppressEvent: true
1177         },    
1179         MAX_HEIGHT_CONFIG =  { 
1180                 key: _MAX_HEIGHT, 
1181                 value: 0, 
1182                 validator: Lang.isNumber,
1183                 supercedes: [_IFRAME],
1184                 suppressEvent: true
1185         }, 
1187         CLASS_NAME_CONFIG =  { 
1188                 key: _CLASSNAME, 
1189                 value: null, 
1190                 validator: Lang.isString,
1191                 suppressEvent: true
1192         }, 
1194         DISABLED_CONFIG =  { 
1195                 key: _DISABLED, 
1196                 value: false, 
1197                 validator: Lang.isBoolean,
1198                 suppressEvent: true
1199         },
1200         
1201         SHADOW_CONFIG =  { 
1202                 key: _SHADOW, 
1203                 value: true, 
1204                 validator: Lang.isBoolean,
1205                 suppressEvent: true,
1206                 supercedes: [_VISIBLE]
1207         },
1208         
1209         KEEP_OPEN_CONFIG = {
1210                 key: _KEEP_OPEN, 
1211                 value: false, 
1212                 validator: Lang.isBoolean
1213         };
1217 YAHOO.lang.extend(Menu, Overlay, {
1220 // Constants
1224 * @property CSS_CLASS_NAME
1225 * @description String representing the CSS class(es) to be applied to the 
1226 * menu's <code>&#60;div&#62;</code> element.
1227 * @default "yuimenu"
1228 * @final
1229 * @type String
1231 CSS_CLASS_NAME: "yuimenu",
1235 * @property ITEM_TYPE
1236 * @description Object representing the type of menu item to instantiate and 
1237 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element, 
1238 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>) 
1239 * of the menu's source HTML element.
1240 * @default YAHOO.widget.MenuItem
1241 * @final
1242 * @type YAHOO.widget.MenuItem
1244 ITEM_TYPE: null,
1248 * @property GROUP_TITLE_TAG_NAME
1249 * @description String representing the tagname of the HTML element used to 
1250 * title the menu's item groups.
1251 * @default H6
1252 * @final
1253 * @type String
1255 GROUP_TITLE_TAG_NAME: "h6",
1259 * @property OFF_SCREEN_POSITION
1260 * @description Array representing the default x and y position that a menu 
1261 * should have when it is positioned outside the viewport by the 
1262 * "poistionOffScreen" method.
1263 * @default "-999em"
1264 * @final
1265 * @type String
1267 OFF_SCREEN_POSITION: "-999em",
1270 // Private properties
1273 /** 
1274 * @property _bHideDelayEventHandlersAssigned
1275 * @description Boolean indicating if the "mouseover" and "mouseout" event 
1276 * handlers used for hiding the menu via a call to "YAHOO.lang.later" have 
1277 * already been assigned.
1278 * @default false
1279 * @private
1280 * @type Boolean
1282 _bHideDelayEventHandlersAssigned: false,
1286 * @property _bHandledMouseOverEvent
1287 * @description Boolean indicating the current state of the menu's 
1288 * "mouseover" event.
1289 * @default false
1290 * @private
1291 * @type Boolean
1293 _bHandledMouseOverEvent: false,
1297 * @property _bHandledMouseOutEvent
1298 * @description Boolean indicating the current state of the menu's
1299 * "mouseout" event.
1300 * @default false
1301 * @private
1302 * @type Boolean
1304 _bHandledMouseOutEvent: false,
1308 * @property _aGroupTitleElements
1309 * @description Array of HTML element used to title groups of menu items.
1310 * @default []
1311 * @private
1312 * @type Array
1314 _aGroupTitleElements: null,
1318 * @property _aItemGroups
1319 * @description Multi-dimensional Array representing the menu items as they
1320 * are grouped in the menu.
1321 * @default []
1322 * @private
1323 * @type Array
1325 _aItemGroups: null,
1329 * @property _aListElements
1330 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is 
1331 * the parent node for each item's <code>&#60;li&#62;</code> element.
1332 * @default []
1333 * @private
1334 * @type Array
1336 _aListElements: null,
1340 * @property _nCurrentMouseX
1341 * @description The current x coordinate of the mouse inside the area of 
1342 * the menu.
1343 * @default 0
1344 * @private
1345 * @type Number
1347 _nCurrentMouseX: 0,
1351 * @property _bStopMouseEventHandlers
1352 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers 
1353 * from executing.
1354 * @default false
1355 * @private
1356 * @type Boolean
1358 _bStopMouseEventHandlers: false,
1362 * @property _sClassName
1363 * @description The current value of the "classname" configuration attribute.
1364 * @default null
1365 * @private
1366 * @type String
1368 _sClassName: null,
1372 // Public properties
1376 * @property lazyLoad
1377 * @description Boolean indicating if the menu's "lazy load" feature is 
1378 * enabled.  If set to "true," initialization and rendering of the menu's 
1379 * items will be deferred until the first time it is made visible.  This 
1380 * property should be set via the constructor using the configuration 
1381 * object literal.
1382 * @default false
1383 * @type Boolean
1385 lazyLoad: false,
1389 * @property itemData
1390 * @description Array of items to be added to the menu.  The array can contain 
1391 * strings representing the text for each item to be created, object literals 
1392 * representing the menu item configuration properties, or MenuItem instances.  
1393 * This property should be set via the constructor using the configuration 
1394 * object literal.
1395 * @default null
1396 * @type Array
1398 itemData: null,
1402 * @property activeItem
1403 * @description Object reference to the item in the menu that has is selected.
1404 * @default null
1405 * @type YAHOO.widget.MenuItem
1407 activeItem: null,
1411 * @property parent
1412 * @description Object reference to the menu's parent menu or menu item.  
1413 * This property can be set via the constructor using the configuration 
1414 * object literal.
1415 * @default null
1416 * @type YAHOO.widget.MenuItem
1418 parent: null,
1422 * @property srcElement
1423 * @description Object reference to the HTML element (either 
1424 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to 
1425 * create the menu.
1426 * @default null
1427 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1428 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a 
1429 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1430 * html#ID-22445964">HTMLDivElement</a>
1432 srcElement: null,
1436 // Events
1440 * @event mouseOverEvent
1441 * @description Fires when the mouse has entered the menu.  Passes back 
1442 * the DOM Event object as an argument.
1447 * @event mouseOutEvent
1448 * @description Fires when the mouse has left the menu.  Passes back the DOM 
1449 * Event object as an argument.
1450 * @type YAHOO.util.CustomEvent
1455 * @event mouseDownEvent
1456 * @description Fires when the user mouses down on the menu.  Passes back the 
1457 * DOM Event object as an argument.
1458 * @type YAHOO.util.CustomEvent
1463 * @event mouseUpEvent
1464 * @description Fires when the user releases a mouse button while the mouse is 
1465 * over the menu.  Passes back the DOM Event object as an argument.
1466 * @type YAHOO.util.CustomEvent
1471 * @event clickEvent
1472 * @description Fires when the user clicks the on the menu.  Passes back the 
1473 * DOM Event object as an argument.
1474 * @type YAHOO.util.CustomEvent
1479 * @event keyPressEvent
1480 * @description Fires when the user presses an alphanumeric key when one of the
1481 * menu's items has focus.  Passes back the DOM Event object as an argument.
1482 * @type YAHOO.util.CustomEvent
1487 * @event keyDownEvent
1488 * @description Fires when the user presses a key when one of the menu's items 
1489 * has focus.  Passes back the DOM Event object as an argument.
1490 * @type YAHOO.util.CustomEvent
1495 * @event keyUpEvent
1496 * @description Fires when the user releases a key when one of the menu's items 
1497 * has focus.  Passes back the DOM Event object as an argument.
1498 * @type YAHOO.util.CustomEvent
1503 * @event itemAddedEvent
1504 * @description Fires when an item is added to the menu.
1505 * @type YAHOO.util.CustomEvent
1510 * @event itemRemovedEvent
1511 * @description Fires when an item is removed to the menu.
1512 * @type YAHOO.util.CustomEvent
1517 * @method init
1518 * @description The Menu class's initialization method. This method is 
1519 * automatically called by the constructor, and sets up all DOM references 
1520 * for pre-existing markup, and creates required markup if it is not 
1521 * already present.
1522 * @param {String} p_oElement String specifying the id attribute of the 
1523 * <code>&#60;div&#62;</code> element of the menu.
1524 * @param {String} p_oElement String specifying the id attribute of the 
1525 * <code>&#60;select&#62;</code> element to be used as the data source 
1526 * for the menu.
1527 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1528 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
1529 * specifying the <code>&#60;div&#62;</code> element of the menu.
1530 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1531 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
1532 * Object specifying the <code>&#60;select&#62;</code> element to be used as 
1533 * the data source for the menu.
1534 * @param {Object} p_oConfig Optional. Object literal specifying the 
1535 * configuration for the menu. See configuration class documentation for 
1536 * more details.
1538 init: function (p_oElement, p_oConfig) {
1540     this._aItemGroups = [];
1541     this._aListElements = [];
1542     this._aGroupTitleElements = [];
1544     if (!this.ITEM_TYPE) {
1546         this.ITEM_TYPE = YAHOO.widget.MenuItem;
1548     }
1551     var oElement;
1553     if (Lang.isString(p_oElement)) {
1555         oElement = Dom.get(p_oElement);
1557     }
1558     else if (p_oElement.tagName) {
1560         oElement = p_oElement;
1562     }
1565     if (oElement && oElement.tagName) {
1567         switch(oElement.tagName.toUpperCase()) {
1568     
1569             case _DIV_UPPERCASE:
1571                 this.srcElement = oElement;
1573                 if (!oElement.id) {
1575                     oElement.setAttribute(_ID, Dom.generateId());
1577                 }
1580                 /* 
1581                     Note: we don't pass the user config in here yet 
1582                     because we only want it executed once, at the lowest 
1583                     subclass level.
1584                 */ 
1585             
1586                 Menu.superclass.init.call(this, oElement);
1588                 this.beforeInitEvent.fire(Menu);
1590                 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1591     
1592             break;
1593     
1594             case _SELECT:
1595     
1596                 this.srcElement = oElement;
1598     
1599                 /*
1600                     The source element is not something that we can use 
1601                     outright, so we need to create a new Overlay
1603                     Note: we don't pass the user config in here yet 
1604                     because we only want it executed once, at the lowest 
1605                     subclass level.
1606                 */ 
1608                 Menu.superclass.init.call(this, Dom.generateId());
1610                 this.beforeInitEvent.fire(Menu);
1612                                 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1614             break;
1616         }
1618     }
1619     else {
1621         /* 
1622             Note: we don't pass the user config in here yet 
1623             because we only want it executed once, at the lowest 
1624             subclass level.
1625         */ 
1626     
1627         Menu.superclass.init.call(this, p_oElement);
1629         this.beforeInitEvent.fire(Menu);
1631                 YAHOO.log("No source element found.  Created element with id: " + this.id, "info", this.toString());
1633     }
1636     if (this.element) {
1638         Dom.addClass(this.element, this.CSS_CLASS_NAME);
1641         // Subscribe to Custom Events
1643         this.initEvent.subscribe(this._onInit);
1644         this.beforeRenderEvent.subscribe(this._onBeforeRender);
1645         this.renderEvent.subscribe(this._onRender);
1646         this.beforeShowEvent.subscribe(this._onBeforeShow);
1647         this.hideEvent.subscribe(this._onHide);
1648         this.showEvent.subscribe(this._onShow);
1649         this.beforeHideEvent.subscribe(this._onBeforeHide);
1650         this.mouseOverEvent.subscribe(this._onMouseOver);
1651         this.mouseOutEvent.subscribe(this._onMouseOut);
1652         this.clickEvent.subscribe(this._onClick);
1653         this.keyDownEvent.subscribe(this._onKeyDown);
1654         this.keyPressEvent.subscribe(this._onKeyPress);
1655         this.blurEvent.subscribe(this._onBlur);
1656         
1658         if (UA.gecko || UA.webkit) {
1660             this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1662         }
1665         if (p_oConfig) {
1666     
1667             this.cfg.applyConfig(p_oConfig, true);
1668     
1669         }
1672         // Register the Menu instance with the MenuManager
1674         MenuManager.addMenu(this);
1675         
1677         this.initEvent.fire(Menu);
1679     }
1685 // Private methods
1689 * @method _initSubTree
1690 * @description Iterates the childNodes of the source element to find nodes 
1691 * used to instantiate menu and menu items.
1692 * @private
1694 _initSubTree: function () {
1696     var oSrcElement = this.srcElement,
1697         sSrcElementTagName,
1698         nGroup,
1699         sGroupTitleTagName,
1700         oNode,
1701         aListElements,
1702         nListElements,
1703         i;
1706     if (oSrcElement) {
1707     
1708         sSrcElementTagName = 
1709             (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1712         if (sSrcElementTagName == _DIV_UPPERCASE) {
1713     
1714             //  Populate the collection of item groups and item group titles
1715     
1716             oNode = this.body.firstChild;
1717     
1719             if (oNode) {
1720     
1721                 nGroup = 0;
1722                 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1723         
1724                 do {
1725         
1727                     if (oNode && oNode.tagName) {
1728         
1729                         switch (oNode.tagName.toUpperCase()) {
1730         
1731                             case sGroupTitleTagName:
1732                             
1733                                 this._aGroupTitleElements[nGroup] = oNode;
1734         
1735                             break;
1736         
1737                             case _UL_UPPERCASE:
1738         
1739                                 this._aListElements[nGroup] = oNode;
1740                                 this._aItemGroups[nGroup] = [];
1741                                 nGroup++;
1742         
1743                             break;
1744         
1745                         }
1746                     
1747                     }
1748         
1749                 }
1750                 while ((oNode = oNode.nextSibling));
1751         
1752         
1753                 /*
1754                     Apply the "first-of-type" class to the first UL to mimic 
1755                     the ":first-of-type" CSS3 psuedo class.
1756                 */
1757         
1758                 if (this._aListElements[0]) {
1759         
1760                     Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1761         
1762                 }
1763             
1764             }
1765     
1766         }
1767     
1768     
1769         oNode = null;
1770     
1771         YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
1772     
1774         if (sSrcElementTagName) {
1775     
1776             switch (sSrcElementTagName) {
1777         
1778                 case _DIV_UPPERCASE:
1780                     aListElements = this._aListElements;
1781                     nListElements = aListElements.length;
1782         
1783                     if (nListElements > 0) {
1784         
1785                                         YAHOO.log("Found " + nListElements + " item groups to initialize.", 
1786                                                                 "info", this.toString());
1787         
1788                         i = nListElements - 1;
1789         
1790                         do {
1791         
1792                             oNode = aListElements[i].firstChild;
1793             
1794                             if (oNode) {
1796                                 YAHOO.log("Scanning " + 
1797                                     aListElements[i].childNodes.length + 
1798                                     " child nodes for items to initialize.", "info", this.toString());
1799             
1800                                 do {
1801                 
1802                                     if (oNode && oNode.tagName && 
1803                                         oNode.tagName.toUpperCase() == _LI) {
1804                 
1805                                         YAHOO.log("Initializing " + 
1806                                             oNode.tagName + " node.", "info", this.toString());
1807         
1808                                         this.addItem(new this.ITEM_TYPE(oNode, 
1809                                                     { parent: this }), i);
1810             
1811                                     }
1812                         
1813                                 }
1814                                 while ((oNode = oNode.nextSibling));
1815                             
1816                             }
1817                     
1818                         }
1819                         while (i--);
1820         
1821                     }
1822         
1823                 break;
1824         
1825                 case _SELECT:
1826         
1827                     YAHOO.log("Scanning " +  
1828                         oSrcElement.childNodes.length + 
1829                         " child nodes for items to initialize.", "info", this.toString());
1830         
1831                     oNode = oSrcElement.firstChild;
1832         
1833                     do {
1834         
1835                         if (oNode && oNode.tagName) {
1836                         
1837                             switch (oNode.tagName.toUpperCase()) {
1838             
1839                                 case _OPTGROUP:
1840                                 case _OPTION:
1841             
1842                                     YAHOO.log("Initializing " +  
1843                                         oNode.tagName + " node.", "info", this.toString());
1844             
1845                                     this.addItem(
1846                                             new this.ITEM_TYPE(
1847                                                     oNode, 
1848                                                     { parent: this }
1849                                                 )
1850                                             );
1851             
1852                                 break;
1853             
1854                             }
1855     
1856                         }
1857         
1858                     }
1859                     while ((oNode = oNode.nextSibling));
1860         
1861                 break;
1862         
1863             }
1864     
1865         }    
1866     
1867     }
1873 * @method _getFirstEnabledItem
1874 * @description Returns the first enabled item in the menu.
1875 * @return {YAHOO.widget.MenuItem}
1876 * @private
1878 _getFirstEnabledItem: function () {
1880     var aItems = this.getItems(),
1881         nItems = aItems.length,
1882         oItem,
1883         returnVal;
1884     
1886     for(var i=0; i<nItems; i++) {
1888         oItem = aItems[i];
1890         if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1892             returnVal = oItem;
1893             break;
1895         }
1896     
1897     }
1898     
1899     return returnVal;
1900     
1905 * @method _addItemToGroup
1906 * @description Adds a menu item to a group.
1907 * @private
1908 * @param {Number} p_nGroupIndex Number indicating the group to which the 
1909 * item belongs.
1910 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
1911 * instance to be added to the menu.
1912 * @param {String} p_oItem String specifying the text of the item to be added 
1913 * to the menu.
1914 * @param {Object} p_oItem Object literal containing a set of menu item 
1915 * configuration properties.
1916 * @param {Number} p_nItemIndex Optional. Number indicating the index at 
1917 * which the menu item should be added.
1918 * @return {YAHOO.widget.MenuItem}
1920 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1922     var oItem,
1923         nGroupIndex,
1924         aGroup,
1925         oGroupItem,
1926         bAppend,
1927         oNextItemSibling,
1928         nItemIndex,
1929         returnVal;
1932     function getNextItemSibling(p_aArray, p_nStartIndex) {
1934         return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1936     }
1939     if (p_oItem instanceof this.ITEM_TYPE) {
1941         oItem = p_oItem;
1942         oItem.parent = this;
1944     }
1945     else if (Lang.isString(p_oItem)) {
1947         oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1948     
1949     }
1950     else if (Lang.isObject(p_oItem)) {
1952         p_oItem.parent = this;
1954         oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1956     }
1959     if (oItem) {
1961         if (oItem.cfg.getProperty(_SELECTED)) {
1963             this.activeItem = oItem;
1964         
1965         }
1968         nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1969         aGroup = this._getItemGroup(nGroupIndex);
1973         if (!aGroup) {
1975             aGroup = this._createItemGroup(nGroupIndex);
1977         }
1980         if (Lang.isNumber(p_nItemIndex)) {
1982             bAppend = (p_nItemIndex >= aGroup.length);            
1985             if (aGroup[p_nItemIndex]) {
1986     
1987                 aGroup.splice(p_nItemIndex, 0, oItem);
1988     
1989             }
1990             else {
1991     
1992                 aGroup[p_nItemIndex] = oItem;
1993     
1994             }
1997             oGroupItem = aGroup[p_nItemIndex];
1999             if (oGroupItem) {
2001                 if (bAppend && (!oGroupItem.element.parentNode || 
2002                         oGroupItem.element.parentNode.nodeType == 11)) {
2003         
2004                     this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2005     
2006                 }
2007                 else {
2008     
2009                     oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
2010     
2011                     if (oNextItemSibling && (!oGroupItem.element.parentNode || 
2012                             oGroupItem.element.parentNode.nodeType == 11)) {
2013             
2014                         this._aListElements[nGroupIndex].insertBefore(
2015                                 oGroupItem.element, oNextItemSibling.element);
2016         
2017                     }
2018     
2019                 }
2020     
2022                 oGroupItem.parent = this;
2023         
2024                 this._subscribeToItemEvents(oGroupItem);
2025     
2026                 this._configureSubmenu(oGroupItem);
2027                 
2028                 this._updateItemProperties(nGroupIndex);
2029         
2030                 YAHOO.log("Item inserted." + 
2031                     " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2032                     " Index: " + oGroupItem.index + ", " + 
2033                     " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2035                 this.itemAddedEvent.fire(oGroupItem);
2036                 this.changeContentEvent.fire();
2038                 returnVal = oGroupItem;
2039     
2040             }
2042         }
2043         else {
2044     
2045             nItemIndex = aGroup.length;
2046     
2047             aGroup[nItemIndex] = oItem;
2049             oGroupItem = aGroup[nItemIndex];
2050     
2052             if (oGroupItem) {
2053     
2054                 if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2055     
2056                     this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2057     
2058                 }
2059     
2060                 oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2061                 oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2062         
2063                 oGroupItem.parent = this;
2064     
2065                 oGroupItem.index = nItemIndex;
2066                 oGroupItem.groupIndex = nGroupIndex;
2067         
2068                 this._subscribeToItemEvents(oGroupItem);
2069     
2070                 this._configureSubmenu(oGroupItem);
2071     
2072                 if (nItemIndex === 0) {
2073         
2074                     Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2075         
2076                 }
2078                 YAHOO.log("Item added." + 
2079                     " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2080                     " Index: " + oGroupItem.index + ", " + 
2081                     " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2082         
2084                 this.itemAddedEvent.fire(oGroupItem);
2085                 this.changeContentEvent.fire();
2087                 returnVal = oGroupItem;
2088     
2089             }
2090     
2091         }
2093     }
2094     
2095     return returnVal;
2096     
2101 * @method _removeItemFromGroupByIndex
2102 * @description Removes a menu item from a group by index.  Returns the menu 
2103 * item that was removed.
2104 * @private
2105 * @param {Number} p_nGroupIndex Number indicating the group to which the menu 
2106 * item belongs.
2107 * @param {Number} p_nItemIndex Number indicating the index of the menu item 
2108 * to be removed.
2109 * @return {YAHOO.widget.MenuItem}
2111 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2113     var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2114         aGroup = this._getItemGroup(nGroupIndex),
2115         aArray,
2116         oItem,
2117         oUL;
2119     if (aGroup) {
2121         aArray = aGroup.splice(p_nItemIndex, 1);
2122         oItem = aArray[0];
2123     
2124         if (oItem) {
2125     
2126             // Update the index and className properties of each member        
2127             
2128             this._updateItemProperties(nGroupIndex);
2129     
2130             if (aGroup.length === 0) {
2131     
2132                 // Remove the UL
2133     
2134                 oUL = this._aListElements[nGroupIndex];
2135     
2136                 if (this.body && oUL) {
2137     
2138                     this.body.removeChild(oUL);
2139     
2140                 }
2141     
2142                 // Remove the group from the array of items
2143     
2144                 this._aItemGroups.splice(nGroupIndex, 1);
2145     
2146     
2147                 // Remove the UL from the array of ULs
2148     
2149                 this._aListElements.splice(nGroupIndex, 1);
2150     
2151     
2152                 /*
2153                      Assign the "first-of-type" class to the new first UL 
2154                      in the collection
2155                 */
2156     
2157                 oUL = this._aListElements[0];
2158     
2159                 if (oUL) {
2160     
2161                     Dom.addClass(oUL, _FIRST_OF_TYPE);
2162     
2163                 }            
2164     
2165             }
2166     
2168             this.itemRemovedEvent.fire(oItem);
2169             this.changeContentEvent.fire();
2170     
2171         }
2173     }
2175         // Return a reference to the item that was removed
2177         return oItem;
2178     
2183 * @method _removeItemFromGroupByValue
2184 * @description Removes a menu item from a group by reference.  Returns the 
2185 * menu item that was removed.
2186 * @private
2187 * @param {Number} p_nGroupIndex Number indicating the group to which the
2188 * menu item belongs.
2189 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2190 * instance to be removed.
2191 * @return {YAHOO.widget.MenuItem}
2192 */    
2193 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2195     var aGroup = this._getItemGroup(p_nGroupIndex),
2196         nItems,
2197         nItemIndex,
2198         returnVal,
2199         i;
2201     if (aGroup) {
2203         nItems = aGroup.length;
2204         nItemIndex = -1;
2205     
2206         if (nItems > 0) {
2207     
2208             i = nItems-1;
2209         
2210             do {
2211         
2212                 if (aGroup[i] == p_oItem) {
2213         
2214                     nItemIndex = i;
2215                     break;    
2216         
2217                 }
2218         
2219             }
2220             while (i--);
2221         
2222             if (nItemIndex > -1) {
2223         
2224                 returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2225         
2226             }
2227     
2228         }
2229     
2230     }
2231     
2232     return returnVal;
2238 * @method _updateItemProperties
2239 * @description Updates the "index," "groupindex," and "className" properties 
2240 * of the menu items in the specified group. 
2241 * @private
2242 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2244 _updateItemProperties: function (p_nGroupIndex) {
2246     var aGroup = this._getItemGroup(p_nGroupIndex),
2247         nItems = aGroup.length,
2248         oItem,
2249         oLI,
2250         i;
2253     if (nItems > 0) {
2255         i = nItems - 1;
2257         // Update the index and className properties of each member
2258     
2259         do {
2261             oItem = aGroup[i];
2263             if (oItem) {
2264     
2265                 oLI = oItem.element;
2267                 oItem.index = i;
2268                 oItem.groupIndex = p_nGroupIndex;
2270                 oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2271                 oLI.setAttribute(_INDEX, i);
2273                 Dom.removeClass(oLI, _FIRST_OF_TYPE);
2275             }
2276     
2277         }
2278         while (i--);
2281         if (oLI) {
2283             Dom.addClass(oLI, _FIRST_OF_TYPE);
2285         }
2287     }
2293 * @method _createItemGroup
2294 * @description Creates a new menu item group (array) and its associated 
2295 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2296 * @private
2297 * @param {Number} p_nIndex Number indicating the group to create.
2298 * @return {Array}
2300 _createItemGroup: function (p_nIndex) {
2302     var oUL,
2303         returnVal;
2305     if (!this._aItemGroups[p_nIndex]) {
2307         this._aItemGroups[p_nIndex] = [];
2309         oUL = document.createElement(_UL_LOWERCASE);
2311         this._aListElements[p_nIndex] = oUL;
2313         returnVal = this._aItemGroups[p_nIndex];
2315     }
2316     
2317     return returnVal;
2323 * @method _getItemGroup
2324 * @description Returns the menu item group at the specified index.
2325 * @private
2326 * @param {Number} p_nIndex Number indicating the index of the menu item group 
2327 * to be retrieved.
2328 * @return {Array}
2330 _getItemGroup: function (p_nIndex) {
2332     var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2333         aGroups = this._aItemGroups,
2334         returnVal;
2336         if (nIndex in aGroups) {
2338             returnVal = aGroups[nIndex];
2340         }
2341         
2342         return returnVal;
2348 * @method _configureSubmenu
2349 * @description Subscribes the menu item's submenu to its parent menu's events.
2350 * @private
2351 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2352 * instance with the submenu to be configured.
2354 _configureSubmenu: function (p_oItem) {
2356     var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2358     if (oSubmenu) {
2359             
2360         /*
2361             Listen for configuration changes to the parent menu 
2362             so they they can be applied to the submenu.
2363         */
2365         this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2367         this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2369     }
2377 * @method _subscribeToItemEvents
2378 * @description Subscribes a menu to a menu item's event.
2379 * @private
2380 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2381 * instance whose events should be subscribed to.
2383 _subscribeToItemEvents: function (p_oItem) {
2385     p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2386     p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2392 * @method _onVisibleChange
2393 * @description Change event handler for the the menu's "visible" configuration
2394 * property.
2395 * @private
2396 * @param {String} p_sType String representing the name of the event that 
2397 * was fired.
2398 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2400 _onVisibleChange: function (p_sType, p_aArgs) {
2402     var bVisible = p_aArgs[0];
2403     
2404     if (bVisible) {
2406         Dom.addClass(this.element, _VISIBLE);
2408     }
2409     else {
2411         Dom.removeClass(this.element, _VISIBLE);
2413     }
2419 * @method _cancelHideDelay
2420 * @description Cancels the call to "hideMenu."
2421 * @private
2423 _cancelHideDelay: function () {
2425     var oTimer = this.getRoot()._hideDelayTimer;
2427     if (oTimer) {
2429                 oTimer.cancel();
2431     }
2437 * @method _execHideDelay
2438 * @description Hides the menu after the number of milliseconds specified by 
2439 * the "hidedelay" configuration property.
2440 * @private
2442 _execHideDelay: function () {
2444     this._cancelHideDelay();
2446     var oRoot = this.getRoot();
2447         
2448         oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2449     
2450         if (oRoot.activeItem) {
2452                         if (oRoot.hasFocus()) {
2454                                 oRoot.activeItem.focus();
2455                         
2456                         }
2457                         
2458             oRoot.clearActiveItem();
2460         }
2462         if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) && 
2463             this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2465             this.hide();
2466         
2467         }
2468     
2469     });
2475 * @method _cancelShowDelay
2476 * @description Cancels the call to the "showMenu."
2477 * @private
2479 _cancelShowDelay: function () {
2481     var oTimer = this.getRoot()._showDelayTimer;
2483     if (oTimer) {
2485         oTimer.cancel();
2487     }
2493 * @method _execSubmenuHideDelay
2494 * @description Hides a submenu after the number of milliseconds specified by 
2495 * the "submenuhidedelay" configuration property have ellapsed.
2496 * @private
2497 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that  
2498 * should be hidden.
2499 * @param {Number} p_nMouseX The x coordinate of the mouse when it left 
2500 * the specified submenu's parent menu item.
2501 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2502 * before the submenu is hidden.
2504 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2506         p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2508         if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2510             p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2511         
2512                 this.hide();
2514             });
2516         }
2517         else {
2519             p_oSubmenu.hide();
2520         
2521         }
2522         
2523         });
2529 // Protected methods
2533 * @method _disableScrollHeader
2534 * @description Disables the header used for scrolling the body of the menu.
2535 * @protected
2537 _disableScrollHeader: function () {
2539     if (!this._bHeaderDisabled) {
2541         Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2542         this._bHeaderDisabled = true;
2544     }
2550 * @method _disableScrollFooter
2551 * @description Disables the footer used for scrolling the body of the menu.
2552 * @protected
2554 _disableScrollFooter: function () {
2556     if (!this._bFooterDisabled) {
2558         Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2559         this._bFooterDisabled = true;
2561     }
2567 * @method _enableScrollHeader
2568 * @description Enables the header used for scrolling the body of the menu.
2569 * @protected
2571 _enableScrollHeader: function () {
2573     if (this._bHeaderDisabled) {
2575         Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2576         this._bHeaderDisabled = false;
2578     }
2584 * @method _enableScrollFooter
2585 * @description Enables the footer used for scrolling the body of the menu.
2586 * @protected
2588 _enableScrollFooter: function () {
2590     if (this._bFooterDisabled) {
2592         Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2593         this._bFooterDisabled = false;
2595     }
2601 * @method _onMouseOver
2602 * @description "mouseover" event handler for the menu.
2603 * @protected
2604 * @param {String} p_sType String representing the name of the event that 
2605 * was fired.
2606 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2608 _onMouseOver: function (p_sType, p_aArgs) {
2610     var oEvent = p_aArgs[0],
2611         oItem = p_aArgs[1],
2612         oTarget = Event.getTarget(oEvent),
2613         oRoot = this.getRoot(),
2614         oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2615         oParentMenu,
2616         nShowDelay,
2617         bShowDelay,
2618         oActiveItem,
2619         oItemCfg,
2620         oSubmenu;
2623     var showSubmenu = function () {
2625         if (this.parent.cfg.getProperty(_SELECTED)) {
2627             this.show();
2629         }
2631     };
2634     if (!this._bStopMouseEventHandlers) {
2635     
2636                 if (!this._bHandledMouseOverEvent && (oTarget == this.element || 
2637                                 Dom.isAncestor(this.element, oTarget))) {
2638         
2639                         // Menu mouseover logic
2640         
2641                         this._nCurrentMouseX = 0;
2642         
2643                         Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2646                         /*
2647                                 If the mouse is moving from the submenu back to its corresponding menu item, 
2648                                 don't hide the submenu or clear the active MenuItem.
2649                         */
2651                         if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2653                                 this.clearActiveItem();
2655                         }
2656         
2658                         if (this.parent && oSubmenuHideDelayTimer) {
2659         
2660                                 oSubmenuHideDelayTimer.cancel();
2661         
2662                                 this.parent.cfg.setProperty(_SELECTED, true);
2663         
2664                                 oParentMenu = this.parent.parent;
2665         
2666                                 oParentMenu._bHandledMouseOutEvent = true;
2667                                 oParentMenu._bHandledMouseOverEvent = false;
2668         
2669                         }
2670         
2671         
2672                         this._bHandledMouseOverEvent = true;
2673                         this._bHandledMouseOutEvent = false;
2674                 
2675                 }
2676         
2677         
2678                 if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) && 
2679                         (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2680         
2681                         // Menu Item mouseover logic
2682         
2683                         nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2684                         bShowDelay = (nShowDelay > 0);
2685         
2686         
2687                         if (bShowDelay) {
2688                         
2689                                 this._cancelShowDelay();
2690                         
2691                         }
2692         
2693         
2694                         oActiveItem = this.activeItem;
2695                 
2696                         if (oActiveItem) {
2697                 
2698                                 oActiveItem.cfg.setProperty(_SELECTED, false);
2699                 
2700                         }
2701         
2702         
2703                         oItemCfg = oItem.cfg;
2704                 
2705                         // Select and focus the current menu item
2706                 
2707                         oItemCfg.setProperty(_SELECTED, true);
2708         
2709         
2710                         if (this.hasFocus() || oRoot._hasFocus) {
2711                         
2712                                 oItem.focus();
2713                                 
2714                                 oRoot._hasFocus = false;
2715                         
2716                         }
2717         
2718         
2719                         if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2720         
2721                                 // Show the submenu this menu item
2722         
2723                                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2724                         
2725                                 if (oSubmenu) {
2726                         
2727                                         if (bShowDelay) {
2728         
2729                                                 oRoot._showDelayTimer = 
2730                                                         Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2731                         
2732                                         }
2733                                         else {
2734         
2735                                                 oSubmenu.show();
2736         
2737                                         }
2738         
2739                                 }
2740         
2741                         }                        
2742         
2743                         oItem.handledMouseOverEvent = true;
2744                         oItem.handledMouseOutEvent = false;
2745         
2746                 }
2747     
2748     }
2754 * @method _onMouseOut
2755 * @description "mouseout" event handler for the menu.
2756 * @protected
2757 * @param {String} p_sType String representing the name of the event that 
2758 * was fired.
2759 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2761 _onMouseOut: function (p_sType, p_aArgs) {
2763     var oEvent = p_aArgs[0],
2764         oItem = p_aArgs[1],
2765         oRelatedTarget = Event.getRelatedTarget(oEvent),
2766         bMovingToSubmenu = false,
2767         oItemCfg,
2768         oSubmenu,
2769         nSubmenuHideDelay,
2770         nShowDelay;
2773     if (!this._bStopMouseEventHandlers) {
2774     
2775                 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2776         
2777                         oItemCfg = oItem.cfg;
2778                         oSubmenu = oItemCfg.getProperty(_SUBMENU);
2779         
2780         
2781                         if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2782                                         Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2783         
2784                                 bMovingToSubmenu = true;
2785         
2786                         }
2787         
2788         
2789                         if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&  
2790                                 !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2791         
2792                                 // Menu Item mouseout logic
2793         
2794                                 if (!bMovingToSubmenu) {
2795         
2796                                         oItem.cfg.setProperty(_SELECTED, false);
2797         
2798         
2799                                         if (oSubmenu) {
2800         
2801                                                 nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2802         
2803                                                 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2804         
2805                                                 if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 && 
2806                                                         nShowDelay >= nSubmenuHideDelay) {
2807         
2808                                                         this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
2809                                                                         nSubmenuHideDelay);
2810         
2811                                                 }
2812                                                 else {
2813         
2814                                                         oSubmenu.hide();
2815         
2816                                                 }
2817         
2818                                         }
2819         
2820                                 }
2821         
2822         
2823                                 oItem.handledMouseOutEvent = true;
2824                                 oItem.handledMouseOverEvent = false;
2825                 
2826                         }
2827         
2828                 }
2831                 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&  
2832                         !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2833         
2834                         // Menu mouseout logic
2835         
2836                         Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2837         
2838                         this._nCurrentMouseX = Event.getPageX(oEvent);
2839         
2840                         this._bHandledMouseOutEvent = true;
2841                         this._bHandledMouseOverEvent = false;
2842         
2843                 }
2844     
2845     }
2851 * @method _onMouseMove
2852 * @description "click" event handler for the menu.
2853 * @protected
2854 * @param {Event} p_oEvent Object representing the DOM event object passed 
2855 * back by the event utility (YAHOO.util.Event).
2856 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
2857 * fired the event.
2859 _onMouseMove: function (p_oEvent, p_oMenu) {
2861     if (!this._bStopMouseEventHandlers) {
2862     
2863             this._nCurrentMouseX = Event.getPageX(p_oEvent);
2864     
2865     }
2871 * @method _onClick
2872 * @description "click" event handler for the menu.
2873 * @protected
2874 * @param {String} p_sType String representing the name of the event that 
2875 * was fired.
2876 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2878 _onClick: function (p_sType, p_aArgs) {
2880         var oEvent = p_aArgs[0],
2881                 oItem = p_aArgs[1],
2882                 bInMenuAnchor = false,
2883                 oSubmenu,
2884                 oRoot,
2885                 sId,
2886                 sURL,
2887                 nHashPos,
2888                 nLen;
2891         var hide = function () {
2893                 /*
2894                         There is an inconsistency between Firefox 2 for Mac OS X and Firefox 2 Windows 
2895                         regarding the triggering of the display of the browser's context menu and the 
2896                         subsequent firing of the "click" event. In Firefox for Windows, when the user 
2897                         triggers the display of the browser's context menu the "click" event also fires 
2898                         for the document object, even though the "click" event did not fire for the 
2899                         element that was the original target of the "contextmenu" event. This is unique 
2900                         to Firefox on Windows. For all other A-Grade browsers, including Firefox 2 for 
2901                         Mac OS X, the "click" event doesn't fire for the document object. 
2903                         This bug in Firefox 2 for Windows affects Menu as Menu instances listen for 
2904                         events at the document level and have an internal "click" event handler they 
2905                         use to hide themselves when clicked. As a result, in Firefox for Windows a 
2906                         Menu will hide when the user right clicks on a MenuItem to raise the browser's 
2907                         default context menu, because its internal "click" event handler ends up 
2908                         getting called.  The following line fixes this bug.
2909                 */
2911                 if (!((UA.gecko && this.platform == _WINDOWS) && oEvent.button > 0)) {
2912                 
2913                         oRoot = this.getRoot();
2915                         if (oRoot instanceof YAHOO.widget.MenuBar || 
2916                                 oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2918                                 oRoot.clearActiveItem();
2920                         }
2921                         else {
2923                                 oRoot.hide();
2924                         
2925                         }
2926                 
2927                 }       
2928         
2929         };
2932         if (oItem) {
2933         
2934                 if (oItem.cfg.getProperty(_DISABLED)) {
2935                 
2936                         Event.preventDefault(oEvent);
2938                         hide.call(this);
2940                 }
2941                 else {
2943                         oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2944         
2945                         
2946                         /*
2947                                  Check if the URL of the anchor is pointing to an element that is 
2948                                  a child of the menu.
2949                         */
2950                         
2951                         sURL = oItem.cfg.getProperty(_URL);
2953                 
2954                         if (sURL) {
2955         
2956                                 nHashPos = sURL.indexOf(_HASH);
2957         
2958                                 nLen = sURL.length;
2959         
2960         
2961                                 if (nHashPos != -1) {
2962         
2963                                         sURL = sURL.substr(nHashPos, nLen);
2964                 
2965                                         nLen = sURL.length;
2966         
2967         
2968                                         if (nLen > 1) {
2969         
2970                                                 sId = sURL.substr(1, nLen);
2971         
2972                                                 bInMenuAnchor = Dom.isAncestor(this.element, sId);
2973                                                 
2974                                         }
2975                                         else if (nLen === 1) {
2976         
2977                                                 bInMenuAnchor = true;
2978                                         
2979                                         }
2980         
2981                                 }
2982                         
2983                         }
2986         
2987                         if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
2988         
2989                                 Event.preventDefault(oEvent);
2990                                 
2992                                 if (UA.webkit) {
2993                                 
2994                                         oItem.focus();
2995                                 
2996                                 }
2997                                 else {
2999                                         oItem.focusEvent.fire();
3000                                 
3001                                 }
3002                         
3003                         }
3004         
3005         
3006                         if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
3007         
3008                                 hide.call(this);
3009         
3010                         }
3011                         
3012                 }
3013         
3014         }
3020 * @method _onKeyDown
3021 * @description "keydown" event handler for the menu.
3022 * @protected
3023 * @param {String} p_sType String representing the name of the event that 
3024 * was fired.
3025 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3027 _onKeyDown: function (p_sType, p_aArgs) {
3029     var oEvent = p_aArgs[0],
3030         oItem = p_aArgs[1],
3031         oSubmenu,
3032         oItemCfg,
3033         oParentItem,
3034         oRoot,
3035         oNextItem,
3036         oBody,
3037         nBodyScrollTop,
3038         nBodyOffsetHeight,
3039         aItems,
3040         nItems,
3041         nNextItemOffsetTop,
3042         nScrollTarget,
3043         oParentMenu;
3046     /*
3047         This function is called to prevent a bug in Firefox.  In Firefox,
3048         moving a DOM element into a stationary mouse pointer will cause the 
3049         browser to fire mouse events.  This can result in the menu mouse
3050         event handlers being called uncessarily, especially when menus are 
3051         moved into a stationary mouse pointer as a result of a 
3052         key event handler.
3053     */
3054     function stopMouseEventHandlers() {
3056         this._bStopMouseEventHandlers = true;
3057         
3058         Lang.later(10, this, function () {
3060             this._bStopMouseEventHandlers = false;
3061         
3062         });
3064     }
3067     if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
3069         oItemCfg = oItem.cfg;
3070         oParentItem = this.parent;
3072         switch(oEvent.keyCode) {
3073     
3074             case 38:    // Up arrow
3075             case 40:    // Down arrow
3076     
3077                 oNextItem = (oEvent.keyCode == 38) ? 
3078                     oItem.getPreviousEnabledSibling() : 
3079                     oItem.getNextEnabledSibling();
3080         
3081                 if (oNextItem) {
3083                     this.clearActiveItem();
3085                     oNextItem.cfg.setProperty(_SELECTED, true);
3086                     oNextItem.focus();
3089                     if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
3091                         oBody = this.body;
3092                         nBodyScrollTop = oBody.scrollTop;
3093                         nBodyOffsetHeight = oBody.offsetHeight;
3094                         aItems = this.getItems();
3095                         nItems = aItems.length - 1;
3096                         nNextItemOffsetTop = oNextItem.element.offsetTop;
3099                         if (oEvent.keyCode == 40 ) {    // Down
3100                        
3101                             if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3103                                 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3105                             }
3106                             else if (nNextItemOffsetTop <= nBodyScrollTop) {
3107                             
3108                                 oBody.scrollTop = 0;
3109                             
3110                             }
3113                             if (oNextItem == aItems[nItems]) {
3115                                 oBody.scrollTop = oNextItem.element.offsetTop;
3117                             }
3119                         }
3120                         else {  // Up
3122                             if (nNextItemOffsetTop <= nBodyScrollTop) {
3124                                 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3125                             
3126                             }
3127                             else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3128                             
3129                                 oBody.scrollTop = nNextItemOffsetTop;
3130                             
3131                             }
3134                             if (oNextItem == aItems[0]) {
3135                             
3136                                 oBody.scrollTop = 0;
3137                             
3138                             }
3140                         }
3143                         nBodyScrollTop = oBody.scrollTop;
3144                         nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3146                         if (nBodyScrollTop === 0) {
3148                             this._disableScrollHeader();
3149                             this._enableScrollFooter();
3151                         }
3152                         else if (nBodyScrollTop == nScrollTarget) {
3154                              this._enableScrollHeader();
3155                              this._disableScrollFooter();
3157                         }
3158                         else {
3160                             this._enableScrollHeader();
3161                             this._enableScrollFooter();
3163                         }
3165                     }
3167                 }
3169     
3170                 Event.preventDefault(oEvent);
3172                 stopMouseEventHandlers();
3173     
3174             break;
3175             
3176     
3177             case 39:    // Right arrow
3178     
3179                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
3180     
3181                 if (oSubmenu) {
3182     
3183                     if (!oItemCfg.getProperty(_SELECTED)) {
3184         
3185                         oItemCfg.setProperty(_SELECTED, true);
3186         
3187                     }
3188     
3189                     oSubmenu.show();
3190                     oSubmenu.setInitialFocus();
3191                     oSubmenu.setInitialSelection();
3192     
3193                 }
3194                 else {
3195     
3196                     oRoot = this.getRoot();
3197                     
3198                     if (oRoot instanceof YAHOO.widget.MenuBar) {
3199     
3200                         oNextItem = oRoot.activeItem.getNextEnabledSibling();
3201     
3202                         if (oNextItem) {
3203                         
3204                             oRoot.clearActiveItem();
3205     
3206                             oNextItem.cfg.setProperty(_SELECTED, true);
3207     
3208                             oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3209     
3210                             if (oSubmenu) {
3211     
3212                                 oSubmenu.show();
3213                                 oSubmenu.setInitialFocus();
3214                             
3215                             }
3216                             else {
3217     
3218                                 oNextItem.focus();
3219                             
3220                             }
3221                         
3222                         }
3223                     
3224                     }
3225                 
3226                 }
3227     
3228     
3229                 Event.preventDefault(oEvent);
3231                 stopMouseEventHandlers();
3233             break;
3234     
3235     
3236             case 37:    // Left arrow
3237     
3238                 if (oParentItem) {
3239     
3240                     oParentMenu = oParentItem.parent;
3241     
3242                     if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3243     
3244                         oNextItem = 
3245                             oParentMenu.activeItem.getPreviousEnabledSibling();
3246     
3247                         if (oNextItem) {
3248                         
3249                             oParentMenu.clearActiveItem();
3250     
3251                             oNextItem.cfg.setProperty(_SELECTED, true);
3252     
3253                             oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3254     
3255                             if (oSubmenu) {
3256                             
3257                                 oSubmenu.show();
3258                                                                 oSubmenu.setInitialFocus();                                
3259                             
3260                             }
3261                             else {
3262     
3263                                 oNextItem.focus();
3264                             
3265                             }
3266                         
3267                         } 
3268                     
3269                     }
3270                     else {
3271     
3272                         this.hide();
3273     
3274                         oParentItem.focus();
3275                     
3276                     }
3277     
3278                 }
3279     
3280                 Event.preventDefault(oEvent);
3282                 stopMouseEventHandlers();
3284             break;        
3285     
3286         }
3289     }
3292     if (oEvent.keyCode == 27) { // Esc key
3294         if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3295         
3296             this.hide();
3298             if (this.parent) {
3300                 this.parent.focus();
3301             
3302             }
3304         }
3305         else if (this.activeItem) {
3307             oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3309             if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3310             
3311                 oSubmenu.hide();
3312                 this.activeItem.focus();
3313             
3314             }
3315             else {
3317                 this.activeItem.blur();
3318                 this.activeItem.cfg.setProperty(_SELECTED, false);
3319         
3320             }
3321         
3322         }
3325         Event.preventDefault(oEvent);
3326     
3327     }
3328     
3333 * @method _onKeyPress
3334 * @description "keypress" event handler for a Menu instance.
3335 * @protected
3336 * @param {String} p_sType The name of the event that was fired.
3337 * @param {Array} p_aArgs Collection of arguments sent when the event 
3338 * was fired.
3340 _onKeyPress: function (p_sType, p_aArgs) {
3341     
3342     var oEvent = p_aArgs[0];
3345     if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3347         Event.preventDefault(oEvent);
3349     }
3355 * @method _onBlur
3356 * @description "blur" event handler for a Menu instance.
3357 * @protected
3358 * @param {String} p_sType The name of the event that was fired.
3359 * @param {Array} p_aArgs Collection of arguments sent when the event 
3360 * was fired.
3362 _onBlur: function (p_sType, p_aArgs) {
3363         
3364         if (this._hasFocus) {
3365                 this._hasFocus = false;
3366         }
3371 * @method _onYChange
3372 * @description "y" event handler for a Menu instance.
3373 * @protected
3374 * @param {String} p_sType The name of the event that was fired.
3375 * @param {Array} p_aArgs Collection of arguments sent when the event 
3376 * was fired.
3378 _onYChange: function (p_sType, p_aArgs) {
3380     var oParent = this.parent,
3381         nScrollTop,
3382         oIFrame,
3383         nY;
3386     if (oParent) {
3388         nScrollTop = oParent.parent.body.scrollTop;
3391         if (nScrollTop > 0) {
3392     
3393             nY = (this.cfg.getProperty(_Y) - nScrollTop);
3394             
3395             Dom.setY(this.element, nY);
3397             oIFrame = this.iframe;            
3398     
3400             if (oIFrame) {
3401     
3402                 Dom.setY(oIFrame, nY);
3403     
3404             }
3405             
3406             this.cfg.setProperty(_Y, nY, true);
3407         
3408         }
3409     
3410     }
3416 * @method _onScrollTargetMouseOver
3417 * @description "mouseover" event handler for the menu's "header" and "footer" 
3418 * elements.  Used to scroll the body of the menu up and down when the 
3419 * menu's "maxheight" configuration property is set to a value greater than 0.
3420 * @protected
3421 * @param {Event} p_oEvent Object representing the DOM event object passed 
3422 * back by the event utility (YAHOO.util.Event).
3423 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3424 * fired the event.
3426 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3428         var oBodyScrollTimer = this._bodyScrollTimer;
3431         if (oBodyScrollTimer) {
3433                 oBodyScrollTimer.cancel();
3435         }
3438         this._cancelHideDelay();
3441     var oTarget = Event.getTarget(p_oEvent),
3442         oBody = this.body,
3443         nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3444         nScrollTarget,
3445         fnScrollFunction;
3448     function scrollBodyDown() {
3450         var nScrollTop = oBody.scrollTop;
3453         if (nScrollTop < nScrollTarget) {
3455             oBody.scrollTop = (nScrollTop + nScrollIncrement);
3457             this._enableScrollHeader();
3459         }
3460         else {
3462             oBody.scrollTop = nScrollTarget;
3464             this._bodyScrollTimer.cancel();
3466             this._disableScrollFooter();
3468         }
3470     }
3473     function scrollBodyUp() {
3475         var nScrollTop = oBody.scrollTop;
3478         if (nScrollTop > 0) {
3480             oBody.scrollTop = (nScrollTop - nScrollIncrement);
3482             this._enableScrollFooter();
3484         }
3485         else {
3487             oBody.scrollTop = 0;
3489                         this._bodyScrollTimer.cancel();
3491             this._disableScrollHeader();
3493         }
3495     }
3497     
3498     if (Dom.hasClass(oTarget, _HD)) {
3500         fnScrollFunction = scrollBodyUp;
3501     
3502     }
3503     else {
3505         nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3507         fnScrollFunction = scrollBodyDown;
3508     
3509     }
3510     
3512     this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3518 * @method _onScrollTargetMouseOut
3519 * @description "mouseout" event handler for the menu's "header" and "footer" 
3520 * elements.  Used to stop scrolling the body of the menu up and down when the 
3521 * menu's "maxheight" configuration property is set to a value greater than 0.
3522 * @protected
3523 * @param {Event} p_oEvent Object representing the DOM event object passed 
3524 * back by the event utility (YAHOO.util.Event).
3525 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3526 * fired the event.
3528 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3530         var oBodyScrollTimer = this._bodyScrollTimer;
3532         if (oBodyScrollTimer) {
3534                 oBodyScrollTimer.cancel();
3536         }
3537         
3538     this._cancelHideDelay();
3544 // Private methods
3548 * @method _onInit
3549 * @description "init" event handler for the menu.
3550 * @private
3551 * @param {String} p_sType String representing the name of the event that 
3552 * was fired.
3553 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3555 _onInit: function (p_sType, p_aArgs) {
3557     this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3559     var bRootMenu = !this.parent,
3560         bLazyLoad = this.lazyLoad;
3563     /*
3564         Automatically initialize a menu's subtree if:
3566         1) This is the root menu and lazyload is off
3567         
3568         2) This is the root menu, lazyload is on, but the menu is 
3569            already visible
3571         3) This menu is a submenu and lazyload is off
3572     */
3576     if (((bRootMenu && !bLazyLoad) || 
3577         (bRootMenu && (this.cfg.getProperty(_VISIBLE) || 
3578         this.cfg.getProperty(_POSITION) == _STATIC)) || 
3579         (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3581         if (this.srcElement) {
3583             this._initSubTree();
3584         
3585         }
3588         if (this.itemData) {
3590             this.addItems(this.itemData);
3592         }
3593     
3594     }
3595     else if (bLazyLoad) {
3597         this.cfg.fireQueue();
3598     
3599     }
3605 * @method _onBeforeRender
3606 * @description "beforerender" event handler for the menu.  Appends all of the 
3607 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying 
3608 * title elements to the body element of the menu.
3609 * @private
3610 * @param {String} p_sType String representing the name of the event that 
3611 * was fired.
3612 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3614 _onBeforeRender: function (p_sType, p_aArgs) {
3616     var oEl = this.element,
3617         nListElements = this._aListElements.length,
3618         bFirstList = true,
3619         i = 0,
3620         oUL,
3621         oGroupTitle;
3623     if (nListElements > 0) {
3625         do {
3627             oUL = this._aListElements[i];
3629             if (oUL) {
3631                 if (bFirstList) {
3632         
3633                     Dom.addClass(oUL, _FIRST_OF_TYPE);
3634                     bFirstList = false;
3635         
3636                 }
3639                 if (!Dom.isAncestor(oEl, oUL)) {
3641                     this.appendToBody(oUL);
3643                 }
3646                 oGroupTitle = this._aGroupTitleElements[i];
3648                 if (oGroupTitle) {
3650                     if (!Dom.isAncestor(oEl, oGroupTitle)) {
3652                         oUL.parentNode.insertBefore(oGroupTitle, oUL);
3654                     }
3657                     Dom.addClass(oUL, _HAS_TITLE);
3659                 }
3661             }
3663             i++;
3665         }
3666         while (i < nListElements);
3668     }
3674 * @method _onRender
3675 * @description "render" event handler for the menu.
3676 * @private
3677 * @param {String} p_sType String representing the name of the event that 
3678 * was fired.
3679 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3681 _onRender: function (p_sType, p_aArgs) {
3683     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { 
3685         if (!this.cfg.getProperty(_VISIBLE)) {
3687             this.positionOffScreen();
3689         }
3690     
3691     }
3700 * @method _onBeforeShow
3701 * @description "beforeshow" event handler for the menu.
3702 * @private
3703 * @param {String} p_sType String representing the name of the event that 
3704 * was fired.
3705 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3707 _onBeforeShow: function (p_sType, p_aArgs) {
3709     var nOptions,
3710         n,
3711         oSrcElement,
3712         oContainer = this.cfg.getProperty(_CONTAINER);
3715     if (this.lazyLoad && this.getItemGroups().length === 0) {
3717         if (this.srcElement) {
3718         
3719             this._initSubTree();
3721         }
3724         if (this.itemData) {
3726             if (this.parent && this.parent.parent && 
3727                 this.parent.parent.srcElement && 
3728                 this.parent.parent.srcElement.tagName.toUpperCase() == 
3729                 _SELECT) {
3731                 nOptions = this.itemData.length;
3732     
3733                 for(n=0; n<nOptions; n++) {
3735                     if (this.itemData[n].tagName) {
3737                         this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3738     
3739                     }
3740     
3741                 }
3742             
3743             }
3744             else {
3746                 this.addItems(this.itemData);
3747             
3748             }
3749         
3750         }
3753         oSrcElement = this.srcElement;
3755         if (oSrcElement) {
3757             if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3759                 if (Dom.inDocument(oSrcElement)) {
3761                     this.render(oSrcElement.parentNode);
3762                 
3763                 }
3764                 else {
3765                 
3766                     this.render(oContainer);
3767                 
3768                 }
3770             }
3771             else {
3773                 this.render();
3775             }
3777         }
3778         else {
3780             if (this.parent) {
3782                 this.render(this.parent.element);     
3784             }
3785             else {
3787                 this.render(oContainer);
3789             }                
3791         }
3793     }
3797     var oParent = this.parent,
3798                 aAlignment;
3801     if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3803         this.cfg.refireEvent(_XY);
3804    
3805     }
3808         if (oParent) {
3810                 aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3811                 
3812                 this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3813                 this.align();
3814         
3815         }
3820 getConstrainedY: function (y) {
3822         var oMenu = this,
3823         
3824                 aContext = oMenu.cfg.getProperty(_CONTEXT),
3825                 nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3827                 nMaxHeight,
3829                 oOverlapPositions = {
3831                         "trbr": true,
3832                         "tlbl": true,
3833                         "bltl": true,
3834                         "brtr": true
3836                 },
3838                 bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3839         
3840                 oMenuEl = oMenu.element,
3841                 nMenuOffsetHeight = oMenuEl.offsetHeight,
3842         
3843                 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3844                 viewPortHeight = Dom.getViewportHeight(),
3845                 scrollY = Dom.getDocumentScrollTop(),
3847                 bCanConstrain = 
3848                         (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3850                 nAvailableHeight,
3852                 oContextEl,
3853                 nContextElY,
3854                 nContextElHeight,
3856                 bFlipped = false,
3858                 nTopRegionHeight,
3859                 nBottomRegionHeight,
3861                 topConstraint,
3862                 bottomConstraint,
3864                 yNew = y;
3865                 
3867         var flipVertical = function () {
3869                 var nNewY;
3870         
3871                 // The Menu is below the context element, flip it above
3872                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3873                         nNewY = (nContextElY - nMenuOffsetHeight);
3874                 }
3875                 else {  // The Menu is above the context element, flip it below
3876                         nNewY = (nContextElY + nContextElHeight);
3877                 }
3879                 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3880                 
3881                 return nNewY;
3882         
3883         };
3886         /*
3887                  Uses the context element's position to calculate the availble height 
3888                  above and below it to display its corresponding Menu.
3889         */
3891         var getDisplayRegionHeight = function () {
3893                 // The Menu is below the context element
3894                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3895                         return (nBottomRegionHeight - nViewportOffset);                         
3896                 }
3897                 else {  // The Menu is above the context element
3898                         return (nTopRegionHeight - nViewportOffset);                            
3899                 }
3901         };
3904         /*
3905                 Sets the Menu's "y" configuration property to the correct value based on its
3906                 current orientation.
3907         */ 
3909         var alignY = function () {
3911                 var nNewY;
3913                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3914                         nNewY = (nContextElY + nContextElHeight);
3915                 }
3916                 else {  
3917                         nNewY = (nContextElY - oMenuEl.offsetHeight);
3918                 }
3920                 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3921         
3922         };
3925         //      Resets the maxheight of the Menu to the value set by the user
3927         var resetMaxHeight = function () {
3929                 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3931                 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3932         
3933         };
3936         /*
3937                 Trys to place the Menu in the best possible position (either above or 
3938                 below its corresponding context element).
3939         */
3941         var setVerticalPosition = function () {
3943                 var nDisplayRegionHeight = getDisplayRegionHeight(),
3944                         bMenuHasItems = (oMenu.getItems().length > 0),
3945                         nMenuMinScrollHeight,
3946                         fnReturnVal,
3947                         nNewY;
3950                 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3952                         nMenuMinScrollHeight = 
3953                                 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3956                         if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3957                                 nMaxHeight = nDisplayRegionHeight;
3958                         }
3959                         else {
3960                                 nMaxHeight = nInitialMaxHeight;
3961                         }
3964                         oMenu._setScrollHeight(nMaxHeight);
3965                         oMenu.hideEvent.subscribe(resetMaxHeight);
3966                         
3968                         // Re-align the Menu since its height has just changed
3969                         // as a result of the setting of the maxheight property.
3971                         alignY();
3972                         
3974                         if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3976                                 if (bFlipped) {
3977         
3978                                         /*
3979                                                  All possible positions and values for the "maxheight" 
3980                                                  configuration property have been tried, but none were 
3981                                                  successful, so fall back to the original size and position.
3982                                         */
3984                                         flipVertical();
3985                                         
3986                                 }
3987                                 else {
3988         
3989                                         flipVertical();
3991                                         bFlipped = true;
3992         
3993                                         fnReturnVal = setVerticalPosition();
3994         
3995                                 }
3996                                 
3997                         }
3998                 
3999                 }
4000                 else if (nMaxHeight && (nMaxHeight != nInitialMaxHeight)) {
4001                 
4002                         oMenu._setScrollHeight(nInitialMaxHeight);
4003                         oMenu.hideEvent.subscribe(resetMaxHeight);
4005                         // Re-align the Menu since its height has just changed
4006                         // as a result of the setting of the maxheight property.
4008                         alignY();
4009                 
4010                 }
4012                 return fnReturnVal;
4014         };
4017         if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
4019                 if (bCanConstrain) {
4021                         oContextEl = aContext[0];
4022                         nContextElHeight = oContextEl.offsetHeight;
4023                         nContextElY = (Dom.getY(oContextEl) - scrollY);
4025                         nTopRegionHeight = nContextElY;
4026                         nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
4028                         setVerticalPosition();
4029                 
4030                 }
4032                 yNew = oMenu.cfg.getProperty(_Y);
4034         }
4035     else if (!(oMenu instanceof YAHOO.widget.MenuBar) && nMenuOffsetHeight >= viewPortHeight) {
4036         
4037                 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
4039                 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
4041                         oMenu._setScrollHeight(nAvailableHeight);
4042                         oMenu.hideEvent.subscribe(resetMaxHeight);
4044                         alignY();
4045                         
4046                         yNew = oMenu.cfg.getProperty(_Y);
4047                 
4048                 }
4050     }   
4051         else {
4053                 if (bCanConstrain) {
4055                         topConstraint = scrollY + nViewportOffset;
4056                         bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset;
4058                         if (y < topConstraint) {
4059                                 yNew  = topConstraint;
4060                         } else if (y  > bottomConstraint) {
4061                                 yNew  = bottomConstraint;
4062                         }
4063                 } else {
4064                         yNew = nViewportOffset + scrollY;
4065                 }
4067         }
4069         return yNew;
4075 * @method _onHide
4076 * @description "hide" event handler for the menu.
4077 * @private
4078 * @param {String} p_sType String representing the name of the event that 
4079 * was fired.
4080 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4082 _onHide: function (p_sType, p_aArgs) {
4084         if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4085         
4086                 this.positionOffScreen();
4087         
4088         }
4094 * @method _onShow
4095 * @description "show" event handler for the menu.
4096 * @private
4097 * @param {String} p_sType String representing the name of the event that 
4098 * was fired.
4099 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4101 _onShow: function (p_sType, p_aArgs) {
4103     var oParent = this.parent,
4104         oParentMenu,
4105                 oElement,
4106                 nOffsetWidth,
4107                 sWidth;        
4110     function disableAutoSubmenuDisplay(p_oEvent) {
4112         var oTarget;
4114         if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4116             /*  
4117                 Set the "autosubmenudisplay" to "false" if the user
4118                 clicks outside the menu bar.
4119             */
4121             oTarget = Event.getTarget(p_oEvent);
4123             if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4125                 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4127                 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4128                 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4130             }
4131         
4132         }
4134     }
4137         function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4138         
4139                 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4140                 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4141         
4142         }
4145     if (oParent) {
4147         oParentMenu = oParent.parent;
4150         if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) && 
4151             (oParentMenu instanceof YAHOO.widget.MenuBar || 
4152             oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4154             oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4156             Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);                             
4157             Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4159         }
4162                 // The following fixes an issue with the selected state of a MenuItem not rendering 
4163                 // correctly when a submenu is aligned to the left of its parent Menu instance.
4165                 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) && 
4166                         (UA.gecko < 1.9) && 
4167                         !this.cfg.getProperty(_WIDTH)) {
4168                 
4169                         oElement = this.element;
4170                         nOffsetWidth = oElement.offsetWidth;
4171                         
4172                         /*
4173                                 Measuring the difference of the offsetWidth before and after
4174                                 setting the "width" style attribute allows us to compute the 
4175                                 about of padding and borders applied to the element, which in 
4176                                 turn allows us to set the "width" property correctly.
4177                         */
4178                         
4179                         oElement.style.width = nOffsetWidth + _PX;
4180                         
4181                         sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4182                         
4183                         this.cfg.setProperty(_WIDTH, sWidth);
4184                 
4185                         this.hideEvent.subscribe(onSubmenuHide, sWidth);
4186                 
4187                 }
4189     }
4195 * @method _onBeforeHide
4196 * @description "beforehide" event handler for the menu.
4197 * @private
4198 * @param {String} p_sType String representing the name of the event that 
4199 * was fired.
4200 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4202 _onBeforeHide: function (p_sType, p_aArgs) {
4204     var oActiveItem = this.activeItem,
4205         oRoot = this.getRoot(),
4206         oConfig,
4207         oSubmenu;
4210     if (oActiveItem) {
4212         oConfig = oActiveItem.cfg;
4214         oConfig.setProperty(_SELECTED, false);
4216         oSubmenu = oConfig.getProperty(_SUBMENU);
4218         if (oSubmenu) {
4220             oSubmenu.hide();
4222         }
4224     }
4227         /*
4228                 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.  
4229                 For this reason, it is necessary to maintain the focused state in a private property 
4230                 so that the _onMouseOver event handler is able to determined whether or not to set focus
4231                 to MenuItems as the user is moving the mouse.
4232         */ 
4234         if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4236                 oRoot._hasFocus = this.hasFocus();
4237         
4238         }
4241     if (oRoot == this) {
4243         oRoot.blur();
4244     
4245     }
4251 * @method _onParentMenuConfigChange
4252 * @description "configchange" event handler for a submenu.
4253 * @private
4254 * @param {String} p_sType String representing the name of the event that 
4255 * was fired.
4256 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4257 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4258 * subscribed to the event.
4260 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4261     
4262     var sPropertyName = p_aArgs[0][0],
4263         oPropertyValue = p_aArgs[0][1];
4265     switch(sPropertyName) {
4267         case _IFRAME:
4268         case _CONSTRAIN_TO_VIEWPORT:
4269         case _HIDE_DELAY:
4270         case _SHOW_DELAY:
4271         case _SUBMENU_HIDE_DELAY:
4272         case _CLICK_TO_HIDE:
4273         case _EFFECT:
4274         case _CLASSNAME:
4275         case _SCROLL_INCREMENT:
4276         case _MIN_SCROLL_HEIGHT:
4277         case _MONITOR_RESIZE:
4278         case _SHADOW:
4279         case _PREVENT_CONTEXT_OVERLAP:
4281             p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4282                 
4283         break;
4284         
4285         case _SUBMENU_ALIGNMENT:
4287                         if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4288                 
4289                                 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4290                 
4291                         }
4292         
4293         break;
4294         
4295     }
4296     
4301 * @method _onParentMenuRender
4302 * @description "render" event handler for a submenu.  Renders a  
4303 * submenu in response to the firing of its parent's "render" event.
4304 * @private
4305 * @param {String} p_sType String representing the name of the event that 
4306 * was fired.
4307 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4308 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4309 * subscribed to the event.
4311 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4313     var oParentMenu = p_oSubmenu.parent.parent,
4314         oParentCfg = oParentMenu.cfg,
4316         oConfig = {
4318             constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4320             xy: [0,0],
4322             clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4323                 
4324             effect: oParentCfg.getProperty(_EFFECT),
4326             showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4327             
4328             hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4330             submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4332             classname: oParentCfg.getProperty(_CLASSNAME),
4333             
4334             scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4335             
4336             minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4337             
4338             iframe: oParentCfg.getProperty(_IFRAME),
4339             
4340             shadow: oParentCfg.getProperty(_SHADOW),
4342                         preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4343             
4344             monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE)
4346         },
4347         
4348         oLI;
4351         
4352         if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4354                 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4356         }
4359     p_oSubmenu.cfg.applyConfig(oConfig);
4362     if (!this.lazyLoad) {
4364         oLI = this.parent.element;
4366         if (this.element.parentNode == oLI) {
4367     
4368             this.render();
4369     
4370         }
4371         else {
4373             this.render(oLI);
4374     
4375         }
4377     }
4378     
4383 * @method _onMenuItemDestroy
4384 * @description "destroy" event handler for the menu's items.
4385 * @private
4386 * @param {String} p_sType String representing the name of the event 
4387 * that was fired.
4388 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4389 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4390 * that fired the event.
4392 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4394     this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4400 * @method _onMenuItemConfigChange
4401 * @description "configchange" event handler for the menu's items.
4402 * @private
4403 * @param {String} p_sType String representing the name of the event that 
4404 * was fired.
4405 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4406 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4407 * that fired the event.
4409 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4411     var sPropertyName = p_aArgs[0][0],
4412         oPropertyValue = p_aArgs[0][1],
4413         oSubmenu;
4416     switch(sPropertyName) {
4418         case _SELECTED:
4420             if (oPropertyValue === true) {
4422                 this.activeItem = p_oItem;
4423             
4424             }
4426         break;
4428         case _SUBMENU:
4430             oSubmenu = p_aArgs[0][1];
4432             if (oSubmenu) {
4434                 this._configureSubmenu(p_oItem);
4436             }
4438         break;
4440     }
4446 // Public event handlers for configuration properties
4450 * @method configVisible
4451 * @description Event handler for when the "visible" configuration property 
4452 * the menu changes.
4453 * @param {String} p_sType String representing the name of the event that 
4454 * was fired.
4455 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4456 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4457 * fired the event.
4459 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4461     var bVisible,
4462         sDisplay;
4464     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4466         Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4468     }
4469     else {
4471         bVisible = p_aArgs[0];
4472         sDisplay = Dom.getStyle(this.element, _DISPLAY);
4474         Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4476         if (bVisible) {
4478             if (sDisplay != _BLOCK) {
4479                 this.beforeShowEvent.fire();
4480                 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4481                 this.showEvent.fire();
4482             }
4483         
4484         }
4485         else {
4487                         if (sDisplay == _BLOCK) {
4488                                 this.beforeHideEvent.fire();
4489                                 Dom.setStyle(this.element, _DISPLAY, _NONE);
4490                                 this.hideEvent.fire();
4491                         }
4492         
4493         }
4495     }
4501 * @method configPosition
4502 * @description Event handler for when the "position" configuration property 
4503 * of the menu changes.
4504 * @param {String} p_sType String representing the name of the event that 
4505 * was fired.
4506 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4507 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4508 * fired the event.
4510 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4512     var oElement = this.element,
4513         sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4514         oCfg = this.cfg,
4515         nZIndex;
4518     Dom.setStyle(oElement, _POSITION, sCSSPosition);
4521     if (sCSSPosition == _STATIC) {
4523         // Statically positioned menus are visible by default
4524         
4525         Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4527         oCfg.setProperty(_VISIBLE, true);
4529     }
4530     else {
4532         /*
4533             Even though the "visible" property is queued to 
4534             "false" by default, we need to set the "visibility" property to 
4535             "hidden" since Overlay's "configVisible" implementation checks the 
4536             element's "visibility" style property before deciding whether 
4537             or not to show an Overlay instance.
4538         */
4540         Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4541     
4542     }
4544          
4545      if (sCSSPosition == _ABSOLUTE) {    
4546          
4547          nZIndex = oCfg.getProperty(_ZINDEX);
4548          
4549          if (!nZIndex || nZIndex === 0) {        
4550          
4551              oCfg.setProperty(_ZINDEX, 1);       
4552          
4553          }       
4554          
4555      }
4561 * @method configIframe
4562 * @description Event handler for when the "iframe" configuration property of 
4563 * the menu changes.
4564 * @param {String} p_sType String representing the name of the event that 
4565 * was fired.
4566 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4567 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4568 * fired the event.
4570 configIframe: function (p_sType, p_aArgs, p_oMenu) {    
4572     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4574         Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4576     }
4582 * @method configHideDelay
4583 * @description Event handler for when the "hidedelay" configuration property 
4584 * of the menu changes.
4585 * @param {String} p_sType String representing the name of the event that 
4586 * was fired.
4587 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4588 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4589 * fired the event.
4591 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4593     var nHideDelay = p_aArgs[0],
4594         oMouseOutEvent = this.mouseOutEvent,
4595         oMouseOverEvent = this.mouseOverEvent,
4596         oKeyDownEvent = this.keyDownEvent;
4598     if (nHideDelay > 0) {
4600         /*
4601             Only assign event handlers once. This way the user change 
4602             the value for the hidedelay as many times as they want.
4603         */
4605         if (!this._bHideDelayEventHandlersAssigned) {
4607             oMouseOutEvent.subscribe(this._execHideDelay);
4608             oMouseOverEvent.subscribe(this._cancelHideDelay);
4609             oKeyDownEvent.subscribe(this._cancelHideDelay);
4611             this._bHideDelayEventHandlersAssigned = true;
4612         
4613         }
4615     }
4616     else {
4618         oMouseOutEvent.unsubscribe(this._execHideDelay);
4619         oMouseOverEvent.unsubscribe(this._cancelHideDelay);
4620         oKeyDownEvent.unsubscribe(this._cancelHideDelay);
4622         this._bHideDelayEventHandlersAssigned = false;
4624     }
4630 * @method configContainer
4631 * @description Event handler for when the "container" configuration property 
4632 * of the menu changes.
4633 * @param {String} p_sType String representing the name of the event that 
4634 * was fired.
4635 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4636 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4637 * fired the event.
4639 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4641         var oElement = p_aArgs[0];
4643         if (Lang.isString(oElement)) {
4645         this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4647         }
4653 * @method _clearSetWidthFlag
4654 * @description Change event listener for the "width" configuration property.  This listener is 
4655 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and 
4656 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property 
4657 * is changed after it was set by the "_setScrollHeight" method.  If the "_widthSetForScroll" 
4658 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down 
4659 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4660 * @private
4662 _clearSetWidthFlag: function () {
4664         this._widthSetForScroll = false;
4665         
4666         this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4672 * @method _setScrollHeight
4673 * @description 
4674 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4675 * @private
4677 _setScrollHeight: function (p_nScrollHeight) {
4679     var nScrollHeight = p_nScrollHeight,
4680                 bRefireIFrameAndShadow = false,
4681                 bSetWidth = false,
4682         oElement,
4683         oBody,
4684         oHeader,
4685         oFooter,
4686                 oParent,
4687         fnMouseOver,
4688         fnMouseOut,
4689         nMinScrollHeight,
4690         nHeight,
4691         nOffsetWidth,
4692         sWidth;
4695         if (this.getItems().length > 0) {
4696         
4697         oElement = this.element;
4698         oBody = this.body;
4699         oHeader = this.header;
4700         oFooter = this.footer;
4701         fnMouseOver = this._onScrollTargetMouseOver;
4702         fnMouseOut = this._onScrollTargetMouseOut;
4703         nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4704         oParent = this.parent;
4707                 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4708                 
4709                         nScrollHeight = nMinScrollHeight;
4710                 
4711                 }
4714                 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4715                 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4716                 oBody.scrollTop = 0;
4719                 /*
4720                         There is a bug in gecko-based browsers where an element whose 
4721                         "position" property is set to "absolute" and "overflow" property is set 
4722                         to "hidden" will not render at the correct width when its 
4723                         offsetParent's "position" property is also set to "absolute."  It is 
4724                         possible to work around this bug by specifying a value for the width 
4725                         property in addition to overflow.
4726         
4727                         In IE it is also necessary to give the Menu a width before the scrollbars are 
4728                         rendered to prevent the Menu from rendering with a width that is 100% of
4729                         the browser viewport.
4730                 */
4731         
4732                 bSetWidth = ((UA.gecko && oParent && oParent.parent && 
4733                         oParent.parent.cfg.getProperty(_POSITION) == _DYNAMIC) || UA.ie);
4735                 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4736         
4737                         nOffsetWidth = oElement.offsetWidth;
4738         
4739                         /*
4740                                 Measuring the difference of the offsetWidth before and after
4741                                 setting the "width" style attribute allows us to compute the 
4742                                 about of padding and borders applied to the element, which in 
4743                                 turn allows us to set the "width" property correctly.
4744                         */
4745                         
4746                         oElement.style.width = nOffsetWidth + _PX;
4747         
4748                         sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4751                         this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4753                         YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.", 
4754                                 "info", this.toString());
4756                         this.cfg.setProperty(_WIDTH, sWidth);
4759                         /*
4760                                 Set a flag (_widthSetForScroll) to maintain some history regarding how the 
4761                                 "width" configuration property was set.  If the "width" configuration property 
4762                                 is set by something other than the "_setScrollHeight" method, it will be 
4763                                 necessary to maintain that new value and not clear the width if scrolling 
4764                                 is turned off.
4765                         */
4767                         this._widthSetForScroll = true;
4769                         this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4770         
4771                 }
4772         
4773         
4774                 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4775         
4776                         YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
4777         
4778                         this.setHeader(_NON_BREAKING_SPACE);
4779                         this.setFooter(_NON_BREAKING_SPACE);
4780         
4781                         oHeader = this.header;
4782                         oFooter = this.footer;
4783         
4784                         Dom.addClass(oHeader, _TOP_SCROLLBAR);
4785                         Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4786                         
4787                         oElement.insertBefore(oHeader, oBody);
4788                         oElement.appendChild(oFooter);
4789                 
4790                 }
4791         
4792         
4793                 nHeight = nScrollHeight;
4794         
4795         
4796                 if (oHeader && oFooter) {
4797                         nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4798                 }
4799         
4800         
4801                 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4803                         YAHOO.log("Setting up styles and event handlers for scrolling.", 
4804                                 "info", this.toString());
4805         
4806                         Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4807                         Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4809                         if (!this._hasScrollEventHandlers) {
4810         
4811                                 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4812                                 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4813                                 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4814                                 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4815         
4816                                 this._hasScrollEventHandlers = true;
4817         
4818                         }
4819         
4820                         this._disableScrollHeader();
4821                         this._enableScrollFooter();
4822                         
4823                         bRefireIFrameAndShadow = true;                  
4824         
4825                 }
4826                 else if (oHeader && oFooter) {
4828                         YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
4829         
4831                         /*
4832                                 Only clear the the "width" configuration property if it was set the 
4833                                 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4834                         */      
4835         
4836                         if (this._widthSetForScroll) {
4837         
4838                                 YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
4840                                 this._widthSetForScroll = false;
4842                                 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4843         
4844                                 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4845                         
4846                         }
4847         
4848         
4849                         this._enableScrollHeader();
4850                         this._enableScrollFooter();
4851         
4852                         if (this._hasScrollEventHandlers) {
4853         
4854                                 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4855                                 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4856                                 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4857                                 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4859                                 this._hasScrollEventHandlers = false;
4860         
4861                         }
4863                         oElement.removeChild(oHeader);
4864                         oElement.removeChild(oFooter);
4865         
4866                         this.header = null;
4867                         this.footer = null;
4868                         
4869                         bRefireIFrameAndShadow = true;
4870                 
4871                 }
4874                 if (bRefireIFrameAndShadow) {
4875         
4876                         this.cfg.refireEvent(_IFRAME);
4877                         this.cfg.refireEvent(_SHADOW);
4878                 
4879                 }
4880         
4881         }
4887 * @method _setMaxHeight
4888 * @description "renderEvent" handler used to defer the setting of the 
4889 * "maxheight" configuration property until the menu is rendered in lazy 
4890 * load scenarios.
4891 * @param {String} p_sType The name of the event that was fired.
4892 * @param {Array} p_aArgs Collection of arguments sent when the event 
4893 * was fired.
4894 * @param {Number} p_nMaxHeight Number representing the value to set for the 
4895 * "maxheight" configuration property.
4896 * @private
4898 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4900     this._setScrollHeight(p_nMaxHeight);
4901     this.renderEvent.unsubscribe(this._setMaxHeight);
4907 * @method configMaxHeight
4908 * @description Event handler for when the "maxheight" configuration property of 
4909 * a Menu changes.
4910 * @param {String} p_sType The name of the event that was fired.
4911 * @param {Array} p_aArgs Collection of arguments sent when the event 
4912 * was fired.
4913 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4914 * the event.
4916 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4918         var nMaxHeight = p_aArgs[0];
4920         if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4921         
4922                 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4924         }
4925         else {
4927                 this._setScrollHeight(nMaxHeight);
4928         
4929         }
4935 * @method configClassName
4936 * @description Event handler for when the "classname" configuration property of 
4937 * a menu changes.
4938 * @param {String} p_sType The name of the event that was fired.
4939 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4940 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4942 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4944     var sClassName = p_aArgs[0];
4946     if (this._sClassName) {
4948         Dom.removeClass(this.element, this._sClassName);
4950     }
4952     Dom.addClass(this.element, sClassName);
4953     this._sClassName = sClassName;
4959 * @method _onItemAdded
4960 * @description "itemadded" event handler for a Menu instance.
4961 * @private
4962 * @param {String} p_sType The name of the event that was fired.
4963 * @param {Array} p_aArgs Collection of arguments sent when the event 
4964 * was fired.
4966 _onItemAdded: function (p_sType, p_aArgs) {
4968     var oItem = p_aArgs[0];
4969     
4970     if (oItem) {
4972         oItem.cfg.setProperty(_DISABLED, true);
4973     
4974     }
4980 * @method configDisabled
4981 * @description Event handler for when the "disabled" configuration property of 
4982 * a menu changes.
4983 * @param {String} p_sType The name of the event that was fired.
4984 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4985 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4987 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4989     var bDisabled = p_aArgs[0],
4990         aItems = this.getItems(),
4991         nItems,
4992         i;
4994     if (Lang.isArray(aItems)) {
4996         nItems = aItems.length;
4997     
4998         if (nItems > 0) {
4999         
5000             i = nItems - 1;
5001     
5002             do {
5003     
5004                 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
5005             
5006             }
5007             while (i--);
5008         
5009         }
5012         if (bDisabled) {
5014             this.clearActiveItem(true);
5016             Dom.addClass(this.element, _DISABLED);
5018             this.itemAddedEvent.subscribe(this._onItemAdded);
5020         }
5021         else {
5023             Dom.removeClass(this.element, _DISABLED);
5025             this.itemAddedEvent.unsubscribe(this._onItemAdded);
5027         }
5028         
5029     }
5035 * @method configShadow
5036 * @description Event handler for when the "shadow" configuration property of 
5037 * a menu changes.
5038 * @param {String} p_sType The name of the event that was fired.
5039 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5040 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5042 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5044     var sizeShadow = function () {
5046         var oElement = this.element,
5047             oShadow = this._shadow;
5048     
5049         if (oShadow && oElement) {
5051                         // Clear the previous width
5053                         if (oShadow.style.width && oShadow.style.height) {
5054                         
5055                                 oShadow.style.width = _EMPTY_STRING;
5056                                 oShadow.style.height = _EMPTY_STRING;
5057                         
5058                         }
5060             oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
5061             oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
5062             
5063         }
5064     
5065     };
5068     var replaceShadow = function () {
5070         this.element.appendChild(this._shadow);
5072     };
5075     var addShadowVisibleClass = function () {
5076     
5077         Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5078     
5079     };
5080     
5082     var removeShadowVisibleClass = function () {
5084         Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5085     
5086     };
5089     var createShadow = function () {
5091         var oShadow = this._shadow,
5092             oElement;
5094         if (!oShadow) {
5096             oElement = this.element;
5099             if (!m_oShadowTemplate) {
5101                 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5102                 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5103             
5104             }
5106             oShadow = m_oShadowTemplate.cloneNode(false);
5108             oElement.appendChild(oShadow);
5109             
5110             this._shadow = oShadow;
5112             this.beforeShowEvent.subscribe(addShadowVisibleClass);
5113             this.beforeHideEvent.subscribe(removeShadowVisibleClass);
5116             if (UA.ie) {
5117         
5118                 /*
5119                      Need to call sizeShadow & syncIframe via setTimeout for 
5120                      IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode 
5121                      or the shadow and iframe shim will not be sized and 
5122                      positioned properly.
5123                 */
5124         
5125                                 Lang.later(0, this, function () {
5127                     sizeShadow.call(this); 
5128                     this.syncIframe();
5129                                 
5130                                 });
5133                 this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
5134                 this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
5135                 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
5136                 this.changeContentEvent.subscribe(sizeShadow);
5138                 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5139                 
5140                 this.destroyEvent.subscribe(function () {
5141                 
5142                     Module.textResizeEvent.unsubscribe(sizeShadow, this);
5143                 
5144                 });
5145         
5146             }
5148             this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
5150         }
5152     };
5155     var onBeforeShow = function () {
5156     
5157         if (this._shadow) {
5159                         // If called because the "shadow" event was refired - just append again and resize
5160                         
5161                         replaceShadow.call(this);
5162                         
5163                         if (UA.ie) {
5164                                 sizeShadow.call(this);
5165                         }
5166         
5167         }
5168         else {
5169     
5170                 createShadow.call(this);
5171         
5172         }
5174         this.beforeShowEvent.unsubscribe(onBeforeShow);
5175     
5176     };
5179         var bShadow = p_aArgs[0];
5182     if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5184         if (this.cfg.getProperty(_VISIBLE)) {
5186                         if (this._shadow) {
5188                                 // If the "shadow" event was refired - just append again and resize
5189                                 
5190                                 replaceShadow.call(this);
5191                                 
5192                                 if (UA.ie) {
5193                                         sizeShadow.call(this);
5194                                 }
5195                                 
5196                         } 
5197                         else {
5198                 createShadow.call(this);
5199             }
5200         
5201         }
5202         else {
5204             this.beforeShowEvent.subscribe(onBeforeShow);
5205         
5206         }
5207     
5208     }
5209     
5214 // Public methods
5218 * @method initEvents
5219 * @description Initializes the custom events for the menu.
5221 initEvents: function () {
5223         Menu.superclass.initEvents.call(this);
5225     // Create custom events
5227         var i = EVENT_TYPES.length - 1,
5228                 aEventData,
5229                 oCustomEvent;
5232         do {
5234                 aEventData = EVENT_TYPES[i];
5236                 oCustomEvent = this.createEvent(aEventData[1]);
5237                 oCustomEvent.signature = CustomEvent.LIST;
5238                 
5239                 this[aEventData[0]] = oCustomEvent;
5241         }
5242         while (i--);
5248 * @method positionOffScreen
5249 * @description Positions the menu outside of the boundaries of the browser's 
5250 * viewport.  Called automatically when a menu is hidden to ensure that 
5251 * it doesn't force the browser to render uncessary scrollbars.
5253 positionOffScreen: function () {
5255     var oIFrame = this.iframe,
5256         oElement = this.element,
5257         sPos = this.OFF_SCREEN_POSITION;
5258     
5259     oElement.style.top = _EMPTY_STRING;
5260     oElement.style.left = _EMPTY_STRING;
5261     
5262     if (oIFrame) {
5264                 oIFrame.style.top = sPos;
5265                 oIFrame.style.left = sPos;
5266     
5267     }
5273 * @method getRoot
5274 * @description Finds the menu's root menu.
5276 getRoot: function () {
5278     var oItem = this.parent,
5279         oParentMenu,
5280         returnVal;
5282     if (oItem) {
5284         oParentMenu = oItem.parent;
5286         returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5288     }
5289     else {
5290     
5291         returnVal = this;
5292     
5293     }
5294     
5295     return returnVal;
5301 * @method toString
5302 * @description Returns a string representing the menu.
5303 * @return {String}
5305 toString: function () {
5307     var sReturnVal = _MENU,
5308         sId = this.id;
5310     if (sId) {
5312         sReturnVal += (_SPACE + sId);
5313     
5314     }
5316     return sReturnVal;
5322 * @method setItemGroupTitle
5323 * @description Sets the title of a group of menu items.
5324 * @param {String} p_sGroupTitle String specifying the title of the group.
5325 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5326 * the title belongs.
5328 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5330     var nGroupIndex,
5331         oTitle,
5332         i,
5333         nFirstIndex;
5334         
5335     if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5337         nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5338         oTitle = this._aGroupTitleElements[nGroupIndex];
5341         if (oTitle) {
5343             oTitle.innerHTML = p_sGroupTitle;
5344             
5345         }
5346         else {
5348             oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5349                     
5350             oTitle.innerHTML = p_sGroupTitle;
5352             this._aGroupTitleElements[nGroupIndex] = oTitle;
5354         }
5357         i = this._aGroupTitleElements.length - 1;
5359         do {
5361             if (this._aGroupTitleElements[i]) {
5363                 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5365                 nFirstIndex = i;
5367             }
5369         }
5370         while (i--);
5373         if (nFirstIndex !== null) {
5375             Dom.addClass(this._aGroupTitleElements[nFirstIndex], 
5376                 _FIRST_OF_TYPE);
5378         }
5380         this.changeContentEvent.fire();
5382     }
5389 * @method addItem
5390 * @description Appends an item to the menu.
5391 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5392 * instance to be added to the menu.
5393 * @param {String} p_oItem String specifying the text of the item to be added 
5394 * to the menu.
5395 * @param {Object} p_oItem Object literal containing a set of menu item 
5396 * configuration properties.
5397 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5398 * which the item belongs.
5399 * @return {YAHOO.widget.MenuItem}
5401 addItem: function (p_oItem, p_nGroupIndex) {
5403         return this._addItemToGroup(p_nGroupIndex, p_oItem);
5409 * @method addItems
5410 * @description Adds an array of items to the menu.
5411 * @param {Array} p_aItems Array of items to be added to the menu.  The array 
5412 * can contain strings specifying the text for each item to be created, object
5413 * literals specifying each of the menu item configuration properties, 
5414 * or MenuItem instances.
5415 * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5416 * which the items belongs.
5417 * @return {Array}
5419 addItems: function (p_aItems, p_nGroupIndex) {
5421     var nItems,
5422         aItems,
5423         oItem,
5424         i,
5425         returnVal;
5428     if (Lang.isArray(p_aItems)) {
5430         nItems = p_aItems.length;
5431         aItems = [];
5433         for(i=0; i<nItems; i++) {
5435             oItem = p_aItems[i];
5437             if (oItem) {
5439                 if (Lang.isArray(oItem)) {
5440     
5441                     aItems[aItems.length] = this.addItems(oItem, i);
5442     
5443                 }
5444                 else {
5445     
5446                     aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5447                 
5448                 }
5450             }
5451     
5452         }
5455         if (aItems.length) {
5456         
5457             returnVal = aItems;
5458         
5459         }
5461     }
5463         return returnVal;
5469 * @method insertItem
5470 * @description Inserts an item into the menu at the specified index.
5471 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5472 * instance to be added to the menu.
5473 * @param {String} p_oItem String specifying the text of the item to be added 
5474 * to the menu.
5475 * @param {Object} p_oItem Object literal containing a set of menu item 
5476 * configuration properties.
5477 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5478 * the item should be added.
5479 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5480 * the item belongs.
5481 * @return {YAHOO.widget.MenuItem}
5483 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5484     
5485         return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5491 * @method removeItem
5492 * @description Removes the specified item from the menu.
5493 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem 
5494 * instance to be removed from the menu.
5495 * @param {Number} p_oObject Number specifying the index of the item 
5496 * to be removed.
5497 * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5498 * which the item belongs.
5499 * @return {YAHOO.widget.MenuItem}
5501 removeItem: function (p_oObject, p_nGroupIndex) {
5503     var oItem,
5504         returnVal;
5505     
5506     if (!Lang.isUndefined(p_oObject)) {
5508         if (p_oObject instanceof YAHOO.widget.MenuItem) {
5510             oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);           
5512         }
5513         else if (Lang.isNumber(p_oObject)) {
5515             oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5517         }
5519         if (oItem) {
5521             oItem.destroy();
5523             YAHOO.log("Item removed." + 
5524                 " Text: " + oItem.cfg.getProperty("text") + ", " + 
5525                 " Index: " + oItem.index + ", " + 
5526                 " Group Index: " + oItem.groupIndex, "info", this.toString());
5528             returnVal = oItem;
5530         }
5532     }
5534         return returnVal;
5540 * @method getItems
5541 * @description Returns an array of all of the items in the menu.
5542 * @return {Array}
5544 getItems: function () {
5546     var aGroups = this._aItemGroups,
5547         nGroups,
5548         returnVal,
5549         aItems = [];
5552     if (Lang.isArray(aGroups)) {
5554         nGroups = aGroups.length;
5556         returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5558     }
5560         return returnVal;
5566 * @method getItemGroups
5567 * @description Multi-dimensional Array representing the menu items as they 
5568 * are grouped in the menu.
5569 * @return {Array}
5570 */        
5571 getItemGroups: function () {
5573     return this._aItemGroups;
5579 * @method getItem
5580 * @description Returns the item at the specified index.
5581 * @param {Number} p_nItemIndex Number indicating the ordinal position of the 
5582 * item to be retrieved.
5583 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5584 * the item belongs.
5585 * @return {YAHOO.widget.MenuItem}
5587 getItem: function (p_nItemIndex, p_nGroupIndex) {
5588     
5589     var aGroup,
5590         returnVal;
5591     
5592     if (Lang.isNumber(p_nItemIndex)) {
5594         aGroup = this._getItemGroup(p_nGroupIndex);
5596         if (aGroup) {
5598             returnVal = aGroup[p_nItemIndex];
5599         
5600         }
5602     }
5603     
5604     return returnVal;
5605     
5610 * @method getSubmenus
5611 * @description Returns an array of all of the submenus that are immediate 
5612 * children of the menu.
5613 * @return {Array}
5615 getSubmenus: function () {
5617     var aItems = this.getItems(),
5618         nItems = aItems.length,
5619         aSubmenus,
5620         oSubmenu,
5621         oItem,
5622         i;
5625     if (nItems > 0) {
5626         
5627         aSubmenus = [];
5629         for(i=0; i<nItems; i++) {
5631             oItem = aItems[i];
5632             
5633             if (oItem) {
5635                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5636                 
5637                 if (oSubmenu) {
5639                     aSubmenus[aSubmenus.length] = oSubmenu;
5641                 }
5642             
5643             }
5644         
5645         }
5646     
5647     }
5649     return aSubmenus;
5655 * @method clearContent
5656 * @description Removes all of the content from the menu, including the menu 
5657 * items, group titles, header and footer.
5659 clearContent: function () {
5661     var aItems = this.getItems(),
5662         nItems = aItems.length,
5663         oElement = this.element,
5664         oBody = this.body,
5665         oHeader = this.header,
5666         oFooter = this.footer,
5667         oItem,
5668         oSubmenu,
5669         i;
5672     if (nItems > 0) {
5674         i = nItems - 1;
5676         do {
5678             oItem = aItems[i];
5680             if (oItem) {
5682                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5684                 if (oSubmenu) {
5686                     this.cfg.configChangedEvent.unsubscribe(
5687                         this._onParentMenuConfigChange, oSubmenu);
5689                     this.renderEvent.unsubscribe(this._onParentMenuRender, 
5690                         oSubmenu);
5692                 }
5693                 
5694                 this.removeItem(oItem, oItem.groupIndex);
5696             }
5697         
5698         }
5699         while (i--);
5701     }
5704     if (oHeader) {
5706         Event.purgeElement(oHeader);
5707         oElement.removeChild(oHeader);
5709     }
5710     
5712     if (oFooter) {
5714         Event.purgeElement(oFooter);
5715         oElement.removeChild(oFooter);
5716     }
5719     if (oBody) {
5721         Event.purgeElement(oBody);
5723         oBody.innerHTML = _EMPTY_STRING;
5725     }
5727     this.activeItem = null;
5729     this._aItemGroups = [];
5730     this._aListElements = [];
5731     this._aGroupTitleElements = [];
5733     this.cfg.setProperty(_WIDTH, null);
5739 * @method destroy
5740 * @description Removes the menu's <code>&#60;div&#62;</code> element 
5741 * (and accompanying child nodes) from the document.
5743 destroy: function () {
5745     // Remove all items
5747     this.clearContent();
5749     this._aItemGroups = null;
5750     this._aListElements = null;
5751     this._aGroupTitleElements = null;
5754     // Continue with the superclass implementation of this method
5756     Menu.superclass.destroy.call(this);
5757     
5758     YAHOO.log("Destroyed.", "info", this.toString());
5764 * @method setInitialFocus
5765 * @description Sets focus to the menu's first enabled item.
5767 setInitialFocus: function () {
5769     var oItem = this._getFirstEnabledItem();
5770     
5771     if (oItem) {
5773         oItem.focus();
5775     }
5776     
5781 * @method setInitialSelection
5782 * @description Sets the "selected" configuration property of the menu's first 
5783 * enabled item to "true."
5785 setInitialSelection: function () {
5787     var oItem = this._getFirstEnabledItem();
5788     
5789     if (oItem) {
5790     
5791         oItem.cfg.setProperty(_SELECTED, true);
5792     }        
5798 * @method clearActiveItem
5799 * @description Sets the "selected" configuration property of the menu's active
5800 * item to "false" and hides the item's submenu.
5801 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item 
5802 * should be blurred.  
5804 clearActiveItem: function (p_bBlur) {
5806     if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5807     
5808         this._cancelShowDelay();
5809     
5810     }
5813     var oActiveItem = this.activeItem,
5814         oConfig,
5815         oSubmenu;
5817     if (oActiveItem) {
5819         oConfig = oActiveItem.cfg;
5821         if (p_bBlur) {
5823             oActiveItem.blur();
5824             
5825             this.getRoot()._hasFocus = true;
5826         
5827         }
5829         oConfig.setProperty(_SELECTED, false);
5831         oSubmenu = oConfig.getProperty(_SUBMENU);
5834         if (oSubmenu) {
5836             oSubmenu.hide();
5838         }
5840         this.activeItem = null;  
5842     }
5848 * @method focus
5849 * @description Causes the menu to receive focus and fires the "focus" event.
5851 focus: function () {
5853     if (!this.hasFocus()) {
5855         this.setInitialFocus();
5856     
5857     }
5863 * @method blur
5864 * @description Causes the menu to lose focus and fires the "blur" event.
5865 */    
5866 blur: function () {
5868     var oItem;
5870     if (this.hasFocus()) {
5871     
5872         oItem = MenuManager.getFocusedMenuItem();
5873         
5874         if (oItem) {
5876             oItem.blur();
5878         }
5880     }
5886 * @method hasFocus
5887 * @description Returns a boolean indicating whether or not the menu has focus.
5888 * @return {Boolean}
5890 hasFocus: function () {
5892     return (MenuManager.getFocusedMenu() == this.getRoot());
5898 * Adds the specified CustomEvent subscriber to the menu and each of 
5899 * its submenus.
5900 * @method subscribe
5901 * @param p_type     {string}   the type, or name of the event
5902 * @param p_fn       {function} the function to exectute when the event fires
5903 * @param p_obj      {Object}   An object to be passed along when the event 
5904 *                              fires
5905 * @param p_override {boolean}  If true, the obj passed in becomes the 
5906 *                              execution scope of the listener
5908 subscribe: function () {
5910     function onItemAdded(p_sType, p_aArgs, p_oObject) {
5912         var oItem = p_aArgs[0],
5913             oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5915         if (oSubmenu) {
5917             oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5919         }
5920     
5921     }
5924     function onSubmenuAdded(p_sType, p_aArgs, p_oObject) { 
5925     
5926         var oSubmenu = this.cfg.getProperty(_SUBMENU);
5927         
5928         if (oSubmenu) {
5930             oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5931         
5932         }
5933     
5934     }
5937     Menu.superclass.subscribe.apply(this, arguments);
5938     Menu.superclass.subscribe.call(this, _ITEM_ADDED, onItemAdded, arguments);
5941     var aItems = this.getItems(),
5942         nItems,
5943         oItem,
5944         oSubmenu,
5945         i;
5946         
5948     if (aItems) {
5950         nItems = aItems.length;
5951         
5952         if (nItems > 0) {
5953         
5954             i = nItems - 1;
5955             
5956             do {
5958                 oItem = aItems[i];
5959                 
5960                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5961                 
5962                 if (oSubmenu) {
5963                 
5964                     oSubmenu.subscribe.apply(oSubmenu, arguments);
5965                 
5966                 }
5967                 else {
5968                 
5969                     oItem.cfg.subscribeToConfigEvent(_SUBMENU, onSubmenuAdded, arguments);
5970                 
5971                 }
5973             }
5974             while (i--);
5975         
5976         }
5978     }
5984 * @description Initializes the class's configurable properties which can be
5985 * changed using the menu's Config object ("cfg").
5986 * @method initDefaultConfig
5988 initDefaultConfig: function () {
5990     Menu.superclass.initDefaultConfig.call(this);
5992     var oConfig = this.cfg;
5995     // Module documentation overrides
5997     /**
5998     * @config effect
5999     * @description Object or array of objects representing the ContainerEffect 
6000     * classes that are active for animating the container.  When set this 
6001     * property is automatically applied to all submenus.
6002     * @type Object
6003     * @default null
6004     */
6006     // Overlay documentation overrides
6009     /**
6010     * @config x
6011     * @description Number representing the absolute x-coordinate position of 
6012     * the Menu.  This property is only applied when the "position" 
6013     * configuration property is set to dynamic.
6014     * @type Number
6015     * @default null
6016     */
6017     
6019     /**
6020     * @config y
6021     * @description Number representing the absolute y-coordinate position of 
6022     * the Menu.  This property is only applied when the "position" 
6023     * configuration property is set to dynamic.
6024     * @type Number
6025     * @default null
6026     */
6029     /**
6030     * @description Array of the absolute x and y positions of the Menu.  This 
6031     * property is only applied when the "position" configuration property is 
6032     * set to dynamic.
6033     * @config xy
6034     * @type Number[]
6035     * @default null
6036     */
6037     
6039     /**
6040     * @config context
6041     * @description Array of context arguments for context-sensitive positioning.  
6042     * The format is: [id or element, element corner, context corner]. 
6043     * For example, setting this property to ["img1", "tl", "bl"] would 
6044     * align the Mnu's top left corner to the context element's 
6045     * bottom left corner.  This property is only applied when the "position" 
6046     * configuration property is set to dynamic.
6047     * @type Array
6048     * @default null
6049     */
6050     
6051     
6052     /**
6053     * @config fixedcenter
6054     * @description Boolean indicating if the Menu should be anchored to the 
6055     * center of the viewport.  This property is only applied when the 
6056     * "position" configuration property is set to dynamic.
6057     * @type Boolean
6058     * @default false
6059     */
6060     
6061     
6062     /**
6063     * @config iframe
6064     * @description Boolean indicating whether or not the Menu should 
6065     * have an IFRAME shim; used to prevent SELECT elements from 
6066     * poking through an Overlay instance in IE6.  When set to "true", 
6067     * the iframe shim is created when the Menu instance is intially
6068     * made visible.  This property is only applied when the "position" 
6069     * configuration property is set to dynamic and is automatically applied 
6070     * to all submenus.
6071     * @type Boolean
6072     * @default true for IE6 and below, false for all other browsers.
6073     */
6076         // Add configuration attributes
6078     /*
6079         Change the default value for the "visible" configuration 
6080         property to "false" by re-adding the property.
6081     */
6083     /**
6084     * @config visible
6085     * @description Boolean indicating whether or not the menu is visible.  If 
6086     * the menu's "position" configuration property is set to "dynamic" (the 
6087     * default), this property toggles the menu's <code>&#60;div&#62;</code> 
6088     * element's "visibility" style property between "visible" (true) or 
6089     * "hidden" (false).  If the menu's "position" configuration property is 
6090     * set to "static" this property toggles the menu's 
6091     * <code>&#60;div&#62;</code> element's "display" style property 
6092     * between "block" (true) or "none" (false).
6093     * @default false
6094     * @type Boolean
6095     */
6096     oConfig.addProperty(
6097         VISIBLE_CONFIG.key, 
6098         {
6099             handler: this.configVisible, 
6100             value: VISIBLE_CONFIG.value, 
6101             validator: VISIBLE_CONFIG.validator
6102         }
6103      );
6106     /*
6107         Change the default value for the "constraintoviewport" configuration 
6108         property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6109     */
6111     /**
6112     * @config constraintoviewport
6113     * @description Boolean indicating if the menu will try to remain inside 
6114     * the boundaries of the size of viewport.  This property is only applied 
6115     * when the "position" configuration property is set to dynamic and is 
6116     * automatically applied to all submenus.
6117     * @default true
6118     * @type Boolean
6119     */
6120     oConfig.addProperty(
6121         CONSTRAIN_TO_VIEWPORT_CONFIG.key, 
6122         {
6123             handler: this.configConstrainToViewport, 
6124             value: CONSTRAIN_TO_VIEWPORT_CONFIG.value, 
6125             validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator, 
6126             supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes 
6127         } 
6128     );
6131     /*
6132         Change the default value for the "preventcontextoverlap" configuration 
6133         property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6134     */
6136         /**
6137         * @config preventcontextoverlap
6138         * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem 
6139         * when the "constraintoviewport" configuration property is set to "true".
6140         * @type Boolean
6141         * @default true
6142         */
6143         oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6145                 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value, 
6146                 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator, 
6147                 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6149         });
6152     /**
6153     * @config position
6154     * @description String indicating how a menu should be positioned on the 
6155     * screen.  Possible values are "static" and "dynamic."  Static menus are 
6156     * visible by default and reside in the normal flow of the document 
6157     * (CSS position: static).  Dynamic menus are hidden by default, reside 
6158     * out of the normal flow of the document (CSS position: absolute), and 
6159     * can overlay other elements on the screen.
6160     * @default dynamic
6161     * @type String
6162     */
6163     oConfig.addProperty(
6164         POSITION_CONFIG.key, 
6165         {
6166             handler: this.configPosition,
6167             value: POSITION_CONFIG.value, 
6168             validator: POSITION_CONFIG.validator,
6169             supercedes: POSITION_CONFIG.supercedes
6170         }
6171     );
6174     /**
6175     * @config submenualignment
6176     * @description Array defining how submenus should be aligned to their 
6177     * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6178     * a submenu's top left corner is aligned to its parent menu item's top 
6179     * right corner.
6180     * @default ["tl","tr"]
6181     * @type Array
6182     */
6183     oConfig.addProperty(
6184         SUBMENU_ALIGNMENT_CONFIG.key, 
6185         { 
6186             value: SUBMENU_ALIGNMENT_CONFIG.value,
6187             suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6188         }
6189     );
6192     /**
6193     * @config autosubmenudisplay
6194     * @description Boolean indicating if submenus are automatically made 
6195     * visible when the user mouses over the menu's items.
6196     * @default true
6197     * @type Boolean
6198     */
6199         oConfig.addProperty(
6200            AUTO_SUBMENU_DISPLAY_CONFIG.key, 
6201            { 
6202                value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
6203                validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6204                suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6205        } 
6206     );
6209     /**
6210     * @config showdelay
6211     * @description Number indicating the time (in milliseconds) that should 
6212     * expire before a submenu is made visible when the user mouses over 
6213     * the menu's items.  This property is only applied when the "position" 
6214     * configuration property is set to dynamic and is automatically applied 
6215     * to all submenus.
6216     * @default 250
6217     * @type Number
6218     */
6219         oConfig.addProperty(
6220            SHOW_DELAY_CONFIG.key, 
6221            { 
6222                value: SHOW_DELAY_CONFIG.value, 
6223                validator: SHOW_DELAY_CONFIG.validator,
6224                suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6225        } 
6226     );
6229     /**
6230     * @config hidedelay
6231     * @description Number indicating the time (in milliseconds) that should 
6232     * expire before the menu is hidden.  This property is only applied when 
6233     * the "position" configuration property is set to dynamic and is 
6234     * automatically applied to all submenus.
6235     * @default 0
6236     * @type Number
6237     */
6238         oConfig.addProperty(
6239            HIDE_DELAY_CONFIG.key, 
6240            { 
6241                handler: this.configHideDelay,
6242                value: HIDE_DELAY_CONFIG.value, 
6243                validator: HIDE_DELAY_CONFIG.validator, 
6244                suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6245        } 
6246     );
6249     /**
6250     * @config submenuhidedelay
6251     * @description Number indicating the time (in milliseconds) that should 
6252     * expire before a submenu is hidden when the user mouses out of a menu item 
6253     * heading in the direction of a submenu.  The value must be greater than or 
6254     * equal to the value specified for the "showdelay" configuration property.
6255     * This property is only applied when the "position" configuration property 
6256     * is set to dynamic and is automatically applied to all submenus.
6257     * @default 250
6258     * @type Number
6259     */
6260         oConfig.addProperty(
6261            SUBMENU_HIDE_DELAY_CONFIG.key, 
6262            { 
6263                value: SUBMENU_HIDE_DELAY_CONFIG.value, 
6264                validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6265                suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6266        } 
6267     );
6270     /**
6271     * @config clicktohide
6272     * @description Boolean indicating if the menu will automatically be 
6273     * hidden if the user clicks outside of it.  This property is only 
6274     * applied when the "position" configuration property is set to dynamic 
6275     * and is automatically applied to all submenus.
6276     * @default true
6277     * @type Boolean
6278     */
6279     oConfig.addProperty(
6280         CLICK_TO_HIDE_CONFIG.key,
6281         {
6282             value: CLICK_TO_HIDE_CONFIG.value,
6283             validator: CLICK_TO_HIDE_CONFIG.validator,
6284             suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6285         }
6286     );
6289         /**
6290         * @config container
6291         * @description HTML element reference or string specifying the id 
6292         * attribute of the HTML element that the menu's markup should be 
6293         * rendered into.
6294         * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6295         * level-one-html.html#ID-58190037">HTMLElement</a>|String
6296         * @default document.body
6297         */
6298         oConfig.addProperty(
6299            CONTAINER_CONFIG.key, 
6300            { 
6301                handler: this.configContainer,
6302                value: document.body,
6303            suppressEvent: CONTAINER_CONFIG.suppressEvent
6304        } 
6305    );
6308     /**
6309     * @config scrollincrement
6310     * @description Number used to control the scroll speed of a menu.  Used to 
6311     * increment the "scrollTop" property of the menu's body by when a menu's 
6312     * content is scrolling.  When set this property is automatically applied 
6313     * to all submenus.
6314     * @default 1
6315     * @type Number
6316     */
6317     oConfig.addProperty(
6318         SCROLL_INCREMENT_CONFIG.key, 
6319         { 
6320             value: SCROLL_INCREMENT_CONFIG.value, 
6321             validator: SCROLL_INCREMENT_CONFIG.validator,
6322             supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6323             suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6324         }
6325     );
6328     /**
6329     * @config minscrollheight
6330     * @description Number defining the minimum threshold for the "maxheight" 
6331     * configuration property.  When set this property is automatically applied 
6332     * to all submenus.
6333     * @default 90
6334     * @type Number
6335     */
6336     oConfig.addProperty(
6337         MIN_SCROLL_HEIGHT_CONFIG.key, 
6338         { 
6339             value: MIN_SCROLL_HEIGHT_CONFIG.value, 
6340             validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6341             supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6342             suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6343         }
6344     );
6347     /**
6348     * @config maxheight
6349     * @description Number defining the maximum height (in pixels) for a menu's 
6350     * body element (<code>&#60;div class="bd"&#60;</code>).  Once a menu's body 
6351     * exceeds this height, the contents of the body are scrolled to maintain 
6352     * this value.  This value cannot be set lower than the value of the 
6353     * "minscrollheight" configuration property.
6354     * @default 0
6355     * @type Number
6356     */
6357     oConfig.addProperty(
6358        MAX_HEIGHT_CONFIG.key, 
6359        {
6360             handler: this.configMaxHeight,
6361             value: MAX_HEIGHT_CONFIG.value,
6362             validator: MAX_HEIGHT_CONFIG.validator,
6363             suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6364             supercedes: MAX_HEIGHT_CONFIG.supercedes            
6365        } 
6366     );
6369     /**
6370     * @config classname
6371     * @description String representing the CSS class to be applied to the 
6372     * menu's root <code>&#60;div&#62;</code> element.  The specified class(es)  
6373     * are appended in addition to the default class as specified by the menu's
6374     * CSS_CLASS_NAME constant. When set this property is automatically 
6375     * applied to all submenus.
6376     * @default null
6377     * @type String
6378     */
6379     oConfig.addProperty(
6380         CLASS_NAME_CONFIG.key, 
6381         { 
6382             handler: this.configClassName,
6383             value: CLASS_NAME_CONFIG.value, 
6384             validator: CLASS_NAME_CONFIG.validator,
6385             supercedes: CLASS_NAME_CONFIG.supercedes      
6386         }
6387     );
6390     /**
6391     * @config disabled
6392     * @description Boolean indicating if the menu should be disabled.  
6393     * Disabling a menu disables each of its items.  (Disabled menu items are 
6394     * dimmed and will not respond to user input or fire events.)  Disabled
6395     * menus have a corresponding "disabled" CSS class applied to their root
6396     * <code>&#60;div&#62;</code> element.
6397     * @default false
6398     * @type Boolean
6399     */
6400     oConfig.addProperty(
6401         DISABLED_CONFIG.key, 
6402         { 
6403             handler: this.configDisabled,
6404             value: DISABLED_CONFIG.value, 
6405             validator: DISABLED_CONFIG.validator,
6406             suppressEvent: DISABLED_CONFIG.suppressEvent
6407         }
6408     );
6411     /**
6412     * @config shadow
6413     * @description Boolean indicating if the menu should have a shadow.
6414     * @default true
6415     * @type Boolean
6416     */
6417     oConfig.addProperty(
6418         SHADOW_CONFIG.key, 
6419         { 
6420             handler: this.configShadow,
6421             value: SHADOW_CONFIG.value, 
6422             validator: SHADOW_CONFIG.validator
6423         }
6424     );
6427     /**
6428     * @config keepopen
6429     * @description Boolean indicating if the menu should remain open when clicked.
6430     * @default flase
6431     * @type Boolean
6432     */
6433     oConfig.addProperty(
6434         KEEP_OPEN_CONFIG.key, 
6435         { 
6436             value: KEEP_OPEN_CONFIG.value, 
6437             validator: KEEP_OPEN_CONFIG.validator
6438         }
6439     );
6443 }); // END YAHOO.lang.extend
6445 })();
6449 (function () {
6452 * Creates an item for a menu.
6454 * @param {String} p_oObject String specifying the text of the menu item.
6455 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6456 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
6457 * the <code>&#60;li&#62;</code> element of the menu item.
6458 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6459 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
6460 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6461 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6462 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
6463 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6464 * @param {Object} p_oConfig Optional. Object literal specifying the 
6465 * configuration for the menu item. See configuration class documentation 
6466 * for more details.
6467 * @class MenuItem
6468 * @constructor
6470 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6472     if (p_oObject) {
6474         if (p_oConfig) {
6475     
6476             this.parent = p_oConfig.parent;
6477             this.value = p_oConfig.value;
6478             this.id = p_oConfig.id;
6480         }
6482         this.init(p_oObject, p_oConfig);
6484     }
6489 var Dom = YAHOO.util.Dom,
6490     Module = YAHOO.widget.Module,
6491     Menu = YAHOO.widget.Menu,
6492     MenuItem = YAHOO.widget.MenuItem,
6493     CustomEvent = YAHOO.util.CustomEvent,
6494     UA = YAHOO.env.ua,
6495     Lang = YAHOO.lang,
6497         // Private string constants
6499         _TEXT = "text",
6500         _HASH = "#",
6501         _HYPHEN = "-",
6502         _HELP_TEXT = "helptext",
6503         _URL = "url",
6504         _TARGET = "target",
6505         _EMPHASIS = "emphasis",
6506         _STRONG_EMPHASIS = "strongemphasis",
6507         _CHECKED = "checked",
6508         _SUBMENU = "submenu",
6509         _DISABLED = "disabled",
6510         _SELECTED = "selected",
6511         _HAS_SUBMENU = "hassubmenu",
6512         _CHECKED_DISABLED = "checked-disabled",
6513         _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6514         _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6515         _CHECKED_SELECTED = "checked-selected",
6516         _ONCLICK = "onclick",
6517         _CLASSNAME = "classname",
6518         _EMPTY_STRING = "",
6519         _OPTION = "OPTION",
6520         _OPTGROUP = "OPTGROUP",
6521         _LI_UPPERCASE = "LI",
6522         _LI_LOWERCASE = "li",
6523         _HREF = "href",
6524         _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6525         _SELECT = "SELECT",
6526         _DIV = "DIV",
6527         _START_HELP_TEXT = "<em class=\"helptext\">",
6528         _START_EM = "<em>",
6529         _END_EM = "</em>",
6530         _START_STRONG = "<strong>",
6531         _END_STRONG = "</strong>",
6532         _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6533         _OBJ = "obj",
6534         _SCOPE = "scope",
6535         _NONE = "none",
6536         _VISIBLE = "visible",
6537         _SPACE = " ",
6538         _MENUITEM = "MenuItem",
6540     EVENT_TYPES = [
6541     
6542         ["mouseOverEvent", "mouseover"],
6543         ["mouseOutEvent", "mouseout"],
6544         ["mouseDownEvent", "mousedown"],
6545         ["mouseUpEvent", "mouseup"],
6546         ["clickEvent", "click"],
6547         ["keyPressEvent", "keypress"],
6548         ["keyDownEvent", "keydown"],
6549         ["keyUpEvent", "keyup"],
6550         ["focusEvent", "focus"],
6551         ["blurEvent", "blur"],
6552         ["destroyEvent", "destroy"]
6553     
6554     ],
6556         TEXT_CONFIG = { 
6557                 key: _TEXT, 
6558                 value: _EMPTY_STRING, 
6559                 validator: Lang.isString, 
6560                 suppressEvent: true 
6561         }, 
6563         HELP_TEXT_CONFIG = { 
6564                 key: _HELP_TEXT,
6565                 supercedes: [_TEXT], 
6566                 suppressEvent: true 
6567         },
6569         URL_CONFIG = { 
6570                 key: _URL, 
6571                 value: _HASH, 
6572                 suppressEvent: true 
6573         }, 
6575         TARGET_CONFIG = { 
6576                 key: _TARGET, 
6577                 suppressEvent: true 
6578         }, 
6580         EMPHASIS_CONFIG = { 
6581                 key: _EMPHASIS, 
6582                 value: false, 
6583                 validator: Lang.isBoolean, 
6584                 suppressEvent: true, 
6585                 supercedes: [_TEXT]
6586         }, 
6588         STRONG_EMPHASIS_CONFIG = { 
6589                 key: _STRONG_EMPHASIS, 
6590                 value: false, 
6591                 validator: Lang.isBoolean, 
6592                 suppressEvent: true,
6593                 supercedes: [_TEXT]
6594         },
6596         CHECKED_CONFIG = { 
6597                 key: _CHECKED, 
6598                 value: false, 
6599                 validator: Lang.isBoolean, 
6600                 suppressEvent: true, 
6601                 supercedes: [_DISABLED, _SELECTED]
6602         }, 
6604         SUBMENU_CONFIG = { 
6605                 key: _SUBMENU,
6606                 suppressEvent: true,
6607                 supercedes: [_DISABLED, _SELECTED]
6608         },
6610         DISABLED_CONFIG = { 
6611                 key: _DISABLED, 
6612                 value: false, 
6613                 validator: Lang.isBoolean, 
6614                 suppressEvent: true,
6615                 supercedes: [_TEXT, _SELECTED]
6616         },
6618         SELECTED_CONFIG = { 
6619                 key: _SELECTED, 
6620                 value: false, 
6621                 validator: Lang.isBoolean, 
6622                 suppressEvent: true
6623         },
6625         ONCLICK_CONFIG = { 
6626                 key: _ONCLICK,
6627                 suppressEvent: true
6628         },
6630         CLASS_NAME_CONFIG = { 
6631                 key: _CLASSNAME, 
6632                 value: null, 
6633                 validator: Lang.isString,
6634                 suppressEvent: true
6635         },
6636     
6637     CLASS_NAMES = {},
6638     
6639     m_oMenuItemTemplate;
6643 * @method getClassNameForState
6644 * @description Returns a class name for the specified prefix and state.  If the class name does not 
6645 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6646 * @private
6647 * @param {String} prefix String representing the prefix for the class name
6648 * @param {String} state String representing a state - "disabled," "checked," etc.
6649 */  
6650 var getClassNameForState = function (prefix, state) {
6652         var oClassNames = CLASS_NAMES[prefix];
6653         
6654         if (!oClassNames) {
6655                 CLASS_NAMES[prefix] = {};
6656                 oClassNames = CLASS_NAMES[prefix];
6657         }
6660         var sClassName = oClassNames[state];
6662         if (!sClassName) {
6663                 sClassName = prefix + _HYPHEN + state;
6664                 oClassNames[state] = sClassName;
6665         }
6667         return sClassName;
6668         
6673 * @method addClassNameForState
6674 * @description Applies a class name to a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6675 * that represents a MenuItem's state - "disabled," "checked," etc.
6676 * @private
6677 * @param {String} state String representing a state - "disabled," "checked," etc.
6678 */  
6679 var addClassNameForState = function (state) {
6681         Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6682         Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6687 * @method removeClassNameForState
6688 * @description Removes a class name from a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6689 * that represents a MenuItem's state - "disabled," "checked," etc.
6690 * @private
6691 * @param {String} state String representing a state - "disabled," "checked," etc.
6692 */  
6693 var removeClassNameForState = function (state) {
6695         Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6696         Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6701 MenuItem.prototype = {
6703     /**
6704     * @property CSS_CLASS_NAME
6705     * @description String representing the CSS class(es) to be applied to the 
6706     * <code>&#60;li&#62;</code> element of the menu item.
6707     * @default "yuimenuitem"
6708     * @final
6709     * @type String
6710     */
6711     CSS_CLASS_NAME: "yuimenuitem",
6714     /**
6715     * @property CSS_LABEL_CLASS_NAME
6716     * @description String representing the CSS class(es) to be applied to the 
6717     * menu item's <code>&#60;a&#62;</code> element.
6718     * @default "yuimenuitemlabel"
6719     * @final
6720     * @type String
6721     */
6722     CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6725     /**
6726     * @property SUBMENU_TYPE
6727     * @description Object representing the type of menu to instantiate and 
6728     * add when parsing the child nodes of the menu item's source HTML element.
6729     * @final
6730     * @type YAHOO.widget.Menu
6731     */
6732     SUBMENU_TYPE: null,
6736     // Private member variables
6737     
6739     /**
6740     * @property _oAnchor
6741     * @description Object reference to the menu item's 
6742     * <code>&#60;a&#62;</code> element.
6743     * @default null 
6744     * @private
6745     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6746     * one-html.html#ID-48250443">HTMLAnchorElement</a>
6747     */
6748     _oAnchor: null,
6749     
6750     
6751     /**
6752     * @property _oHelpTextEM
6753     * @description Object reference to the menu item's help text 
6754     * <code>&#60;em&#62;</code> element.
6755     * @default null
6756     * @private
6757     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6758     * one-html.html#ID-58190037">HTMLElement</a>
6759     */
6760     _oHelpTextEM: null,
6761     
6762     
6763     /**
6764     * @property _oSubmenu
6765     * @description Object reference to the menu item's submenu.
6766     * @default null
6767     * @private
6768     * @type YAHOO.widget.Menu
6769     */
6770     _oSubmenu: null,
6773     /** 
6774     * @property _oOnclickAttributeValue
6775     * @description Object reference to the menu item's current value for the 
6776     * "onclick" configuration attribute.
6777     * @default null
6778     * @private
6779     * @type Object
6780     */
6781     _oOnclickAttributeValue: null,
6784     /**
6785     * @property _sClassName
6786     * @description The current value of the "classname" configuration attribute.
6787     * @default null
6788     * @private
6789     * @type String
6790     */
6791     _sClassName: null,
6795     // Public properties
6798         /**
6799     * @property constructor
6800         * @description Object reference to the menu item's constructor function.
6801     * @default YAHOO.widget.MenuItem
6802         * @type YAHOO.widget.MenuItem
6803         */
6804         constructor: MenuItem,
6807     /**
6808     * @property index
6809     * @description Number indicating the ordinal position of the menu item in 
6810     * its group.
6811     * @default null
6812     * @type Number
6813     */
6814     index: null,
6817     /**
6818     * @property groupIndex
6819     * @description Number indicating the index of the group to which the menu 
6820     * item belongs.
6821     * @default null
6822     * @type Number
6823     */
6824     groupIndex: null,
6827     /**
6828     * @property parent
6829     * @description Object reference to the menu item's parent menu.
6830     * @default null
6831     * @type YAHOO.widget.Menu
6832     */
6833     parent: null,
6836     /**
6837     * @property element
6838     * @description Object reference to the menu item's 
6839     * <code>&#60;li&#62;</code> element.
6840     * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6841     * -one-html.html#ID-74680021">HTMLLIElement</a>
6842     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6843     * one-html.html#ID-74680021">HTMLLIElement</a>
6844     */
6845     element: null,
6848     /**
6849     * @property srcElement
6850     * @description Object reference to the HTML element (either 
6851     * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or 
6852     * <code>&#60;option&#62;</code>) used create the menu item.
6853     * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6854     * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6855     * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6856     * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6857     * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6858     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6859     * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6860     * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6861     * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6862     * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6863     */
6864     srcElement: null,
6867     /**
6868     * @property value
6869     * @description Object reference to the menu item's value.
6870     * @default null
6871     * @type Object
6872     */
6873     value: null,
6876         /**
6877     * @property browser
6878     * @deprecated Use YAHOO.env.ua
6879         * @description String representing the browser.
6880         * @type String
6881         */
6882         browser: Module.prototype.browser,
6885     /**
6886     * @property id
6887     * @description Id of the menu item's root <code>&#60;li&#62;</code> 
6888     * element.  This property should be set via the constructor using the 
6889     * configuration object literal.  If an id is not specified, then one will 
6890     * be created using the "generateId" method of the Dom utility.
6891     * @default null
6892     * @type String
6893     */
6894     id: null,
6898     // Events
6901     /**
6902     * @event destroyEvent
6903     * @description Fires when the menu item's <code>&#60;li&#62;</code> 
6904     * element is removed from its parent <code>&#60;ul&#62;</code> element.
6905     * @type YAHOO.util.CustomEvent
6906     */
6909     /**
6910     * @event mouseOverEvent
6911     * @description Fires when the mouse has entered the menu item.  Passes 
6912     * back the DOM Event object as an argument.
6913     * @type YAHOO.util.CustomEvent
6914     */
6917     /**
6918     * @event mouseOutEvent
6919     * @description Fires when the mouse has left the menu item.  Passes back 
6920     * the DOM Event object as an argument.
6921     * @type YAHOO.util.CustomEvent
6922     */
6925     /**
6926     * @event mouseDownEvent
6927     * @description Fires when the user mouses down on the menu item.  Passes 
6928     * back the DOM Event object as an argument.
6929     * @type YAHOO.util.CustomEvent
6930     */
6933     /**
6934     * @event mouseUpEvent
6935     * @description Fires when the user releases a mouse button while the mouse 
6936     * is over the menu item.  Passes back the DOM Event object as an argument.
6937     * @type YAHOO.util.CustomEvent
6938     */
6941     /**
6942     * @event clickEvent
6943     * @description Fires when the user clicks the on the menu item.  Passes 
6944     * back the DOM Event object as an argument.
6945     * @type YAHOO.util.CustomEvent
6946     */
6949     /**
6950     * @event keyPressEvent
6951     * @description Fires when the user presses an alphanumeric key when the 
6952     * menu item has focus.  Passes back the DOM Event object as an argument.
6953     * @type YAHOO.util.CustomEvent
6954     */
6957     /**
6958     * @event keyDownEvent
6959     * @description Fires when the user presses a key when the menu item has 
6960     * focus.  Passes back the DOM Event object as an argument.
6961     * @type YAHOO.util.CustomEvent
6962     */
6965     /**
6966     * @event keyUpEvent
6967     * @description Fires when the user releases a key when the menu item has 
6968     * focus.  Passes back the DOM Event object as an argument.
6969     * @type YAHOO.util.CustomEvent
6970     */
6973     /**
6974     * @event focusEvent
6975     * @description Fires when the menu item receives focus.
6976     * @type YAHOO.util.CustomEvent
6977     */
6980     /**
6981     * @event blurEvent
6982     * @description Fires when the menu item loses the input focus.
6983     * @type YAHOO.util.CustomEvent
6984     */
6987     /**
6988     * @method init
6989     * @description The MenuItem class's initialization method. This method is 
6990     * automatically called by the constructor, and sets up all DOM references 
6991     * for pre-existing markup, and creates required markup if it is not 
6992     * already present.
6993     * @param {String} p_oObject String specifying the text of the menu item.
6994     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6995     * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
6996     * the <code>&#60;li&#62;</code> element of the menu item.
6997     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6998     * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
6999     * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
7000     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7001     * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
7002     * specifying the <code>&#60;option&#62;</code> element of the menu item.
7003     * @param {Object} p_oConfig Optional. Object literal specifying the 
7004     * configuration for the menu item. See configuration class documentation 
7005     * for more details.
7006     */
7007     init: function (p_oObject, p_oConfig) {
7010         if (!this.SUBMENU_TYPE) {
7011     
7012             this.SUBMENU_TYPE = Menu;
7013     
7014         }
7017         // Create the config object
7019         this.cfg = new YAHOO.util.Config(this);
7021         this.initDefaultConfig();
7023         var oConfig = this.cfg,
7024             sURL = _HASH,
7025             oCustomEvent,
7026                         aEventData,
7027             oAnchor,
7028             sTarget,
7029             sText,
7030             sId,
7031             i;
7034         if (Lang.isString(p_oObject)) {
7036             this._createRootNodeStructure();
7038             oConfig.queueProperty(_TEXT, p_oObject);
7040         }
7041         else if (p_oObject && p_oObject.tagName) {
7043             switch(p_oObject.tagName.toUpperCase()) {
7045                 case _OPTION:
7047                     this._createRootNodeStructure();
7049                     oConfig.queueProperty(_TEXT, p_oObject.text);
7050                     oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7052                     this.value = p_oObject.value;
7054                     this.srcElement = p_oObject;
7056                 break;
7058                 case _OPTGROUP:
7060                     this._createRootNodeStructure();
7062                     oConfig.queueProperty(_TEXT, p_oObject.label);
7063                     oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7065                     this.srcElement = p_oObject;
7067                     this._initSubTree();
7069                 break;
7071                 case _LI_UPPERCASE:
7073                     // Get the anchor node (if it exists)
7074                     
7075                     oAnchor = Dom.getFirstChild(p_oObject);
7078                     // Capture the "text" and/or the "URL"
7080                     if (oAnchor) {
7082                         sURL = oAnchor.getAttribute(_HREF, 2);
7083                         sTarget = oAnchor.getAttribute(_TARGET);
7085                         sText = oAnchor.innerHTML;
7087                     }
7089                     this.srcElement = p_oObject;
7090                     this.element = p_oObject;
7091                     this._oAnchor = oAnchor;
7093                     /*
7094                         Set these properties silently to sync up the 
7095                         configuration object without making changes to the 
7096                         element's DOM
7097                     */ 
7099                     oConfig.setProperty(_TEXT, sText, true);
7100                     oConfig.setProperty(_URL, sURL, true);
7101                     oConfig.setProperty(_TARGET, sTarget, true);
7103                     this._initSubTree();
7105                 break;
7107             }            
7109         }
7112         if (this.element) {
7114             sId = (this.srcElement || this.element).id;
7116             if (!sId) {
7118                 sId = this.id || Dom.generateId();
7120                 this.element.id = sId;
7122             }
7124             this.id = sId;
7127             Dom.addClass(this.element, this.CSS_CLASS_NAME);
7128             Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7131                         i = EVENT_TYPES.length - 1;
7133                         do {
7135                                 aEventData = EVENT_TYPES[i];
7137                                 oCustomEvent = this.createEvent(aEventData[1]);
7138                                 oCustomEvent.signature = CustomEvent.LIST;
7139                                 
7140                                 this[aEventData[0]] = oCustomEvent;
7142                         }
7143                         while (i--);
7146             if (p_oConfig) {
7147     
7148                 oConfig.applyConfig(p_oConfig);
7149     
7150             }        
7152             oConfig.fireQueue();
7154         }
7156     },
7160     // Private methods
7162     /**
7163     * @method _createRootNodeStructure
7164     * @description Creates the core DOM structure for the menu item.
7165     * @private
7166     */
7167     _createRootNodeStructure: function () {
7169         var oElement,
7170             oAnchor;
7172         if (!m_oMenuItemTemplate) {
7174             m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7175             m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7177         }
7179         oElement = m_oMenuItemTemplate.cloneNode(true);
7180         oElement.className = this.CSS_CLASS_NAME;
7182         oAnchor = oElement.firstChild;
7183         oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7184         
7185         this.element = oElement;
7186         this._oAnchor = oAnchor;
7188     },
7191     /**
7192     * @method _initSubTree
7193     * @description Iterates the source element's childNodes collection and uses 
7194     * the child nodes to instantiate other menus.
7195     * @private
7196     */
7197     _initSubTree: function () {
7199         var oSrcEl = this.srcElement,
7200             oConfig = this.cfg,
7201             oNode,
7202             aOptions,
7203             nOptions,
7204             oMenu,
7205             n;
7208         if (oSrcEl.childNodes.length > 0) {
7210             if (this.parent.lazyLoad && this.parent.srcElement && 
7211                 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7213                 oConfig.setProperty(
7214                         _SUBMENU, 
7215                         { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7216                     );
7218             }
7219             else {
7221                 oNode = oSrcEl.firstChild;
7222                 aOptions = [];
7223     
7224                 do {
7225     
7226                     if (oNode && oNode.tagName) {
7227     
7228                         switch(oNode.tagName.toUpperCase()) {
7229                 
7230                             case _DIV:
7231                 
7232                                 oConfig.setProperty(_SUBMENU, oNode);
7233                 
7234                             break;
7235          
7236                             case _OPTION:
7237         
7238                                 aOptions[aOptions.length] = oNode;
7239         
7240                             break;
7241                
7242                         }
7243                     
7244                     }
7245                 
7246                 }        
7247                 while((oNode = oNode.nextSibling));
7248     
7249     
7250                 nOptions = aOptions.length;
7251     
7252                 if (nOptions > 0) {
7253     
7254                     oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7255                     
7256                     oConfig.setProperty(_SUBMENU, oMenu);
7257     
7258                     for(n=0; n<nOptions; n++) {
7259         
7260                         oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7261         
7262                     }
7263         
7264                 }
7265             
7266             }
7268         }
7270     },
7274     // Event handlers for configuration properties
7277     /**
7278     * @method configText
7279     * @description Event handler for when the "text" configuration property of 
7280     * the menu item changes.
7281     * @param {String} p_sType String representing the name of the event that 
7282     * was fired.
7283     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7284     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7285     * that fired the event.
7286     */
7287     configText: function (p_sType, p_aArgs, p_oItem) {
7289         var sText = p_aArgs[0],
7290             oConfig = this.cfg,
7291             oAnchor = this._oAnchor,
7292             sHelpText = oConfig.getProperty(_HELP_TEXT),
7293             sHelpTextHTML = _EMPTY_STRING,
7294             sEmphasisStartTag = _EMPTY_STRING,
7295             sEmphasisEndTag = _EMPTY_STRING;
7298         if (sText) {
7301             if (sHelpText) {
7302                     
7303                 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7304             
7305             }
7308             if (oConfig.getProperty(_EMPHASIS)) {
7310                 sEmphasisStartTag = _START_EM;
7311                 sEmphasisEndTag = _END_EM;
7313             }
7316             if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7318                 sEmphasisStartTag = _START_STRONG;
7319                 sEmphasisEndTag = _END_STRONG;
7320             
7321             }
7324             oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7326         }
7328     },
7331     /**
7332     * @method configHelpText
7333     * @description Event handler for when the "helptext" configuration property 
7334     * of the 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.
7340     */    
7341     configHelpText: function (p_sType, p_aArgs, p_oItem) {
7343         this.cfg.refireEvent(_TEXT);
7345     },
7348     /**
7349     * @method configURL
7350     * @description Event handler for when the "url" configuration property of 
7351     * the menu item changes.
7352     * @param {String} p_sType String representing the name of the event that 
7353     * was fired.
7354     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7355     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7356     * that fired the event.
7357     */    
7358     configURL: function (p_sType, p_aArgs, p_oItem) {
7360         var sURL = p_aArgs[0];
7362         if (!sURL) {
7364             sURL = _HASH;
7366         }
7368         var oAnchor = this._oAnchor;
7370         if (UA.opera) {
7372             oAnchor.removeAttribute(_HREF);
7373         
7374         }
7376         oAnchor.setAttribute(_HREF, sURL);
7378     },
7381     /**
7382     * @method configTarget
7383     * @description Event handler for when the "target" configuration property 
7384     * of the menu item changes.  
7385     * @param {String} p_sType String representing the name of the event that 
7386     * was fired.
7387     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7388     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7389     * that fired the event.
7390     */    
7391     configTarget: function (p_sType, p_aArgs, p_oItem) {
7393         var sTarget = p_aArgs[0],
7394             oAnchor = this._oAnchor;
7396         if (sTarget && sTarget.length > 0) {
7398             oAnchor.setAttribute(_TARGET, sTarget);
7400         }
7401         else {
7403             oAnchor.removeAttribute(_TARGET);
7404         
7405         }
7407     },
7410     /**
7411     * @method configEmphasis
7412     * @description Event handler for when the "emphasis" configuration property
7413     * of the menu item changes.
7414     * @param {String} p_sType String representing the name of the event that 
7415     * was fired.
7416     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7417     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7418     * that fired the event.
7419     */    
7420     configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7422         var bEmphasis = p_aArgs[0],
7423             oConfig = this.cfg;
7426         if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7428             oConfig.setProperty(_STRONG_EMPHASIS, false);
7430         }
7433         oConfig.refireEvent(_TEXT);
7435     },
7438     /**
7439     * @method configStrongEmphasis
7440     * @description Event handler for when the "strongemphasis" configuration 
7441     * property of the menu item changes.
7442     * @param {String} p_sType String representing the name of the event that 
7443     * was fired.
7444     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7445     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7446     * that fired the event.
7447     */    
7448     configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7450         var bStrongEmphasis = p_aArgs[0],
7451             oConfig = this.cfg;
7454         if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7456             oConfig.setProperty(_EMPHASIS, false);
7458         }
7460         oConfig.refireEvent(_TEXT);
7462     },
7465     /**
7466     * @method configChecked
7467     * @description Event handler for when the "checked" configuration property 
7468     * of the menu item changes. 
7469     * @param {String} p_sType String representing the name of the event that 
7470     * was fired.
7471     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7472     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7473     * that fired the event.
7474     */    
7475     configChecked: function (p_sType, p_aArgs, p_oItem) {
7477         var bChecked = p_aArgs[0],
7478             oConfig = this.cfg;
7481         if (bChecked) {
7483             addClassNameForState.call(this, _CHECKED);
7485         }
7486         else {
7488             removeClassNameForState.call(this, _CHECKED);
7489         }
7492         oConfig.refireEvent(_TEXT);
7495         if (oConfig.getProperty(_DISABLED)) {
7497             oConfig.refireEvent(_DISABLED);
7499         }
7502         if (oConfig.getProperty(_SELECTED)) {
7504             oConfig.refireEvent(_SELECTED);
7506         }
7508     },
7512     /**
7513     * @method configDisabled
7514     * @description Event handler for when the "disabled" configuration property 
7515     * of the menu item changes. 
7516     * @param {String} p_sType String representing the name of the event that 
7517     * was fired.
7518     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7519     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7520     * that fired the event.
7521     */    
7522     configDisabled: function (p_sType, p_aArgs, p_oItem) {
7524         var bDisabled = p_aArgs[0],
7525             oConfig = this.cfg,
7526             oSubmenu = oConfig.getProperty(_SUBMENU),
7527             bChecked = oConfig.getProperty(_CHECKED);
7530         if (bDisabled) {
7532             if (oConfig.getProperty(_SELECTED)) {
7534                 oConfig.setProperty(_SELECTED, false);
7536             }
7539                         addClassNameForState.call(this, _DISABLED);
7542             if (oSubmenu) {
7544                                 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7545             
7546             }
7547             
7549             if (bChecked) {
7551                                 addClassNameForState.call(this, _CHECKED_DISABLED);
7553             }
7555         }
7556         else {
7558                         removeClassNameForState.call(this, _DISABLED);
7561             if (oSubmenu) {
7563                                 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7564             
7565             }
7566             
7568             if (bChecked) {
7570                                 removeClassNameForState.call(this, _CHECKED_DISABLED);
7572             }
7574         }
7576     },
7579     /**
7580     * @method configSelected
7581     * @description Event handler for when the "selected" configuration property 
7582     * of the menu item changes. 
7583     * @param {String} p_sType String representing the name of the event that 
7584     * was fired.
7585     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7586     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7587     * that fired the event.
7588     */    
7589     configSelected: function (p_sType, p_aArgs, p_oItem) {
7591         var oConfig = this.cfg,
7592                 oAnchor = this._oAnchor,
7593                 
7594             bSelected = p_aArgs[0],
7595             bChecked = oConfig.getProperty(_CHECKED),
7596             oSubmenu = oConfig.getProperty(_SUBMENU);
7599         if (UA.opera) {
7601             oAnchor.blur();
7602         
7603         }
7606         if (bSelected && !oConfig.getProperty(_DISABLED)) {
7608                         addClassNameForState.call(this, _SELECTED);
7611             if (oSubmenu) {
7613                                 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7614             
7615             }
7618             if (bChecked) {
7620                                 addClassNameForState.call(this, _CHECKED_SELECTED);
7622             }
7624         }
7625         else {
7627                         removeClassNameForState.call(this, _SELECTED);
7630             if (oSubmenu) {
7632                                 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7633             
7634             }
7637             if (bChecked) {
7639                                 removeClassNameForState.call(this, _CHECKED_SELECTED);
7641             }
7643         }
7646         if (this.hasFocus() && UA.opera) {
7647         
7648             oAnchor.focus();
7649         
7650         }
7652     },
7655     /**
7656     * @method _onSubmenuBeforeHide
7657     * @description "beforehide" Custom Event handler for a submenu.
7658     * @private
7659     * @param {String} p_sType String representing the name of the event that 
7660     * was fired.
7661     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7662     */
7663     _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7665         var oItem = this.parent,
7666             oMenu;
7668         function onHide() {
7670             oItem._oAnchor.blur();
7671             oMenu.beforeHideEvent.unsubscribe(onHide);
7672         
7673         }
7676         if (oItem.hasFocus()) {
7678             oMenu = oItem.parent;
7680             oMenu.beforeHideEvent.subscribe(onHide);
7681         
7682         }
7683     
7684     },
7687     /**
7688     * @method configSubmenu
7689     * @description Event handler for when the "submenu" configuration property 
7690     * of the menu item changes. 
7691     * @param {String} p_sType String representing the name of the event that 
7692     * was fired.
7693     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7694     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7695     * that fired the event.
7696     */
7697     configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7699         var oSubmenu = p_aArgs[0],
7700             oConfig = this.cfg,
7701             bLazyLoad = this.parent && this.parent.lazyLoad,
7702             oMenu,
7703             sSubmenuId,
7704             oSubmenuConfig;
7707         if (oSubmenu) {
7709             if (oSubmenu instanceof Menu) {
7711                 oMenu = oSubmenu;
7712                 oMenu.parent = this;
7713                 oMenu.lazyLoad = bLazyLoad;
7715             }
7716             else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7718                 sSubmenuId = oSubmenu.id;
7719                 oSubmenuConfig = oSubmenu;
7721                 oSubmenuConfig.lazyload = bLazyLoad;
7722                 oSubmenuConfig.parent = this;
7724                 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7727                 // Set the value of the property to the Menu instance
7729                 oConfig.setProperty(_SUBMENU, oMenu, true);
7731             }
7732             else {
7734                 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7737                 // Set the value of the property to the Menu instance
7738                 
7739                 oConfig.setProperty(_SUBMENU, oMenu, true);
7741             }
7744             if (oMenu) {
7746                                 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7748                 addClassNameForState.call(this, _HAS_SUBMENU);
7751                                 if (oConfig.getProperty(_URL) === _HASH) {
7752                                 
7753                                         oConfig.setProperty(_URL, (_HASH + oMenu.id));
7754                                 
7755                                 }
7758                 this._oSubmenu = oMenu;
7761                 if (UA.opera) {
7762                 
7763                     oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);               
7764                 
7765                 }
7766             
7767             }
7769         }
7770         else {
7772                         removeClassNameForState.call(this, _HAS_SUBMENU);
7774             if (this._oSubmenu) {
7776                 this._oSubmenu.destroy();
7778             }
7780         }
7783         if (oConfig.getProperty(_DISABLED)) {
7785             oConfig.refireEvent(_DISABLED);
7787         }
7790         if (oConfig.getProperty(_SELECTED)) {
7792             oConfig.refireEvent(_SELECTED);
7794         }
7796     },
7799     /**
7800     * @method configOnClick
7801     * @description Event handler for when the "onclick" configuration property 
7802     * of the menu item changes. 
7803     * @param {String} p_sType String representing the name of the event that 
7804     * was fired.
7805     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7806     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7807     * that fired the event.
7808     */
7809     configOnClick: function (p_sType, p_aArgs, p_oItem) {
7811         var oObject = p_aArgs[0];
7813         /*
7814             Remove any existing listeners if a "click" event handler has 
7815             already been specified.
7816         */
7818         if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7820             this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn, 
7821                                 this._oOnclickAttributeValue.obj);
7823             this._oOnclickAttributeValue = null;
7825         }
7828         if (!this._oOnclickAttributeValue && Lang.isObject(oObject) && 
7829             Lang.isFunction(oObject.fn)) {
7830             
7831             this.clickEvent.subscribe(oObject.fn, 
7832                 ((_OBJ in oObject) ? oObject.obj : this), 
7833                 ((_SCOPE in oObject) ? oObject.scope : null) );
7835             this._oOnclickAttributeValue = oObject;
7837         }
7838     
7839     },
7842     /**
7843     * @method configClassName
7844     * @description Event handler for when the "classname" configuration 
7845     * property of a menu item changes.
7846     * @param {String} p_sType String representing the name of the event that 
7847     * was fired.
7848     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7849     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7850     * that fired the event.
7851     */
7852     configClassName: function (p_sType, p_aArgs, p_oItem) {
7853     
7854         var sClassName = p_aArgs[0];
7855     
7856         if (this._sClassName) {
7857     
7858             Dom.removeClass(this.element, this._sClassName);
7859     
7860         }
7861     
7862         Dom.addClass(this.element, sClassName);
7863         this._sClassName = sClassName;
7864     
7865     },
7869     // Public methods
7872         /**
7873     * @method initDefaultConfig
7874         * @description Initializes an item's configurable properties.
7875         */
7876         initDefaultConfig : function () {
7878         var oConfig = this.cfg;
7881         // Define the configuration attributes
7883         /**
7884         * @config text
7885         * @description String specifying the text label for the menu item.  
7886         * When building a menu from existing HTML the value of this property
7887         * will be interpreted from the menu's markup.
7888         * @default ""
7889         * @type String
7890         */
7891         oConfig.addProperty(
7892             TEXT_CONFIG.key, 
7893             { 
7894                 handler: this.configText, 
7895                 value: TEXT_CONFIG.value, 
7896                 validator: TEXT_CONFIG.validator, 
7897                 suppressEvent: TEXT_CONFIG.suppressEvent 
7898             }
7899         );
7900         
7902         /**
7903         * @config helptext
7904         * @description String specifying additional instructional text to 
7905         * accompany the text for the menu item.
7906         * @deprecated Use "text" configuration property to add help text markup.  
7907         * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em 
7908         * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
7909         * @default null
7910         * @type String|<a href="http://www.w3.org/TR/
7911         * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
7912         * HTMLElement</a>
7913         */
7914         oConfig.addProperty(
7915             HELP_TEXT_CONFIG.key,
7916             {
7917                 handler: this.configHelpText, 
7918                 supercedes: HELP_TEXT_CONFIG.supercedes,
7919                 suppressEvent: HELP_TEXT_CONFIG.suppressEvent 
7920             }
7921         );
7924         /**
7925         * @config url
7926         * @description String specifying the URL for the menu item's anchor's 
7927         * "href" attribute.  When building a menu from existing HTML the value 
7928         * of this property will be interpreted from the menu's markup.
7929         * @default "#"
7930         * @type String
7931         */        
7932         oConfig.addProperty(
7933             URL_CONFIG.key, 
7934             {
7935                 handler: this.configURL, 
7936                 value: URL_CONFIG.value, 
7937                 suppressEvent: URL_CONFIG.suppressEvent
7938             }
7939         );
7942         /**
7943         * @config target
7944         * @description String specifying the value for the "target" attribute 
7945         * of the menu item's anchor element. <strong>Specifying a target will 
7946         * require the user to click directly on the menu item's anchor node in
7947         * order to cause the browser to navigate to the specified URL.</strong> 
7948         * When building a menu from existing HTML the value of this property 
7949         * will be interpreted from the menu's markup.
7950         * @default null
7951         * @type String
7952         */        
7953         oConfig.addProperty(
7954             TARGET_CONFIG.key, 
7955             {
7956                 handler: this.configTarget, 
7957                 suppressEvent: TARGET_CONFIG.suppressEvent
7958             }
7959         );
7962         /**
7963         * @config emphasis
7964         * @description Boolean indicating if the text of the menu item will be 
7965         * rendered with emphasis.
7966         * @deprecated Use the "text" configuration property to add emphasis.  
7967         * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some 
7968         * Text&#60;/em&#62;");</code>
7969         * @default false
7970         * @type Boolean
7971         */
7972         oConfig.addProperty(
7973             EMPHASIS_CONFIG.key, 
7974             { 
7975                 handler: this.configEmphasis, 
7976                 value: EMPHASIS_CONFIG.value, 
7977                 validator: EMPHASIS_CONFIG.validator, 
7978                 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
7979                 supercedes: EMPHASIS_CONFIG.supercedes
7980             }
7981         );
7984         /**
7985         * @config strongemphasis
7986         * @description Boolean indicating if the text of the menu item will be 
7987         * rendered with strong emphasis.
7988         * @deprecated Use the "text" configuration property to add strong emphasis.  
7989         * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62; 
7990         * Some Text&#60;/strong&#62;");</code>
7991         * @default false
7992         * @type Boolean
7993         */
7994         oConfig.addProperty(
7995             STRONG_EMPHASIS_CONFIG.key,
7996             {
7997                 handler: this.configStrongEmphasis,
7998                 value: STRONG_EMPHASIS_CONFIG.value,
7999                 validator: STRONG_EMPHASIS_CONFIG.validator,
8000                 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8001                 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8002             }
8003         );
8006         /**
8007         * @config checked
8008         * @description Boolean indicating if the menu item should be rendered 
8009         * with a checkmark.
8010         * @default false
8011         * @type Boolean
8012         */
8013         oConfig.addProperty(
8014             CHECKED_CONFIG.key, 
8015             {
8016                 handler: this.configChecked, 
8017                 value: CHECKED_CONFIG.value, 
8018                 validator: CHECKED_CONFIG.validator, 
8019                 suppressEvent: CHECKED_CONFIG.suppressEvent,
8020                 supercedes: CHECKED_CONFIG.supercedes
8021             } 
8022         );
8025         /**
8026         * @config disabled
8027         * @description Boolean indicating if the menu item should be disabled.  
8028         * (Disabled menu items are  dimmed and will not respond to user input 
8029         * or fire events.)
8030         * @default false
8031         * @type Boolean
8032         */
8033         oConfig.addProperty(
8034             DISABLED_CONFIG.key,
8035             {
8036                 handler: this.configDisabled,
8037                 value: DISABLED_CONFIG.value,
8038                 validator: DISABLED_CONFIG.validator,
8039                 suppressEvent: DISABLED_CONFIG.suppressEvent
8040             }
8041         );
8044         /**
8045         * @config selected
8046         * @description Boolean indicating if the menu item should 
8047         * be highlighted.
8048         * @default false
8049         * @type Boolean
8050         */
8051         oConfig.addProperty(
8052             SELECTED_CONFIG.key,
8053             {
8054                 handler: this.configSelected,
8055                 value: SELECTED_CONFIG.value,
8056                 validator: SELECTED_CONFIG.validator,
8057                 suppressEvent: SELECTED_CONFIG.suppressEvent
8058             }
8059         );
8062         /**
8063         * @config submenu
8064         * @description Object specifying the submenu to be appended to the 
8065         * menu item.  The value can be one of the following: <ul><li>Object 
8066         * specifying a Menu instance.</li><li>Object literal specifying the
8067         * menu to be created.  Format: <code>{ id: [menu id], itemdata: 
8068         * [<a href="YAHOO.widget.Menu.html#itemData">array of values for 
8069         * items</a>] }</code>.</li><li>String specifying the id attribute 
8070         * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
8071         * Object specifying the <code>&#60;div&#62;</code> element of the 
8072         * menu.</li></ul>
8073         * @default null
8074         * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8075         * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8076         * HTMLElement</a>
8077         */
8078         oConfig.addProperty(
8079             SUBMENU_CONFIG.key, 
8080             {
8081                 handler: this.configSubmenu, 
8082                 supercedes: SUBMENU_CONFIG.supercedes,
8083                 suppressEvent: SUBMENU_CONFIG.suppressEvent
8084             }
8085         );
8088         /**
8089         * @config onclick
8090         * @description Object literal representing the code to be executed when 
8091         * the item is clicked.  Format:<br> <code> {<br> 
8092         * <strong>fn:</strong> Function,   &#47;&#47; The handler to call when 
8093         * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An 
8094         * object to  pass back to the handler.<br> <strong>scope:</strong> 
8095         * Object &#47;&#47; The object to use for the scope of the handler.
8096         * <br> } </code>
8097         * @type Object
8098         * @default null
8099         */
8100         oConfig.addProperty(
8101             ONCLICK_CONFIG.key, 
8102             {
8103                 handler: this.configOnClick, 
8104                 suppressEvent: ONCLICK_CONFIG.suppressEvent 
8105             }
8106         );
8109         /**
8110         * @config classname
8111         * @description CSS class to be applied to the menu item's root 
8112         * <code>&#60;li&#62;</code> element.  The specified class(es) are 
8113         * appended in addition to the default class as specified by the menu 
8114         * item's CSS_CLASS_NAME constant.
8115         * @default null
8116         * @type String
8117         */
8118         oConfig.addProperty(
8119             CLASS_NAME_CONFIG.key, 
8120             { 
8121                 handler: this.configClassName,
8122                 value: CLASS_NAME_CONFIG.value, 
8123                 validator: CLASS_NAME_CONFIG.validator,
8124                 suppressEvent: CLASS_NAME_CONFIG.suppressEvent 
8125             }
8126         );
8128         },
8131     /**
8132     * @method getNextEnabledSibling
8133     * @description Finds the menu item's next enabled sibling.
8134     * @return YAHOO.widget.MenuItem
8135     */
8136     getNextEnabledSibling: function () {
8138         var nGroupIndex,
8139             aItemGroups,
8140             oNextItem,
8141             nNextGroupIndex,
8142             aNextGroup,
8143             returnVal;
8145         function getNextArrayItem(p_aArray, p_nStartIndex) {
8147             return p_aArray[p_nStartIndex] || getNextArrayItem(p_aArray, (p_nStartIndex+1));
8149         }
8151         if (this.parent instanceof Menu) {
8153             nGroupIndex = this.groupIndex;
8154     
8155             aItemGroups = this.parent.getItemGroups();
8156     
8157             if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
8158     
8159                 oNextItem = getNextArrayItem(aItemGroups[nGroupIndex], 
8160                         (this.index+1));
8161     
8162             }
8163             else {
8164     
8165                 if (nGroupIndex < (aItemGroups.length - 1)) {
8166     
8167                     nNextGroupIndex = nGroupIndex + 1;
8168     
8169                 }
8170                 else {
8171     
8172                     nNextGroupIndex = 0;
8173     
8174                 }
8175     
8176                 aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
8177     
8178                 // Retrieve the first menu item in the next group
8179     
8180                 oNextItem = getNextArrayItem(aNextGroup, 0);
8181     
8182             }
8183     
8184             returnVal = (oNextItem.cfg.getProperty(_DISABLED) || 
8185                 oNextItem.element.style.display == _NONE) ? 
8186                 oNextItem.getNextEnabledSibling() : oNextItem;
8188         }
8189         
8190         return returnVal;
8192     },
8195     /**
8196     * @method getPreviousEnabledSibling
8197     * @description Finds the menu item's previous enabled sibling.
8198     * @return {YAHOO.widget.MenuItem}
8199     */
8200     getPreviousEnabledSibling: function () {
8202         var nGroupIndex,
8203             aItemGroups,
8204             oPreviousItem,
8205             nPreviousGroupIndex,
8206             aPreviousGroup,
8207             returnVal;
8209         function getPreviousArrayItem(p_aArray, p_nStartIndex) {
8211             return p_aArray[p_nStartIndex] || getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
8213         }
8215         function getFirstItemIndex(p_aArray, p_nStartIndex) {
8217             return p_aArray[p_nStartIndex] ? p_nStartIndex : 
8218                 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
8220         }
8222        if (this.parent instanceof Menu) {
8224             nGroupIndex = this.groupIndex;
8225             aItemGroups = this.parent.getItemGroups();
8227     
8228             if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
8229     
8230                 oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex], 
8231                         (this.index-1));
8232     
8233             }
8234             else {
8235     
8236                 if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
8237     
8238                     nPreviousGroupIndex = nGroupIndex - 1;
8239     
8240                 }
8241                 else {
8242     
8243                     nPreviousGroupIndex = aItemGroups.length - 1;
8244     
8245                 }
8246     
8247                 aPreviousGroup = getPreviousArrayItem(aItemGroups, 
8248                     nPreviousGroupIndex);
8249     
8250                 oPreviousItem = getPreviousArrayItem(aPreviousGroup, 
8251                         (aPreviousGroup.length - 1));
8252     
8253             }
8255             returnVal = (oPreviousItem.cfg.getProperty(_DISABLED) || 
8256                 oPreviousItem.element.style.display == _NONE) ? 
8257                 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
8259         }
8260         
8261         return returnVal;
8263     },
8266     /**
8267     * @method focus
8268     * @description Causes the menu item to receive the focus and fires the 
8269     * focus event.
8270     */
8271     focus: function () {
8273         var oParent = this.parent,
8274             oAnchor = this._oAnchor,
8275             oActiveItem = oParent.activeItem;
8278         function setFocus() {
8280             try {
8282                 if (!(UA.ie && !document.hasFocus())) {
8283                 
8284                                         if (oActiveItem) {
8285                 
8286                                                 oActiveItem.blurEvent.fire();
8287                 
8288                                         }
8289         
8290                                         oAnchor.focus();
8291                                         
8292                                         this.focusEvent.fire();
8293                 
8294                 }
8296             }
8297             catch(e) {
8298             
8299             }
8301         }
8304         if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) && 
8305             this.element.style.display != _NONE) {
8308             /*
8309                 Setting focus via a timer fixes a race condition in Firefox, IE 
8310                 and Opera where the browser viewport jumps as it trys to 
8311                 position and focus the menu.
8312             */
8314             Lang.later(0, this, setFocus);
8316         }
8318     },
8321     /**
8322     * @method blur
8323     * @description Causes the menu item to lose focus and fires the 
8324     * blur event.
8325     */    
8326     blur: function () {
8328         var oParent = this.parent;
8330         if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8332             Lang.later(0, this, function () {
8334                 try {
8335     
8336                     this._oAnchor.blur();
8337                     this.blurEvent.fire();    
8339                 } 
8340                 catch (e) {
8341                 
8342                 }
8343                 
8344             }, 0);
8346         }
8348     },
8351     /**
8352     * @method hasFocus
8353     * @description Returns a boolean indicating whether or not the menu item
8354     * has focus.
8355     * @return {Boolean}
8356     */
8357     hasFocus: function () {
8358     
8359         return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8360     
8361     },
8364         /**
8365     * @method destroy
8366         * @description Removes the menu item's <code>&#60;li&#62;</code> element 
8367         * from its parent <code>&#60;ul&#62;</code> element.
8368         */
8369     destroy: function () {
8371         var oEl = this.element,
8372             oSubmenu,
8373             oParentNode,
8374             aEventData,
8375             i;
8378         if (oEl) {
8381             // If the item has a submenu, destroy it first
8383             oSubmenu = this.cfg.getProperty(_SUBMENU);
8385             if (oSubmenu) {
8386             
8387                 oSubmenu.destroy();
8388             
8389             }
8392             // Remove the element from the parent node
8394             oParentNode = oEl.parentNode;
8396             if (oParentNode) {
8398                 oParentNode.removeChild(oEl);
8400                 this.destroyEvent.fire();
8402             }
8405             // Remove CustomEvent listeners
8407                         i = EVENT_TYPES.length - 1;
8409                         do {
8411                                 aEventData = EVENT_TYPES[i];
8412                                 
8413                                 this[aEventData[0]].unsubscribeAll();
8415                         }
8416                         while (i--);
8417             
8418             
8419             this.cfg.configChangedEvent.unsubscribeAll();
8421         }
8423     },
8426     /**
8427     * @method toString
8428     * @description Returns a string representing the menu item.
8429     * @return {String}
8430     */
8431     toString: function () {
8433         var sReturnVal = _MENUITEM,
8434             sId = this.id;
8436         if (sId) {
8437     
8438             sReturnVal += (_SPACE + sId);
8439         
8440         }
8442         return sReturnVal;
8443     
8444     }
8448 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8450 })();
8451 (function () {
8453         var _XY = "xy",
8454                 _MOUSEDOWN = "mousedown",
8455                 _CONTEXTMENU = "ContextMenu",
8456                 _SPACE = " ";
8459 * Creates a list of options or commands which are made visible in response to 
8460 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8462 * @param {String} p_oElement String specifying the id attribute of the 
8463 * <code>&#60;div&#62;</code> element of the context menu.
8464 * @param {String} p_oElement String specifying the id attribute of the 
8465 * <code>&#60;select&#62;</code> element to be used as the data source for the 
8466 * context menu.
8467 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8468 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8469 * <code>&#60;div&#62;</code> element of the context menu.
8470 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8471 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8472 * the <code>&#60;select&#62;</code> element to be used as the data source for 
8473 * the context menu.
8474 * @param {Object} p_oConfig Optional. Object literal specifying the 
8475 * configuration for the context menu. See configuration class documentation 
8476 * for more details.
8477 * @class ContextMenu
8478 * @constructor
8479 * @extends YAHOO.widget.Menu
8480 * @namespace YAHOO.widget
8482 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8484     YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8489 var Event = YAHOO.util.Event,
8490         UA = YAHOO.env.ua,
8491     ContextMenu = YAHOO.widget.ContextMenu,
8495     /**
8496     * Constant representing the name of the ContextMenu's events
8497     * @property EVENT_TYPES
8498     * @private
8499     * @final
8500     * @type Object
8501     */
8502     EVENT_TYPES = {
8504         "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8505         "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8506         "CLICK": "click"
8508     },
8509     
8510     
8511     /**
8512     * Constant representing the ContextMenu's configuration properties
8513     * @property DEFAULT_CONFIG
8514     * @private
8515     * @final
8516     * @type Object
8517     */
8518     TRIGGER_CONFIG = { 
8519                 key: "trigger",
8520                 suppressEvent: true
8521     };
8525 * @method position
8526 * @description "beforeShow" event handler used to position the contextmenu.
8527 * @private
8528 * @param {String} p_sType String representing the name of the event that 
8529 * was fired.
8530 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8531 * @param {Array} p_aPos Array representing the xy position for the context menu.
8533 function position(p_sType, p_aArgs, p_aPos) {
8535     this.cfg.setProperty(_XY, p_aPos);
8536     
8537     this.beforeShowEvent.unsubscribe(position, p_aPos);
8542 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8546 // Private properties
8550 * @property _oTrigger
8551 * @description Object reference to the current value of the "trigger" 
8552 * configuration property.
8553 * @default null
8554 * @private
8555 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8556 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8558 _oTrigger: null,
8562 * @property _bCancelled
8563 * @description Boolean indicating if the display of the context menu should 
8564 * be cancelled.
8565 * @default false
8566 * @private
8567 * @type Boolean
8569 _bCancelled: false,
8573 // Public properties
8577 * @property contextEventTarget
8578 * @description Object reference for the HTML element that was the target of the
8579 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of 
8580 * the context menu.
8581 * @default null
8582 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8583 * html.html#ID-58190037">HTMLElement</a>
8585 contextEventTarget: null,
8589 // Events
8593 * @event triggerContextMenuEvent
8594 * @description Custom Event wrapper for the "contextmenu" DOM event 
8595 * ("mousedown" for Opera) fired by the element(s) that trigger the display of 
8596 * the context menu.
8598 triggerContextMenuEvent: null,
8603 * @method init
8604 * @description The ContextMenu class's initialization method. This method is 
8605 * automatically called by the constructor, and sets up all DOM references for 
8606 * pre-existing markup, and creates required markup if it is not already present.
8607 * @param {String} p_oElement String specifying the id attribute of the 
8608 * <code>&#60;div&#62;</code> element of the context menu.
8609 * @param {String} p_oElement String specifying the id attribute of the 
8610 * <code>&#60;select&#62;</code> element to be used as the data source for 
8611 * the context menu.
8612 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8613 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8614 * <code>&#60;div&#62;</code> element of the context menu.
8615 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8616 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8617 * the <code>&#60;select&#62;</code> element to be used as the data source for 
8618 * the context menu.
8619 * @param {Object} p_oConfig Optional. Object literal specifying the 
8620 * configuration for the context menu. See configuration class documentation 
8621 * for more details.
8623 init: function(p_oElement, p_oConfig) {
8626     // Call the init of the superclass (YAHOO.widget.Menu)
8628     ContextMenu.superclass.init.call(this, p_oElement);
8631     this.beforeInitEvent.fire(ContextMenu);
8634     if (p_oConfig) {
8636         this.cfg.applyConfig(p_oConfig, true);
8638     }
8639     
8640     this.initEvent.fire(ContextMenu);
8641     
8646 * @method initEvents
8647 * @description Initializes the custom events for the context menu.
8649 initEvents: function() {
8651         ContextMenu.superclass.initEvents.call(this);
8653     // Create custom events
8655     this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8657     this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8663 * @method cancel
8664 * @description Cancels the display of the context menu.
8666 cancel: function() {
8668     this._bCancelled = true;
8674 // Private methods
8678 * @method _removeEventHandlers
8679 * @description Removes all of the DOM event handlers from the HTML element(s) 
8680 * whose "context menu" event ("click" for Opera) trigger the display of 
8681 * the context menu.
8682 * @private
8684 _removeEventHandlers: function() {
8686     var oTrigger = this._oTrigger;
8689     // Remove the event handlers from the trigger(s)
8691     if (oTrigger) {
8693         Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);    
8694         
8695         if (UA.opera) {
8696         
8697             Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8698     
8699         }
8701     }
8707 // Private event handlers
8712 * @method _onTriggerClick
8713 * @description "click" event handler for the HTML element(s) identified as the 
8714 * "trigger" for the context menu.  Used to cancel default behaviors in Opera.
8715 * @private
8716 * @param {Event} p_oEvent Object representing the DOM event object passed back 
8717 * by the event utility (YAHOO.util.Event).
8718 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8719 * menu that is handling the event.
8721 _onTriggerClick: function(p_oEvent, p_oMenu) {
8723     if (p_oEvent.ctrlKey) {
8724     
8725         Event.stopEvent(p_oEvent);
8727     }
8728     
8733 * @method _onTriggerContextMenu
8734 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML 
8735 * element(s) that trigger the display of the context menu.
8736 * @private
8737 * @param {Event} p_oEvent Object representing the DOM event object passed back 
8738 * by the event utility (YAHOO.util.Event).
8739 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8740 * menu that is handling the event.
8742 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8744     var aXY;
8746     if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8748                 /*
8749                         Prevent the browser's default context menu from appearing and 
8750                         stop the propagation of the "contextmenu" event so that 
8751                         other ContextMenu instances are not displayed.
8752                 */
8753         
8754                 Event.stopEvent(p_oEvent);
8755         
8756         
8757                 this.contextEventTarget = Event.getTarget(p_oEvent);
8758         
8759                 this.triggerContextMenuEvent.fire(p_oEvent);
8760         
8761         
8762                 // Hide any other Menu instances that might be visible
8763         
8764                 YAHOO.widget.MenuManager.hideVisible();
8765                 
8766         
8767         
8768                 if (!this._bCancelled) {
8769         
8770                         // Position and display the context menu
8771         
8772                         aXY = Event.getXY(p_oEvent);
8773         
8774         
8775                         if (!YAHOO.util.Dom.inDocument(this.element)) {
8776         
8777                                 this.beforeShowEvent.subscribe(position, aXY);
8778         
8779                         }
8780                         else {
8781         
8782                                 this.cfg.setProperty(_XY, aXY);
8783                         
8784                         }
8785         
8786         
8787                         this.show();
8788         
8789                 }
8790         
8791                 this._bCancelled = false;
8793     }
8799 // Public methods
8803 * @method toString
8804 * @description Returns a string representing the context menu.
8805 * @return {String}
8807 toString: function() {
8809     var sReturnVal = _CONTEXTMENU,
8810         sId = this.id;
8812     if (sId) {
8814         sReturnVal += (_SPACE + sId);
8815     
8816     }
8818     return sReturnVal;
8824 * @method initDefaultConfig
8825 * @description Initializes the class's configurable properties which can be 
8826 * changed using the context menu's Config object ("cfg").
8828 initDefaultConfig: function() {
8830     ContextMenu.superclass.initDefaultConfig.call(this);
8832     /**
8833     * @config trigger
8834     * @description The HTML element(s) whose "contextmenu" event ("mousedown" 
8835     * for Opera) trigger the display of the context menu.  Can be a string 
8836     * representing the id attribute of the HTML element, an object reference 
8837     * for the HTML element, or an array of strings or HTML element references.
8838     * @default null
8839     * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8840     * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8841     */
8842     this.cfg.addProperty(TRIGGER_CONFIG.key, 
8843         {
8844             handler: this.configTrigger, 
8845             suppressEvent: TRIGGER_CONFIG.suppressEvent 
8846         }
8847     );
8853 * @method destroy
8854 * @description Removes the context menu's <code>&#60;div&#62;</code> element 
8855 * (and accompanying child nodes) from the document.
8857 destroy: function() {
8859     // Remove the DOM event handlers from the current trigger(s)
8861     this._removeEventHandlers();
8864     // Continue with the superclass implementation of this method
8866     ContextMenu.superclass.destroy.call(this);
8872 // Public event handlers for configuration properties
8876 * @method configTrigger
8877 * @description Event handler for when the value of the "trigger" configuration 
8878 * property changes. 
8879 * @param {String} p_sType String representing the name of the event that 
8880 * was fired.
8881 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8882 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8883 * menu that fired the event.
8885 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
8886     
8887     var oTrigger = p_aArgs[0];
8889     if (oTrigger) {
8891         /*
8892             If there is a current "trigger" - remove the event handlers 
8893             from that element(s) before assigning new ones
8894         */
8896         if (this._oTrigger) {
8897         
8898             this._removeEventHandlers();
8900         }
8902         this._oTrigger = oTrigger;
8905         /*
8906             Listen for the "mousedown" event in Opera b/c it does not 
8907             support the "contextmenu" event
8908         */ 
8909   
8910         Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
8913         /*
8914             Assign a "click" event handler to the trigger element(s) for
8915             Opera to prevent default browser behaviors.
8916         */
8918         if (UA.opera) {
8919         
8920             Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
8922         }
8924     }
8925     else {
8926    
8927         this._removeEventHandlers();
8928     
8929     }
8930     
8933 }); // END YAHOO.lang.extend
8935 }());
8940 * Creates an item for a context menu.
8942 * @param {String} p_oObject String specifying the text of the context menu item.
8943 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8944 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
8945 * <code>&#60;li&#62;</code> element of the context menu item.
8946 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8947 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
8948 * specifying the <code>&#60;optgroup&#62;</code> element of the context 
8949 * menu item.
8950 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8951 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
8952 * the <code>&#60;option&#62;</code> element of the context menu item.
8953 * @param {Object} p_oConfig Optional. Object literal specifying the 
8954 * configuration for the context menu item. See configuration class 
8955 * documentation for more details.
8956 * @class ContextMenuItem
8957 * @constructor
8958 * @extends YAHOO.widget.MenuItem
8959 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
8960 * are of type YAHOO.widget.MenuItem.
8962 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
8963 (function () {
8965         var Lang = YAHOO.lang,
8967                 // String constants
8968         
8969                 _STATIC = "static",
8970                 _DYNAMIC_STATIC = "dynamic," + _STATIC,
8971                 _DISABLED = "disabled",
8972                 _SELECTED = "selected",
8973                 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
8974                 _SUBMENU = "submenu",
8975                 _VISIBLE = "visible",
8976                 _SPACE = " ",
8977                 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
8978                 _MENUBAR = "MenuBar";
8981 * Horizontal collection of items, each of which can contain a submenu.
8983 * @param {String} p_oElement String specifying the id attribute of the 
8984 * <code>&#60;div&#62;</code> element of the menu bar.
8985 * @param {String} p_oElement String specifying the id attribute of the 
8986 * <code>&#60;select&#62;</code> element to be used as the data source for the 
8987 * menu bar.
8988 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8989 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
8990 * the <code>&#60;div&#62;</code> element of the menu bar.
8991 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
8992 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
8993 * specifying the <code>&#60;select&#62;</code> element to be used as the data 
8994 * source for the menu bar.
8995 * @param {Object} p_oConfig Optional. Object literal specifying the 
8996 * configuration for the menu bar. See configuration class documentation for
8997 * more details.
8998 * @class MenuBar
8999 * @constructor
9000 * @extends YAHOO.widget.Menu
9001 * @namespace YAHOO.widget
9003 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9005     YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9011 * @method checkPosition
9012 * @description Checks to make sure that the value of the "position" property 
9013 * is one of the supported strings. Returns true if the position is supported.
9014 * @private
9015 * @param {Object} p_sPosition String specifying the position of the menu.
9016 * @return {Boolean}
9018 function checkPosition(p_sPosition) {
9020         var returnVal = false;
9022     if (Lang.isString(p_sPosition)) {
9024         returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9026     }
9027     
9028     return returnVal;
9033 var Event = YAHOO.util.Event,
9034     MenuBar = YAHOO.widget.MenuBar,
9036     POSITION_CONFIG =  { 
9037                 key: "position", 
9038                 value: _STATIC, 
9039                 validator: checkPosition, 
9040                 supercedes: [_VISIBLE] 
9041         }, 
9043         SUBMENU_ALIGNMENT_CONFIG =  { 
9044                 key: "submenualignment", 
9045                 value: ["tl","bl"]
9046         },
9048         AUTO_SUBMENU_DISPLAY_CONFIG =  { 
9049                 key: _AUTO_SUBMENU_DISPLAY, 
9050                 value: false, 
9051                 validator: Lang.isBoolean,
9052                 suppressEvent: true
9053         },
9054         
9055         SUBMENU_TOGGLE_REGION_CONFIG = {
9056                 key: _SUBMENU_TOGGLE_REGION, 
9057                 value: false, 
9058                 validator: Lang.isBoolean
9059         };
9063 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9066 * @method init
9067 * @description The MenuBar class's initialization method. This method is 
9068 * automatically called by the constructor, and sets up all DOM references for 
9069 * pre-existing markup, and creates required markup if it is not already present.
9070 * @param {String} p_oElement String specifying the id attribute of the 
9071 * <code>&#60;div&#62;</code> element of the menu bar.
9072 * @param {String} p_oElement String specifying the id attribute of the 
9073 * <code>&#60;select&#62;</code> element to be used as the data source for the 
9074 * menu bar.
9075 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9076 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
9077 * the <code>&#60;div&#62;</code> element of the menu bar.
9078 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9079 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
9080 * specifying the <code>&#60;select&#62;</code> element to be used as the data 
9081 * source for the menu bar.
9082 * @param {Object} p_oConfig Optional. Object literal specifying the 
9083 * configuration for the menu bar. See configuration class documentation for
9084 * more details.
9086 init: function(p_oElement, p_oConfig) {
9088     if(!this.ITEM_TYPE) {
9090         this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9092     }
9095     // Call the init of the superclass (YAHOO.widget.Menu)
9097     MenuBar.superclass.init.call(this, p_oElement);
9100     this.beforeInitEvent.fire(MenuBar);
9103     if(p_oConfig) {
9105         this.cfg.applyConfig(p_oConfig, true);
9107     }
9109     this.initEvent.fire(MenuBar);
9115 // Constants
9119 * @property CSS_CLASS_NAME
9120 * @description String representing the CSS class(es) to be applied to the menu 
9121 * bar's <code>&#60;div&#62;</code> element.
9122 * @default "yuimenubar"
9123 * @final
9124 * @type String
9126 CSS_CLASS_NAME: "yuimenubar",
9130 * @property SUBMENU_TOGGLE_REGION_WIDTH
9131 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9132 * display of the MenuBarItem's submenu.
9133 * @default 20
9134 * @final
9135 * @type Number
9137 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9140 // Protected event handlers
9144 * @method _onKeyDown
9145 * @description "keydown" Custom Event handler for the menu bar.
9146 * @private
9147 * @param {String} p_sType String representing the name of the event that 
9148 * was fired.
9149 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9150 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9151 * that fired the event.
9153 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9155     var oEvent = p_aArgs[0],
9156         oItem = p_aArgs[1],
9157         oSubmenu,
9158         oItemCfg,
9159         oNextItem;
9162     if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9164         oItemCfg = oItem.cfg;
9166         switch(oEvent.keyCode) {
9167     
9168             case 37:    // Left arrow
9169             case 39:    // Right arrow
9170     
9171                 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9172     
9173                     oItemCfg.setProperty(_SELECTED, true);
9174     
9175                 }
9176                 else {
9177     
9178                     oNextItem = (oEvent.keyCode == 37) ? 
9179                         oItem.getPreviousEnabledSibling() : 
9180                         oItem.getNextEnabledSibling();
9181             
9182                     if(oNextItem) {
9183     
9184                         this.clearActiveItem();
9185     
9186                         oNextItem.cfg.setProperty(_SELECTED, true);
9187                         
9188                                                 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9189                                                 
9190                                                 if(oSubmenu) {
9191                                         
9192                                                         oSubmenu.show();
9193                                                         oSubmenu.setInitialFocus();
9194                                                 
9195                                                 }
9196                                                 else {
9197                                                         oNextItem.focus();  
9198                                                 }
9199     
9200                     }
9201     
9202                 }
9203     
9204                 Event.preventDefault(oEvent);
9205     
9206             break;
9207     
9208             case 40:    // Down arrow
9209     
9210                 if(this.activeItem != oItem) {
9211     
9212                     this.clearActiveItem();
9213     
9214                     oItemCfg.setProperty(_SELECTED, true);
9215                     oItem.focus();
9216                 
9217                 }
9218     
9219                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9220     
9221                 if(oSubmenu) {
9222     
9223                     if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9224     
9225                         oSubmenu.setInitialSelection();
9226                         oSubmenu.setInitialFocus();
9227                     
9228                     }
9229                     else {
9230     
9231                         oSubmenu.show();
9232                         oSubmenu.setInitialFocus();
9233                     
9234                     }
9235     
9236                 }
9237     
9238                 Event.preventDefault(oEvent);
9239     
9240             break;
9241     
9242         }
9244     }
9247     if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9249         oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9251         if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9252         
9253             oSubmenu.hide();
9254             this.activeItem.focus();
9255         
9256         }
9257         else {
9259             this.activeItem.cfg.setProperty(_SELECTED, false);
9260             this.activeItem.blur();
9261     
9262         }
9264         Event.preventDefault(oEvent);
9265     
9266     }
9272 * @method _onClick
9273 * @description "click" event handler for the menu bar.
9274 * @protected
9275 * @param {String} p_sType String representing the name of the event that 
9276 * was fired.
9277 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9278 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9279 * that fired the event.
9281 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9283     MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9285     var oItem = p_aArgs[1],
9286         bReturnVal = true,
9287         oItemEl,
9288         oEvent,
9289         oTarget,
9290         oActiveItem,
9291         oConfig,
9292         oSubmenu,
9293         nMenuItemX,
9294         nToggleRegion;
9297         var toggleSubmenuDisplay = function () {
9299                 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9300                 
9301                         oSubmenu.hide();
9302                 
9303                 }
9304                 else {
9305                 
9306                         oSubmenu.show();                    
9307                 
9308                 }
9309         
9310         };
9311     
9313     if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9315         oEvent = p_aArgs[0];
9316         oTarget = Event.getTarget(oEvent);
9317         oActiveItem = this.activeItem;
9318         oConfig = this.cfg;
9321         // Hide any other submenus that might be visible
9322     
9323         if(oActiveItem && oActiveItem != oItem) {
9324     
9325             this.clearActiveItem();
9326     
9327         }
9329     
9330         oItem.cfg.setProperty(_SELECTED, true);
9331     
9333         // Show the submenu for the item
9334     
9335         oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9338         if(oSubmenu) {
9340                         oItemEl = oItem.element;
9341                         nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9342                         nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9344                         if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9346                                 if (Event.getPageX(oEvent) > nToggleRegion) {
9348                                         toggleSubmenuDisplay();
9350                                         Event.preventDefault(oEvent);
9352                                         /*
9353                                                  Return false so that other click event handlers are not called when the 
9354                                                  user clicks inside the toggle region.
9355                                         */
9356                                         bReturnVal = false;
9357                                 
9358                                 }
9359         
9360                 }
9361                         else {
9363                                 toggleSubmenuDisplay();
9364             
9365             }
9366         
9367         }
9368     
9369     }
9372         return bReturnVal;
9378 // Public methods
9381 * @method configSubmenuToggle
9382 * @description Event handler for when the "submenutoggleregion" configuration property of 
9383 * a MenuBar changes.
9384 * @param {String} p_sType The name of the event that was fired.
9385 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9387 configSubmenuToggle: function (p_sType, p_aArgs) {
9389         var bSubmenuToggle = p_aArgs[0];
9390         
9391         if (bSubmenuToggle) {
9392         
9393                 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9394         
9395         }
9401 * @method toString
9402 * @description Returns a string representing the menu bar.
9403 * @return {String}
9405 toString: function() {
9407     var sReturnVal = _MENUBAR,
9408         sId = this.id;
9410     if(sId) {
9412         sReturnVal += (_SPACE + sId);
9413     
9414     }
9416     return sReturnVal;
9422 * @description Initializes the class's configurable properties which can be
9423 * changed using the menu bar's Config object ("cfg").
9424 * @method initDefaultConfig
9426 initDefaultConfig: function() {
9428     MenuBar.superclass.initDefaultConfig.call(this);
9430     var oConfig = this.cfg;
9432         // Add configuration properties
9435     /*
9436         Set the default value for the "position" configuration property
9437         to "static" by re-adding the property.
9438     */
9441     /**
9442     * @config position
9443     * @description String indicating how a menu bar should be positioned on the 
9444     * screen.  Possible values are "static" and "dynamic."  Static menu bars 
9445     * are visible by default and reside in the normal flow of the document 
9446     * (CSS position: static).  Dynamic menu bars are hidden by default, reside
9447     * out of the normal flow of the document (CSS position: absolute), and can 
9448     * overlay other elements on the screen.
9449     * @default static
9450     * @type String
9451     */
9452     oConfig.addProperty(
9453         POSITION_CONFIG.key, 
9454         {
9455             handler: this.configPosition, 
9456             value: POSITION_CONFIG.value, 
9457             validator: POSITION_CONFIG.validator,
9458             supercedes: POSITION_CONFIG.supercedes
9459         }
9460     );
9463     /*
9464         Set the default value for the "submenualignment" configuration property
9465         to ["tl","bl"] by re-adding the property.
9466     */
9468     /**
9469     * @config submenualignment
9470     * @description Array defining how submenus should be aligned to their 
9471     * parent menu bar item. The format is: [itemCorner, submenuCorner].
9472     * @default ["tl","bl"]
9473     * @type Array
9474     */
9475     oConfig.addProperty(
9476         SUBMENU_ALIGNMENT_CONFIG.key, 
9477         {
9478             value: SUBMENU_ALIGNMENT_CONFIG.value,
9479             suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9480         }
9481     );
9484     /*
9485         Change the default value for the "autosubmenudisplay" configuration 
9486         property to "false" by re-adding the property.
9487     */
9489     /**
9490     * @config autosubmenudisplay
9491     * @description Boolean indicating if submenus are automatically made 
9492     * visible when the user mouses over the menu bar's items.
9493     * @default false
9494     * @type Boolean
9495     */
9496         oConfig.addProperty(
9497            AUTO_SUBMENU_DISPLAY_CONFIG.key, 
9498            {
9499                value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
9500                validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9501                suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9502        } 
9503     );
9506     /**
9507     * @config submenutoggleregion
9508     * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the 
9509     * display of a submenu.  The default width of the region is determined by the value of the
9510     * SUBMENU_TOGGLE_REGION_WIDTH property.  If set to true, the autosubmenudisplay 
9511     * configuration property will be set to false, and any click event listeners will not be 
9512     * called when the user clicks inside the submenu toggle region of a MenuBarItem.  If the 
9513     * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its 
9514     * standard behavior.
9515     * @default false
9516     * @type Boolean
9517     */
9518         oConfig.addProperty(
9519            SUBMENU_TOGGLE_REGION_CONFIG.key, 
9520            {
9521                value: SUBMENU_TOGGLE_REGION_CONFIG.value, 
9522                validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9523                handler: this.configSubmenuToggle
9524        } 
9525     );
9529 }); // END YAHOO.lang.extend
9531 }());
9536 * Creates an item for a menu bar.
9538 * @param {String} p_oObject String specifying the text of the menu bar item.
9539 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9540 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9541 * <code>&#60;li&#62;</code> element of the menu bar item.
9542 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9543 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9544 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9545 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9546 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9547 * the <code>&#60;option&#62;</code> element of the menu bar item.
9548 * @param {Object} p_oConfig Optional. Object literal specifying the 
9549 * configuration for the menu bar item. See configuration class documentation 
9550 * for more details.
9551 * @class MenuBarItem
9552 * @constructor
9553 * @extends YAHOO.widget.MenuItem
9555 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9557     YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9561 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9566 * @method init
9567 * @description The MenuBarItem class's initialization method. This method is 
9568 * automatically called by the constructor, and sets up all DOM references for 
9569 * pre-existing markup, and creates required markup if it is not already present.
9570 * @param {String} p_oObject String specifying the text of the menu bar item.
9571 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9572 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9573 * <code>&#60;li&#62;</code> element of the menu bar item.
9574 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9575 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9576 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9577 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9578 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9579 * the <code>&#60;option&#62;</code> element of the menu bar item.
9580 * @param {Object} p_oConfig Optional. Object literal specifying the 
9581 * configuration for the menu bar item. See configuration class documentation 
9582 * for more details.
9584 init: function(p_oObject, p_oConfig) {
9586     if(!this.SUBMENU_TYPE) {
9588         this.SUBMENU_TYPE = YAHOO.widget.Menu;
9590     }
9593     /* 
9594         Call the init of the superclass (YAHOO.widget.MenuItem)
9595         Note: We don't pass the user config in here yet 
9596         because we only want it executed once, at the lowest 
9597         subclass level.
9598     */ 
9600     YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);  
9603     var oConfig = this.cfg;
9605     if(p_oConfig) {
9607         oConfig.applyConfig(p_oConfig, true);
9609     }
9611     oConfig.fireQueue();
9617 // Constants
9621 * @property CSS_CLASS_NAME
9622 * @description String representing the CSS class(es) to be applied to the 
9623 * <code>&#60;li&#62;</code> element of the menu bar item.
9624 * @default "yuimenubaritem"
9625 * @final
9626 * @type String
9628 CSS_CLASS_NAME: "yuimenubaritem",
9632 * @property CSS_LABEL_CLASS_NAME
9633 * @description String representing the CSS class(es) to be applied to the 
9634 * menu bar item's <code>&#60;a&#62;</code> element.
9635 * @default "yuimenubaritemlabel"
9636 * @final
9637 * @type String
9639 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9643 // Public methods
9647 * @method toString
9648 * @description Returns a string representing the menu bar item.
9649 * @return {String}
9651 toString: function() {
9653     var sReturnVal = "MenuBarItem";
9655     if(this.cfg && this.cfg.getProperty("text")) {
9657         sReturnVal += (": " + this.cfg.getProperty("text"));
9659     }
9661     return sReturnVal;
9664     
9665 }); // END YAHOO.lang.extend
9666 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.6.0", build: "1321"});