Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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