PageSourceSearch

https://www.plcgroup.com/wp-content/themes/plcgroup-theme/js/jquery.slicknav.js?ver=1.0

js plcgroup.com collected 2026-09-29 12:49:25 UTC 21,205 bytes, 590 lines download raw bytes

vendor: 5,308 bytes, lines 1-166
1/*!
2 * SlickNav Responsive Mobile Menu v1.0.10
3 * (c) 2016 Josh Cope
4 * licensed under MIT
5 */
6;(function ($, document, window) {
7    var
8    // default settings object.
9        defaults = {
10            label: 'MENU',
11            duplicate: true,
12            duration: 200,
13            easingOpen: 'swing',
14            easingClose: 'swing',
15            closedSymbol: '►',
16            openedSymbol: '▼',
17            prependTo: 'body',
18            appendTo: '',
19            parentTag: 'a',
20            closeOnClick: false,
21            allowParentLinks: false,
22            nestedParentLinks: true,
23            showChildren: false,
24            removeIds: true,
25            removeClasses: false,
26            removeStyles: false,
27			brand: '',
28            animations: 'jquery',
29            init: function () {},
30            beforeOpen: function () {},
31            beforeClose: function () {},
32            afterOpen: function () {},
33            afterClose: function () {}
34        },
35        mobileMenu = 'slicknav',
36        prefix = 'slicknav';
37
38        Keyboard = {
39            DOWN: 40,
40            ENTER: 13,
41            ESCAPE: 27,
42            LEFT: 37,
43            RIGHT: 39,
44            SPACE: 32,
45            TAB: 9,
46            UP: 38,
47        };
48
49    function Plugin(element, options) {
50        this.element = element;
51
52        // jQuery has an extend method which merges the contents of two or
53        // more objects, storing the result in the first object. The first object
54        // is generally empty as we don't want to alter the default options for
55        // future instances of the plugin
56        this.settings = $.extend({}, defaults, options);
57
58        // Don't remove IDs by default if duplicate is false
59        if (!this.settings.duplicate && !options.hasOwnProperty("removeIds")) {
60          this.settings.removeIds = false;
61        }
62
63        this._defaults = defaults;
64        this._name = mobileMenu;
65
66        this.init();
67    }
68
69    Plugin.prototype.init = function () {
70        var $this = this,
71            menu = $(this.element),
72            settings = this.settings,
73            iconClass,
74            menuBar;
75
76        // clone menu if needed
77        if (settings.duplicate) {
78            $this.mobileNav = menu.clone();
79        } else {
80            $this.mobileNav = menu;
81        }
82
83        // remove IDs if set
84        if (settings.removeIds) {
85          $this.mobileNav.removeAttr('id');
86          $this.mobileNav.find('*').each(function (i, e) {
87              $(e).removeAttr('id');
88          });
89        }
90
91        // remove classes if set
92        if (settings.removeClasses) {
93            $this.mobileNav.removeAttr('class');
94            $this.mobileNav.find('*').each(function (i, e) {
95                $(e).removeAttr('class');
96            });
97        }
98
99        // remove styles if set
100        if (settings.removeStyles) {
101            $this.mobileNav.removeAttr('style');
102            $this.mobileNav.find('*').each(function (i, e) {
103                $(e).removeAttr('style');
104            });
105        }
106
107        // styling class for the button
108        iconClass = prefix + '_icon';
109
110        if (settings.label === '') {
111            iconClass += ' ' + prefix + '_no-text';
112        }
113
114        if (settings.parentTag === 'a') {
115            settings.parentTag = 'a href="#"';
116        }
117
118        // create menu bar
119        $this.mobileNav.attr('class', prefix + '_nav');
120        menuBar = $('<div class="' + prefix + '_menu"></div>');
121		if (settings.brand !== '') {
122			var brand = $('<div class="' + prefix + '_brand">'+settings.brand+'</div>');
123			$(menuBar).append(brand);
124		}
125        $this.btn = $(
126            ['<' + settings.parentTag + ' aria-haspopup="true" role="button" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed">',
127                '<span class="' + prefix + '_menutxt">' + settings.label + '</span>',
128                '<span class="' + iconClass + '">',
129                    '<span class="' + prefix + '_icon-bar"></span>',
130                    '<span class="' + prefix + '_icon-bar"></span>',
131                    '<span class="' + prefix + '_icon-bar"></span>',
132                '</span>',
133            '</' + settings.parentTag + '>'
134            ].join('')
135        );
136        $('.navbar-toggle').append($this.btn);
137        if(settings.appendTo !== '') {
138            $(settings.appendTo).append(menuBar);
139        } else {
140            $(settings.prependTo).prepend(menuBar);
141        }
142        menuBar.append($this.mobileNav);
143
144        // iterate over structure adding additional structure
145        var items = $this.mobileNav.find('li');
146        $(items).each(function () {
147            var item = $(this),
148                data = {};
149            data.children = item.children('ul').attr('role', 'menu');
150            item.data('menu', data);
151
152            // if a list item has a nested menu
153            if (data.children.length > 0) {
154
155                // select all text before the child menu
156                // check for anchors
157
158                var a = item.contents(),
159                    containsAnchor = false,
160                    nodes = [];
161
162                $(a).each(function () {
163                    if (!$(this).is('ul')) {
164                        nodes.push(this);
165                    } else {
166                        return false;
167                    }
168
169                    if($(this).is("a")) {
170                        containsAnchor = true;
171                    }
172                });
173
174                var wrapElement = $(
175                    '<' + settings.parentTag + ' role="menuitem" aria-haspopup="true" tabindex="-1" class="' + prefix + '_item"/>'
176                );
177
178                // wrap item text with tag and add classes unless we are separating parent links
179                if ((!settings.allowParentLinks || settings.nestedParentLinks) || !containsAnchor) {
180                    var $wrap = $(nodes).wrapAll(wrapElement).parent();
181                    $wrap.addClass(prefix+'_row');
182                } else
183                    $(nodes).wrapAll('<span class="'+prefix+'_parent-link '+prefix+'_row"/>').parent();
184
185                if (!settings.showChildren) {
186                    item.addClass(prefix+'_collapsed');
187                } else {
188                    item.addClass(prefix+'_open');
189                }
190
191                item.addClass(prefix+'_parent');
192
193                // create parent arrow. wrap with link if parent links and separating
194                var arrowElement = $('<span class="'+prefix+'_arrow">'+(settings.showChildren?settings.openedSymbol:settings.closedSymbol)+'</span>');
195
196                if (settings.allowParentLinks && !settings.nestedParentLinks && containsAnchor)
197                    arrowElement = arrowElement.wrap(wrapElement).parent();
198
199                //append arrow
200                $(nodes).last().after(arrowElement);
201
202
203            } else if ( item.children().length === 0) {
204                 item.addClass(prefix+'_txtnode');
205            }
206
207            // accessibility for links
208            item.children('a').attr('role', 'menuitem').on("click", function(event){
209                //Ensure that it's not a parent
210                if (settings.closeOnClick && !$(event.target).parent().closest('li').hasClass(prefix+'_parent')) {
211                        //Emulate menu close if set
212                        $($this.btn).trigger('click');
213                    }
214            });
215
216            //also close on click if parent links are set
217            if (settings.closeOnClick && settings.allowParentLinks) {
218				
219                item.children('a').children('a').on("click", function(event){
220                    //Emulate menu close
221                    $($this.btn).trigger('click');
222                });
223
224                item.find('.'+prefix+'_parent-link a:not(.'+prefix+'_item)').on("click", function(event){
225                    //Emulate menu close
226						$($this.btn).trigger('click');
227                });
228            }
229        });
230
231        // structure is in place, now hide appropriate items
232        $(items).each(function () {
233            var data = $(this).data('menu');
234            if (!settings.showChildren){
235                $this._visibilityToggle(data.children, null, false, null, true);
236            }
237        });
238
239        // finally toggle entire menu
240        $this._visibilityToggle($this.mobileNav, null, false, 'init', true);
241
242        // accessibility for menu button
243        $this.mobileNav.attr('role','menu');
244
245        // outline prevention when using mouse
246        $(document).on( "mousedown", function() {
247			$this._outlines(false);
248        });
249
250		$(document).on( "keyup", function() {
251            $this._outlines(true);
252        });
253
254        // menu button click
255        $($this.btn).on("click", function(e){
256            e.preventDefault();
257            $this._menuToggle();
258        });
259
260        // click on menu parent
261        $this.mobileNav.on('click', '.' + prefix + '_item', function (e) {
262            e.preventDefault();
263            $this._itemClick($(this));
264        });
265
266        // check for keyboard events on menu button and menu parents
267        $($this.btn).on("keydown", function(e){
268            var ev = e || event;
269
270            switch(ev.keyCode) {
271                case Keyboard.ENTER:
272                case Keyboard.SPACE:
273                case Keyboard.DOWN:
274                    e.preventDefault();
275                    if (ev.keyCode !== Keyboard.DOWN || !$($this.btn).hasClass(prefix+'_open')){
276                        $this._menuToggle();
277                    }
278                    
279                    $($this.btn).next().find('[role="menuitem"]').first().trigger( "focus" );
280                    break;
281            }
282
283            
284        });
285
286        $this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) {
287            var ev = e || event;
288
289            switch(ev.keyCode) {
290                case Keyboard.ENTER:
291                    e.preventDefault();
292                    $this._itemClick($(e.target));
293                    break;
294                case Keyboard.RIGHT:
295                    e.preventDefault();
296                    if ($(e.target).parent().hasClass(prefix+'_collapsed')) {
297                        $this._itemClick($(e.target));
298                    }
299                    $(e.target).next().find('[role="menuitem"]').first().trigger( "focus" );
300                    break;
301            }
302        });
303
304        $this.mobileNav.on('keydown', '[role="menuitem"]', function(e) {
305            var ev = e || event;
306
307            switch(ev.keyCode){
308                case Keyboard.DOWN:
309                    e.preventDefault();
310                    var allItems = $(e.target).parent().parent().children().children('[role="menuitem"]:visible');
311                    var idx = allItems.index( e.target );
312                    var nextIdx = idx + 1;
313                    if (allItems.length <= nextIdx) {
314                        nextIdx = 0;
315                    }
316                    var next = allItems.eq( nextIdx );
317                    next.trigger( "focus" );
318                break;
319                case Keyboard.UP:
320                    e.preventDefault();
321                    var allItems = $(e.target).parent().parent().children().children('[role="menuitem"]:visible');
322                    var idx = allItems.index( e.target );
323                    var next = allItems.eq( idx - 1 );
324                    next.trigger( "focus" );
325                break;
326                case Keyboard.LEFT:
327                    e.preventDefault();
328                    if ($(e.target).parent().parent().parent().hasClass(prefix+'_open')) {
329                        var parent = $(e.target).parent().parent().prev();
330                        parent.trigger( "focus" );
331                        $this._itemClick(parent);
332                    } else if ($(e.target).parent().parent().hasClass(prefix+'_nav')){
333                        $this._menuToggle();
334                        $($this.btn).trigger( "focus" );
335                    }
336                    break;
337                case Keyboard.ESCAPE:
338                    e.preventDefault();
339                    $this._menuToggle();
340                    $($this.btn).trigger( "focus" );
341                    break;    
342            }
343        });
344
345        // allow links clickable within parent tags if set
346        if (settings.allowParentLinks && settings.nestedParentLinks) {
347            $('.'+prefix+'_item a').on("click", function(e){
348                    e.stopImmediatePropagation();
349            });
350        }
351    };
352
353    //toggle menu
354    Plugin.prototype._menuToggle = function (el) {
355        var $this = this;
356        var btn = $this.btn;
357        var mobileNav = $this.mobileNav;
358
359        if (btn.hasClass(prefix+'_collapsed')) {
360            btn.removeClass(prefix+'_collapsed');
361            btn.addClass(prefix+'_open');
362        } else {
363            btn.removeClass(prefix+'_open');
364            btn.addClass(prefix+'_collapsed');
365        }
366        btn.addClass(prefix+'_animating');
367        $this._visibilityToggle(mobileNav, btn.parent(), true, btn);
368    };
369
370    // toggle clicked items
371    Plugin.prototype._itemClick = function (el) {
372        var $this = this;
373        var settings = $this.settings;
374        var data = el.data('menu');
375        if (!data) {
376            data = {};
377            data.arrow = el.children('.'+prefix+'_arrow');
378            data.ul = el.next('ul');
379            data.parent = el.parent();
380            //Separated parent link structure
381            if (data.parent.hasClass(prefix+'_parent-link')) {
382                data.parent = el.parent().parent();
383                data.ul = el.parent().next('ul');
384            }
385            el.data('menu', data);
386        }
387        if (data.parent.hasClass(prefix+'_collapsed')) {
388            data.arrow.html(settings.openedSymbol);
389            data.parent.removeClass(prefix+'_collapsed');
390            data.parent.addClass(prefix+'_open');
391            data.parent.addClass(prefix+'_animating');
392            $this._visibilityToggle(data.ul, data.parent, true, el);
393        } else {
394            data.arrow.html(settings.closedSymbol);
395            data.parent.addClass(prefix+'_collapsed');
396            data.parent.removeClass(prefix+'_open');
397            data.parent.addClass(prefix+'_animating');
398            $this._visibilityToggle(data.ul, data.parent, true, el);
399        }
400    };
401
402    // toggle actual visibility and accessibility tags
403    Plugin.prototype._visibilityToggle = function(el, parent, animate, trigger, init) {
404        var $this = this;
405        var settings = $this.settings;
406        var items = $this._getActionItems(el);
407        var duration = 0;
408        if (animate) {
409            duration = settings.duration;
410        }
411        
412        function afterOpen(trigger, parent) {
413            $(trigger).removeClass(prefix+'_animating');
414            $(parent).removeClass(prefix+'_animating');
415
416            //Fire afterOpen callback
417            if (!init) {
418                settings.afterOpen(trigger);
419            }
420        }
421        
vendor: 6,211 bytes, lines 422-590
422        function afterClose(trigger, parent) {
423            el.attr('aria-hidden','true');
424            items.attr('tabindex', '-1');
425            $this._setVisAttr(el, true);
426            el.hide(); //jQuery 1.7 bug fix
427
428            $(trigger).removeClass(prefix+'_animating');
429            $(parent).removeClass(prefix+'_animating');
430
431            //Fire init or afterClose callback
432            if (!init){
433                settings.afterClose(trigger);
434            } else if (trigger === 'init'){
435                settings.init();
436            }
437        }
438
439        if (el.hasClass(prefix+'_hidden')) {
440            el.removeClass(prefix+'_hidden');
441             //Fire beforeOpen callback
442            if (!init) {
443                settings.beforeOpen(trigger);
444            }
445            if (settings.animations === 'jquery') {
446                el.stop(true,true).slideDown(duration, settings.easingOpen, function(){
447                    afterOpen(trigger, parent);
448                });
449            } else if(settings.animations === 'velocity') {
450                el.velocity("finish").velocity("slideDown", {
451                    duration: duration,
452                    easing: settings.easingOpen,
453                    complete: function() {
454                        afterOpen(trigger, parent);
455                    }
456                });
457            }
458            el.attr('aria-hidden','false');
459            items.attr('tabindex', '0');
460            $this._setVisAttr(el, false);
461        } else {
462            el.addClass(prefix+'_hidden');
463
464            //Fire init or beforeClose callback
465            if (!init){
466                settings.beforeClose(trigger);
467            }
468
469            if (settings.animations === 'jquery') {
470                el.stop(true,true).slideUp(duration, this.settings.easingClose, function() {
471                    afterClose(trigger, parent)
472                });
473            } else if (settings.animations === 'velocity') {
474                
475                el.velocity("finish").velocity("slideUp", {
476                    duration: duration,
477                    easing: settings.easingClose,
478                    complete: function() {
479                        afterClose(trigger, parent);
480                    }
481                });
482            }
483        }
484    };
485
486    // set attributes of element and children based on visibility
487    Plugin.prototype._setVisAttr = function(el, hidden) {
488        var $this = this;
489
490        // select all parents that aren't hidden
491        var nonHidden = el.children('li').children('ul').not('.'+prefix+'_hidden');
492
493        // iterate over all items setting appropriate tags
494        if (!hidden) {
495            nonHidden.each(function(){
496                var ul = $(this);
497                ul.attr('aria-hidden','false');
498                var items = $this._getActionItems(ul);
499                items.attr('tabindex', '0');
500                $this._setVisAttr(ul, hidden);
501            });
502        } else {
503            nonHidden.each(function(){
504                var ul = $(this);
505                ul.attr('aria-hidden','true');
506                var items = $this._getActionItems(ul);
507                items.attr('tabindex', '-1');
508                $this._setVisAttr(ul, hidden);
509            });
510        }
511    };
512
513    // get all 1st level items that are clickable
514    Plugin.prototype._getActionItems = function(el) {
515        var data = el.data("menu");
516        if (!data) {
517            data = {};
518            var items = el.children('li');
519            var anchors = items.find('a');
520            data.links = anchors.add(items.find('.'+prefix+'_item'));
521            el.data('menu', data);
522        }
523        return data.links;
524    };
525
526    Plugin.prototype._outlines = function(state) {
527        if (!state) {
528            $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','none');
529        } else {
530            $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','');
531        }
532    };
533
534    Plugin.prototype.toggle = function(){
535        var $this = this;
536        $this._menuToggle();
537    };
538
539    Plugin.prototype.open = function(){
540        var $this = this;
541        if ($this.btn.hasClass(prefix+'_collapsed')) {
542            $this._menuToggle();
543        }
544    };
545
546    Plugin.prototype.close = function(){
547        var $this = this;
548        if ($this.btn.hasClass(prefix+'_open')) {
549            $this._menuToggle();
550        }
551    };
552
553    $.fn[mobileMenu] = function ( options ) {
554        var args = arguments;
555
556        // Is the first parameter an object (options), or was omitted, instantiate a new instance
557        if (options === undefined || typeof options === 'object') {
558            return this.each(function () {
559
560                // Only allow the plugin to be instantiated once due to methods
561                if (!$.data(this, 'plugin_' + mobileMenu)) {
562
563                    // if it has no instance, create a new one, pass options to our plugin constructor,
564                    // and store the plugin instance in the elements jQuery data object.
565                    $.data(this, 'plugin_' + mobileMenu, new Plugin( this, options ));
566                }
567            });
568
569        // If is a string and doesn't start with an underscore or 'init' function, treat this as a call to a public method.
570        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
571
572            // Cache the method call to make it possible to return a value
573            var returns;
574
575            this.each(function () {
576                var instance = $.data(this, 'plugin_' + mobileMenu);
577
578                // Tests that there's already a plugin-instance and checks that the requested public method exists
579                if (instance instanceof Plugin && typeof instance[options] === 'function') {
580
581                    // Call the method of our plugin instance, and pass it the supplied arguments.
582                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
583                }
584            });
585
586            // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
587            return returns !== undefined ? returns : this;
588        }
589    };
590}(jQuery, document, window));

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.