PageSourceSearch

https://rwandainindia.gov.rw/_assets/b2ee7e11602f92239d61e026cd4ed9a2/Javascript/smoothscroll.js?1787574001

js rwandainindia.gov.rw collected 2026-09-25 12:31:54 UTC 13,011 bytes, 429 lines download raw bytes

vendor: 13,011 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.