PageSourceSearch

https://www.calendarwiz.com/js/headroom.js?v=20221102

js calendarwiz.com collected 2026-10-01 12:29:51 UTC 11,494 bytes, 390 lines download raw bytes

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

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.