PageSourceSearch

https://connecticutwatercolorsociety.com/assets/dropdown/js/nav-dropdown.js

js connecticutwatercolorsociety.com collected 2026-10-05 23:01:08 UTC 18,913 bytes, 643 lines download raw bytes

1(function($){
2
3    var NAME = 'navDropdown';
4    var DATA_KEY = 'bs.nav-dropdown';
5    var EVENT_KEY = '.' + DATA_KEY;
6    var DATA_API_KEY = '.data-api';
7    var JQUERY_NO_CONFLICT = $.fn[NAME];
8
9    var Event = {
10        HIDE: 'hide' + EVENT_KEY,
11        HIDDEN: 'hidden' + EVENT_KEY,
12        SHOW: 'show' + EVENT_KEY,
13        SHOWN: 'shown' + EVENT_KEY,
14        CLICK: 'click' + EVENT_KEY,
15        READY: 'ready' + EVENT_KEY,
16        COLLAPSE: 'collapse' + EVENT_KEY,
17        LOAD_DATA_API: 'ready' + EVENT_KEY + DATA_API_KEY,
18        CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
19        RESIZE_DATA_API: 'resize' + EVENT_KEY + DATA_API_KEY,
20        KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY,
21        NAVBAR_COLLAPSE: 'collapse.bs.navbar-dropdown'
22    };
23
24    var Hotkeys = {
25        ESC: 27,
26        LEFT: 37,
27        UP: 38,
28        RIGHT: 39,
29        DOWN: 40
30    };
31
32    var Breakpoints = {
33        XS: 544,
34        SM: 768,
35        MD: 992,
36        LG: 1200,
37        XL: Infinity
38    };
39
40    var ClassName = {
41        BACKDROP: 'dropdown-backdrop',
42        DISABLED: 'disabled',
43        OPEN: 'open',
44        SM: 'nav-dropdown-sm'
45    };
46
47    var Selector = {
48        BASE: '.nav-dropdown',
49        DROPDOWN: '.dropdown',
50        DROPDOWN_MENU: '.dropdown-menu',
51        BACKDROP: '.' + ClassName.BACKDROP,
52        DATA_BUTTON: '[data-button]',
53        DATA_TOGGLE: '[data-toggle="dropdown-submenu"]',
54        FORM_CHILD: '.dropdown form'
55    };
56
57
58
59    var $$ = (function(){
60
61        function Item(elements, prevItem) {
62            if (!('length' in elements)) elements = [elements];
63            this.props = {};
64            this.length = elements.length;
65            if (prevItem) {
66                this.prevItem = prevItem;
67                $.extend(this.props, prevItem.props);
68            }
69            for (var i = 0; i < elements.length; i++) {
70                this[i] = elements[i];
71            }
72        }
73
74        Item.prototype.eq = function(index) {
75            return new Item(this[index] ? this[index] : [], this);
76        };
77
78        Item.prototype.parent = function() {
79            return new Item(
80                
81                $(this).map(function(){
82
83                    var $$this = new Item(this);
84
85                    if ($$this.is(':upper')) return null;
86
87                    return $( $$this.is(':toggle') ? this.parentNode.parentNode : this )
88                        .closest(Selector.DROPDOWN)
89                        .find('>' + Selector.DATA_TOGGLE)[0];
90
91                }),
92
93                this
94
95            );
96        };
97
98        Item.prototype.parents = function(selector) {
99            var elements = $(this).map(function(){
100
101                return (new Item(this)).is(':toggle') ? this.parentNode : this;
102
103            }).parentsUntil(Selector.BASE, Selector.DROPDOWN);
104
105            if (selector === ':upper') elements = elements.last();
106                
107            elements = elements.find('>' + Selector.DATA_TOGGLE);
108
109            return new Item(elements, this);
110        };
111
112        Item.prototype.children = function(deepSearch) {
113
114            var elements = [];
115
116            $(this).each(function(){
117
118                var $parent, $items, $$item = new Item(this);
119
120                if ($$item.is(':root')) {
121                    $parent = $(this);
122                } else if ($$item.is(':toggle')) {
123                    $parent = $(this).parent().find('>' + Selector.DROPDOWN_MENU);
124                } else {
125                    return;
126                }
127
128                if (deepSearch) {
129                    $items = $parent.find('a');
130                } else if ($$item.is(':root')) {
131                    $items = $parent.find('>li>a');
132                } else {
133                    $items = $parent.find('>a, >' + Selector.DROPDOWN + '>a');
134                }
135
136                $items.each(function(){
137
138                    if ((deepSearch && !this.offsetWidth && !this.offsetHeight)
139                        || this.disabled || $(this).is(Selector.DATA_BUTTON) || $(this).hasClass(ClassName.DISABLED) || ~$.inArray(this, elements)) {
140                        return;
141                    }
142
143                    elements.push(this);
144
145                });
146
147            });
148
149            return new Item(elements, this);
150
151        };
152
153        Item.prototype.root = function() {
154            return new Item(
155                $(this).closest(Selector.BASE),
156                this
157            );
158        };
159
160        Item.prototype.jump = function(step) {
161            step = step || 'next';
162            
163            if (!this.length) {
164                return new Item([], this);
165            }
166            
167            var children, $$item = this.eq(0);
168            if (this.is(':flat') || $$item.is(':upper')) {
169                children = $$item.root().children( this.is(':flat') );
170            } else {
171                children = $$item.parent().children();
172            }
173
174            var index = $.inArray(this[0], children);
175            if (!children.length || !~index) {
176                return new Item([], this);
177            }
178
179            if (step == 'next') {
180                index += 1;
181                if (index < children.length) {
182                    return new Item(children[index], this);
183                }
184                step = 'first';
185            } else if (step == 'prev') {
186                index -= 1;
187                if (index >= 0) {
188                    return new Item(children[index], this);
189                }
190                step = 'last';
191            }
192
193            if (step == 'first') return new Item(children[0], this);
194            if (step == 'last') return new Item(children[ children.length - 1 ], this);
195
196            return new Item([], this);
197        };
198
199        Item.prototype.next = function() {
200            return this.jump('next');
201        };
202
203        Item.prototype.prev = function() {
204            return this.jump('prev');
205        };
206
207        Item.prototype.first = function() {
208            return this.jump('first');
209        };
210
211        Item.prototype.last = function() {
212            return this.jump('last');
213        };
214
215        Item.prototype.prop = function(name, value) {
216            if (arguments.length) {
217                if (arguments.length > 1) {
218                    this.props[name] = value;
219                    return this;
220                }
221                if (typeof arguments[0] == 'object') {
222                    $.extend(this.props, arguments[0]);
223                    return this;
224                }
225                return (name in this.props) ?
226                    this.props[name] : null;
227            }
228            return $.extend({}, this.props);
229        };
230
231        Item.prototype.removeProp = function(name) {
232            delete this.props[name];
233            return this;
234        };
235
236        Item.prototype.is = function(selector) {
237            var $this = $(this),
238                selectors = (selector || '').split(/(?=[*#.\[:\s])/);
239            
240            while (selector = selectors.pop()){
241            
242                switch (selector){
243                
244                    case ':root':
245                        if (!$this.is(Selector.BASE))
246                            return false;
247                        break;
248
249                    case ':upper':
250                        if (!$this.parent().parent().is(Selector.BASE))
251                            return false;
252                        break;
253
254                    case ':opened':
255                    case ':closed':
256                        if ((selector == ':opened') != $this.parent().hasClass(ClassName.OPEN))
257                            return false;
258                    case ':toggle':
259                        if (!$this.is(Selector.DATA_TOGGLE))
260                            return false;
261                        break;
262
263                    default:
264                        if (!this.props[selector])
265                            return false;
266                        break;
267
268                }
269
270            }
271
272            return true;
273        };
274
275        Item.prototype.open = function() {
276            if (this.is(':closed')) {
277                this.click();
278            }
279            return this;
280        };
281
282        Item.prototype.close = function() {
283            if (this.is(':opened')) {
284                this.click();
285            }
286            return this;
287        };
288
289        Item.prototype.focus = function() {
290            if (this.length) {
291                this[0].focus();
292            }
293            return this;
294        };
295
296        Item.prototype.click = function() {
297            if (this.length) {
298                $(this[0]).trigger('click');
299            }
300            return this;
301        }
302
303        return function(element) {
304            return new Item(element);
305        };
306
307    })();
308
309
310
311    var NavDropdown = function(element){
312        this._element = element;
313        $(this._element).on(Event.CLICK, this.toggle);
314    };
315
316    NavDropdown.prototype.toggle = function(event) {        
317        if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
318            return false;
319        }
320
321        var $parent = $(this.parentNode);
322        var isActive = $parent.hasClass(ClassName.OPEN);
323        var isCollapsed = NavDropdown._isCollapsed( $(this).closest(Selector.BASE) );
324
325        NavDropdown._clearMenus(
326            $.Event('click', {
327                target: this,
328                data: {
329                    toggles: isCollapsed ? [this] : null
330                }
331            })
332        );
333
334        if (isActive) {
335            return false;
336        }
337
338        if ('ontouchstart' in document.documentElement
339            && !$parent.closest(Selector.DROPDOWN + '.' + ClassName.OPEN).length) {
340        
341            // if mobile we use a backdrop because click events don't delegate
342            var dropdown = document.createElement('div');
343            dropdown.className = ClassName.BACKDROP;
344            $(dropdown).insertBefore( $(this).closest(Selector.BASE) );
345            $(dropdown).on('click', NavDropdown._clearMenus);
346
347        }
348
349        var relatedTarget = { relatedTarget: this };
350        var showEvent = $.Event(Event.SHOW, relatedTarget);
351
352        $parent.trigger(showEvent);
353
354        if (showEvent.isDefaultPrevented()) {
355            return false;
356        }
357
358        this.focus();
359        this.setAttribute('aria-expanded', 'true');
360
361        $parent.toggleClass(ClassName.OPEN);
362        $parent.trigger( $.Event(Event.SHOWN, relatedTarget) );
363
364        return false;
365    };
366
367    NavDropdown.prototype.dispose = function() {
368        $.removeData(this._element, DATA_KEY);
369        $(this._element).off(EVENT_KEY);
370        this._element = null;
371    };
372
373    NavDropdown._clearMenus = function(event) {
374        event = event || {};
375
376        if (event.which === 3) {
377            return;
378        }
379
380        var collapseEvent;
381        var filter = function(){ return false; };
382
383        if (event.target) {
384
385            if (this === document) {
386
387                if ( $(event.target).is('a:not([disabled], .' + ClassName.DISABLED +  ')') ) {
388                    collapseEvent = $.Event(Event.COLLAPSE, { relatedTarget: event.target })
389                } else  {
390
391                    var $rootNode = (event.targetWrapper && $(event.targetWrapper).find(Selector.BASE)) || $(event.target).closest(Selector.BASE);
392
393                    if (NavDropdown._isCollapsed($rootNode)) return;
394                }
395
396            } else {
397
398                if ($(event.target).hasClass(ClassName.BACKDROP)) {
399                    var $nextNode = $(event.target).next();
400                    if ($nextNode.is(Selector.BASE) && NavDropdown._isCollapsed($nextNode)) {
401                        return;
402                    }
403                }
404
405            }
406
407            if ($(event.target).is(Selector.DATA_TOGGLE)) {
408                filter = $(event.target.parentNode).parents(Selector.DROPDOWN).find('>' + Selector.DATA_TOGGLE);
409            } else {
410                $(Selector.BACKDROP).remove();
411            }
412
413        }
414
415        var toggles = (event.data && event.data.toggles && $(event.data.toggles).parent().find(Selector.DATA_TOGGLE)) || $.makeArray( $(Selector.DATA_TOGGLE).not(filter) );
416
417        for (var i = 0; i < toggles.length; i++) {
418
419            var parent = toggles[i].parentNode;
420            var relatedTarget = { relatedTarget: toggles[i] };
421
422            if (!$(parent).hasClass(ClassName.OPEN)) {
423                continue;
424            }
425
426            if (event.type === 'click' &&
427                (/input|textarea/i.test(event.target.tagName)) &&
428                ($.contains(parent, event.target))) {
429                continue;
430            }
431
432            var hideEvent = $.Event(Event.HIDE, relatedTarget);
433            $(parent).trigger(hideEvent);
434            if (hideEvent.isDefaultPrevented()) {
435                continue;
436            }
437
438            toggles[i].setAttribute('aria-expanded', 'false');
439
440            $(parent)
441                .removeClass(ClassName.OPEN)
442                .trigger( $.Event(Event.HIDDEN, relatedTarget) );
443                
444        }
445
446        if (collapseEvent) {
447            $(document).trigger(collapseEvent);
448        }
449
450    };
451
452    // static
453    NavDropdown._dataApiKeydownHandler = function(event) {
454
455          if (/input|textarea/i.test(event.target.tagName)) {
456            return;
457          }
458
459          // ????
460          var found;
461          for (var k in Hotkeys) {
462            if (found = (Hotkeys[k] === event.which)) {
463                break;
464            }
465          }
466          if (!found) return;
467
468          event.preventDefault();
469          event.stopPropagation();
470
471          if (event.which == Hotkeys.ESC) {
472
473            if (NavDropdown._isCollapsed(this)) {
474                return;
475            }
476
477            var toggle = $(event.target).parents(Selector.DROPDOWN + '.' + ClassName.OPEN)
478                .last().find('>' + Selector.DATA_TOGGLE);
479            NavDropdown._clearMenus();
480            toggle.trigger('focus');
481            return;
482
483          }
484
485          if (event.target.tagName != 'A') {
486            return;
487          }
488
489          var $$item = $$(event.target);
490          
491          $$item.prop(':flat', NavDropdown._isCollapsed($$item.root()));
492
493          if ($$item.is(':flat')){
494
495            if (event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) {
496
497                $$item[ event.which === Hotkeys.UP ? 'prev' : 'next' ]().focus();
498
499            } else if (event.which === Hotkeys.LEFT) {
500                
501                if ($$item.is(':opened')) {
502                    $$item.close();
503                } else {
504                    $$item.parent().close().focus();
505                }
506
507            } else if (event.which === Hotkeys.RIGHT && $$item.is(':toggle')) {
508                $$item.open();
509            }
510
511          } else if ($$item.is(':upper')) {
512          
513              if (event.which === Hotkeys.LEFT || event.which === Hotkeys.RIGHT) {
514
515                $$item[event.which === Hotkeys.LEFT ? 'prev' : 'next']().focus().open();
516                if ($$item.is(':toggle')) $$item.close();
517
518              } else if ((event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) && $$item.is(':toggle')) {
519
520                $$item.children()[ event.which === Hotkeys.DOWN ? 'first' : 'last' ]().focus();
521
522              }
523
524          } else {
525
526              if (event.which === Hotkeys.LEFT) {
527
528                var $$parent = $$item.parent();
529                
530                if ($$parent.is(':upper')) {
531                    $$parent.close().prev().focus().open();
532                } else {
533                    $$parent.focus().close();
534                }
535
536              } else if (event.which === Hotkeys.RIGHT) {
537                
538                var $$children = $$item.children();
539                if ($$children.length) {
540                    $$item.open();
541                    $$children.first().focus();
542                } else {
543                    $$item.parents(':upper').close().next().focus().open();
544                }
545
546              } else if (event.which === Hotkeys.DOWN || event.which === Hotkeys.UP) {
547
548                $$item[ event.which === Hotkeys.UP ? 'prev' : 'next' ]().focus();
549
550              }
551
552          }
553          
554    };
555
556    // static
557    NavDropdown._isCollapsed = function(rootNode) {
558        var match;
559        if (rootNode.length) rootNode = rootNode[0];
560        return rootNode && (match = /navbar-toggleable-(xs|sm|md|lg|xl)/.exec(rootNode.className))
561            && (window.innerWidth < Breakpoints[ match[1].toUpperCase() ]);
562    };
563
564    // static
565    NavDropdown._dataApiResizeHandler = function() {
566
567        $(Selector.BASE).each(function(){
568            
569            var isCollapsed = NavDropdown._isCollapsed(this);
570            
571            $(this).find(Selector.DROPDOWN).removeClass(ClassName.OPEN);
572            $(this).find('[aria-expanded="true"]').attr('aria-expanded', 'false');
573
574            var backdrop = $(Selector.BACKDROP)[0];
575            if (backdrop) {
576                backdrop.parentNode.removeChild(backdrop); // ???
577            }
578
579            if (isCollapsed == $(this).hasClass(ClassName.SM)) {
580                return;
581            }
582
583            if (isCollapsed) {
584                $(this).addClass(ClassName.SM);
585            } else {
586                $(this).removeClass(ClassName.SM);
587
588                // $(this).removeClass(ClassName.SM + ' in'); /// ???
589                // NavDropdown._clearMenus();
590            }
591
592        });
593    };
594
595    /**
596     * ------------------------------------------------------------------------
597     * jQuery
598     * ------------------------------------------------------------------------
599     */
600
601    $.fn[NAME] = function(config) {
602        return this.each(function(){
603            
604            var data  = $(this).data(DATA_KEY);
605
606            if (!data) {
607                $(this).data(DATA_KEY, (data = new NavDropdown(this)));
608            }
609
610            if (typeof config === 'string') {
611                if (data[config] === undefined) {
612                    throw new Error('No method named "' + config + '"');
613                }
614                data[config].call(this);
615            }
616
617        });
618    };
619    $.fn[NAME].noConflict = function() {
620        $.fn[NAME] = JQUERY_NO_CONFLICT;
621        return this;
622    };
623    $.fn[NAME].Constructor = NavDropdown;
624    $.fn[NAME].$$ = $$;
625
626
627    $(window)
628        .on(Event.RESIZE_DATA_API + ' ' + Event.LOAD_DATA_API, NavDropdown._dataApiResizeHandler);
629
630    $(document)
631        .on(Event.KEYDOWN_DATA_API, Selector.BASE,  NavDropdown._dataApiKeydownHandler)
632        .on(Event.NAVBAR_COLLAPSE, NavDropdown._clearMenus)
633        .on(Event.CLICK_DATA_API, NavDropdown._clearMenus)
634        .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, NavDropdown.prototype.toggle)
635        .on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function(e){
636            e.stopPropagation();
637        });
638
639    $(window)
640       .trigger(Event.READY);
641
642
643})(jQuery);

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.