PageSourceSearch

https://smtech-rus.ru/g/libs/headeroom/0.12.0/headroom.js

js smtech-rus.ru collected 2026-09-30 02:54:09 UTC 11,161 bytes, 437 lines download raw bytes

vendor: 11,161 bytes, lines 1-437
1/*!
2 * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it
3 * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js
4 * License: MIT
5 */
6
7(function (global, factory) {
8  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9  typeof define === 'function' && define.amd ? define(factory) :
10  (global = global || self, global.Headroom = factory());
11}(this, function () { 'use strict';
12
13  function isBrowser() {
14    return typeof window !== "undefined";
15  }
16
17  /**
18   * Used to detect browser support for adding an event listener with options
19   * Credit: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
20   */
21  function passiveEventsSupported() {
22    var supported = false;
23
24    try {
25      var options = {
26        // eslint-disable-next-line getter-return
27        get passive() {
28          supported = true;
29        }
30      };
31      window.addEventListener("test", options, options);
32      window.removeEventListener("test", options, options);
33    } catch (err) {
34      supported = false;
35    }
36
37    return supported;
38  }
39
40  function isSupported() {
41    return !!(
42      isBrowser() &&
43      function() {}.bind &&
44      "classList" in document.documentElement &&
45      Object.assign &&
46      Object.keys &&
47      requestAnimationFrame
48    );
49  }
50
51  function isDocument(obj) {
52    return obj.nodeType === 9; // Node.DOCUMENT_NODE === 9
53  }
54
55  function isWindow(obj) {
56    // `obj === window` or `obj instanceof Window` is not sufficient,
57    // as the obj may be the window of an iframe.
58    return obj && obj.document && isDocument(obj.document);
59  }
60
61  function windowScroller(win) {
62    var doc = win.document;
63    var body = doc.body;
64    var html = doc.documentElement;
65
66    return {
67      /**
68       * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/
69       * @return {Number} the scroll height of the document in pixels
70       */
71      scrollHeight: function() {
72        return Math.max(
73          body.scrollHeight,
74          html.scrollHeight,
75          body.offsetHeight,
76          html.offsetHeight,
77          body.clientHeight,
78          html.clientHeight
79        );
80      },
81
82      /**
83       * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript
84       * @return {Number} the height of the viewport in pixels
85       */
86      height: function() {
87        return win.innerHeight || html.clientHeight || body.clientHeight;
88      },
89
90      /**
91       * Gets the Y scroll position
92       * @return {Number} pixels the page has scrolled along the Y-axis
93       */
94      scrollY: function() {
95        if (win.pageYOffset !== undefined) {
96          return win.pageYOffset;
97        }
98
99        return (html || body.parentNode || body).scrollTop;
100      }
101    };
102  }
103
104  function elementScroller(element) {
105    return {
106      /**
107       * @return {Number} the scroll height of the element in pixels
108       */
109      scrollHeight: function() {
110        return Math.max(
111          element.scrollHeight,
112          element.offsetHeight,
113          element.clientHeight
114        );
115      },
116
117      /**
118       * @return {Number} the height of the element in pixels
119       */
120      height: function() {
121        return Math.max(element.offsetHeight, element.clientHeight);
122      },
123
124      /**
125       * Gets the Y scroll position
126       * @return {Number} pixels the element has scrolled along the Y-axis
127       */
128      scrollY: function() {
129        return element.scrollTop;
130      }
131    };
132  }
133
134  function createScroller(element) {
135    return isWindow(element) ? windowScroller(element) : elementScroller(element);
136  }
137
138  /**
139   * @param element EventTarget
140   */
141  function trackScroll(element, options, callback) {
142    var isPassiveSupported = passiveEventsSupported();
143    var rafId;
144    var scrolled = false;
145    var scroller = createScroller(element);
146    var lastScrollY = scroller.scrollY();
147    var details = {};
148
149    function update() {
150      var scrollY = Math.round(scroller.scrollY());
151      var height = scroller.height();
152      var scrollHeight = scroller.scrollHeight();
153
154      // reuse object for less memory churn
155      details.scrollY = scrollY;
156      details.lastScrollY = lastScrollY;
157      details.direction = scrollY > lastScrollY ? "down" : "up";
158      details.distance = Math.abs(scrollY - lastScrollY);
159      details.isOutOfBounds = scrollY < 0 || scrollY + height > scrollHeight;
160      details.top = scrollY <= options.offset[details.direction];
161      details.bottom = scrollY + height >= scrollHeight;
162      details.toleranceExceeded =
163        details.distance > options.tolerance[details.direction];
164
165      callback(details);
166
167      lastScrollY = scrollY;
168      scrolled = false;
169    }
170
171    function handleScroll() {
172      if (!scrolled) {
173        scrolled = true;
174        rafId = requestAnimationFrame(update);
175      }
176    }
177
178    var eventOptions = isPassiveSupported
179      ? { passive: true, capture: false }
180      : false;
181
182    element.addEventListener("scroll", handleScroll, eventOptions);
183    update();
184
185    return {
186      destroy: function() {
187        cancelAnimationFrame(rafId);
188        element.removeEventListener("scroll", handleScroll, eventOptions);
189      }
190    };
191  }
192
193  function normalizeUpDown(t) {
194    return t === Object(t) ? t : { down: t, up: t };
195  }
196
197  /**
198   * UI enhancement for fixed headers.
199   * Hides header when scrolling down
200   * Shows header when scrolling up
201   * @constructor
202   * @param {DOMElement} elem the header element
203   * @param {Object} options options for the widget
204   */
205  function Headroom(elem, options) {
206    options = options || {};
207    Object.assign(this, Headroom.options, options);
208    this.classes = Object.assign({}, Headroom.options.classes, options.classes);
209
210    this.elem = elem;
211    this.tolerance = normalizeUpDown(this.tolerance);
212    this.offset = normalizeUpDown(this.offset);
213    this.initialised = false;
214    this.frozen = false;
215  }
216  Headroom.prototype = {
217    constructor: Headroom,
218
219    /**
220     * Start listening to scrolling
221     * @public
222     */
223    init: function() {
224      if (Headroom.cutsTheMustard && !this.initialised) {
225        this.addClass("initial");
226        this.initialised = true;
227
228        // defer event registration to handle browser
229        // potentially restoring previous scroll position
230        setTimeout(
231          function(self) {
232            self.scrollTracker = trackScroll(
233              self.scroller,
234              { offset: self.offset, tolerance: self.tolerance },
235              self.update.bind(self)
236            );
237          },
238          100,
239          this
240        );
241      }
242
243      return this;
244    },
245
246    /**
247     * Destroy the widget, clearing up after itself
248     * @public
249     */
250    destroy: function() {
251      this.initialised = false;
252      Object.keys(this.classes).forEach(this.removeClass, this);
253      this.scrollTracker.destroy();
254    },
255
256    /**
257     * Unpin the element
258     * @public
259     */
260    unpin: function() {
261      if (this.hasClass("pinned") || !this.hasClass("unpinned")) {
262        this.addClass("unpinned");
263        this.removeClass("pinned");
264
265        if (this.onUnpin) {
266          this.onUnpin.call(this);
267        }
268      }
269    },
270
271    /**
272     * Pin the element
273     * @public
274     */
275    pin: function() {
276      if (this.hasClass("unpinned")) {
277        this.addClass("pinned");
278        this.removeClass("unpinned");
279
280        if (this.onPin) {
281          this.onPin.call(this);
282        }
283      }
284    },
285
286    /**
287     * Freezes the current state of the widget
288     * @public
289     */
290    freeze: function() {
291      this.frozen = true;
292      this.addClass("frozen");
293    },
294
295    /**
296     * Re-enables the default behaviour of the widget
297     * @public
298     */
299    unfreeze: function() {
300      this.frozen = false;
301      this.removeClass("frozen");
302    },
303
304    top: function() {
305      if (!this.hasClass("top")) {
306        this.addClass("top");
307        this.removeClass("notTop");
308
309        if (this.onTop) {
310          this.onTop.call(this);
311        }
312      }
313    },
314
315    notTop: function() {
316      if (!this.hasClass("notTop")) {
317        this.addClass("notTop");
318        this.removeClass("top");
319
320        if (this.onNotTop) {
321          this.onNotTop.call(this);
322        }
323      }
324    },
325
326    bottom: function() {
327      if (!this.hasClass("bottom")) {
328        this.addClass("bottom");
329        this.removeClass("notBottom");
330
331        if (this.onBottom) {
332          this.onBottom.call(this);
333        }
334      }
335    },
336
337    notBottom: function() {
338      if (!this.hasClass("notBottom")) {
339        this.addClass("notBottom");
340        this.removeClass("bottom");
341
342        if (this.onNotBottom) {
343          this.onNotBottom.call(this);
344        }
345      }
346    },
347
348    shouldUnpin: function(details) {
349      var scrollingDown = details.direction === "down";
350
351      return scrollingDown && !details.top && details.toleranceExceeded;
352    },
353
354    shouldPin: function(details) {
355      var scrollingUp = details.direction === "up";
356
357      return (scrollingUp && details.toleranceExceeded) || details.top;
358    },
359
360    addClass: function(className) {
361      this.elem.classList.add.apply(
362        this.elem.classList,
363        this.classes[className].split(" ")
364      );
365    },
366
367    removeClass: function(className) {
368      this.elem.classList.remove.apply(
369        this.elem.classList,
370        this.classes[className].split(" ")
371      );
372    },
373
374    hasClass: function(className) {
375      return this.classes[className].split(" ").every(function(cls) {
376        return this.classList.contains(cls);
377      }, this.elem);
378    },
379
380    update: function(details) {
381      if (details.isOutOfBounds) {
382        // Ignore bouncy scrolling in OSX
383        return;
384      }
385
386      if (this.frozen === true) {
387        return;
388      }
389
390      if (details.top) {
391        this.top();
392      } else {
393        this.notTop();
394      }
395
396      if (details.bottom) {
397        this.bottom();
398      } else {
399        this.notBottom();
400      }
401
402      if (this.shouldUnpin(details)) {
403        this.unpin();
404      } else if (this.shouldPin(details)) {
405        this.pin();
406      }
407    }
408  };
409
410  /**
411   * Default options
412   * @type {Object}
413   */
414  Headroom.options = {
415    tolerance: {
416      up: 0,
417      down: 0
418    },
419    offset: 0,
420    scroller: isBrowser() ? window : null,
421    classes: {
422      frozen: "headroom--frozen",
423      pinned: "headroom--pinned",
424      unpinned: "headroom--unpinned",
425      top: "headroom--top",
426      notTop: "headroom--not-top",
427      bottom: "headroom--bottom",
428      notBottom: "headroom--not-bottom",
429      initial: "headroom"
430    }
431  };
432
433  Headroom.cutsTheMustard = isSupported();
434
435  return Headroom;
436
437}));

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.