PageSourceSearch

https://www.slumberworldhawaii.com/js/libs/fdn-toggle.js

js slumberworldhawaii.com collected 2026-10-04 12:51:29 UTC 21,058 bytes, 624 lines download raw bytes

1/**
2* Toggle
3* ======
4*
5* An object representing a pair of html elements, className + "-trigger" and
6* className + "-target".  When activated through a specified event, an "--active"
7* class is added and can be styled to dynamically show the target content.
8* The "--active" modifier class is added to both trigger and target elements.
9*
10*
11* @param {jQuery Object} trigger (required) - element that serves as the
12*        activator for adding and removing the "--active" modifier class
13*
14* @param {jQuery Object} target (required) - element that is associated with
15*        the trigger element and also receives the "--active" modifier class
16*        when activated
17*
18* @param {string} relatives (optional) - comma delimited list of HTML element
19*        selectors that specify which elements are related to the toggle and
20*        should not close the related toggle when clicked.
21*
22* @param {boolean} useHover (optional) - specifies whether or not hovering
23*        the trigger will cause the target to be displayed.  Touch only
24*        devices ignore this.
25*        default: false
26*
27* @param {String} useHoverMq (optional) - hover will only work when the
28*        specified media query is true, receives "--disabled" class
29*        default: false
30*
31* @param {String} toggleMq (optional) - toggle will only work when the
32*        specified media query is true, receives "--disabled" class
33*        default: false
34*
35* @param {String} className (optional) - sets the prefix class
36*        default: "fdn-toggle"
37*
38* @param {String} useHoverIntent (optional) - uses hover intent library for
39*        hover states (still needs built)
40*        default: false
41*
42* @param {String} persist (optional) - when true, prevents toggles of the same
43*        className from closing when another is activated
44*        default: false
45*
46**/
47
48
49// Public toggle array - stores instantiated Toggle objects
50var ToggleArray = [];
51
52
53(function () {
54
55
56    // Class definition / constructor
57    function Toggle(trigger, target, relatives, useHover, useHoverMq, toggleMq, className, useHoverIntent, persist) {
58
59
60        // check for jQuery library
61        if (!window.jQuery) {
62            throw 'Failed to create Toggle object.  This object requires the jQuery library.';
63        }
64
65        // check for Modernizr library
66        if (!window.Modernizr) {
67            throw 'Failed to create Toggle object.  This object requires the Modernizr library.';
68        }
69
70
71        /*==========  Arguments  ==========*/
72
73        // trigger
74        if (typeof trigger === 'undefined') {
75            throw 'Failed to create Toggle object.  The supplied argument "trigger" is undefined.';
76        }
77
78        if (!trigger instanceof jQuery) {
79            throw 'Failed to create Toggle object.  The supplied argument "trigger" must be a jQuery object.';
80        }
81
82        this.trigger = trigger;
83        this.trigger.addClass(className + '-trigger');
84        this.trigger.attr('aria-expanded', false);
85
86
87        // target
88        if (typeof target === 'undefined') {
89            throw 'Failed to create Toggle object.  The supplied argument "target" is undefined.';
90        }
91
92        if (!target instanceof jQuery) {
93            throw 'Failed to create Toggle object.  The supplied argument "target" must be a jQuery object.';
94        }
95
96        this.target = target;
97        this.target.addClass(className + '-target');
98
99        // relatives
100        this.relatives = relatives;
101
102
103        // useHover
104        if (typeof useHover === 'undefined') {
105            this.useHover = false;
106        }
107
108        if (typeof useHover !== 'boolean') {
109            throw 'Failed to create Toggle object.  The supplied argument "useHover" must be of type boolean.';
110        }
111
112        this.useHover = useHover;
113
114
115        // useHoverMq
116        if (typeof useHoverMq === 'undefined') {
117            this.useHoverMq = false;
118        }
119
120        if (typeof useHoverMq !== 'string') {
121            throw 'Failed to create Toggle object.  The supplied argument "useHoverMq" must be of type string.';
122        }
123
124        this.useHoverMq = useHoverMq.toLowerCase();
125
126
127        // toggle media query
128        if (typeof toggleMq === 'undefined') {
129            this.toggleMq = false;
130        }
131
132        if (typeof toggleMq !== 'string') {
133            throw 'Failed to create Toggle object.  The supplied argument "toggleMq" must be of type string.';
134        }
135
136        this.toggleMq = toggleMq.toLowerCase();
137
138
139        // class name
140        this.className = typeof className === "undefined" || className.length === 0 ? "fdn-toggle" : className;
141
142
143        // hover intent
144        if (typeof useHoverIntent === 'undefined') {
145            this.useHoverIntent = false;
146        }
147
148        if (typeof useHoverIntent !== 'boolean') {
149            throw 'Failed to create Toggle object.  The supplied argument "useHoverIntent" must be of type boolean.';
150        }
151
152        this.useHoverIntent = useHoverIntent;
153        this.persist = persist;
154
155        if (this.persist) {
156            this.trigger.addClass(this.className + "-trigger--persist");
157            this.target.addClass(this.className + "-target--persist");
158        }
159
160        // private variables
161        var isDisabled = false;
162        var preventHover = false;
163
164
165        // disable text selection in IE10 on touch devices
166        this.trigger.on('selectstart', function (e) { e.preventDefault(); }, false);
167
168
169        // setup toggle media query
170        if (this.toggleMq.length > 0) {
171
172            // check for enquire library
173            if (!window.enquire) {
174                throw 'Failed to create Toggle object.  This object requires the Enquire.js library.';
175            }
176
177            this.setUpToggleMq();
178
179        }
180
181        // setup useHover media query
182        if (this.useHoverMq.length > 0) {
183
184            // check for enquire library
185            if (!window.enquire) {
186                throw 'Failed to create Toggle object.  This object requires the Enquire.js library.';
187            }
188
189            this.setUpUseHoverMq();
190
191        }
192
193        // setup relatives, prevent closing of toggle when relative is clicked
194        if (this.relatives.length > 0) {
195            this.bindRelatives();
196        }
197
198        this.bind();
199
200    }
201
202
203    // Instance methods
204
205    Toggle.prototype = {
206
207        constructor: Toggle,
208
209        disable : function () {
210            this.trigger.addClass(this.className + '-trigger--disabled').removeClass(this.className + '-trigger--active').removeClass(this.className + '-trigger--enabled');
211            this.target.addClass(this.className + '-target--disabled').removeClass(this.className + '-target--active').removeClass(this.className + '-target--enabled');
212            this.isDisabled = true;
213        },
214
215        enable : function () {
216            this.trigger.removeClass(this.className + '-trigger--disabled').addClass(this.className + '-trigger--enabled');
217            this.target.removeClass(this.className + '-target--disabled').addClass(this.className + '-target--enabled');
218            this.isDisabled = false;
219        },
220
221        setUpToggleMq : function () {
222
223            var toggle = this;
224
225            enquire.register(toggle.toggleMq, {
226
227                deferSetup : false,
228                setup: function () { toggle.disable(); },
229                match : function () { toggle.enable(); },
230                unmatch : function () { toggle.disable(); }
231
232            });
233
234        },
235
236        setUpUseHoverMq : function () {
237
238            var toggle = this;
239
240            enquire.register(toggle.useHoverMq, {
241
242                deferSetup : false,
243                setup: function () { toggle.preventHover = true; },
244                match : function () { toggle.preventHover = false; },
245                unmatch : function () { toggle.preventHover = true; }
246
247            });
248
249        },
250
251        slideToggleTarget : function (action) {
252
253            var toHeight;
254
255            if (typeof action === 'undefined') {
256
257                if (this.target.hasClass(this.className + '-target--active')) {
258
259                    this.target.css('max-height', '0');
260                    this.target.attr('aria-expanded', false);
261
262                } else {
263
264                    toHeight = this.target.children().outerHeight(true);
265                    this.target.attr('aria-expanded', true);
266                    this.target.css('max-height', toHeight);
267
268                }
269
270                this.target.toggleClass(this.className + '-target--active');
271
272            } else if (action === "open" && !this.target.hasClass(this.className + '-target--active')) {
273
274                toHeight = this.target.children().outerHeight(true);
275                this.target.attr('aria-expanded', true);
276                this.target.css('max-height', toHeight);
277
278                this.target.addClass(this.className + '-target--active');
279
280            } else if (action === "close" && this.target.hasClass(this.className + '-target--active')) {
281
282                this.target.css('max-height', '0');
283                this.target.attr('aria-expanded', false);
284                this.target.removeClass(this.className + '-target--active');
285
286            }
287        },
288
289        defaultToggleTarget : function (action) {
290
291            if (typeof action === 'undefined') {
292
293                // recursively uses this method to toggle classes
294                if (this.trigger.hasClass(this.className + '-trigger--active')) {
295                    this.target.attr('aria-expanded', false);
296                    this.defaultToggleTarget('close');
297                } else {
298                    this.target.attr('aria-expanded', true);
299                    this.defaultToggleTarget('open');
300                }
301
302            } else if (action === 'open') {
303
304                // remove active class from triggers not in the current toggle tree
305                $("." + this.className + "-trigger--active")
306                    .not(this.trigger.parents("." + this.className + "-target"))
307                    .not(this.trigger.parents("." + this.className + "-target").siblings("." + this.className + "-trigger"))
308                    .not("." + this.className + "-trigger--persist")
309                    .removeClass(this.className + "-trigger--active");
310
311                // remove active class from parent targets not in the current toggle tree
312                $("." + this.className + "-target--active-parent")
313                    .not(this.trigger.parents())
314                    .not("." + this.className + "-target--persist")
315                    .removeClass(this.className + "-target--active-parent");
316
317                // remove active class from targets not in the current toggle tree
318                $("." + this.className + "-target--active")
319                    .not(this.trigger.parents())
320                    .not("." + this.className + "-target--persist")
321                    .removeClass(this.className + "-target--active");
322
323                // add active classes to trigger and parent target of trigger
324                this.trigger
325                    .addClass(this.className + '-trigger--active')
326                    .closest("." + this.className + "-target")
327                    .addClass(this.className + "-target--active-parent");
328
329                // add active classes to targets
330                this.target.addClass(this.className + '-target--active');
331
332                this.target.attr('aria-expanded', true);
333
334            } else if (action === "close") {
335
336                // remove active classes from toggles
337
338                this.trigger
339                    .removeClass(this.className + "-trigger--active")
340                    .closest("." + this.className + "-target--active-parent")
341                    .removeClass(this.className + "-target--active-parent");
342
343                this.target
344                    .removeClass(this.className + "-target--active-parent " + this.className + "-target--active")
345                    .find("." + this.className + "-trigger--active")
346                    .removeClass(this.className + "-trigger--active")
347                    .find("." + this.className + "-target--active")
348                    .removeClass(this.className + "-target--active")
349                    .find("." + this.className + "-target--active-parent")
350                    .removeClass(this.className + "-target--active-parent")
351                    .off("vclick");
352
353                this.target.attr('aria-expanded', false);
354            }
355        },
356
357        toggleTarget : function (action) {
358
359            if (!this.isDisabled) {
360
361                switch (this.animation) {
362
363                    case "slide":
364
365                        this.slideToggleTarget(action);
366                        break;
367
368                    case "none":
369                    default:
370                        this.defaultToggleTarget(action);
371                        break;
372
373                }
374
375            }
376        },
377
378        bind : function () {
379
380            var toggle = this,
381                isHoveringTarget = false,
382                userIsHovering = false,
383                touchStart = false;
384
385            if (this.useHoverIntent) {
386
387                this.trigger.parent().hoverIntent({
388                    over: function () {
389                        if (!toggle.preventHover && !toggle.isDisabled) {
390                            toggle.toggleTarget("open");
391                        }
392                    },
393                    out: function () {
394                        if (!toggle.preventHover && !toggle.isDisabled) {
395                            toggle.toggleTarget("close");
396                        }
397                    }
398                });
399
400            } else if (this.useHover) {
401
402                this.trigger.on("vclick", function (event) {
403
404                    event.stopPropagation();
405                    if (!userIsHovering) {
406
407                        touchStart = true;
408
409                        setTimeout(function () {
410                            touchStart = false;
411                        }, 2000);
412
413                        event.preventDefault();
414
415                        if (!toggle.isDisabled) toggle.toggleTarget();
416
417                        // prevent toggle from closing when target is clicked
418                        toggle.target.on("vclick", function (event) {
419                            event.stopPropagation();
420                        });
421                    }
422                }).on(mouseenterEvent, function () {
423
424                    setTimeout(function () {
425                        if (!toggle.preventHover && !toggle.isDisabled && !touchStart) {
426
427                            userIsHovering = true;
428
429                            setTimeout(function () {
430                                userIsHovering = false;
431                            }, 2000);
432
433                            toggle.toggleTarget("open");
434                        }
435
436                    }, 100);
437
438                }).on(mouseleaveEvent, function () {
439
440                    setTimeout(function () {
441
442                        if (!toggle.preventHover && !isHoveringTarget && !touchStart) {
443
444                            userIsHovering = true;
445
446                            setTimeout(function () {
447                                userIsHovering = false;
448                            }, 2000);
449
450                            toggle.toggleTarget("close");
451                        }
452
453                    }, 150);
454
455                });
456
457                this.target.on(mouseenterEvent, function () {
458
459                    isHoveringTarget = true;
460
461                }).on(mouseleaveEvent, function () {
462
463                    setTimeout(function () {
464
465                        if (!toggle.preventHover && !touchStart) {
466
467                            toggle.toggleTarget("close");
468                            isHoveringTarget = false;
469                        }
470
471                    }, 100);
472
473                });
474
475            }
476
477            this.trigger.on("vclick", function (event) {
478
479                event.stopPropagation();
480
481                if (!userIsHovering && !touchStart) {
482
483                    event.preventDefault();
484
485                    if (!toggle.isDisabled) toggle.toggleTarget();
486
487                    // prevent toggle from closing when target is clicked
488                    toggle.target.on("vclick", function (event) {
489                        event.stopPropagation();
490                    });
491
492                }
493
494            });
495
496        },
497
498        bindRelatives : function () {
499
500            this.relatives.split(",").forEach(function (e) {
501
502                $(e).on("vclick", function (event) {
503                    event.stopPropagation();
504                });
505
506            });
507
508        }
509
510    };
511
512
513
514    /*================================================
515    =            FDN Toggle jQuery Plugin            =
516    ================================================*/
517
518    // TODO small optimization - target and trigger could be passed as strings to Toggle constructor (rather than jQuery objects)
519
520    (function ($) {
521
522        "use strict";
523
524        $.fn.fdnToggle = function (userOptions) {
525
526            return this.each(function () {
527
528                var trigger = $(this),
529                    options = $.extend({
530
531                        triggers: "",
532                        targets: "",
533                        relatives: "",
534                        useHover: false,
535                        useHoverMq: "",
536                        toggleMq: "",
537                        className: "",
538                        useHoverIntent: false,
539                        persist: false,
540                        closeOnClick: true
541
542                    }, userOptions);
543
544                // remove toggle active classes on click/touch of non-toggle area
545                if (options.closeOnClick) {
546
547                    $("body").on("vclick", function (event) {
548
549                        event.stopPropagation();
550
551                        $("." + options.className + "-target--active-parent").removeClass(options.className + "-target--active-parent");
552                        $("." + options.className + "-trigger--active").removeClass(options.className + "-trigger--active");
553                        $("." + options.className + "-target--active").removeClass(options.className + "-target--active");
554
555                    });
556
557                }
558
559                // if more triggers are defined then add them to the trigger object
560                if (options.triggers.length > 0) {
561
562                    // triggers should be separated by commas, split into array,
563                    // loop through triggers from data-toggle-trigger attribute,
564                    // add additional triggers to trigger object
565                    options.triggers.split(',').forEach(
566                        function(t) { trigger = trigger.add($(t));
567                    });
568
569                }
570
571                // declare and define toggle targets
572                var target;
573
574                // split target string into array, loop through and
575                // add each as jquery object
576                if (options.targets.length > 0) {
577
578                    options.targets.split(',').forEach(
579                        function(t){ target = $(target).add($(t));
580                    });
581
582                } else {
583                    if (trigger.first().next().length > 0) {
584                        target = trigger.first().next()
585                    } else {
586                        // no target found, cease creating toggle
587                        if (Utils.IsDev) {
588                            console.warn("FDN Toggle could not be created for " + trigger[0].outerHTML + ".  Could not locate toggle target.");
589                        }
590                        return;
591                    }
592                }
593
594                // create new Toggle object
595                try {
596
597                    ToggleArray.push(new Toggle(
598                        trigger,
599                        target,
600                        options.relatives,
601                        options.useHover,
602                        options.useHoverMq,
603                        options.toggleMq,
604                        options.className,
605                        options.useHoverIntent,
606                        options.persist
607                    ));
608
609                } catch (err) {
610
611                    console.error(err);
612
613                }
614
615            });
616
617        };
617
618
619    }(jQuery));
620    
621    /*-----  End of FDN Toggle jQuery Plugin  ------*/
622
623
624}());

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.