PageSourceSearch

https://carsonllp.com/wp-content/themes/carsonboxberger/assets/js/snappy/snappy.js

js carsonllp.com collected 2026-10-07 13:16:35 UTC 19,480 bytes, 767 lines download raw bytes

1/**
2 * Copyright (c) 2013-present, Guido Bouman
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8/* global jQuery */
9
10// Utility for creating objects in older browsers
11if (typeof Object.create !== 'function') {
12  Object.create = function (obj) {
13    function F() { }
14    F.prototype = obj;
15    return new F();
16  };
17}
18
19/*!
20 * jQuery panelSnap
21 * Version 0.15.1
22 *
23 * Requires:
24 * - jQuery 1.7 or higher (no jQuery.migrate needed)
25 *
26 * https://github.com/guidobouman/jquery-panelsnap
27 */
28(function ($, window, document) {
29  'use strict';
30
31  var pluginName = 'panelSnap';
32  var storageName = 'plugin_' + pluginName;
33
34  var pluginObject = {
35
36    isMouseDown: false,
37    isSnapping: false,
38    enabled: true,
39    scrollOffset: 0,
40
41    init: function (options, container) {
42      var self = this;
43
44      self.container = container;
45      self.$container = $(container);
46
47      self.$eventContainer = self.$container;
48      self.$snapContainer = self.$container;
49
50      if (self.$container.is('body')) {
51        self.$eventContainer = $(document);
52        self.$snapContainer = $(document.scrollingElement || document.documentElement);
53
54        var ua = navigator.userAgent;
55        if (ua.indexOf('WebKit') !== -1 && ua.indexOf('Chrome') === -1) {
56          self.$snapContainer = $('body');
57        }
58      }
59
60      self.options = $.extend(true, {}, $.fn.panelSnap.options, options);
61
62      self.bind();
63
64      if (self.options.$menu !== false && $('.active', self.options.$menu).length > 0) {
65        $('.active', self.options.$menu).click();
66      } else {
67        var $target = self.getPanel(':first');
68        self.activatePanel($target);
69      }
70
71      return self;
72    },
73
74    bind: function () {
75      var self = this;
76
77      self.bindProxied(self.$eventContainer, 'scrollstop', self.scrollStop);
78      self.bindProxied(self.$eventContainer, 'mousewheel', self.mouseWheel);
79      self.bindProxied(self.$eventContainer, 'mousedown', self.mouseDown);
80      self.bindProxied(self.$eventContainer, 'mouseup', self.mouseUp);
81
82      self.bindProxied($(window), 'resizestop', self.resize);
83
84      if (self.options.$menu) {
85        self.bindProxied(self.options.$menu, 'click', self.captureMenuClick, self.options.menuSelector);
86      }
87
88      if (self.options.navigation.keys.nextKey || self.options.navigation.keys.prevKey) {
89        self.bindProxied($(window), 'keydown', self.keyDown);
90      }
91
92      if (self.options.navigation.buttons.$nextButton) {
93        self.bindProxied(self.options.navigation.buttons.$nextButton, 'click', self.captureNextClick);
94      }
95
96      if (self.options.navigation.buttons.$prevButton) {
97        self.bindProxied(self.options.navigation.buttons.$prevButton, 'click', self.capturePrevClick);
98      }
99    },
100
101    bindProxied: function ($element, event, method, selector) {
102      var self = this;
103
104      selector = typeof selector === 'string' ? selector : null;
105
106      $element.on(event + self.options.namespace, selector, $.proxy(function (e) {
107        return method.call(self, e);
108      }, self));
109    },
110
111    destroy: function () {
112      var self = this;
113
114      // Gotta love namespaced events!
115      self.$eventContainer.off(self.options.namespace);
116
117      $(window).off(self.options.namespace);
118
119      if (self.options.$menu !== false) {
120        $(self.options.menuSelector, self.options.$menu).off(self.options.namespace);
121      }
122
123      self.$container.removeData(storageName);
124    },
125
126    scrollStop: function (e) {
127      var self = this;
128      var $target;
129
130      e.stopPropagation();
131
132      if (self.isMouseDown) {
133        return;
134      }
135
136      if (self.isSnapping) {
137        return;
138      }
139
140      // Check if enabled or just 1 panel in viewport
141      var panelsInViewPort = self.getPanelsInViewport();
142      if (!self.enabled || panelsInViewPort.length < 2) {
143        $target = panelsInViewPort.eq(0);
144        if (!$target.is(self.getPanel('.active'))) {
145          self.activatePanel($target);
146        }
147
148        return;
149      }
150
151      var offset = self.$snapContainer.scrollTop();
152      var scrollDifference = offset - self.scrollOffset;
153      var overThreshold = Math.abs(scrollDifference) > self.options.directionThreshold;
154
155      var panelNumber;
156      if (scrollDifference > 0) {
157        panelNumber = overThreshold ? 1 : 0;
158      } else if (scrollDifference < 0) {
159        panelNumber = overThreshold ? 0 : 1;
160      } else {
161        // Nothing to scroll, get out.
162        return;
163      }
164
165      $target = panelsInViewPort.eq(panelNumber);
166
167      var maxOffset = self.$container[0].scrollHeight - self.scrollInterval;
168      if (offset <= 0 || offset >= maxOffset) {
169        // Only activate, prevent stuttering
170        self.activatePanel($target);
171        // Set scrollOffset to a sane number for next scroll
172        self.scrollOffset = offset <= 0 ? 0 : maxOffset;
173      } else {
174        self.snapToPanel($target);
175      }
176    },
177
178    getPanelsInViewport: function () {
179      var self = this;
180
181      var viewport = { top: self.$snapContainer.scrollTop() };
182      viewport.bottom = viewport.top + self.$snapContainer.height();
183
184      var panels = self.getPanel().filter(function (_, el) {
185        var $el = $(el);
186        var bounds;
187
188        if (self.$container.is('body')) {
189          bounds = $el.offset();
190        } else {
191          bounds = $el.position();
192          bounds.top += self.$snapContainer.scrollTop();
193        }
194
195        bounds.bottom = bounds.top + $el.outerHeight();
196
197        return !(viewport.bottom < bounds.top || viewport.top > bounds.bottom);
198      });
199
200      return panels;
201    },
202
203    mouseWheel: function () {
204      var self = this;
205
206      // This event only fires when the user actually scrolls with their input device.
207      // Be it a trackpad, legacy mouse or anything else.
208
209      if (self.isSnapping) {
210        self.scrollOffset = self.$snapContainer.scrollTop();
211        self.$snapContainer.stop(true);
212        self.isSnapping = false;
213      }
214    },
215
216    mouseDown: function () {
217      var self = this;
218
219      self.isMouseDown = true;
220    },
221
222    mouseUp: function (e) {
223      var self = this;
224
225      self.isMouseDown = false;
226
227      if (self.scrollOffset !== self.$snapContainer.scrollTop()) {
228        self.scrollStop(e);
229      }
230    },
231
232    keyDown: function (e) {
233      var self = this;
234
235      var nav = self.options.navigation;
236
237      if (!self.enabled) {
238        return;
239      }
240
241      switch (e.which) {
242        case nav.keys.prevKey:
243        case nav.keys.nextKey:
244          e.preventDefault();
245          break;
246
247        // no default
248      }
249
250      if (self.isSnapping) {
251        return;
252      }
253
254      switch (e.which) {
255        case nav.keys.prevKey:
256          self.snapTo('prev', nav.wrapAround);
257          break;
258
259        case nav.keys.nextKey:
260          self.snapTo('next', nav.wrapAround);
261          break;
262
263        // no default
264      }
265    },
266
267    captureNextClick: function (e) {
268      var self = this;
269
270      e.preventDefault();
271
272      if (self.isSnapping) {
273        return;
274      }
275
276      self.snapTo('next', self.options.navigation.wrapAround);
277    },
278
279    capturePrevClick: function (e) {
280      var self = this;
281
282      e.preventDefault();
283
284      if (self.isSnapping) {
285        return;
286      }
287
288      self.snapTo('prev', self.options.navigation.wrapAround);
289    },
290
291    resize: function () {
292      var self = this;
293
294      if (!self.enabled) {
295        return;
296      }
297
298      var $target = self.getPanel('.active');
299
300      self.snapToPanel($target);
301    },
302
303    captureMenuClick: function (e) {
304      var self = this;
305
306      var panel = $(e.currentTarget).data('panel');
307      var $target = self.getPanel('[data-panel="' + panel + '"]');
308
309      self.snapToPanel($target);
310
311      return false;
312    },
313
314    snapToPanel: function ($target) {
315      var self = this;
316
317      if (!$target.jquery) {
318        return;
319      }
320
321      self.isSnapping = true;
322
323      self.options.onSnapStart.call(self, $target);
324      self.$container.trigger('panelsnap:start', [$target]);
325
326      var scrollTarget = 0;
327      if (self.$container.is('body')) {
328        scrollTarget = $target.offset().top;
329      } else {
330        scrollTarget = self.$snapContainer.scrollTop() + $target.position().top;
331      }
332
333      scrollTarget -= self.options.offset;
334
335      var isScrollingUp = self.scrollOffset > scrollTarget;
336      var isLargeTarget = $target.outerHeight() > self.$snapContainer.outerHeight();
337      if (isScrollingUp && isLargeTarget) {
338        // Snap to bottom of target
339        scrollTarget += $target.outerHeight();
340        scrollTarget -= self.$snapContainer.outerHeight();
341      }
342
343      self.$snapContainer.stop(true).delay(self.options.delay).animate({
344        scrollTop: scrollTarget
345      }, self.options.slideSpeed, self.options.easing, function () {
346        // Set scrollOffset to scrollTop
347        // (not to scrollTarget since on iPad those sometimes differ)
348        self.scrollOffset = self.$snapContainer.scrollTop();
349        self.isSnapping = false;
350
351        // Call callback
352        self.options.onSnapFinish.call(self, $target);
353        self.$container.trigger('panelsnap:finish', [$target]);
354
355        self.activatePanel($target);
356      });
357    },
358
359    activatePanel: function ($target) {
360      var self = this;
361
362      self.getPanel('.active').removeClass('active');
363      $target.addClass('active');
364
365      if (self.options.$menu !== false) {
366        var activeItemSelector = self.options.menuSelector + '.active';
367        $(activeItemSelector, self.options.$menu).removeClass('active');
368
369        var attribute = '[data-panel="' + $target.data('panel') + '"]';
370        var itemSelector = self.options.menuSelector + attribute;
371        var $itemToActivate = $(itemSelector, self.options.$menu);
372        $itemToActivate.addClass('active');
373      }
374
375      var nav = self.options.navigation;
376
377      if (!nav.wrapAround) {
378        var $panels = self.getPanel();
379        var index = $panels.index(self.getPanel('.active'));
380
381        if (nav.buttons.$nextButton !== false) {
382          $target = $panels.eq(index + 1);
383          if ($target.length < 1) {
384            $(nav.buttons.$nextButton).attr('aria-disabled', 'true');
385            $(nav.buttons.$nextButton).addClass('disabled');
386          } else {
387            $(nav.buttons.$nextButton).attr('aria-disabled', 'false');
388            $(nav.buttons.$nextButton).removeClass('disabled');
389          }
390        }
391
392        if (nav.buttons.$prevButton !== false) {
393          if (index < 1) {
394            $(nav.buttons.$prevButton).attr('aria-disabled', 'true');
395            $(nav.buttons.$prevButton).addClass('disabled');
396          } else {
397            $(nav.buttons.$prevButton).attr('aria-disabled', 'false');
398            $(nav.buttons.$prevButton).removeClass('disabled');
399          }
400        }
401      }
402
403      self.options.onActivate.call(self, $target);
404      self.$container.trigger('panelsnap:activate', [$target]);
405    },
406
407    getPanel: function (selector) {
408      var self = this;
409
410      if (typeof selector === 'undefined') {
411        selector = '';
412      }
413
414      return $(self.options.panelSelector + selector, self.$container);
415    },
416
417    snapTo: function (target, wrap) {
418      var self = this;
419
420      if (typeof wrap !== 'boolean') {
421        wrap = true;
422      }
423
424      var $panels = self.getPanel();
425      var index = $panels.index(self.getPanel('.active'));
426      var $target;
427
428      switch (target) {
429        case 'prev':
430          $target = $panels.eq(index - 1);
431          if (index < 1 && !wrap) {
432            $target = []; // Clear target, because negative indexes wrap automatically
433          }
434          break;
435
436        case 'next':
437          $target = $panels.eq(index + 1);
438          if ($target.length < 1 && wrap) {
439            $target = $panels.filter(':first');
440          }
441          break;
442
443        case 'first':
444          $target = $panels.filter(':first');
445          break;
446
447        case 'last':
448          $target = $panels.filter(':last');
449          break;
450
451        // no default
452      }
453
454      if ($target.length > 0) {
455        self.snapToPanel($target);
456      }
457    },
458
459    enable: function () {
460      var self = this;
461
462      // Gather scrollOffset for next scroll
463      self.scrollOffset = self.$snapContainer.scrollTop();
464
465      self.enabled = true;
466    },
467
468    disable: function () {
469      var self = this;
470
471      self.enabled = false;
472    },
473
474    toggle: function () {
475      var self = this;
476
477      if (self.enabled) {
478        self.disable();
479      } else {
480        self.enable();
481      }
482    }
483
484  };
485
486  $.fn[pluginName] = function (options) {
487    var args = Array.prototype.slice.call(arguments);
488
489    return this.each(function () {
490      var pluginInstance = $.data(this, storageName);
491      if (typeof options === 'object' || options === 'init' || !options) {
492        if (!pluginInstance) {
493          if (options === 'init') {
494            options = args[1] || {};
495          }
496
497          pluginInstance = Object.create(pluginObject).init(options, this);
498          $.data(this, storageName, pluginInstance);
499        } else {
500          $.error('Plugin is already initialized for this object.');
501        }
502      } else if (!pluginInstance) {
503        $.error('Plugin is not initialized for this object yet.');
504      } else if (pluginInstance[options]) {
505        var method = options;
506        options = args.slice(1);
507        pluginInstance[method].apply(pluginInstance, options);
508      } else {
509        $.error('Method ' + options + ' does not exist on jQuery.panelSnap.');
510      }
511    });
512  };
513
514  $.fn[pluginName].options = {
515    $menu: false,
516    menuSelector: 'a',
517    panelSelector: '> section',
518    namespace: '.panelSnap',
519    onSnapStart: function () { },
520    onSnapFinish: function () { },
521    onActivate: function () { },
522    directionThreshold: 50,
523    slideSpeed: 200,
524    delay: 0,
525    easing: 'linear',
526    offset: 0,
527    navigation: {
528      keys: {
529        nextKey: false,
530        prevKey: false
531      },
532      buttons: {
533        $nextButton: false,
534        $prevButton: false
535      },
536      wrapAround: false
537    }
538  };
539}(jQuery, window, document));
540
541/*!
542 * Special flavoured jQuery Mobile scrollstart & scrollstop events.
543 * Version 0.1.3
544 *
545 * Requires:
546 * - jQuery 1.7.1 or higher (no jQuery.migrate needed)
547 */
548(function ($) {
549  // Also handles the scrollstop event
550  $.event.special.scrollstart = {
551
552    enabled: true,
553
554    setup: function () {
555      var thisObject = this;
556      var $this = $(thisObject);
557      var timer;
558      var isTouching;
559
560      $this.data('scrollwatch', true);
561
562      function trigger(event, scrolling) {
563        event.type = scrolling ? 'scrollstart' : 'scrollstop';
564        $this.trigger(event);
565      }
566
567      $this.on('touchstart', function () {
568        isTouching = true;
569      });
570
571      $this.on('touchleave touchcancel touchend', function () {
572        isTouching = false;
573        setTimeout(function () {
574          clearTimeout(timer);
575        }, 50);
576      });
577
578      $this.on('touchmove scroll', function (event) {
579        if (isTouching) {
580          return;
581        }
582
583        if (!$.event.special.scrollstart.enabled) {
584          return;
585        }
586
587        if (!$.event.special.scrollstart.scrolling) {
588          $.event.special.scrollstart.scrolling = true;
589          trigger(event, true);
590        }
591
592        clearTimeout(timer);
593        timer = setTimeout(function () {
594          $.event.special.scrollstart.scrolling = false;
595          trigger(event, false);
596        }, 50);
597      });
598    }
599
600  };
601
602  // Proxies scrollstart when needed
603  $.event.special.scrollstop = {
604
605    setup: function () {
606      var thisObject = this;
607      var $this = $(thisObject);
608
609      if (!$this.data('scrollwatch')) {
610        $(this).on('scrollstart', function () { });
611      }
612    }
613
614  };
615}(jQuery));
616
617/*!
618 * Resizestart and resizestop events.
619 * Version 0.0.1
620 *
621 * Requires:
622 * - jQuery 1.7.1 or higher (no jQuery.migrate needed)
623 */
624(function ($) {
625  // Also handles the resizestop event
626  $.event.special.resizestart = {
627
628    enabled: true,
629
630    setup: function () {
631      var thisObject = this;
632      var $this = $(thisObject);
633      var timer;
634
635      $this.data('resizewatch', true);
636
637      function trigger(event, resizing) {
638        event.type = resizing ? 'resizestart' : 'resizestop';
639        $this.trigger(event);
640      }
641
642      $this.on('resize', function (event) {
643        if (!$.event.special.resizestart.enabled) {
644          return;
645        }
646
647        if (!$.event.special.resizestart.resizing) {
648          $.event.special.resizestart.resizing = true;
649          trigger(event, true);
650        }
651
652        clearTimeout(timer);
653        timer = setTimeout(function () {
654          $.event.special.resizestart.resizing = false;
655          trigger(event, false);
656        }, 200);
657      });
658    }
659
660  };
661
662  // Proxies resizestart when needed
663  $.event.special.resizestop = {
664
665    setup: function () {
666      var thisObject = this;
667      var $this = $(thisObject);
668
669      if (!$this.data('resizewatch')) {
670        $(this).on('resizestart', function () { });
671      }
672    }
673
674  };
675}(jQuery));
676
677/* eslint-disable */
678
679/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
680 * Licensed under the MIT License (LICENSE.txt).
681 *
682 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
683 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
684 * Thanks to: Seamus Leahy for adding deltaX and deltaY
685 *
686 * Version: 3.0.6
687 *
688 * Requires: 1.2.2+
689 */
690(function ($) {
691
692  var types = ['DOMMouseScroll', 'mousewheel'];
693
694  if ($.event.fixHooks) {
695    for (var i = types.length; i;) {
696      $.event.fixHooks[types[--i]] = $.event.mouseHooks;
697    }
698  }
699
700  $.event.special.mousewheel = {
701    setup: function () {
702      if (this.addEventListener) {
703        for (var i = types.length; i;) {
704          this.addEventListener(types[--i], handler, false);
705        }
706      } else {
707        this.onmousewheel = handler;
708      }
709    },
710
711    teardown: function () {
712      if (this.removeEventListener) {
713        for (var i = types.length; i;) {
714          this.removeEventListener(types[--i], handler, false);
715        }
716      } else {
717        this.onmousewheel = null;
718      }
719    }
720  };
721
722  $.fn.extend({
723    mousewheel: function (fn) {
724      return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
725    },
726
727    unmousewheel: function (fn) {
728      return this.unbind('mousewheel', fn);
729    }
730  });
731
732  function handler(event) {
733    var orgEvent = event || window.event,
734      args = [].slice.call(arguments, 1),
735      delta = 0,
736      returnValue = true,
737      deltaX = 0,
738      deltaY = 0;
739
740    event = $.event.fix(orgEvent);
741    event.type = 'mousewheel';
742
743    // Old school scrollwheel delta
744    if (orgEvent.wheelDelta) { delta = orgEvent.wheelDelta / 120; }
745    if (orgEvent.detail) { delta = -orgEvent.detail / 3; }
746
747    // New school multidimensional scroll (touchpads) deltas
748    deltaY = delta;
749
750    // Gecko
751    if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
752      deltaY = 0;
753      deltaX = -1 * delta;
754    }
755
756    // Webkit
757    if (orgEvent.wheelDeltaY !== undefined) { deltaY = orgEvent.wheelDeltaY / 120; }
758    if (orgEvent.wheelDeltaX !== undefined) { deltaX = -1 * orgEvent.wheelDeltaX / 120; }
759
760    // Add event and delta to the front of the arguments
761    args.unshift(event, delta, deltaX, deltaY);
762
763    return ($.event.dispatch || $.event.handle).apply(this, args);
764  }
765
766})(jQuery);
767/* eslint-enable */

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.