PageSourceSearch

https://www.wolfreisen-konstanz.de/application/themes/wolfreisen/js/smoothscroll.js

js wolfreisen-konstanz.de collected 2026-10-06 20:39:41 UTC 11,383 bytes, 429 lines download raw bytes

vendor: 11,383 bytes, lines 1-429
1'use strict';
2
3// polyfill
4function polyfill() {
5  // aliases
6  var w = window;
7  var d = document;
8
9  // return if scroll behavior is supported and polyfill is not forced
10  if (
11    'scrollBehavior' in d.documentElement.style &&
12    w.__forceSmoothScrollPolyfill__ !== true
13  ) {
14    return;
15  }
16
17  // globals
18  var Element = w.HTMLElement || w.Element;
19  var SCROLL_TIME = 468;
20
21  // object gathering original scroll methods
22  var original = {
23    scroll: w.scroll || w.scrollTo,
24    scrollBy: w.scrollBy,
25    elementScroll: Element.prototype.scroll || scrollElement,
26    scrollIntoView: Element.prototype.scrollIntoView
27  };
28
29  // define timing method
30  var now =
31    w.performance && w.performance.now
32      ? w.performance.now.bind(w.performance)
33      : Date.now;
34
35  /**
36   * indicates if a the current browser is made by Microsoft
37   * @method isMicrosoftBrowser
38   * @param {String} userAgent
39   * @returns {Boolean}
40   */
41  function isMicrosoftBrowser(userAgent) {
42    var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
43
44    return new RegExp(userAgentPatterns.join('|')).test(userAgent);
45  }
46
47  /*
48   * IE has rounding bug rounding down clientHeight and clientWidth and
49   * rounding up scrollHeight and scrollWidth causing false positives
50   * on hasScrollableSpace
51   */
52  var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
53
54  /**
55   * changes scroll position inside an element
56   * @method scrollElement
57   * @param {Number} x
58   * @param {Number} y
59   * @returns {undefined}
60   */
61  function scrollElement(x, y) {
62    this.scrollLeft = x;
63    this.scrollTop = y;
64  }
65
66  /**
67   * returns result of applying ease math function to a number
68   * @method ease
69   * @param {Number} k
70   * @returns {Number}
71   */
72  function ease(k) {
73    return 0.5 * (1 - Math.cos(Math.PI * k));
74  }
75
76  /**
77   * indicates if a smooth behavior should be applied
78   * @method shouldBailOut
79   * @param {Number|Object} firstArg
80   * @returns {Boolean}
81   */
82  function shouldBailOut(firstArg) {
83    if (
84      firstArg === null ||
85      typeof firstArg !== 'object' ||
86      firstArg.behavior === undefined ||
87      firstArg.behavior === 'auto' ||
88      firstArg.behavior === 'instant'
89    ) {
90      // first argument is not an object/null
91      // or behavior is auto, instant or undefined
92      return true;
93    }
94
95    if (typeof firstArg === 'object' && firstArg.behavior === 'smooth') {
96      // first argument is an object and behavior is smooth
97      return false;
98    }
99
100    // throw error when behavior is not supported
101    throw new TypeError(
102      'behavior member of ScrollOptions ' +
103        firstArg.behavior +
104        ' is not a valid value for enumeration ScrollBehavior.'
105    );
106  }
107
108  /**
109   * indicates if an element has scrollable space in the provided axis
110   * @method hasScrollableSpace
111   * @param {Node} el
112   * @param {String} axis
113   * @returns {Boolean}
114   */
115  function hasScrollableSpace(el, axis) {
116    if (axis === 'Y') {
117      return el.clientHeight + ROUNDING_TOLERANCE < el.scrollHeight;
118    }
119
120    if (axis === 'X') {
121      return el.clientWidth + ROUNDING_TOLERANCE < el.scrollWidth;
122    }
123  }
124
125  /**
126   * indicates if an element has a scrollable overflow property in the axis
127   * @method canOverflow
128   * @param {Node} el
129   * @param {String} axis
130   * @returns {Boolean}
131   */
132  function canOverflow(el, axis) {
133    var overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
134
135    return overflowValue === 'auto' || overflowValue === 'scroll';
136  }
137
138  /**
139   * indicates if an element can be scrolled in either axis
140   * @method isScrollable
141   * @param {Node} el
142   * @param {String} axis
143   * @returns {Boolean}
144   */
145  function isScrollable(el) {
146    var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
147    var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
148
149    return isScrollableY || isScrollableX;
150  }
151
152  /**
153   * finds scrollable parent of an element
154   * @method findScrollableParent
155   * @param {Node} el
156   * @returns {Node} el
157   */
158  function findScrollableParent(el) {
159    while (el !== d.body && isScrollable(el) === false) {
160      el = el.parentNode || el.host;
161    }
162
163    return el;
164  }
165
166  /**
167   * self invoked function that, given a context, steps through scrolling
168   * @method step
169   * @param {Object} context
170   * @returns {undefined}
171   */
172  function step(context) {
173    var time = now();
174    var value;
175    var currentX;
176    var currentY;
177    var elapsed = (time - context.startTime) / SCROLL_TIME;
178
179    // avoid elapsed times higher than one
180    elapsed = elapsed > 1 ? 1 : elapsed;
181
182    // apply easing to elapsed time
183    value = ease(elapsed);
184
185    currentX = context.startX + (context.x - context.startX) * value;
186    currentY = context.startY + (context.y - context.startY) * value;
187
188    context.method.call(context.scrollable, currentX, currentY);
189
190    // scroll more if we have not reached our destination
191    if (currentX !== context.x || currentY !== context.y) {
192      w.requestAnimationFrame(step.bind(w, context));
193    }
194  }
195
196  /**
197   * scrolls window or element with a smooth behavior
198   * @method smoothScroll
199   * @param {Object|Node} el
200   * @param {Number} x
201   * @param {Number} y
202   * @returns {undefined}
203   */
204  function smoothScroll(el, x, y) {
205    var scrollable;
206    var startX;
207    var startY;
208    var method;
209    var startTime = now();
210
211    // define scroll context
212    if (el === d.body) {
213      scrollable = w;
214      startX = w.scrollX || w.pageXOffset;
215      startY = w.scrollY || w.pageYOffset;
216      method = original.scroll;
217    } else {
218      scrollable = el;
219      startX = el.scrollLeft;
220      startY = el.scrollTop;
221      method = scrollElement;
222    }
223
224    // scroll looping over a frame
225    step({
226      scrollable: scrollable,
227      method: method,
228      startTime: startTime,
229      startX: startX,
230      startY: startY,
231      x: x,
232      y: y
233    });
234  }
235
236  // ORIGINAL METHODS OVERRIDES
237  // w.scroll and w.scrollTo
238  w.scroll = w.scrollTo = function() {
239    // avoid action when no arguments are passed
240    if (arguments[0] === undefined) {
241      return;
242    }
243
244    // avoid smooth behavior if not required
245    if (shouldBailOut(arguments[0]) === true) {
246      original.scroll.call(
247        w,
248        arguments[0].left !== undefined
249          ? arguments[0].left
250          : typeof arguments[0] !== 'object'
251            ? arguments[0]
252            : w.scrollX || w.pageXOffset,
253        // use top prop, second argument if present or fallback to scrollY
254        arguments[0].top !== undefined
255          ? arguments[0].top
256          : arguments[1] !== undefined
257            ? arguments[1]
258            : w.scrollY || w.pageYOffset
259      );
260
261      return;
262    }
263
264    // LET THE SMOOTHNESS BEGIN!
265    smoothScroll.call(
266      w,
267      d.body,
268      arguments[0].left !== undefined
269        ? ~~arguments[0].left
270        : w.scrollX || w.pageXOffset,
271      arguments[0].top !== undefined
272        ? ~~arguments[0].top
273        : w.scrollY || w.pageYOffset
274    );
275  };
276
277  // w.scrollBy
278  w.scrollBy = function() {
279    // avoid action when no arguments are passed
280    if (arguments[0] === undefined) {
281      return;
282    }
283
284    // avoid smooth behavior if not required
285    if (shouldBailOut(arguments[0])) {
286      original.scrollBy.call(
287        w,
288        arguments[0].left !== undefined
289          ? arguments[0].left
290          : typeof arguments[0] !== 'object' ? arguments[0] : 0,
291        arguments[0].top !== undefined
292          ? arguments[0].top
293          : arguments[1] !== undefined ? arguments[1] : 0
294      );
295
296      return;
297    }
298
299    // LET THE SMOOTHNESS BEGIN!
300    smoothScroll.call(
301      w,
302      d.body,
303      ~~arguments[0].left + (w.scrollX || w.pageXOffset),
304      ~~arguments[0].top + (w.scrollY || w.pageYOffset)
305    );
306  };
307
308  // Element.prototype.scroll and Element.prototype.scrollTo
309  Element.prototype.scroll = Element.prototype.scrollTo = function() {
310    // avoid action when no arguments are passed
311    if (arguments[0] === undefined) {
312      return;
313    }
314
315    // avoid smooth behavior if not required
316    if (shouldBailOut(arguments[0]) === true) {
317      // if one number is passed, throw error to match Firefox implementation
318      if (typeof arguments[0] === 'number' && arguments[1] === undefined) {
319        throw new SyntaxError('Value could not be converted');
320      }
321
322      original.elementScroll.call(
323        this,
324        // use left prop, first number argument or fallback to scrollLeft
325        arguments[0].left !== undefined
326          ? ~~arguments[0].left
327          : typeof arguments[0] !== 'object' ? ~~arguments[0] : this.scrollLeft,
328        // use top prop, second argument or fallback to scrollTop
329        arguments[0].top !== undefined
330          ? ~~arguments[0].top
331          : arguments[1] !== undefined ? ~~arguments[1] : this.scrollTop
332      );
333
334      return;
335    }
336
337    var left = arguments[0].left;
338    var top = arguments[0].top;
339
340    // LET THE SMOOTHNESS BEGIN!
341    smoothScroll.call(
342      this,
343      this,
344      typeof left === 'undefined' ? this.scrollLeft : ~~left,
345      typeof top === 'undefined' ? this.scrollTop : ~~top
346    );
347  };
348
349  // Element.prototype.scrollBy
350  Element.prototype.scrollBy = function() {
351    // avoid action when no arguments are passed
352    if (arguments[0] === undefined) {
353      return;
354    }
355
356    // avoid smooth behavior if not required
357    if (shouldBailOut(arguments[0]) === true) {
358      original.elementScroll.call(
359        this,
360        arguments[0].left !== undefined
361          ? ~~arguments[0].left + this.scrollLeft
362          : ~~arguments[0] + this.scrollLeft,
363        arguments[0].top !== undefined
364          ? ~~arguments[0].top + this.scrollTop
365          : ~~arguments[1] + this.scrollTop
366      );
367
368      return;
369    }
370
371    this.scroll({
372      left: ~~arguments[0].left + this.scrollLeft,
373      top: ~~arguments[0].top + this.scrollTop,
374      behavior: arguments[0].behavior
375    });
376  };
377
378  // Element.prototype.scrollIntoView
379  Element.prototype.scrollIntoView = function() {
380    // avoid smooth behavior if not required
381    if (shouldBailOut(arguments[0]) === true) {
382      original.scrollIntoView.call(
383        this,
384        arguments[0] === undefined ? true : arguments[0]
385      );
386
387      return;
388    }
389
390    // LET THE SMOOTHNESS BEGIN!
391    var scrollableParent = findScrollableParent(this);
392    var parentRects = scrollableParent.getBoundingClientRect();
393    var clientRects = this.getBoundingClientRect();
394
395    if (scrollableParent !== d.body) {
396      // reveal element inside parent
397      smoothScroll.call(
398        this,
399        scrollableParent,
400        scrollableParent.scrollLeft + clientRects.left - parentRects.left,
401        scrollableParent.scrollTop + clientRects.top - parentRects.top
402      );
403
404      // reveal parent in viewport unless is fixed
405      if (w.getComputedStyle(scrollableParent).position !== 'fixed') {
406        w.scrollBy({
407          left: parentRects.left,
408          top: parentRects.top,
409          behavior: 'smooth'
410        });
411      }
412    } else {
413      // reveal element in viewport
414      w.scrollBy({
415        left: clientRects.left,
416        top: clientRects.top,
417        behavior: 'smooth'
418      });
419    }
420  };
421}
422
423if (typeof exports === 'object' && typeof module !== 'undefined') {
424  // commonjs
425  module.exports = { polyfill: polyfill };
426} else {
427  // global
428  polyfill();
429}

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.