~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/node-menunav/node-menunav.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
7
 
*/
8
 
YUI.add('node-menunav', function(Y) {
9
 
 
10
 
/**
11
 
* <p>The MenuNav Node Plugin makes it easy to transform existing list-based 
12
 
* markup into traditional, drop down navigational menus that are both accessible 
13
 
* and easy to customize, and only require a small set of dependencies.</p>
14
 
15
 
16
 
* <p>To use the MenuNav Node Plugin, simply pass a reference to the plugin to a 
17
 
* Node instance's <code>plug</code> method.</p>
18
 
19
 
* <p>
20
 
* <code>
21
 
* &#60;script type="text/javascript"&#62; <br>
22
 
* <br>
23
 
*               //      Call the "use" method, passing in "node-menunav".  This will <br>
24
 
*               //      load the script and CSS for the MenuNav Node Plugin and all of <br>
25
 
*               //      the required dependencies. <br>
26
 
* <br>
27
 
*               YUI().use("node-menunav", function(Y) { <br>
28
 
* <br>
29
 
*                       //      Use the "contentready" event to initialize the menu when <br>
30
 
*                       //      the subtree of element representing the root menu <br>
31
 
*                       //      (&#60;div id="menu-1"&#62;) is ready to be scripted. <br>
32
 
* <br>
33
 
*                       Y.on("contentready", function () { <br>
34
 
* <br>
35
 
*                               //      The scope of the callback will be a Node instance <br>
36
 
*                               //      representing the root menu (&#60;div id="menu-1"&#62;). <br>
37
 
*                               //      Therefore, since "this" represents a Node instance, it <br>
38
 
*                               //      is possible to just call "this.plug" passing in a <br>
39
 
*                               //      reference to the MenuNav Node Plugin. <br>
40
 
* <br>
41
 
*                               this.plug(Y.Plugin.NodeMenuNav); <br>
42
 
* <br>
43
 
*                       }, "#menu-1"); <br>
44
 
* <br>          
45
 
*               }); <br>
46
 
* <br>  
47
 
*       &#60;/script&#62; <br>
48
 
* </code>
49
 
* </p>
50
 
*
51
 
* <p>The MenuNav Node Plugin has several configuration properties that can be 
52
 
* set via an object literal that is passed as a second argument to a Node 
53
 
* instance's <code>plug</code> method.
54
 
* </p>
55
 
*
56
 
* <p>
57
 
* <code>
58
 
* &#60;script type="text/javascript"&#62; <br>
59
 
* <br>
60
 
*               //      Call the "use" method, passing in "node-menunav".  This will <br>
61
 
*               //      load the script and CSS for the MenuNav Node Plugin and all of <br>
62
 
*               //      the required dependencies. <br>
63
 
* <br>
64
 
*               YUI().use("node-menunav", function(Y) { <br>
65
 
* <br>
66
 
*                       //      Use the "contentready" event to initialize the menu when <br>
67
 
*                       //      the subtree of element representing the root menu <br>
68
 
*                       //      (&#60;div id="menu-1"&#62;) is ready to be scripted. <br>
69
 
* <br>
70
 
*                       Y.on("contentready", function () { <br>
71
 
* <br>
72
 
*                               //      The scope of the callback will be a Node instance <br>
73
 
*                               //      representing the root menu (&#60;div id="menu-1"&#62;). <br>
74
 
*                               //      Therefore, since "this" represents a Node instance, it <br>
75
 
*                               //      is possible to just call "this.plug" passing in a <br>
76
 
*                               //      reference to the MenuNav Node Plugin. <br>
77
 
* <br>
78
 
*                               this.plug(Y.Plugin.NodeMenuNav, { mouseOutHideDelay: 1000 });
79
 
* <br><br>
80
 
*                       }, "#menu-1"); <br>
81
 
* <br>          
82
 
*               }); <br>
83
 
* <br>  
84
 
*       &#60;/script&#62; <br>
85
 
* </code>
86
 
* </p>
87
 
88
 
* @module node-menunav
89
 
*/
90
 
 
91
 
 
92
 
        //      Util shortcuts
93
 
 
94
 
var UA = Y.UA,
95
 
        later = Y.later,
96
 
        getClassName = Y.ClassNameManager.getClassName,
97
 
 
98
 
 
99
 
 
100
 
        //      Frequently used strings
101
 
 
102
 
        MENU = "menu",
103
 
        MENUITEM = "menuitem",
104
 
        HIDDEN = "hidden",
105
 
        PARENT_NODE = "parentNode",
106
 
        CHILDREN = "children",
107
 
        OFFSET_HEIGHT = "offsetHeight",
108
 
        OFFSET_WIDTH = "offsetWidth",
109
 
        PX = "px",
110
 
        ID = "id",
111
 
        PERIOD = ".",
112
 
        HANDLED_MOUSEOUT = "handledMouseOut",
113
 
        HANDLED_MOUSEOVER = "handledMouseOver",
114
 
        ACTIVE = "active",
115
 
        LABEL = "label",
116
 
        LOWERCASE_A = "a",
117
 
        MOUSEDOWN = "mousedown",
118
 
        KEYDOWN = "keydown",
119
 
        CLICK = "click",
120
 
        EMPTY_STRING = "",
121
 
        FIRST_OF_TYPE = "first-of-type",
122
 
        ROLE = "role",
123
 
        PRESENTATION = "presentation",
124
 
        DESCENDANTS = "descendants",
125
 
        UI = "UI",
126
 
        ACTIVE_DESCENDANT = "activeDescendant",
127
 
        USE_ARIA = "useARIA",
128
 
        ARIA_HIDDEN = "aria-hidden",
129
 
        CONTENT = "content",
130
 
        HOST = "host",
131
 
        ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
132
 
 
133
 
 
134
 
        //      Attribute keys
135
 
        
136
 
        AUTO_SUBMENU_DISPLAY = "autoSubmenuDisplay",
137
 
        MOUSEOUT_HIDE_DELAY = "mouseOutHideDelay",
138
 
 
139
 
 
140
 
        //      CSS class names
141
 
 
142
 
        CSS_MENU = getClassName(MENU),
143
 
        CSS_MENU_HIDDEN = getClassName(MENU, HIDDEN),
144
 
        CSS_MENU_HORIZONTAL = getClassName(MENU, "horizontal"),
145
 
        CSS_MENU_LABEL = getClassName(MENU, LABEL),
146
 
        CSS_MENU_LABEL_ACTIVE = getClassName(MENU, LABEL, ACTIVE),
147
 
        CSS_MENU_LABEL_MENUVISIBLE = getClassName(MENU, LABEL, (MENU + "visible")),
148
 
        CSS_MENUITEM = getClassName(MENUITEM),
149
 
        CSS_MENUITEM_ACTIVE = getClassName(MENUITEM, ACTIVE),
150
 
 
151
 
 
152
 
        //      CSS selectors
153
 
        
154
 
        MENU_SELECTOR = PERIOD + CSS_MENU,
155
 
        MENU_TOGGLE_SELECTOR = (PERIOD + getClassName(MENU, "toggle")),
156
 
    MENU_CONTENT_SELECTOR = PERIOD + getClassName(MENU, CONTENT),
157
 
    MENU_LABEL_SELECTOR = PERIOD + CSS_MENU_LABEL,
158
 
 
159
 
        STANDARD_QUERY = ">" + MENU_CONTENT_SELECTOR + ">ul>li>a",
160
 
        EXTENDED_QUERY = ">" + MENU_CONTENT_SELECTOR + ">ul>li>" + MENU_LABEL_SELECTOR + ">a:first-child";
161
 
 
162
 
//      Utility functions
163
 
 
164
 
 
165
 
var getPreviousSibling = function (node) {
166
 
 
167
 
        var oPrevious = node.previous(),
168
 
                oChildren;
169
 
 
170
 
        if (!oPrevious) {
171
 
                oChildren = node.get(PARENT_NODE).get(CHILDREN);
172
 
                oPrevious = oChildren.item(oChildren.size() - 1);
173
 
        }
174
 
        
175
 
        return oPrevious;
176
 
 
177
 
};
178
 
 
179
 
 
180
 
var getNextSibling = function (node) {
181
 
 
182
 
        var oNext = node.next();
183
 
 
184
 
        if (!oNext) {
185
 
                oNext = node.get(PARENT_NODE).get(CHILDREN).item(0);            
186
 
        }
187
 
        
188
 
        return oNext;
189
 
 
190
 
};
191
 
 
192
 
 
193
 
var isAnchor = function (node) {
194
 
        
195
 
        var bReturnVal = false;
196
 
        
197
 
        if (node) {
198
 
                bReturnVal = node.get("nodeName").toLowerCase() === LOWERCASE_A;
199
 
        }
200
 
        
201
 
        return bReturnVal;
202
 
        
203
 
};
204
 
 
205
 
 
206
 
var isMenuItem = function (node) {
207
 
 
208
 
        return node.hasClass(CSS_MENUITEM);
209
 
 
210
 
};
211
 
 
212
 
 
213
 
var isMenuLabel = function (node) {
214
 
 
215
 
        return node.hasClass(CSS_MENU_LABEL);
216
 
 
217
 
};
218
 
 
219
 
 
220
 
var isHorizontalMenu = function (menu) {
221
 
 
222
 
        return menu.hasClass(CSS_MENU_HORIZONTAL);
223
 
 
224
 
};
225
 
 
226
 
 
227
 
var hasVisibleSubmenu = function (menuLabel) {
228
 
 
229
 
        return menuLabel.hasClass(CSS_MENU_LABEL_MENUVISIBLE);
230
 
 
231
 
};
232
 
 
233
 
 
234
 
var getItemAnchor = function (node) {
235
 
 
236
 
        return isAnchor(node) ? node : node.one(LOWERCASE_A);
237
 
 
238
 
};
239
 
 
240
 
 
241
 
var getNodeWithClass = function (node, className, searchAncestors) {
242
 
 
243
 
        var oItem;
244
 
        
245
 
        if (node) {
246
 
                
247
 
                if (node.hasClass(className)) {
248
 
                        oItem = node;
249
 
                }
250
 
                
251
 
                if (!oItem && searchAncestors) {
252
 
                        oItem = node.ancestor((PERIOD + className));
253
 
                }
254
 
        
255
 
        }
256
 
        
257
 
        return oItem;
258
 
 
259
 
};
260
 
 
261
 
 
262
 
var getParentMenu = function (node) {
263
 
 
264
 
        return node.ancestor(MENU_SELECTOR);
265
 
        
266
 
};
267
 
 
268
 
 
269
 
var getMenu = function (node, searchAncestors) {
270
 
 
271
 
        return getNodeWithClass(node, CSS_MENU, searchAncestors);
272
 
 
273
 
};
274
 
 
275
 
 
276
 
var getMenuItem = function (node, searchAncestors) {
277
 
 
278
 
        var oItem;
279
 
        
280
 
        if (node) {
281
 
                oItem = getNodeWithClass(node, CSS_MENUITEM, searchAncestors);
282
 
        }
283
 
        
284
 
        return oItem;
285
 
 
286
 
};
287
 
 
288
 
 
289
 
var getMenuLabel = function (node, searchAncestors) {
290
 
 
291
 
        var oItem;
292
 
        
293
 
        if (node) {
294
 
        
295
 
                if (searchAncestors) {
296
 
                        oItem = getNodeWithClass(node, CSS_MENU_LABEL, searchAncestors);
297
 
                }
298
 
                else {
299
 
                        oItem = getNodeWithClass(node, CSS_MENU_LABEL) || 
300
 
                                node.one((PERIOD + CSS_MENU_LABEL));
301
 
                }
302
 
                
303
 
        }
304
 
        
305
 
        return oItem;
306
 
 
307
 
};
308
 
 
309
 
 
310
 
var getItem = function (node, searchAncestors) {
311
 
 
312
 
        var oItem;
313
 
        
314
 
        if (node) {
315
 
                oItem = getMenuItem(node, searchAncestors) || 
316
 
                        getMenuLabel(node, searchAncestors);
317
 
        }
318
 
        
319
 
        return oItem;   
320
 
 
321
 
};
322
 
 
323
 
 
324
 
var getFirstItem = function (menu) {
325
 
        
326
 
        return getItem(menu.one("li"));
327
 
 
328
 
};
329
 
 
330
 
 
331
 
var getActiveClass = function (node) {
332
 
 
333
 
        return isMenuItem(node) ? CSS_MENUITEM_ACTIVE : CSS_MENU_LABEL_ACTIVE;
334
 
 
335
 
};
336
 
 
337
 
 
338
 
var handleMouseOverForNode = function (node, target) {
339
 
 
340
 
        return node && !node[HANDLED_MOUSEOVER] && 
341
 
                (node.compareTo(target) || node.contains(target));
342
 
 
343
 
};
344
 
 
345
 
 
346
 
var handleMouseOutForNode = function (node, relatedTarget) {
347
 
 
348
 
        return node && !node[HANDLED_MOUSEOUT] && 
349
 
                (!node.compareTo(relatedTarget) && !node.contains(relatedTarget));
350
 
 
351
 
};
352
 
 
353
 
/**
354
 
* The NodeMenuNav class is a plugin for a Node instance.  The class is used via  
355
 
* the <a href="Node.html#method_plug"><code>plug</code></a> method of Node and 
356
 
* should not be instantiated directly.
357
 
* @namespace plugin
358
 
* @class NodeMenuNav
359
 
*/
360
 
var NodeMenuNav = function () {
361
 
 
362
 
        NodeMenuNav.superclass.constructor.apply(this, arguments);
363
 
 
364
 
};
365
 
 
366
 
NodeMenuNav.NAME = "nodeMenuNav";
367
 
NodeMenuNav.NS = "menuNav";
368
 
 
369
 
 
370
 
/** 
371
 
* @property NodeMenuNav.SHIM_TEMPLATE_TITLE
372
 
* @description String representing the value for the <code>title</code> 
373
 
* attribute for the shim used to prevent <code>&#60;select&#62;</code> elements 
374
 
* from poking through menus in IE 6.
375
 
* @default "Menu Stacking Shim"
376
 
* @type String
377
 
*/
378
 
NodeMenuNav.SHIM_TEMPLATE_TITLE = "Menu Stacking Shim";
379
 
 
380
 
 
381
 
/** 
382
 
* @property NodeMenuNav.SHIM_TEMPLATE
383
 
* @description String representing the HTML used to create the 
384
 
* <code>&#60;iframe&#62;</code> shim used to prevent 
385
 
* <code>&#60;select&#62;</code> elements from poking through menus in IE 6.
386
 
* @default &#34;&#60;iframe frameborder=&#34;0&#34; tabindex=&#34;-1&#34; 
387
 
* class=&#34;yui-shim&#34; title=&#34;Menu Stacking Shim&#34; 
388
 
* src=&#34;javascript:false;&#34;&#62;&#60;/iframe&#62;&#34;
389
 
* @type String
390
 
*/
391
 
 
392
 
//      <iframe> shim notes:
393
 
//
394
 
//      1) Need to set the "frameBorder" property to 0 to suppress the default 
395
 
//      <iframe> border in IE.  (Setting the CSS "border" property alone doesn't  
396
 
//      suppress it.) 
397
 
//
398
 
//      2) The "src" attribute of the <iframe> is set to "javascript:false;" so 
399
 
//      that it won't load a page inside it, preventing the secure/nonsecure 
400
 
//      warning in IE when using HTTPS.
401
 
//
402
 
//      3) Since the role of the <iframe> shim is completely presentational, its 
403
 
//      "tabindex" attribute is set to "-1" and its title attribute is set to 
404
 
//      "Menu Stacking Shim".  Both strategies help users of screen readers to 
405
 
//      avoid mistakenly interacting with the <iframe> shim.
406
 
 
407
 
NodeMenuNav.SHIM_TEMPLATE = '<iframe frameborder="0" tabindex="-1" class="' + 
408
 
                                                        getClassName("shim") + 
409
 
                                                        '" title="' + NodeMenuNav.SHIM_TEMPLATE_TITLE + 
410
 
                                                        '" src="javascript:false;"></iframe>';
411
 
 
412
 
 
413
 
NodeMenuNav.ATTRS = {
414
 
 
415
 
        /**
416
 
        * Boolean indicating if use of the WAI-ARIA Roles and States should be 
417
 
        * enabled for the menu.
418
 
        *
419
 
        * @attribute useARIA
420
 
        * @readOnly
421
 
        * @writeOnce    
422
 
        * @default true
423
 
        * @type boolean
424
 
        */
425
 
        useARIA: {
426
 
                
427
 
                value: true,
428
 
                writeOnce: true,
429
 
                lazyAdd: false,
430
 
                setter: function (value) {
431
 
 
432
 
                        var oMenu = this.get(HOST),
433
 
                                oMenuLabel,
434
 
                                oMenuToggle,
435
 
                                oSubmenu,
436
 
                                sID;
437
 
 
438
 
                        if (value) {
439
 
 
440
 
                                oMenu.set(ROLE, MENU);
441
 
 
442
 
                                oMenu.all("ul,li," + MENU_CONTENT_SELECTOR).set(ROLE, PRESENTATION);
443
 
 
444
 
                                oMenu.all((PERIOD + getClassName(MENUITEM, CONTENT))).set(ROLE, MENUITEM);
445
 
 
446
 
                                oMenu.all((PERIOD + CSS_MENU_LABEL)).each(function (node) {
447
 
 
448
 
                                        oMenuLabel = node;
449
 
                                        oMenuToggle = node.one(MENU_TOGGLE_SELECTOR);
450
 
 
451
 
                                        if (oMenuToggle) {
452
 
                                                oMenuToggle.set(ROLE, PRESENTATION);
453
 
                                                oMenuLabel = oMenuToggle.previous();
454
 
                                        }
455
 
 
456
 
                                        oMenuLabel.set(ROLE, MENUITEM);
457
 
                                        oMenuLabel.set("aria-haspopup", true);
458
 
 
459
 
                                        oSubmenu = node.next();
460
 
 
461
 
                                        if (oSubmenu) {
462
 
 
463
 
                                                oSubmenu.set(ROLE, MENU);
464
 
 
465
 
                                                oMenuLabel = oSubmenu.previous();
466
 
                                                oMenuToggle = oMenuLabel.one(MENU_TOGGLE_SELECTOR);
467
 
 
468
 
                                                if (oMenuToggle) {
469
 
                                                        oMenuLabel = oMenuToggle;
470
 
                                                }
471
 
 
472
 
                                                sID = Y.stamp(oMenuLabel);
473
 
 
474
 
                                                if (!oMenuLabel.get(ID)) {
475
 
                                                        oMenuLabel.set(ID, sID);
476
 
                                                }
477
 
 
478
 
                                                oSubmenu.set("aria-labelledby", sID);
479
 
                                                oSubmenu.set(ARIA_HIDDEN, true);
480
 
                                                
481
 
                                        }
482
 
 
483
 
                                });
484
 
                                
485
 
                        }
486
 
 
487
 
                }
488
 
                
489
 
        },
490
 
 
491
 
 
492
 
        /**
493
 
        * Boolean indicating if submenus are automatically made visible when the 
494
 
        * user mouses over the menu's items.
495
 
        *
496
 
        * @attribute autoSubmenuDisplay
497
 
        * @readOnly
498
 
        * @writeOnce    
499
 
        * @default true
500
 
        * @type boolean
501
 
        */      
502
 
        autoSubmenuDisplay: {
503
 
                
504
 
                value: true,
505
 
                writeOnce: true
506
 
                
507
 
        },
508
 
 
509
 
 
510
 
        /**
511
 
        * Number indicating the time (in milliseconds) that should expire before a 
512
 
        * submenu is made visible when the user mouses over the menu's label.
513
 
        *
514
 
        * @attribute submenuShowDelay
515
 
        * @readOnly
516
 
        * @writeOnce    
517
 
        * @default 250
518
 
        * @type Number
519
 
        */
520
 
        submenuShowDelay: {
521
 
                
522
 
                value: 250,
523
 
                writeOnce: true
524
 
                
525
 
        },
526
 
 
527
 
 
528
 
        /**
529
 
        * Number indicating the time (in milliseconds) that should expire before a 
530
 
        * submenu is hidden when the user mouses out of a menu label heading in the 
531
 
        * direction of a submenu.  
532
 
        *
533
 
        * @attribute submenuHideDelay
534
 
        * @readOnly
535
 
        * @writeOnce    
536
 
        * @default 250
537
 
        * @type Number
538
 
        */
539
 
        submenuHideDelay: {
540
 
                
541
 
                value: 250,
542
 
                writeOnce: true
543
 
                
544
 
        },
545
 
 
546
 
 
547
 
        /**
548
 
        * Number indicating the time (in milliseconds) that should expire before a 
549
 
        * submenu is hidden when the user mouses out of it.
550
 
        * 
551
 
        * @attribute mouseOutHideDelay
552
 
        * @readOnly
553
 
        * @writeOnce    
554
 
        * @default 750
555
 
        * @type Number
556
 
        */      
557
 
        mouseOutHideDelay: {
558
 
                
559
 
                value: 750,
560
 
                writeOnce: true
561
 
                
562
 
        }
563
 
 
564
 
};
565
 
 
566
 
 
567
 
Y.extend(NodeMenuNav, Y.Plugin.Base, {
568
 
 
569
 
        //      Protected properties
570
 
 
571
 
        /** 
572
 
        * @property _rootMenu
573
 
        * @description Node instance representing the root menu in the menu.
574
 
        * @default null
575
 
        * @protected
576
 
        * @type Node
577
 
        */
578
 
        _rootMenu: null,        
579
 
 
580
 
 
581
 
        /** 
582
 
        * @property _activeItem
583
 
        * @description Node instance representing the menu's active descendent: 
584
 
        * the menuitem or menu label the user is currently interacting with.
585
 
        * @default null
586
 
        * @protected
587
 
        * @type Node
588
 
        */
589
 
        _activeItem: null, 
590
 
 
591
 
 
592
 
        /** 
593
 
        * @property _activeMenu
594
 
        * @description Node instance representing the menu that is the parent of 
595
 
        * the menu's active descendent.
596
 
        * @default null
597
 
        * @protected
598
 
        * @type Node
599
 
        */
600
 
        _activeMenu: null,
601
 
 
602
 
 
603
 
        /** 
604
 
        * @property _hasFocus
605
 
        * @description Boolean indicating if the menu has focus.
606
 
        * @default false
607
 
        * @protected
608
 
        * @type Boolean
609
 
        */
610
 
        _hasFocus: false,
611
 
 
612
 
 
613
 
        //      In gecko-based browsers a mouseover and mouseout event will fire even 
614
 
        //      if a DOM element moves out from under the mouse without the user 
615
 
        //      actually moving the mouse.  This bug affects NodeMenuNav because the  
616
 
        //      user can hit the Esc key to hide a menu, and if the mouse is over the  
617
 
        //      menu when the user presses Esc, the _onMenuMouseOut handler will be 
618
 
        //      called.  To fix this bug the following flag (_blockMouseEvent) is used 
619
 
        // to block the code in the _onMenuMouseOut handler from executing.
620
 
 
621
 
        /** 
622
 
        * @property _blockMouseEvent
623
 
        * @description Boolean indicating whether or not to handle the 
624
 
        * "mouseover" event.
625
 
        * @default false
626
 
        * @protected
627
 
        * @type Boolean
628
 
        */
629
 
        _blockMouseEvent: false,
630
 
 
631
 
 
632
 
        /** 
633
 
        * @property _currentMouseX
634
 
        * @description Number representing the current x coordinate of the mouse 
635
 
        * inside the menu.
636
 
        * @default 0
637
 
        * @protected
638
 
        * @type Number
639
 
        */
640
 
        _currentMouseX: 0,
641
 
 
642
 
 
643
 
        /** 
644
 
        * @property _movingToSubmenu
645
 
        * @description Boolean indicating if the mouse is moving from a menu 
646
 
        * label to its corresponding submenu.
647
 
        * @default false
648
 
        * @protected
649
 
        * @type Boolean
650
 
        */
651
 
        _movingToSubmenu: false,
652
 
 
653
 
 
654
 
        /** 
655
 
        * @property _showSubmenuTimer
656
 
        * @description Timer used to show a submenu.
657
 
        * @default null
658
 
        * @protected
659
 
        * @type Object
660
 
        */
661
 
        _showSubmenuTimer: null,
662
 
 
663
 
 
664
 
        /** 
665
 
        * @property _hideSubmenuTimer
666
 
        * @description Timer used to hide a submenu.
667
 
        * @default null
668
 
        * @protected
669
 
        * @type Object
670
 
        */
671
 
        _hideSubmenuTimer: null,
672
 
 
673
 
 
674
 
        /** 
675
 
        * @property _hideAllSubmenusTimer
676
 
        * @description Timer used to hide a all submenus.
677
 
        * @default null
678
 
        * @protected
679
 
        * @type Object
680
 
        */
681
 
        _hideAllSubmenusTimer: null,
682
 
 
683
 
 
684
 
        /** 
685
 
        * @property _firstItem
686
 
        * @description Node instance representing the first item (menuitem or menu 
687
 
        * label) in the root menu of a menu.
688
 
        * @default null
689
 
        * @protected
690
 
        * @type Node
691
 
        */
692
 
        _firstItem: null,
693
 
 
694
 
 
695
 
        //      Public methods
696
 
 
697
 
 
698
 
    initializer: function (config) {
699
 
 
700
 
                var menuNav = this,
701
 
                        oRootMenu = this.get(HOST),
702
 
                        aHandlers = [],
703
 
                        oDoc;
704
 
 
705
 
 
706
 
                if (oRootMenu) {
707
 
 
708
 
                        menuNav._rootMenu = oRootMenu;
709
 
 
710
 
                        oRootMenu.all("ul:first-child").addClass(FIRST_OF_TYPE);
711
 
 
712
 
                        //      Hide all visible submenus
713
 
 
714
 
                        oRootMenu.all(MENU_SELECTOR).addClass(CSS_MENU_HIDDEN);
715
 
 
716
 
 
717
 
                        //      Wire up all event handlers
718
 
 
719
 
                        aHandlers.push(oRootMenu.on("mouseover", menuNav._onMouseOver, menuNav));
720
 
                        aHandlers.push(oRootMenu.on("mouseout", menuNav._onMouseOut, menuNav));
721
 
                        aHandlers.push(oRootMenu.on("mousemove", menuNav._onMouseMove, menuNav));
722
 
                        aHandlers.push(oRootMenu.on(MOUSEDOWN, menuNav._toggleSubmenuDisplay, menuNav));
723
 
                        aHandlers.push(Y.on("key", menuNav._toggleSubmenuDisplay, oRootMenu, "down:13", menuNav));
724
 
                        aHandlers.push(oRootMenu.on(CLICK, menuNav._toggleSubmenuDisplay, menuNav));
725
 
                        aHandlers.push(oRootMenu.on("keypress", menuNav._onKeyPress, menuNav));
726
 
                        aHandlers.push(oRootMenu.on(KEYDOWN, menuNav._onKeyDown, menuNav));
727
 
 
728
 
                        oDoc = oRootMenu.get("ownerDocument");
729
 
 
730
 
                    aHandlers.push(oDoc.on(MOUSEDOWN, menuNav._onDocMouseDown, menuNav));
731
 
                        aHandlers.push(oDoc.on("focus", menuNav._onDocFocus, menuNav));
732
 
 
733
 
                        this._eventHandlers = aHandlers;
734
 
 
735
 
                        menuNav._initFocusManager();
736
 
 
737
 
                }
738
 
                
739
 
 
740
 
    },
741
 
 
742
 
        destructor: function () {
743
 
 
744
 
                var aHandlers = this._eventHandlers;
745
 
 
746
 
                if (aHandlers) {
747
 
 
748
 
                        Y.Array.each(aHandlers, function (handle) {
749
 
                                handle.detach();
750
 
                        });
751
 
 
752
 
                        this._eventHandlers = null;
753
 
 
754
 
                }
755
 
                
756
 
                this.get(HOST).unplug("focusManager");
757
 
                
758
 
    },
759
 
 
760
 
 
761
 
 
762
 
        //      Protected methods
763
 
 
764
 
        /**
765
 
        * @method _isRoot
766
 
        * @description Returns a boolean indicating if the specified menu is the 
767
 
        * root menu in the menu.
768
 
        * @protected
769
 
        * @param {Node} menu Node instance representing a menu.
770
 
        * @return {Boolean} Boolean indicating if the specified menu is the root 
771
 
        * menu in the menu.
772
 
        */
773
 
        _isRoot: function (menu) {
774
 
 
775
 
                return this._rootMenu.compareTo(menu);
776
 
 
777
 
        },
778
 
 
779
 
 
780
 
        /**
781
 
        * @method _getTopmostSubmenu
782
 
        * @description Returns the topmost submenu of a submenu hierarchy.
783
 
        * @protected
784
 
        * @param {Node} menu Node instance representing a menu.
785
 
        * @return {Node} Node instance representing a menu.
786
 
        */
787
 
        _getTopmostSubmenu: function (menu) {
788
 
        
789
 
                var menuNav = this,
790
 
                        oMenu = getParentMenu(menu),
791
 
                        returnVal;
792
 
 
793
 
 
794
 
                if (!oMenu) {
795
 
                        returnVal = menu;
796
 
                }
797
 
                else if (menuNav._isRoot(oMenu)) {
798
 
                        returnVal = menu;
799
 
                }
800
 
                else {
801
 
                        returnVal = menuNav._getTopmostSubmenu(oMenu);
802
 
                }
803
 
        
804
 
                return returnVal;
805
 
        
806
 
        },
807
 
 
808
 
 
809
 
        /**
810
 
        * @method _clearActiveItem
811
 
        * @description Clears the menu's active descendent.
812
 
        * @protected
813
 
        */
814
 
        _clearActiveItem: function () {
815
 
 
816
 
                var menuNav = this,
817
 
                        oActiveItem = menuNav._activeItem;
818
 
                
819
 
                if (oActiveItem) {
820
 
                        oActiveItem.removeClass(getActiveClass(oActiveItem));
821
 
                }
822
 
 
823
 
                menuNav._activeItem = null;
824
 
        
825
 
        },
826
 
 
827
 
 
828
 
        /**
829
 
        * @method _setActiveItem
830
 
        * @description Sets the specified menuitem or menu label as the menu's 
831
 
        * active descendent.
832
 
        * @protected
833
 
        * @param {Node} item Node instance representing a menuitem or menu label.
834
 
        */
835
 
        _setActiveItem: function (item) {
836
 
 
837
 
                var menuNav = this;
838
 
        
839
 
                if (item) {
840
 
                        
841
 
                        menuNav._clearActiveItem();
842
 
        
843
 
                        item.addClass(getActiveClass(item));
844
 
                        
845
 
                        menuNav._activeItem = item;
846
 
                
847
 
                }
848
 
        
849
 
        },
850
 
 
851
 
 
852
 
        /**
853
 
        * @method _focusItem
854
 
        * @description Focuses the specified menuitem or menu label.
855
 
        * @protected
856
 
        * @param {Node} item Node instance representing a menuitem or menu label.
857
 
        */
858
 
        _focusItem: function (item) {
859
 
        
860
 
                var menuNav = this,
861
 
                        oMenu,
862
 
                        oItem;
863
 
        
864
 
                if (item && menuNav._hasFocus) {
865
 
 
866
 
                        oMenu = getParentMenu(item);
867
 
                        oItem = getItemAnchor(item);
868
 
 
869
 
                        if (oMenu && !oMenu.compareTo(menuNav._activeMenu)) {
870
 
                                menuNav._activeMenu = oMenu;
871
 
                                menuNav._initFocusManager();
872
 
                        }
873
 
                
874
 
                        menuNav._focusManager.focus(oItem);
875
 
 
876
 
                }
877
 
        
878
 
        },
879
 
 
880
 
 
881
 
        /**
882
 
        * @method _showMenu
883
 
        * @description Shows the specified menu.
884
 
        * @protected
885
 
        * @param {Node} menu Node instance representing a menu.
886
 
        */
887
 
        _showMenu: function (menu) {
888
 
 
889
 
                var oParentMenu = getParentMenu(menu),
890
 
                        oLI = menu.get(PARENT_NODE),
891
 
                        aXY = oLI.getXY();
892
 
 
893
 
 
894
 
                if (this.get(USE_ARIA)) {
895
 
                        menu.set(ARIA_HIDDEN, false);
896
 
                }
897
 
 
898
 
 
899
 
                if (isHorizontalMenu(oParentMenu)) {
900
 
                        aXY[1] = aXY[1] + oLI.get(OFFSET_HEIGHT);
901
 
                }
902
 
                else {
903
 
                        aXY[0] = aXY[0] + oLI.get(OFFSET_WIDTH);
904
 
                }
905
 
                
906
 
                menu.setXY(aXY);
907
 
 
908
 
                if (UA.ie < 8) {
909
 
 
910
 
                        if (UA.ie === 6 && !menu.hasIFrameShim) {
911
 
        
912
 
                                menu.appendChild(Y.Node.create(NodeMenuNav.SHIM_TEMPLATE));
913
 
                                menu.hasIFrameShim = true;
914
 
 
915
 
                        }
916
 
 
917
 
                        //      Clear previous values for height and width
918
 
 
919
 
                        menu.setStyles({ height: EMPTY_STRING, width: EMPTY_STRING });
920
 
 
921
 
                        //      Set the width and height of the menu's bounding box - this is 
922
 
                        //      necessary for IE 6 so that the CSS for the <iframe> shim can 
923
 
                        //      simply set the <iframe>'s width and height to 100% to ensure 
924
 
                        //      that dimensions of an <iframe> shim are always sync'd to the 
925
 
                        //      that of its parent menu.  Specifying a width and height also 
926
 
                        //      helps when positioning decorator elements (for creating effects 
927
 
                        //      like rounded corners) inside a menu's bounding box in IE 7.
928
 
                        
929
 
                        menu.setStyles({ 
930
 
                                height: (menu.get(OFFSET_HEIGHT) + PX), 
931
 
                                width: (menu.get(OFFSET_WIDTH) + PX) });
932
 
 
933
 
                }
934
 
 
935
 
                menu.previous().addClass(CSS_MENU_LABEL_MENUVISIBLE);
936
 
                menu.removeClass(CSS_MENU_HIDDEN);
937
 
 
938
 
        },
939
 
        
940
 
 
941
 
        /**
942
 
        * @method _hideMenu 
943
 
        * @description Hides the specified menu.
944
 
        * @protected
945
 
        * @param {Node} menu Node instance representing a menu.
946
 
        * @param {Boolean} activateAndFocusLabel Boolean indicating if the label 
947
 
        * for the specified 
948
 
        * menu should be focused and set as active.
949
 
        */
950
 
        _hideMenu: function (menu, activateAndFocusLabel) {
951
 
 
952
 
                var menuNav = this,
953
 
                        oLabel = menu.previous(),
954
 
                        oActiveItem;
955
 
 
956
 
                oLabel.removeClass(CSS_MENU_LABEL_MENUVISIBLE);
957
 
 
958
 
 
959
 
                if (activateAndFocusLabel) {
960
 
                        menuNav._focusItem(oLabel);
961
 
                        menuNav._setActiveItem(oLabel);                 
962
 
                }
963
 
 
964
 
                oActiveItem = menu.one((PERIOD + CSS_MENUITEM_ACTIVE));
965
 
 
966
 
                if (oActiveItem) {
967
 
                        oActiveItem.removeClass(CSS_MENUITEM_ACTIVE);
968
 
                }
969
 
 
970
 
                //      Clear the values for top and left that were set by the call to 
971
 
                //      "setXY" when the menu was shown so that the hidden position 
972
 
                //      specified in the core CSS file will take affect.
973
 
 
974
 
                menu.setStyles({ left: EMPTY_STRING, top: EMPTY_STRING });
975
 
                
976
 
                menu.addClass(CSS_MENU_HIDDEN);
977
 
 
978
 
                if (menuNav.get(USE_ARIA)) {
979
 
                        menu.set(ARIA_HIDDEN, true);
980
 
                }       
981
 
                
982
 
        },
983
 
 
984
 
 
985
 
        /**
986
 
        * @method _hideAllSubmenus
987
 
        * @description Hides all submenus of the specified menu.
988
 
        * @protected
989
 
        * @param {Node} menu Node instance representing a menu.
990
 
        */
991
 
        _hideAllSubmenus: function (menu) {
992
 
 
993
 
                var menuNav = this;
994
 
 
995
 
                menu.all(MENU_SELECTOR).each(Y.bind(function (submenuNode) {
996
 
                
997
 
                        menuNav._hideMenu(submenuNode);
998
 
                
999
 
                }, menuNav));
1000
 
        
1001
 
        },
1002
 
 
1003
 
 
1004
 
        /**
1005
 
        * @method _cancelShowSubmenuTimer
1006
 
        * @description Cancels the timer used to show a submenu.
1007
 
        * @protected
1008
 
        */
1009
 
        _cancelShowSubmenuTimer: function () {
1010
 
 
1011
 
                var menuNav = this,
1012
 
                        oShowSubmenuTimer = menuNav._showSubmenuTimer;
1013
 
 
1014
 
                if (oShowSubmenuTimer) {
1015
 
                        oShowSubmenuTimer.cancel();
1016
 
                        menuNav._showSubmenuTimer = null;
1017
 
                }
1018
 
        
1019
 
        },
1020
 
 
1021
 
 
1022
 
        /**
1023
 
        * @method _cancelHideSubmenuTimer
1024
 
        * @description Cancels the timer used to hide a submenu.
1025
 
        * @protected
1026
 
        */
1027
 
        _cancelHideSubmenuTimer: function () {
1028
 
 
1029
 
                var menuNav = this,
1030
 
                        oHideSubmenuTimer = menuNav._hideSubmenuTimer;
1031
 
 
1032
 
 
1033
 
                if (oHideSubmenuTimer) {
1034
 
                        oHideSubmenuTimer.cancel();
1035
 
                        menuNav._hideSubmenuTimer = null;
1036
 
                }
1037
 
        
1038
 
        },
1039
 
 
1040
 
 
1041
 
        /**
1042
 
        * @method _initFocusManager
1043
 
        * @description Initializes and updates the Focus Manager so that is is 
1044
 
        * always managing descendants of the active menu.
1045
 
        * @protected
1046
 
        */
1047
 
        _initFocusManager: function () {
1048
 
 
1049
 
                var menuNav = this,
1050
 
                        oRootMenu = menuNav._rootMenu,
1051
 
                        oMenu = menuNav._activeMenu || oRootMenu,
1052
 
                        sSelectorBase = 
1053
 
                                menuNav._isRoot(oMenu) ? EMPTY_STRING : ("#" + oMenu.get("id")),
1054
 
                        oFocusManager = menuNav._focusManager,
1055
 
                        sKeysVal,
1056
 
                        sDescendantSelector,
1057
 
                        sQuery;
1058
 
 
1059
 
                if (isHorizontalMenu(oMenu)) {
1060
 
 
1061
 
                        sDescendantSelector = sSelectorBase + STANDARD_QUERY + "," + 
1062
 
                                sSelectorBase + EXTENDED_QUERY;
1063
 
                        
1064
 
                        sKeysVal = { next: "down:39", previous: "down:37" };
1065
 
                        
1066
 
                }
1067
 
                else {
1068
 
 
1069
 
                        sDescendantSelector = sSelectorBase + STANDARD_QUERY;
1070
 
                        sKeysVal = { next: "down:40", previous: "down:38" };
1071
 
 
1072
 
                }
1073
 
 
1074
 
 
1075
 
                if (!oFocusManager) {
1076
 
 
1077
 
                        oRootMenu.plug(Y.Plugin.NodeFocusManager, { 
1078
 
                                descendants: sDescendantSelector,
1079
 
                                keys: sKeysVal,
1080
 
                                circular: true
1081
 
                        });
1082
 
 
1083
 
                        oFocusManager = oRootMenu.focusManager;
1084
 
 
1085
 
                        sQuery = "#" + oRootMenu.get("id") + MENU_SELECTOR + " a," + 
1086
 
                                                        MENU_TOGGLE_SELECTOR;
1087
 
 
1088
 
                        oRootMenu.all(sQuery).set("tabIndex", -1);
1089
 
 
1090
 
                        oFocusManager.on(ACTIVE_DESCENDANT_CHANGE, 
1091
 
                                this._onActiveDescendantChange, oFocusManager, this);
1092
 
 
1093
 
                        oFocusManager.after(ACTIVE_DESCENDANT_CHANGE, 
1094
 
                                this._afterActiveDescendantChange, oFocusManager, this);
1095
 
                        
1096
 
                        menuNav._focusManager = oFocusManager;
1097
 
                        
1098
 
                }
1099
 
                else {
1100
 
 
1101
 
                        oFocusManager.set(ACTIVE_DESCENDANT, -1);
1102
 
                        oFocusManager.set(DESCENDANTS, sDescendantSelector);
1103
 
                        oFocusManager.set("keys", sKeysVal);
1104
 
                        
1105
 
                }
1106
 
 
1107
 
        },
1108
 
 
1109
 
 
1110
 
        //      Event handlers for discrete pieces of pieces of the menu
1111
 
 
1112
 
 
1113
 
        /**
1114
 
        * @method _onActiveDescendantChange
1115
 
        * @description "activeDescendantChange" event handler for menu's 
1116
 
        * Focus Manager.
1117
 
        * @protected
1118
 
        * @param {Object} event Object representing the Attribute change event.
1119
 
        * @param {NodeMenuNav} menuNav Object representing the NodeMenuNav instance.
1120
 
        */
1121
 
        _onActiveDescendantChange: function (event, menuNav) {
1122
 
 
1123
 
                if (event.src === UI && menuNav._activeMenu && 
1124
 
                                !menuNav._movingToSubmenu) {
1125
 
 
1126
 
                        menuNav._hideAllSubmenus(menuNav._activeMenu);
1127
 
 
1128
 
                }
1129
 
                
1130
 
        },
1131
 
 
1132
 
 
1133
 
        /**
1134
 
        * @method _afterActiveDescendantChange
1135
 
        * @description "activeDescendantChange" event handler for menu's 
1136
 
        * Focus Manager.
1137
 
        * @protected
1138
 
        * @param {Object} event Object representing the Attribute change event.
1139
 
        * @param {NodeMenuNav} menuNav Object representing the NodeMenuNav instance.
1140
 
        */
1141
 
        _afterActiveDescendantChange: function (event, menuNav) {
1142
 
 
1143
 
                var oItem;
1144
 
 
1145
 
                if (event.src === UI) {
1146
 
                        oItem = getItem(this.get(DESCENDANTS).item(event.newVal), true);
1147
 
                        menuNav._setActiveItem(oItem);
1148
 
                }
1149
 
        
1150
 
        },
1151
 
 
1152
 
 
1153
 
        /**
1154
 
        * @method _onDocFocus
1155
 
        * @description "focus" event handler for the owner document of the MenuNav.
1156
 
        * @protected
1157
 
        * @param {Object} event Object representing the DOM event.
1158
 
        */
1159
 
        _onDocFocus: function (event) {
1160
 
        
1161
 
                var menuNav = this,
1162
 
                        oActiveItem = menuNav._activeItem,
1163
 
                        oTarget = event.target,
1164
 
                        oMenu;
1165
 
        
1166
 
 
1167
 
                if (menuNav._rootMenu.contains(oTarget)) {      //      The menu has focus
1168
 
 
1169
 
                        if (menuNav._hasFocus) {        
1170
 
 
1171
 
                                oMenu = getParentMenu(oTarget);
1172
 
 
1173
 
                                //      If the element that was focused is a descendant of the 
1174
 
                                //      root menu, but is in a submenu not currently being 
1175
 
                                //      managed by the Focus Manager, update the Focus Manager so 
1176
 
                                //      that it is now managing the submenu that is the parent of  
1177
 
                                //      the element that was focused.
1178
 
                                
1179
 
                                if (!menuNav._activeMenu.compareTo(oMenu)) {
1180
 
 
1181
 
                                        menuNav._activeMenu = oMenu;
1182
 
                                        menuNav._initFocusManager();
1183
 
                                        menuNav._focusManager.set(ACTIVE_DESCENDANT, oTarget);
1184
 
                                        menuNav._setActiveItem(getItem(oTarget, true));
1185
 
                                        
1186
 
                                }
1187
 
                        
1188
 
                        }
1189
 
                        else { //       Initial focus
1190
 
 
1191
 
                                //      First time the menu has been focused, need to setup focused 
1192
 
                                //      state and established active active descendant
1193
 
        
1194
 
                                menuNav._hasFocus = true;
1195
 
        
1196
 
                                oActiveItem = getItem(oTarget, true);
1197
 
        
1198
 
                                if (oActiveItem) {      
1199
 
                                        menuNav._setActiveItem(oActiveItem);
1200
 
                                }
1201
 
                                
1202
 
                        }
1203
 
                
1204
 
                }
1205
 
                else {  //      The menu has lost focus
1206
 
 
1207
 
                        menuNav._clearActiveItem();
1208
 
 
1209
 
                        menuNav._cancelShowSubmenuTimer();
1210
 
                        menuNav._hideAllSubmenus(menuNav._rootMenu);
1211
 
 
1212
 
                        menuNav._activeMenu = menuNav._rootMenu;
1213
 
                        menuNav._initFocusManager();
1214
 
                        
1215
 
                        menuNav._focusManager.set(ACTIVE_DESCENDANT, 0);
1216
 
                        
1217
 
                        menuNav._hasFocus = false;
1218
 
 
1219
 
                }
1220
 
        
1221
 
        },
1222
 
 
1223
 
 
1224
 
        /**
1225
 
        * @method _onMenuMouseOver
1226
 
        * @description "mouseover" event handler for a menu.
1227
 
        * @protected
1228
 
        * @param {Node} menu Node instance representing a menu.
1229
 
        * @param {Object} event Object representing the DOM event.
1230
 
        */
1231
 
        _onMenuMouseOver: function (menu, event) {
1232
 
 
1233
 
                var menuNav = this,
1234
 
                        oHideAllSubmenusTimer = menuNav._hideAllSubmenusTimer;
1235
 
 
1236
 
                if (oHideAllSubmenusTimer) {
1237
 
                        oHideAllSubmenusTimer.cancel();
1238
 
                        menuNav._hideAllSubmenusTimer = null;
1239
 
                }
1240
 
 
1241
 
                menuNav._cancelHideSubmenuTimer();
1242
 
 
1243
 
                //      Need to update the FocusManager in advance of focus a new 
1244
 
                //      Menu in order to avoid the FocusManager thinking that 
1245
 
                //      it has lost focus
1246
 
                
1247
 
                if (menu && !menu.compareTo(menuNav._activeMenu)) {
1248
 
                        menuNav._activeMenu = menu;
1249
 
 
1250
 
                        if (menuNav._hasFocus) {
1251
 
                                menuNav._initFocusManager();
1252
 
                        }
1253
 
 
1254
 
                }
1255
 
 
1256
 
                if (menuNav._movingToSubmenu && isHorizontalMenu(menu)) {
1257
 
                        menuNav._movingToSubmenu = false;
1258
 
                }
1259
 
 
1260
 
        },
1261
 
 
1262
 
 
1263
 
        /**
1264
 
        * @method _hideAndFocusLabel
1265
 
        * @description Hides all of the submenus of the root menu and focuses the 
1266
 
        * label of the topmost submenu
1267
 
        * @protected
1268
 
        */
1269
 
        _hideAndFocusLabel: function () {
1270
 
 
1271
 
                var     menuNav = this,
1272
 
                        oActiveMenu = menuNav._activeMenu,
1273
 
                        oSubmenu;
1274
 
        
1275
 
                menuNav._hideAllSubmenus(menuNav._rootMenu);
1276
 
 
1277
 
                if (oActiveMenu) {
1278
 
 
1279
 
                        //      Focus the label element for the topmost submenu
1280
 
                        oSubmenu = menuNav._getTopmostSubmenu(oActiveMenu);
1281
 
                        menuNav._focusItem(oSubmenu.previous());
1282
 
 
1283
 
                }
1284
 
        
1285
 
        },
1286
 
 
1287
 
 
1288
 
        /**
1289
 
        * @method _onMenuMouseOut
1290
 
        * @description "mouseout" event handler for a menu.
1291
 
        * @protected
1292
 
        * @param {Node} menu Node instance representing a menu.
1293
 
        * @param {Object} event Object representing the DOM event.
1294
 
        */
1295
 
        _onMenuMouseOut: function (menu, event) {
1296
 
 
1297
 
                var menuNav = this,
1298
 
                        oActiveMenu = menuNav._activeMenu,
1299
 
                        oRelatedTarget = event.relatedTarget,
1300
 
                        oActiveItem = menuNav._activeItem,
1301
 
                        oParentMenu,
1302
 
                        oMenu;
1303
 
 
1304
 
 
1305
 
                if (oActiveMenu && !oActiveMenu.contains(oRelatedTarget)) {
1306
 
                
1307
 
                        oParentMenu = getParentMenu(oActiveMenu);
1308
 
                        
1309
 
 
1310
 
                        if (oParentMenu && !oParentMenu.contains(oRelatedTarget)) {
1311
 
 
1312
 
                                if (menuNav.get(MOUSEOUT_HIDE_DELAY) > 0) {
1313
 
 
1314
 
                                        menuNav._cancelShowSubmenuTimer();
1315
 
 
1316
 
                                        menuNav._hideAllSubmenusTimer = 
1317
 
 
1318
 
                                                later(menuNav.get(MOUSEOUT_HIDE_DELAY), 
1319
 
                                                        menuNav, menuNav._hideAndFocusLabel);
1320
 
                                                
1321
 
                                }
1322
 
                        
1323
 
                        }
1324
 
                        else {
1325
 
                        
1326
 
                                if (oActiveItem) {
1327
 
                                
1328
 
                                        oMenu = getParentMenu(oActiveItem);
1329
 
 
1330
 
                                        if (!menuNav._isRoot(oMenu)) { 
1331
 
                                                menuNav._focusItem(oMenu.previous());
1332
 
                                        }
1333
 
                                
1334
 
                                }
1335
 
                        
1336
 
                        }
1337
 
 
1338
 
                }
1339
 
 
1340
 
        },
1341
 
 
1342
 
 
1343
 
        /**
1344
 
        * @method _onMenuLabelMouseOver
1345
 
        * @description "mouseover" event handler for a menu label.
1346
 
        * @protected
1347
 
        * @param {Node} menuLabel Node instance representing a menu label.
1348
 
        * @param {Object} event Object representing the DOM event.
1349
 
        */
1350
 
        _onMenuLabelMouseOver: function (menuLabel, event) {
1351
 
 
1352
 
                var menuNav = this,
1353
 
                        oActiveMenu = menuNav._activeMenu,
1354
 
                        bIsRoot = menuNav._isRoot(oActiveMenu),
1355
 
                        bUseAutoSubmenuDisplay = 
1356
 
                                (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot),
1357
 
            submenuShowDelay = menuNav.get("submenuShowDelay"), 
1358
 
                        oSubmenu;
1359
 
                                
1360
 
 
1361
 
        var showSubmenu = function (delay) {
1362
 
 
1363
 
                        menuNav._cancelHideSubmenuTimer();
1364
 
                        menuNav._cancelShowSubmenuTimer();
1365
 
 
1366
 
                        if (!hasVisibleSubmenu(menuLabel)) {
1367
 
 
1368
 
                                oSubmenu = menuLabel.next();
1369
 
 
1370
 
                                if (oSubmenu) {
1371
 
                                        menuNav._hideAllSubmenus(oActiveMenu);
1372
 
                                        menuNav._showSubmenuTimer = later(delay, menuNav, menuNav._showMenu, oSubmenu);
1373
 
                                }
1374
 
 
1375
 
                        }
1376
 
            
1377
 
        };
1378
 
 
1379
 
 
1380
 
                menuNav._focusItem(menuLabel);
1381
 
                menuNav._setActiveItem(menuLabel);
1382
 
 
1383
 
 
1384
 
                if (bUseAutoSubmenuDisplay) {
1385
 
        
1386
 
                if (menuNav._movingToSubmenu) {
1387
 
                    
1388
 
                    //  If the user is moving diagonally from a submenu to 
1389
 
                    //  another submenu and they then stop and pause on a
1390
 
                    //  menu label for an amount of time equal to the amount of 
1391
 
                    //  time defined for the display of a submenu then show the 
1392
 
                    //  submenu immediately.
1393
 
                    //  http://yuilibrary.com/projects/yui3/ticket/2528316
1394
 
                    
1395
 
                    Y.message("Pause path");
1396
 
                    
1397
 
                    menuNav._hoverTimer = later(submenuShowDelay, menuNav, function () {
1398
 
                    showSubmenu(0);
1399
 
                    });
1400
 
                    
1401
 
                }
1402
 
                else {
1403
 
                showSubmenu(submenuShowDelay);
1404
 
                }
1405
 
                
1406
 
                }
1407
 
 
1408
 
        },
1409
 
 
1410
 
 
1411
 
        /**
1412
 
        * @method _onMenuLabelMouseOut
1413
 
        * @description "mouseout" event handler for a menu label.
1414
 
        * @protected
1415
 
        * @param {Node} menuLabel Node instance representing a menu label.
1416
 
        * @param {Object} event Object representing the DOM event.
1417
 
        */
1418
 
        _onMenuLabelMouseOut: function (menuLabel, event) {
1419
 
 
1420
 
                var menuNav = this,
1421
 
                        bIsRoot = menuNav._isRoot(menuNav._activeMenu),
1422
 
                        bUseAutoSubmenuDisplay = 
1423
 
                                (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot),
1424
 
 
1425
 
                        oRelatedTarget = event.relatedTarget,
1426
 
                        oSubmenu = menuLabel.next(),
1427
 
                        hoverTimer = menuNav._hoverTimer;
1428
 
 
1429
 
        if (hoverTimer) {
1430
 
            hoverTimer.cancel();
1431
 
        }
1432
 
 
1433
 
                menuNav._clearActiveItem();
1434
 
 
1435
 
                if (bUseAutoSubmenuDisplay) {
1436
 
 
1437
 
                        if (menuNav._movingToSubmenu && 
1438
 
                                        !menuNav._showSubmenuTimer && oSubmenu) {
1439
 
 
1440
 
                                //      If the mouse is moving diagonally toward the submenu and 
1441
 
                                //      another submenu isn't in the process of being displayed 
1442
 
                                //      (via a timer), then hide the submenu via a timer to give
1443
 
                                //      the user some time to reach the submenu.
1444
 
                        
1445
 
                                menuNav._hideSubmenuTimer = 
1446
 
                                        later(menuNav.get("submenuHideDelay"), menuNav, 
1447
 
                                                menuNav._hideMenu, oSubmenu);
1448
 
                        
1449
 
                        }
1450
 
                        else if (!menuNav._movingToSubmenu && oSubmenu && (!oRelatedTarget || 
1451
 
                                (oRelatedTarget && 
1452
 
                                    !oSubmenu.contains(oRelatedTarget) && 
1453
 
                                    !oRelatedTarget.compareTo(oSubmenu)))) {
1454
 
 
1455
 
                                //      If the mouse is not moving toward the submenu, cancel any 
1456
 
                                //      submenus that might be in the process of being displayed 
1457
 
                                //      (via a timer) and hide this submenu immediately.
1458
 
 
1459
 
                                menuNav._cancelShowSubmenuTimer();
1460
 
 
1461
 
                                menuNav._hideMenu(oSubmenu);
1462
 
 
1463
 
                        }
1464
 
 
1465
 
                }
1466
 
 
1467
 
        },
1468
 
        
1469
 
 
1470
 
        /**
1471
 
        * @method _onMenuItemMouseOver
1472
 
        * @description "mouseover" event handler for a menuitem.
1473
 
        * @protected
1474
 
        * @param {Node} menuItem Node instance representing a menuitem.
1475
 
        * @param {Object} event Object representing the DOM event.
1476
 
        */
1477
 
        _onMenuItemMouseOver: function (menuItem, event) {
1478
 
 
1479
 
                var menuNav = this,
1480
 
                        oActiveMenu = menuNav._activeMenu,
1481
 
                        bIsRoot = menuNav._isRoot(oActiveMenu),
1482
 
                        bUseAutoSubmenuDisplay = 
1483
 
                                (menuNav.get(AUTO_SUBMENU_DISPLAY) && bIsRoot || !bIsRoot);
1484
 
 
1485
 
 
1486
 
                menuNav._focusItem(menuItem);
1487
 
                menuNav._setActiveItem(menuItem);
1488
 
 
1489
 
 
1490
 
                if (bUseAutoSubmenuDisplay && !menuNav._movingToSubmenu) {
1491
 
 
1492
 
                        menuNav._hideAllSubmenus(oActiveMenu);
1493
 
 
1494
 
                }
1495
 
 
1496
 
        },
1497
 
        
1498
 
 
1499
 
        /**
1500
 
        * @method _onMenuItemMouseOut
1501
 
        * @description "mouseout" event handler for a menuitem.
1502
 
        * @protected
1503
 
        * @param {Node} menuItem Node instance representing a menuitem.
1504
 
        * @param {Object} event Object representing the DOM event.
1505
 
        */
1506
 
        _onMenuItemMouseOut: function (menuItem, event) {
1507
 
 
1508
 
                this._clearActiveItem();
1509
 
 
1510
 
        },
1511
 
 
1512
 
 
1513
 
        /**
1514
 
        * @method _onVerticalMenuKeyDown
1515
 
        * @description "keydown" event handler for vertical menus.
1516
 
        * @protected
1517
 
        * @param {Object} event Object representing the DOM event.
1518
 
        */
1519
 
        _onVerticalMenuKeyDown: function (event) {
1520
 
 
1521
 
                var menuNav = this,
1522
 
                        oActiveMenu = menuNav._activeMenu,
1523
 
                        oRootMenu = menuNav._rootMenu,
1524
 
                        oTarget = event.target,
1525
 
                        bPreventDefault = false,
1526
 
                        nKeyCode = event.keyCode,
1527
 
                        oSubmenu,
1528
 
                        oParentMenu,
1529
 
                        oLI,
1530
 
                        oItem;
1531
 
 
1532
 
 
1533
 
                switch (nKeyCode) {
1534
 
 
1535
 
                        case 37:        //      left arrow
1536
 
 
1537
 
                                oParentMenu = getParentMenu(oActiveMenu);
1538
 
 
1539
 
                                if (oParentMenu && isHorizontalMenu(oParentMenu)) {
1540
 
                                
1541
 
                                        menuNav._hideMenu(oActiveMenu);
1542
 
                                        oLI = getPreviousSibling(oActiveMenu.get(PARENT_NODE));
1543
 
                                        oItem = getItem(oLI);
1544
 
                                        
1545
 
                                        if (oItem) {
1546
 
 
1547
 
                                                if (isMenuLabel(oItem)) {       //      Menu label
1548
 
                                                
1549
 
                                                        oSubmenu = oItem.next();
1550
 
                                                
1551
 
 
1552
 
                                                        if (oSubmenu) {
1553
 
 
1554
 
                                                                menuNav._showMenu(oSubmenu);
1555
 
                                                                menuNav._focusItem(getFirstItem(oSubmenu));
1556
 
                                                                menuNav._setActiveItem(getFirstItem(oSubmenu));
1557
 
 
1558
 
                                                        }
1559
 
                                                        else {
1560
 
        
1561
 
                                                                menuNav._focusItem(oItem);
1562
 
                                                                menuNav._setActiveItem(oItem);
1563
 
        
1564
 
                                                        }
1565
 
                                                
1566
 
                                                }
1567
 
                                                else {  //      MenuItem
1568
 
 
1569
 
                                                        menuNav._focusItem(oItem);
1570
 
                                                        menuNav._setActiveItem(oItem);
1571
 
 
1572
 
                                                }
1573
 
                                        
1574
 
                                        }
1575
 
 
1576
 
                                }
1577
 
                                else if (!menuNav._isRoot(oActiveMenu)) {
1578
 
                                        menuNav._hideMenu(oActiveMenu, true);
1579
 
                                }
1580
 
 
1581
 
 
1582
 
                                bPreventDefault = true;
1583
 
 
1584
 
                        break;
1585
 
 
1586
 
                        case 39:        //      right arrow
1587
 
 
1588
 
                                if (isMenuLabel(oTarget)) {
1589
 
                                        
1590
 
                                        oSubmenu = oTarget.next();
1591
 
 
1592
 
                                        if (oSubmenu) {
1593
 
 
1594
 
                                                menuNav._showMenu(oSubmenu);
1595
 
                                                menuNav._focusItem(getFirstItem(oSubmenu));
1596
 
                                                menuNav._setActiveItem(getFirstItem(oSubmenu));
1597
 
 
1598
 
                                        }
1599
 
                                
1600
 
                                }
1601
 
                                else if (isHorizontalMenu(oRootMenu)) {
1602
 
 
1603
 
                                        oSubmenu = menuNav._getTopmostSubmenu(oActiveMenu);
1604
 
                                        oLI = getNextSibling(oSubmenu.get(PARENT_NODE));
1605
 
                                        oItem = getItem(oLI);
1606
 
 
1607
 
                                        menuNav._hideAllSubmenus(oRootMenu);
1608
 
 
1609
 
                                        if (oItem) {
1610
 
 
1611
 
                                                if (isMenuLabel(oItem)) {       //      Menu label
1612
 
 
1613
 
                                                        oSubmenu = oItem.next();
1614
 
 
1615
 
                                                        if (oSubmenu) {
1616
 
 
1617
 
                                                                menuNav._showMenu(oSubmenu);
1618
 
                                                                menuNav._focusItem(getFirstItem(oSubmenu));
1619
 
                                                                menuNav._setActiveItem(getFirstItem(oSubmenu));
1620
 
 
1621
 
                                                        }
1622
 
                                                        else {
1623
 
 
1624
 
                                                                menuNav._focusItem(oItem);
1625
 
                                                                menuNav._setActiveItem(oItem);  
1626
 
 
1627
 
                                                        }
1628
 
                                                
1629
 
                                                }
1630
 
                                                else {  //      MenuItem
1631
 
 
1632
 
                                                        menuNav._focusItem(oItem);
1633
 
                                                        menuNav._setActiveItem(oItem);
1634
 
 
1635
 
                                                }                                                       
1636
 
 
1637
 
                                        }
1638
 
                                
1639
 
                                }
1640
 
 
1641
 
                                bPreventDefault = true;
1642
 
 
1643
 
                        break;
1644
 
 
1645
 
                }       
1646
 
 
1647
 
 
1648
 
                if (bPreventDefault) {
1649
 
 
1650
 
                        //      Prevent the browser from scrolling the window
1651
 
 
1652
 
                        event.preventDefault();                 
1653
 
 
1654
 
                }
1655
 
        
1656
 
        },
1657
 
        
1658
 
 
1659
 
        /**
1660
 
        * @method _onHorizontalMenuKeyDown
1661
 
        * @description "keydown" event handler for horizontal menus.
1662
 
        * @protected
1663
 
        * @param {Object} event Object representing the DOM event.
1664
 
        */
1665
 
        _onHorizontalMenuKeyDown: function (event) {
1666
 
 
1667
 
                var menuNav = this,
1668
 
                        oActiveMenu = menuNav._activeMenu,
1669
 
                        oTarget = event.target,
1670
 
                        oFocusedItem = getItem(oTarget, true),
1671
 
                        bPreventDefault = false,
1672
 
                        nKeyCode = event.keyCode,
1673
 
                        oSubmenu;
1674
 
 
1675
 
 
1676
 
                if (nKeyCode === 40) {
1677
 
 
1678
 
                        menuNav._hideAllSubmenus(oActiveMenu);
1679
 
 
1680
 
                        if (isMenuLabel(oFocusedItem)) {
1681
 
                        
1682
 
                                oSubmenu = oFocusedItem.next();
1683
 
 
1684
 
                                if (oSubmenu) {
1685
 
 
1686
 
                                        menuNav._showMenu(oSubmenu);
1687
 
                                        menuNav._focusItem(getFirstItem(oSubmenu));
1688
 
                                        menuNav._setActiveItem(getFirstItem(oSubmenu));
1689
 
 
1690
 
                                }
1691
 
 
1692
 
                                bPreventDefault = true;
1693
 
                        
1694
 
                        }
1695
 
 
1696
 
                }               
1697
 
 
1698
 
 
1699
 
                if (bPreventDefault) {
1700
 
 
1701
 
                        //      Prevent the browser from scrolling the window
1702
 
 
1703
 
                        event.preventDefault();                 
1704
 
 
1705
 
                }
1706
 
        
1707
 
        },
1708
 
 
1709
 
 
1710
 
        //      Generic DOM Event handlers
1711
 
 
1712
 
 
1713
 
        /**
1714
 
        * @method _onMouseMove
1715
 
        * @description "mousemove" event handler for the menu.
1716
 
        * @protected
1717
 
        * @param {Object} event Object representing the DOM event.
1718
 
        */
1719
 
        _onMouseMove: function (event) {
1720
 
 
1721
 
                var menuNav = this;
1722
 
 
1723
 
                //      Using a timer to set the value of the "_currentMouseX" property 
1724
 
                //      helps improve the reliability of the calculation used to set the 
1725
 
                //      value of the "_movingToSubmenu" property - especially in Opera.
1726
 
 
1727
 
                later(10, menuNav, function () {
1728
 
 
1729
 
                        menuNav._currentMouseX = event.pageX;
1730
 
                
1731
 
                });
1732
 
        
1733
 
        },
1734
 
 
1735
 
 
1736
 
        /**
1737
 
        * @method _onMouseOver
1738
 
        * @description "mouseover" event handler for the menu.
1739
 
        * @protected
1740
 
        * @param {Object} event Object representing the DOM event.
1741
 
        */
1742
 
        _onMouseOver: function (event) {
1743
 
 
1744
 
                var menuNav = this,
1745
 
                        oTarget,
1746
 
                        oMenu,
1747
 
                        oMenuLabel,
1748
 
                        oParentMenu,
1749
 
                        oMenuItem;
1750
 
 
1751
 
 
1752
 
                if (menuNav._blockMouseEvent) {
1753
 
                        menuNav._blockMouseEvent = false;
1754
 
                }
1755
 
                else {
1756
 
 
1757
 
                        oTarget = event.target;
1758
 
                        oMenu = getMenu(oTarget, true);
1759
 
                        oMenuLabel = getMenuLabel(oTarget, true);
1760
 
                        oMenuItem = getMenuItem(oTarget, true);
1761
 
 
1762
 
 
1763
 
                        if (handleMouseOverForNode(oMenu, oTarget)) {
1764
 
 
1765
 
                                menuNav._onMenuMouseOver(oMenu, event);
1766
 
 
1767
 
                                oMenu[HANDLED_MOUSEOVER] = true;
1768
 
                                oMenu[HANDLED_MOUSEOUT] = false;
1769
 
 
1770
 
                                oParentMenu = getParentMenu(oMenu);
1771
 
 
1772
 
                                if (oParentMenu) {
1773
 
 
1774
 
                                        oParentMenu[HANDLED_MOUSEOUT] = true;
1775
 
                                        oParentMenu[HANDLED_MOUSEOVER] = false;
1776
 
                
1777
 
                                }
1778
 
                        
1779
 
                        }
1780
 
 
1781
 
                        if (handleMouseOverForNode(oMenuLabel, oTarget)) {
1782
 
 
1783
 
                                menuNav._onMenuLabelMouseOver(oMenuLabel, event);
1784
 
 
1785
 
                                oMenuLabel[HANDLED_MOUSEOVER] = true;
1786
 
                                oMenuLabel[HANDLED_MOUSEOUT] = false;
1787
 
        
1788
 
                        }
1789
 
 
1790
 
                        if (handleMouseOverForNode(oMenuItem, oTarget)) {
1791
 
        
1792
 
                                menuNav._onMenuItemMouseOver(oMenuItem, event);
1793
 
 
1794
 
                                oMenuItem[HANDLED_MOUSEOVER] = true;
1795
 
                                oMenuItem[HANDLED_MOUSEOUT] = false;
1796
 
                                
1797
 
                        }
1798
 
 
1799
 
                }
1800
 
 
1801
 
        },
1802
 
 
1803
 
 
1804
 
        /**
1805
 
        * @method _onMouseOut
1806
 
        * @description "mouseout" event handler for the menu.
1807
 
        * @protected
1808
 
        * @param {Object} event Object representing the DOM event.
1809
 
        */
1810
 
        _onMouseOut: function (event) {
1811
 
                        
1812
 
                var menuNav = this,
1813
 
                        oActiveMenu = menuNav._activeMenu,
1814
 
                        bMovingToSubmenu = false,
1815
 
                        oTarget,
1816
 
                        oRelatedTarget,
1817
 
                        oMenu,
1818
 
                        oMenuLabel,
1819
 
                        oSubmenu,
1820
 
                        oMenuItem;
1821
 
 
1822
 
 
1823
 
                menuNav._movingToSubmenu = 
1824
 
                                        (oActiveMenu && !isHorizontalMenu(oActiveMenu) && 
1825
 
                                                ((event.pageX - 5) > menuNav._currentMouseX));
1826
 
                
1827
 
                oTarget = event.target;
1828
 
                oRelatedTarget = event.relatedTarget;
1829
 
                oMenu = getMenu(oTarget, true);
1830
 
                oMenuLabel = getMenuLabel(oTarget, true);
1831
 
                oMenuItem = getMenuItem(oTarget, true);
1832
 
 
1833
 
 
1834
 
                if (handleMouseOutForNode(oMenuLabel, oRelatedTarget)) {
1835
 
 
1836
 
                        menuNav._onMenuLabelMouseOut(oMenuLabel, event);
1837
 
 
1838
 
                        oMenuLabel[HANDLED_MOUSEOUT] = true;
1839
 
                        oMenuLabel[HANDLED_MOUSEOVER] = false;
1840
 
 
1841
 
                }
1842
 
 
1843
 
                if (handleMouseOutForNode(oMenuItem, oRelatedTarget)) {
1844
 
 
1845
 
                        menuNav._onMenuItemMouseOut(oMenuItem, event);
1846
 
 
1847
 
                        oMenuItem[HANDLED_MOUSEOUT] = true;
1848
 
                        oMenuItem[HANDLED_MOUSEOVER] = false;
1849
 
                        
1850
 
                }
1851
 
 
1852
 
 
1853
 
                if (oMenuLabel) {
1854
 
 
1855
 
                        oSubmenu = oMenuLabel.next();
1856
 
 
1857
 
                        if (oSubmenu && oRelatedTarget && 
1858
 
                                (oRelatedTarget.compareTo(oSubmenu) || 
1859
 
                                        oSubmenu.contains(oRelatedTarget))) {
1860
 
 
1861
 
                                bMovingToSubmenu = true;
1862
 
 
1863
 
                        }
1864
 
                
1865
 
                }
1866
 
                
1867
 
 
1868
 
                if (handleMouseOutForNode(oMenu, oRelatedTarget) || bMovingToSubmenu) {
1869
 
 
1870
 
                        menuNav._onMenuMouseOut(oMenu, event);                          
1871
 
 
1872
 
                        oMenu[HANDLED_MOUSEOUT] = true;
1873
 
                        oMenu[HANDLED_MOUSEOVER] = false;
1874
 
                
1875
 
                }
1876
 
        
1877
 
        },
1878
 
 
1879
 
 
1880
 
        /**
1881
 
        * @method _toggleSubmenuDisplay
1882
 
        * @description "mousedown," "keydown," and "click" event handler for the 
1883
 
        * menu used to toggle the display of a submenu.
1884
 
        * @protected
1885
 
        * @param {Object} event Object representing the DOM event.
1886
 
        */
1887
 
        _toggleSubmenuDisplay: function (event) {
1888
 
 
1889
 
                var menuNav = this,
1890
 
                        oTarget = event.target,
1891
 
                        oMenuLabel = getMenuLabel(oTarget, true),
1892
 
                        sType = event.type,
1893
 
                        oAnchor,
1894
 
                        oSubmenu,
1895
 
                        sHref,
1896
 
                        nHashPos,
1897
 
                        nLen,
1898
 
                        sId;
1899
 
 
1900
 
 
1901
 
                if (oMenuLabel) {
1902
 
 
1903
 
                        oAnchor = isAnchor(oTarget) ? oTarget : oTarget.ancestor(isAnchor);
1904
 
                        
1905
 
 
1906
 
                        if (oAnchor) {
1907
 
 
1908
 
                                //      Need to pass "2" as a second argument to "getAttribute" for 
1909
 
                                //      IE otherwise IE will return a fully qualified URL for the 
1910
 
                                //      value of the "href" attribute.
1911
 
                                //      http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
1912
 
 
1913
 
                                sHref = oAnchor.getAttribute("href", 2);
1914
 
                                nHashPos = sHref.indexOf("#");
1915
 
                                nLen = sHref.length;
1916
 
 
1917
 
                                if (nHashPos === 0 && nLen > 1) {
1918
 
 
1919
 
                                        sId = sHref.substr(1, nLen);
1920
 
                                        oSubmenu = oMenuLabel.next();
1921
 
 
1922
 
                                        if (oSubmenu && (oSubmenu.get(ID) === sId)) {
1923
 
 
1924
 
                                                if (sType === MOUSEDOWN || sType === KEYDOWN) {
1925
 
                                                        
1926
 
                                                        if ((UA.opera || UA.gecko || UA.ie) && sType === KEYDOWN && !menuNav._preventClickHandle) {
1927
 
 
1928
 
                                                                //      Prevent the browser from following the URL of 
1929
 
                                                                //      the anchor element
1930
 
 
1931
 
                                                                menuNav._preventClickHandle = menuNav._rootMenu.on("click", function (event) {
1932
 
 
1933
 
                                                                        event.preventDefault();
1934
 
 
1935
 
                                                                        menuNav._preventClickHandle.detach();
1936
 
                                                                        menuNav._preventClickHandle = null;
1937
 
 
1938
 
                                                                });
1939
 
 
1940
 
                                                        }
1941
 
                                                        
1942
 
                                                        if (sType == MOUSEDOWN) {
1943
 
 
1944
 
                                                                //      Prevent the target from getting focused by 
1945
 
                                                                //      default, since the element to be focused will
1946
 
                                                                //      be determined by weather or not the submenu
1947
 
                                                                //      is visible.
1948
 
                                                                event.preventDefault();
1949
 
 
1950
 
                                                                //      FocusManager will attempt to focus any 
1951
 
                                                                //      descendant that is the target of the mousedown
1952
 
                                                                //      event.  Since we want to explicitly control 
1953
 
                                                                //      where focus is going, we need to call 
1954
 
                                                                //      "stopImmediatePropagation" to stop the 
1955
 
                                                                //      FocusManager from doing its thing.
1956
 
                                                                event.stopImmediatePropagation();       
1957
 
 
1958
 
                                                                //      The "_focusItem" method relies on the 
1959
 
                                                                //      "_hasFocus" property being set to true.  The
1960
 
                                                                //      "_hasFocus" property is normally set via a 
1961
 
                                                                //      "focus" event listener, but since we've 
1962
 
                                                                //      blocked focus from happening, we need to set 
1963
 
                                                                //      this property manually.
1964
 
                                                                menuNav._hasFocus = true;
1965
 
 
1966
 
                                                        }
1967
 
 
1968
 
                                                                
1969
 
                                                        if (menuNav._isRoot(getParentMenu(oTarget))) {  //      Event target is a submenu label in the root menu
1970
 
                                                        
1971
 
                                                                //      Menu label toggle functionality
1972
 
                                                        
1973
 
                                                                if (hasVisibleSubmenu(oMenuLabel)) {
1974
 
                                                        
1975
 
                                                                        menuNav._hideMenu(oSubmenu);
1976
 
                                                                        menuNav._focusItem(oMenuLabel); 
1977
 
                                                                        menuNav._setActiveItem(oMenuLabel);
1978
 
                                                                        
1979
 
                                                                }
1980
 
                                                                else {
1981
 
                                                        
1982
 
                                                                        menuNav._hideAllSubmenus(menuNav._rootMenu);
1983
 
                                                                        menuNav._showMenu(oSubmenu);
1984
 
 
1985
 
                                                                        menuNav._focusItem(getFirstItem(oSubmenu));
1986
 
                                                                        menuNav._setActiveItem(getFirstItem(oSubmenu));
1987
 
                                                                        
1988
 
                                                                }
1989
 
                                                        
1990
 
                                                        }
1991
 
                                                        else {  //      Event target is a submenu label within a submenu
1992
 
                                                        
1993
 
                                                                if (menuNav._activeItem == oMenuLabel) {
1994
 
                                                        
1995
 
                                                                        menuNav._showMenu(oSubmenu);
1996
 
                                                                        menuNav._focusItem(getFirstItem(oSubmenu));
1997
 
                                                                        menuNav._setActiveItem(getFirstItem(oSubmenu));                                                                         
1998
 
                                                        
1999
 
                                                                }
2000
 
                                                                else {
2001
 
                                                        
2002
 
                                                                        if (!oMenuLabel._clickHandle) {
2003
 
 
2004
 
                                                                                oMenuLabel._clickHandle = oMenuLabel.on("click", function () {
2005
 
 
2006
 
                                                                                        menuNav._hideAllSubmenus(menuNav._rootMenu);
2007
 
 
2008
 
                                                                                        menuNav._hasFocus = false;
2009
 
                                                                                        menuNav._clearActiveItem();
2010
 
 
2011
 
 
2012
 
                                                                                        oMenuLabel._clickHandle.detach();
2013
 
                                                                                        
2014
 
                                                                                        oMenuLabel._clickHandle = null;
2015
 
 
2016
 
                                                                                });
2017
 
                                                                                
2018
 
                                                                        }
2019
 
                                                                        
2020
 
                                                                }
2021
 
                                                                
2022
 
                                                        }
2023
 
 
2024
 
                                                }
2025
 
 
2026
 
 
2027
 
                                                if (sType === CLICK) {
2028
 
                                                
2029
 
                                                        //      Prevent the browser from following the URL of 
2030
 
                                                        //      the anchor element
2031
 
                                                        
2032
 
                                                        event.preventDefault();
2033
 
                                                
2034
 
                                                }
2035
 
                                        
2036
 
                                        }
2037
 
                                
2038
 
                                }                               
2039
 
 
2040
 
 
2041
 
                        }
2042
 
                
2043
 
                }
2044
 
        
2045
 
        },
2046
 
        
2047
 
 
2048
 
        /**
2049
 
        * @method _onKeyPress
2050
 
        * @description "keypress" event handler for the menu.
2051
 
        * @protected
2052
 
        * @param {Object} event Object representing the DOM event.
2053
 
        */
2054
 
        _onKeyPress: function (event) {
2055
 
        
2056
 
                switch (event.keyCode) {
2057
 
 
2058
 
                        case 37:        //      left arrow
2059
 
                        case 38:        //      up arrow
2060
 
                        case 39:        //      right arrow
2061
 
                        case 40:        //      down arrow
2062
 
 
2063
 
                                //      Prevent the browser from scrolling the window
2064
 
 
2065
 
                                event.preventDefault();
2066
 
 
2067
 
                        break;
2068
 
 
2069
 
                }                                               
2070
 
 
2071
 
        },      
2072
 
 
2073
 
 
2074
 
        /**
2075
 
        * @method _onKeyDown
2076
 
        * @description "keydown" event handler for the menu.
2077
 
        * @protected
2078
 
        * @param {Object} event Object representing the DOM event.
2079
 
        */
2080
 
        _onKeyDown: function (event) {
2081
 
 
2082
 
                var menuNav = this,
2083
 
                        oActiveItem = menuNav._activeItem,
2084
 
                        oTarget = event.target,
2085
 
                        oActiveMenu = getParentMenu(oTarget),
2086
 
                        oSubmenu;
2087
 
 
2088
 
                if (oActiveMenu) {
2089
 
 
2090
 
                        menuNav._activeMenu = oActiveMenu;
2091
 
 
2092
 
                        if (isHorizontalMenu(oActiveMenu)) {
2093
 
                                menuNav._onHorizontalMenuKeyDown(event);
2094
 
                        }
2095
 
                        else {
2096
 
                                menuNav._onVerticalMenuKeyDown(event);
2097
 
                        }
2098
 
 
2099
 
 
2100
 
                        if (event.keyCode === 27) {
2101
 
 
2102
 
                                if (!menuNav._isRoot(oActiveMenu)) {
2103
 
 
2104
 
                                        if (UA.opera) {
2105
 
                                                later(0, menuNav, function () {
2106
 
                                                        menuNav._hideMenu(oActiveMenu, true);
2107
 
                                                });                                             
2108
 
                                        }
2109
 
                                        else {
2110
 
                                                menuNav._hideMenu(oActiveMenu, true);                                           
2111
 
                                        }
2112
 
 
2113
 
                                        event.stopPropagation();
2114
 
                                        menuNav._blockMouseEvent = UA.gecko ? true : false;
2115
 
 
2116
 
                                }
2117
 
                                else if (oActiveItem) {
2118
 
 
2119
 
                                        if (isMenuLabel(oActiveItem) && 
2120
 
                                                        hasVisibleSubmenu(oActiveItem)) {
2121
 
                                        
2122
 
                                                oSubmenu = oActiveItem.next();
2123
 
 
2124
 
                                                if (oSubmenu) {
2125
 
                                                        menuNav._hideMenu(oSubmenu);
2126
 
                                                }
2127
 
 
2128
 
                                        }
2129
 
                                        else {
2130
 
 
2131
 
                                                menuNav._focusManager.blur();
2132
 
 
2133
 
                                                //      This is necessary for Webkit since blurring the 
2134
 
                                                //      active menuitem won't result in the document 
2135
 
                                                //      gaining focus, meaning the that _onDocFocus 
2136
 
                                                //      listener won't clear the active menuitem.
2137
 
 
2138
 
                                                menuNav._clearActiveItem();     
2139
 
                                                
2140
 
                                                menuNav._hasFocus = false;
2141
 
 
2142
 
                                        }
2143
 
 
2144
 
                                }
2145
 
                        
2146
 
                        }
2147
 
                
2148
 
                }
2149
 
        
2150
 
        },
2151
 
        
2152
 
        /**
2153
 
        * @method _onDocMouseDown
2154
 
        * @description "mousedown" event handler for the owner document of 
2155
 
        * the menu.
2156
 
        * @protected
2157
 
        * @param {Object} event Object representing the DOM event.
2158
 
        */
2159
 
        _onDocMouseDown: function (event) {
2160
 
 
2161
 
                var menuNav = this,
2162
 
                        oRoot = menuNav._rootMenu,
2163
 
                        oTarget = event.target;
2164
 
 
2165
 
 
2166
 
                if (!(oRoot.compareTo(oTarget) || oRoot.contains(oTarget))) {
2167
 
 
2168
 
                        menuNav._hideAllSubmenus(oRoot);
2169
 
 
2170
 
                        //      Document doesn't receive focus in Webkit when the user mouses 
2171
 
                        //      down on it, so the "_hasFocus" property won't get set to the 
2172
 
                        //      correct value.  The following line corrects the problem.
2173
 
 
2174
 
                        if (UA.webkit) {
2175
 
                                menuNav._hasFocus = false;
2176
 
                                menuNav._clearActiveItem();
2177
 
                        }
2178
 
 
2179
 
                }
2180
 
 
2181
 
        }
2182
 
        
2183
 
});
2184
 
 
2185
 
 
2186
 
Y.namespace('Plugin');
2187
 
 
2188
 
Y.Plugin.NodeMenuNav = NodeMenuNav;
2189
 
 
2190
 
 
2191
 
}, '3.2.0' ,{requires:['node', 'classnamemanager', 'node-focusmanager']});