Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/themefisher/meghna-hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/assets
diff options
context:
space:
mode:
authorhawkeye116477 <hawkeye116477@gmail.com>2019-02-10 14:32:24 +0300
committerhawkeye116477 <hawkeye116477@gmail.com>2019-02-10 14:32:24 +0300
commitd27fc556bc366ce9f36afe2fdb1141ba373f10d5 (patch)
treefc6d3a23b9831ec379c3ca029afa17c906818e34 /assets
parent1b14ded6d8e658c140df5ccf2073e69f5071a5f7 (diff)
Use native smooth scrolling if possible, if not then use polyfill
Diffstat (limited to 'assets')
-rw-r--r--assets/js/script.js35
-rw-r--r--assets/js/scroll-behavior-polyfill.js931
2 files changed, 935 insertions, 31 deletions
diff --git a/assets/js/script.js b/assets/js/script.js
index e37a22c..dafb0c2 100644
--- a/assets/js/script.js
+++ b/assets/js/script.js
@@ -5,38 +5,11 @@ jQuery(function ($) {
/* Page Preloader
/* ========================================================================= */
- // Preloader js
+ // Preloader js
$(window).on('load', function () {
$('#preloader').fadeOut(700);
});
-
- //animation scroll js
- var html_body = $('html, body');
- $('nav a, .page-scroll').on('click', function () { //use page-scroll class in any HTML tag for scrolling
- if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
- var target = $(this.hash);
- target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
- if (target.length) {
- html_body.animate({
- scrollTop: target.offset().top - 50
- }, 1500, "easeInOutExpo");
- return false;
- }
- }
- });
-
- //easeInOutExpo Declaration
- jQuery.extend(jQuery.easing, {
- easeInOutExpo: function (x, t, b, c, d) {
- if (t == 0) return b;
- if (t == d) return b + c;
- if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
- return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
- }
- });
-
-
/* ========================================================================= */
/* Post image slider
/* ========================================================================= */
@@ -118,10 +91,10 @@ jQuery(function ($) {
where VARIABLE is the variable we are checking (like name, email),
length is a JavaScript function to get the number of characters.
And as you can see if the num of characters is 0 we set the error
- variable to true and show the name_error div with the fadeIn effect.
+ variable to true and show the name_error div with the fadeIn effect.
if it's not 0 then we fadeOut the div( that's if the div is shown and
- the error is fixed it fadesOut.
-
+ the error is fixed it fadesOut.
+
The only difference from these checks is the email checking, we have
email.indexOf('@') which checks if there is @ in the email input field.
This JavaScript function will return -1 if no occurrence have been found.*/
diff --git a/assets/js/scroll-behavior-polyfill.js b/assets/js/scroll-behavior-polyfill.js
new file mode 100644
index 0000000..2486c68
--- /dev/null
+++ b/assets/js/scroll-behavior-polyfill.js
@@ -0,0 +1,931 @@
+// https://www.jsdelivr.com/package/npm/scroll-behavior-polyfill?path=dist
+/*!
+ scroll-behavior-polyfill 2.0.4
+ license: MIT (https://github.com/wessberg/scroll-behavior-polyfill/blob/master/LICENSE.md)
+ Copyright © 2019 Frederik Wessberg <frederikwessberg@hotmail.com>
+*/
+
+(function () {
+ 'use strict';
+
+ /**
+ * Is true if the browser natively supports the 'scroll-behavior' CSS-property.
+ * @type {boolean}
+ */
+ var SUPPORTS_SCROLL_BEHAVIOR = "scrollBehavior" in document.documentElement.style;
+
+ /*! *****************************************************************************
+ Copyright (c) Microsoft Corporation. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of the
+ License at http://www.apache.org/licenses/LICENSE-2.0
+
+ THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+ WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+ MERCHANTABLITY OR NON-INFRINGEMENT.
+
+ See the Apache Version 2.0 License for specific language governing permissions
+ and limitations under the License.
+ ***************************************************************************** */
+
+ var __assign = function() {
+ __assign = Object.assign || function __assign(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+ };
+
+ function __read(o, n) {
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
+ if (!m) return o;
+ var i = m.call(o), r, ar = [], e;
+ try {
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
+ }
+ catch (error) { e = { error: error }; }
+ finally {
+ try {
+ if (r && !r.done && (m = i["return"])) m.call(i);
+ }
+ finally { if (e) throw e.error; }
+ }
+ return ar;
+ }
+
+ var styleDeclarationPropertyName = "scrollBehavior";
+ var styleAttributePropertyName = "scroll-behavior";
+ var styleAttributePropertyNameRegex = new RegExp(styleAttributePropertyName + ":\\s*([^;]*)");
+ /**
+ * Determines the scroll behavior to use, depending on the given ScrollOptions and the position of the Element
+ * within the DOM
+ * @param {Element|HTMLElement|Window} inputTarget
+ * @param {ScrollOptions} [options]
+ * @returns {ScrollBehavior}
+ */
+ function getScrollBehavior(inputTarget, options) {
+ // If the given 'behavior' is 'smooth', apply smooth scrolling no matter what
+ if (options != null && options.behavior === "smooth")
+ return "smooth";
+ var target = "style" in inputTarget ? inputTarget : document.scrollingElement != null ? document.scrollingElement : document.documentElement;
+ var value;
+ if ("style" in target) {
+ // Check if scroll-behavior is set as a property on the CSSStyleDeclaration
+ var scrollBehaviorPropertyValue = target.style[styleDeclarationPropertyName];
+ // Return it if it is given and has a proper value
+ if (scrollBehaviorPropertyValue != null && scrollBehaviorPropertyValue !== "") {
+ value = scrollBehaviorPropertyValue;
+ }
+ }
+ if (value == null) {
+ var attributeValue = target.getAttribute("scroll-behavior");
+ if (attributeValue != null && attributeValue !== "") {
+ value = attributeValue;
+ }
+ }
+ if (value == null) {
+ // Otherwise, check if it is set as an inline style
+ var styleAttributeValue = target.getAttribute("style");
+ if (styleAttributeValue != null && styleAttributeValue.includes(styleAttributePropertyName)) {
+ var match = styleAttributeValue.match(styleAttributePropertyNameRegex);
+ if (match != null) {
+ var _a = __read(match, 2), behavior = _a[1];
+ if (behavior != null && behavior !== "") {
+ value = behavior;
+ }
+ }
+ }
+ }
+ if (value == null) {
+ // Take the computed style for the element and see if it contains a specific 'scroll-behavior' value
+ var computedStyle = getComputedStyle(target);
+ var computedStyleValue = computedStyle.getPropertyValue("scrollBehavior");
+ if (computedStyleValue != null && computedStyleValue !== "") {
+ value = computedStyleValue;
+ }
+ }
+ // In all other cases, use the value from the CSSOM
+ return value;
+ }
+
+ var HALF = 0.5;
+ /**
+ * The easing function to use when applying the smooth scrolling
+ * @param {number} k
+ * @returns {number}
+ */
+ function ease(k) {
+ return HALF * (1 - Math.cos(Math.PI * k));
+ }
+
+ /**
+ * The duration of a smooth scroll
+ * @type {number}
+ */
+ var SCROLL_TIME = 15000;
+ /**
+ * Performs a smooth repositioning of the scroll
+ * @param {ISmoothScrollOptions} options
+ */
+ function smoothScroll(options) {
+ var startTime = options.startTime, startX = options.startX, startY = options.startY, endX = options.endX, endY = options.endY, method = options.method;
+ var timeLapsed = 0;
+ var distanceX = endX - startX;
+ var distanceY = endY - startY;
+ var speed = Math.max(Math.abs(distanceX / 1000 * SCROLL_TIME), Math.abs(distanceY / 1000 * SCROLL_TIME));
+ requestAnimationFrame(function animate(timestamp) {
+ timeLapsed += timestamp - startTime;
+ var percentage = Math.max(0, Math.min(1, speed === 0 ? 0 : (timeLapsed / speed)));
+ var positionX = Math.floor(startX + (distanceX * ease(percentage)));
+ var positionY = Math.floor(startY + (distanceY * ease(percentage)));
+ method(positionX, positionY);
+ if (positionX !== endX || positionY !== endY) {
+ requestAnimationFrame(animate);
+ }
+ });
+ }
+
+ /**
+ * Returns a High Resolution timestamp if possible, otherwise fallbacks to Date.now()
+ * @returns {number}
+ */
+ function now() {
+ if ("performance" in window)
+ return performance.now();
+ return Date.now();
+ }
+
+ var ELEMENT_ORIGINAL_SCROLL = Element.prototype.scroll;
+
+ var WINDOW_ORIGINAL_SCROLL = window.scroll;
+
+ var ELEMENT_ORIGINAL_SCROLL_BY = Element.prototype.scrollBy;
+
+ var WINDOW_ORIGINAL_SCROLL_BY = window.scrollBy;
+
+ var ELEMENT_ORIGINAL_SCROLL_TO = Element.prototype.scrollTo;
+
+ var WINDOW_ORIGINAL_SCROLL_TO = window.scrollTo;
+
+ /**
+ * A fallback if Element.prototype.scroll is not defined
+ * @param {number} x
+ * @param {number} y
+ */
+ function elementPrototypeScrollFallback(x, y) {
+ this.__adjustingScrollPosition = true;
+ this.scrollLeft = x;
+ this.scrollTop = y;
+ delete this.__adjustingScrollPosition;
+ }
+ /**
+ * A fallback if Element.prototype.scrollTo is not defined
+ * @param {number} x
+ * @param {number} y
+ */
+ function elementPrototypeScrollToFallback(x, y) {
+ return elementPrototypeScrollFallback.call(this, x, y);
+ }
+ /**
+ * A fallback if Element.prototype.scrollBy is not defined
+ * @param {number} x
+ * @param {number} y
+ */
+ function elementPrototypeScrollByFallback(x, y) {
+ this.__adjustingScrollPosition = true;
+ this.scrollLeft += x;
+ this.scrollTop += y;
+ delete this.__adjustingScrollPosition;
+ }
+ /**
+ * Gets the original non-patched prototype method for the given kind
+ * @param {ScrollMethodName} kind
+ * @param {Element|Window} element
+ * @return {Function}
+ */
+ function getOriginalScrollMethodForKind(kind, element) {
+ switch (kind) {
+ case "scroll":
+ if (element instanceof Element) {
+ if (ELEMENT_ORIGINAL_SCROLL != null) {
+ return ELEMENT_ORIGINAL_SCROLL;
+ }
+ else {
+ return elementPrototypeScrollFallback;
+ }
+ }
+ else {
+ return WINDOW_ORIGINAL_SCROLL;
+ }
+ case "scrollBy":
+ if (element instanceof Element) {
+ if (ELEMENT_ORIGINAL_SCROLL_BY != null) {
+ return ELEMENT_ORIGINAL_SCROLL_BY;
+ }
+ else {
+ return elementPrototypeScrollByFallback;
+ }
+ }
+ else {
+ return WINDOW_ORIGINAL_SCROLL_BY;
+ }
+ case "scrollTo":
+ if (element instanceof Element) {
+ if (ELEMENT_ORIGINAL_SCROLL_TO != null) {
+ return ELEMENT_ORIGINAL_SCROLL_TO;
+ }
+ else {
+ return elementPrototypeScrollToFallback;
+ }
+ }
+ else {
+ return WINDOW_ORIGINAL_SCROLL_TO;
+ }
+ }
+ }
+
+ /**
+ * Gets the Smooth Scroll Options to use for the step function
+ * @param {Element|Window} element
+ * @param {number} x
+ * @param {number} y
+ * @param {ScrollMethodName} kind
+ * @returns {ISmoothScrollOptions}
+ */
+ function getSmoothScrollOptions(element, x, y, kind) {
+ var startTime = now();
+ if (!(element instanceof Element)) {
+ // Use window as the scroll container
+ var scrollX_1 = window.scrollX, pageXOffset_1 = window.pageXOffset, scrollY_1 = window.scrollY, pageYOffset_1 = window.pageYOffset;
+ var startX = scrollX_1 == null || scrollX_1 === 0 ? pageXOffset_1 : scrollX_1;
+ var startY = scrollY_1 == null || scrollY_1 === 0 ? pageYOffset_1 : scrollY_1;
+ return {
+ startTime: startTime,
+ startX: startX,
+ startY: startY,
+ endX: Math.floor(kind === "scrollBy"
+ ? startX + x
+ : x),
+ endY: Math.floor(kind === "scrollBy"
+ ? startY + y
+ : y),
+ method: getOriginalScrollMethodForKind("scrollTo", window).bind(window)
+ };
+ }
+ else {
+ var scrollLeft = element.scrollLeft, scrollTop = element.scrollTop;
+ var startX = scrollLeft;
+ var startY = scrollTop;
+ return {
+ startTime: startTime,
+ startX: startX,
+ startY: startY,
+ endX: Math.floor(kind === "scrollBy"
+ ? startX + x
+ : x),
+ endY: Math.floor(kind === "scrollBy"
+ ? startY + y
+ : y),
+ method: getOriginalScrollMethodForKind("scrollTo", element).bind(element)
+ };
+ }
+ }
+
+ /**
+ * Ensures that the given value is numeric
+ * @param {number} value
+ * @return {number}
+ */
+ function ensureNumeric(value) {
+ if (value == null)
+ return 0;
+ else if (typeof value === "number") {
+ return value;
+ }
+ else if (typeof value === "string") {
+ return parseFloat(value);
+ }
+ else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns true if the given value is some ScrollToOptions
+ * @param {number | ScrollToOptions} value
+ * @return {value is ScrollToOptions}
+ */
+ function isScrollToOptions(value) {
+ return value != null && typeof value === "object";
+ }
+
+ /**
+ * Handles a scroll method
+ * @param {Element|Window} element
+ * @param {ScrollMethodName} kind
+ * @param {number | ScrollToOptions} optionsOrX
+ * @param {number} y
+ */
+ function handleScrollMethod(element, kind, optionsOrX, y) {
+ onScrollWithOptions(getScrollToOptionsWithValidation(optionsOrX, y), element, kind);
+ }
+ /**
+ * Invoked when a 'ScrollToOptions' dict is provided to 'scroll()' as the first argument
+ * @param {ScrollToOptions} options
+ * @param {Element|Window} element
+ * @param {ScrollMethodName} kind
+ */
+ function onScrollWithOptions(options, element, kind) {
+ var behavior = getScrollBehavior(element, options);
+ // If the behavior is 'auto' apply instantaneous scrolling
+ if (behavior == null || behavior === "auto") {
+ getOriginalScrollMethodForKind(kind, element).call(element, options.left, options.top);
+ }
+ else {
+ smoothScroll(getSmoothScrollOptions(element, options.left, options.top, kind));
+ }
+ }
+ /**
+ * Normalizes the given scroll coordinates
+ * @param {number?} x
+ * @param {number?} y
+ * @return {Required<Pick<ScrollToOptions, "top" | "left">>}
+ */
+ function normalizeScrollCoordinates(x, y) {
+ return {
+ left: ensureNumeric(x),
+ top: ensureNumeric(y)
+ };
+ }
+ /**
+ * Gets ScrollToOptions based on the given arguments. Will throw if validation fails
+ * @param {number | ScrollToOptions} optionsOrX
+ * @param {number} y
+ * @return {Required<ScrollToOptions>}
+ */
+ function getScrollToOptionsWithValidation(optionsOrX, y) {
+ // If only one argument is given, and it isn't an options object, throw a TypeError
+ if (y === undefined && !isScrollToOptions(optionsOrX)) {
+ throw new TypeError("Failed to execute 'scroll' on 'Element': parameter 1 ('options') is not an object.");
+ }
+ // Scroll based on the primitive values given as arguments
+ if (!isScrollToOptions(optionsOrX)) {
+ return __assign({}, normalizeScrollCoordinates(optionsOrX, y), { behavior: "auto" });
+ }
+ // Scroll based on the received options object
+ else {
+ return __assign({}, normalizeScrollCoordinates(optionsOrX.left, optionsOrX.top), { behavior: optionsOrX.behavior == null ? "auto" : optionsOrX.behavior });
+ }
+ }
+
+ /**
+ * Patches the 'scroll' method on the Element prototype
+ */
+ function patchElementScroll() {
+ Element.prototype.scroll = function (optionsOrX, y) {
+ handleScrollMethod(this, "scroll", optionsOrX, y);
+ };
+ }
+
+ /**
+ * Patches the 'scrollBy' method on the Element prototype
+ */
+ function patchElementScrollBy() {
+ Element.prototype.scrollBy = function (optionsOrX, y) {
+ handleScrollMethod(this, "scrollBy", optionsOrX, y);
+ };
+ }
+
+ /**
+ * Patches the 'scrollTo' method on the Element prototype
+ */
+ function patchElementScrollTo() {
+ Element.prototype.scrollTo = function (optionsOrX, y) {
+ handleScrollMethod(this, "scrollTo", optionsOrX, y);
+ };
+ }
+
+ /**
+ * Patches the 'scroll' method on the Window prototype
+ */
+ function patchWindowScroll() {
+ window.scroll = function (optionsOrX, y) {
+ handleScrollMethod(this, "scroll", optionsOrX, y);
+ };
+ }
+
+ /**
+ * Patches the 'scrollBy' method on the Window prototype
+ */
+ function patchWindowScrollBy() {
+ window.scrollBy = function (optionsOrX, y) {
+ handleScrollMethod(this, "scrollBy", optionsOrX, y);
+ };
+ }
+
+ /**
+ * Patches the 'scrollTo' method on the Window prototype
+ */
+ function patchWindowScrollTo() {
+ window.scrollTo = function (optionsOrX, y) {
+ handleScrollMethod(this, "scrollTo", optionsOrX, y);
+ };
+ }
+
+ // tslint:disable:no-any
+ /**
+ * Gets the parent of an element, taking into account DocumentFragments, ShadowRoots, as well as the root context (window)
+ * @param {EventTarget} currentElement
+ * @returns {EventTarget | null}
+ */
+ function getParent(currentElement) {
+ if ("nodeType" in currentElement && currentElement.nodeType === 1) {
+ return currentElement.parentNode;
+ }
+ if ("ShadowRoot" in window && (currentElement instanceof window.ShadowRoot)) {
+ return currentElement.host;
+ }
+ else if (currentElement === document) {
+ return window;
+ }
+ else if (currentElement instanceof Node)
+ return currentElement.parentNode;
+ return null;
+ }
+
+ var scrollingElement = document.scrollingElement != null ? document.scrollingElement : document.documentElement;
+ /**
+ * Returns true if the given overflow property represents a scrollable overflow value
+ * @param {string | null} overflow
+ * @return {boolean}
+ */
+ function canOverflow(overflow) {
+ return overflow !== "visible" && overflow !== "clip";
+ }
+ /**
+ * Returns true if the given element is scrollable
+ * @param {Element} element
+ * @return {boolean}
+ */
+ function isScrollable(element) {
+ if (element.clientHeight < element.scrollHeight || element.clientWidth < element.scrollWidth) {
+ var style = getComputedStyle(element, null);
+ return (canOverflow(style.overflowY) ||
+ canOverflow(style.overflowX));
+ }
+ return false;
+ }
+ /**
+ * Finds the nearest ancestor of an element that can scroll
+ * @param {Element} target
+ * @returns {Element|Window?}
+ */
+ function findNearestAncestorsWithScrollBehavior(target) {
+ var currentElement = target;
+ while (currentElement != null) {
+ var behavior = getScrollBehavior(currentElement);
+ if (behavior != null && (currentElement === scrollingElement || isScrollable(currentElement))) {
+ return [currentElement, behavior];
+ }
+ var parent_1 = getParent(currentElement);
+ currentElement = parent_1;
+ }
+ // No such element could be found. Start over, but this time find the nearest ancestor that can simply scroll
+ currentElement = target;
+ while (currentElement != null) {
+ if (currentElement === scrollingElement || isScrollable(currentElement)) {
+ return [currentElement, "auto"];
+ }
+ var parent_2 = getParent(currentElement);
+ currentElement = parent_2;
+ }
+ // Default to the scrolling element
+ return [scrollingElement, "auto"];
+ }
+
+ // tslint:disable:no-any
+ /**
+ * Finds the nearest root from an element
+ * @param {Element} target
+ * @returns {Document|ShadowRoot}
+ */
+ function findNearestRoot(target) {
+ var currentElement = target;
+ while (currentElement != null) {
+ if ("ShadowRoot" in window && (currentElement instanceof window.ShadowRoot)) {
+ // Assume this is a ShadowRoot
+ return currentElement;
+ }
+ var parent_1 = getParent(currentElement);
+ if (parent_1 === currentElement) {
+ return document;
+ }
+ currentElement = parent_1;
+ }
+ return document;
+ }
+
+ /**
+ * A Regular expression that matches id's of the form "#[digit]"
+ * @type {RegExp}
+ */
+ var ID_WITH_LEADING_DIGIT_REGEXP = /^#\d/;
+ /**
+ * Catches anchor navigation to IDs within the same root and ensures that they can be smooth-scrolled
+ * if the scroll behavior is smooth in the first rooter within that context
+ */
+ function catchNavigation() {
+ // Listen for 'click' events globally
+ window.addEventListener("click", function (e) {
+ // Only work with trusted events on HTMLAnchorElements
+ if (!e.isTrusted || !(e.target instanceof HTMLAnchorElement))
+ return;
+ var hrefAttributeValue = e.target.getAttribute("href");
+ // Only work with HTMLAnchorElements that navigates to a specific ID
+ if (hrefAttributeValue == null || !hrefAttributeValue.startsWith("#"))
+ return;
+ // Find the nearest root, whether it be a ShadowRoot or the document itself
+ var root = findNearestRoot(e.target);
+ // Attempt to match the selector from that root. querySelector' doesn't support IDs that start with a digit, so work around that limitation
+ var elementMatch = hrefAttributeValue.match(ID_WITH_LEADING_DIGIT_REGEXP) != null
+ ? root.getElementById(hrefAttributeValue.slice(1))
+ : root.querySelector(hrefAttributeValue);
+ // If no selector could be found, don't proceed
+ if (elementMatch == null)
+ return;
+ // Find the nearest ancestor that can be scrolled
+ var _a = __read(findNearestAncestorsWithScrollBehavior(elementMatch), 2), ancestorWithScrollBehavior = _a[0], behavior = _a[1];
+ // If the behavior isn't smooth, don't proceed
+ if (behavior !== "smooth")
+ return;
+ // Otherwise, first prevent the default action.
+ e.preventDefault();
+ // Now, scroll to the element with that ID
+ ancestorWithScrollBehavior.scrollTo({
+ behavior: behavior,
+ top: elementMatch.offsetTop,
+ left: elementMatch.offsetLeft
+ });
+ });
+ }
+
+ var ELEMENT_ORIGINAL_SCROLL_INTO_VIEW = Element.prototype.scrollIntoView;
+
+ /**
+ * The majority of this file is based on https://github.com/stipsan/compute-scroll-into-view (MIT license),
+ * but has been rewritten to accept a scroller as an argument.
+ */
+ /**
+ * Find out which edge to align against when logical scroll position is "nearest"
+ * Interesting fact: "nearest" works similarly to "if-needed", if the element is fully visible it will not scroll it
+ *
+ * Legends:
+ * ┌────────┐ ┏ ━ ━ ━ ┓
+ * │ target │ frame
+ * └────────┘ ┗ ━ ━ ━ ┛
+ */
+ function alignNearest(scrollingEdgeStart, scrollingEdgeEnd, scrollingSize, scrollingBorderStart, scrollingBorderEnd, elementEdgeStart, elementEdgeEnd, elementSize) {
+ /**
+ * If element edge A and element edge B are both outside scrolling box edge A and scrolling box edge B
+ *
+ * ┌──┐
+ * ┏━│━━│━┓
+ * │ │
+ * ┃ │ │ ┃ do nothing
+ * │ │
+ * ┗━│━━│━┛
+ * └──┘
+ *
+ * If element edge C and element edge D are both outside scrolling box edge C and scrolling box edge D
+ *
+ * ┏ ━ ━ ━ ━ ┓
+ * ┌───────────┐
+ * │┃ ┃│ do nothing
+ * └───────────┘
+ * ┗ ━ ━ ━ ━ ┛
+ */
+ if ((elementEdgeStart < scrollingEdgeStart &&
+ elementEdgeEnd > scrollingEdgeEnd) ||
+ (elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd)) {
+ return 0;
+ }
+ /**
+ * If element edge A is outside scrolling box edge A and element height is less than scrolling box height
+ *
+ * ┌──┐
+ * ┏━│━━│━┓ ┏━┌━━┐━┓
+ * └──┘ │ │
+ * from ┃ ┃ to ┃ └──┘ ┃
+ *
+ * ┗━ ━━ ━┛ ┗━ ━━ ━┛
+ *
+ * If element edge B is outside scrolling box edge B and element height is greater than scrolling box height
+ *
+ * ┏━ ━━ ━┓ ┏━┌━━┐━┓
+ * │ │
+ * from ┃ ┌──┐ ┃ to ┃ │ │ ┃
+ * │ │ │ │
+ * ┗━│━━│━┛ ┗━│━━│━┛
+ * │ │ └──┘
+ * │ │
+ * └──┘
+ *
+ * If element edge C is outside scrolling box edge C and element width is less than scrolling box width
+ *
+ * from to
+ * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓
+ * ┌───┐ ┌───┐
+ * │ ┃ │ ┃ ┃ │ ┃
+ * └───┘ └───┘
+ * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛
+ *
+ * If element edge D is outside scrolling box edge D and element width is greater than scrolling box width
+ *
+ * from to
+ * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓
+ * ┌───────────┐ ┌───────────┐
+ * ┃ │ ┃ │ ┃ ┃ │
+ * └───────────┘ └───────────┘
+ * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛
+ */
+ if ((elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize) ||
+ (elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize)) {
+ return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart;
+ }
+ /**
+ * If element edge B is outside scrolling box edge B and element height is less than scrolling box height
+ *
+ * ┏━ ━━ ━┓ ┏━ ━━ ━┓
+ *
+ * from ┃ ┃ to ┃ ┌──┐ ┃
+ * ┌──┐ │ │
+ * ┗━│━━│━┛ ┗━└━━┘━┛
+ * └──┘
+ *
+ * If element edge A is outside scrolling box edge A and element height is greater than scrolling box height
+ *
+ * ┌──┐
+ * │ │
+ * │ │ ┌──┐
+ * ┏━│━━│━┓ ┏━│━━│━┓
+ * │ │ │ │
+ * from ┃ └──┘ ┃ to ┃ │ │ ┃
+ * │ │
+ * ┗━ ━━ ━┛ ┗━└━━┘━┛
+ *
+ * If element edge C is outside scrolling box edge C and element width is greater than scrolling box width
+ *
+ * from to
+ * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓
+ * ┌───────────┐ ┌───────────┐
+ * │ ┃ │ ┃ │ ┃ ┃
+ * └───────────┘ └───────────┘
+ * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛
+ *
+ * If element edge D is outside scrolling box edge D and element width is less than scrolling box width
+ *
+ * from to
+ * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓
+ * ┌───┐ ┌───┐
+ * ┃ │ ┃ │ ┃ │ ┃
+ * └───┘ └───┘
+ * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛
+ *
+ */
+ if ((elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize) ||
+ (elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize)) {
+ return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd;
+ }
+ return 0;
+ }
+ function computeScrollIntoView(target, scroller, options) {
+ var block = options.block, inline = options.inline;
+ // Used to handle the top most element that can be scrolled
+ var scrollingElement = document.scrollingElement || document.documentElement;
+ // Support pinch-zooming properly, making sure elements scroll into the visual viewport
+ // Browsers that don't support visualViewport will report the layout viewport dimensions on document.documentElement.clientWidth/Height
+ // and viewport dimensions on window.innerWidth/Height
+ // https://www.quirksmode.org/mobile/viewports2.html
+ // https://bokand.github.io/viewport/index.html
+ var viewportWidth = window.visualViewport != null
+ ? visualViewport.width
+ : innerWidth;
+ var viewportHeight = window.visualViewport != null
+ ? visualViewport.height
+ : innerHeight;
+ var viewportX = window.scrollX != null ? window.scrollX : window.pageXOffset;
+ var viewportY = window.scrollY != null ? window.scrollY : window.pageYOffset;
+ var _a = target.getBoundingClientRect(), targetHeight = _a.height, targetWidth = _a.width, targetTop = _a.top, targetRight = _a.right, targetBottom = _a.bottom, targetLeft = _a.left;
+ // These values mutate as we loop through and generate scroll coordinates
+ var targetBlock = block === "start" || block === "nearest"
+ ? targetTop
+ : block === "end"
+ ? targetBottom
+ : targetTop + targetHeight / 2; // block === 'center
+ var targetInline = inline === "center"
+ ? targetLeft + targetWidth / 2
+ : inline === "end"
+ ? targetRight
+ : targetLeft; // inline === 'start || inline === 'nearest
+ var _b = scroller.getBoundingClientRect(), height = _b.height, width = _b.width, top = _b.top, right = _b.right, bottom = _b.bottom, left = _b.left;
+ var frameStyle = getComputedStyle(scroller);
+ var borderLeft = parseInt(frameStyle.borderLeftWidth, 10);
+ var borderTop = parseInt(frameStyle.borderTopWidth, 10);
+ var borderRight = parseInt(frameStyle.borderRightWidth, 10);
+ var borderBottom = parseInt(frameStyle.borderBottomWidth, 10);
+ var blockScroll = 0;
+ var inlineScroll = 0;
+ // The property existance checks for offset[Width|Height] is because only HTMLElement objects have them, but any Element might pass by here
+ // @TODO find out if the "as HTMLElement" overrides can be dropped
+ var scrollbarWidth = "offsetWidth" in scroller
+ ? scroller.offsetWidth -
+ scroller.clientWidth -
+ borderLeft -
+ borderRight
+ : 0;
+ var scrollbarHeight = "offsetHeight" in scroller
+ ? scroller.offsetHeight -
+ scroller.clientHeight -
+ borderTop -
+ borderBottom
+ : 0;
+ if (scrollingElement === scroller) {
+ // Handle viewport logic (document.documentElement or document.body)
+ if (block === "start") {
+ blockScroll = targetBlock;
+ }
+ else if (block === "end") {
+ blockScroll = targetBlock - viewportHeight;
+ }
+ else if (block === "nearest") {
+ blockScroll = alignNearest(viewportY, viewportY + viewportHeight, viewportHeight, borderTop, borderBottom, viewportY + targetBlock, viewportY + targetBlock + targetHeight, targetHeight);
+ }
+ else {
+ // block === 'center' is the default
+ blockScroll = targetBlock - viewportHeight / 2;
+ }
+ if (inline === "start") {
+ inlineScroll = targetInline;
+ }
+ else if (inline === "center") {
+ inlineScroll = targetInline - viewportWidth / 2;
+ }
+ else if (inline === "end") {
+ inlineScroll = targetInline - viewportWidth;
+ }
+ else {
+ // inline === 'nearest' is the default
+ inlineScroll = alignNearest(viewportX, viewportX + viewportWidth, viewportWidth, borderLeft, borderRight, viewportX + targetInline, viewportX + targetInline + targetWidth, targetWidth);
+ }
+ // Apply scroll position offsets and ensure they are within bounds
+ // @TODO add more test cases to cover this 100%
+ blockScroll = Math.max(0, blockScroll + viewportY);
+ inlineScroll = Math.max(0, inlineScroll + viewportX);
+ }
+ else {
+ // Handle each scrolling frame that might exist between the target and the viewport
+ if (block === "start") {
+ blockScroll = targetBlock - top - borderTop;
+ }
+ else if (block === "end") {
+ blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight;
+ }
+ else if (block === "nearest") {
+ blockScroll = alignNearest(top, bottom, height, borderTop, borderBottom + scrollbarHeight, targetBlock, targetBlock + targetHeight, targetHeight);
+ }
+ else {
+ // block === 'center' is the default
+ blockScroll = targetBlock - (top + height / 2) + scrollbarHeight / 2;
+ }
+ if (inline === "start") {
+ inlineScroll = targetInline - left - borderLeft;
+ }
+ else if (inline === "center") {
+ inlineScroll = targetInline - (left + width / 2) + scrollbarWidth / 2;
+ }
+ else if (inline === "end") {
+ inlineScroll = targetInline - right + borderRight + scrollbarWidth;
+ }
+ else {
+ // inline === 'nearest' is the default
+ inlineScroll = alignNearest(left, right, width, borderLeft, borderRight + scrollbarWidth, targetInline, targetInline + targetWidth, targetWidth);
+ }
+ var scrollLeft = scroller.scrollLeft, scrollTop = scroller.scrollTop;
+ // Ensure scroll coordinates are not out of bounds while applying scroll offsets
+ blockScroll = Math.max(0, Math.min(scrollTop + blockScroll, scroller.scrollHeight - height + scrollbarHeight));
+ inlineScroll = Math.max(0, Math.min(scrollLeft + inlineScroll, scroller.scrollWidth - width + scrollbarWidth));
+ }
+ return {
+ top: blockScroll,
+ left: inlineScroll
+ };
+ }
+
+ /**
+ * Patches the 'scrollIntoView' method on the Element prototype
+ */
+ function patchElementScrollIntoView() {
+ Element.prototype.scrollIntoView = function (arg) {
+ var normalizedOptions = arg == null || arg === true
+ ? {
+ block: "start",
+ inline: "nearest"
+ }
+ : arg === false
+ ? {
+ block: "end",
+ inline: "nearest"
+ }
+ : arg;
+ // Find the nearest ancestor that can be scrolled
+ var _a = __read(findNearestAncestorsWithScrollBehavior(this), 2), ancestorWithScroll = _a[0], ancestorWithScrollBehavior = _a[1];
+ var behavior = normalizedOptions.behavior != null
+ ? normalizedOptions.behavior
+ : ancestorWithScrollBehavior;
+ // If the behavior isn't smooth, simply invoke the original implementation and do no more
+ if (behavior !== "smooth") {
+ // Assert that 'scrollIntoView' is actually defined
+ if (ELEMENT_ORIGINAL_SCROLL_INTO_VIEW != null) {
+ ELEMENT_ORIGINAL_SCROLL_INTO_VIEW.call(this, normalizedOptions);
+ }
+ // Otherwise, invoke 'scrollTo' instead and provide the scroll coordinates
+ else {
+ var _b = computeScrollIntoView(this, ancestorWithScroll, normalizedOptions), top_1 = _b.top, left = _b.left;
+ getOriginalScrollMethodForKind("scrollTo", this).call(this, left, top_1);
+ }
+ return;
+ }
+ ancestorWithScroll.scrollTo(__assign({ behavior: behavior }, computeScrollIntoView(this, ancestorWithScroll, normalizedOptions)));
+ };
+ }
+
+ var ELEMENT_ORIGINAL_SCROLL_TOP_SET_DESCRIPTOR = Object.getOwnPropertyDescriptor(Element.prototype, "scrollTop").set;
+
+ /**
+ * Patches the 'scrollTop' property descriptor on the Element prototype
+ */
+ function patchElementScrollTop() {
+ Object.defineProperty(Element.prototype, "scrollTop", {
+ set: function (scrollTop) {
+ if (this.__adjustingScrollPosition) {
+ return ELEMENT_ORIGINAL_SCROLL_TOP_SET_DESCRIPTOR.call(this, scrollTop);
+ }
+ handleScrollMethod(this, "scrollTo", this.scrollLeft, scrollTop);
+ return scrollTop;
+ }
+ });
+ }
+
+ var ELEMENT_ORIGINAL_SCROLL_LEFT_SET_DESCRIPTOR = Object.getOwnPropertyDescriptor(Element.prototype, "scrollLeft").set;
+
+ /**
+ * Patches the 'scrollLeft' property descriptor on the Element prototype
+ */
+ function patchElementScrollLeft() {
+ Object.defineProperty(Element.prototype, "scrollLeft", {
+ set: function (scrollLeft) {
+ if (this.__adjustingScrollPosition) {
+ return ELEMENT_ORIGINAL_SCROLL_LEFT_SET_DESCRIPTOR.call(this, scrollLeft);
+ }
+ handleScrollMethod(this, "scrollTo", scrollLeft, this.scrollTop);
+ return scrollLeft;
+ }
+ });
+ }
+
+ /**
+ * Applies the polyfill
+ */
+ function patch() {
+ // Element.prototype methods
+ patchElementScroll();
+ patchElementScrollBy();
+ patchElementScrollTo();
+ patchElementScrollIntoView();
+ // Element.prototype descriptors
+ patchElementScrollLeft();
+ patchElementScrollTop();
+ // window methods
+ patchWindowScroll();
+ patchWindowScrollBy();
+ patchWindowScrollTo();
+ // Navigation
+ catchNavigation();
+ }
+
+ /**
+ * Is true if the browser natively supports the Element.prototype.[scroll|scrollTo|scrollBy|scrollIntoView] methods
+ * @type {boolean}
+ */
+ var SUPPORTS_ELEMENT_PROTOTYPE_SCROLL_METHODS = "scroll" in Element.prototype && "scrollTo" in Element.prototype && "scrollBy" in Element.prototype && "scrollIntoView" in Element.prototype;
+
+ if (!SUPPORTS_SCROLL_BEHAVIOR || !SUPPORTS_ELEMENT_PROTOTYPE_SCROLL_METHODS) {
+ patch();
+ }
+
+}());
+