PageSourceSearch

https://demo.hashthemes.com/super-woocommerce-product-filter/wp-content/themes/total/js/headroom.js?ver=2.2.5

js hashthemes.com collected 2026-09-24 08:38:15 UTC 14,398 bytes, 511 lines download raw bytes

1/*!
2 * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it
3 * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js
4 * License: MIT
5 */
6
7(function(root, factory) {
8  'use strict';
9
10  if (typeof define === 'function' && define.amd) {
11    // AMD. Register as an anonymous module.
12    define([], factory);
13  }
14  else if (typeof exports === 'object') {
15    // COMMONJS
16    module.exports = factory();
17  }
18  else {
19    // BROWSER
20    root.Headroom = factory();
21  }
22}(this, function() {
23  'use strict';
24
25  /* exported features */
26  
27  var features = {
28    bind : !!(function(){}.bind),
29    classList : 'classList' in document.documentElement,
30    rAF : !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame)
31  };
32  window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
33  
34  /**
35   * Handles debouncing of events via requestAnimationFrame
36   * @see http://www.html5rocks.com/en/tutorials/speed/animations/
37   * @param {Function} callback The callback to handle whichever event
38   */
39  function Debouncer (callback) {
40    this.callback = callback;
41    this.ticking = false;
42  }
43  Debouncer.prototype = {
44    constructor : Debouncer,
45  
46    /**
47     * dispatches the event to the supplied callback
48     * @private
49     */
50    update : function() {
51      this.callback && this.callback();
52      this.ticking = false;
53    },
54  
55    /**
56     * ensures events don't get stacked
57     * @private
58     */
59    requestTick : function() {
60      if(!this.ticking) {
61        requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
62        this.ticking = true;
63      }
64    },
65  
66    /**
67     * Attach this as the event listeners
68     */
69    handleEvent : function() {
70      this.requestTick();
71    }
72  };
73  /**
74   * Check if object is part of the DOM
75   * @constructor
76   * @param {Object} obj element to check
77   */
78  function isDOMElement(obj) {
79    return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType);
80  }
81  
82  /**
83   * Helper function for extending objects
84   */
85  function extend (object /*, objectN ... */) {
86    if(arguments.length <= 0) {
87      throw new Error('Missing arguments in extend function');
88    }
89  
90    var result = object || {},
91        key,
92        i;
93  
94    for (i = 1; i < arguments.length; i++) {
95      var replacement = arguments[i] || {};
96  
97      for (key in replacement) {
98        // Recurse into object except if the object is a DOM element
99        if(typeof result[key] === 'object' && ! isDOMElement(result[key])) {
100          result[key] = extend(result[key], replacement[key]);
101        }
102        else {
103          result[key] = result[key] || replacement[key];
104        }
105      }
106    }
107  
108    return result;
109  }
110  
111  /**
112   * Helper function for normalizing tolerance option to object format
113   */
114  function normalizeTolerance (t) {
115    return t === Object(t) ? t : { down : t, up : t };
116  }
117  
118  /**
119   * UI enhancement for fixed headers.
120   * Hides header when scrolling down
121   * Shows header when scrolling up
122   * @constructor
123   * @param {DOMElement} elem the header element
124   * @param {Object} options options for the widget
125   */
126  function Headroom (elem, options) {
127    options = extend(options, Headroom.options);
128  
129    this.lastKnownScrollY = 0;
130    this.elem             = elem;
131    this.tolerance        = normalizeTolerance(options.tolerance);
132    this.classes          = options.classes;
133    this.offset           = options.offset;
134    this.scroller         = options.scroller;
135    this.initialised      = false;
136    this.onPin            = options.onPin;
137    this.onUnpin          = options.onUnpin;
138    this.onTop            = options.onTop;
139    this.onNotTop         = options.onNotTop;
140    this.onBottom         = options.onBottom;
141    this.onNotBottom      = options.onNotBottom;
142  }
143  Headroom.prototype = {
144    constructor : Headroom,
145  
146    /**
147     * Initialises the widget
148     */
149    init : function() {
150      if(!Headroom.cutsTheMustard) {
151        return;
152      }
153  
154      this.debouncer = new Debouncer(this.update.bind(this));
155      this.elem.classList.add(this.classes.initial);
156  
157      // defer event registration to handle browser
158      // potentially restoring previous scroll position
159      setTimeout(this.attachEvent.bind(this), 100);
160  
161      return this;
162    },
163  
164    /**
165     * Unattaches events and removes any classes that were added
166     */
167    destroy : function() {
168      var classes = this.classes;
169  
170      this.initialised = false;
171  
172      for (var key in classes) {
173        if(classes.hasOwnProperty(key)) {
174          this.elem.classList.remove(classes[key]);
175        }
176      }
177  
178      this.scroller.removeEventListener('scroll', this.debouncer, false);
179    },
180  
181    /**
182     * Attaches the scroll event
183     * @private
184     */
185    attachEvent : function() {
186      if(!this.initialised){
187        this.lastKnownScrollY = this.getScrollY();
188        this.initialised = true;
189        this.scroller.addEventListener('scroll', this.debouncer, false);
190  
191        this.debouncer.handleEvent();
192      }
193    },
194  
195    /**
196     * Unpins the header if it's currently pinned
197     */
198    unpin : function() {
199      var classList = this.elem.classList,
200        classes = this.classes;
201  
202      if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) {
203        classList.add(classes.unpinned);
204        classList.remove(classes.pinned);
205        this.onUnpin && this.onUnpin.call(this);
206      }
207    },
208  
209    /**
210     * Pins the header if it's currently unpinned
211     */
212    pin : function() {
213      var classList = this.elem.classList,
214        classes = this.classes;
215  
216      if(classList.contains(classes.unpinned)) {
217        classList.remove(classes.unpinned);
218        classList.add(classes.pinned);
219        this.onPin && this.onPin.call(this);
220      }
221    },
222  
223    /**
224     * Handles the top states
225     */
226    top : function() {
227      var classList = this.elem.classList,
228        classes = this.classes;
229  
230      if(!classList.contains(classes.top)) {
231        classList.add(classes.top);
232        classList.remove(classes.notTop);
233        this.onTop && this.onTop.call(this);
234      }
235    },
236  
237    /**
238     * Handles the not top state
239     */
240    notTop : function() {
241      var classList = this.elem.classList,
242        classes = this.classes;
243  
244      if(!classList.contains(classes.notTop)) {
245        classList.add(classes.notTop);
246        classList.remove(classes.top);
247        this.onNotTop && this.onNotTop.call(this);
248      }
249    },
250  
251    bottom : function() {
252      var classList = this.elem.classList,
253        classes = this.classes;
254  
255      if(!classList.contains(classes.bottom)) {
256        classList.add(classes.bottom);
257        classList.remove(classes.notBottom);
258        this.onBottom && this.onBottom.call(this);
259      }
260    },
261  
262    /**
263     * Handles the not top state
264     */
265    notBottom : function() {
266      var classList = this.elem.classList,
267        classes = this.classes;
268  
269      if(!classList.contains(classes.notBottom)) {
270        classList.add(classes.notBottom);
271        classList.remove(classes.bottom);
272        this.onNotBottom && this.onNotBottom.call(this);
273      }
274    },
275  
276    /**
277     * Gets the Y scroll position
278     * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
279     * @return {Number} pixels the page has scrolled along the Y-axis
280     */
281    getScrollY : function() {
282      return (this.scroller.pageYOffset !== undefined)
283        ? this.scroller.pageYOffset
284        : (this.scroller.scrollTop !== undefined)
285          ? this.scroller.scrollTop
286          : (document.documentElement || document.body.parentNode || document.body).scrollTop;
287    },
288  
289    /**
290     * Gets the height of the viewport
291     * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript
292     * @return {int} the height of the viewport in pixels
293     */
294    getViewportHeight : function () {
295      return window.innerHeight
296        || document.documentElement.clientHeight
297        || document.body.clientHeight;
298    },
299  
300    /**
301     * Gets the physical height of the DOM element
302     * @param  {Object}  elm the element to calculate the physical height of which
303     * @return {int}     the physical height of the element in pixels
304     */
305    getElementPhysicalHeight : function (elm) {
306      return Math.max(
307        elm.offsetHeight,
308        elm.clientHeight
309      );
310    },
311  
312    /**
313     * Gets the physical height of the scroller element
314     * @return {int} the physical height of the scroller element in pixels
315     */
316    getScrollerPhysicalHeight : function () {
317      return (this.scroller === window || this.scroller === document.body)
318        ? this.getViewportHeight()
319        : this.getElementPhysicalHeight(this.scroller);
320    },
321  
322    /**
323     * Gets the height of the document
324     * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/
325     * @return {int} the height of the document in pixels
326     */
327    getDocumentHeight : function () {
328      var body = document.body,
329        documentElement = document.documentElement;
330  
331      return Math.max(
332        body.scrollHeight, documentElement.scrollHeight,
333        body.offsetHeight, documentElement.offsetHeight,
334        body.clientHeight, documentElement.clientHeight
335      );
336    },
337  
338    /**
339     * Gets the height of the DOM element
340     * @param  {Object}  elm the element to calculate the height of which
341     * @return {int}     the height of the element in pixels
342     */
343    getElementHeight : function (elm) {
344      return Math.max(
345        elm.scrollHeight,
346        elm.offsetHeight,
347        elm.clientHeight
348      );
349    },
350  
351    /**
352     * Gets the height of the scroller element
353     * @return {int} the height of the scroller element in pixels
354     */
355    getScrollerHeight : function () {
356      return (this.scroller === window || this.scroller === document.body)
357        ? this.getDocumentHeight()
358        : this.getElementHeight(this.scroller);
359    },
360  
361    /**
362     * determines if the scroll position is outside of document boundaries
363     * @param  {int}  currentScrollY the current y scroll position
364     * @return {bool} true if out of bounds, false otherwise
365     */
366    isOutOfBounds : function (currentScrollY) {
367      var pastTop  = currentScrollY < 0,
368        pastBottom = currentScrollY + this.getScrollerPhysicalHeight() > this.getScrollerHeight();
369  
370      return pastTop || pastBottom;
371    },
372  
373    /**
374     * determines if the tolerance has been exceeded
375     * @param  {int} currentScrollY the current scroll y position
376     * @return {bool} true if tolerance exceeded, false otherwise
377     */
378    toleranceExceeded : function (currentScrollY, direction) {
379      return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction];
380    },
381  
382    /**
383     * determine if it is appropriate to unpin
384     * @param  {int} currentScrollY the current y scroll position
385     * @param  {bool} toleranceExceeded has the tolerance been exceeded?
386     * @return {bool} true if should unpin, false otherwise
387     */
388    shouldUnpin : function (currentScrollY, toleranceExceeded) {
389      var scrollingDown = currentScrollY > this.lastKnownScrollY,
390        pastOffset = currentScrollY >= this.offset;
391  
392      return scrollingDown && pastOffset && toleranceExceeded;
393    },
394  
395    /**
396     * determine if it is appropriate to pin
397     * @param  {int} currentScrollY the current y scroll position
398     * @param  {bool} toleranceExceeded has the tolerance been exceeded?
399     * @return {bool} true if should pin, false otherwise
400     */
401    shouldPin : function (currentScrollY, toleranceExceeded) {
402      var scrollingUp  = currentScrollY < this.lastKnownScrollY,
403        pastOffset = currentScrollY <= this.offset;
404  
405      return (scrollingUp && toleranceExceeded) || pastOffset;
406    },
407  
408    /**
409     * Handles updating the state of the widget
410     */
411    update : function() {
412      var currentScrollY  = this.getScrollY(),
413        scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up',
414        toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection);
415  
416      if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX
417        return;
418      }
419  
420      if (currentScrollY <= this.offset ) {
421        this.top();
422      } else {
423        this.notTop();
424      }
425  
426      if(currentScrollY + this.getViewportHeight() >= this.getScrollerHeight()) {
427        this.bottom();
428      }
429      else {
430        this.notBottom();
431      }
432  
433      if(this.shouldUnpin(currentScrollY, toleranceExceeded)) {
434        this.unpin();
435      }
436      else if(this.shouldPin(currentScrollY, toleranceExceeded)) {
437        this.pin();
438      }
439  
440      this.lastKnownScrollY = currentScrollY;
441    }
442  };
443  /**
444   * Default options
445   * @type {Object}
446   */
447  Headroom.options = {
448    tolerance : {
449      up : 0,
450      down : 0
451    },
452    offset : 0,
453    scroller: window,
454    classes : {
455      pinned : 'headroom--pinned',
456      unpinned : 'headroom--unpinned',
457      top : 'headroom--top',
458      notTop : 'headroom--not-top',
459      bottom : 'headroom--bottom',
460      notBottom : 'headroom--not-bottom',
461      initial : 'headroom'
462    }
463  };
464  Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList;
465
466  return Headroom;
467}));
468
469(function($) {
470
471  if(!$) {
472    return;
473  }
474
475  ////////////
476  // Plugin //
477  ////////////
478
479  $.fn.headroom = function(option) {
480    return this.each(function() {
481      var $this   = $(this),
482        data      = $this.data('headroom'),
483        options   = typeof option === 'object' && option;
484
485      options = $.extend(true, {}, Headroom.options, options);
486
487      if (!data) {
488        data = new Headroom(this, options);
489        data.init();
490        $this.data('headroom', data);
491      }
492      if (typeof option === 'string') {
493        data[option]();
494
495        if(option === 'destroy'){
496          $this.removeData('headroom');
497        }
498      }
499    });
500  };
501
502  //////////////
503  // Data API //
504  //////////////
505
506  $('[data-headroom]').each(function() {
507    var $this = $(this);
508    $this.headroom($this.data());
509  });
510
511}(window.Zepto || window.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.