OSDN Git Service

Update YUI 2.8.0r4 -> 2.8.1
[feedblog/feedgenerator.git] / yui / build / menu / menu-debug.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.8.1
6 */
7
8
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
28 */
29 (function () {
30
31     var UA = YAHOO.env.ua,
32                 Dom = YAHOO.util.Dom,
33             Event = YAHOO.util.Event,
34             Lang = YAHOO.lang,
35
36                 _DIV = "DIV",
37         _HD = "hd",
38         _BD = "bd",
39         _FT = "ft",
40         _LI = "LI",
41         _DISABLED = "disabled",
42                 _MOUSEOVER = "mouseover",
43                 _MOUSEOUT = "mouseout",
44                 _MOUSEDOWN = "mousedown",
45                 _MOUSEUP = "mouseup",
46                 _CLICK = "click",
47                 _KEYDOWN = "keydown",
48                 _KEYUP = "keyup",
49                 _KEYPRESS = "keypress",
50                 _CLICK_TO_HIDE = "clicktohide",
51                 _POSITION = "position", 
52                 _DYNAMIC = "dynamic",
53                 _SHOW_DELAY = "showdelay",
54                 _SELECTED = "selected",
55                 _VISIBLE = "visible",
56                 _UL = "UL",
57                 _MENUMANAGER = "MenuManager";
58
59
60     /**
61     * Singleton that manages a collection of all menus and menu items.  Listens 
62     * for DOM events at the document level and dispatches the events to the 
63     * corresponding menu or menu item.
64     *
65     * @namespace YAHOO.widget
66     * @class MenuManager
67     * @static
68     */
69     YAHOO.widget.MenuManager = function () {
70     
71         // Private member variables
72     
73     
74         // Flag indicating if the DOM event handlers have been attached
75     
76         var m_bInitializedEventHandlers = false,
77     
78     
79         // Collection of menus
80
81         m_oMenus = {},
82
83
84         // Collection of visible menus
85     
86         m_oVisibleMenus = {},
87     
88     
89         //  Collection of menu items 
90
91         m_oItems = {},
92
93
94         // Map of DOM event types to their equivalent CustomEvent types
95         
96         m_oEventTypes = {
97             "click": "clickEvent",
98             "mousedown": "mouseDownEvent",
99             "mouseup": "mouseUpEvent",
100             "mouseover": "mouseOverEvent",
101             "mouseout": "mouseOutEvent",
102             "keydown": "keyDownEvent",
103             "keyup": "keyUpEvent",
104             "keypress": "keyPressEvent",
105             "focus": "focusEvent",
106             "focusin": "focusEvent",
107             "blur": "blurEvent",
108             "focusout": "blurEvent"
109         },
110     
111     
112         m_oFocusedMenuItem = null;
113     
114     
115     
116         // Private methods
117     
118     
119         /**
120         * @method getMenuRootElement
121         * @description Finds the root DIV node of a menu or the root LI node of 
122         * a menu item.
123         * @private
124         * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
125         * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object 
126         * specifying an HTML element.
127         */
128         function getMenuRootElement(p_oElement) {
129         
130             var oParentNode,
131                 returnVal;
132     
133             if (p_oElement && p_oElement.tagName) {
134             
135                 switch (p_oElement.tagName.toUpperCase()) {
136                         
137                 case _DIV:
138     
139                     oParentNode = p_oElement.parentNode;
140     
141                     // Check if the DIV is the inner "body" node of a menu
142
143                     if ((
144                             Dom.hasClass(p_oElement, _HD) ||
145                             Dom.hasClass(p_oElement, _BD) ||
146                             Dom.hasClass(p_oElement, _FT)
147                         ) && 
148                         oParentNode && 
149                         oParentNode.tagName && 
150                         oParentNode.tagName.toUpperCase() == _DIV) {
151                     
152                         returnVal = oParentNode;
153                     
154                     }
155                     else {
156                     
157                         returnVal = p_oElement;
158                     
159                     }
160                 
161                     break;
162
163                 case _LI:
164     
165                     returnVal = p_oElement;
166                     
167                     break;
168
169                 default:
170     
171                     oParentNode = p_oElement.parentNode;
172     
173                     if (oParentNode) {
174                     
175                         returnVal = getMenuRootElement(oParentNode);
176                     
177                     }
178                 
179                     break;
180                 
181                 }
182     
183             }
184             
185             return returnVal;
186             
187         }
188     
189     
190     
191         // Private event handlers
192     
193     
194         /**
195         * @method onDOMEvent
196         * @description Generic, global event handler for all of a menu's 
197         * DOM-based events.  This listens for events against the document 
198         * object.  If the target of a given event is a member of a menu or 
199         * menu item's DOM, the instance's corresponding Custom Event is fired.
200         * @private
201         * @param {Event} p_oEvent Object representing the DOM event object  
202         * passed back by the event utility (YAHOO.util.Event).
203         */
204         function onDOMEvent(p_oEvent) {
205     
206             // Get the target node of the DOM event
207         
208             var oTarget = Event.getTarget(p_oEvent),
209                 
210             // See if the target of the event was a menu, or a menu item
211     
212             oElement = getMenuRootElement(oTarget),
213                         bFireEvent = true,
214                         sEventType = p_oEvent.type,
215             sCustomEventType,
216             sTagName,
217             sId,
218             oMenuItem,
219             oMenu; 
220     
221     
222             if (oElement) {
223     
224                 sTagName = oElement.tagName.toUpperCase();
225         
226                 if (sTagName == _LI) {
227             
228                     sId = oElement.id;
229             
230                     if (sId && m_oItems[sId]) {
231             
232                         oMenuItem = m_oItems[sId];
233                         oMenu = oMenuItem.parent;
234             
235                     }
236                 
237                 }
238                 else if (sTagName == _DIV) {
239                 
240                     if (oElement.id) {
241                     
242                         oMenu = m_oMenus[oElement.id];
243                     
244                     }
245                 
246                 }
247     
248             }
249     
250     
251             if (oMenu) {
252     
253                 sCustomEventType = m_oEventTypes[sEventType];
254
255                                 /*
256                                         There is an inconsistency between Firefox for Mac OS X and 
257                                         Firefox Windows & Linux regarding the triggering of the 
258                                         display of the browser's context menu and the subsequent 
259                                         firing of the "click" event. In Firefox for Windows & Linux, 
260                                         when the user triggers the display of the browser's context 
261                                         menu the "click" event also fires for the document object, 
262                                         even though the "click" event did not fire for the element 
263                                         that was the original target of the "contextmenu" event. 
264                                         This is unique to Firefox on Windows & Linux.  For all 
265                                         other A-Grade browsers, including Firefox for Mac OS X, the 
266                                         "click" event doesn't fire for the document object. 
267
268                                         This bug in Firefox for Windows affects Menu, as Menu 
269                                         instances listen for events at the document level and 
270                                         dispatches Custom Events of the same name.  Therefore users
271                                         of Menu will get an unwanted firing of the "click" 
272                                         custom event.  The following line fixes this bug.
273                                 */
274                                 
275
276
277                                 if (sEventType == "click" && 
278                                         (UA.gecko && oMenu.platform != "mac") && 
279                                         p_oEvent.button > 0) {
280
281                                         bFireEvent = false;
282
283                                 }
284     
285                 // Fire the Custom Event that corresponds the current DOM event    
286         
287                 if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
288                     oMenuItem[sCustomEventType].fire(p_oEvent);                   
289                 }
290         
291                                 if (bFireEvent) {
292                         oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
293                                 }
294             
295             }
296             else if (sEventType == _MOUSEDOWN) {
297     
298                 /*
299                     If the target of the event wasn't a menu, hide all 
300                     dynamically positioned menus
301                 */
302                 
303                 for (var i in m_oVisibleMenus) {
304         
305                     if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
306         
307                         oMenu = m_oVisibleMenus[i];
308
309                         if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) && 
310                             !(oMenu instanceof YAHOO.widget.MenuBar) && 
311                             oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
312
313                             oMenu.hide();
314
315                                                         //      In IE when the user mouses down on a focusable 
316                                                         //      element that element will be focused and become 
317                                                         //      the "activeElement".
318                                                         //      (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
319                                                         //      However, there is a bug in IE where if there is 
320                                                         //      a positioned element with a focused descendant 
321                                                         //      that is hidden in response to the mousedown 
322                                                         //      event, the target of the mousedown event will 
323                                                         //      appear to have focus, but will not be set as 
324                                                         //      the activeElement.  This will result in the 
325                                                         //      element not firing key events, even though it
326                                                         //      appears to have focus.  The following call to 
327                                                         //      "setActive" fixes this bug.
328
329                                                         if (UA.ie && oTarget.focus) {
330                                                                 oTarget.setActive();
331                                                         }
332         
333                         }
334                         else {
335                             
336                                                         if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
337                                                         
338                                                                 oMenu._cancelShowDelay();
339                                                         
340                                                         }
341
342
343                                                         if (oMenu.activeItem) {
344                                                 
345                                                                 oMenu.activeItem.blur();
346                                                                 oMenu.activeItem.cfg.setProperty(_SELECTED, false);
347                                                 
348                                                                 oMenu.activeItem = null;            
349                                                 
350                                                         }
351         
352                         }
353         
354                     }
355         
356                 } 
357     
358             }
359             
360         }
361     
362     
363         /**
364         * @method onMenuDestroy
365         * @description "destroy" event handler for a menu.
366         * @private
367         * @param {String} p_sType String representing the name of the event 
368         * that was fired.
369         * @param {Array} p_aArgs Array of arguments sent when the event 
370         * was fired.
371         * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
372         */
373         function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
374     
375             if (m_oMenus[p_oMenu.id]) {
376     
377                 this.removeMenu(p_oMenu);
378     
379             }
380     
381         }
382     
383     
384         /**
385         * @method onMenuFocus
386         * @description "focus" event handler for a MenuItem 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         */
393         function onMenuFocus(p_sType, p_aArgs) {
394     
395             var oItem = p_aArgs[1];
396     
397             if (oItem) {
398     
399                 m_oFocusedMenuItem = oItem;
400             
401             }
402     
403         }
404     
405     
406         /**
407         * @method onMenuBlur
408         * @description "blur" event handler for a MenuItem instance.
409         * @private
410         * @param {String} p_sType String representing the name of the event  
411         * that was fired.
412         * @param {Array} p_aArgs Array of arguments sent when the event 
413         * was fired.
414         */
415         function onMenuBlur(p_sType, p_aArgs) {
416     
417             m_oFocusedMenuItem = null;
418     
419         }
420
421     
422         /**
423         * @method onMenuVisibleConfigChange
424         * @description Event handler for when the "visible" configuration  
425         * property of a Menu instance changes.
426         * @private
427         * @param {String} p_sType String representing the name of the event  
428         * that was fired.
429         * @param {Array} p_aArgs Array of arguments sent when the event 
430         * was fired.
431         */
432         function onMenuVisibleConfigChange(p_sType, p_aArgs) {
433     
434             var bVisible = p_aArgs[0],
435                 sId = this.id;
436             
437             if (bVisible) {
438     
439                 m_oVisibleMenus[sId] = this;
440                 
441                 YAHOO.log(this + " added to the collection of visible menus.", 
442                         "info", _MENUMANAGER);
443             
444             }
445             else if (m_oVisibleMenus[sId]) {
446             
447                 delete m_oVisibleMenus[sId];
448                 
449                 YAHOO.log(this + " removed from the collection of visible menus.", 
450                         "info", _MENUMANAGER);
451             
452             }
453         
454         }
455     
456     
457         /**
458         * @method onItemDestroy
459         * @description "destroy" event handler for a MenuItem instance.
460         * @private
461         * @param {String} p_sType String representing the name of the event  
462         * that was fired.
463         * @param {Array} p_aArgs Array of arguments sent when the event 
464         * was fired.
465         */
466         function onItemDestroy(p_sType, p_aArgs) {
467     
468             removeItem(this);
469     
470         }
471
472
473         /**
474         * @method removeItem
475         * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
476         * @private
477         * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
478         */    
479         function removeItem(p_oMenuItem) {
480
481             var sId = p_oMenuItem.id;
482     
483             if (sId && m_oItems[sId]) {
484     
485                 if (m_oFocusedMenuItem == p_oMenuItem) {
486     
487                     m_oFocusedMenuItem = null;
488     
489                 }
490     
491                 delete m_oItems[sId];
492                 
493                 p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
494     
495                 YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
496     
497             }
498
499         }
500     
501     
502         /**
503         * @method onItemAdded
504         * @description "itemadded" event handler for a Menu instance.
505         * @private
506         * @param {String} p_sType String representing the name of the event  
507         * that was fired.
508         * @param {Array} p_aArgs Array of arguments sent when the event 
509         * was fired.
510         */
511         function onItemAdded(p_sType, p_aArgs) {
512     
513             var oItem = p_aArgs[0],
514                 sId;
515     
516             if (oItem instanceof YAHOO.widget.MenuItem) { 
517     
518                 sId = oItem.id;
519         
520                 if (!m_oItems[sId]) {
521             
522                     m_oItems[sId] = oItem;
523         
524                     oItem.destroyEvent.subscribe(onItemDestroy);
525         
526                     YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
527         
528                 }
529     
530             }
531         
532         }
533     
534     
535         return {
536     
537             // Privileged methods
538     
539     
540             /**
541             * @method addMenu
542             * @description Adds a menu to the collection of known menus.
543             * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
544             * instance to be added.
545             */
546             addMenu: function (p_oMenu) {
547     
548                 var oDoc;
549     
550                 if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id && 
551                     !m_oMenus[p_oMenu.id]) {
552         
553                     m_oMenus[p_oMenu.id] = p_oMenu;
554                 
555             
556                     if (!m_bInitializedEventHandlers) {
557             
558                         oDoc = document;
559                 
560                         Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
561                         Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
562                         Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
563                         Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
564                         Event.on(oDoc, _CLICK, onDOMEvent, this, true);
565                         Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
566                         Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
567                         Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
568     
569                                                 Event.onFocus(oDoc, onDOMEvent, this, true);
570                                                 Event.onBlur(oDoc, onDOMEvent, this, true);                                             
571     
572                         m_bInitializedEventHandlers = true;
573                         
574                         YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
575             
576                     }
577             
578                     p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
579                     p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
580                     p_oMenu.itemAddedEvent.subscribe(onItemAdded);
581                     p_oMenu.focusEvent.subscribe(onMenuFocus);
582                     p_oMenu.blurEvent.subscribe(onMenuBlur);
583         
584                     YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
585         
586                 }
587         
588             },
589     
590         
591             /**
592             * @method removeMenu
593             * @description Removes a menu from the collection of known menus.
594             * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
595             * instance to be removed.
596             */
597             removeMenu: function (p_oMenu) {
598     
599                 var sId,
600                     aItems,
601                     i;
602         
603                 if (p_oMenu) {
604     
605                     sId = p_oMenu.id;
606         
607                     if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
608
609                         // Unregister each menu item
610
611                         aItems = p_oMenu.getItems();
612
613                         if (aItems && aItems.length > 0) {
614
615                             i = aItems.length - 1;
616
617                             do {
618
619                                 removeItem(aItems[i]);
620
621                             }
622                             while (i--);
623
624                         }
625
626
627                         // Unregister the menu
628
629                         delete m_oMenus[sId];
630             
631                         YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
632         
633
634                         /*
635                              Unregister the menu from the collection of 
636                              visible menus
637                         */
638
639                         if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
640             
641                             delete m_oVisibleMenus[sId];
642                             
643                             YAHOO.log(p_oMenu + " unregistered from the" + 
644                                         " collection of visible menus.", "info", _MENUMANAGER);
645        
646                         }
647
648
649                         // Unsubscribe event listeners
650
651                         if (p_oMenu.cfg) {
652
653                             p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE, 
654                                 onMenuVisibleConfigChange);
655                             
656                         }
657
658                         p_oMenu.destroyEvent.unsubscribe(onMenuDestroy, 
659                             p_oMenu);
660                 
661                         p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
662                         p_oMenu.focusEvent.unsubscribe(onMenuFocus);
663                         p_oMenu.blurEvent.unsubscribe(onMenuBlur);
664
665                     }
666                 
667                 }
668     
669             },
670         
671         
672             /**
673             * @method hideVisible
674             * @description Hides all visible, dynamically positioned menus 
675             * (excluding instances of YAHOO.widget.MenuBar).
676             */
677             hideVisible: function () {
678         
679                 var oMenu;
680         
681                 for (var i in m_oVisibleMenus) {
682         
683                     if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
684         
685                         oMenu = m_oVisibleMenus[i];
686         
687                         if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
688                             oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
689         
690                             oMenu.hide();
691         
692                         }
693         
694                     }
695         
696                 }        
697     
698             },
699
700
701             /**
702             * @method getVisible
703             * @description Returns a collection of all visible menus registered
704             * with the menu manger.
705             * @return {Object}
706             */
707             getVisible: function () {
708             
709                 return m_oVisibleMenus;
710             
711             },
712
713     
714             /**
715             * @method getMenus
716             * @description Returns a collection of all menus registered with the 
717             * menu manger.
718             * @return {Object}
719             */
720             getMenus: function () {
721     
722                 return m_oMenus;
723             
724             },
725     
726     
727             /**
728             * @method getMenu
729             * @description Returns a menu with the specified id.
730             * @param {String} p_sId String specifying the id of the 
731             * <code>&#60;div&#62;</code> element representing the menu to
732             * be retrieved.
733             * @return {YAHOO.widget.Menu}
734             */
735             getMenu: function (p_sId) {
736                 
737                 var returnVal;
738                 
739                 if (p_sId in m_oMenus) {
740                 
741                                         returnVal = m_oMenus[p_sId];
742                                 
743                                 }
744             
745                 return returnVal;
746             
747             },
748     
749     
750             /**
751             * @method getMenuItem
752             * @description Returns a menu item with the specified id.
753             * @param {String} p_sId String specifying the id of the 
754             * <code>&#60;li&#62;</code> element representing the menu item to
755             * be retrieved.
756             * @return {YAHOO.widget.MenuItem}
757             */
758             getMenuItem: function (p_sId) {
759     
760                         var returnVal;
761     
762                         if (p_sId in m_oItems) {
763     
764                                         returnVal = m_oItems[p_sId];
765                                 
766                                 }
767                                 
768                                 return returnVal;
769             
770             },
771
772
773             /**
774             * @method getMenuItemGroup
775             * @description Returns an array of menu item instances whose 
776             * corresponding <code>&#60;li&#62;</code> elements are child 
777             * nodes of the <code>&#60;ul&#62;</code> element with the 
778             * specified id.
779             * @param {String} p_sId String specifying the id of the 
780             * <code>&#60;ul&#62;</code> element representing the group of 
781             * menu items to be retrieved.
782             * @return {Array}
783             */
784             getMenuItemGroup: function (p_sId) {
785
786                 var oUL = Dom.get(p_sId),
787                     aItems,
788                     oNode,
789                     oItem,
790                     sId,
791                     returnVal;
792     
793
794                 if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
795
796                     oNode = oUL.firstChild;
797
798                     if (oNode) {
799
800                         aItems = [];
801                         
802                         do {
803
804                             sId = oNode.id;
805
806                             if (sId) {
807                             
808                                 oItem = this.getMenuItem(sId);
809                                 
810                                 if (oItem) {
811                                 
812                                     aItems[aItems.length] = oItem;
813                                 
814                                 }
815                             
816                             }
817                         
818                         }
819                         while ((oNode = oNode.nextSibling));
820
821
822                         if (aItems.length > 0) {
823
824                             returnVal = aItems;
825                         
826                         }
827
828                     }
829                 
830                 }
831
832                                 return returnVal;
833             
834             },
835
836     
837             /**
838             * @method getFocusedMenuItem
839             * @description Returns a reference to the menu item that currently 
840             * has focus.
841             * @return {YAHOO.widget.MenuItem}
842             */
843             getFocusedMenuItem: function () {
844     
845                 return m_oFocusedMenuItem;
846     
847             },
848     
849     
850             /**
851             * @method getFocusedMenu
852             * @description Returns a reference to the menu that currently 
853             * has focus.
854             * @return {YAHOO.widget.Menu}
855             */
856             getFocusedMenu: function () {
857
858                                 var returnVal;
859     
860                 if (m_oFocusedMenuItem) {
861     
862                     returnVal = m_oFocusedMenuItem.parent.getRoot();
863                 
864                 }
865     
866                         return returnVal;
867     
868             },
869     
870         
871             /**
872             * @method toString
873             * @description Returns a string representing the menu manager.
874             * @return {String}
875             */
876             toString: function () {
877             
878                 return _MENUMANAGER;
879             
880             }
881     
882         };
883     
884     }();
885
886 })();
887
888
889
890 (function () {
891
892         var Lang = YAHOO.lang,
893
894         // String constants
895         
896                 _MENU = "Menu",
897                 _DIV_UPPERCASE = "DIV",
898                 _DIV_LOWERCASE = "div",
899                 _ID = "id",
900                 _SELECT = "SELECT",
901                 _XY = "xy",
902                 _Y = "y",
903                 _UL_UPPERCASE = "UL",
904                 _UL_LOWERCASE = "ul",
905                 _FIRST_OF_TYPE = "first-of-type",
906                 _LI = "LI",
907                 _OPTGROUP = "OPTGROUP",
908                 _OPTION = "OPTION",
909                 _DISABLED = "disabled",
910                 _NONE = "none",
911                 _SELECTED = "selected",
912                 _GROUP_INDEX = "groupindex",
913                 _INDEX = "index",
914                 _SUBMENU = "submenu",
915                 _VISIBLE = "visible",
916                 _HIDE_DELAY = "hidedelay",
917                 _POSITION = "position",
918                 _DYNAMIC = "dynamic",
919                 _STATIC = "static",
920                 _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
921                 _URL = "url",
922                 _HASH = "#",
923                 _TARGET = "target",
924                 _MAX_HEIGHT = "maxheight",
925         _TOP_SCROLLBAR = "topscrollbar",
926         _BOTTOM_SCROLLBAR = "bottomscrollbar",
927         _UNDERSCORE = "_",
928                 _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
929                 _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
930                 _MOUSEMOVE = "mousemove",
931                 _SHOW_DELAY = "showdelay",
932                 _SUBMENU_HIDE_DELAY = "submenuhidedelay",
933                 _IFRAME = "iframe",
934                 _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
935                 _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
936                 _SUBMENU_ALIGNMENT = "submenualignment",
937                 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
938                 _CLICK_TO_HIDE = "clicktohide",
939                 _CONTAINER = "container",
940                 _SCROLL_INCREMENT = "scrollincrement",
941                 _MIN_SCROLL_HEIGHT = "minscrollheight",
942                 _CLASSNAME = "classname",
943                 _SHADOW = "shadow",
944                 _KEEP_OPEN = "keepopen",
945                 _HD = "hd",
946                 _HAS_TITLE = "hastitle",
947                 _CONTEXT = "context",
948                 _EMPTY_STRING = "",
949                 _MOUSEDOWN = "mousedown",
950                 _KEYDOWN = "keydown",
951                 _HEIGHT = "height",
952                 _WIDTH = "width",
953                 _PX = "px",
954                 _EFFECT = "effect",
955                 _MONITOR_RESIZE = "monitorresize",
956                 _DISPLAY = "display",
957                 _BLOCK = "block",
958                 _VISIBILITY = "visibility",
959                 _ABSOLUTE = "absolute",
960                 _ZINDEX = "zindex",
961                 _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
962                 _NON_BREAKING_SPACE = "&#32;",
963                 _SPACE = " ",
964                 _MOUSEOVER = "mouseover",
965                 _MOUSEOUT = "mouseout",
966         _ITEM_ADDED = "itemAdded",
967         _ITEM_REMOVED = "itemRemoved",
968         _HIDDEN = "hidden",
969         _YUI_MENU_SHADOW = "yui-menu-shadow",
970         _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
971         _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
972
973
974 /**
975 * The Menu class creates a container that holds a vertical list representing 
976 * a set of options or commands.  Menu is the base class for all 
977 * menu containers. 
978 * @param {String} p_oElement String specifying the id attribute of the 
979 * <code>&#60;div&#62;</code> element of the menu.
980 * @param {String} p_oElement String specifying the id attribute of the 
981 * <code>&#60;select&#62;</code> element to be used as the data source 
982 * for the menu.
983 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
984 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
985 * specifying the <code>&#60;div&#62;</code> element of the menu.
986 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
987 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
988 * Object specifying the <code>&#60;select&#62;</code> element to be used as 
989 * the data source for the menu.
990 * @param {Object} p_oConfig Optional. Object literal specifying the 
991 * configuration for the menu. See configuration class documentation for 
992 * more details.
993 * @namespace YAHOO.widget
994 * @class Menu
995 * @constructor
996 * @extends YAHOO.widget.Overlay
997 */
998 YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
999
1000     if (p_oConfig) {
1001
1002         this.parent = p_oConfig.parent;
1003         this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
1004         this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
1005
1006     }
1007
1008
1009     YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1010
1011 };
1012
1013
1014
1015 /**
1016 * @method checkPosition
1017 * @description Checks to make sure that the value of the "position" property 
1018 * is one of the supported strings. Returns true if the position is supported.
1019 * @private
1020 * @param {Object} p_sPosition String specifying the position of the menu.
1021 * @return {Boolean}
1022 */
1023 function checkPosition(p_sPosition) {
1024
1025         var returnVal = false;
1026
1027     if (Lang.isString(p_sPosition)) {
1028
1029         returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1030
1031     }
1032
1033         return returnVal;
1034
1035 }
1036
1037
1038 var Dom = YAHOO.util.Dom,
1039     Event = YAHOO.util.Event,
1040     Module = YAHOO.widget.Module,
1041     Overlay = YAHOO.widget.Overlay,
1042     Menu = YAHOO.widget.Menu,
1043     MenuManager = YAHOO.widget.MenuManager,
1044     CustomEvent = YAHOO.util.CustomEvent,
1045     UA = YAHOO.env.ua,
1046     
1047     m_oShadowTemplate,
1048
1049         bFocusListenerInitialized = false,
1050
1051         oFocusedElement,
1052
1053         EVENT_TYPES = [
1054     
1055                 ["mouseOverEvent", _MOUSEOVER],
1056                 ["mouseOutEvent", _MOUSEOUT],
1057                 ["mouseDownEvent", _MOUSEDOWN],
1058                 ["mouseUpEvent", "mouseup"],
1059                 ["clickEvent", "click"],
1060                 ["keyPressEvent", "keypress"],
1061                 ["keyDownEvent", _KEYDOWN],
1062                 ["keyUpEvent", "keyup"],
1063                 ["focusEvent", "focus"],
1064                 ["blurEvent", "blur"],
1065                 ["itemAddedEvent", _ITEM_ADDED],
1066                 ["itemRemovedEvent", _ITEM_REMOVED]
1067
1068         ],
1069
1070         VISIBLE_CONFIG =  { 
1071                 key: _VISIBLE, 
1072                 value: false, 
1073                 validator: Lang.isBoolean
1074         }, 
1075
1076         CONSTRAIN_TO_VIEWPORT_CONFIG =  {
1077                 key: _CONSTRAIN_TO_VIEWPORT, 
1078                 value: true, 
1079                 validator: Lang.isBoolean, 
1080                 supercedes: [_IFRAME,"x",_Y,_XY]
1081         }, 
1082
1083         PREVENT_CONTEXT_OVERLAP_CONFIG =  {
1084                 key: _PREVENT_CONTEXT_OVERLAP,
1085                 value: true,
1086                 validator: Lang.isBoolean,  
1087                 supercedes: [_CONSTRAIN_TO_VIEWPORT]
1088         },
1089
1090         POSITION_CONFIG =  { 
1091                 key: _POSITION, 
1092                 value: _DYNAMIC, 
1093                 validator: checkPosition, 
1094                 supercedes: [_VISIBLE, _IFRAME]
1095         }, 
1096
1097         SUBMENU_ALIGNMENT_CONFIG =  { 
1098                 key: _SUBMENU_ALIGNMENT, 
1099                 value: ["tl","tr"]
1100         },
1101
1102         AUTO_SUBMENU_DISPLAY_CONFIG =  { 
1103                 key: _AUTO_SUBMENU_DISPLAY, 
1104                 value: true, 
1105                 validator: Lang.isBoolean,
1106                 suppressEvent: true
1107         }, 
1108
1109         SHOW_DELAY_CONFIG =  { 
1110                 key: _SHOW_DELAY, 
1111                 value: 250, 
1112                 validator: Lang.isNumber, 
1113                 suppressEvent: true
1114         }, 
1115
1116         HIDE_DELAY_CONFIG =  { 
1117                 key: _HIDE_DELAY, 
1118                 value: 0, 
1119                 validator: Lang.isNumber, 
1120                 suppressEvent: true
1121         }, 
1122
1123         SUBMENU_HIDE_DELAY_CONFIG =  { 
1124                 key: _SUBMENU_HIDE_DELAY, 
1125                 value: 250, 
1126                 validator: Lang.isNumber,
1127                 suppressEvent: true
1128         }, 
1129
1130         CLICK_TO_HIDE_CONFIG =  { 
1131                 key: _CLICK_TO_HIDE, 
1132                 value: true, 
1133                 validator: Lang.isBoolean,
1134                 suppressEvent: true
1135         },
1136
1137         CONTAINER_CONFIG =  { 
1138                 key: _CONTAINER,
1139                 suppressEvent: true
1140         }, 
1141
1142         SCROLL_INCREMENT_CONFIG =  { 
1143                 key: _SCROLL_INCREMENT, 
1144                 value: 1, 
1145                 validator: Lang.isNumber,
1146                 supercedes: [_MAX_HEIGHT],
1147                 suppressEvent: true
1148         },
1149
1150         MIN_SCROLL_HEIGHT_CONFIG =  { 
1151                 key: _MIN_SCROLL_HEIGHT, 
1152                 value: 90, 
1153                 validator: Lang.isNumber,
1154                 supercedes: [_MAX_HEIGHT],
1155                 suppressEvent: true
1156         },    
1157
1158         MAX_HEIGHT_CONFIG =  { 
1159                 key: _MAX_HEIGHT, 
1160                 value: 0, 
1161                 validator: Lang.isNumber,
1162                 supercedes: [_IFRAME],
1163                 suppressEvent: true
1164         }, 
1165
1166         CLASS_NAME_CONFIG =  { 
1167                 key: _CLASSNAME, 
1168                 value: null, 
1169                 validator: Lang.isString,
1170                 suppressEvent: true
1171         }, 
1172
1173         DISABLED_CONFIG =  { 
1174                 key: _DISABLED, 
1175                 value: false, 
1176                 validator: Lang.isBoolean,
1177                 suppressEvent: true
1178         },
1179         
1180         SHADOW_CONFIG =  { 
1181                 key: _SHADOW, 
1182                 value: true, 
1183                 validator: Lang.isBoolean,
1184                 suppressEvent: true,
1185                 supercedes: [_VISIBLE]
1186         },
1187         
1188         KEEP_OPEN_CONFIG = {
1189                 key: _KEEP_OPEN, 
1190                 value: false, 
1191                 validator: Lang.isBoolean
1192         };
1193
1194
1195 function onDocFocus(event) {
1196
1197         oFocusedElement = Event.getTarget(event);
1198
1199 }
1200
1201
1202
1203 YAHOO.lang.extend(Menu, Overlay, {
1204
1205
1206 // Constants
1207
1208
1209 /**
1210 * @property CSS_CLASS_NAME
1211 * @description String representing the CSS class(es) to be applied to the 
1212 * menu's <code>&#60;div&#62;</code> element.
1213 * @default "yuimenu"
1214 * @final
1215 * @type String
1216 */
1217 CSS_CLASS_NAME: "yuimenu",
1218
1219
1220 /**
1221 * @property ITEM_TYPE
1222 * @description Object representing the type of menu item to instantiate and 
1223 * add when parsing the child nodes (either <code>&#60;li&#62;</code> element, 
1224 * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>) 
1225 * of the menu's source HTML element.
1226 * @default YAHOO.widget.MenuItem
1227 * @final
1228 * @type YAHOO.widget.MenuItem
1229 */
1230 ITEM_TYPE: null,
1231
1232
1233 /**
1234 * @property GROUP_TITLE_TAG_NAME
1235 * @description String representing the tagname of the HTML element used to 
1236 * title the menu's item groups.
1237 * @default H6
1238 * @final
1239 * @type String
1240 */
1241 GROUP_TITLE_TAG_NAME: "h6",
1242
1243
1244 /**
1245 * @property OFF_SCREEN_POSITION
1246 * @description Array representing the default x and y position that a menu 
1247 * should have when it is positioned outside the viewport by the 
1248 * "poistionOffScreen" method.
1249 * @default "-999em"
1250 * @final
1251 * @type String
1252 */
1253 OFF_SCREEN_POSITION: "-999em",
1254
1255
1256 // Private properties
1257
1258
1259 /** 
1260 * @property _useHideDelay
1261 * @description Boolean indicating if the "mouseover" and "mouseout" event 
1262 * handlers used for hiding the menu via a call to "YAHOO.lang.later" have 
1263 * already been assigned.
1264 * @default false
1265 * @private
1266 * @type Boolean
1267 */
1268 _useHideDelay: false,
1269
1270
1271 /**
1272 * @property _bHandledMouseOverEvent
1273 * @description Boolean indicating the current state of the menu's 
1274 * "mouseover" event.
1275 * @default false
1276 * @private
1277 * @type Boolean
1278 */
1279 _bHandledMouseOverEvent: false,
1280
1281
1282 /**
1283 * @property _bHandledMouseOutEvent
1284 * @description Boolean indicating the current state of the menu's
1285 * "mouseout" event.
1286 * @default false
1287 * @private
1288 * @type Boolean
1289 */
1290 _bHandledMouseOutEvent: false,
1291
1292
1293 /**
1294 * @property _aGroupTitleElements
1295 * @description Array of HTML element used to title groups of menu items.
1296 * @default []
1297 * @private
1298 * @type Array
1299 */
1300 _aGroupTitleElements: null,
1301
1302
1303 /**
1304 * @property _aItemGroups
1305 * @description Multi-dimensional Array representing the menu items as they
1306 * are grouped in the menu.
1307 * @default []
1308 * @private
1309 * @type Array
1310 */
1311 _aItemGroups: null,
1312
1313
1314 /**
1315 * @property _aListElements
1316 * @description Array of <code>&#60;ul&#62;</code> elements, each of which is 
1317 * the parent node for each item's <code>&#60;li&#62;</code> element.
1318 * @default []
1319 * @private
1320 * @type Array
1321 */
1322 _aListElements: null,
1323
1324
1325 /**
1326 * @property _nCurrentMouseX
1327 * @description The current x coordinate of the mouse inside the area of 
1328 * the menu.
1329 * @default 0
1330 * @private
1331 * @type Number
1332 */
1333 _nCurrentMouseX: 0,
1334
1335
1336 /**
1337 * @property _bStopMouseEventHandlers
1338 * @description Stops "mouseover," "mouseout," and "mousemove" event handlers 
1339 * from executing.
1340 * @default false
1341 * @private
1342 * @type Boolean
1343 */
1344 _bStopMouseEventHandlers: false,
1345
1346
1347 /**
1348 * @property _sClassName
1349 * @description The current value of the "classname" configuration attribute.
1350 * @default null
1351 * @private
1352 * @type String
1353 */
1354 _sClassName: null,
1355
1356
1357
1358 // Public properties
1359
1360
1361 /**
1362 * @property lazyLoad
1363 * @description Boolean indicating if the menu's "lazy load" feature is 
1364 * enabled.  If set to "true," initialization and rendering of the menu's 
1365 * items will be deferred until the first time it is made visible.  This 
1366 * property should be set via the constructor using the configuration 
1367 * object literal.
1368 * @default false
1369 * @type Boolean
1370 */
1371 lazyLoad: false,
1372
1373
1374 /**
1375 * @property itemData
1376 * @description Array of items to be added to the menu.  The array can contain 
1377 * strings representing the text for each item to be created, object literals 
1378 * representing the menu item configuration properties, or MenuItem instances.  
1379 * This property should be set via the constructor using the configuration 
1380 * object literal.
1381 * @default null
1382 * @type Array
1383 */
1384 itemData: null,
1385
1386
1387 /**
1388 * @property activeItem
1389 * @description Object reference to the item in the menu that has is selected.
1390 * @default null
1391 * @type YAHOO.widget.MenuItem
1392 */
1393 activeItem: null,
1394
1395
1396 /**
1397 * @property parent
1398 * @description Object reference to the menu's parent menu or menu item.  
1399 * This property can be set via the constructor using the configuration 
1400 * object literal.
1401 * @default null
1402 * @type YAHOO.widget.MenuItem
1403 */
1404 parent: null,
1405
1406
1407 /**
1408 * @property srcElement
1409 * @description Object reference to the HTML element (either 
1410 * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to 
1411 * create the menu.
1412 * @default null
1413 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1414 * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a 
1415 * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1416 * html#ID-22445964">HTMLDivElement</a>
1417 */
1418 srcElement: null,
1419
1420
1421
1422 // Events
1423
1424
1425 /**
1426 * @event mouseOverEvent
1427 * @description Fires when the mouse has entered the menu.  Passes back 
1428 * the DOM Event object as an argument.
1429 */
1430
1431
1432 /**
1433 * @event mouseOutEvent
1434 * @description Fires when the mouse has left the menu.  Passes back the DOM 
1435 * Event object as an argument.
1436 * @type YAHOO.util.CustomEvent
1437 */
1438
1439
1440 /**
1441 * @event mouseDownEvent
1442 * @description Fires when the user mouses down on the menu.  Passes back the 
1443 * DOM Event object as an argument.
1444 * @type YAHOO.util.CustomEvent
1445 */
1446
1447
1448 /**
1449 * @event mouseUpEvent
1450 * @description Fires when the user releases a mouse button while the mouse is 
1451 * over the menu.  Passes back the DOM Event object as an argument.
1452 * @type YAHOO.util.CustomEvent
1453 */
1454
1455
1456 /**
1457 * @event clickEvent
1458 * @description Fires when the user clicks the on the menu.  Passes back the 
1459 * DOM Event object as an argument.
1460 * @type YAHOO.util.CustomEvent
1461 */
1462
1463
1464 /**
1465 * @event keyPressEvent
1466 * @description Fires when the user presses an alphanumeric key when one of the
1467 * menu's items has focus.  Passes back the DOM Event object as an argument.
1468 * @type YAHOO.util.CustomEvent
1469 */
1470
1471
1472 /**
1473 * @event keyDownEvent
1474 * @description Fires when the user presses a key when one of the menu's items 
1475 * has focus.  Passes back the DOM Event object as an argument.
1476 * @type YAHOO.util.CustomEvent
1477 */
1478
1479
1480 /**
1481 * @event keyUpEvent
1482 * @description Fires when the user releases a key when one of the menu's items 
1483 * has focus.  Passes back the DOM Event object as an argument.
1484 * @type YAHOO.util.CustomEvent
1485 */
1486
1487
1488 /**
1489 * @event itemAddedEvent
1490 * @description Fires when an item is added to the menu.
1491 * @type YAHOO.util.CustomEvent
1492 */
1493
1494
1495 /**
1496 * @event itemRemovedEvent
1497 * @description Fires when an item is removed to the menu.
1498 * @type YAHOO.util.CustomEvent
1499 */
1500
1501
1502 /**
1503 * @method init
1504 * @description The Menu class's initialization method. This method is 
1505 * automatically called by the constructor, and sets up all DOM references 
1506 * for pre-existing markup, and creates required markup if it is not 
1507 * already present.
1508 * @param {String} p_oElement String specifying the id attribute of the 
1509 * <code>&#60;div&#62;</code> element of the menu.
1510 * @param {String} p_oElement String specifying the id attribute of the 
1511 * <code>&#60;select&#62;</code> element to be used as the data source 
1512 * for the menu.
1513 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1514 * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
1515 * specifying the <code>&#60;div&#62;</code> element of the menu.
1516 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1517 * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
1518 * Object specifying the <code>&#60;select&#62;</code> element to be used as 
1519 * the data source for the menu.
1520 * @param {Object} p_oConfig Optional. Object literal specifying the 
1521 * configuration for the menu. See configuration class documentation for 
1522 * more details.
1523 */
1524 init: function (p_oElement, p_oConfig) {
1525
1526     this._aItemGroups = [];
1527     this._aListElements = [];
1528     this._aGroupTitleElements = [];
1529
1530     if (!this.ITEM_TYPE) {
1531
1532         this.ITEM_TYPE = YAHOO.widget.MenuItem;
1533
1534     }
1535
1536
1537     var oElement;
1538
1539     if (Lang.isString(p_oElement)) {
1540
1541         oElement = Dom.get(p_oElement);
1542
1543     }
1544     else if (p_oElement.tagName) {
1545
1546         oElement = p_oElement;
1547
1548     }
1549
1550
1551     if (oElement && oElement.tagName) {
1552
1553         switch(oElement.tagName.toUpperCase()) {
1554     
1555             case _DIV_UPPERCASE:
1556
1557                 this.srcElement = oElement;
1558
1559                 if (!oElement.id) {
1560
1561                     oElement.setAttribute(_ID, Dom.generateId());
1562
1563                 }
1564
1565
1566                 /* 
1567                     Note: we don't pass the user config in here yet 
1568                     because we only want it executed once, at the lowest 
1569                     subclass level.
1570                 */ 
1571             
1572                 Menu.superclass.init.call(this, oElement);
1573
1574                 this.beforeInitEvent.fire(Menu);
1575
1576                 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1577     
1578             break;
1579     
1580             case _SELECT:
1581     
1582                 this.srcElement = oElement;
1583
1584     
1585                 /*
1586                     The source element is not something that we can use 
1587                     outright, so we need to create a new Overlay
1588
1589                     Note: we don't pass the user config in here yet 
1590                     because we only want it executed once, at the lowest 
1591                     subclass level.
1592                 */ 
1593
1594                 Menu.superclass.init.call(this, Dom.generateId());
1595
1596                 this.beforeInitEvent.fire(Menu);
1597
1598                                 YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1599
1600             break;
1601
1602         }
1603
1604     }
1605     else {
1606
1607         /* 
1608             Note: we don't pass the user config in here yet 
1609             because we only want it executed once, at the lowest 
1610             subclass level.
1611         */ 
1612     
1613         Menu.superclass.init.call(this, p_oElement);
1614
1615         this.beforeInitEvent.fire(Menu);
1616
1617                 YAHOO.log("No source element found.  Created element with id: " + this.id, "info", this.toString());
1618
1619     }
1620
1621
1622     if (this.element) {
1623
1624         Dom.addClass(this.element, this.CSS_CLASS_NAME);
1625
1626
1627         // Subscribe to Custom Events
1628
1629         this.initEvent.subscribe(this._onInit);
1630         this.beforeRenderEvent.subscribe(this._onBeforeRender);
1631         this.renderEvent.subscribe(this._onRender);
1632         this.beforeShowEvent.subscribe(this._onBeforeShow);
1633                 this.hideEvent.subscribe(this._onHide);
1634         this.showEvent.subscribe(this._onShow);
1635                 this.beforeHideEvent.subscribe(this._onBeforeHide);
1636         this.mouseOverEvent.subscribe(this._onMouseOver);
1637         this.mouseOutEvent.subscribe(this._onMouseOut);
1638         this.clickEvent.subscribe(this._onClick);
1639         this.keyDownEvent.subscribe(this._onKeyDown);
1640         this.keyPressEvent.subscribe(this._onKeyPress);
1641         this.blurEvent.subscribe(this._onBlur);
1642
1643
1644                 if (!bFocusListenerInitialized) {
1645                         Event.onFocus(document, onDocFocus);
1646                         bFocusListenerInitialized = true;
1647                 }
1648
1649
1650                 //      Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY" 
1651                 //      methods return values that don't take scrollTop into consideration 
1652
1653         if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) {
1654
1655             this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1656
1657         }
1658
1659
1660         if (p_oConfig) {
1661     
1662             this.cfg.applyConfig(p_oConfig, true);
1663     
1664         }
1665
1666
1667         // Register the Menu instance with the MenuManager
1668
1669         MenuManager.addMenu(this);
1670
1671
1672         this.initEvent.fire(Menu);
1673
1674     }
1675
1676 },
1677
1678
1679
1680 // Private methods
1681
1682
1683 /**
1684 * @method _initSubTree
1685 * @description Iterates the childNodes of the source element to find nodes 
1686 * used to instantiate menu and menu items.
1687 * @private
1688 */
1689 _initSubTree: function () {
1690
1691     var oSrcElement = this.srcElement,
1692         sSrcElementTagName,
1693         nGroup,
1694         sGroupTitleTagName,
1695         oNode,
1696         aListElements,
1697         nListElements,
1698         i;
1699
1700
1701     if (oSrcElement) {
1702     
1703         sSrcElementTagName = 
1704             (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1705
1706
1707         if (sSrcElementTagName == _DIV_UPPERCASE) {
1708     
1709             //  Populate the collection of item groups and item group titles
1710     
1711             oNode = this.body.firstChild;
1712     
1713
1714             if (oNode) {
1715     
1716                 nGroup = 0;
1717                 sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1718         
1719                 do {
1720         
1721
1722                     if (oNode && oNode.tagName) {
1723         
1724                         switch (oNode.tagName.toUpperCase()) {
1725         
1726                             case sGroupTitleTagName:
1727                             
1728                                 this._aGroupTitleElements[nGroup] = oNode;
1729         
1730                             break;
1731         
1732                             case _UL_UPPERCASE:
1733         
1734                                 this._aListElements[nGroup] = oNode;
1735                                 this._aItemGroups[nGroup] = [];
1736                                 nGroup++;
1737         
1738                             break;
1739         
1740                         }
1741                     
1742                     }
1743         
1744                 }
1745                 while ((oNode = oNode.nextSibling));
1746         
1747         
1748                 /*
1749                     Apply the "first-of-type" class to the first UL to mimic 
1750                     the ":first-of-type" CSS3 psuedo class.
1751                 */
1752         
1753                 if (this._aListElements[0]) {
1754         
1755                     Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1756         
1757                 }
1758             
1759             }
1760     
1761         }
1762     
1763     
1764         oNode = null;
1765     
1766         YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
1767     
1768
1769         if (sSrcElementTagName) {
1770     
1771             switch (sSrcElementTagName) {
1772         
1773                 case _DIV_UPPERCASE:
1774
1775                     aListElements = this._aListElements;
1776                     nListElements = aListElements.length;
1777         
1778                     if (nListElements > 0) {
1779         
1780                                         YAHOO.log("Found " + nListElements + " item groups to initialize.", 
1781                                                                 "info", this.toString());
1782         
1783                         i = nListElements - 1;
1784         
1785                         do {
1786         
1787                             oNode = aListElements[i].firstChild;
1788             
1789                             if (oNode) {
1790
1791                                 YAHOO.log("Scanning " + 
1792                                     aListElements[i].childNodes.length + 
1793                                     " child nodes for items to initialize.", "info", this.toString());
1794             
1795                                 do {
1796                 
1797                                     if (oNode && oNode.tagName && 
1798                                         oNode.tagName.toUpperCase() == _LI) {
1799                 
1800                                         YAHOO.log("Initializing " + 
1801                                             oNode.tagName + " node.", "info", this.toString());
1802         
1803                                         this.addItem(new this.ITEM_TYPE(oNode, 
1804                                                     { parent: this }), i);
1805             
1806                                     }
1807                         
1808                                 }
1809                                 while ((oNode = oNode.nextSibling));
1810                             
1811                             }
1812                     
1813                         }
1814                         while (i--);
1815         
1816                     }
1817         
1818                 break;
1819         
1820                 case _SELECT:
1821         
1822                     YAHOO.log("Scanning " +  
1823                         oSrcElement.childNodes.length + 
1824                         " child nodes for items to initialize.", "info", this.toString());
1825         
1826                     oNode = oSrcElement.firstChild;
1827         
1828                     do {
1829         
1830                         if (oNode && oNode.tagName) {
1831                         
1832                             switch (oNode.tagName.toUpperCase()) {
1833             
1834                                 case _OPTGROUP:
1835                                 case _OPTION:
1836             
1837                                     YAHOO.log("Initializing " +  
1838                                         oNode.tagName + " node.", "info", this.toString());
1839             
1840                                     this.addItem(
1841                                             new this.ITEM_TYPE(
1842                                                     oNode, 
1843                                                     { parent: this }
1844                                                 )
1845                                             );
1846             
1847                                 break;
1848             
1849                             }
1850     
1851                         }
1852         
1853                     }
1854                     while ((oNode = oNode.nextSibling));
1855         
1856                 break;
1857         
1858             }
1859     
1860         }    
1861     
1862     }
1863
1864 },
1865
1866
1867 /**
1868 * @method _getFirstEnabledItem
1869 * @description Returns the first enabled item in the menu.
1870 * @return {YAHOO.widget.MenuItem}
1871 * @private
1872 */
1873 _getFirstEnabledItem: function () {
1874
1875     var aItems = this.getItems(),
1876         nItems = aItems.length,
1877         oItem,
1878         returnVal;
1879     
1880
1881     for(var i=0; i<nItems; i++) {
1882
1883         oItem = aItems[i];
1884
1885         if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1886
1887             returnVal = oItem;
1888             break;
1889
1890         }
1891     
1892     }
1893     
1894     return returnVal;
1895     
1896 },
1897
1898
1899 /**
1900 * @method _addItemToGroup
1901 * @description Adds a menu item to a group.
1902 * @private
1903 * @param {Number} p_nGroupIndex Number indicating the group to which the 
1904 * item belongs.
1905 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
1906 * instance to be added to the menu.
1907 * @param {String} p_oItem String specifying the text of the item to be added 
1908 * to the menu.
1909 * @param {Object} p_oItem Object literal containing a set of menu item 
1910 * configuration properties.
1911 * @param {Number} p_nItemIndex Optional. Number indicating the index at 
1912 * which the menu item should be added.
1913 * @return {YAHOO.widget.MenuItem}
1914 */
1915 _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1916
1917     var oItem,
1918         nGroupIndex,
1919         aGroup,
1920         oGroupItem,
1921         bAppend,
1922         oNextItemSibling,
1923         nItemIndex,
1924         returnVal;
1925
1926
1927     function getNextItemSibling(p_aArray, p_nStartIndex) {
1928
1929         return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1930
1931     }
1932
1933
1934     if (p_oItem instanceof this.ITEM_TYPE) {
1935
1936         oItem = p_oItem;
1937         oItem.parent = this;
1938
1939     }
1940     else if (Lang.isString(p_oItem)) {
1941
1942         oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1943     
1944     }
1945     else if (Lang.isObject(p_oItem)) {
1946
1947         p_oItem.parent = this;
1948
1949         oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1950
1951     }
1952
1953
1954     if (oItem) {
1955
1956         if (oItem.cfg.getProperty(_SELECTED)) {
1957
1958             this.activeItem = oItem;
1959         
1960         }
1961
1962
1963         nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1964         aGroup = this._getItemGroup(nGroupIndex);
1965
1966
1967
1968         if (!aGroup) {
1969
1970             aGroup = this._createItemGroup(nGroupIndex);
1971
1972         }
1973
1974
1975         if (Lang.isNumber(p_nItemIndex)) {
1976
1977             bAppend = (p_nItemIndex >= aGroup.length);            
1978
1979
1980             if (aGroup[p_nItemIndex]) {
1981     
1982                 aGroup.splice(p_nItemIndex, 0, oItem);
1983     
1984             }
1985             else {
1986     
1987                 aGroup[p_nItemIndex] = oItem;
1988     
1989             }
1990
1991
1992             oGroupItem = aGroup[p_nItemIndex];
1993
1994             if (oGroupItem) {
1995
1996                 if (bAppend && (!oGroupItem.element.parentNode || 
1997                         oGroupItem.element.parentNode.nodeType == 11)) {
1998         
1999                     this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2000     
2001                 }
2002                 else {
2003     
2004                     oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
2005     
2006                     if (oNextItemSibling && (!oGroupItem.element.parentNode || 
2007                             oGroupItem.element.parentNode.nodeType == 11)) {
2008             
2009                         this._aListElements[nGroupIndex].insertBefore(
2010                                 oGroupItem.element, oNextItemSibling.element);
2011         
2012                     }
2013     
2014                 }
2015     
2016
2017                 oGroupItem.parent = this;
2018         
2019                 this._subscribeToItemEvents(oGroupItem);
2020     
2021                 this._configureSubmenu(oGroupItem);
2022                 
2023                 this._updateItemProperties(nGroupIndex);
2024         
2025                 YAHOO.log("Item inserted." + 
2026                     " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2027                     " Index: " + oGroupItem.index + ", " + 
2028                     " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2029
2030                 this.itemAddedEvent.fire(oGroupItem);
2031                 this.changeContentEvent.fire();
2032
2033                 returnVal = oGroupItem;
2034     
2035             }
2036
2037         }
2038         else {
2039     
2040             nItemIndex = aGroup.length;
2041     
2042             aGroup[nItemIndex] = oItem;
2043
2044             oGroupItem = aGroup[nItemIndex];
2045     
2046
2047             if (oGroupItem) {
2048     
2049                 if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2050     
2051                     this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2052     
2053                 }
2054     
2055                 oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2056                 oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2057         
2058                 oGroupItem.parent = this;
2059     
2060                 oGroupItem.index = nItemIndex;
2061                 oGroupItem.groupIndex = nGroupIndex;
2062         
2063                 this._subscribeToItemEvents(oGroupItem);
2064     
2065                 this._configureSubmenu(oGroupItem);
2066     
2067                 if (nItemIndex === 0) {
2068         
2069                     Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2070         
2071                 }
2072
2073                 YAHOO.log("Item added." + 
2074                     " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2075                     " Index: " + oGroupItem.index + ", " + 
2076                     " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2077         
2078
2079                 this.itemAddedEvent.fire(oGroupItem);
2080                 this.changeContentEvent.fire();
2081
2082                 returnVal = oGroupItem;
2083     
2084             }
2085     
2086         }
2087
2088     }
2089     
2090     return returnVal;
2091     
2092 },
2093
2094
2095 /**
2096 * @method _removeItemFromGroupByIndex
2097 * @description Removes a menu item from a group by index.  Returns the menu 
2098 * item that was removed.
2099 * @private
2100 * @param {Number} p_nGroupIndex Number indicating the group to which the menu 
2101 * item belongs.
2102 * @param {Number} p_nItemIndex Number indicating the index of the menu item 
2103 * to be removed.
2104 * @return {YAHOO.widget.MenuItem}
2105 */
2106 _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2107
2108     var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2109         aGroup = this._getItemGroup(nGroupIndex),
2110         aArray,
2111         oItem,
2112         oUL;
2113
2114     if (aGroup) {
2115
2116         aArray = aGroup.splice(p_nItemIndex, 1);
2117         oItem = aArray[0];
2118     
2119         if (oItem) {
2120     
2121             // Update the index and className properties of each member        
2122             
2123             this._updateItemProperties(nGroupIndex);
2124     
2125             if (aGroup.length === 0) {
2126     
2127                 // Remove the UL
2128     
2129                 oUL = this._aListElements[nGroupIndex];
2130     
2131                 if (this.body && oUL) {
2132     
2133                     this.body.removeChild(oUL);
2134     
2135                 }
2136     
2137                 // Remove the group from the array of items
2138     
2139                 this._aItemGroups.splice(nGroupIndex, 1);
2140     
2141     
2142                 // Remove the UL from the array of ULs
2143     
2144                 this._aListElements.splice(nGroupIndex, 1);
2145     
2146     
2147                 /*
2148                      Assign the "first-of-type" class to the new first UL 
2149                      in the collection
2150                 */
2151     
2152                 oUL = this._aListElements[0];
2153     
2154                 if (oUL) {
2155     
2156                     Dom.addClass(oUL, _FIRST_OF_TYPE);
2157     
2158                 }            
2159     
2160             }
2161     
2162
2163             this.itemRemovedEvent.fire(oItem);
2164             this.changeContentEvent.fire();
2165     
2166         }
2167
2168     }
2169
2170         // Return a reference to the item that was removed
2171
2172         return oItem;
2173     
2174 },
2175
2176
2177 /**
2178 * @method _removeItemFromGroupByValue
2179 * @description Removes a menu item from a group by reference.  Returns the 
2180 * menu item that was removed.
2181 * @private
2182 * @param {Number} p_nGroupIndex Number indicating the group to which the
2183 * menu item belongs.
2184 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2185 * instance to be removed.
2186 * @return {YAHOO.widget.MenuItem}
2187 */    
2188 _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2189
2190     var aGroup = this._getItemGroup(p_nGroupIndex),
2191         nItems,
2192         nItemIndex,
2193         returnVal,
2194         i;
2195
2196     if (aGroup) {
2197
2198         nItems = aGroup.length;
2199         nItemIndex = -1;
2200     
2201         if (nItems > 0) {
2202     
2203             i = nItems-1;
2204         
2205             do {
2206         
2207                 if (aGroup[i] == p_oItem) {
2208         
2209                     nItemIndex = i;
2210                     break;    
2211         
2212                 }
2213         
2214             }
2215             while (i--);
2216         
2217             if (nItemIndex > -1) {
2218         
2219                 returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2220         
2221             }
2222     
2223         }
2224     
2225     }
2226     
2227     return returnVal;
2228
2229 },
2230
2231
2232 /**
2233 * @method _updateItemProperties
2234 * @description Updates the "index," "groupindex," and "className" properties 
2235 * of the menu items in the specified group. 
2236 * @private
2237 * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2238 */
2239 _updateItemProperties: function (p_nGroupIndex) {
2240
2241     var aGroup = this._getItemGroup(p_nGroupIndex),
2242         nItems = aGroup.length,
2243         oItem,
2244         oLI,
2245         i;
2246
2247
2248     if (nItems > 0) {
2249
2250         i = nItems - 1;
2251
2252         // Update the index and className properties of each member
2253     
2254         do {
2255
2256             oItem = aGroup[i];
2257
2258             if (oItem) {
2259     
2260                 oLI = oItem.element;
2261
2262                 oItem.index = i;
2263                 oItem.groupIndex = p_nGroupIndex;
2264
2265                 oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2266                 oLI.setAttribute(_INDEX, i);
2267
2268                 Dom.removeClass(oLI, _FIRST_OF_TYPE);
2269
2270             }
2271     
2272         }
2273         while (i--);
2274
2275
2276         if (oLI) {
2277
2278             Dom.addClass(oLI, _FIRST_OF_TYPE);
2279
2280         }
2281
2282     }
2283
2284 },
2285
2286
2287 /**
2288 * @method _createItemGroup
2289 * @description Creates a new menu item group (array) and its associated 
2290 * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2291 * @private
2292 * @param {Number} p_nIndex Number indicating the group to create.
2293 * @return {Array}
2294 */
2295 _createItemGroup: function (p_nIndex) {
2296
2297     var oUL,
2298         returnVal;
2299
2300     if (!this._aItemGroups[p_nIndex]) {
2301
2302         this._aItemGroups[p_nIndex] = [];
2303
2304         oUL = document.createElement(_UL_LOWERCASE);
2305
2306         this._aListElements[p_nIndex] = oUL;
2307
2308         returnVal = this._aItemGroups[p_nIndex];
2309
2310     }
2311     
2312     return returnVal;
2313
2314 },
2315
2316
2317 /**
2318 * @method _getItemGroup
2319 * @description Returns the menu item group at the specified index.
2320 * @private
2321 * @param {Number} p_nIndex Number indicating the index of the menu item group 
2322 * to be retrieved.
2323 * @return {Array}
2324 */
2325 _getItemGroup: function (p_nIndex) {
2326
2327     var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2328         aGroups = this._aItemGroups,
2329         returnVal;
2330
2331         if (nIndex in aGroups) {
2332
2333             returnVal = aGroups[nIndex];
2334
2335         }
2336         
2337         return returnVal;
2338
2339 },
2340
2341
2342 /**
2343 * @method _configureSubmenu
2344 * @description Subscribes the menu item's submenu to its parent menu's events.
2345 * @private
2346 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2347 * instance with the submenu to be configured.
2348 */
2349 _configureSubmenu: function (p_oItem) {
2350
2351     var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2352
2353     if (oSubmenu) {
2354             
2355         /*
2356             Listen for configuration changes to the parent menu 
2357             so they they can be applied to the submenu.
2358         */
2359
2360         this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2361
2362         this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2363
2364     }
2365
2366 },
2367
2368
2369
2370
2371 /**
2372 * @method _subscribeToItemEvents
2373 * @description Subscribes a menu to a menu item's event.
2374 * @private
2375 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2376 * instance whose events should be subscribed to.
2377 */
2378 _subscribeToItemEvents: function (p_oItem) {
2379
2380     p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2381     p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2382
2383 },
2384
2385
2386 /**
2387 * @method _onVisibleChange
2388 * @description Change event handler for the the menu's "visible" configuration
2389 * property.
2390 * @private
2391 * @param {String} p_sType String representing the name of the event that 
2392 * was fired.
2393 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2394 */
2395 _onVisibleChange: function (p_sType, p_aArgs) {
2396
2397     var bVisible = p_aArgs[0];
2398     
2399     if (bVisible) {
2400
2401         Dom.addClass(this.element, _VISIBLE);
2402
2403     }
2404     else {
2405
2406         Dom.removeClass(this.element, _VISIBLE);
2407
2408     }
2409
2410 },
2411
2412
2413 /**
2414 * @method _cancelHideDelay
2415 * @description Cancels the call to "hideMenu."
2416 * @private
2417 */
2418 _cancelHideDelay: function () {
2419
2420     var oTimer = this.getRoot()._hideDelayTimer;
2421
2422     if (oTimer) {
2423
2424                 oTimer.cancel();
2425
2426     }
2427
2428 },
2429
2430
2431 /**
2432 * @method _execHideDelay
2433 * @description Hides the menu after the number of milliseconds specified by 
2434 * the "hidedelay" configuration property.
2435 * @private
2436 */
2437 _execHideDelay: function () {
2438
2439     this._cancelHideDelay();
2440
2441     var oRoot = this.getRoot();
2442         
2443         oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2444     
2445         if (oRoot.activeItem) {
2446
2447                         if (oRoot.hasFocus()) {
2448
2449                                 oRoot.activeItem.focus();
2450                         
2451                         }
2452                         
2453             oRoot.clearActiveItem();
2454
2455         }
2456
2457         if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) && 
2458             this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2459
2460             this.hide();
2461         
2462         }
2463     
2464     });
2465
2466 },
2467
2468
2469 /**
2470 * @method _cancelShowDelay
2471 * @description Cancels the call to the "showMenu."
2472 * @private
2473 */
2474 _cancelShowDelay: function () {
2475
2476     var oTimer = this.getRoot()._showDelayTimer;
2477
2478     if (oTimer) {
2479
2480         oTimer.cancel();
2481
2482     }
2483
2484 },
2485
2486
2487 /**
2488 * @method _execSubmenuHideDelay
2489 * @description Hides a submenu after the number of milliseconds specified by 
2490 * the "submenuhidedelay" configuration property have ellapsed.
2491 * @private
2492 * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that  
2493 * should be hidden.
2494 * @param {Number} p_nMouseX The x coordinate of the mouse when it left 
2495 * the specified submenu's parent menu item.
2496 * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2497 * before the submenu is hidden.
2498 */
2499 _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2500
2501         p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2502
2503         if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2504
2505             p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2506         
2507                 this.hide();
2508
2509             });
2510
2511         }
2512         else {
2513
2514             p_oSubmenu.hide();
2515         
2516         }
2517         
2518         });
2519
2520 },
2521
2522
2523
2524 // Protected methods
2525
2526
2527 /**
2528 * @method _disableScrollHeader
2529 * @description Disables the header used for scrolling the body of the menu.
2530 * @protected
2531 */
2532 _disableScrollHeader: function () {
2533
2534     if (!this._bHeaderDisabled) {
2535
2536         Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2537         this._bHeaderDisabled = true;
2538
2539     }
2540
2541 },
2542
2543
2544 /**
2545 * @method _disableScrollFooter
2546 * @description Disables the footer used for scrolling the body of the menu.
2547 * @protected
2548 */
2549 _disableScrollFooter: function () {
2550
2551     if (!this._bFooterDisabled) {
2552
2553         Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2554         this._bFooterDisabled = true;
2555
2556     }
2557
2558 },
2559
2560
2561 /**
2562 * @method _enableScrollHeader
2563 * @description Enables the header used for scrolling the body of the menu.
2564 * @protected
2565 */
2566 _enableScrollHeader: function () {
2567
2568     if (this._bHeaderDisabled) {
2569
2570         Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2571         this._bHeaderDisabled = false;
2572
2573     }
2574
2575 },
2576
2577
2578 /**
2579 * @method _enableScrollFooter
2580 * @description Enables the footer used for scrolling the body of the menu.
2581 * @protected
2582 */
2583 _enableScrollFooter: function () {
2584
2585     if (this._bFooterDisabled) {
2586
2587         Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2588         this._bFooterDisabled = false;
2589
2590     }
2591
2592 },
2593
2594
2595 /**
2596 * @method _onMouseOver
2597 * @description "mouseover" event handler for the menu.
2598 * @protected
2599 * @param {String} p_sType String representing the name of the event that 
2600 * was fired.
2601 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2602 */
2603 _onMouseOver: function (p_sType, p_aArgs) {
2604
2605     var oEvent = p_aArgs[0],
2606         oItem = p_aArgs[1],
2607         oTarget = Event.getTarget(oEvent),
2608         oRoot = this.getRoot(),
2609         oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2610         oParentMenu,
2611         nShowDelay,
2612         bShowDelay,
2613         oActiveItem,
2614         oItemCfg,
2615         oSubmenu;
2616
2617
2618     var showSubmenu = function () {
2619
2620         if (this.parent.cfg.getProperty(_SELECTED)) {
2621
2622             this.show();
2623
2624         }
2625
2626     };
2627
2628
2629     if (!this._bStopMouseEventHandlers) {
2630     
2631                 if (!this._bHandledMouseOverEvent && (oTarget == this.element || 
2632                                 Dom.isAncestor(this.element, oTarget))) {
2633         
2634                         // Menu mouseover logic
2635
2636                 if (this._useHideDelay) {
2637                         this._cancelHideDelay();
2638                 }
2639         
2640                         this._nCurrentMouseX = 0;
2641         
2642                         Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2643
2644
2645                         /*
2646                                 If the mouse is moving from the submenu back to its corresponding menu item, 
2647                                 don't hide the submenu or clear the active MenuItem.
2648                         */
2649
2650                         if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2651
2652                                 this.clearActiveItem();
2653
2654                         }
2655         
2656
2657                         if (this.parent && oSubmenuHideDelayTimer) {
2658         
2659                                 oSubmenuHideDelayTimer.cancel();
2660         
2661                                 this.parent.cfg.setProperty(_SELECTED, true);
2662         
2663                                 oParentMenu = this.parent.parent;
2664         
2665                                 oParentMenu._bHandledMouseOutEvent = true;
2666                                 oParentMenu._bHandledMouseOverEvent = false;
2667         
2668                         }
2669         
2670         
2671                         this._bHandledMouseOverEvent = true;
2672                         this._bHandledMouseOutEvent = false;
2673                 
2674                 }
2675         
2676         
2677                 if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) && 
2678                         (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2679         
2680                         // Menu Item mouseover logic
2681         
2682                         nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2683                         bShowDelay = (nShowDelay > 0);
2684         
2685         
2686                         if (bShowDelay) {
2687                         
2688                                 this._cancelShowDelay();
2689                         
2690                         }
2691         
2692         
2693                         oActiveItem = this.activeItem;
2694                 
2695                         if (oActiveItem) {
2696                 
2697                                 oActiveItem.cfg.setProperty(_SELECTED, false);
2698                 
2699                         }
2700         
2701         
2702                         oItemCfg = oItem.cfg;
2703                 
2704                         // Select and focus the current menu item
2705                 
2706                         oItemCfg.setProperty(_SELECTED, true);
2707         
2708         
2709                         if (this.hasFocus() || oRoot._hasFocus) {
2710                         
2711                                 oItem.focus();
2712                                 
2713                                 oRoot._hasFocus = false;
2714                         
2715                         }
2716         
2717         
2718                         if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2719         
2720                                 // Show the submenu this menu item
2721         
2722                                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
2723                         
2724                                 if (oSubmenu) {
2725                         
2726                                         if (bShowDelay) {
2727         
2728                                                 oRoot._showDelayTimer = 
2729                                                         Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2730                         
2731                                         }
2732                                         else {
2733         
2734                                                 oSubmenu.show();
2735         
2736                                         }
2737         
2738                                 }
2739         
2740                         }                        
2741         
2742                         oItem.handledMouseOverEvent = true;
2743                         oItem.handledMouseOutEvent = false;
2744         
2745                 }
2746     
2747     }
2748
2749 },
2750
2751
2752 /**
2753 * @method _onMouseOut
2754 * @description "mouseout" event handler for the menu.
2755 * @protected
2756 * @param {String} p_sType String representing the name of the event that 
2757 * was fired.
2758 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2759 */
2760 _onMouseOut: function (p_sType, p_aArgs) {
2761
2762     var oEvent = p_aArgs[0],
2763         oItem = p_aArgs[1],
2764         oRelatedTarget = Event.getRelatedTarget(oEvent),
2765         bMovingToSubmenu = false,
2766         oItemCfg,
2767         oSubmenu,
2768         nSubmenuHideDelay,
2769         nShowDelay;
2770
2771
2772     if (!this._bStopMouseEventHandlers) {
2773     
2774                 if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2775         
2776                         oItemCfg = oItem.cfg;
2777                         oSubmenu = oItemCfg.getProperty(_SUBMENU);
2778         
2779         
2780                         if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
2781                                         Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2782         
2783                                 bMovingToSubmenu = true;
2784         
2785                         }
2786         
2787         
2788                         if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&  
2789                                 !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2790         
2791                                 // Menu Item mouseout logic
2792         
2793                                 if (!bMovingToSubmenu) {
2794         
2795                                         oItem.cfg.setProperty(_SELECTED, false);
2796         
2797         
2798                                         if (oSubmenu) {
2799         
2800                                                 nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2801         
2802                                                 nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2803         
2804                                                 if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 && 
2805                                                         nShowDelay >= nSubmenuHideDelay) {
2806         
2807                                                         this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
2808                                                                         nSubmenuHideDelay);
2809         
2810                                                 }
2811                                                 else {
2812         
2813                                                         oSubmenu.hide();
2814         
2815                                                 }
2816         
2817                                         }
2818         
2819                                 }
2820         
2821         
2822                                 oItem.handledMouseOutEvent = true;
2823                                 oItem.handledMouseOverEvent = false;
2824                 
2825                         }
2826         
2827                 }
2828
2829
2830                 if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&  
2831                         !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
2832         
2833                         // Menu mouseout logic
2834
2835                 if (this._useHideDelay) {
2836                         this._execHideDelay();
2837                 }
2838
2839                         Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2840         
2841                         this._nCurrentMouseX = Event.getPageX(oEvent);
2842         
2843                         this._bHandledMouseOutEvent = true;
2844                         this._bHandledMouseOverEvent = false;
2845         
2846                 }
2847     
2848     }
2849
2850 },
2851
2852
2853 /**
2854 * @method _onMouseMove
2855 * @description "click" event handler for the menu.
2856 * @protected
2857 * @param {Event} p_oEvent Object representing the DOM event object passed 
2858 * back by the event utility (YAHOO.util.Event).
2859 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
2860 * fired the event.
2861 */
2862 _onMouseMove: function (p_oEvent, p_oMenu) {
2863
2864     if (!this._bStopMouseEventHandlers) {
2865     
2866             this._nCurrentMouseX = Event.getPageX(p_oEvent);
2867     
2868     }
2869
2870 },
2871
2872
2873 /**
2874 * @method _onClick
2875 * @description "click" event handler for the menu.
2876 * @protected
2877 * @param {String} p_sType String representing the name of the event that 
2878 * was fired.
2879 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2880 */
2881 _onClick: function (p_sType, p_aArgs) {
2882
2883         var oEvent = p_aArgs[0],
2884                 oItem = p_aArgs[1],
2885                 bInMenuAnchor = false,
2886                 oSubmenu,
2887                 oMenu,
2888                 oRoot,
2889                 sId,
2890                 sURL,
2891                 nHashPos,
2892                 nLen;
2893
2894
2895         var hide = function () {
2896                 
2897                 oRoot = this.getRoot();
2898
2899                 if (oRoot instanceof YAHOO.widget.MenuBar || 
2900                         oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2901
2902                         oRoot.clearActiveItem();
2903
2904                 }
2905                 else {
2906
2907                         oRoot.hide();
2908                 
2909                 }
2910         
2911         };
2912
2913
2914         if (oItem) {
2915         
2916                 if (oItem.cfg.getProperty(_DISABLED)) {
2917                 
2918                         Event.preventDefault(oEvent);
2919
2920                         hide.call(this);
2921
2922                 }
2923                 else {
2924
2925                         oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2926         
2927                         
2928                         /*
2929                                  Check if the URL of the anchor is pointing to an element that is 
2930                                  a child of the menu.
2931                         */
2932                         
2933                         sURL = oItem.cfg.getProperty(_URL);
2934
2935                 
2936                         if (sURL) {
2937         
2938                                 nHashPos = sURL.indexOf(_HASH);
2939         
2940                                 nLen = sURL.length;
2941         
2942         
2943                                 if (nHashPos != -1) {
2944         
2945                                         sURL = sURL.substr(nHashPos, nLen);
2946                 
2947                                         nLen = sURL.length;
2948         
2949         
2950                                         if (nLen > 1) {
2951         
2952                                                 sId = sURL.substr(1, nLen);
2953         
2954                                                 oMenu = YAHOO.widget.MenuManager.getMenu(sId);
2955                                                 
2956                                                 if (oMenu) {
2957
2958                                                         bInMenuAnchor = 
2959                                                                 (this.getRoot() === oMenu.getRoot());
2960
2961                                                 }
2962                                                 
2963                                         }
2964                                         else if (nLen === 1) {
2965         
2966                                                 bInMenuAnchor = true;
2967                                         
2968                                         }
2969         
2970                                 }
2971                         
2972                         }
2973
2974         
2975                         if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
2976         
2977                                 Event.preventDefault(oEvent);
2978                                 
2979
2980                                 if (UA.webkit) {
2981                                 
2982                                         oItem.focus();
2983                                 
2984                                 }
2985                                 else {
2986
2987                                         oItem.focusEvent.fire();
2988                                 
2989                                 }
2990                         
2991                         }
2992         
2993         
2994                         if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
2995         
2996                                 hide.call(this);
2997         
2998                         }
2999                         
3000                 }
3001         
3002         }
3003
3004 },
3005
3006
3007 /**
3008 * @method _onKeyDown
3009 * @description "keydown" event handler for the menu.
3010 * @protected
3011 * @param {String} p_sType String representing the name of the event that 
3012 * was fired.
3013 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3014 */
3015 _onKeyDown: function (p_sType, p_aArgs) {
3016
3017     var oEvent = p_aArgs[0],
3018         oItem = p_aArgs[1],
3019         oSubmenu,
3020         oItemCfg,
3021         oParentItem,
3022         oRoot,
3023         oNextItem,
3024         oBody,
3025         nBodyScrollTop,
3026         nBodyOffsetHeight,
3027         aItems,
3028         nItems,
3029         nNextItemOffsetTop,
3030         nScrollTarget,
3031         oParentMenu,
3032                 oFocusedEl;
3033
3034
3035         if (this._useHideDelay) {
3036                 this._cancelHideDelay();
3037         }
3038
3039
3040     /*
3041         This function is called to prevent a bug in Firefox.  In Firefox,
3042         moving a DOM element into a stationary mouse pointer will cause the 
3043         browser to fire mouse events.  This can result in the menu mouse
3044         event handlers being called uncessarily, especially when menus are 
3045         moved into a stationary mouse pointer as a result of a 
3046         key event handler.
3047     */
3048     function stopMouseEventHandlers() {
3049
3050         this._bStopMouseEventHandlers = true;
3051         
3052         Lang.later(10, this, function () {
3053
3054             this._bStopMouseEventHandlers = false;
3055         
3056         });
3057
3058     }
3059
3060
3061     if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
3062
3063         oItemCfg = oItem.cfg;
3064         oParentItem = this.parent;
3065
3066         switch(oEvent.keyCode) {
3067     
3068             case 38:    // Up arrow
3069             case 40:    // Down arrow
3070     
3071                 oNextItem = (oEvent.keyCode == 38) ? 
3072                     oItem.getPreviousEnabledSibling() : 
3073                     oItem.getNextEnabledSibling();
3074         
3075                 if (oNextItem) {
3076
3077                     this.clearActiveItem();
3078
3079                     oNextItem.cfg.setProperty(_SELECTED, true);
3080                     oNextItem.focus();
3081
3082
3083                     if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
3084
3085                         oBody = this.body;
3086                         nBodyScrollTop = oBody.scrollTop;
3087                         nBodyOffsetHeight = oBody.offsetHeight;
3088                         aItems = this.getItems();
3089                         nItems = aItems.length - 1;
3090                         nNextItemOffsetTop = oNextItem.element.offsetTop;
3091
3092
3093                         if (oEvent.keyCode == 40 ) {    // Down
3094                        
3095                             if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3096
3097                                 oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3098
3099                             }
3100                             else if (nNextItemOffsetTop <= nBodyScrollTop) {
3101                             
3102                                 oBody.scrollTop = 0;
3103                             
3104                             }
3105
3106
3107                             if (oNextItem == aItems[nItems]) {
3108
3109                                 oBody.scrollTop = oNextItem.element.offsetTop;
3110
3111                             }
3112
3113                         }
3114                         else {  // Up
3115
3116                             if (nNextItemOffsetTop <= nBodyScrollTop) {
3117
3118                                 oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3119                             
3120                             }
3121                             else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3122                             
3123                                 oBody.scrollTop = nNextItemOffsetTop;
3124                             
3125                             }
3126
3127
3128                             if (oNextItem == aItems[0]) {
3129                             
3130                                 oBody.scrollTop = 0;
3131                             
3132                             }
3133
3134                         }
3135
3136
3137                         nBodyScrollTop = oBody.scrollTop;
3138                         nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3139
3140                         if (nBodyScrollTop === 0) {
3141
3142                             this._disableScrollHeader();
3143                             this._enableScrollFooter();
3144
3145                         }
3146                         else if (nBodyScrollTop == nScrollTarget) {
3147
3148                              this._enableScrollHeader();
3149                              this._disableScrollFooter();
3150
3151                         }
3152                         else {
3153
3154                             this._enableScrollHeader();
3155                             this._enableScrollFooter();
3156
3157                         }
3158
3159                     }
3160
3161                 }
3162
3163     
3164                 Event.preventDefault(oEvent);
3165
3166                 stopMouseEventHandlers();
3167     
3168             break;
3169             
3170     
3171             case 39:    // Right arrow
3172     
3173                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
3174     
3175                 if (oSubmenu) {
3176     
3177                     if (!oItemCfg.getProperty(_SELECTED)) {
3178         
3179                         oItemCfg.setProperty(_SELECTED, true);
3180         
3181                     }
3182     
3183                     oSubmenu.show();
3184                     oSubmenu.setInitialFocus();
3185                     oSubmenu.setInitialSelection();
3186     
3187                 }
3188                 else {
3189     
3190                     oRoot = this.getRoot();
3191                     
3192                     if (oRoot instanceof YAHOO.widget.MenuBar) {
3193     
3194                         oNextItem = oRoot.activeItem.getNextEnabledSibling();
3195     
3196                         if (oNextItem) {
3197                         
3198                             oRoot.clearActiveItem();
3199     
3200                             oNextItem.cfg.setProperty(_SELECTED, true);
3201     
3202                             oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3203     
3204                             if (oSubmenu) {
3205     
3206                                 oSubmenu.show();
3207                                 oSubmenu.setInitialFocus();
3208                             
3209                             }
3210                             else {
3211     
3212                                 oNextItem.focus();
3213                             
3214                             }
3215                         
3216                         }
3217                     
3218                     }
3219                 
3220                 }
3221     
3222     
3223                 Event.preventDefault(oEvent);
3224
3225                 stopMouseEventHandlers();
3226
3227             break;
3228     
3229     
3230             case 37:    // Left arrow
3231     
3232                 if (oParentItem) {
3233     
3234                     oParentMenu = oParentItem.parent;
3235     
3236                     if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3237     
3238                         oNextItem = 
3239                             oParentMenu.activeItem.getPreviousEnabledSibling();
3240     
3241                         if (oNextItem) {
3242                         
3243                             oParentMenu.clearActiveItem();
3244     
3245                             oNextItem.cfg.setProperty(_SELECTED, true);
3246     
3247                             oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3248     
3249                             if (oSubmenu) {
3250                             
3251                                 oSubmenu.show();
3252                                                                 oSubmenu.setInitialFocus();                                
3253                             
3254                             }
3255                             else {
3256     
3257                                 oNextItem.focus();
3258                             
3259                             }
3260                         
3261                         } 
3262                     
3263                     }
3264                     else {
3265     
3266                         this.hide();
3267     
3268                         oParentItem.focus();
3269                     
3270                     }
3271     
3272                 }
3273     
3274                 Event.preventDefault(oEvent);
3275
3276                 stopMouseEventHandlers();
3277
3278             break;        
3279     
3280         }
3281
3282
3283     }
3284
3285
3286     if (oEvent.keyCode == 27) { // Esc key
3287
3288         if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3289         
3290             this.hide();
3291
3292             if (this.parent) {
3293
3294                 this.parent.focus();
3295             
3296             }
3297                         else {
3298                                 // Focus the element that previously had focus
3299
3300                                 oFocusedEl = this._focusedElement;
3301
3302                                 if (oFocusedEl && oFocusedEl.focus) {
3303
3304                                         try {
3305                                                 oFocusedEl.focus();
3306                                         }
3307                                         catch(ex) {
3308                                         }
3309
3310                                 }
3311                                 
3312                         }
3313
3314         }
3315         else if (this.activeItem) {
3316
3317             oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3318
3319             if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3320             
3321                 oSubmenu.hide();
3322                 this.activeItem.focus();
3323             
3324             }
3325             else {
3326
3327                 this.activeItem.blur();
3328                 this.activeItem.cfg.setProperty(_SELECTED, false);
3329         
3330             }
3331         
3332         }
3333
3334
3335         Event.preventDefault(oEvent);
3336     
3337     }
3338     
3339 },
3340
3341
3342 /**
3343 * @method _onKeyPress
3344 * @description "keypress" event handler for a Menu instance.
3345 * @protected
3346 * @param {String} p_sType The name of the event that was fired.
3347 * @param {Array} p_aArgs Collection of arguments sent when the event 
3348 * was fired.
3349 */
3350 _onKeyPress: function (p_sType, p_aArgs) {
3351     
3352     var oEvent = p_aArgs[0];
3353
3354
3355     if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3356
3357         Event.preventDefault(oEvent);
3358
3359     }
3360
3361 },
3362
3363
3364 /**
3365 * @method _onBlur
3366 * @description "blur" event handler for a Menu instance.
3367 * @protected
3368 * @param {String} p_sType The name of the event that was fired.
3369 * @param {Array} p_aArgs Collection of arguments sent when the event 
3370 * was fired.
3371 */
3372 _onBlur: function (p_sType, p_aArgs) {
3373         
3374         if (this._hasFocus) {
3375                 this._hasFocus = false;
3376         }
3377
3378 },
3379
3380 /**
3381 * @method _onYChange
3382 * @description "y" event handler for a Menu instance.
3383 * @protected
3384 * @param {String} p_sType The name of the event that was fired.
3385 * @param {Array} p_aArgs Collection of arguments sent when the event 
3386 * was fired.
3387 */
3388 _onYChange: function (p_sType, p_aArgs) {
3389
3390     var oParent = this.parent,
3391         nScrollTop,
3392         oIFrame,
3393         nY;
3394
3395
3396     if (oParent) {
3397
3398         nScrollTop = oParent.parent.body.scrollTop;
3399
3400
3401         if (nScrollTop > 0) {
3402     
3403             nY = (this.cfg.getProperty(_Y) - nScrollTop);
3404             
3405             Dom.setY(this.element, nY);
3406
3407             oIFrame = this.iframe;            
3408     
3409
3410             if (oIFrame) {
3411     
3412                 Dom.setY(oIFrame, nY);
3413     
3414             }
3415             
3416             this.cfg.setProperty(_Y, nY, true);
3417         
3418         }
3419     
3420     }
3421
3422 },
3423
3424
3425 /**
3426 * @method _onScrollTargetMouseOver
3427 * @description "mouseover" event handler for the menu's "header" and "footer" 
3428 * elements.  Used to scroll the body of the menu up and down when the 
3429 * menu's "maxheight" configuration property is set to a value greater than 0.
3430 * @protected
3431 * @param {Event} p_oEvent Object representing the DOM event object passed 
3432 * back by the event utility (YAHOO.util.Event).
3433 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3434 * fired the event.
3435 */
3436 _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3437
3438         var oBodyScrollTimer = this._bodyScrollTimer;
3439
3440
3441         if (oBodyScrollTimer) {
3442
3443                 oBodyScrollTimer.cancel();
3444
3445         }
3446
3447
3448         this._cancelHideDelay();
3449
3450
3451     var oTarget = Event.getTarget(p_oEvent),
3452         oBody = this.body,
3453         nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3454         nScrollTarget,
3455         fnScrollFunction;
3456
3457
3458     function scrollBodyDown() {
3459
3460         var nScrollTop = oBody.scrollTop;
3461
3462
3463         if (nScrollTop < nScrollTarget) {
3464
3465             oBody.scrollTop = (nScrollTop + nScrollIncrement);
3466
3467             this._enableScrollHeader();
3468
3469         }
3470         else {
3471
3472             oBody.scrollTop = nScrollTarget;
3473
3474             this._bodyScrollTimer.cancel();
3475
3476             this._disableScrollFooter();
3477
3478         }
3479
3480     }
3481
3482
3483     function scrollBodyUp() {
3484
3485         var nScrollTop = oBody.scrollTop;
3486
3487
3488         if (nScrollTop > 0) {
3489
3490             oBody.scrollTop = (nScrollTop - nScrollIncrement);
3491
3492             this._enableScrollFooter();
3493
3494         }
3495         else {
3496
3497             oBody.scrollTop = 0;
3498
3499                         this._bodyScrollTimer.cancel();
3500
3501             this._disableScrollHeader();
3502
3503         }
3504
3505     }
3506
3507     
3508     if (Dom.hasClass(oTarget, _HD)) {
3509
3510         fnScrollFunction = scrollBodyUp;
3511     
3512     }
3513     else {
3514
3515         nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3516
3517         fnScrollFunction = scrollBodyDown;
3518     
3519     }
3520     
3521
3522     this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3523
3524 },
3525
3526
3527 /**
3528 * @method _onScrollTargetMouseOut
3529 * @description "mouseout" event handler for the menu's "header" and "footer" 
3530 * elements.  Used to stop scrolling the body of the menu up and down when the 
3531 * menu's "maxheight" configuration property is set to a value greater than 0.
3532 * @protected
3533 * @param {Event} p_oEvent Object representing the DOM event object passed 
3534 * back by the event utility (YAHOO.util.Event).
3535 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3536 * fired the event.
3537 */
3538 _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3539
3540         var oBodyScrollTimer = this._bodyScrollTimer;
3541
3542         if (oBodyScrollTimer) {
3543
3544                 oBodyScrollTimer.cancel();
3545
3546         }
3547         
3548     this._cancelHideDelay();
3549
3550 },
3551
3552
3553
3554 // Private methods
3555
3556
3557 /**
3558 * @method _onInit
3559 * @description "init" event handler for the menu.
3560 * @private
3561 * @param {String} p_sType String representing the name of the event that 
3562 * was fired.
3563 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3564 */
3565 _onInit: function (p_sType, p_aArgs) {
3566
3567     this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3568
3569     var bRootMenu = !this.parent,
3570         bLazyLoad = this.lazyLoad;
3571
3572
3573     /*
3574         Automatically initialize a menu's subtree if:
3575
3576         1) This is the root menu and lazyload is off
3577         
3578         2) This is the root menu, lazyload is on, but the menu is 
3579            already visible
3580
3581         3) This menu is a submenu and lazyload is off
3582     */
3583
3584
3585
3586     if (((bRootMenu && !bLazyLoad) || 
3587         (bRootMenu && (this.cfg.getProperty(_VISIBLE) || 
3588         this.cfg.getProperty(_POSITION) == _STATIC)) || 
3589         (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3590
3591         if (this.srcElement) {
3592
3593             this._initSubTree();
3594         
3595         }
3596
3597
3598         if (this.itemData) {
3599
3600             this.addItems(this.itemData);
3601
3602         }
3603     
3604     }
3605     else if (bLazyLoad) {
3606
3607         this.cfg.fireQueue();
3608     
3609     }
3610
3611 },
3612
3613
3614 /**
3615 * @method _onBeforeRender
3616 * @description "beforerender" event handler for the menu.  Appends all of the 
3617 * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying 
3618 * title elements to the body element of the menu.
3619 * @private
3620 * @param {String} p_sType String representing the name of the event that 
3621 * was fired.
3622 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3623 */
3624 _onBeforeRender: function (p_sType, p_aArgs) {
3625
3626     var oEl = this.element,
3627         nListElements = this._aListElements.length,
3628         bFirstList = true,
3629         i = 0,
3630         oUL,
3631         oGroupTitle;
3632
3633     if (nListElements > 0) {
3634
3635         do {
3636
3637             oUL = this._aListElements[i];
3638
3639             if (oUL) {
3640
3641                 if (bFirstList) {
3642         
3643                     Dom.addClass(oUL, _FIRST_OF_TYPE);
3644                     bFirstList = false;
3645         
3646                 }
3647
3648
3649                 if (!Dom.isAncestor(oEl, oUL)) {
3650
3651                     this.appendToBody(oUL);
3652
3653                 }
3654
3655
3656                 oGroupTitle = this._aGroupTitleElements[i];
3657
3658                 if (oGroupTitle) {
3659
3660                     if (!Dom.isAncestor(oEl, oGroupTitle)) {
3661
3662                         oUL.parentNode.insertBefore(oGroupTitle, oUL);
3663
3664                     }
3665
3666
3667                     Dom.addClass(oUL, _HAS_TITLE);
3668
3669                 }
3670
3671             }
3672
3673             i++;
3674
3675         }
3676         while (i < nListElements);
3677
3678     }
3679
3680 },
3681
3682
3683 /**
3684 * @method _onRender
3685 * @description "render" event handler for the menu.
3686 * @private
3687 * @param {String} p_sType String representing the name of the event that 
3688 * was fired.
3689 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3690 */
3691 _onRender: function (p_sType, p_aArgs) {
3692
3693     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { 
3694
3695         if (!this.cfg.getProperty(_VISIBLE)) {
3696
3697             this.positionOffScreen();
3698
3699         }
3700     
3701     }
3702
3703 },
3704
3705
3706
3707
3708
3709 /**
3710 * @method _onBeforeShow
3711 * @description "beforeshow" event handler for the menu.
3712 * @private
3713 * @param {String} p_sType String representing the name of the event that 
3714 * was fired.
3715 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3716 */
3717 _onBeforeShow: function (p_sType, p_aArgs) {
3718
3719     var nOptions,
3720         n,
3721         oSrcElement,
3722         oContainer = this.cfg.getProperty(_CONTAINER);
3723
3724
3725     if (this.lazyLoad && this.getItemGroups().length === 0) {
3726
3727         if (this.srcElement) {
3728         
3729             this._initSubTree();
3730
3731         }
3732
3733
3734         if (this.itemData) {
3735
3736             if (this.parent && this.parent.parent && 
3737                 this.parent.parent.srcElement && 
3738                 this.parent.parent.srcElement.tagName.toUpperCase() == 
3739                 _SELECT) {
3740
3741                 nOptions = this.itemData.length;
3742     
3743                 for(n=0; n<nOptions; n++) {
3744
3745                     if (this.itemData[n].tagName) {
3746
3747                         this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3748     
3749                     }
3750     
3751                 }
3752             
3753             }
3754             else {
3755
3756                 this.addItems(this.itemData);
3757             
3758             }
3759         
3760         }
3761
3762
3763         oSrcElement = this.srcElement;
3764
3765         if (oSrcElement) {
3766
3767             if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3768
3769                 if (Dom.inDocument(oSrcElement)) {
3770
3771                     this.render(oSrcElement.parentNode);
3772                 
3773                 }
3774                 else {
3775                 
3776                     this.render(oContainer);
3777                 
3778                 }
3779
3780             }
3781             else {
3782
3783                 this.render();
3784
3785             }
3786
3787         }
3788         else {
3789
3790             if (this.parent) {
3791
3792                 this.render(this.parent.element);     
3793
3794             }
3795             else {
3796
3797                 this.render(oContainer);
3798
3799             }                
3800
3801         }
3802
3803     }
3804
3805
3806
3807     var oParent = this.parent,
3808                 aAlignment;
3809
3810
3811     if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3812
3813         this.cfg.refireEvent(_XY);
3814    
3815     }
3816
3817
3818         if (oParent) {
3819
3820                 aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3821                 
3822                 this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3823                 this.align();
3824         
3825         }
3826
3827 },
3828
3829
3830 getConstrainedY: function (y) {
3831
3832         var oMenu = this,
3833         
3834                 aContext = oMenu.cfg.getProperty(_CONTEXT),
3835                 nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3836
3837                 nMaxHeight,
3838
3839                 oOverlapPositions = {
3840
3841                         "trbr": true,
3842                         "tlbl": true,
3843                         "bltl": true,
3844                         "brtr": true
3845
3846                 },
3847
3848                 bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3849         
3850                 oMenuEl = oMenu.element,
3851                 nMenuOffsetHeight = oMenuEl.offsetHeight,
3852         
3853                 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3854                 viewPortHeight = Dom.getViewportHeight(),
3855                 scrollY = Dom.getDocumentScrollTop(),
3856
3857                 bCanConstrain = 
3858                         (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3859
3860                 nAvailableHeight,
3861
3862                 oContextEl,
3863                 nContextElY,
3864                 nContextElHeight,
3865
3866                 bFlipped = false,
3867
3868                 nTopRegionHeight,
3869                 nBottomRegionHeight,
3870
3871                 topConstraint = scrollY + nViewportOffset,
3872                 bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
3873
3874                 yNew = y;
3875                 
3876
3877         var flipVertical = function () {
3878
3879                 var nNewY;
3880         
3881                 // The Menu is below the context element, flip it above
3882                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3883                         nNewY = (nContextElY - nMenuOffsetHeight);
3884                 }
3885                 else {  // The Menu is above the context element, flip it below
3886                         nNewY = (nContextElY + nContextElHeight);
3887                 }
3888
3889                 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3890                 
3891                 return nNewY;
3892         
3893         };
3894
3895
3896         /*
3897                  Uses the context element's position to calculate the availble height 
3898                  above and below it to display its corresponding Menu.
3899         */
3900
3901         var getDisplayRegionHeight = function () {
3902
3903                 // The Menu is below the context element
3904                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3905                         return (nBottomRegionHeight - nViewportOffset);                         
3906                 }
3907                 else {  // The Menu is above the context element
3908                         return (nTopRegionHeight - nViewportOffset);                            
3909                 }
3910
3911         };
3912
3913
3914         /*
3915                 Sets the Menu's "y" configuration property to the correct value based on its
3916                 current orientation.
3917         */ 
3918
3919         var alignY = function () {
3920
3921                 var nNewY;
3922
3923                 if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3924                         nNewY = (nContextElY + nContextElHeight);
3925                 }
3926                 else {  
3927                         nNewY = (nContextElY - oMenuEl.offsetHeight);
3928                 }
3929
3930                 oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3931         
3932         };
3933
3934
3935         //      Resets the maxheight of the Menu to the value set by the user
3936
3937         var resetMaxHeight = function () {
3938
3939                 oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3940
3941                 oMenu.hideEvent.unsubscribe(resetMaxHeight);
3942         
3943         };
3944
3945
3946         /*
3947                 Trys to place the Menu in the best possible position (either above or 
3948                 below its corresponding context element).
3949         */
3950
3951         var setVerticalPosition = function () {
3952
3953                 var nDisplayRegionHeight = getDisplayRegionHeight(),
3954                         bMenuHasItems = (oMenu.getItems().length > 0),
3955                         nMenuMinScrollHeight,
3956                         fnReturnVal;
3957
3958
3959                 if (nMenuOffsetHeight > nDisplayRegionHeight) {
3960
3961                         nMenuMinScrollHeight = 
3962                                 bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3963
3964
3965                         if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3966                                 nMaxHeight = nDisplayRegionHeight;
3967                         }
3968                         else {
3969                                 nMaxHeight = nInitialMaxHeight;
3970                         }
3971
3972
3973                         oMenu._setScrollHeight(nMaxHeight);
3974                         oMenu.hideEvent.subscribe(resetMaxHeight);
3975                         
3976
3977                         // Re-align the Menu since its height has just changed
3978                         // as a result of the setting of the maxheight property.
3979
3980                         alignY();
3981                         
3982
3983                         if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3984
3985                                 if (bFlipped) {
3986         
3987                                         /*
3988                                                  All possible positions and values for the "maxheight" 
3989                                                  configuration property have been tried, but none were 
3990                                                  successful, so fall back to the original size and position.
3991                                         */
3992
3993                                         flipVertical();
3994                                         
3995                                 }
3996                                 else {
3997         
3998                                         flipVertical();
3999
4000                                         bFlipped = true;
4001         
4002                                         fnReturnVal = setVerticalPosition();
4003         
4004                                 }
4005                                 
4006                         }
4007                 
4008                 }
4009                 else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
4010                 
4011                         oMenu._setScrollHeight(nInitialMaxHeight);
4012                         oMenu.hideEvent.subscribe(resetMaxHeight);
4013
4014                         // Re-align the Menu since its height has just changed
4015                         // as a result of the setting of the maxheight property.
4016
4017                         alignY();
4018                 
4019                 }
4020
4021                 return fnReturnVal;
4022
4023         };
4024
4025
4026         // Determine if the current value for the Menu's "y" configuration property will
4027         // result in the Menu being positioned outside the boundaries of the viewport
4028
4029         if (y < topConstraint || y  > bottomConstraint) {
4030
4031                 // The current value for the Menu's "y" configuration property WILL
4032                 // result in the Menu being positioned outside the boundaries of the viewport
4033
4034                 if (bCanConstrain) {
4035
4036                         if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
4037                 
4038                                 //      SOLUTION #1:
4039                                 //      If the "preventcontextoverlap" configuration property is set to "true", 
4040                                 //      try to flip and/or scroll the Menu to both keep it inside the boundaries of the 
4041                                 //      viewport AND from overlaping its context element (MenuItem or MenuBarItem).
4042
4043                                 oContextEl = aContext[0];
4044                                 nContextElHeight = oContextEl.offsetHeight;
4045                                 nContextElY = (Dom.getY(oContextEl) - scrollY);
4046         
4047                                 nTopRegionHeight = nContextElY;
4048                                 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
4049         
4050                                 setVerticalPosition();
4051                                 
4052                                 yNew = oMenu.cfg.getProperty(_Y);
4053                 
4054                         }
4055                         else if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
4056                                 nMenuOffsetHeight >= viewPortHeight) {
4057
4058                                 //      SOLUTION #2:
4059                                 //      If the Menu exceeds the height of the viewport, introduce scroll bars
4060                                 //      to keep the Menu inside the boundaries of the viewport
4061
4062                                 nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
4063                 
4064                                 if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
4065                 
4066                                         oMenu._setScrollHeight(nAvailableHeight);
4067                                         oMenu.hideEvent.subscribe(resetMaxHeight);
4068                 
4069                                         alignY();
4070                                         
4071                                         yNew = oMenu.cfg.getProperty(_Y);
4072                                 
4073                                 }
4074                 
4075                         }       
4076                         else {
4077
4078                                 //      SOLUTION #3:
4079                         
4080                                 if (y < topConstraint) {
4081                                         yNew  = topConstraint;
4082                                 } else if (y  > bottomConstraint) {
4083                                         yNew  = bottomConstraint;
4084                                 }                               
4085                         
4086                         }
4087
4088                 }
4089                 else {
4090                         //      The "y" configuration property cannot be set to a value that will keep
4091                         //      entire Menu inside the boundary of the viewport.  Therefore, set  
4092                         //      the "y" configuration property to scrollY to keep as much of the 
4093                         //      Menu inside the viewport as possible.
4094                         yNew = nViewportOffset + scrollY;
4095                 }       
4096
4097         }
4098
4099         return yNew;
4100
4101 },
4102
4103
4104 /**
4105 * @method _onHide
4106 * @description "hide" event handler for the menu.
4107 * @private
4108 * @param {String} p_sType String representing the name of the event that 
4109 * was fired.
4110 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4111 */
4112 _onHide: function (p_sType, p_aArgs) {
4113
4114         if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4115         
4116                 this.positionOffScreen();
4117         
4118         }
4119
4120 },
4121
4122
4123 /**
4124 * @method _onShow
4125 * @description "show" event handler for the menu.
4126 * @private
4127 * @param {String} p_sType String representing the name of the event that 
4128 * was fired.
4129 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4130 */
4131 _onShow: function (p_sType, p_aArgs) {
4132
4133     var oParent = this.parent,
4134         oParentMenu,
4135                 oElement,
4136                 nOffsetWidth,
4137                 sWidth;        
4138
4139
4140     function disableAutoSubmenuDisplay(p_oEvent) {
4141
4142         var oTarget;
4143
4144         if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4145
4146             /*  
4147                 Set the "autosubmenudisplay" to "false" if the user
4148                 clicks outside the menu bar.
4149             */
4150
4151             oTarget = Event.getTarget(p_oEvent);
4152
4153             if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4154
4155                 oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4156
4157                 Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4158                 Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4159
4160             }
4161         
4162         }
4163
4164     }
4165
4166
4167         function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4168         
4169                 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4170                 this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4171         
4172         }
4173
4174
4175     if (oParent) {
4176
4177         oParentMenu = oParent.parent;
4178
4179
4180         if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) && 
4181             (oParentMenu instanceof YAHOO.widget.MenuBar || 
4182             oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4183
4184             oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4185
4186             Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);                             
4187             Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4188
4189         }
4190
4191
4192                 //      The following fixes an issue with the selected state of a MenuItem 
4193                 //      not rendering correctly when a submenu is aligned to the left of
4194                 //      its parent Menu instance.
4195
4196                 if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) && 
4197                         (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4198
4199                         oElement = this.element;
4200                         nOffsetWidth = oElement.offsetWidth;
4201                         
4202                         /*
4203                                 Measuring the difference of the offsetWidth before and after
4204                                 setting the "width" style attribute allows us to compute the 
4205                                 about of padding and borders applied to the element, which in 
4206                                 turn allows us to set the "width" property correctly.
4207                         */
4208                         
4209                         oElement.style.width = nOffsetWidth + _PX;
4210                         
4211                         sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4212                         
4213                         this.cfg.setProperty(_WIDTH, sWidth);
4214                 
4215                         this.hideEvent.subscribe(onSubmenuHide, sWidth);
4216                 
4217                 }
4218
4219     }
4220
4221
4222         /*
4223                 Dynamically positioned, root Menus focus themselves when visible, and 
4224                 will then, when hidden, restore focus to the UI control that had focus 
4225                 before the Menu was made visible.
4226         */ 
4227
4228         if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4229
4230                 this._focusedElement = oFocusedElement;
4231                 
4232                 this.focus();
4233         
4234         }
4235
4236
4237 },
4238
4239
4240 /**
4241 * @method _onBeforeHide
4242 * @description "beforehide" event handler for the menu.
4243 * @private
4244 * @param {String} p_sType String representing the name of the event that 
4245 * was fired.
4246 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4247 */
4248 _onBeforeHide: function (p_sType, p_aArgs) {
4249
4250     var oActiveItem = this.activeItem,
4251         oRoot = this.getRoot(),
4252         oConfig,
4253         oSubmenu;
4254
4255
4256     if (oActiveItem) {
4257
4258         oConfig = oActiveItem.cfg;
4259
4260         oConfig.setProperty(_SELECTED, false);
4261
4262         oSubmenu = oConfig.getProperty(_SUBMENU);
4263
4264         if (oSubmenu) {
4265
4266             oSubmenu.hide();
4267
4268         }
4269
4270     }
4271
4272
4273         /*
4274                 Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.  
4275                 For this reason, it is necessary to maintain the focused state in a private property 
4276                 so that the _onMouseOver event handler is able to determined whether or not to set focus
4277                 to MenuItems as the user is moving the mouse.
4278         */ 
4279
4280         if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4281
4282                 oRoot._hasFocus = this.hasFocus();
4283         
4284         }
4285
4286
4287     if (oRoot == this) {
4288
4289         oRoot.blur();
4290     
4291     }
4292
4293 },
4294
4295
4296 /**
4297 * @method _onParentMenuConfigChange
4298 * @description "configchange" event handler for a submenu.
4299 * @private
4300 * @param {String} p_sType String representing the name of the event that 
4301 * was fired.
4302 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4303 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4304 * subscribed to the event.
4305 */
4306 _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4307     
4308     var sPropertyName = p_aArgs[0][0],
4309         oPropertyValue = p_aArgs[0][1];
4310
4311     switch(sPropertyName) {
4312
4313         case _IFRAME:
4314         case _CONSTRAIN_TO_VIEWPORT:
4315         case _HIDE_DELAY:
4316         case _SHOW_DELAY:
4317         case _SUBMENU_HIDE_DELAY:
4318         case _CLICK_TO_HIDE:
4319         case _EFFECT:
4320         case _CLASSNAME:
4321         case _SCROLL_INCREMENT:
4322         case _MAX_HEIGHT:
4323         case _MIN_SCROLL_HEIGHT:
4324         case _MONITOR_RESIZE:
4325         case _SHADOW:
4326         case _PREVENT_CONTEXT_OVERLAP:
4327                 case _KEEP_OPEN:
4328
4329             p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4330                 
4331         break;
4332         
4333         case _SUBMENU_ALIGNMENT:
4334
4335                         if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4336                 
4337                                 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4338                 
4339                         }
4340         
4341         break;
4342         
4343     }
4344     
4345 },
4346
4347
4348 /**
4349 * @method _onParentMenuRender
4350 * @description "render" event handler for a submenu.  Renders a  
4351 * submenu in response to the firing of its parent's "render" event.
4352 * @private
4353 * @param {String} p_sType String representing the name of the event that 
4354 * was fired.
4355 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4356 * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4357 * subscribed to the event.
4358 */
4359 _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4360
4361     var oParentMenu = p_oSubmenu.parent.parent,
4362         oParentCfg = oParentMenu.cfg,
4363
4364         oConfig = {
4365
4366             constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4367
4368             xy: [0,0],
4369
4370             clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4371                 
4372             effect: oParentCfg.getProperty(_EFFECT),
4373
4374             showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4375             
4376             hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4377
4378             submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4379
4380             classname: oParentCfg.getProperty(_CLASSNAME),
4381             
4382             scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4383             
4384                         maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4385
4386             minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4387             
4388             iframe: oParentCfg.getProperty(_IFRAME),
4389             
4390             shadow: oParentCfg.getProperty(_SHADOW),
4391
4392                         preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4393             
4394             monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
4395
4396                         keepopen: oParentCfg.getProperty(_KEEP_OPEN)
4397
4398         },
4399         
4400         oLI;
4401
4402
4403         
4404         if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4405
4406                 oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4407
4408         }
4409
4410
4411     p_oSubmenu.cfg.applyConfig(oConfig);
4412
4413
4414     if (!this.lazyLoad) {
4415
4416         oLI = this.parent.element;
4417
4418         if (this.element.parentNode == oLI) {
4419     
4420             this.render();
4421     
4422         }
4423         else {
4424
4425             this.render(oLI);
4426     
4427         }
4428
4429     }
4430     
4431 },
4432
4433
4434 /**
4435 * @method _onMenuItemDestroy
4436 * @description "destroy" event handler for the menu's items.
4437 * @private
4438 * @param {String} p_sType String representing the name of the event 
4439 * that was fired.
4440 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4441 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4442 * that fired the event.
4443 */
4444 _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4445
4446     this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4447
4448 },
4449
4450
4451 /**
4452 * @method _onMenuItemConfigChange
4453 * @description "configchange" event handler for the menu's items.
4454 * @private
4455 * @param {String} p_sType String representing the name of the event that 
4456 * was fired.
4457 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4458 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4459 * that fired the event.
4460 */
4461 _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4462
4463     var sPropertyName = p_aArgs[0][0],
4464         oPropertyValue = p_aArgs[0][1],
4465         oSubmenu;
4466
4467
4468     switch(sPropertyName) {
4469
4470         case _SELECTED:
4471
4472             if (oPropertyValue === true) {
4473
4474                 this.activeItem = p_oItem;
4475             
4476             }
4477
4478         break;
4479
4480         case _SUBMENU:
4481
4482             oSubmenu = p_aArgs[0][1];
4483
4484             if (oSubmenu) {
4485
4486                 this._configureSubmenu(p_oItem);
4487
4488             }
4489
4490         break;
4491
4492     }
4493
4494 },
4495
4496
4497
4498 // Public event handlers for configuration properties
4499
4500
4501 /**
4502 * @method configVisible
4503 * @description Event handler for when the "visible" configuration property 
4504 * the menu changes.
4505 * @param {String} p_sType String representing the name of the event that 
4506 * was fired.
4507 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4508 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4509 * fired the event.
4510 */
4511 configVisible: function (p_sType, p_aArgs, p_oMenu) {
4512
4513     var bVisible,
4514         sDisplay;
4515
4516     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4517
4518         Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4519
4520     }
4521     else {
4522
4523         bVisible = p_aArgs[0];
4524         sDisplay = Dom.getStyle(this.element, _DISPLAY);
4525
4526         Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4527
4528         if (bVisible) {
4529
4530             if (sDisplay != _BLOCK) {
4531                 this.beforeShowEvent.fire();
4532                 Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4533                 this.showEvent.fire();
4534             }
4535         
4536         }
4537         else {
4538
4539                         if (sDisplay == _BLOCK) {
4540                                 this.beforeHideEvent.fire();
4541                                 Dom.setStyle(this.element, _DISPLAY, _NONE);
4542                                 this.hideEvent.fire();
4543                         }
4544         
4545         }
4546
4547     }
4548
4549 },
4550
4551
4552 /**
4553 * @method configPosition
4554 * @description Event handler for when the "position" configuration property 
4555 * of the menu changes.
4556 * @param {String} p_sType String representing the name of the event that 
4557 * was fired.
4558 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4559 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4560 * fired the event.
4561 */
4562 configPosition: function (p_sType, p_aArgs, p_oMenu) {
4563
4564     var oElement = this.element,
4565         sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4566         oCfg = this.cfg,
4567         nZIndex;
4568
4569
4570     Dom.setStyle(oElement, _POSITION, sCSSPosition);
4571
4572
4573     if (sCSSPosition == _STATIC) {
4574
4575         // Statically positioned menus are visible by default
4576         
4577         Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4578
4579         oCfg.setProperty(_VISIBLE, true);
4580
4581     }
4582     else {
4583
4584         /*
4585             Even though the "visible" property is queued to 
4586             "false" by default, we need to set the "visibility" property to 
4587             "hidden" since Overlay's "configVisible" implementation checks the 
4588             element's "visibility" style property before deciding whether 
4589             or not to show an Overlay instance.
4590         */
4591
4592         Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4593     
4594     }
4595
4596          
4597      if (sCSSPosition == _ABSOLUTE) {    
4598          
4599          nZIndex = oCfg.getProperty(_ZINDEX);
4600          
4601          if (!nZIndex || nZIndex === 0) {        
4602          
4603              oCfg.setProperty(_ZINDEX, 1);       
4604          
4605          }       
4606          
4607      }
4608
4609 },
4610
4611
4612 /**
4613 * @method configIframe
4614 * @description Event handler for when the "iframe" configuration property of 
4615 * the menu changes.
4616 * @param {String} p_sType String representing the name of the event that 
4617 * was fired.
4618 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4619 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4620 * fired the event.
4621 */
4622 configIframe: function (p_sType, p_aArgs, p_oMenu) {    
4623
4624     if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4625
4626         Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4627
4628     }
4629
4630 },
4631
4632
4633 /**
4634 * @method configHideDelay
4635 * @description Event handler for when the "hidedelay" configuration property 
4636 * of the menu changes.
4637 * @param {String} p_sType String representing the name of the event that 
4638 * was fired.
4639 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4640 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4641 * fired the event.
4642 */
4643 configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4644
4645     var nHideDelay = p_aArgs[0];
4646
4647         this._useHideDelay = (nHideDelay > 0);
4648
4649 },
4650
4651
4652 /**
4653 * @method configContainer
4654 * @description Event handler for when the "container" configuration property 
4655 * of the menu changes.
4656 * @param {String} p_sType String representing the name of the event that 
4657 * was fired.
4658 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4659 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4660 * fired the event.
4661 */
4662 configContainer: function (p_sType, p_aArgs, p_oMenu) {
4663
4664         var oElement = p_aArgs[0];
4665
4666         if (Lang.isString(oElement)) {
4667
4668         this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4669
4670         }
4671
4672 },
4673
4674
4675 /**
4676 * @method _clearSetWidthFlag
4677 * @description Change event listener for the "width" configuration property.  This listener is 
4678 * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and 
4679 * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property 
4680 * is changed after it was set by the "_setScrollHeight" method.  If the "_widthSetForScroll" 
4681 * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down 
4682 * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4683 * @private
4684 */
4685 _clearSetWidthFlag: function () {
4686
4687         this._widthSetForScroll = false;
4688         
4689         this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4690
4691 },
4692
4693
4694 /**
4695 * @method _setScrollHeight
4696 * @description 
4697 * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4698 * @private
4699 */
4700 _setScrollHeight: function (p_nScrollHeight) {
4701
4702     var nScrollHeight = p_nScrollHeight,
4703                 bRefireIFrameAndShadow = false,
4704                 bSetWidth = false,
4705         oElement,
4706         oBody,
4707         oHeader,
4708         oFooter,
4709         fnMouseOver,
4710         fnMouseOut,
4711         nMinScrollHeight,
4712         nHeight,
4713         nOffsetWidth,
4714         sWidth;
4715
4716
4717         if (this.getItems().length > 0) {
4718         
4719         oElement = this.element;
4720         oBody = this.body;
4721         oHeader = this.header;
4722         oFooter = this.footer;
4723         fnMouseOver = this._onScrollTargetMouseOver;
4724         fnMouseOut = this._onScrollTargetMouseOut;
4725         nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4726
4727
4728                 if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4729                 
4730                         nScrollHeight = nMinScrollHeight;
4731                 
4732                 }
4733
4734
4735                 Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4736                 Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4737                 oBody.scrollTop = 0;
4738
4739
4740                 //      Need to set a width for the Menu to fix the following problems in 
4741                 //      Firefox 2 and IE:
4742
4743                 //      #1) Scrolled Menus will render at 1px wide in Firefox 2
4744
4745                 //      #2) There is a bug in gecko-based browsers where an element whose 
4746                 //      "position" property is set to "absolute" and "overflow" property is 
4747                 //      set to "hidden" will not render at the correct width when its 
4748                 //      offsetParent's "position" property is also set to "absolute."  It is 
4749                 //      possible to work around this bug by specifying a value for the width 
4750                 //      property in addition to overflow.
4751
4752                 //      #3) In IE it is necessary to give the Menu a width before the 
4753                 //      scrollbars are rendered to prevent the Menu from rendering with a 
4754                 //      width that is 100% of the browser viewport.
4755         
4756                 bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4757
4758                 if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4759
4760                         nOffsetWidth = oElement.offsetWidth;
4761         
4762                         /*
4763                                 Measuring the difference of the offsetWidth before and after
4764                                 setting the "width" style attribute allows us to compute the 
4765                                 about of padding and borders applied to the element, which in 
4766                                 turn allows us to set the "width" property correctly.
4767                         */
4768                         
4769                         oElement.style.width = nOffsetWidth + _PX;
4770         
4771                         sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4772
4773
4774                         this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4775
4776                         YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.", 
4777                                 "info", this.toString());
4778
4779                         this.cfg.setProperty(_WIDTH, sWidth);
4780
4781
4782                         /*
4783                                 Set a flag (_widthSetForScroll) to maintain some history regarding how the 
4784                                 "width" configuration property was set.  If the "width" configuration property 
4785                                 is set by something other than the "_setScrollHeight" method, it will be 
4786                                 necessary to maintain that new value and not clear the width if scrolling 
4787                                 is turned off.
4788                         */
4789
4790                         this._widthSetForScroll = true;
4791
4792                         this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4793         
4794                 }
4795         
4796         
4797                 if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4798         
4799                         YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
4800         
4801                         this.setHeader(_NON_BREAKING_SPACE);
4802                         this.setFooter(_NON_BREAKING_SPACE);
4803         
4804                         oHeader = this.header;
4805                         oFooter = this.footer;
4806         
4807                         Dom.addClass(oHeader, _TOP_SCROLLBAR);
4808                         Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4809                         
4810                         oElement.insertBefore(oHeader, oBody);
4811                         oElement.appendChild(oFooter);
4812                 
4813                 }
4814         
4815         
4816                 nHeight = nScrollHeight;
4817         
4818         
4819                 if (oHeader && oFooter) {
4820                         nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4821                 }
4822         
4823         
4824                 if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4825
4826                         YAHOO.log("Setting up styles and event handlers for scrolling.", 
4827                                 "info", this.toString());
4828         
4829                         Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4830                         Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4831
4832                         if (!this._hasScrollEventHandlers) {
4833         
4834                                 Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4835                                 Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4836                                 Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4837                                 Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4838         
4839                                 this._hasScrollEventHandlers = true;
4840         
4841                         }
4842         
4843                         this._disableScrollHeader();
4844                         this._enableScrollFooter();
4845                         
4846                         bRefireIFrameAndShadow = true;                  
4847         
4848                 }
4849                 else if (oHeader && oFooter) {
4850
4851                         YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
4852         
4853
4854                         /*
4855                                 Only clear the the "width" configuration property if it was set the 
4856                                 "_setScrollHeight" method and wasn't changed by some other means after it was set.
4857                         */      
4858         
4859                         if (this._widthSetForScroll) {
4860         
4861                                 YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
4862
4863                                 this._widthSetForScroll = false;
4864
4865                                 this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4866         
4867                                 this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4868                         
4869                         }
4870         
4871         
4872                         this._enableScrollHeader();
4873                         this._enableScrollFooter();
4874         
4875                         if (this._hasScrollEventHandlers) {
4876         
4877                                 Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4878                                 Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4879                                 Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4880                                 Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4881
4882                                 this._hasScrollEventHandlers = false;
4883         
4884                         }
4885
4886                         oElement.removeChild(oHeader);
4887                         oElement.removeChild(oFooter);
4888         
4889                         this.header = null;
4890                         this.footer = null;
4891                         
4892                         bRefireIFrameAndShadow = true;
4893                 
4894                 }
4895
4896
4897                 if (bRefireIFrameAndShadow) {
4898         
4899                         this.cfg.refireEvent(_IFRAME);
4900                         this.cfg.refireEvent(_SHADOW);
4901                 
4902                 }
4903         
4904         }
4905
4906 },
4907
4908
4909 /**
4910 * @method _setMaxHeight
4911 * @description "renderEvent" handler used to defer the setting of the 
4912 * "maxheight" configuration property until the menu is rendered in lazy 
4913 * load scenarios.
4914 * @param {String} p_sType The name of the event that was fired.
4915 * @param {Array} p_aArgs Collection of arguments sent when the event 
4916 * was fired.
4917 * @param {Number} p_nMaxHeight Number representing the value to set for the 
4918 * "maxheight" configuration property.
4919 * @private
4920 */
4921 _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4922
4923     this._setScrollHeight(p_nMaxHeight);
4924     this.renderEvent.unsubscribe(this._setMaxHeight);
4925
4926 },
4927
4928
4929 /**
4930 * @method configMaxHeight
4931 * @description Event handler for when the "maxheight" configuration property of 
4932 * a Menu changes.
4933 * @param {String} p_sType The name of the event that was fired.
4934 * @param {Array} p_aArgs Collection of arguments sent when the event 
4935 * was fired.
4936 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4937 * the event.
4938 */
4939 configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4940
4941         var nMaxHeight = p_aArgs[0];
4942
4943         if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4944         
4945                 this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4946
4947         }
4948         else {
4949
4950                 this._setScrollHeight(nMaxHeight);
4951         
4952         }
4953
4954 },
4955
4956
4957 /**
4958 * @method configClassName
4959 * @description Event handler for when the "classname" configuration property of 
4960 * a menu changes.
4961 * @param {String} p_sType The name of the event that was fired.
4962 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4963 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4964 */
4965 configClassName: function (p_sType, p_aArgs, p_oMenu) {
4966
4967     var sClassName = p_aArgs[0];
4968
4969     if (this._sClassName) {
4970
4971         Dom.removeClass(this.element, this._sClassName);
4972
4973     }
4974
4975     Dom.addClass(this.element, sClassName);
4976     this._sClassName = sClassName;
4977
4978 },
4979
4980
4981 /**
4982 * @method _onItemAdded
4983 * @description "itemadded" event handler for a Menu instance.
4984 * @private
4985 * @param {String} p_sType The name of the event that was fired.
4986 * @param {Array} p_aArgs Collection of arguments sent when the event 
4987 * was fired.
4988 */
4989 _onItemAdded: function (p_sType, p_aArgs) {
4990
4991     var oItem = p_aArgs[0];
4992     
4993     if (oItem) {
4994
4995         oItem.cfg.setProperty(_DISABLED, true);
4996     
4997     }
4998
4999 },
5000
5001
5002 /**
5003 * @method configDisabled
5004 * @description Event handler for when the "disabled" configuration property of 
5005 * a menu changes.
5006 * @param {String} p_sType The name of the event that was fired.
5007 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5008 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5009 */
5010 configDisabled: function (p_sType, p_aArgs, p_oMenu) {
5011
5012     var bDisabled = p_aArgs[0],
5013         aItems = this.getItems(),
5014         nItems,
5015         i;
5016
5017     if (Lang.isArray(aItems)) {
5018
5019         nItems = aItems.length;
5020     
5021         if (nItems > 0) {
5022         
5023             i = nItems - 1;
5024     
5025             do {
5026     
5027                 aItems[i].cfg.setProperty(_DISABLED, bDisabled);
5028             
5029             }
5030             while (i--);
5031         
5032         }
5033
5034
5035         if (bDisabled) {
5036
5037             this.clearActiveItem(true);
5038
5039             Dom.addClass(this.element, _DISABLED);
5040
5041             this.itemAddedEvent.subscribe(this._onItemAdded);
5042
5043         }
5044         else {
5045
5046             Dom.removeClass(this.element, _DISABLED);
5047
5048             this.itemAddedEvent.unsubscribe(this._onItemAdded);
5049
5050         }
5051         
5052     }
5053
5054 },
5055
5056
5057 /**
5058 * @method configShadow
5059 * @description Event handler for when the "shadow" configuration property of 
5060 * a menu changes.
5061 * @param {String} p_sType The name of the event that was fired.
5062 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5063 * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5064 */
5065 configShadow: function (p_sType, p_aArgs, p_oMenu) {
5066
5067     var sizeShadow = function () {
5068
5069         var oElement = this.element,
5070             oShadow = this._shadow;
5071     
5072         if (oShadow && oElement) {
5073
5074                         // Clear the previous width
5075
5076                         if (oShadow.style.width && oShadow.style.height) {
5077                         
5078                                 oShadow.style.width = _EMPTY_STRING;
5079                                 oShadow.style.height = _EMPTY_STRING;
5080                         
5081                         }
5082
5083             oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
5084             oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
5085             
5086         }
5087     
5088     };
5089
5090
5091     var replaceShadow = function () {
5092
5093         this.element.appendChild(this._shadow);
5094
5095     };
5096
5097
5098     var addShadowVisibleClass = function () {
5099     
5100         Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5101     
5102     };
5103     
5104
5105     var removeShadowVisibleClass = function () {
5106
5107         Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5108     
5109     };
5110
5111
5112     var createShadow = function () {
5113
5114         var oShadow = this._shadow,
5115             oElement;
5116
5117         if (!oShadow) {
5118
5119             oElement = this.element;
5120
5121
5122             if (!m_oShadowTemplate) {
5123
5124                 m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5125                 m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5126             
5127             }
5128
5129             oShadow = m_oShadowTemplate.cloneNode(false);
5130
5131             oElement.appendChild(oShadow);
5132             
5133             this._shadow = oShadow;
5134
5135             this.beforeShowEvent.subscribe(addShadowVisibleClass);
5136             this.beforeHideEvent.subscribe(removeShadowVisibleClass);
5137
5138
5139             if (UA.ie) {
5140         
5141                 /*
5142                      Need to call sizeShadow & syncIframe via setTimeout for 
5143                      IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode 
5144                      or the shadow and iframe shim will not be sized and 
5145                      positioned properly.
5146                 */
5147         
5148                                 Lang.later(0, this, function () {
5149
5150                     sizeShadow.call(this); 
5151                     this.syncIframe();
5152                                 
5153                                 });
5154
5155
5156                 this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
5157                 this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
5158                 this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
5159                 this.changeContentEvent.subscribe(sizeShadow);
5160
5161                 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5162                 
5163                 this.destroyEvent.subscribe(function () {
5164                 
5165                     Module.textResizeEvent.unsubscribe(sizeShadow, this);
5166                 
5167                 });
5168         
5169             }
5170
5171             this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
5172
5173         }
5174
5175     };
5176
5177
5178     var onBeforeShow = function () {
5179
5180         if (this._shadow) {
5181
5182                         // If called because the "shadow" event was refired - just append again and resize
5183                         
5184                         replaceShadow.call(this);
5185                         
5186                         if (UA.ie) {
5187                                 sizeShadow.call(this);
5188                         }
5189         
5190         }
5191         else {
5192     
5193                 createShadow.call(this);
5194         
5195         }
5196
5197         this.beforeShowEvent.unsubscribe(onBeforeShow);
5198     
5199     };
5200
5201
5202         var bShadow = p_aArgs[0];
5203
5204
5205     if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5206
5207         if (this.cfg.getProperty(_VISIBLE)) {
5208
5209                         if (this._shadow) {
5210
5211                                 // If the "shadow" event was refired - just append again and resize
5212                                 
5213                                 replaceShadow.call(this);
5214                                 
5215                                 if (UA.ie) {
5216                                         sizeShadow.call(this);
5217                                 }
5218                                 
5219                         } 
5220                         else {
5221                 createShadow.call(this);
5222             }
5223         
5224         }
5225         else {
5226
5227             this.beforeShowEvent.subscribe(onBeforeShow);
5228         
5229         }
5230     
5231     }
5232     
5233 },
5234
5235
5236
5237 // Public methods
5238
5239
5240 /**
5241 * @method initEvents
5242 * @description Initializes the custom events for the menu.
5243 */
5244 initEvents: function () {
5245
5246         Menu.superclass.initEvents.call(this);
5247
5248     // Create custom events
5249
5250         var i = EVENT_TYPES.length - 1,
5251                 aEventData,
5252                 oCustomEvent;
5253
5254
5255         do {
5256
5257                 aEventData = EVENT_TYPES[i];
5258
5259                 oCustomEvent = this.createEvent(aEventData[1]);
5260                 oCustomEvent.signature = CustomEvent.LIST;
5261                 
5262                 this[aEventData[0]] = oCustomEvent;
5263
5264         }
5265         while (i--);
5266
5267 },
5268
5269
5270 /**
5271 * @method positionOffScreen
5272 * @description Positions the menu outside of the boundaries of the browser's 
5273 * viewport.  Called automatically when a menu is hidden to ensure that 
5274 * it doesn't force the browser to render uncessary scrollbars.
5275 */
5276 positionOffScreen: function () {
5277
5278     var oIFrame = this.iframe,
5279         oElement = this.element,
5280         sPos = this.OFF_SCREEN_POSITION;
5281     
5282     oElement.style.top = _EMPTY_STRING;
5283     oElement.style.left = _EMPTY_STRING;
5284     
5285     if (oIFrame) {
5286
5287                 oIFrame.style.top = sPos;
5288                 oIFrame.style.left = sPos;
5289     
5290     }
5291
5292 },
5293
5294
5295 /**
5296 * @method getRoot
5297 * @description Finds the menu's root menu.
5298 */
5299 getRoot: function () {
5300
5301     var oItem = this.parent,
5302         oParentMenu,
5303         returnVal;
5304
5305     if (oItem) {
5306
5307         oParentMenu = oItem.parent;
5308
5309         returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5310
5311     }
5312     else {
5313     
5314         returnVal = this;
5315     
5316     }
5317     
5318     return returnVal;
5319
5320 },
5321
5322
5323 /**
5324 * @method toString
5325 * @description Returns a string representing the menu.
5326 * @return {String}
5327 */
5328 toString: function () {
5329
5330     var sReturnVal = _MENU,
5331         sId = this.id;
5332
5333     if (sId) {
5334
5335         sReturnVal += (_SPACE + sId);
5336     
5337     }
5338
5339     return sReturnVal;
5340
5341 },
5342
5343
5344 /**
5345 * @method setItemGroupTitle
5346 * @description Sets the title of a group of menu items.
5347 * @param {String} p_sGroupTitle String specifying the title of the group.
5348 * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5349 * the title belongs.
5350 */
5351 setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5352
5353     var nGroupIndex,
5354         oTitle,
5355         i,
5356         nFirstIndex;
5357         
5358     if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5359
5360         nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5361         oTitle = this._aGroupTitleElements[nGroupIndex];
5362
5363
5364         if (oTitle) {
5365
5366             oTitle.innerHTML = p_sGroupTitle;
5367             
5368         }
5369         else {
5370
5371             oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5372                     
5373             oTitle.innerHTML = p_sGroupTitle;
5374
5375             this._aGroupTitleElements[nGroupIndex] = oTitle;
5376
5377         }
5378
5379
5380         i = this._aGroupTitleElements.length - 1;
5381
5382         do {
5383
5384             if (this._aGroupTitleElements[i]) {
5385
5386                 Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5387
5388                 nFirstIndex = i;
5389
5390             }
5391
5392         }
5393         while (i--);
5394
5395
5396         if (nFirstIndex !== null) {
5397
5398             Dom.addClass(this._aGroupTitleElements[nFirstIndex], 
5399                 _FIRST_OF_TYPE);
5400
5401         }
5402
5403         this.changeContentEvent.fire();
5404
5405     }
5406
5407 },
5408
5409
5410
5411 /**
5412 * @method addItem
5413 * @description Appends an item to the menu.
5414 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5415 * instance to be added to the menu.
5416 * @param {String} p_oItem String specifying the text of the item to be added 
5417 * to the menu.
5418 * @param {Object} p_oItem Object literal containing a set of menu item 
5419 * configuration properties.
5420 * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5421 * which the item belongs.
5422 * @return {YAHOO.widget.MenuItem}
5423 */
5424 addItem: function (p_oItem, p_nGroupIndex) {
5425
5426         return this._addItemToGroup(p_nGroupIndex, p_oItem);
5427
5428 },
5429
5430
5431 /**
5432 * @method addItems
5433 * @description Adds an array of items to the menu.
5434 * @param {Array} p_aItems Array of items to be added to the menu.  The array 
5435 * can contain strings specifying the text for each item to be created, object
5436 * literals specifying each of the menu item configuration properties, 
5437 * or MenuItem instances.
5438 * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5439 * which the items belongs.
5440 * @return {Array}
5441 */
5442 addItems: function (p_aItems, p_nGroupIndex) {
5443
5444     var nItems,
5445         aItems,
5446         oItem,
5447         i,
5448         returnVal;
5449
5450
5451     if (Lang.isArray(p_aItems)) {
5452
5453         nItems = p_aItems.length;
5454         aItems = [];
5455
5456         for(i=0; i<nItems; i++) {
5457
5458             oItem = p_aItems[i];
5459
5460             if (oItem) {
5461
5462                 if (Lang.isArray(oItem)) {
5463     
5464                     aItems[aItems.length] = this.addItems(oItem, i);
5465     
5466                 }
5467                 else {
5468     
5469                     aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5470                 
5471                 }
5472
5473             }
5474     
5475         }
5476
5477
5478         if (aItems.length) {
5479         
5480             returnVal = aItems;
5481         
5482         }
5483
5484     }
5485
5486         return returnVal;
5487
5488 },
5489
5490
5491 /**
5492 * @method insertItem
5493 * @description Inserts an item into the menu at the specified index.
5494 * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5495 * instance to be added to the menu.
5496 * @param {String} p_oItem String specifying the text of the item to be added 
5497 * to the menu.
5498 * @param {Object} p_oItem Object literal containing a set of menu item 
5499 * configuration properties.
5500 * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5501 * the item should be added.
5502 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5503 * the item belongs.
5504 * @return {YAHOO.widget.MenuItem}
5505 */
5506 insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5507     
5508         return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5509
5510 },
5511
5512
5513 /**
5514 * @method removeItem
5515 * @description Removes the specified item from the menu.
5516 * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem 
5517 * instance to be removed from the menu.
5518 * @param {Number} p_oObject Number specifying the index of the item 
5519 * to be removed.
5520 * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5521 * which the item belongs.
5522 * @return {YAHOO.widget.MenuItem}
5523 */
5524 removeItem: function (p_oObject, p_nGroupIndex) {
5525
5526     var oItem,
5527         returnVal;
5528     
5529     if (!Lang.isUndefined(p_oObject)) {
5530
5531         if (p_oObject instanceof YAHOO.widget.MenuItem) {
5532
5533             oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);           
5534
5535         }
5536         else if (Lang.isNumber(p_oObject)) {
5537
5538             oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5539
5540         }
5541
5542         if (oItem) {
5543
5544             oItem.destroy();
5545
5546             YAHOO.log("Item removed." + 
5547                 " Text: " + oItem.cfg.getProperty("text") + ", " + 
5548                 " Index: " + oItem.index + ", " + 
5549                 " Group Index: " + oItem.groupIndex, "info", this.toString());
5550
5551             returnVal = oItem;
5552
5553         }
5554
5555     }
5556
5557         return returnVal;
5558
5559 },
5560
5561
5562 /**
5563 * @method getItems
5564 * @description Returns an array of all of the items in the menu.
5565 * @return {Array}
5566 */
5567 getItems: function () {
5568
5569     var aGroups = this._aItemGroups,
5570         nGroups,
5571         returnVal,
5572         aItems = [];
5573
5574
5575     if (Lang.isArray(aGroups)) {
5576
5577         nGroups = aGroups.length;
5578
5579         returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5580
5581     }
5582
5583         return returnVal;
5584
5585 },
5586
5587
5588 /**
5589 * @method getItemGroups
5590 * @description Multi-dimensional Array representing the menu items as they 
5591 * are grouped in the menu.
5592 * @return {Array}
5593 */        
5594 getItemGroups: function () {
5595
5596     return this._aItemGroups;
5597
5598 },
5599
5600
5601 /**
5602 * @method getItem
5603 * @description Returns the item at the specified index.
5604 * @param {Number} p_nItemIndex Number indicating the ordinal position of the 
5605 * item to be retrieved.
5606 * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5607 * the item belongs.
5608 * @return {YAHOO.widget.MenuItem}
5609 */
5610 getItem: function (p_nItemIndex, p_nGroupIndex) {
5611     
5612     var aGroup,
5613         returnVal;
5614     
5615     if (Lang.isNumber(p_nItemIndex)) {
5616
5617         aGroup = this._getItemGroup(p_nGroupIndex);
5618
5619         if (aGroup) {
5620
5621             returnVal = aGroup[p_nItemIndex];
5622         
5623         }
5624
5625     }
5626     
5627     return returnVal;
5628     
5629 },
5630
5631
5632 /**
5633 * @method getSubmenus
5634 * @description Returns an array of all of the submenus that are immediate 
5635 * children of the menu.
5636 * @return {Array}
5637 */
5638 getSubmenus: function () {
5639
5640     var aItems = this.getItems(),
5641         nItems = aItems.length,
5642         aSubmenus,
5643         oSubmenu,
5644         oItem,
5645         i;
5646
5647
5648     if (nItems > 0) {
5649         
5650         aSubmenus = [];
5651
5652         for(i=0; i<nItems; i++) {
5653
5654             oItem = aItems[i];
5655             
5656             if (oItem) {
5657
5658                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5659                 
5660                 if (oSubmenu) {
5661
5662                     aSubmenus[aSubmenus.length] = oSubmenu;
5663
5664                 }
5665             
5666             }
5667         
5668         }
5669     
5670     }
5671
5672     return aSubmenus;
5673
5674 },
5675
5676
5677 /**
5678 * @method clearContent
5679 * @description Removes all of the content from the menu, including the menu 
5680 * items, group titles, header and footer.
5681 */
5682 clearContent: function () {
5683
5684     var aItems = this.getItems(),
5685         nItems = aItems.length,
5686         oElement = this.element,
5687         oBody = this.body,
5688         oHeader = this.header,
5689         oFooter = this.footer,
5690         oItem,
5691         oSubmenu,
5692         i;
5693
5694
5695     if (nItems > 0) {
5696
5697         i = nItems - 1;
5698
5699         do {
5700
5701             oItem = aItems[i];
5702
5703             if (oItem) {
5704
5705                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5706
5707                 if (oSubmenu) {
5708
5709                     this.cfg.configChangedEvent.unsubscribe(
5710                         this._onParentMenuConfigChange, oSubmenu);
5711
5712                     this.renderEvent.unsubscribe(this._onParentMenuRender, 
5713                         oSubmenu);
5714
5715                 }
5716                 
5717                 this.removeItem(oItem, oItem.groupIndex);
5718
5719             }
5720         
5721         }
5722         while (i--);
5723
5724     }
5725
5726
5727     if (oHeader) {
5728
5729         Event.purgeElement(oHeader);
5730         oElement.removeChild(oHeader);
5731
5732     }
5733     
5734
5735     if (oFooter) {
5736
5737         Event.purgeElement(oFooter);
5738         oElement.removeChild(oFooter);
5739     }
5740
5741
5742     if (oBody) {
5743
5744         Event.purgeElement(oBody);
5745
5746         oBody.innerHTML = _EMPTY_STRING;
5747
5748     }
5749
5750     this.activeItem = null;
5751
5752     this._aItemGroups = [];
5753     this._aListElements = [];
5754     this._aGroupTitleElements = [];
5755
5756     this.cfg.setProperty(_WIDTH, null);
5757
5758 },
5759
5760
5761 /**
5762 * @method destroy
5763 * @description Removes the menu's <code>&#60;div&#62;</code> element 
5764 * (and accompanying child nodes) from the document.
5765 */
5766 destroy: function () {
5767
5768     // Remove all items
5769
5770     this.clearContent();
5771
5772     this._aItemGroups = null;
5773     this._aListElements = null;
5774     this._aGroupTitleElements = null;
5775
5776
5777     // Continue with the superclass implementation of this method
5778
5779     Menu.superclass.destroy.call(this);
5780     
5781     YAHOO.log("Destroyed.", "info", this.toString());
5782
5783 },
5784
5785
5786 /**
5787 * @method setInitialFocus
5788 * @description Sets focus to the menu's first enabled item.
5789 */
5790 setInitialFocus: function () {
5791
5792     var oItem = this._getFirstEnabledItem();
5793     
5794     if (oItem) {
5795
5796         oItem.focus();
5797
5798     }
5799     
5800 },
5801
5802
5803 /**
5804 * @method setInitialSelection
5805 * @description Sets the "selected" configuration property of the menu's first 
5806 * enabled item to "true."
5807 */
5808 setInitialSelection: function () {
5809
5810     var oItem = this._getFirstEnabledItem();
5811     
5812     if (oItem) {
5813     
5814         oItem.cfg.setProperty(_SELECTED, true);
5815     }        
5816
5817 },
5818
5819
5820 /**
5821 * @method clearActiveItem
5822 * @description Sets the "selected" configuration property of the menu's active
5823 * item to "false" and hides the item's submenu.
5824 * @param {Boolean} p_bBlur Boolean indicating if the menu's active item 
5825 * should be blurred.  
5826 */
5827 clearActiveItem: function (p_bBlur) {
5828
5829     if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5830     
5831         this._cancelShowDelay();
5832     
5833     }
5834
5835
5836     var oActiveItem = this.activeItem,
5837         oConfig,
5838         oSubmenu;
5839
5840     if (oActiveItem) {
5841
5842         oConfig = oActiveItem.cfg;
5843
5844         if (p_bBlur) {
5845
5846             oActiveItem.blur();
5847             
5848             this.getRoot()._hasFocus = true;
5849         
5850         }
5851
5852         oConfig.setProperty(_SELECTED, false);
5853
5854         oSubmenu = oConfig.getProperty(_SUBMENU);
5855
5856
5857         if (oSubmenu) {
5858
5859             oSubmenu.hide();
5860
5861         }
5862
5863         this.activeItem = null;  
5864
5865     }
5866
5867 },
5868
5869
5870 /**
5871 * @method focus
5872 * @description Causes the menu to receive focus and fires the "focus" event.
5873 */
5874 focus: function () {
5875
5876     if (!this.hasFocus()) {
5877
5878         this.setInitialFocus();
5879     
5880     }
5881
5882 },
5883
5884
5885 /**
5886 * @method blur
5887 * @description Causes the menu to lose focus and fires the "blur" event.
5888 */    
5889 blur: function () {
5890
5891     var oItem;
5892
5893     if (this.hasFocus()) {
5894     
5895         oItem = MenuManager.getFocusedMenuItem();
5896         
5897         if (oItem) {
5898
5899             oItem.blur();
5900
5901         }
5902
5903     }
5904
5905 },
5906
5907
5908 /**
5909 * @method hasFocus
5910 * @description Returns a boolean indicating whether or not the menu has focus.
5911 * @return {Boolean}
5912 */
5913 hasFocus: function () {
5914
5915     return (MenuManager.getFocusedMenu() == this.getRoot());
5916
5917 },
5918
5919
5920 _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5921
5922     var oItem = p_aArgs[0],
5923         oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5924
5925     if (oSubmenu) {
5926         oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5927     }
5928
5929 },
5930
5931
5932 _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) { 
5933
5934     var oSubmenu = this.cfg.getProperty(_SUBMENU);
5935     
5936     if (oSubmenu) {
5937         oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5938     }
5939
5940 },
5941
5942
5943 /**
5944 * Adds the specified CustomEvent subscriber to the menu and each of 
5945 * its submenus.
5946 * @method subscribe
5947 * @param p_type     {string}   the type, or name of the event
5948 * @param p_fn       {function} the function to exectute when the event fires
5949 * @param p_obj      {Object}   An object to be passed along when the event 
5950 *                              fires
5951 * @param p_override {boolean}  If true, the obj passed in becomes the 
5952 *                              execution scope of the listener
5953 */
5954 subscribe: function () {
5955
5956         //      Subscribe to the event for this Menu instance
5957     Menu.superclass.subscribe.apply(this, arguments);
5958
5959         //      Subscribe to the "itemAdded" event so that all future submenus
5960         //      also subscribe to this event
5961     Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5962
5963
5964     var aItems = this.getItems(),
5965         nItems,
5966         oItem,
5967         oSubmenu,
5968         i;
5969         
5970
5971     if (aItems) {
5972
5973         nItems = aItems.length;
5974         
5975         if (nItems > 0) {
5976         
5977             i = nItems - 1;
5978             
5979             do {
5980
5981                 oItem = aItems[i];
5982                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5983                 
5984                 if (oSubmenu) {
5985                     oSubmenu.subscribe.apply(oSubmenu, arguments);
5986                 }
5987                 else {
5988                     oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5989                 }
5990
5991             }
5992             while (i--);
5993         
5994         }
5995
5996     }
5997
5998 },
5999
6000
6001 unsubscribe: function () {
6002
6003         //      Remove the event for this Menu instance
6004     Menu.superclass.unsubscribe.apply(this, arguments);
6005
6006         //      Remove the "itemAdded" event so that all future submenus don't have 
6007         //      the event handler
6008     Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
6009
6010
6011     var aItems = this.getItems(),
6012         nItems,
6013         oItem,
6014         oSubmenu,
6015         i;
6016         
6017
6018     if (aItems) {
6019
6020         nItems = aItems.length;
6021         
6022         if (nItems > 0) {
6023         
6024             i = nItems - 1;
6025             
6026             do {
6027
6028                 oItem = aItems[i];
6029                 oSubmenu = oItem.cfg.getProperty(_SUBMENU);
6030                 
6031                 if (oSubmenu) {
6032                     oSubmenu.unsubscribe.apply(oSubmenu, arguments);
6033                 }
6034                 else {
6035                     oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
6036                 }
6037
6038             }
6039             while (i--);
6040         
6041         }
6042
6043     }
6044
6045 },
6046
6047
6048 /**
6049 * @description Initializes the class's configurable properties which can be
6050 * changed using the menu's Config object ("cfg").
6051 * @method initDefaultConfig
6052 */
6053 initDefaultConfig: function () {
6054
6055     Menu.superclass.initDefaultConfig.call(this);
6056
6057     var oConfig = this.cfg;
6058
6059
6060     // Module documentation overrides
6061
6062     /**
6063     * @config effect
6064     * @description Object or array of objects representing the ContainerEffect 
6065     * classes that are active for animating the container.  When set this 
6066     * property is automatically applied to all submenus.
6067     * @type Object
6068     * @default null
6069     */
6070
6071     // Overlay documentation overrides
6072
6073
6074     /**
6075     * @config x
6076     * @description Number representing the absolute x-coordinate position of 
6077     * the Menu.  This property is only applied when the "position" 
6078     * configuration property is set to dynamic.
6079     * @type Number
6080     * @default null
6081     */
6082     
6083
6084     /**
6085     * @config y
6086     * @description Number representing the absolute y-coordinate position of 
6087     * the Menu.  This property is only applied when the "position" 
6088     * configuration property is set to dynamic.
6089     * @type Number
6090     * @default null
6091     */
6092
6093
6094     /**
6095     * @description Array of the absolute x and y positions of the Menu.  This 
6096     * property is only applied when the "position" configuration property is 
6097     * set to dynamic.
6098     * @config xy
6099     * @type Number[]
6100     * @default null
6101     */
6102     
6103
6104     /**
6105     * @config context
6106     * @description Array of context arguments for context-sensitive positioning.  
6107     * The format is: [id or element, element corner, context corner]. 
6108     * For example, setting this property to ["img1", "tl", "bl"] would 
6109     * align the Menu's top left corner to the context element's 
6110     * bottom left corner.  This property is only applied when the "position" 
6111     * configuration property is set to dynamic.
6112     * @type Array
6113     * @default null
6114     */
6115     
6116     
6117     /**
6118     * @config fixedcenter
6119     * @description Boolean indicating if the Menu should be anchored to the 
6120     * center of the viewport.  This property is only applied when the 
6121     * "position" configuration property is set to dynamic.
6122     * @type Boolean
6123     * @default false
6124     */
6125     
6126     
6127     /**
6128     * @config iframe
6129     * @description Boolean indicating whether or not the Menu should 
6130     * have an IFRAME shim; used to prevent SELECT elements from 
6131     * poking through an Overlay instance in IE6.  When set to "true", 
6132     * the iframe shim is created when the Menu instance is intially
6133     * made visible.  This property is only applied when the "position" 
6134     * configuration property is set to dynamic and is automatically applied 
6135     * to all submenus.
6136     * @type Boolean
6137     * @default true for IE6 and below, false for all other browsers.
6138     */
6139
6140
6141         // Add configuration attributes
6142
6143     /*
6144         Change the default value for the "visible" configuration 
6145         property to "false" by re-adding the property.
6146     */
6147
6148     /**
6149     * @config visible
6150     * @description Boolean indicating whether or not the menu is visible.  If 
6151     * the menu's "position" configuration property is set to "dynamic" (the 
6152     * default), this property toggles the menu's <code>&#60;div&#62;</code> 
6153     * element's "visibility" style property between "visible" (true) or 
6154     * "hidden" (false).  If the menu's "position" configuration property is 
6155     * set to "static" this property toggles the menu's 
6156     * <code>&#60;div&#62;</code> element's "display" style property 
6157     * between "block" (true) or "none" (false).
6158     * @default false
6159     * @type Boolean
6160     */
6161     oConfig.addProperty(
6162         VISIBLE_CONFIG.key, 
6163         {
6164             handler: this.configVisible, 
6165             value: VISIBLE_CONFIG.value, 
6166             validator: VISIBLE_CONFIG.validator
6167         }
6168      );
6169
6170
6171     /*
6172         Change the default value for the "constraintoviewport" configuration 
6173         property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6174     */
6175
6176     /**
6177     * @config constraintoviewport
6178     * @description Boolean indicating if the menu will try to remain inside 
6179     * the boundaries of the size of viewport.  This property is only applied 
6180     * when the "position" configuration property is set to dynamic and is 
6181     * automatically applied to all submenus.
6182     * @default true
6183     * @type Boolean
6184     */
6185     oConfig.addProperty(
6186         CONSTRAIN_TO_VIEWPORT_CONFIG.key, 
6187         {
6188             handler: this.configConstrainToViewport, 
6189             value: CONSTRAIN_TO_VIEWPORT_CONFIG.value, 
6190             validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator, 
6191             supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes 
6192         } 
6193     );
6194
6195
6196     /*
6197         Change the default value for the "preventcontextoverlap" configuration 
6198         property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6199     */
6200
6201         /**
6202         * @config preventcontextoverlap
6203         * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem 
6204         * when the "constraintoviewport" configuration property is set to "true".
6205         * @type Boolean
6206         * @default true
6207         */
6208         oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6209
6210                 value: PREVENT_CONTEXT_OVERLAP_CONFIG.value, 
6211                 validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator, 
6212                 supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6213
6214         });
6215
6216
6217     /**
6218     * @config position
6219     * @description String indicating how a menu should be positioned on the 
6220     * screen.  Possible values are "static" and "dynamic."  Static menus are 
6221     * visible by default and reside in the normal flow of the document 
6222     * (CSS position: static).  Dynamic menus are hidden by default, reside 
6223     * out of the normal flow of the document (CSS position: absolute), and 
6224     * can overlay other elements on the screen.
6225     * @default dynamic
6226     * @type String
6227     */
6228     oConfig.addProperty(
6229         POSITION_CONFIG.key, 
6230         {
6231             handler: this.configPosition,
6232             value: POSITION_CONFIG.value, 
6233             validator: POSITION_CONFIG.validator,
6234             supercedes: POSITION_CONFIG.supercedes
6235         }
6236     );
6237
6238
6239     /**
6240     * @config submenualignment
6241     * @description Array defining how submenus should be aligned to their 
6242     * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6243     * a submenu's top left corner is aligned to its parent menu item's top 
6244     * right corner.
6245     * @default ["tl","tr"]
6246     * @type Array
6247     */
6248     oConfig.addProperty(
6249         SUBMENU_ALIGNMENT_CONFIG.key, 
6250         { 
6251             value: SUBMENU_ALIGNMENT_CONFIG.value,
6252             suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6253         }
6254     );
6255
6256
6257     /**
6258     * @config autosubmenudisplay
6259     * @description Boolean indicating if submenus are automatically made 
6260     * visible when the user mouses over the menu's items.
6261     * @default true
6262     * @type Boolean
6263     */
6264         oConfig.addProperty(
6265            AUTO_SUBMENU_DISPLAY_CONFIG.key, 
6266            { 
6267                value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
6268                validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6269                suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6270        } 
6271     );
6272
6273
6274     /**
6275     * @config showdelay
6276     * @description Number indicating the time (in milliseconds) that should 
6277     * expire before a submenu is made visible when the user mouses over 
6278     * the menu's items.  This property is only applied when the "position" 
6279     * configuration property is set to dynamic and is automatically applied 
6280     * to all submenus.
6281     * @default 250
6282     * @type Number
6283     */
6284         oConfig.addProperty(
6285            SHOW_DELAY_CONFIG.key, 
6286            { 
6287                value: SHOW_DELAY_CONFIG.value, 
6288                validator: SHOW_DELAY_CONFIG.validator,
6289                suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6290        } 
6291     );
6292
6293
6294     /**
6295     * @config hidedelay
6296     * @description Number indicating the time (in milliseconds) that should 
6297     * expire before the menu is hidden.  This property is only applied when 
6298     * the "position" configuration property is set to dynamic and is 
6299     * automatically applied to all submenus.
6300     * @default 0
6301     * @type Number
6302     */
6303         oConfig.addProperty(
6304            HIDE_DELAY_CONFIG.key, 
6305            { 
6306                handler: this.configHideDelay,
6307                value: HIDE_DELAY_CONFIG.value, 
6308                validator: HIDE_DELAY_CONFIG.validator, 
6309                suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6310        } 
6311     );
6312
6313
6314     /**
6315     * @config submenuhidedelay
6316     * @description Number indicating the time (in milliseconds) that should 
6317     * expire before a submenu is hidden when the user mouses out of a menu item 
6318     * heading in the direction of a submenu.  The value must be greater than or 
6319     * equal to the value specified for the "showdelay" configuration property.
6320     * This property is only applied when the "position" configuration property 
6321     * is set to dynamic and is automatically applied to all submenus.
6322     * @default 250
6323     * @type Number
6324     */
6325         oConfig.addProperty(
6326            SUBMENU_HIDE_DELAY_CONFIG.key, 
6327            { 
6328                value: SUBMENU_HIDE_DELAY_CONFIG.value, 
6329                validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6330                suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6331        } 
6332     );
6333
6334
6335     /**
6336     * @config clicktohide
6337     * @description Boolean indicating if the menu will automatically be 
6338     * hidden if the user clicks outside of it.  This property is only 
6339     * applied when the "position" configuration property is set to dynamic 
6340     * and is automatically applied to all submenus.
6341     * @default true
6342     * @type Boolean
6343     */
6344     oConfig.addProperty(
6345         CLICK_TO_HIDE_CONFIG.key,
6346         {
6347             value: CLICK_TO_HIDE_CONFIG.value,
6348             validator: CLICK_TO_HIDE_CONFIG.validator,
6349             suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6350         }
6351     );
6352
6353
6354         /**
6355         * @config container
6356         * @description HTML element reference or string specifying the id 
6357         * attribute of the HTML element that the menu's markup should be 
6358         * rendered into.
6359         * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6360         * level-one-html.html#ID-58190037">HTMLElement</a>|String
6361         * @default document.body
6362         */
6363         oConfig.addProperty(
6364            CONTAINER_CONFIG.key, 
6365            { 
6366                handler: this.configContainer,
6367                value: document.body,
6368            suppressEvent: CONTAINER_CONFIG.suppressEvent
6369        } 
6370    );
6371
6372
6373     /**
6374     * @config scrollincrement
6375     * @description Number used to control the scroll speed of a menu.  Used to 
6376     * increment the "scrollTop" property of the menu's body by when a menu's 
6377     * content is scrolling.  When set this property is automatically applied 
6378     * to all submenus.
6379     * @default 1
6380     * @type Number
6381     */
6382     oConfig.addProperty(
6383         SCROLL_INCREMENT_CONFIG.key, 
6384         { 
6385             value: SCROLL_INCREMENT_CONFIG.value, 
6386             validator: SCROLL_INCREMENT_CONFIG.validator,
6387             supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6388             suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6389         }
6390     );
6391
6392
6393     /**
6394     * @config minscrollheight
6395     * @description Number defining the minimum threshold for the "maxheight" 
6396     * configuration property.  When set this property is automatically applied 
6397     * to all submenus.
6398     * @default 90
6399     * @type Number
6400     */
6401     oConfig.addProperty(
6402         MIN_SCROLL_HEIGHT_CONFIG.key, 
6403         { 
6404             value: MIN_SCROLL_HEIGHT_CONFIG.value, 
6405             validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6406             supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6407             suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6408         }
6409     );
6410
6411
6412     /**
6413     * @config maxheight
6414     * @description Number defining the maximum height (in pixels) for a menu's 
6415     * body element (<code>&#60;div class="bd"&#62;</code>).  Once a menu's body 
6416     * exceeds this height, the contents of the body are scrolled to maintain 
6417     * this value.  This value cannot be set lower than the value of the 
6418     * "minscrollheight" configuration property.
6419     * @default 0
6420     * @type Number
6421     */
6422     oConfig.addProperty(
6423        MAX_HEIGHT_CONFIG.key, 
6424        {
6425             handler: this.configMaxHeight,
6426             value: MAX_HEIGHT_CONFIG.value,
6427             validator: MAX_HEIGHT_CONFIG.validator,
6428             suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6429             supercedes: MAX_HEIGHT_CONFIG.supercedes            
6430        } 
6431     );
6432
6433
6434     /**
6435     * @config classname
6436     * @description String representing the CSS class to be applied to the 
6437     * menu's root <code>&#60;div&#62;</code> element.  The specified class(es)  
6438     * are appended in addition to the default class as specified by the menu's
6439     * CSS_CLASS_NAME constant. When set this property is automatically 
6440     * applied to all submenus.
6441     * @default null
6442     * @type String
6443     */
6444     oConfig.addProperty(
6445         CLASS_NAME_CONFIG.key, 
6446         { 
6447             handler: this.configClassName,
6448             value: CLASS_NAME_CONFIG.value, 
6449             validator: CLASS_NAME_CONFIG.validator,
6450             supercedes: CLASS_NAME_CONFIG.supercedes      
6451         }
6452     );
6453
6454
6455     /**
6456     * @config disabled
6457     * @description Boolean indicating if the menu should be disabled.  
6458     * Disabling a menu disables each of its items.  (Disabled menu items are 
6459     * dimmed and will not respond to user input or fire events.)  Disabled
6460     * menus have a corresponding "disabled" CSS class applied to their root
6461     * <code>&#60;div&#62;</code> element.
6462     * @default false
6463     * @type Boolean
6464     */
6465     oConfig.addProperty(
6466         DISABLED_CONFIG.key, 
6467         { 
6468             handler: this.configDisabled,
6469             value: DISABLED_CONFIG.value, 
6470             validator: DISABLED_CONFIG.validator,
6471             suppressEvent: DISABLED_CONFIG.suppressEvent
6472         }
6473     );
6474
6475
6476     /**
6477     * @config shadow
6478     * @description Boolean indicating if the menu should have a shadow.
6479     * @default true
6480     * @type Boolean
6481     */
6482     oConfig.addProperty(
6483         SHADOW_CONFIG.key, 
6484         { 
6485             handler: this.configShadow,
6486             value: SHADOW_CONFIG.value, 
6487             validator: SHADOW_CONFIG.validator
6488         }
6489     );
6490
6491
6492     /**
6493     * @config keepopen
6494     * @description Boolean indicating if the menu should remain open when clicked.
6495     * @default false
6496     * @type Boolean
6497     */
6498     oConfig.addProperty(
6499         KEEP_OPEN_CONFIG.key, 
6500         { 
6501             value: KEEP_OPEN_CONFIG.value, 
6502             validator: KEEP_OPEN_CONFIG.validator
6503         }
6504     );
6505
6506 }
6507
6508 }); // END YAHOO.lang.extend
6509
6510 })();
6511
6512
6513
6514 (function () {
6515
6516 /**
6517 * Creates an item for a menu.
6518
6519 * @param {String} p_oObject String specifying the text of the menu item.
6520 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6521 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
6522 * the <code>&#60;li&#62;</code> element of the menu item.
6523 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6524 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
6525 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6526 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6527 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
6528 * specifying the <code>&#60;option&#62;</code> element of the menu item.
6529 * @param {Object} p_oConfig Optional. Object literal specifying the 
6530 * configuration for the menu item. See configuration class documentation 
6531 * for more details.
6532 * @class MenuItem
6533 * @constructor
6534 */
6535 YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6536
6537     if (p_oObject) {
6538
6539         if (p_oConfig) {
6540     
6541             this.parent = p_oConfig.parent;
6542             this.value = p_oConfig.value;
6543             this.id = p_oConfig.id;
6544
6545         }
6546
6547         this.init(p_oObject, p_oConfig);
6548
6549     }
6550
6551 };
6552
6553
6554 var Dom = YAHOO.util.Dom,
6555     Module = YAHOO.widget.Module,
6556     Menu = YAHOO.widget.Menu,
6557     MenuItem = YAHOO.widget.MenuItem,
6558     CustomEvent = YAHOO.util.CustomEvent,
6559     UA = YAHOO.env.ua,
6560     Lang = YAHOO.lang,
6561
6562         // Private string constants
6563
6564         _TEXT = "text",
6565         _HASH = "#",
6566         _HYPHEN = "-",
6567         _HELP_TEXT = "helptext",
6568         _URL = "url",
6569         _TARGET = "target",
6570         _EMPHASIS = "emphasis",
6571         _STRONG_EMPHASIS = "strongemphasis",
6572         _CHECKED = "checked",
6573         _SUBMENU = "submenu",
6574         _DISABLED = "disabled",
6575         _SELECTED = "selected",
6576         _HAS_SUBMENU = "hassubmenu",
6577         _CHECKED_DISABLED = "checked-disabled",
6578         _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6579         _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6580         _CHECKED_SELECTED = "checked-selected",
6581         _ONCLICK = "onclick",
6582         _CLASSNAME = "classname",
6583         _EMPTY_STRING = "",
6584         _OPTION = "OPTION",
6585         _OPTGROUP = "OPTGROUP",
6586         _LI_UPPERCASE = "LI",
6587         _HREF = "href",
6588         _SELECT = "SELECT",
6589         _DIV = "DIV",
6590         _START_HELP_TEXT = "<em class=\"helptext\">",
6591         _START_EM = "<em>",
6592         _END_EM = "</em>",
6593         _START_STRONG = "<strong>",
6594         _END_STRONG = "</strong>",
6595         _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6596         _OBJ = "obj",
6597         _SCOPE = "scope",
6598         _NONE = "none",
6599         _VISIBLE = "visible",
6600         _SPACE = " ",
6601         _MENUITEM = "MenuItem",
6602         _CLICK = "click",
6603         _SHOW = "show",
6604         _HIDE = "hide",
6605         _LI_LOWERCASE = "li",
6606         _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6607
6608     EVENT_TYPES = [
6609     
6610         ["mouseOverEvent", "mouseover"],
6611         ["mouseOutEvent", "mouseout"],
6612         ["mouseDownEvent", "mousedown"],
6613         ["mouseUpEvent", "mouseup"],
6614         ["clickEvent", _CLICK],
6615         ["keyPressEvent", "keypress"],
6616         ["keyDownEvent", "keydown"],
6617         ["keyUpEvent", "keyup"],
6618         ["focusEvent", "focus"],
6619         ["blurEvent", "blur"],
6620         ["destroyEvent", "destroy"]
6621     
6622     ],
6623
6624         TEXT_CONFIG = { 
6625                 key: _TEXT, 
6626                 value: _EMPTY_STRING, 
6627                 validator: Lang.isString, 
6628                 suppressEvent: true 
6629         }, 
6630
6631         HELP_TEXT_CONFIG = { 
6632                 key: _HELP_TEXT,
6633                 supercedes: [_TEXT], 
6634                 suppressEvent: true 
6635         },
6636
6637         URL_CONFIG = { 
6638                 key: _URL, 
6639                 value: _HASH, 
6640                 suppressEvent: true 
6641         }, 
6642
6643         TARGET_CONFIG = { 
6644                 key: _TARGET, 
6645                 suppressEvent: true 
6646         }, 
6647
6648         EMPHASIS_CONFIG = { 
6649                 key: _EMPHASIS, 
6650                 value: false, 
6651                 validator: Lang.isBoolean, 
6652                 suppressEvent: true, 
6653                 supercedes: [_TEXT]
6654         }, 
6655
6656         STRONG_EMPHASIS_CONFIG = { 
6657                 key: _STRONG_EMPHASIS, 
6658                 value: false, 
6659                 validator: Lang.isBoolean, 
6660                 suppressEvent: true,
6661                 supercedes: [_TEXT]
6662         },
6663
6664         CHECKED_CONFIG = { 
6665                 key: _CHECKED, 
6666                 value: false, 
6667                 validator: Lang.isBoolean, 
6668                 suppressEvent: true, 
6669                 supercedes: [_DISABLED, _SELECTED]
6670         }, 
6671
6672         SUBMENU_CONFIG = { 
6673                 key: _SUBMENU,
6674                 suppressEvent: true,
6675                 supercedes: [_DISABLED, _SELECTED]
6676         },
6677
6678         DISABLED_CONFIG = { 
6679                 key: _DISABLED, 
6680                 value: false, 
6681                 validator: Lang.isBoolean, 
6682                 suppressEvent: true,
6683                 supercedes: [_TEXT, _SELECTED]
6684         },
6685
6686         SELECTED_CONFIG = { 
6687                 key: _SELECTED, 
6688                 value: false, 
6689                 validator: Lang.isBoolean, 
6690                 suppressEvent: true
6691         },
6692
6693         ONCLICK_CONFIG = { 
6694                 key: _ONCLICK,
6695                 suppressEvent: true
6696         },
6697
6698         CLASS_NAME_CONFIG = { 
6699                 key: _CLASSNAME, 
6700                 value: null, 
6701                 validator: Lang.isString,
6702                 suppressEvent: true
6703         },
6704     
6705         KEY_LISTENER_CONFIG = {
6706                 key: "keylistener", 
6707                 value: null, 
6708                 suppressEvent: true
6709         },
6710
6711         m_oMenuItemTemplate = null,
6712
6713     CLASS_NAMES = {};
6714
6715
6716 /**
6717 * @method getClassNameForState
6718 * @description Returns a class name for the specified prefix and state.  If the class name does not 
6719 * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6720 * @private
6721 * @param {String} prefix String representing the prefix for the class name
6722 * @param {String} state String representing a state - "disabled," "checked," etc.
6723 */  
6724 var getClassNameForState = function (prefix, state) {
6725
6726         var oClassNames = CLASS_NAMES[prefix];
6727         
6728         if (!oClassNames) {
6729                 CLASS_NAMES[prefix] = {};
6730                 oClassNames = CLASS_NAMES[prefix];
6731         }
6732
6733
6734         var sClassName = oClassNames[state];
6735
6736         if (!sClassName) {
6737                 sClassName = prefix + _HYPHEN + state;
6738                 oClassNames[state] = sClassName;
6739         }
6740
6741         return sClassName;
6742         
6743 };
6744
6745
6746 /**
6747 * @method addClassNameForState
6748 * @description Applies a class name to a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6749 * that represents a MenuItem's state - "disabled," "checked," etc.
6750 * @private
6751 * @param {String} state String representing a state - "disabled," "checked," etc.
6752 */  
6753 var addClassNameForState = function (state) {
6754
6755         Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6756         Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6757
6758 };
6759
6760 /**
6761 * @method removeClassNameForState
6762 * @description Removes a class name from a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6763 * that represents a MenuItem's state - "disabled," "checked," etc.
6764 * @private
6765 * @param {String} state String representing a state - "disabled," "checked," etc.
6766 */  
6767 var removeClassNameForState = function (state) {
6768
6769         Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6770         Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6771
6772 };
6773
6774
6775 MenuItem.prototype = {
6776
6777     /**
6778     * @property CSS_CLASS_NAME
6779     * @description String representing the CSS class(es) to be applied to the 
6780     * <code>&#60;li&#62;</code> element of the menu item.
6781     * @default "yuimenuitem"
6782     * @final
6783     * @type String
6784     */
6785     CSS_CLASS_NAME: "yuimenuitem",
6786
6787
6788     /**
6789     * @property CSS_LABEL_CLASS_NAME
6790     * @description String representing the CSS class(es) to be applied to the 
6791     * menu item's <code>&#60;a&#62;</code> element.
6792     * @default "yuimenuitemlabel"
6793     * @final
6794     * @type String
6795     */
6796     CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6797
6798
6799     /**
6800     * @property SUBMENU_TYPE
6801     * @description Object representing the type of menu to instantiate and 
6802     * add when parsing the child nodes of the menu item's source HTML element.
6803     * @final
6804     * @type YAHOO.widget.Menu
6805     */
6806     SUBMENU_TYPE: null,
6807
6808
6809
6810     // Private member variables
6811     
6812
6813     /**
6814     * @property _oAnchor
6815     * @description Object reference to the menu item's 
6816     * <code>&#60;a&#62;</code> element.
6817     * @default null 
6818     * @private
6819     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6820     * one-html.html#ID-48250443">HTMLAnchorElement</a>
6821     */
6822     _oAnchor: null,
6823     
6824     
6825     /**
6826     * @property _oHelpTextEM
6827     * @description Object reference to the menu item's help text 
6828     * <code>&#60;em&#62;</code> element.
6829     * @default null
6830     * @private
6831     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6832     * one-html.html#ID-58190037">HTMLElement</a>
6833     */
6834     _oHelpTextEM: null,
6835     
6836     
6837     /**
6838     * @property _oSubmenu
6839     * @description Object reference to the menu item's submenu.
6840     * @default null
6841     * @private
6842     * @type YAHOO.widget.Menu
6843     */
6844     _oSubmenu: null,
6845
6846
6847     /** 
6848     * @property _oOnclickAttributeValue
6849     * @description Object reference to the menu item's current value for the 
6850     * "onclick" configuration attribute.
6851     * @default null
6852     * @private
6853     * @type Object
6854     */
6855     _oOnclickAttributeValue: null,
6856
6857
6858     /**
6859     * @property _sClassName
6860     * @description The current value of the "classname" configuration attribute.
6861     * @default null
6862     * @private
6863     * @type String
6864     */
6865     _sClassName: null,
6866
6867
6868
6869     // Public properties
6870
6871
6872         /**
6873     * @property constructor
6874         * @description Object reference to the menu item's constructor function.
6875     * @default YAHOO.widget.MenuItem
6876         * @type YAHOO.widget.MenuItem
6877         */
6878         constructor: MenuItem,
6879
6880
6881     /**
6882     * @property index
6883     * @description Number indicating the ordinal position of the menu item in 
6884     * its group.
6885     * @default null
6886     * @type Number
6887     */
6888     index: null,
6889
6890
6891     /**
6892     * @property groupIndex
6893     * @description Number indicating the index of the group to which the menu 
6894     * item belongs.
6895     * @default null
6896     * @type Number
6897     */
6898     groupIndex: null,
6899
6900
6901     /**
6902     * @property parent
6903     * @description Object reference to the menu item's parent menu.
6904     * @default null
6905     * @type YAHOO.widget.Menu
6906     */
6907     parent: null,
6908
6909
6910     /**
6911     * @property element
6912     * @description Object reference to the menu item's 
6913     * <code>&#60;li&#62;</code> element.
6914     * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6915     * -one-html.html#ID-74680021">HTMLLIElement</a>
6916     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6917     * one-html.html#ID-74680021">HTMLLIElement</a>
6918     */
6919     element: null,
6920
6921
6922     /**
6923     * @property srcElement
6924     * @description Object reference to the HTML element (either 
6925     * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or 
6926     * <code>&#60;option&#62;</code>) used create the menu item.
6927     * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6928     * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6929     * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6930     * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6931     * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6932     * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6933     * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6934     * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6935     * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6936     * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6937     */
6938     srcElement: null,
6939
6940
6941     /**
6942     * @property value
6943     * @description Object reference to the menu item's value.
6944     * @default null
6945     * @type Object
6946     */
6947     value: null,
6948
6949
6950         /**
6951     * @property browser
6952     * @deprecated Use YAHOO.env.ua
6953         * @description String representing the browser.
6954         * @type String
6955         */
6956         browser: Module.prototype.browser,
6957
6958
6959     /**
6960     * @property id
6961     * @description Id of the menu item's root <code>&#60;li&#62;</code> 
6962     * element.  This property should be set via the constructor using the 
6963     * configuration object literal.  If an id is not specified, then one will 
6964     * be created using the "generateId" method of the Dom utility.
6965     * @default null
6966     * @type String
6967     */
6968     id: null,
6969
6970
6971
6972     // Events
6973
6974
6975     /**
6976     * @event destroyEvent
6977     * @description Fires when the menu item's <code>&#60;li&#62;</code> 
6978     * element is removed from its parent <code>&#60;ul&#62;</code> element.
6979     * @type YAHOO.util.CustomEvent
6980     */
6981
6982
6983     /**
6984     * @event mouseOverEvent
6985     * @description Fires when the mouse has entered the menu item.  Passes 
6986     * back the DOM Event object as an argument.
6987     * @type YAHOO.util.CustomEvent
6988     */
6989
6990
6991     /**
6992     * @event mouseOutEvent
6993     * @description Fires when the mouse has left the menu item.  Passes back 
6994     * the DOM Event object as an argument.
6995     * @type YAHOO.util.CustomEvent
6996     */
6997
6998
6999     /**
7000     * @event mouseDownEvent
7001     * @description Fires when the user mouses down on the menu item.  Passes 
7002     * back the DOM Event object as an argument.
7003     * @type YAHOO.util.CustomEvent
7004     */
7005
7006
7007     /**
7008     * @event mouseUpEvent
7009     * @description Fires when the user releases a mouse button while the mouse 
7010     * is over the menu item.  Passes back the DOM Event object as an argument.
7011     * @type YAHOO.util.CustomEvent
7012     */
7013
7014
7015     /**
7016     * @event clickEvent
7017     * @description Fires when the user clicks the on the menu item.  Passes 
7018     * back the DOM Event object as an argument.
7019     * @type YAHOO.util.CustomEvent
7020     */
7021
7022
7023     /**
7024     * @event keyPressEvent
7025     * @description Fires when the user presses an alphanumeric key when the 
7026     * menu item has focus.  Passes back the DOM Event object as an argument.
7027     * @type YAHOO.util.CustomEvent
7028     */
7029
7030
7031     /**
7032     * @event keyDownEvent
7033     * @description Fires when the user presses a key when the menu item has 
7034     * focus.  Passes back the DOM Event object as an argument.
7035     * @type YAHOO.util.CustomEvent
7036     */
7037
7038
7039     /**
7040     * @event keyUpEvent
7041     * @description Fires when the user releases a key when the menu item has 
7042     * focus.  Passes back the DOM Event object as an argument.
7043     * @type YAHOO.util.CustomEvent
7044     */
7045
7046
7047     /**
7048     * @event focusEvent
7049     * @description Fires when the menu item receives focus.
7050     * @type YAHOO.util.CustomEvent
7051     */
7052
7053
7054     /**
7055     * @event blurEvent
7056     * @description Fires when the menu item loses the input focus.
7057     * @type YAHOO.util.CustomEvent
7058     */
7059
7060
7061     /**
7062     * @method init
7063     * @description The MenuItem class's initialization method. This method is 
7064     * automatically called by the constructor, and sets up all DOM references 
7065     * for pre-existing markup, and creates required markup if it is not 
7066     * already present.
7067     * @param {String} p_oObject String specifying the text of the menu item.
7068     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7069     * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
7070     * the <code>&#60;li&#62;</code> element of the menu item.
7071     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7072     * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
7073     * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
7074     * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7075     * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
7076     * specifying the <code>&#60;option&#62;</code> element of the menu item.
7077     * @param {Object} p_oConfig Optional. Object literal specifying the 
7078     * configuration for the menu item. See configuration class documentation 
7079     * for more details.
7080     */
7081     init: function (p_oObject, p_oConfig) {
7082
7083
7084         if (!this.SUBMENU_TYPE) {
7085     
7086             this.SUBMENU_TYPE = Menu;
7087     
7088         }
7089
7090
7091         // Create the config object
7092
7093         this.cfg = new YAHOO.util.Config(this);
7094
7095         this.initDefaultConfig();
7096
7097         var oConfig = this.cfg,
7098             sURL = _HASH,
7099             oCustomEvent,
7100                         aEventData,
7101             oAnchor,
7102             sTarget,
7103             sText,
7104             sId,
7105             i;
7106
7107
7108         if (Lang.isString(p_oObject)) {
7109
7110             this._createRootNodeStructure();
7111
7112             oConfig.queueProperty(_TEXT, p_oObject);
7113
7114         }
7115         else if (p_oObject && p_oObject.tagName) {
7116
7117             switch(p_oObject.tagName.toUpperCase()) {
7118
7119                 case _OPTION:
7120
7121                     this._createRootNodeStructure();
7122
7123                     oConfig.queueProperty(_TEXT, p_oObject.text);
7124                     oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7125
7126                     this.value = p_oObject.value;
7127
7128                     this.srcElement = p_oObject;
7129
7130                 break;
7131
7132                 case _OPTGROUP:
7133
7134                     this._createRootNodeStructure();
7135
7136                     oConfig.queueProperty(_TEXT, p_oObject.label);
7137                     oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7138
7139                     this.srcElement = p_oObject;
7140
7141                     this._initSubTree();
7142
7143                 break;
7144
7145                 case _LI_UPPERCASE:
7146
7147                     // Get the anchor node (if it exists)
7148                     
7149                     oAnchor = Dom.getFirstChild(p_oObject);
7150
7151
7152                     // Capture the "text" and/or the "URL"
7153
7154                     if (oAnchor) {
7155
7156                         sURL = oAnchor.getAttribute(_HREF, 2);
7157                         sTarget = oAnchor.getAttribute(_TARGET);
7158
7159                         sText = oAnchor.innerHTML;
7160
7161                     }
7162
7163                     this.srcElement = p_oObject;
7164                     this.element = p_oObject;
7165                     this._oAnchor = oAnchor;
7166
7167                     /*
7168                         Set these properties silently to sync up the 
7169                         configuration object without making changes to the 
7170                         element's DOM
7171                     */ 
7172
7173                     oConfig.setProperty(_TEXT, sText, true);
7174                     oConfig.setProperty(_URL, sURL, true);
7175                     oConfig.setProperty(_TARGET, sTarget, true);
7176
7177                     this._initSubTree();
7178
7179                 break;
7180
7181             }            
7182
7183         }
7184
7185
7186         if (this.element) {
7187
7188             sId = (this.srcElement || this.element).id;
7189
7190             if (!sId) {
7191
7192                 sId = this.id || Dom.generateId();
7193
7194                 this.element.id = sId;
7195
7196             }
7197
7198             this.id = sId;
7199
7200
7201             Dom.addClass(this.element, this.CSS_CLASS_NAME);
7202             Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7203
7204
7205                         i = EVENT_TYPES.length - 1;
7206
7207                         do {
7208
7209                                 aEventData = EVENT_TYPES[i];
7210
7211                                 oCustomEvent = this.createEvent(aEventData[1]);
7212                                 oCustomEvent.signature = CustomEvent.LIST;
7213                                 
7214                                 this[aEventData[0]] = oCustomEvent;
7215
7216                         }
7217                         while (i--);
7218
7219
7220             if (p_oConfig) {
7221     
7222                 oConfig.applyConfig(p_oConfig);
7223     
7224             }        
7225
7226             oConfig.fireQueue();
7227
7228         }
7229
7230     },
7231
7232
7233
7234     // Private methods
7235
7236     /**
7237     * @method _createRootNodeStructure
7238     * @description Creates the core DOM structure for the menu item.
7239     * @private
7240     */
7241     _createRootNodeStructure: function () {
7242
7243         var oElement,
7244             oAnchor;
7245
7246         if (!m_oMenuItemTemplate) {
7247
7248             m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7249             m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7250
7251         }
7252
7253         oElement = m_oMenuItemTemplate.cloneNode(true);
7254         oElement.className = this.CSS_CLASS_NAME;
7255
7256         oAnchor = oElement.firstChild;
7257         oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7258
7259         this.element = oElement;
7260         this._oAnchor = oAnchor;
7261
7262     },
7263
7264
7265     /**
7266     * @method _initSubTree
7267     * @description Iterates the source element's childNodes collection and uses 
7268     * the child nodes to instantiate other menus.
7269     * @private
7270     */
7271     _initSubTree: function () {
7272
7273         var oSrcEl = this.srcElement,
7274             oConfig = this.cfg,
7275             oNode,
7276             aOptions,
7277             nOptions,
7278             oMenu,
7279             n;
7280
7281
7282         if (oSrcEl.childNodes.length > 0) {
7283
7284             if (this.parent.lazyLoad && this.parent.srcElement && 
7285                 this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7286
7287                 oConfig.setProperty(
7288                         _SUBMENU, 
7289                         { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7290                     );
7291
7292             }
7293             else {
7294
7295                 oNode = oSrcEl.firstChild;
7296                 aOptions = [];
7297     
7298                 do {
7299     
7300                     if (oNode && oNode.tagName) {
7301     
7302                         switch(oNode.tagName.toUpperCase()) {
7303                 
7304                             case _DIV:
7305                 
7306                                 oConfig.setProperty(_SUBMENU, oNode);
7307                 
7308                             break;
7309          
7310                             case _OPTION:
7311         
7312                                 aOptions[aOptions.length] = oNode;
7313         
7314                             break;
7315                
7316                         }
7317                     
7318                     }
7319                 
7320                 }        
7321                 while((oNode = oNode.nextSibling));
7322     
7323     
7324                 nOptions = aOptions.length;
7325     
7326                 if (nOptions > 0) {
7327     
7328                     oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7329                     
7330                     oConfig.setProperty(_SUBMENU, oMenu);
7331     
7332                     for(n=0; n<nOptions; n++) {
7333         
7334                         oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7335         
7336                     }
7337         
7338                 }
7339             
7340             }
7341
7342         }
7343
7344     },
7345
7346
7347
7348     // Event handlers for configuration properties
7349
7350
7351     /**
7352     * @method configText
7353     * @description Event handler for when the "text" configuration property of 
7354     * the menu item changes.
7355     * @param {String} p_sType String representing the name of the event that 
7356     * was fired.
7357     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7358     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7359     * that fired the event.
7360     */
7361     configText: function (p_sType, p_aArgs, p_oItem) {
7362
7363         var sText = p_aArgs[0],
7364             oConfig = this.cfg,
7365             oAnchor = this._oAnchor,
7366             sHelpText = oConfig.getProperty(_HELP_TEXT),
7367             sHelpTextHTML = _EMPTY_STRING,
7368             sEmphasisStartTag = _EMPTY_STRING,
7369             sEmphasisEndTag = _EMPTY_STRING;
7370
7371
7372         if (sText) {
7373
7374
7375             if (sHelpText) {
7376                     
7377                 sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7378             
7379             }
7380
7381
7382             if (oConfig.getProperty(_EMPHASIS)) {
7383
7384                 sEmphasisStartTag = _START_EM;
7385                 sEmphasisEndTag = _END_EM;
7386
7387             }
7388
7389
7390             if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7391
7392                 sEmphasisStartTag = _START_STRONG;
7393                 sEmphasisEndTag = _END_STRONG;
7394             
7395             }
7396
7397
7398             oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7399
7400         }
7401
7402     },
7403
7404
7405     /**
7406     * @method configHelpText
7407     * @description Event handler for when the "helptext" configuration property 
7408     * of the menu item changes.
7409     * @param {String} p_sType String representing the name of the event that 
7410     * was fired.
7411     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7412     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7413     * that fired the event.
7414     */    
7415     configHelpText: function (p_sType, p_aArgs, p_oItem) {
7416
7417         this.cfg.refireEvent(_TEXT);
7418
7419     },
7420
7421
7422     /**
7423     * @method configURL
7424     * @description Event handler for when the "url" configuration property of 
7425     * the menu item changes.
7426     * @param {String} p_sType String representing the name of the event that 
7427     * was fired.
7428     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7429     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7430     * that fired the event.
7431     */    
7432     configURL: function (p_sType, p_aArgs, p_oItem) {
7433
7434         var sURL = p_aArgs[0];
7435
7436         if (!sURL) {
7437
7438             sURL = _HASH;
7439
7440         }
7441
7442         var oAnchor = this._oAnchor;
7443
7444         if (UA.opera) {
7445
7446             oAnchor.removeAttribute(_HREF);
7447         
7448         }
7449
7450         oAnchor.setAttribute(_HREF, sURL);
7451
7452     },
7453
7454
7455     /**
7456     * @method configTarget
7457     * @description Event handler for when the "target" configuration property 
7458     * of the menu item changes.  
7459     * @param {String} p_sType String representing the name of the event that 
7460     * was fired.
7461     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7462     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7463     * that fired the event.
7464     */    
7465     configTarget: function (p_sType, p_aArgs, p_oItem) {
7466
7467         var sTarget = p_aArgs[0],
7468             oAnchor = this._oAnchor;
7469
7470         if (sTarget && sTarget.length > 0) {
7471
7472             oAnchor.setAttribute(_TARGET, sTarget);
7473
7474         }
7475         else {
7476
7477             oAnchor.removeAttribute(_TARGET);
7478         
7479         }
7480
7481     },
7482
7483
7484     /**
7485     * @method configEmphasis
7486     * @description Event handler for when the "emphasis" configuration property
7487     * of the menu item changes.
7488     * @param {String} p_sType String representing the name of the event that 
7489     * was fired.
7490     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7491     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7492     * that fired the event.
7493     */    
7494     configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7495
7496         var bEmphasis = p_aArgs[0],
7497             oConfig = this.cfg;
7498
7499
7500         if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7501
7502             oConfig.setProperty(_STRONG_EMPHASIS, false);
7503
7504         }
7505
7506
7507         oConfig.refireEvent(_TEXT);
7508
7509     },
7510
7511
7512     /**
7513     * @method configStrongEmphasis
7514     * @description Event handler for when the "strongemphasis" configuration 
7515     * property 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     configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7523
7524         var bStrongEmphasis = p_aArgs[0],
7525             oConfig = this.cfg;
7526
7527
7528         if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7529
7530             oConfig.setProperty(_EMPHASIS, false);
7531
7532         }
7533
7534         oConfig.refireEvent(_TEXT);
7535
7536     },
7537
7538
7539     /**
7540     * @method configChecked
7541     * @description Event handler for when the "checked" configuration property 
7542     * of the menu item changes. 
7543     * @param {String} p_sType String representing the name of the event that 
7544     * was fired.
7545     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7546     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7547     * that fired the event.
7548     */    
7549     configChecked: function (p_sType, p_aArgs, p_oItem) {
7550
7551         var bChecked = p_aArgs[0],
7552             oConfig = this.cfg;
7553
7554
7555         if (bChecked) {
7556
7557             addClassNameForState.call(this, _CHECKED);
7558
7559         }
7560         else {
7561
7562             removeClassNameForState.call(this, _CHECKED);
7563         }
7564
7565
7566         oConfig.refireEvent(_TEXT);
7567
7568
7569         if (oConfig.getProperty(_DISABLED)) {
7570
7571             oConfig.refireEvent(_DISABLED);
7572
7573         }
7574
7575
7576         if (oConfig.getProperty(_SELECTED)) {
7577
7578             oConfig.refireEvent(_SELECTED);
7579
7580         }
7581
7582     },
7583
7584
7585
7586     /**
7587     * @method configDisabled
7588     * @description Event handler for when the "disabled" configuration property 
7589     * of the menu item changes. 
7590     * @param {String} p_sType String representing the name of the event that 
7591     * was fired.
7592     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7593     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7594     * that fired the event.
7595     */    
7596     configDisabled: function (p_sType, p_aArgs, p_oItem) {
7597
7598         var bDisabled = p_aArgs[0],
7599             oConfig = this.cfg,
7600             oSubmenu = oConfig.getProperty(_SUBMENU),
7601             bChecked = oConfig.getProperty(_CHECKED);
7602
7603
7604         if (bDisabled) {
7605
7606             if (oConfig.getProperty(_SELECTED)) {
7607
7608                 oConfig.setProperty(_SELECTED, false);
7609
7610             }
7611
7612
7613                         addClassNameForState.call(this, _DISABLED);
7614
7615
7616             if (oSubmenu) {
7617
7618                                 addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7619             
7620             }
7621             
7622
7623             if (bChecked) {
7624
7625                                 addClassNameForState.call(this, _CHECKED_DISABLED);
7626
7627             }
7628
7629         }
7630         else {
7631
7632                         removeClassNameForState.call(this, _DISABLED);
7633
7634
7635             if (oSubmenu) {
7636
7637                                 removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7638             
7639             }
7640             
7641
7642             if (bChecked) {
7643
7644                                 removeClassNameForState.call(this, _CHECKED_DISABLED);
7645
7646             }
7647
7648         }
7649
7650     },
7651
7652
7653     /**
7654     * @method configSelected
7655     * @description Event handler for when the "selected" configuration property 
7656     * of the menu item changes. 
7657     * @param {String} p_sType String representing the name of the event that 
7658     * was fired.
7659     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7660     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7661     * that fired the event.
7662     */    
7663     configSelected: function (p_sType, p_aArgs, p_oItem) {
7664
7665         var oConfig = this.cfg,
7666                 oAnchor = this._oAnchor,
7667                 
7668             bSelected = p_aArgs[0],
7669             bChecked = oConfig.getProperty(_CHECKED),
7670             oSubmenu = oConfig.getProperty(_SUBMENU);
7671
7672
7673         if (UA.opera) {
7674
7675             oAnchor.blur();
7676         
7677         }
7678
7679
7680         if (bSelected && !oConfig.getProperty(_DISABLED)) {
7681
7682                         addClassNameForState.call(this, _SELECTED);
7683
7684
7685             if (oSubmenu) {
7686
7687                                 addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7688             
7689             }
7690
7691
7692             if (bChecked) {
7693
7694                                 addClassNameForState.call(this, _CHECKED_SELECTED);
7695
7696             }
7697
7698         }
7699         else {
7700
7701                         removeClassNameForState.call(this, _SELECTED);
7702
7703
7704             if (oSubmenu) {
7705
7706                                 removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7707             
7708             }
7709
7710
7711             if (bChecked) {
7712
7713                                 removeClassNameForState.call(this, _CHECKED_SELECTED);
7714
7715             }
7716
7717         }
7718
7719
7720         if (this.hasFocus() && UA.opera) {
7721         
7722             oAnchor.focus();
7723         
7724         }
7725
7726     },
7727
7728
7729     /**
7730     * @method _onSubmenuBeforeHide
7731     * @description "beforehide" Custom Event handler for a submenu.
7732     * @private
7733     * @param {String} p_sType String representing the name of the event that 
7734     * was fired.
7735     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7736     */
7737     _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7738
7739         var oItem = this.parent,
7740             oMenu;
7741
7742         function onHide() {
7743
7744             oItem._oAnchor.blur();
7745             oMenu.beforeHideEvent.unsubscribe(onHide);
7746         
7747         }
7748
7749
7750         if (oItem.hasFocus()) {
7751
7752             oMenu = oItem.parent;
7753
7754             oMenu.beforeHideEvent.subscribe(onHide);
7755         
7756         }
7757     
7758     },
7759
7760
7761     /**
7762     * @method configSubmenu
7763     * @description Event handler for when the "submenu" configuration property 
7764     * of the menu item changes. 
7765     * @param {String} p_sType String representing the name of the event that 
7766     * was fired.
7767     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7768     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7769     * that fired the event.
7770     */
7771     configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7772
7773         var oSubmenu = p_aArgs[0],
7774             oConfig = this.cfg,
7775             bLazyLoad = this.parent && this.parent.lazyLoad,
7776             oMenu,
7777             sSubmenuId,
7778             oSubmenuConfig;
7779
7780
7781         if (oSubmenu) {
7782
7783             if (oSubmenu instanceof Menu) {
7784
7785                 oMenu = oSubmenu;
7786                 oMenu.parent = this;
7787                 oMenu.lazyLoad = bLazyLoad;
7788
7789             }
7790             else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7791
7792                 sSubmenuId = oSubmenu.id;
7793                 oSubmenuConfig = oSubmenu;
7794
7795                 oSubmenuConfig.lazyload = bLazyLoad;
7796                 oSubmenuConfig.parent = this;
7797
7798                 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7799
7800
7801                 // Set the value of the property to the Menu instance
7802
7803                 oConfig.setProperty(_SUBMENU, oMenu, true);
7804
7805             }
7806             else {
7807
7808                 oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7809
7810
7811                 // Set the value of the property to the Menu instance
7812                 
7813                 oConfig.setProperty(_SUBMENU, oMenu, true);
7814
7815             }
7816
7817
7818             if (oMenu) {
7819
7820                                 oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7821
7822                 addClassNameForState.call(this, _HAS_SUBMENU);
7823
7824
7825                                 if (oConfig.getProperty(_URL) === _HASH) {
7826                                 
7827                                         oConfig.setProperty(_URL, (_HASH + oMenu.id));
7828                                 
7829                                 }
7830
7831
7832                 this._oSubmenu = oMenu;
7833
7834
7835                 if (UA.opera) {
7836                 
7837                     oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);               
7838                 
7839                 }
7840             
7841             }
7842
7843         }
7844         else {
7845
7846                         removeClassNameForState.call(this, _HAS_SUBMENU);
7847
7848             if (this._oSubmenu) {
7849
7850                 this._oSubmenu.destroy();
7851
7852             }
7853
7854         }
7855
7856
7857         if (oConfig.getProperty(_DISABLED)) {
7858
7859             oConfig.refireEvent(_DISABLED);
7860
7861         }
7862
7863
7864         if (oConfig.getProperty(_SELECTED)) {
7865
7866             oConfig.refireEvent(_SELECTED);
7867
7868         }
7869
7870     },
7871
7872
7873     /**
7874     * @method configOnClick
7875     * @description Event handler for when the "onclick" configuration property 
7876     * of the menu item changes. 
7877     * @param {String} p_sType String representing the name of the event that 
7878     * was fired.
7879     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7880     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7881     * that fired the event.
7882     */
7883     configOnClick: function (p_sType, p_aArgs, p_oItem) {
7884
7885         var oObject = p_aArgs[0];
7886
7887         /*
7888             Remove any existing listeners if a "click" event handler has 
7889             already been specified.
7890         */
7891
7892         if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7893
7894             this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn, 
7895                                 this._oOnclickAttributeValue.obj);
7896
7897             this._oOnclickAttributeValue = null;
7898
7899         }
7900
7901
7902         if (!this._oOnclickAttributeValue && Lang.isObject(oObject) && 
7903             Lang.isFunction(oObject.fn)) {
7904             
7905             this.clickEvent.subscribe(oObject.fn, 
7906                 ((_OBJ in oObject) ? oObject.obj : this), 
7907                 ((_SCOPE in oObject) ? oObject.scope : null) );
7908
7909             this._oOnclickAttributeValue = oObject;
7910
7911         }
7912     
7913     },
7914
7915
7916     /**
7917     * @method configClassName
7918     * @description Event handler for when the "classname" configuration 
7919     * property of a menu item changes.
7920     * @param {String} p_sType String representing the name of the event that 
7921     * was fired.
7922     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7923     * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7924     * that fired the event.
7925     */
7926     configClassName: function (p_sType, p_aArgs, p_oItem) {
7927     
7928         var sClassName = p_aArgs[0];
7929     
7930         if (this._sClassName) {
7931     
7932             Dom.removeClass(this.element, this._sClassName);
7933     
7934         }
7935     
7936         Dom.addClass(this.element, sClassName);
7937         this._sClassName = sClassName;
7938     
7939     },
7940
7941
7942     /**
7943     * @method _dispatchClickEvent
7944     * @description Dispatches a DOM "click" event to the anchor element of a 
7945         * MenuItem instance.
7946         * @private      
7947     */
7948         _dispatchClickEvent: function () {
7949
7950                 var oMenuItem = this,
7951                         oAnchor,
7952                         oEvent;
7953
7954                 if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7955
7956                         oAnchor = Dom.getFirstChild(oMenuItem.element);
7957
7958                         //      Dispatch a "click" event to the MenuItem's anchor so that its
7959                         //      "click" event handlers will get called in response to the user 
7960                         //      pressing the keyboard shortcut defined by the "keylistener"
7961                         //      configuration property.
7962
7963                         if (UA.ie) {
7964                                 oAnchor.fireEvent(_ONCLICK);
7965                         }
7966                         else {
7967
7968                                 if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7969
7970                                         oEvent = document.createEvent("HTMLEvents");
7971                                         oEvent.initEvent(_CLICK, true, true);
7972
7973                                 }
7974                                 else {
7975
7976                                         oEvent = document.createEvent("MouseEvents");
7977                                         oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0, 
7978                                                 0, 0, false, false, false, false, 0, null);
7979
7980                                 }
7981
7982                                 oAnchor.dispatchEvent(oEvent);
7983
7984                         }
7985
7986                 }
7987
7988         },
7989
7990
7991     /**
7992     * @method _createKeyListener
7993     * @description "show" event handler for a Menu instance - responsible for 
7994         * setting up the KeyListener instance for a MenuItem.
7995         * @private      
7996     * @param {String} type String representing the name of the event that 
7997     * was fired.
7998     * @param {Array} args Array of arguments sent when the event was fired.
7999     * @param {Array} keyData Array of arguments sent when the event was fired.
8000     */
8001         _createKeyListener: function (type, args, keyData) {
8002
8003                 var oMenuItem = this,
8004                         oMenu = oMenuItem.parent;
8005
8006                 var oKeyListener = new YAHOO.util.KeyListener(
8007                                                                                 oMenu.element.ownerDocument, 
8008                                                                                 keyData, 
8009                                                                                 {
8010                                                                                         fn: oMenuItem._dispatchClickEvent, 
8011                                                                                         scope: oMenuItem, 
8012                                                                                         correctScope: true });
8013
8014
8015                 if (oMenu.cfg.getProperty(_VISIBLE)) {
8016                         oKeyListener.enable();
8017                 }
8018
8019
8020                 oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
8021                 oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
8022                 
8023                 oMenuItem._keyListener = oKeyListener;
8024                 
8025                 oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
8026                 
8027         },
8028
8029
8030     /**
8031     * @method configKeyListener
8032     * @description Event handler for when the "keylistener" configuration 
8033     * property of a menu item changes.
8034     * @param {String} p_sType String representing the name of the event that 
8035     * was fired.
8036     * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8037     */
8038     configKeyListener: function (p_sType, p_aArgs) {
8039
8040                 var oKeyData = p_aArgs[0],
8041                         oMenuItem = this,
8042                         oMenu = oMenuItem.parent;
8043
8044                 if (oMenuItem._keyData) {
8045
8046                         //      Unsubscribe from the "show" event in case the keylistener 
8047                         //      config was changed before the Menu was ever made visible.
8048
8049                         oMenu.unsubscribe(_SHOW, 
8050                                         oMenuItem._createKeyListener, oMenuItem._keyData);
8051
8052                         oMenuItem._keyData = null;                                      
8053                                         
8054                 }
8055
8056
8057                 //      Tear down for the previous value of the "keylistener" property
8058
8059                 if (oMenuItem._keyListener) {
8060
8061                         oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
8062                         oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
8063
8064                         oMenuItem._keyListener.disable();
8065                         oMenuItem._keyListener = null;
8066
8067                 }
8068
8069
8070         if (oKeyData) {
8071         
8072                         oMenuItem._keyData = oKeyData;
8073
8074                         //      Defer the creation of the KeyListener instance until the 
8075                         //      parent Menu is visible.  This is necessary since the 
8076                         //      KeyListener instance needs to be bound to the document the 
8077                         //      Menu has been rendered into.  Deferring creation of the 
8078                         //      KeyListener instance also improves performance.
8079
8080                         oMenu.subscribe(_SHOW, oMenuItem._createKeyListener, 
8081                                 oKeyData, oMenuItem);
8082                 }
8083     
8084     },
8085
8086
8087     // Public methods
8088
8089
8090         /**
8091     * @method initDefaultConfig
8092         * @description Initializes an item's configurable properties.
8093         */
8094         initDefaultConfig : function () {
8095
8096         var oConfig = this.cfg;
8097
8098
8099         // Define the configuration attributes
8100
8101         /**
8102         * @config text
8103         * @description String specifying the text label for the menu item.  
8104         * When building a menu from existing HTML the value of this property
8105         * will be interpreted from the menu's markup.
8106         * @default ""
8107         * @type String
8108         */
8109         oConfig.addProperty(
8110             TEXT_CONFIG.key, 
8111             { 
8112                 handler: this.configText, 
8113                 value: TEXT_CONFIG.value, 
8114                 validator: TEXT_CONFIG.validator, 
8115                 suppressEvent: TEXT_CONFIG.suppressEvent 
8116             }
8117         );
8118         
8119
8120         /**
8121         * @config helptext
8122         * @description String specifying additional instructional text to 
8123         * accompany the text for the menu item.
8124         * @deprecated Use "text" configuration property to add help text markup.  
8125         * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em 
8126         * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
8127         * @default null
8128         * @type String|<a href="http://www.w3.org/TR/
8129         * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8130         * HTMLElement</a>
8131         */
8132         oConfig.addProperty(
8133             HELP_TEXT_CONFIG.key,
8134             {
8135                 handler: this.configHelpText, 
8136                 supercedes: HELP_TEXT_CONFIG.supercedes,
8137                 suppressEvent: HELP_TEXT_CONFIG.suppressEvent 
8138             }
8139         );
8140
8141
8142         /**
8143         * @config url
8144         * @description String specifying the URL for the menu item's anchor's 
8145         * "href" attribute.  When building a menu from existing HTML the value 
8146         * of this property will be interpreted from the menu's markup.
8147         * @default "#"
8148         * @type String
8149         */        
8150         oConfig.addProperty(
8151             URL_CONFIG.key, 
8152             {
8153                 handler: this.configURL, 
8154                 value: URL_CONFIG.value, 
8155                 suppressEvent: URL_CONFIG.suppressEvent
8156             }
8157         );
8158
8159
8160         /**
8161         * @config target
8162         * @description String specifying the value for the "target" attribute 
8163         * of the menu item's anchor element. <strong>Specifying a target will 
8164         * require the user to click directly on the menu item's anchor node in
8165         * order to cause the browser to navigate to the specified URL.</strong> 
8166         * When building a menu from existing HTML the value of this property 
8167         * will be interpreted from the menu's markup.
8168         * @default null
8169         * @type String
8170         */        
8171         oConfig.addProperty(
8172             TARGET_CONFIG.key, 
8173             {
8174                 handler: this.configTarget, 
8175                 suppressEvent: TARGET_CONFIG.suppressEvent
8176             }
8177         );
8178
8179
8180         /**
8181         * @config emphasis
8182         * @description Boolean indicating if the text of the menu item will be 
8183         * rendered with emphasis.
8184         * @deprecated Use the "text" configuration property to add emphasis.  
8185         * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some 
8186         * Text&#60;/em&#62;");</code>
8187         * @default false
8188         * @type Boolean
8189         */
8190         oConfig.addProperty(
8191             EMPHASIS_CONFIG.key, 
8192             { 
8193                 handler: this.configEmphasis, 
8194                 value: EMPHASIS_CONFIG.value, 
8195                 validator: EMPHASIS_CONFIG.validator, 
8196                 suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8197                 supercedes: EMPHASIS_CONFIG.supercedes
8198             }
8199         );
8200
8201
8202         /**
8203         * @config strongemphasis
8204         * @description Boolean indicating if the text of the menu item will be 
8205         * rendered with strong emphasis.
8206         * @deprecated Use the "text" configuration property to add strong emphasis.  
8207         * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62; 
8208         * Some Text&#60;/strong&#62;");</code>
8209         * @default false
8210         * @type Boolean
8211         */
8212         oConfig.addProperty(
8213             STRONG_EMPHASIS_CONFIG.key,
8214             {
8215                 handler: this.configStrongEmphasis,
8216                 value: STRONG_EMPHASIS_CONFIG.value,
8217                 validator: STRONG_EMPHASIS_CONFIG.validator,
8218                 suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8219                 supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8220             }
8221         );
8222
8223
8224         /**
8225         * @config checked
8226         * @description Boolean indicating if the menu item should be rendered 
8227         * with a checkmark.
8228         * @default false
8229         * @type Boolean
8230         */
8231         oConfig.addProperty(
8232             CHECKED_CONFIG.key, 
8233             {
8234                 handler: this.configChecked, 
8235                 value: CHECKED_CONFIG.value, 
8236                 validator: CHECKED_CONFIG.validator, 
8237                 suppressEvent: CHECKED_CONFIG.suppressEvent,
8238                 supercedes: CHECKED_CONFIG.supercedes
8239             } 
8240         );
8241
8242
8243         /**
8244         * @config disabled
8245         * @description Boolean indicating if the menu item should be disabled.  
8246         * (Disabled menu items are  dimmed and will not respond to user input 
8247         * or fire events.)
8248         * @default false
8249         * @type Boolean
8250         */
8251         oConfig.addProperty(
8252             DISABLED_CONFIG.key,
8253             {
8254                 handler: this.configDisabled,
8255                 value: DISABLED_CONFIG.value,
8256                 validator: DISABLED_CONFIG.validator,
8257                 suppressEvent: DISABLED_CONFIG.suppressEvent
8258             }
8259         );
8260
8261
8262         /**
8263         * @config selected
8264         * @description Boolean indicating if the menu item should 
8265         * be highlighted.
8266         * @default false
8267         * @type Boolean
8268         */
8269         oConfig.addProperty(
8270             SELECTED_CONFIG.key,
8271             {
8272                 handler: this.configSelected,
8273                 value: SELECTED_CONFIG.value,
8274                 validator: SELECTED_CONFIG.validator,
8275                 suppressEvent: SELECTED_CONFIG.suppressEvent
8276             }
8277         );
8278
8279
8280         /**
8281         * @config submenu
8282         * @description Object specifying the submenu to be appended to the 
8283         * menu item.  The value can be one of the following: <ul><li>Object 
8284         * specifying a Menu instance.</li><li>Object literal specifying the
8285         * menu to be created.  Format: <code>{ id: [menu id], itemdata: 
8286         * [<a href="YAHOO.widget.Menu.html#itemData">array of values for 
8287         * items</a>] }</code>.</li><li>String specifying the id attribute 
8288         * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
8289         * Object specifying the <code>&#60;div&#62;</code> element of the 
8290         * menu.</li></ul>
8291         * @default null
8292         * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8293         * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8294         * HTMLElement</a>
8295         */
8296         oConfig.addProperty(
8297             SUBMENU_CONFIG.key, 
8298             {
8299                 handler: this.configSubmenu, 
8300                 supercedes: SUBMENU_CONFIG.supercedes,
8301                 suppressEvent: SUBMENU_CONFIG.suppressEvent
8302             }
8303         );
8304
8305
8306         /**
8307         * @config onclick
8308         * @description Object literal representing the code to be executed when 
8309         * the item is clicked.  Format:<br> <code> {<br> 
8310         * <strong>fn:</strong> Function,   &#47;&#47; The handler to call when 
8311         * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An 
8312         * object to  pass back to the handler.<br> <strong>scope:</strong> 
8313         * Object &#47;&#47; The object to use for the scope of the handler.
8314         * <br> } </code>
8315         * @type Object
8316         * @default null
8317         */
8318         oConfig.addProperty(
8319             ONCLICK_CONFIG.key, 
8320             {
8321                 handler: this.configOnClick, 
8322                 suppressEvent: ONCLICK_CONFIG.suppressEvent 
8323             }
8324         );
8325
8326
8327         /**
8328         * @config classname
8329         * @description CSS class to be applied to the menu item's root 
8330         * <code>&#60;li&#62;</code> element.  The specified class(es) are 
8331         * appended in addition to the default class as specified by the menu 
8332         * item's CSS_CLASS_NAME constant.
8333         * @default null
8334         * @type String
8335         */
8336         oConfig.addProperty(
8337             CLASS_NAME_CONFIG.key, 
8338             { 
8339                 handler: this.configClassName,
8340                 value: CLASS_NAME_CONFIG.value, 
8341                 validator: CLASS_NAME_CONFIG.validator,
8342                 suppressEvent: CLASS_NAME_CONFIG.suppressEvent 
8343             }
8344         );
8345
8346
8347         /**
8348         * @config keylistener
8349         * @description Object literal representing the key(s) that can be used 
8350                 * to trigger the MenuItem's "click" event.  Possible attributes are 
8351                 * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int 
8352                 * or an array of ints representing keycodes).
8353         * @default null
8354         * @type Object
8355         */
8356         oConfig.addProperty(
8357             KEY_LISTENER_CONFIG.key, 
8358             { 
8359                 handler: this.configKeyListener,
8360                 value: KEY_LISTENER_CONFIG.value, 
8361                 suppressEvent: KEY_LISTENER_CONFIG.suppressEvent 
8362             }
8363         );
8364
8365         },
8366
8367     /**
8368     * @method getNextSibling
8369     * @description Finds the menu item's next sibling.
8370     * @return YAHOO.widget.MenuItem
8371     */
8372         getNextSibling: function () {
8373         
8374                 var isUL = function (el) {
8375                                 return (el.nodeName.toLowerCase() === "ul");
8376                         },
8377         
8378                         menuitemEl = this.element,
8379                         next = Dom.getNextSibling(menuitemEl),
8380                         parent,
8381                         sibling,
8382                         list;
8383                 
8384                 if (!next) {
8385                         
8386                         parent = menuitemEl.parentNode;
8387                         sibling = Dom.getNextSiblingBy(parent, isUL);
8388                         
8389                         if (sibling) {
8390                                 list = sibling;
8391                         }
8392                         else {
8393                                 list = Dom.getFirstChildBy(parent.parentNode, isUL);
8394                         }
8395                         
8396                         next = Dom.getFirstChild(list);
8397                         
8398                 }
8399
8400                 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8401
8402         },
8403
8404     /**
8405     * @method getNextEnabledSibling
8406     * @description Finds the menu item's next enabled sibling.
8407     * @return YAHOO.widget.MenuItem
8408     */
8409         getNextEnabledSibling: function () {
8410                 
8411                 var next = this.getNextSibling();
8412                 
8413         return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
8414                 
8415         },
8416
8417
8418     /**
8419     * @method getPreviousSibling
8420     * @description Finds the menu item's previous sibling.
8421     * @return {YAHOO.widget.MenuItem}
8422     */  
8423         getPreviousSibling: function () {
8424
8425                 var isUL = function (el) {
8426                                 return (el.nodeName.toLowerCase() === "ul");
8427                         },
8428
8429                         menuitemEl = this.element,
8430                         next = Dom.getPreviousSibling(menuitemEl),
8431                         parent,
8432                         sibling,
8433                         list;
8434                 
8435                 if (!next) {
8436                         
8437                         parent = menuitemEl.parentNode;
8438                         sibling = Dom.getPreviousSiblingBy(parent, isUL);
8439                         
8440                         if (sibling) {
8441                                 list = sibling;
8442                         }
8443                         else {
8444                                 list = Dom.getLastChildBy(parent.parentNode, isUL);
8445                         }
8446                         
8447                         next = Dom.getLastChild(list);
8448                         
8449                 }
8450
8451                 return YAHOO.widget.MenuManager.getMenuItem(next.id);
8452                 
8453         },
8454
8455
8456     /**
8457     * @method getPreviousEnabledSibling
8458     * @description Finds the menu item's previous enabled sibling.
8459     * @return {YAHOO.widget.MenuItem}
8460     */
8461         getPreviousEnabledSibling: function () {
8462                 
8463                 var next = this.getPreviousSibling();
8464                 
8465         return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
8466                 
8467         },
8468
8469
8470     /**
8471     * @method focus
8472     * @description Causes the menu item to receive the focus and fires the 
8473     * focus event.
8474     */
8475     focus: function () {
8476
8477         var oParent = this.parent,
8478             oAnchor = this._oAnchor,
8479             oActiveItem = oParent.activeItem;
8480
8481
8482         function setFocus() {
8483
8484             try {
8485
8486                 if (!(UA.ie && !document.hasFocus())) {
8487                 
8488                                         if (oActiveItem) {
8489                 
8490                                                 oActiveItem.blurEvent.fire();
8491                 
8492                                         }
8493         
8494                                         oAnchor.focus();
8495                                         
8496                                         this.focusEvent.fire();
8497                 
8498                 }
8499
8500             }
8501             catch(e) {
8502             
8503             }
8504
8505         }
8506
8507
8508         if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) && 
8509             this.element.style.display != _NONE) {
8510
8511
8512             /*
8513                 Setting focus via a timer fixes a race condition in Firefox, IE 
8514                 and Opera where the browser viewport jumps as it trys to 
8515                 position and focus the menu.
8516             */
8517
8518             Lang.later(0, this, setFocus);
8519
8520         }
8521
8522     },
8523
8524
8525     /**
8526     * @method blur
8527     * @description Causes the menu item to lose focus and fires the 
8528     * blur event.
8529     */    
8530     blur: function () {
8531
8532         var oParent = this.parent;
8533
8534         if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8535
8536             Lang.later(0, this, function () {
8537
8538                 try {
8539     
8540                     this._oAnchor.blur();
8541                     this.blurEvent.fire();    
8542
8543                 } 
8544                 catch (e) {
8545                 
8546                 }
8547                 
8548             }, 0);
8549
8550         }
8551
8552     },
8553
8554
8555     /**
8556     * @method hasFocus
8557     * @description Returns a boolean indicating whether or not the menu item
8558     * has focus.
8559     * @return {Boolean}
8560     */
8561     hasFocus: function () {
8562     
8563         return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8564     
8565     },
8566
8567
8568         /**
8569     * @method destroy
8570         * @description Removes the menu item's <code>&#60;li&#62;</code> element 
8571         * from its parent <code>&#60;ul&#62;</code> element.
8572         */
8573     destroy: function () {
8574
8575         var oEl = this.element,
8576             oSubmenu,
8577             oParentNode,
8578             aEventData,
8579             i;
8580
8581
8582         if (oEl) {
8583
8584
8585             // If the item has a submenu, destroy it first
8586
8587             oSubmenu = this.cfg.getProperty(_SUBMENU);
8588
8589             if (oSubmenu) {
8590             
8591                 oSubmenu.destroy();
8592             
8593             }
8594
8595
8596             // Remove the element from the parent node
8597
8598             oParentNode = oEl.parentNode;
8599
8600             if (oParentNode) {
8601
8602                 oParentNode.removeChild(oEl);
8603
8604                 this.destroyEvent.fire();
8605
8606             }
8607
8608
8609             // Remove CustomEvent listeners
8610
8611                         i = EVENT_TYPES.length - 1;
8612
8613                         do {
8614
8615                                 aEventData = EVENT_TYPES[i];
8616                                 
8617                                 this[aEventData[0]].unsubscribeAll();
8618
8619                         }
8620                         while (i--);
8621             
8622             
8623             this.cfg.configChangedEvent.unsubscribeAll();
8624
8625         }
8626
8627     },
8628
8629
8630     /**
8631     * @method toString
8632     * @description Returns a string representing the menu item.
8633     * @return {String}
8634     */
8635     toString: function () {
8636
8637         var sReturnVal = _MENUITEM,
8638             sId = this.id;
8639
8640         if (sId) {
8641     
8642             sReturnVal += (_SPACE + sId);
8643         
8644         }
8645
8646         return sReturnVal;
8647     
8648     }
8649
8650 };
8651
8652 Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8653
8654 })();
8655 (function () {
8656
8657         var _XY = "xy",
8658                 _MOUSEDOWN = "mousedown",
8659                 _CONTEXTMENU = "ContextMenu",
8660                 _SPACE = " ";
8661
8662 /**
8663 * Creates a list of options or commands which are made visible in response to 
8664 * an HTML element's "contextmenu" event ("mousedown" for Opera).
8665 *
8666 * @param {String} p_oElement String specifying the id attribute of the 
8667 * <code>&#60;div&#62;</code> element of the context menu.
8668 * @param {String} p_oElement String specifying the id attribute of the 
8669 * <code>&#60;select&#62;</code> element to be used as the data source for the 
8670 * context menu.
8671 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8672 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8673 * <code>&#60;div&#62;</code> element of the context menu.
8674 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8675 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8676 * the <code>&#60;select&#62;</code> element to be used as the data source for 
8677 * the context menu.
8678 * @param {Object} p_oConfig Optional. Object literal specifying the 
8679 * configuration for the context menu. See configuration class documentation 
8680 * for more details.
8681 * @class ContextMenu
8682 * @constructor
8683 * @extends YAHOO.widget.Menu
8684 * @namespace YAHOO.widget
8685 */
8686 YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8687
8688     YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8689
8690 };
8691
8692
8693 var Event = YAHOO.util.Event,
8694         UA = YAHOO.env.ua,
8695     ContextMenu = YAHOO.widget.ContextMenu,
8696
8697
8698
8699     /**
8700     * Constant representing the name of the ContextMenu's events
8701     * @property EVENT_TYPES
8702     * @private
8703     * @final
8704     * @type Object
8705     */
8706     EVENT_TYPES = {
8707
8708         "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8709         "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8710         "CLICK": "click"
8711
8712     },
8713     
8714     
8715     /**
8716     * Constant representing the ContextMenu's configuration properties
8717     * @property DEFAULT_CONFIG
8718     * @private
8719     * @final
8720     * @type Object
8721     */
8722     TRIGGER_CONFIG = { 
8723                 key: "trigger",
8724                 suppressEvent: true
8725     };
8726
8727
8728 /**
8729 * @method position
8730 * @description "beforeShow" event handler used to position the contextmenu.
8731 * @private
8732 * @param {String} p_sType String representing the name of the event that 
8733 * was fired.
8734 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8735 * @param {Array} p_aPos Array representing the xy position for the context menu.
8736 */
8737 function position(p_sType, p_aArgs, p_aPos) {
8738
8739     this.cfg.setProperty(_XY, p_aPos);
8740     
8741     this.beforeShowEvent.unsubscribe(position, p_aPos);
8742
8743 }
8744
8745
8746 YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8747
8748
8749
8750 // Private properties
8751
8752
8753 /**
8754 * @property _oTrigger
8755 * @description Object reference to the current value of the "trigger" 
8756 * configuration property.
8757 * @default null
8758 * @private
8759 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8760 * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8761 */
8762 _oTrigger: null,
8763
8764
8765 /**
8766 * @property _bCancelled
8767 * @description Boolean indicating if the display of the context menu should 
8768 * be cancelled.
8769 * @default false
8770 * @private
8771 * @type Boolean
8772 */
8773 _bCancelled: false,
8774
8775
8776
8777 // Public properties
8778
8779
8780 /**
8781 * @property contextEventTarget
8782 * @description Object reference for the HTML element that was the target of the
8783 * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of 
8784 * the context menu.
8785 * @default null
8786 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8787 * html.html#ID-58190037">HTMLElement</a>
8788 */
8789 contextEventTarget: null,
8790
8791
8792
8793 // Events
8794
8795
8796 /**
8797 * @event triggerContextMenuEvent
8798 * @description Custom Event wrapper for the "contextmenu" DOM event 
8799 * ("mousedown" for Opera) fired by the element(s) that trigger the display of 
8800 * the context menu.
8801 */
8802 triggerContextMenuEvent: null,
8803
8804
8805
8806 /**
8807 * @method init
8808 * @description The ContextMenu class's initialization method. This method is 
8809 * automatically called by the constructor, and sets up all DOM references for 
8810 * pre-existing markup, and creates required markup if it is not already present.
8811 * @param {String} p_oElement String specifying the id attribute of the 
8812 * <code>&#60;div&#62;</code> element of the context menu.
8813 * @param {String} p_oElement String specifying the id attribute of the 
8814 * <code>&#60;select&#62;</code> element to be used as the data source for 
8815 * the context menu.
8816 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8817 * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8818 * <code>&#60;div&#62;</code> element of the context menu.
8819 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8820 * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8821 * the <code>&#60;select&#62;</code> element to be used as the data source for 
8822 * the context menu.
8823 * @param {Object} p_oConfig Optional. Object literal specifying the 
8824 * configuration for the context menu. See configuration class documentation 
8825 * for more details.
8826 */
8827 init: function(p_oElement, p_oConfig) {
8828
8829
8830     // Call the init of the superclass (YAHOO.widget.Menu)
8831
8832     ContextMenu.superclass.init.call(this, p_oElement);
8833
8834
8835     this.beforeInitEvent.fire(ContextMenu);
8836
8837
8838     if (p_oConfig) {
8839
8840         this.cfg.applyConfig(p_oConfig, true);
8841
8842     }
8843     
8844     this.initEvent.fire(ContextMenu);
8845     
8846 },
8847
8848
8849 /**
8850 * @method initEvents
8851 * @description Initializes the custom events for the context menu.
8852 */
8853 initEvents: function() {
8854
8855         ContextMenu.superclass.initEvents.call(this);
8856
8857     // Create custom events
8858
8859     this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8860
8861     this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8862
8863 },
8864
8865
8866 /**
8867 * @method cancel
8868 * @description Cancels the display of the context menu.
8869 */
8870 cancel: function() {
8871
8872     this._bCancelled = true;
8873
8874 },
8875
8876
8877
8878 // Private methods
8879
8880
8881 /**
8882 * @method _removeEventHandlers
8883 * @description Removes all of the DOM event handlers from the HTML element(s) 
8884 * whose "context menu" event ("click" for Opera) trigger the display of 
8885 * the context menu.
8886 * @private
8887 */
8888 _removeEventHandlers: function() {
8889
8890     var oTrigger = this._oTrigger;
8891
8892
8893     // Remove the event handlers from the trigger(s)
8894
8895     if (oTrigger) {
8896
8897         Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);    
8898         
8899         if (UA.opera) {
8900         
8901             Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8902     
8903         }
8904
8905     }
8906
8907 },
8908
8909
8910
8911 // Private event handlers
8912
8913
8914
8915 /**
8916 * @method _onTriggerClick
8917 * @description "click" event handler for the HTML element(s) identified as the 
8918 * "trigger" for the context menu.  Used to cancel default behaviors in Opera.
8919 * @private
8920 * @param {Event} p_oEvent Object representing the DOM event object passed back 
8921 * by the event utility (YAHOO.util.Event).
8922 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8923 * menu that is handling the event.
8924 */
8925 _onTriggerClick: function(p_oEvent, p_oMenu) {
8926
8927     if (p_oEvent.ctrlKey) {
8928     
8929         Event.stopEvent(p_oEvent);
8930
8931     }
8932     
8933 },
8934
8935
8936 /**
8937 * @method _onTriggerContextMenu
8938 * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML 
8939 * element(s) that trigger the display of the context menu.
8940 * @private
8941 * @param {Event} p_oEvent Object representing the DOM event object passed back 
8942 * by the event utility (YAHOO.util.Event).
8943 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8944 * menu that is handling the event.
8945 */
8946 _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8947
8948     var aXY;
8949
8950     if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8951         
8952                 this.contextEventTarget = Event.getTarget(p_oEvent);
8953         
8954                 this.triggerContextMenuEvent.fire(p_oEvent);
8955                 
8956         
8957                 if (!this._bCancelled) {
8958
8959                         /*
8960                                 Prevent the browser's default context menu from appearing and 
8961                                 stop the propagation of the "contextmenu" event so that 
8962                                 other ContextMenu instances are not displayed.
8963                         */
8964
8965                         Event.stopEvent(p_oEvent);
8966
8967
8968                         // Hide any other Menu instances that might be visible
8969
8970                         YAHOO.widget.MenuManager.hideVisible();
8971                         
8972         
8973
8974                         // Position and display the context menu
8975         
8976                         aXY = Event.getXY(p_oEvent);
8977         
8978         
8979                         if (!YAHOO.util.Dom.inDocument(this.element)) {
8980         
8981                                 this.beforeShowEvent.subscribe(position, aXY);
8982         
8983                         }
8984                         else {
8985         
8986                                 this.cfg.setProperty(_XY, aXY);
8987                         
8988                         }
8989         
8990         
8991                         this.show();
8992         
8993                 }
8994         
8995                 this._bCancelled = false;
8996
8997     }
8998
8999 },
9000
9001
9002
9003 // Public methods
9004
9005
9006 /**
9007 * @method toString
9008 * @description Returns a string representing the context menu.
9009 * @return {String}
9010 */
9011 toString: function() {
9012
9013     var sReturnVal = _CONTEXTMENU,
9014         sId = this.id;
9015
9016     if (sId) {
9017
9018         sReturnVal += (_SPACE + sId);
9019     
9020     }
9021
9022     return sReturnVal;
9023
9024 },
9025
9026
9027 /**
9028 * @method initDefaultConfig
9029 * @description Initializes the class's configurable properties which can be 
9030 * changed using the context menu's Config object ("cfg").
9031 */
9032 initDefaultConfig: function() {
9033
9034     ContextMenu.superclass.initDefaultConfig.call(this);
9035
9036     /**
9037     * @config trigger
9038     * @description The HTML element(s) whose "contextmenu" event ("mousedown" 
9039     * for Opera) trigger the display of the context menu.  Can be a string 
9040     * representing the id attribute of the HTML element, an object reference 
9041     * for the HTML element, or an array of strings or HTML element references.
9042     * @default null
9043     * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
9044     * level-one-html.html#ID-58190037">HTMLElement</a>|Array
9045     */
9046     this.cfg.addProperty(TRIGGER_CONFIG.key, 
9047         {
9048             handler: this.configTrigger, 
9049             suppressEvent: TRIGGER_CONFIG.suppressEvent 
9050         }
9051     );
9052
9053 },
9054
9055
9056 /**
9057 * @method destroy
9058 * @description Removes the context menu's <code>&#60;div&#62;</code> element 
9059 * (and accompanying child nodes) from the document.
9060 */
9061 destroy: function() {
9062
9063     // Remove the DOM event handlers from the current trigger(s)
9064
9065     this._removeEventHandlers();
9066
9067
9068     // Continue with the superclass implementation of this method
9069
9070     ContextMenu.superclass.destroy.call(this);
9071
9072 },
9073
9074
9075
9076 // Public event handlers for configuration properties
9077
9078
9079 /**
9080 * @method configTrigger
9081 * @description Event handler for when the value of the "trigger" configuration 
9082 * property changes. 
9083 * @param {String} p_sType String representing the name of the event that 
9084 * was fired.
9085 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9086 * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
9087 * menu that fired the event.
9088 */
9089 configTrigger: function(p_sType, p_aArgs, p_oMenu) {
9090     
9091     var oTrigger = p_aArgs[0];
9092
9093     if (oTrigger) {
9094
9095         /*
9096             If there is a current "trigger" - remove the event handlers 
9097             from that element(s) before assigning new ones
9098         */
9099
9100         if (this._oTrigger) {
9101         
9102             this._removeEventHandlers();
9103
9104         }
9105
9106         this._oTrigger = oTrigger;
9107
9108
9109         /*
9110             Listen for the "mousedown" event in Opera b/c it does not 
9111             support the "contextmenu" event
9112         */ 
9113   
9114         Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9115
9116
9117         /*
9118             Assign a "click" event handler to the trigger element(s) for
9119             Opera to prevent default browser behaviors.
9120         */
9121
9122         if (UA.opera) {
9123         
9124             Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9125
9126         }
9127
9128     }
9129     else {
9130    
9131         this._removeEventHandlers();
9132     
9133     }
9134     
9135 }
9136
9137 }); // END YAHOO.lang.extend
9138
9139 }());
9140
9141
9142
9143 /**
9144 * Creates an item for a context menu.
9145
9146 * @param {String} p_oObject String specifying the text of the context menu item.
9147 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9148 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9149 * <code>&#60;li&#62;</code> element of the context menu item.
9150 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9151 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9152 * specifying the <code>&#60;optgroup&#62;</code> element of the context 
9153 * menu item.
9154 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9155 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9156 * the <code>&#60;option&#62;</code> element of the context menu item.
9157 * @param {Object} p_oConfig Optional. Object literal specifying the 
9158 * configuration for the context menu item. See configuration class 
9159 * documentation for more details.
9160 * @class ContextMenuItem
9161 * @constructor
9162 * @extends YAHOO.widget.MenuItem
9163 * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9164 * are of type YAHOO.widget.MenuItem.
9165 */
9166 YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9167 (function () {
9168
9169         var Lang = YAHOO.lang,
9170
9171                 // String constants
9172         
9173                 _STATIC = "static",
9174                 _DYNAMIC_STATIC = "dynamic," + _STATIC,
9175                 _DISABLED = "disabled",
9176                 _SELECTED = "selected",
9177                 _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9178                 _SUBMENU = "submenu",
9179                 _VISIBLE = "visible",
9180                 _SPACE = " ",
9181                 _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9182                 _MENUBAR = "MenuBar";
9183
9184 /**
9185 * Horizontal collection of items, each of which can contain a submenu.
9186
9187 * @param {String} p_oElement String specifying the id attribute of the 
9188 * <code>&#60;div&#62;</code> element of the menu bar.
9189 * @param {String} p_oElement String specifying the id attribute of the 
9190 * <code>&#60;select&#62;</code> element to be used as the data source for the 
9191 * menu bar.
9192 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9193 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
9194 * the <code>&#60;div&#62;</code> element of the menu bar.
9195 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9196 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
9197 * specifying the <code>&#60;select&#62;</code> element to be used as the data 
9198 * source for the menu bar.
9199 * @param {Object} p_oConfig Optional. Object literal specifying the 
9200 * configuration for the menu bar. See configuration class documentation for
9201 * more details.
9202 * @class MenuBar
9203 * @constructor
9204 * @extends YAHOO.widget.Menu
9205 * @namespace YAHOO.widget
9206 */
9207 YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9208
9209     YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9210
9211 };
9212
9213
9214 /**
9215 * @method checkPosition
9216 * @description Checks to make sure that the value of the "position" property 
9217 * is one of the supported strings. Returns true if the position is supported.
9218 * @private
9219 * @param {Object} p_sPosition String specifying the position of the menu.
9220 * @return {Boolean}
9221 */
9222 function checkPosition(p_sPosition) {
9223
9224         var returnVal = false;
9225
9226     if (Lang.isString(p_sPosition)) {
9227
9228         returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9229
9230     }
9231     
9232     return returnVal;
9233
9234 }
9235
9236
9237 var Event = YAHOO.util.Event,
9238     MenuBar = YAHOO.widget.MenuBar,
9239
9240     POSITION_CONFIG =  { 
9241                 key: "position", 
9242                 value: _STATIC, 
9243                 validator: checkPosition, 
9244                 supercedes: [_VISIBLE] 
9245         }, 
9246
9247         SUBMENU_ALIGNMENT_CONFIG =  { 
9248                 key: "submenualignment", 
9249                 value: ["tl","bl"]
9250         },
9251
9252         AUTO_SUBMENU_DISPLAY_CONFIG =  { 
9253                 key: _AUTO_SUBMENU_DISPLAY, 
9254                 value: false, 
9255                 validator: Lang.isBoolean,
9256                 suppressEvent: true
9257         },
9258         
9259         SUBMENU_TOGGLE_REGION_CONFIG = {
9260                 key: _SUBMENU_TOGGLE_REGION, 
9261                 value: false, 
9262                 validator: Lang.isBoolean
9263         };
9264
9265
9266
9267 Lang.extend(MenuBar, YAHOO.widget.Menu, {
9268
9269 /**
9270 * @method init
9271 * @description The MenuBar class's initialization method. This method is 
9272 * automatically called by the constructor, and sets up all DOM references for 
9273 * pre-existing markup, and creates required markup if it is not already present.
9274 * @param {String} p_oElement String specifying the id attribute of the 
9275 * <code>&#60;div&#62;</code> element of the menu bar.
9276 * @param {String} p_oElement String specifying the id attribute of the 
9277 * <code>&#60;select&#62;</code> element to be used as the data source for the 
9278 * menu bar.
9279 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9280 * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
9281 * the <code>&#60;div&#62;</code> element of the menu bar.
9282 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9283 * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
9284 * specifying the <code>&#60;select&#62;</code> element to be used as the data 
9285 * source for the menu bar.
9286 * @param {Object} p_oConfig Optional. Object literal specifying the 
9287 * configuration for the menu bar. See configuration class documentation for
9288 * more details.
9289 */
9290 init: function(p_oElement, p_oConfig) {
9291
9292     if(!this.ITEM_TYPE) {
9293
9294         this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9295
9296     }
9297
9298
9299     // Call the init of the superclass (YAHOO.widget.Menu)
9300
9301     MenuBar.superclass.init.call(this, p_oElement);
9302
9303
9304     this.beforeInitEvent.fire(MenuBar);
9305
9306
9307     if(p_oConfig) {
9308
9309         this.cfg.applyConfig(p_oConfig, true);
9310
9311     }
9312
9313     this.initEvent.fire(MenuBar);
9314
9315 },
9316
9317
9318
9319 // Constants
9320
9321
9322 /**
9323 * @property CSS_CLASS_NAME
9324 * @description String representing the CSS class(es) to be applied to the menu 
9325 * bar's <code>&#60;div&#62;</code> element.
9326 * @default "yuimenubar"
9327 * @final
9328 * @type String
9329 */
9330 CSS_CLASS_NAME: "yuimenubar",
9331
9332
9333 /**
9334 * @property SUBMENU_TOGGLE_REGION_WIDTH
9335 * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9336 * display of the MenuBarItem's submenu.
9337 * @default 20
9338 * @final
9339 * @type Number
9340 */
9341 SUBMENU_TOGGLE_REGION_WIDTH: 20,
9342
9343
9344 // Protected event handlers
9345
9346
9347 /**
9348 * @method _onKeyDown
9349 * @description "keydown" Custom Event handler for the menu bar.
9350 * @private
9351 * @param {String} p_sType String representing the name of the event that 
9352 * was fired.
9353 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9354 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9355 * that fired the event.
9356 */
9357 _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9358
9359     var oEvent = p_aArgs[0],
9360         oItem = p_aArgs[1],
9361         oSubmenu,
9362         oItemCfg,
9363         oNextItem;
9364
9365
9366     if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9367
9368         oItemCfg = oItem.cfg;
9369
9370         switch(oEvent.keyCode) {
9371     
9372             case 37:    // Left arrow
9373             case 39:    // Right arrow
9374     
9375                 if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9376     
9377                     oItemCfg.setProperty(_SELECTED, true);
9378     
9379                 }
9380                 else {
9381     
9382                     oNextItem = (oEvent.keyCode == 37) ? 
9383                         oItem.getPreviousEnabledSibling() : 
9384                         oItem.getNextEnabledSibling();
9385             
9386                     if(oNextItem) {
9387     
9388                         this.clearActiveItem();
9389     
9390                         oNextItem.cfg.setProperty(_SELECTED, true);
9391                         
9392                                                 oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9393                                                 
9394                                                 if(oSubmenu) {
9395                                         
9396                                                         oSubmenu.show();
9397                                                         oSubmenu.setInitialFocus();
9398                                                 
9399                                                 }
9400                                                 else {
9401                                                         oNextItem.focus();  
9402                                                 }
9403     
9404                     }
9405     
9406                 }
9407     
9408                 Event.preventDefault(oEvent);
9409     
9410             break;
9411     
9412             case 40:    // Down arrow
9413     
9414                 if(this.activeItem != oItem) {
9415     
9416                     this.clearActiveItem();
9417     
9418                     oItemCfg.setProperty(_SELECTED, true);
9419                     oItem.focus();
9420                 
9421                 }
9422     
9423                 oSubmenu = oItemCfg.getProperty(_SUBMENU);
9424     
9425                 if(oSubmenu) {
9426     
9427                     if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9428     
9429                         oSubmenu.setInitialSelection();
9430                         oSubmenu.setInitialFocus();
9431                     
9432                     }
9433                     else {
9434     
9435                         oSubmenu.show();
9436                         oSubmenu.setInitialFocus();
9437                     
9438                     }
9439     
9440                 }
9441     
9442                 Event.preventDefault(oEvent);
9443     
9444             break;
9445     
9446         }
9447
9448     }
9449
9450
9451     if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9452
9453         oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9454
9455         if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9456         
9457             oSubmenu.hide();
9458             this.activeItem.focus();
9459         
9460         }
9461         else {
9462
9463             this.activeItem.cfg.setProperty(_SELECTED, false);
9464             this.activeItem.blur();
9465     
9466         }
9467
9468         Event.preventDefault(oEvent);
9469     
9470     }
9471
9472 },
9473
9474
9475 /**
9476 * @method _onClick
9477 * @description "click" event handler for the menu bar.
9478 * @protected
9479 * @param {String} p_sType String representing the name of the event that 
9480 * was fired.
9481 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9482 * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9483 * that fired the event.
9484 */
9485 _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9486
9487     MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9488
9489     var oItem = p_aArgs[1],
9490         bReturnVal = true,
9491         oItemEl,
9492         oEvent,
9493         oTarget,
9494         oActiveItem,
9495         oConfig,
9496         oSubmenu,
9497         nMenuItemX,
9498         nToggleRegion;
9499
9500
9501         var toggleSubmenuDisplay = function () {
9502
9503                 if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9504                 
9505                         oSubmenu.hide();
9506                 
9507                 }
9508                 else {
9509                 
9510                         oSubmenu.show();                    
9511                 
9512                 }
9513         
9514         };
9515     
9516
9517     if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9518
9519         oEvent = p_aArgs[0];
9520         oTarget = Event.getTarget(oEvent);
9521         oActiveItem = this.activeItem;
9522         oConfig = this.cfg;
9523
9524
9525         // Hide any other submenus that might be visible
9526     
9527         if(oActiveItem && oActiveItem != oItem) {
9528     
9529             this.clearActiveItem();
9530     
9531         }
9532
9533     
9534         oItem.cfg.setProperty(_SELECTED, true);
9535     
9536
9537         // Show the submenu for the item
9538     
9539         oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9540
9541
9542         if(oSubmenu) {
9543
9544                         oItemEl = oItem.element;
9545                         nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9546                         nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9547
9548                         if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9549
9550                                 if (Event.getPageX(oEvent) > nToggleRegion) {
9551
9552                                         toggleSubmenuDisplay();
9553
9554                                         Event.preventDefault(oEvent);
9555
9556                                         /*
9557                                                  Return false so that other click event handlers are not called when the 
9558                                                  user clicks inside the toggle region.
9559                                         */
9560                                         bReturnVal = false;
9561                                 
9562                                 }
9563         
9564                 }
9565                         else {
9566
9567                                 toggleSubmenuDisplay();
9568             
9569             }
9570         
9571         }
9572     
9573     }
9574
9575
9576         return bReturnVal;
9577
9578 },
9579
9580
9581
9582 // Public methods
9583
9584 /**
9585 * @method configSubmenuToggle
9586 * @description Event handler for when the "submenutoggleregion" configuration property of 
9587 * a MenuBar changes.
9588 * @param {String} p_sType The name of the event that was fired.
9589 * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9590 */
9591 configSubmenuToggle: function (p_sType, p_aArgs) {
9592
9593         var bSubmenuToggle = p_aArgs[0];
9594         
9595         if (bSubmenuToggle) {
9596         
9597                 this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9598         
9599         }
9600
9601 },
9602
9603
9604 /**
9605 * @method toString
9606 * @description Returns a string representing the menu bar.
9607 * @return {String}
9608 */
9609 toString: function() {
9610
9611     var sReturnVal = _MENUBAR,
9612         sId = this.id;
9613
9614     if(sId) {
9615
9616         sReturnVal += (_SPACE + sId);
9617     
9618     }
9619
9620     return sReturnVal;
9621
9622 },
9623
9624
9625 /**
9626 * @description Initializes the class's configurable properties which can be
9627 * changed using the menu bar's Config object ("cfg").
9628 * @method initDefaultConfig
9629 */
9630 initDefaultConfig: function() {
9631
9632     MenuBar.superclass.initDefaultConfig.call(this);
9633
9634     var oConfig = this.cfg;
9635
9636         // Add configuration properties
9637
9638
9639     /*
9640         Set the default value for the "position" configuration property
9641         to "static" by re-adding the property.
9642     */
9643
9644
9645     /**
9646     * @config position
9647     * @description String indicating how a menu bar should be positioned on the 
9648     * screen.  Possible values are "static" and "dynamic."  Static menu bars 
9649     * are visible by default and reside in the normal flow of the document 
9650     * (CSS position: static).  Dynamic menu bars are hidden by default, reside
9651     * out of the normal flow of the document (CSS position: absolute), and can 
9652     * overlay other elements on the screen.
9653     * @default static
9654     * @type String
9655     */
9656     oConfig.addProperty(
9657         POSITION_CONFIG.key, 
9658         {
9659             handler: this.configPosition, 
9660             value: POSITION_CONFIG.value, 
9661             validator: POSITION_CONFIG.validator,
9662             supercedes: POSITION_CONFIG.supercedes
9663         }
9664     );
9665
9666
9667     /*
9668         Set the default value for the "submenualignment" configuration property
9669         to ["tl","bl"] by re-adding the property.
9670     */
9671
9672     /**
9673     * @config submenualignment
9674     * @description Array defining how submenus should be aligned to their 
9675     * parent menu bar item. The format is: [itemCorner, submenuCorner].
9676     * @default ["tl","bl"]
9677     * @type Array
9678     */
9679     oConfig.addProperty(
9680         SUBMENU_ALIGNMENT_CONFIG.key, 
9681         {
9682             value: SUBMENU_ALIGNMENT_CONFIG.value,
9683             suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9684         }
9685     );
9686
9687
9688     /*
9689         Change the default value for the "autosubmenudisplay" configuration 
9690         property to "false" by re-adding the property.
9691     */
9692
9693     /**
9694     * @config autosubmenudisplay
9695     * @description Boolean indicating if submenus are automatically made 
9696     * visible when the user mouses over the menu bar's items.
9697     * @default false
9698     * @type Boolean
9699     */
9700         oConfig.addProperty(
9701            AUTO_SUBMENU_DISPLAY_CONFIG.key, 
9702            {
9703                value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
9704                validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9705                suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9706        } 
9707     );
9708
9709
9710     /**
9711     * @config submenutoggleregion
9712     * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the 
9713     * display of a submenu.  The default width of the region is determined by the value of the
9714     * SUBMENU_TOGGLE_REGION_WIDTH property.  If set to true, the autosubmenudisplay 
9715     * configuration property will be set to false, and any click event listeners will not be 
9716     * called when the user clicks inside the submenu toggle region of a MenuBarItem.  If the 
9717     * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its 
9718     * standard behavior.
9719     * @default false
9720     * @type Boolean
9721     */
9722         oConfig.addProperty(
9723            SUBMENU_TOGGLE_REGION_CONFIG.key, 
9724            {
9725                value: SUBMENU_TOGGLE_REGION_CONFIG.value, 
9726                validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9727                handler: this.configSubmenuToggle
9728        } 
9729     );
9730
9731 }
9732  
9733 }); // END YAHOO.lang.extend
9734
9735 }());
9736
9737
9738
9739 /**
9740 * Creates an item for a menu bar.
9741
9742 * @param {String} p_oObject String specifying the text of the menu bar item.
9743 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9744 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9745 * <code>&#60;li&#62;</code> element of the menu bar item.
9746 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9747 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9748 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9749 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9750 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9751 * the <code>&#60;option&#62;</code> element of the menu bar item.
9752 * @param {Object} p_oConfig Optional. Object literal specifying the 
9753 * configuration for the menu bar item. See configuration class documentation 
9754 * for more details.
9755 * @class MenuBarItem
9756 * @constructor
9757 * @extends YAHOO.widget.MenuItem
9758 */
9759 YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9760
9761     YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9762
9763 };
9764
9765 YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9766
9767
9768
9769 /**
9770 * @method init
9771 * @description The MenuBarItem class's initialization method. This method is 
9772 * automatically called by the constructor, and sets up all DOM references for 
9773 * pre-existing markup, and creates required markup if it is not already present.
9774 * @param {String} p_oObject String specifying the text of the menu bar item.
9775 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9776 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9777 * <code>&#60;li&#62;</code> element of the menu bar item.
9778 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9779 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9780 * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9781 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9782 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9783 * the <code>&#60;option&#62;</code> element of the menu bar item.
9784 * @param {Object} p_oConfig Optional. Object literal specifying the 
9785 * configuration for the menu bar item. See configuration class documentation 
9786 * for more details.
9787 */
9788 init: function(p_oObject, p_oConfig) {
9789
9790     if(!this.SUBMENU_TYPE) {
9791
9792         this.SUBMENU_TYPE = YAHOO.widget.Menu;
9793
9794     }
9795
9796
9797     /* 
9798         Call the init of the superclass (YAHOO.widget.MenuItem)
9799         Note: We don't pass the user config in here yet 
9800         because we only want it executed once, at the lowest 
9801         subclass level.
9802     */ 
9803
9804     YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);  
9805
9806
9807     var oConfig = this.cfg;
9808
9809     if(p_oConfig) {
9810
9811         oConfig.applyConfig(p_oConfig, true);
9812
9813     }
9814
9815     oConfig.fireQueue();
9816
9817 },
9818
9819
9820
9821 // Constants
9822
9823
9824 /**
9825 * @property CSS_CLASS_NAME
9826 * @description String representing the CSS class(es) to be applied to the 
9827 * <code>&#60;li&#62;</code> element of the menu bar item.
9828 * @default "yuimenubaritem"
9829 * @final
9830 * @type String
9831 */
9832 CSS_CLASS_NAME: "yuimenubaritem",
9833
9834
9835 /**
9836 * @property CSS_LABEL_CLASS_NAME
9837 * @description String representing the CSS class(es) to be applied to the 
9838 * menu bar item's <code>&#60;a&#62;</code> element.
9839 * @default "yuimenubaritemlabel"
9840 * @final
9841 * @type String
9842 */
9843 CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9844
9845
9846
9847 // Public methods
9848
9849
9850 /**
9851 * @method toString
9852 * @description Returns a string representing the menu bar item.
9853 * @return {String}
9854 */
9855 toString: function() {
9856
9857     var sReturnVal = "MenuBarItem";
9858
9859     if(this.cfg && this.cfg.getProperty("text")) {
9860
9861         sReturnVal += (": " + this.cfg.getProperty("text"));
9862
9863     }
9864
9865     return sReturnVal;
9866
9867 }
9868     
9869 }); // END YAHOO.lang.extend
9870 YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.8.1", build: "19"});