~andreserl/maas/packaging_precise_rebase

« back to all changes in this revision

Viewing changes to debian/extras/jslibs/yui/node-menunav/node-menunav-debug.js

  • Committer: Andres Rodriguez
  • Date: 2013-03-20 18:12:30 UTC
  • mfrom: (145.2.22 precise.sru)
  • Revision ID: andreserl@ubuntu.com-20130320181230-6l5guc0nhlv2z4p7
Re-base againts latest quantal released branch towards SRU

Show diffs side-by-side

added added

removed removed

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