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