~ubuntu-branches/ubuntu/utopic/moodle/utopic

« back to all changes in this revision

Viewing changes to lib/yuilib/3.13.0/node-menunav/node-menunav-debug.js

  • Committer: Package Import Robot
  • Author(s): Thijs Kinkhorst
  • Date: 2014-05-12 16:10:38 UTC
  • mfrom: (36.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20140512161038-puyqf65k4e0s8ytz
Tags: 2.6.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

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