~ubuntu-branches/ubuntu/karmic/loggerhead/karmic-security

« back to all changes in this revision

Viewing changes to loggerhead/static/javascript/yui/build/node-menunav/node-menunav.js

  • Committer: Bazaar Package Importer
  • Author(s): James Westby, Roland Mas, Jelmer Vernooij, James Westby
  • Date: 2009-08-26 13:18:03 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090826131803-0ce1fhaetci8b0c5
Tags: 1.17-0ubuntu1
[ Roland Mas ]
* Use the YUI library provided by libjs-yui. (Closes: #511286)

[ Jelmer Vernooij ]
* Use my debian.org address in Uploaders field.
* Add ${misc:Depends} to please lintian.
* Suggest recent version of paste, which doesn't expose internal port
  numbers in links. (Closes: #507000)
* Bump standards version to 3.8.1.

[ James Westby ]
* New upstream release.
* Drop get-orig-source rule in favour of debian/watch.
* Add python-pkg-resources and python-paste to Build-Depends,
  python-pkg-resources to Depends and python-simplejson to
  Recommends due to dependency changes.

Show diffs side-by-side

added added

removed removed

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