PageSourceSearch

https://hiergraph.github.io/SEAL_files/menu.js

js hiergraph.github.io collected 2026-10-03 09:17:43 UTC 224,448 bytes, 8,982 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.