PageSourceSearch

https://beacon.beacontest.com/_global/js/accessible-mega-menu-click-only.js

js beacontest.com collected 2026-10-05 18:32:33 UTC 35,163 bytes, 751 lines download raw bytes

1/* Copyright 2013 Adobe Systems Incorporated. */
2(function ($, window, document) {
3    "use strict";
4    var pluginName = "accessibleMegaMenu",
5        defaults = {
6            uuidPrefix: "accessible-megamenu",
7            menuClass: "accessible-megamenu",
8            topNavItemClass: "accessible-megamenu-top-nav-item",
9            panelClass: "accessible-megamenu-panel",
10            panelGroupClass: "accessible-megamenu-panel-group",
11            hoverClass: "hover",
12            focusClass: "focus",
13            openClass: "open",
14            toggleButtonClass: "accessible-megamenu-toggle",
15            openDelay: 0,
16            closeDelay: 250,
17            openOnMouseover: false
18        },
19        Keyboard = {
20            BACKSPACE: 8,
21            COMMA: 188,
22            DELETE: 46,
23            DOWN: 40,
24            END: 35,
25            ENTER: 13,
26            ESCAPE: 27,
27            HOME: 36,
28            LEFT: 37,
29            PAGE_DOWN: 34,
30            PAGE_UP: 33,
31            PERIOD: 190,
32            RIGHT: 39,
33            SPACE: 32,
34            TAB: 9,
35            UP: 38,
36            keyMap: {
37                48: "0",
38                49: "1",
39                50: "2",
40                51: "3",
41                52: "4",
42                53: "5",
43                54: "6",
44                55: "7",
45                56: "8",
46                57: "9",
47                59: ";",
48                65: "a",
49                66: "b",
50                67: "c",
51                68: "d",
52                69: "e",
53                70: "f",
54                71: "g",
55                72: "h",
56                73: "i",
57                74: "j",
58                75: "k",
59                76: "l",
60                77: "m",
61                78: "n",
62                79: "o",
63                80: "p",
64                81: "q",
65                82: "r",
66                83: "s",
67                84: "t",
68                85: "u",
69                86: "v",
70                87: "w",
71                88: "x",
72                89: "y",
73                90: "z",
74                96: "0",
75                97: "1",
76                98: "2",
77                99: "3",
78                100: "4",
79                101: "5",
80                102: "6",
81                103: "7",
82                104: "8",
83                105: "9",
84                190: "."
85            }
86        },
87        clearTimeout = window.clearTimeout,
88        setTimeout = window.setTimeout,
89        isOpera = window.opera && window.opera.toString() === '[object Opera]';
90    /* @desc Creates a new accessible mega menu instance. */
91    function AccessibleMegaMenu(element, options) {
92        this.element = element;
93        // merge optional settings and defaults into settings
94        this.settings = $.extend({}, defaults, options);
95        this._defaults = defaults;
96        this._name = pluginName;
97        this.mouseTimeoutID = null;
98        this.focusTimeoutID = null;
99        this.mouseFocused = false;
100        this.justFocused = false;
101        this.init();
102    }
103    AccessibleMegaMenu.prototype = (function () {
104        var uuid = 0,
105            keydownTimeoutDuration = 1000,
106            keydownSearchString = "",
107            isTouch = 'ontouchstart' in window || window.navigator.msMaxTouchPoints,
108            _getPlugin,
109            _addUniqueId,
110            _togglePanel,
111            _clickHandler,
112            _touchmoveHandler,
113            _clickOutsideHandler,
114            _DOMAttrModifiedHandler,
115            _focusInHandler,
116            _focusOutHandler,
117            _keyDownHandler,
118            _mouseDownHandler,
119            _mouseOverHandler,
120            _mouseOutHandler,
121            _clickToggleHandler,
122            _toggleExpandedEventHandlers,
123            _addEventHandlers,
124            _removeEventHandlers;
125        /* @desc Returns the parent accessibleMegaMenu instance for a given element */
126        _getPlugin = function (element) {
127            return $(element).closest(':data(plugin_' + pluginName + ')').data("plugin_" + pluginName);
128        };
129        /* @desc Adds a unique id and element. */
130        _addUniqueId = function (element) {
131            element = $(element);
132            var settings = this.settings;
133            if (!element.attr("id")) {
134                element.attr("id", settings.uuidPrefix + "-" + new Date().getTime() + "-" + (++uuid));
135            }
136        };
137        /* @desc Toggle the display of mega menu panels in response to an event. */
138        _togglePanel = function (event, hide) {
139            var target = $(event.target),
140                that = this,
141                settings = this.settings,
142                menu = this.menu,
143                topli = target.closest('.' + settings.topNavItemClass),
144                panel = target.hasClass(settings.panelClass) ? target : target.closest('.' + settings.panelClass),
145                newfocus;
146            _toggleExpandedEventHandlers.call(this, true);
147            // Hide all panels.
148            if (hide) {
149                // Get the first top level menu item.
150                topli = menu.find('.' + settings.topNavItemClass + ' .' + settings.openClass + ':first').closest('.' + settings.topNavItemClass);
151                // Validate event.
152                if (!(topli.is(event.relatedTarget) || topli.has(event.relatedTarget).length > 0)) {
153                    if ((event.type === 'mouseout' || event.type === 'focusout') && topli.has(document.activeElement).length > 0) {
154                        return;
155                    }
156                    // Close top level link.
157                    topli.find('[aria-expanded]')
158                        .attr('aria-expanded', 'false')
159                        .removeClass(settings.openClass);
160                    // Close panel.
161                    topli.find('.' + settings.panelClass)
162                        .removeClass(settings.openClass);
163                    if ((event.type === 'keydown' && event.keyCode === Keyboard.ESCAPE) || event.type === 'DOMAttrModified') {
164                        newfocus = topli.find(':tabbable:first');
165                        setTimeout(function () {
166                            menu.find('[aria-expanded].' + that.settings.panelClass).off('DOMAttrModified.accessible-megamenu');
167                            newfocus.focus();
168                            that.justFocused = false;
169                        }, 99);
170                    }
171                } else if (topli.length === 0) {
172                    menu.find('[aria-expanded=true]')
173                        .attr('aria-expanded', 'false')
174                        .removeClass(settings.openClass)
175                        .closest('.' + settings.topNavItemClass)
176                        .find('.' + settings.panelClass)
177                        .removeClass(settings.openClass);
178                }
179            }
180            // Toggle panels.
181            else {
182                clearTimeout(that.focusTimeoutID);
183                // Close previously open top level link and its panel.
184                var openli = menu.find('[aria-expanded=true]').closest('.' + settings.topNavItemClass);
185                if (!openli.is(topli)) {
186                    openli.find('[aria-expanded]')
187                        .attr('aria-expanded', 'false')
188                        .removeClass(settings.openClass);
189                    openli.find('.' + settings.panelClass)
190                        .removeClass(settings.openClass);
191                }
192                // Open current top level link and its panel.
193                topli.find('[aria-expanded]')
194                    .attr('aria-expanded', 'true')
195                    .addClass(settings.openClass);
196                topli.find('.' + settings.panelClass)
197                    .addClass(settings.openClass);
198
199                if (topli.length) {
200                    var pageScrollPosition = $('html')[0].scrollTop;
201                    var openPanelTopPosition = topli.offset().top;
202
203                    if (pageScrollPosition > openPanelTopPosition) {
204                        $('html')[0].scrollTop = openPanelTopPosition;
205                    }
206                }
207
208                if (event.type === 'mouseover' && target.is(':tabbable') && topli.length === 1 && panel.length === 0 && menu.has(document.activeElement).length > 0) {
209                    target.focus();
210                    that.justFocused = false;
211                }
212
213                _toggleExpandedEventHandlers.call(that);
214            }
215        };
216        /* @desc Handle click event on mega menu item */
217        _clickHandler = function (event) {
218            var target = $(event.target).closest(':tabbable'),
219                topli = target.closest('.' + this.settings.topNavItemClass),
220                panel = target.closest('.' + this.settings.panelClass);
221            // With panel.
222            if (topli.length === 1 && panel.length === 0 && topli.find('.' + this.settings.panelClass).length === 1) {
223                // Handle click event.
224                if (!target.hasClass(this.settings.openClass)) {
225                    event.preventDefault();
226                    event.stopPropagation();
227                    _togglePanel.call(this, event);
228                    this.justFocused = false;
229                }
230                else {
231                    // Handle focus event.
232                    if (this.justFocused) {
233                        event.preventDefault();
234                        event.stopPropagation();
235                        this.justFocused = false;
236                    }
237                    // Handle touch/click event.
238                    else if (isTouch || !isTouch && !this.settings.openOnMouseover) {
239                        event.preventDefault();
240                        event.stopPropagation();
241                        _togglePanel.call(this, event, target.hasClass(this.settings.openClass));
242                    }
243                }
244            }
245            // Without panel on enter event.
246            else if (topli.length === 1 && panel.length === 0 && event.type == "keydown" && target.hasAttribute("href")) {
247                window.location.href = target.attr("href");
248            }
249        };
250        /* @desc Handle touch move event on menu */
251        _touchmoveHandler = function () {
252            this.justMoved = true;
253        };
254        /* @desc Handle click event outside of a the megamenu */
255        _clickOutsideHandler = function (event) {
256            if ($(event.target).closest(this.menu).length === 0) {
257                event.preventDefault();
258                event.stopPropagation();
259                _togglePanel.call(this, event, true);
260            }
261        };
262        /* @desc Handle DOMAttrModified event on panel to respond to Windows 8 Narrator */
263        _DOMAttrModifiedHandler = function (event) {
264            if (event.originalEvent.attrName === 'aria-expanded'
265                    && event.originalEvent.newValue === 'false'
266                    && $(event.target).hasClass(this.settings.openClass)) {
267                event.preventDefault();
268                event.stopPropagation();
269                _togglePanel.call(this, event, true);
270            }
271        };
272        /* @desc Handle focusin event on mega menu item. */
273        _focusInHandler = function (event) {
274            clearTimeout(this.focusTimeoutID);
275            var target = $(event.target),
276                panel = target.closest('.' + this.settings.panelClass);
277            target
278                .addClass(this.settings.focusClass);
279            this.justFocused = !this.mouseFocused || (!this.settings.openOnMouseover && this.mouseFocused);
280            this.mouseFocused = false;
281            if (this.justFocused && this.panels.not(panel).filter('.' + this.settings.openClass).length) {
282                _togglePanel.call(this, event);
283            }
284        };
285        /* @desc Handle focusout event on mega menu item. */
286        _focusOutHandler = function (event) {
287            this.justFocused = false;
288            var that = this,
289                target = $(event.target),
290                topli = target.closest('.' + this.settings.topNavItemClass);
291            target
292                .removeClass(this.settings.focusClass);
293            if (typeof window.cvox === 'object' && typeof window.cvox.Api !== 'object') {
294                // If ChromeVox is running...
295                that.focusTimeoutID = setTimeout(function () {
296                    window.cvox.Api.getCurrentNode(function (node) {
297                        if (topli.has(node).length) {
298                            // and the current node being voiced is in
299                            // the mega menu, clearTimeout,
300                            // so the panel stays open.
301                            clearTimeout(that.focusTimeoutID);
302                        } else {
303                            that.focusTimeoutID = setTimeout(function (scope, event, hide) {
304                                _togglePanel.call(scope, event, hide);
305                            }, 275, that, event, true);
306                        }
307                    });
308                }, 25);
309            } else {
310                that.focusTimeoutID = setTimeout(function () {
311                    if (that.mouseFocused && event.relatedTarget === null) {
312                        return;
313                    }
314                    _togglePanel.call(that, event, true);
315                }, 300);
316            }
317        };
318        /* @desc Handle keydown event on mega menu. */
319        _keyDownHandler = function (event) {
320            var that = (this.constructor === AccessibleMegaMenu) ? this : _getPlugin(this), // determine the AccessibleMegaMenu plugin instance
321                settings = that.settings,
322                target = $($(this).is('.' + settings.hoverClass + ':tabbable') ? this : event.target), // if the element is hovered the target is this, otherwise, its the focused element
323                menu = that.menu,
324                topnavitems = that.topnavitems,
325                topli = target.closest('.' + settings.topNavItemClass),
326                tabbables = menu.find(':tabbable'),
327                panel = target.hasClass(settings.panelClass) ? target : target.closest('.' + settings.panelClass),
328                panelGroups = panel.find('.' + settings.panelGroupClass),
329                currentPanelGroup = target.closest('.' + settings.panelGroupClass),
330                next,
331                keycode = event.keyCode || event.which,
332                start,
333                i,
334                o,
335                label,
336                found = false,
337                newString = Keyboard.keyMap[event.keyCode] || '',
338                regex,
339                isTopNavItem = (topli.length === 1 && panel.length === 0);
340
341            if (target.is("input:focus, select:focus, textarea:focus, button:focus")) {
342                // if the event target is a form element we should handle keydown normally
343                return;
344            }
345            if (target.is('.' + settings.hoverClass + ':tabbable')) {
346                $('html').off('keydown.accessible-megamenu');
347            }
348            switch (keycode) {
349            case Keyboard.ESCAPE:
350                this.mouseFocused = false;
351                _togglePanel.call(that, event, true);
352                break;
353            case Keyboard.DOWN:
354                event.preventDefault();
355                this.mouseFocused = false;
356                if (isTopNavItem) {
357                    _togglePanel.call(that, event);
358                    found = (topli.find('.' + settings.panelClass + ' :tabbable:first').focus().length === 1);
359                } else {
360                    found = (tabbables.filter(':gt(' + tabbables.index(target) + '):first').focus().length === 1);
361                }
362
363                if (!found && isOpera && (event.ctrlKey || event.metaKey)) {
364                    tabbables = $(':tabbable');
365                    i = tabbables.index(target);
366                    found = ($(':tabbable:gt(' + $(':tabbable').index(target) + '):first').focus().length === 1);
367                }
368                break;
369            case Keyboard.UP:
370                event.preventDefault();
371                this.mouseFocused = false;
372                if (isTopNavItem && target.hasClass(settings.openClass)) {
373                    _togglePanel.call(that, event, true);
374                    next = topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last');
375                    if (next.children('.' + settings.panelClass).length) {
376                        next.find('[aria-expanded]')
377                            .attr('aria-expanded', 'true')
378                            .addClass(settings.openClass);
379                        found = (next.children('.' + settings.panelClass)
380                                .addClass(settings.openClass)
381                                .find(':tabbable:last')
382                                .focus() === 1);
383                    }
384                } else if (!isTopNavItem) {
385                    found = (tabbables.filter(':lt(' + tabbables.index(target) + '):last').focus().length === 1);
386                }
387
388                if (!found && isOpera && (event.ctrlKey || event.metaKey)) {
389                    tabbables = $(':tabbable');
390                    i = tabbables.index(target);
391                    found = ($(':tabbable:lt(' + $(':tabbable').index(target) + '):first').focus().length === 1);
392                }
393                break;
394            case Keyboard.RIGHT:
395                event.preventDefault();
396                this.mouseFocused = false;
397                if (isTopNavItem) {
398                    found = (topnavitems.filter(':gt(' + topnavitems.index(topli) + '):first').find(':tabbable:first').focus().length === 1);
399                } else {
400                    if (panelGroups.length && currentPanelGroup.length) {
401                        // if the current panel contains panel groups, and we are able to focus the first tabbable element of the next panel group
402                        found = (panelGroups.filter(':gt(' + panelGroups.index(currentPanelGroup) + '):first').find(':tabbable:first').focus().length === 1);
403                    }
404
405                    if (!found) {
406                        found = (topli.find(':tabbable:first').focus().length === 1);
407                    }
408                }
409                break;
410            case Keyboard.LEFT:
411                event.preventDefault();
412                this.mouseFocused = false;
413                if (isTopNavItem) {
414                    found = (topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last').find(':tabbable:first').focus().length === 1);
415                } else {
416                    if (panelGroups.length && currentPanelGroup.length) {
417                        // if the current panel contains panel groups, and we are able to focus the first tabbable element of the previous panel group
418                        found = (panelGroups.filter(':lt(' + panelGroups.index(currentPanelGroup) + '):last').find(':tabbable:first').focus().length === 1);
419                    }
420
421                    if (!found) {
422                        found = (topli.find(':tabbable:first').focus().length === 1);
423                    }
424                }
425                break;
426            case Keyboard.TAB:
427                this.mouseFocused = false;
428                i = tabbables.index(target);
429                if (event.shiftKey && isTopNavItem && target.hasClass(settings.openClass)) {
430                    _togglePanel.call(that, event, true);
431                    next = topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last');
432                    if (next.children('.' + settings.panelClass).length) {
433                        found = next.children()
434                            .attr('aria-expanded', 'true')
435                            .addClass(settings.openClass)
436                            .filter('.' + settings.panelClass)
437                            .find(':tabbable:last')
438                            .focus();
439                    }
440                } else if (event.shiftKey && i > 0) {
441                    found = (tabbables.filter(':lt(' + i + '):last').focus().length === 1);
442                } else if (!event.shiftKey && i < tabbables.length - 1) {
443                    found = (tabbables.filter(':gt(' + i + '):first').focus().length === 1);
444                } else if (isOpera) {
445                    tabbables = $(':tabbable');
446                    i = tabbables.index(target);
447                    if (event.shiftKey) {
448                        found = ($(':tabbable:lt(' + $(':tabbable').index(target) + '):last').focus().length === 1);
449                    } else {
450                        found = ($(':tabbable:gt(' + $(':tabbable').index(target) + '):first').focus().length === 1);
451                    }
452                }
453                if (found) {
454                    event.preventDefault();
455                }
456                break;
457            case Keyboard.SPACE:
458            case Keyboard.ENTER:
459                // Top level links.
460                if (isTopNavItem) {
461                    event.preventDefault();
462                    // Handle enter event on open top level link as escape event.
463                    if (target.hasClass("open")) {
464                        this.mouseFocused = false;
465                        _togglePanel.call(that, event, true);
466                    }
467                    // Handle enter event on top level link as a click.
468                    else {
469                        _clickHandler.call(that, event);
470                    }
471                }
472                // Sub level links.
473                else {
474                  return true;
475                }
476                break;
477            default:
478                // alphanumeric filter
479                clearTimeout(this.keydownTimeoutID);
480                keydownSearchString += newString !== keydownSearchString ? newString : '';
481                if (keydownSearchString.length === 0) {
482                    return;
483                }
484                this.keydownTimeoutID = setTimeout(function () {
485                    keydownSearchString = '';
486                }, keydownTimeoutDuration);
487                if (isTopNavItem && !target.hasClass(settings.openClass)) {
488                    tabbables = tabbables.filter(':not(.' + settings.panelClass + ' :tabbable)');
489                } else {
490                    tabbables = topli.find(':tabbable');
491                }
492                if (event.shiftKey) {
493                    tabbables = $(tabbables.get()
494                        .reverse());
495                }
496                for (i = 0; i < tabbables.length; i++) {
497                    o = tabbables.eq(i);
498                    if (o.is(target)) {
499                        start = (keydownSearchString.length === 1) ? i + 1 : i;
500                        break;
501                    }
502                }
503                regex = new RegExp('^' + keydownSearchString.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'), 'i');
504                for (i = start; i < tabbables.length; i++) {
505                    o = tabbables.eq(i);
506                    label = $.trim(o.text());
507                    if (regex.test(label)) {
508                        found = true;
509                        o.focus();
510                        break;
511                    }
512                }
513                if (!found) {
514                    for (i = 0; i < start; i++) {
515                        o = tabbables.eq(i);
516                        label = $.trim(o.text());
517                        if (regex.test(label)) {
518                            o.focus();
519                            break;
520                        }
521                    }
522                }
523                break;
524            }
525            that.justFocused = false;
526        };
527        /* @desc Handle mousedown event on mega menu. */
528        _mouseDownHandler = function (event) {
529            if ($(event.target).closest(this.settings.panelClass) || $(event.target).closest(":focusable").length) {
530                this.mouseFocused = true;
531                if ($(event.target).closest(this.settings.menuClass)) {
532                    $('html').on('keydown.accessible-megamenu', $.proxy(_keyDownHandler, event.target));
533                }
534            }
535            clearTimeout(this.mouseTimeoutID);
536            this.mouseTimeoutID = setTimeout(function () {
537                clearTimeout(this.focusTimeoutID);
538            }, 1);
539        };
540        /* @desc Handle mouseover event on mega menu. */
541        _mouseOverHandler = function (event) {
542            clearTimeout(this.mouseTimeoutID);
543            var that = this;
544
545            if (!that.settings.openOnMouseover) {
546                return;
547            }
548            this.mouseTimeoutID = setTimeout(function () {
549                $(event.target).addClass(that.settings.hoverClass);
550                _togglePanel.call(that, event);
551                if ($(event.target).closest(that.settings.menuClass)) {
552                    $('html').on('keydown.accessible-megamenu', $.proxy(_keyDownHandler, event.target));
553                }
554            }, this.settings.openDelay);
555        };
556        /* @desc Handle mouseout event on mega menu. */
557        _mouseOutHandler = function (event) {
558            clearTimeout(this.mouseTimeoutID);
559            var that = this;
560
561            if (!that.settings.openOnMouseover) {
562                return;
563            }
564            $(event.target)
565                .removeClass(that.settings.hoverClass);
566            that.mouseTimeoutID = setTimeout(function () {
567                _togglePanel.call(that, event, true);
568            }, this.settings.closeDelay);
569            if ($(event.target).is(':tabbable')) {
570                $('html').off('keydown.accessible-megamenu');
571            }
572        };
573        /* @desc Handle click event on menu toggle button. */
574        _clickToggleHandler = function () {
575            var isExpanded = this.toggleButton.attr('aria-expanded') === 'true';
576            this.toggleButton.attr({'aria-expanded': !isExpanded});
577        };
578        _toggleExpandedEventHandlers = function (hide) {
579            var menu = this.menu;
580            if (hide) {
581                $('html').off('mouseup.outside-accessible-megamenu, touchend.outside-accessible-megamenu, mspointerup.outside-accessible-megamenu,  pointerup.outside-accessible-megamenu');
582
583                menu.find('[aria-expanded].' + this.settings.panelClass).off('DOMAttrModified.accessible-megamenu');
584            } else {
585                $('html').on('mouseup.outside-accessible-megamenu, touchend.outside-accessible-megamenu, mspointerup.outside-accessible-megamenu,  pointerup.outside-accessible-megamenu', $.proxy(_clickOutsideHandler, this));
586                menu.find('[aria-expanded=true].' + this.settings.panelClass).on('DOMAttrModified.accessible-megamenu', $.proxy(_DOMAttrModifiedHandler, this));
587            }
588        };
589        _addEventHandlers = function() {
590            var menu = this.menu,
591                toggleButton = this.toggleButton;
592            menu.on("focusin.accessible-megamenu", ":focusable, ." + this.settings.panelClass, $.proxy(_focusInHandler, this))
593                .on("focusout.accessible-megamenu", ":focusable, ." + this.settings.panelClass, $.proxy(_focusOutHandler, this))
594                .on("keydown.accessible-megamenu", $.proxy(_keyDownHandler, this))
595                .on("mouseover.accessible-megamenu", $.proxy(_mouseOverHandler, this))
596                .on("mouseout.accessible-megamenu", $.proxy(_mouseOutHandler, this))
597                .on("mousedown.accessible-megamenu", $.proxy(_mouseDownHandler, this))
598                .on("click.accessible-megamenu", $.proxy(_clickHandler, this));
599
600            toggleButton.on('click.accessible-megamenu', $.proxy(_clickToggleHandler, this));
601
602            if (isTouch) {
603                menu.on("touchmove.accessible-megamenu", $.proxy(_touchmoveHandler, this));
604            }
605
606            if ($(document.activeElement).closest(menu).length) {
607              $(document.activeElement).trigger("focusin.accessible-megamenu");
608            }
609        };
610        _removeEventHandlers = function () {
611            var menu = this.menu,
612                toggleButton = this.toggleButton;
613            menu.off('.accessible-megamenu');
614            if (menu.find('[aria-expanded=true].' + this.settings.panelClass).length) {
615                _toggleExpandedEventHandlers.call(this, true);
616            }
617
618            toggleButton.off('.accessible-megamenu');
619        };
620        return {
621            constructor: AccessibleMegaMenu,
622            /* @desc Initializes an instance of the accessibleMegaMenu plugins */
623            init: function () {
624                var settings = this.settings,
625                    nav = $(this.element),
626                    menu = nav.children('ol,ul').first(),
627                    topnavitems = menu.children(),
628                    toggleButton = nav.children('button').first();
629                this.start(settings, nav, menu, topnavitems, toggleButton);
630            },
631            start: function(settings, nav, menu, topnavitems, toggleButton) {
632                var that = this;
633                this.settings = settings;
634                this.menu = menu;
635                this.topnavitems = topnavitems;
636                this.toggleButton = toggleButton;
637                _addUniqueId.call(that, menu);
638                menu.addClass(settings.menuClass);
639                menu.addClass(['js', settings.menuClass].join('-'));
640                topnavitems.each(function (i, topnavitem) {
641                    var topnavitemlink, topnavitempanel;
642                    topnavitem = $(topnavitem);
643                    topnavitem.addClass(settings.topNavItemClass);
644                    topnavitemlink = topnavitem.find(":tabbable:first");
645                    topnavitempanel = topnavitem.children(":not(:tabbable):last");
646                    _addUniqueId.call(that, topnavitemlink);
647                    // When sub nav exists.
648                    if (topnavitempanel.length) {
649                        _addUniqueId.call(that, topnavitempanel);
650                        // Add attributes to top level link.
651                        topnavitemlink.attr({
652                            "aria-expanded": false,
653                            "tabindex": 0
654                        });
655                        // Add attributes to sub nav.
656                        topnavitempanel.attr({
657                            
658                        })
659                        .addClass(settings.panelClass)
660                        .not("[aria-labelledby]")
661                        .attr("aria-labelledby", topnavitemlink.attr("id"));
662                    }
663                });
664                this.panels = menu.find("." + settings.panelClass);
665                toggleButton.addClass(settings.toggleButtonClass);
666                toggleButton.attr({'aria-expanded': false});
667                _addEventHandlers.call(this);
668            },
669            /* @example $(selector).accessibleMegaMenu("destroy"); */
670            destroy: function () {
671                this.menu.removeClass(['js', this.settings.menuClass].join('-'));
672                _removeEventHandlers.call(this, true);
673            },
674            /* @example $(selector).accessibleMegaMenu("getDefaults"); */
675            getDefaults: function () {
676                return this._defaults;
677            },
678
679            /* @example $(selector).accessibleMegaMenu("getOption", some_option); */
680            getOption: function (opt) {
681                return this.settings[opt];
682            },
683
684            /* @example $(selector).accessibleMegaMenu("getAllOptions"); */
685            getAllOptions: function () {
686                return this.settings;
687            },
688            /* @example $(selector).accessibleMegaMenu */
689            setOption: function (opt, value, reinitialize) {
690                this.settings[opt] = value;
691                if (reinitialize) {
692                    this.init();
693                }
694            }
695        };
696    }());
697    $.fn[pluginName] = function (options) {
698        return this.each(function () {
699            var pluginInstance = $.data(this, "plugin_" + pluginName);
700            if (!pluginInstance) {
701                $.data(this, "plugin_" + pluginName, new $.fn[pluginName].Acce
701ssibleMegaMenu(this, options));
702            } else if (typeof pluginInstance[options] === 'function') {
703                pluginInstance[options].apply(pluginInstance, Array.prototype.slice.call(arguments, 1));
704            }
705        });
706    };
707    $.fn[pluginName].AccessibleMegaMenu = AccessibleMegaMenu;
708    /* :focusable and :tabbable selectors */
709    function visible(element) {
710        return $.expr.filters.visible(element) && !$(element).parents().addBack().filter(function () {
711            return $.css(this, "visibility") === "hidden";
712        }).length;
713    }
714    function focusable(element, isTabIndexNotNaN) {
715        var map, mapName, img,
716            nodeName = element.nodeName.toLowerCase();
717        if ("area" === nodeName) {
718            map = element.parentNode;
719            mapName = map.name;
720            if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") {
721                return false;
722            }
723            img = $("img[usemap=#" + mapName + "]")[0];
724            return !!img && visible(img);
725        }
726        return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled :
727                "a" === nodeName ?
728                        element.href || isTabIndexNotNaN :
729                        isTabIndexNotNaN) &&
730                            // the element and all of its ancestors must be visible
731                            visible(element);
732    }
733    $.extend($.expr[":"], {
734        data: $.expr.createPseudo ? $.expr.createPseudo(function (dataName) {
735            return function (elem) {
736                return !!$.data(elem, dataName);
737            };
738        }) : // support: jQuery <1.8
739                function (elem, i, match) {
740                    return !!$.data(elem, match[3]);
741                },
742        focusable: function (element) {
743            return focusable(element, !isNaN($.attr(element, "tabindex")));
744        },
745        tabbable: function (element) {
746            var tabIndex = $.attr(element, "tabindex"),
747                isTabIndexNaN = isNaN(tabIndex);
748            return (isTabIndexNaN || tabIndex >= 0) && focusable(element, !isTabIndexNaN);
749        }
750    });
751}(jQuery, window, document));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.