~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error

« back to all changes in this revision

Viewing changes to src/webcatalog/static/yui/3.10.3/build/node-menunav/node-menunav.js

  • Committer: Tarmac
  • Author(s): Stephen Stewart
  • Date: 2013-06-26 09:19:32 UTC
  • mfrom: (184.1.4 ubuntu-global-nav)
  • Revision ID: tarmac-20130626091932-8urtuli368k8p7ds
[r=beuno,jonas-drange] add ubuntu global nav to apps.ubuntu.com

Show diffs side-by-side

added added

removed removed

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