JAVASCRIPT   100

SmoothScroll.js

Guest on 5th August 2021 05:17:16 PM

  1. //
  2. // SmoothScroll for websites v1.4.0 (Balazs Galambosi)
  3. // http://www.smoothscroll.net/
  4. //
  5. // Licensed under the terms of the MIT license.
  6. //
  7. // You may use it in your theme if you credit me.
  8. // It is also free to use on any individual website.
  9. //
  10. // Exception:
  11. // The only restriction is to not publish any  
  12. // extension for browsers or native application
  13. // without getting a written permission first.
  14. //
  15.  
  16. (function () {
  17.  
  18. // Scroll Variables (tweakable)
  19. var defaultOptions = {
  20.  
  21.     // Scrolling Core
  22.     frameRate        : 150, // [Hz]
  23.     animationTime    : 400, // [ms]
  24.     stepSize         : 100, // [px]
  25.  
  26.     // Pulse (less tweakable)
  27.     // ratio of "tail" to "acceleration"
  28.     pulseAlgorithm   : true,
  29.     pulseScale       : 4,
  30.     pulseNormalize   : 1,
  31.  
  32.     // Acceleration
  33.     accelerationDelta : 50,  // 50
  34.     accelerationMax   : 3,   // 3
  35.  
  36.     // Keyboard Settings
  37.     keyboardSupport   : true,  // option
  38.     arrowScroll       : 50,    // [px]
  39.  
  40.     // Other
  41.     touchpadSupport   : false, // ignore touchpad by default
  42.     fixedBackground   : true,
  43.     excluded          : ''    
  44. };
  45.  
  46. var options = defaultOptions;
  47.  
  48.  
  49. // Other Variables
  50. var isExcluded = false;
  51. var isFrame = false;
  52. var direction = { x: 0, y: 0 };
  53. var initDone  = false;
  54. var root = document.documentElement;
  55. var activeElement;
  56. var observer;
  57. var refreshSize;
  58. var deltaBuffer = [];
  59. var isMac = /^Mac/.test(navigator.platform);
  60.  
  61. var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32,
  62.             pageup: 33, pagedown: 34, end: 35, home: 36 };
  63.  
  64.  
  65. /***********************************************
  66.  * INITIALIZE
  67.  ***********************************************/
  68.  
  69. /**
  70.  * Tests if smooth scrolling is allowed. Shuts down everything if not.
  71.  */
  72. function initTest() {
  73.     if (options.keyboardSupport) {
  74.         addEvent('keydown', keydown);
  75.     }
  76. }
  77.  
  78. /**
  79.  * Sets up scrolls array, determines if frames are involved.
  80.  */
  81. function init() {
  82.  
  83.     if (initDone || !document.body) return;
  84.  
  85.     initDone = true;
  86.  
  87.     var body = document.body;
  88.     var html = document.documentElement;
  89.     var windowHeight = window.innerHeight;
  90.     var scrollHeight = body.scrollHeight;
  91.    
  92.     // check compat mode for root element
  93.     root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
  94.     activeElement = body;
  95.    
  96.     initTest();
  97.  
  98.     // Checks if this script is running in a frame
  99.     if (top != self) {
  100.         isFrame = true;
  101.     }
  102.  
  103.     /**
  104.      * Please duplicate this radar for a Safari fix!
  105.      * rdar://22376037
  106.      * https://openradar.appspot.com/radar?id=4965070979203072
  107.      *
  108.      * Only applies to Safari now, Chrome fixed it in v45:
  109.      * This fixes a bug where the areas left and right to
  110.      * the content does not trigger the onmousewheel event
  111.      * on some pages. e.g.: html, body { height: 100% }
  112.      */
  113.     else if (scrollHeight > windowHeight &&
  114.             (body.offsetHeight <= windowHeight ||
  115.              html.offsetHeight <= windowHeight)) {
  116.  
  117.         var fullPageElem = document.createElement('div');
  118.         fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
  119.                                      'top:0; left:0; right:0; height:' +
  120.                                       root.scrollHeight + 'px';
  121.         document.body.appendChild(fullPageElem);
  122.        
  123.         // DOM changed (throttled) to fix height
  124.         var pendingRefresh;
  125.         refreshSize = function () {
  126.             if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
  127.             pendingRefresh = setTimeout(function () {
  128.                 if (isExcluded) return; // could be running after cleanup
  129.                 fullPageElem.style.height = '0';
  130.                 fullPageElem.style.height = root.scrollHeight + 'px';
  131.                 pendingRefresh = null;
  132.             }, 500); // act rarely to stay fast
  133.         };
  134.  
  135.         setTimeout(refreshSize, 10);
  136.  
  137.         addEvent('resize', refreshSize);
  138.         jQuery(window).on('resize', refreshSize);
  139.  
  140.         // TODO: attributeFilter?
  141.         var config = {
  142.             attributes: true,
  143.             childList: true,
  144.             characterData: false
  145.             // subtree: true
  146.         };
  147.  
  148.         observer = new MutationObserver(refreshSize);
  149.         observer.observe(body, config);
  150.  
  151.         if (root.offsetHeight <= windowHeight) {
  152.             var clearfix = document.createElement('div');  
  153.             clearfix.style.clear = 'both';
  154.             body.appendChild(clearfix);
  155.         }
  156.     }
  157.  
  158.     // disable fixed background
  159.     if (!options.fixedBackground && !isExcluded) {
  160.         body.style.backgroundAttachment = 'scroll';
  161.         html.style.backgroundAttachment = 'scroll';
  162.     }
  163. }
  164.  
  165. /**
  166.  * Removes event listeners and other traces left on the page.
  167.  */
  168. function cleanup() {
  169.     observer && observer.disconnect();
  170.     removeEvent(wheelEvent, wheel);
  171.     removeEvent('mousedown', mousedown);
  172.     removeEvent('keydown', keydown);
  173.     removeEvent('resize', refreshSize);
  174.     removeEvent('load', init);
  175. }
  176.  
  177.  
  178. /************************************************
  179.  * SCROLLING
  180.  ************************************************/
  181.  
  182. var que = [];
  183. var pending = false;
  184. var lastScroll = Date.now();
  185.  
  186. /**
  187.  * Pushes scroll actions to the scrolling queue.
  188.  */
  189. function scrollArray(elem, left, top) {
  190.    
  191.     directionCheck(left, top);
  192.  
  193.     if (options.accelerationMax != 1) {
  194.         var now = Date.now();
  195.         var elapsed = now - lastScroll;
  196.         if (elapsed < options.accelerationDelta) {
  197.             var factor = (1 + (50 / elapsed)) / 2;
  198.             if (factor > 1) {
  199.                 factor = Math.min(factor, options.accelerationMax);
  200.                 left *= factor;
  201.                 top  *= factor;
  202.             }
  203.         }
  204.         lastScroll = Date.now();
  205.     }          
  206.    
  207.     // push a scroll command
  208.     que.push({
  209.         x: left,
  210.         y: top,
  211.         lastX: (left < 0) ? 0.99 : -0.99,
  212.         lastY: (top  < 0) ? 0.99 : -0.99,
  213.         start: Date.now()
  214.     });
  215.        
  216.     // don't act if there's a pending queue
  217.     if (pending) {
  218.         return;
  219.     }  
  220.  
  221.     var scrollWindow = (elem === document.body);
  222.    
  223.     var step = function (time) {
  224.        
  225.         var now = Date.now();
  226.         var scrollX = 0;
  227.         var scrollY = 0;
  228.    
  229.         for (var i = 0; i < que.length; i++) {
  230.            
  231.             var item = que[i];
  232.             var elapsed  = now - item.start;
  233.             var finished = (elapsed >= options.animationTime);
  234.            
  235.             // scroll position: [0, 1]
  236.             var position = (finished) ? 1 : elapsed / options.animationTime;
  237.            
  238.             // easing [optional]
  239.             if (options.pulseAlgorithm) {
  240.                 position = pulse(position);
  241.             }
  242.            
  243.             // only need the difference
  244.             var x = (item.x * position - item.lastX) >> 0;
  245.             var y = (item.y * position - item.lastY) >> 0;
  246.            
  247.             // add this to the total scrolling
  248.             scrollX += x;
  249.             scrollY += y;            
  250.            
  251.             // update last values
  252.             item.lastX += x;
  253.             item.lastY += y;
  254.        
  255.             // delete and step back if it's over
  256.             if (finished) {
  257.                 que.splice(i, 1); i--;
  258.             }          
  259.         }
  260.  
  261.         // scroll left and top
  262.         if (scrollWindow) {
  263.             window.scrollBy(scrollX, scrollY);
  264.         }
  265.         else {
  266.             if (scrollX) elem.scrollLeft += scrollX;
  267.             if (scrollY) elem.scrollTop  += scrollY;                    
  268.         }
  269.        
  270.         // clean up if there's nothing left to do
  271.         if (!left && !top) {
  272.             que = [];
  273.         }
  274.        
  275.         if (que.length) {
  276.             requestFrame(step, elem, (1000 / options.frameRate + 1));
  277.         } else {
  278.             pending = false;
  279.         }
  280.     };
  281.    
  282.     // start a new queue of actions
  283.     requestFrame(step, elem, 0);
  284.     pending = true;
  285. }
  286.  
  287.  
  288. /***********************************************
  289.  * EVENTS
  290.  ***********************************************/
  291.  
  292. /**
  293.  * Mouse wheel handler.
  294.  * @param {Object} event
  295.  */
  296. function wheel(event) {
  297.  
  298.     if (!initDone) {
  299.         init();
  300.     }
  301.    
  302.     var target = event.target;
  303.     var overflowing = overflowingAncestor(target);
  304.  
  305.     // use default if there's no overflowing
  306.     // element or default action is prevented  
  307.     // or it's a zooming event with CTRL
  308.     if (!overflowing || event.defaultPrevented || event.ctrlKey) {
  309.         return true;
  310.     }
  311.    
  312.     // leave embedded content alone (flash & pdf)
  313.     if (isNodeName(activeElement, 'embed') ||
  314.        (isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
  315.        isNodeName(activeElement, 'object')) {
  316.         return true;
  317.     }
  318.  
  319.     var deltaX = -event.wheelDeltaX || event.deltaX || 0;
  320.     var deltaY = -event.wheelDeltaY || event.deltaY || 0;
  321.    
  322.     if (isMac) {
  323.         if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
  324.             deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
  325.         }
  326.         if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
  327.             deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
  328.         }
  329.     }
  330.    
  331.     // use wheelDelta if deltaX/Y is not available
  332.     if (!deltaX && !deltaY) {
  333.         deltaY = -event.wheelDelta || 0;
  334.     }
  335.  
  336.     // line based scrolling (Firefox mostly)
  337.     if (event.deltaMode === 1) {
  338.         deltaX *= 40;
  339.         deltaY *= 40;
  340.     }
  341.    
  342.     // check if it's a touchpad scroll that should be ignored
  343.     if (!options.touchpadSupport && isTouchpad(deltaY)) {
  344.         return true;
  345.     }
  346.  
  347.     // scale by step size
  348.     // delta is 120 most of the time
  349.     // synaptics seems to send 1 sometimes
  350.     if (Math.abs(deltaX) > 1.2) {
  351.         deltaX *= options.stepSize / 120;
  352.     }
  353.     if (Math.abs(deltaY) > 1.2) {
  354.         deltaY *= options.stepSize / 120;
  355.     }
  356.    
  357.     scrollArray(overflowing, deltaX, deltaY);
  358.     event.preventDefault();
  359.     scheduleClearCache();
  360. }
  361.  
  362. /**
  363.  * Keydown event handler.
  364.  * @param {Object} event
  365.  */
  366. function keydown(event) {
  367.  
  368.     var target   = event.target;
  369.     var modifier = event.ctrlKey || event.altKey || event.metaKey ||
  370.                   (event.shiftKey && event.keyCode !== key.spacebar);
  371.    
  372.     // our own tracked active element could've been removed from the DOM
  373.     if (!document.contains(activeElement)) {
  374.         activeElement = document.activeElement;
  375.     }
  376.  
  377.     // do nothing if user is editing text
  378.     // or using a modifier key (except shift)
  379.     // or in a dropdown
  380.     // or inside interactive elements
  381.     var inputNodeNames = /^(textarea|select|embed|object)$/i;
  382.     var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
  383.     if ( inputNodeNames.test(target.nodeName) ||
  384.          isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
  385.          isNodeName(activeElement, 'video') ||
  386.          isInsideYoutubeVideo(event) ||
  387.          target.isContentEditable ||
  388.          event.defaultPrevented   ||
  389.          modifier ) {
  390.       return true;
  391.     }
  392.    
  393.     // spacebar should trigger button press
  394.     if ((isNodeName(target, 'button') ||
  395.          isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
  396.         event.keyCode === key.spacebar) {
  397.       return true;
  398.     }
  399.    
  400.     var shift, x = 0, y = 0;
  401.     var elem = overflowingAncestor(activeElement);
  402.     var clientHeight = elem.clientHeight;
  403.  
  404.     if (elem == document.body) {
  405.         clientHeight = window.innerHeight;
  406.     }
  407.  
  408.     switch (event.keyCode) {
  409.         case key.up:
  410.             y = -options.arrowScroll;
  411.             break;
  412.         case key.down:
  413.             y = options.arrowScroll;
  414.             break;        
  415.         case key.spacebar: // (+ shift)
  416.             shift = event.shiftKey ? 1 : -1;
  417.             y = -shift * clientHeight * 0.9;
  418.             break;
  419.         case key.pageup:
  420.             y = -clientHeight * 0.9;
  421.             break;
  422.         case key.pagedown:
  423.             y = clientHeight * 0.9;
  424.             break;
  425.         case key.home:
  426.             y = -elem.scrollTop;
  427.             break;
  428.         case key.end:
  429.             var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
  430.             y = (damt > 0) ? damt+10 : 0;
  431.             break;
  432.         case key.left:
  433.             x = -options.arrowScroll;
  434.             break;
  435.         case key.right:
  436.             x = options.arrowScroll;
  437.             break;            
  438.         default:
  439.             return true; // a key we don't care about
  440.     }
  441.  
  442.     scrollArray(elem, x, y);
  443.     event.preventDefault();
  444.     scheduleClearCache();
  445. }
  446.  
  447. /**
  448.  * Mousedown event only for updating activeElement
  449.  */
  450. function mousedown(event) {
  451.     activeElement = event.target;
  452. }
  453.  
  454.  
  455. /***********************************************
  456.  * OVERFLOW
  457.  ***********************************************/
  458.  
  459. var uniqueID = (function () {
  460.     var i = 0;
  461.     return function (el) {
  462.         return el.uniqueID || (el.uniqueID = i++);
  463.     };
  464. })();
  465.  
  466. var cache = {}; // cleared out after a scrolling session
  467. var clearCacheTimer;
  468.  
  469. //setInterval(function () { cache = {}; }, 10 * 1000);
  470.  
  471. function scheduleClearCache() {
  472.     clearTimeout(clearCacheTimer);
  473.     clearCacheTimer = setInterval(function () { cache = {}; }, 1*1000);
  474. }
  475.  
  476. function setCache(elems, overflowing) {
  477.     for (var i = elems.length; i--;)
  478.         cache[uniqueID(elems[i])] = overflowing;
  479.     return overflowing;
  480. }
  481.  
  482. //  (body)                (root)
  483. //         | hidden | visible | scroll |  auto  |
  484. // hidden  |   no   |    no   |   YES  |   YES  |
  485. // visible |   no   |   YES   |   YES  |   YES  |
  486. // scroll  |   no   |   YES   |   YES  |   YES  |
  487. // auto    |   no   |   YES   |   YES  |   YES  |
  488.  
  489. function overflowingAncestor(el) {
  490.     var elems = [];
  491.     var body = document.body;
  492.     var rootScrollHeight = root.scrollHeight;
  493.     do {
  494.         var cached = cache[uniqueID(el)];
  495.         if (cached) {
  496.             return setCache(elems, cached);
  497.         }
  498.         elems.push(el);
  499.         if (rootScrollHeight === el.scrollHeight) {
  500.             var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
  501.             var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
  502.             if (isFrame && isContentOverflowing(root) ||
  503.                !isFrame && isOverflowCSS) {
  504.                 return setCache(elems, getScrollRoot());
  505.             }
  506.         } else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
  507.             return setCache(elems, el);
  508.         }
  509.     } while (el = el.parentElement);
  510. }
  511.  
  512. function isContentOverflowing(el) {
  513.     return (el.clientHeight + 10 < el.scrollHeight);
  514. }
  515.  
  516. // typically for <body> and <html>
  517. function overflowNotHidden(el) {
  518.     var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
  519.     return (overflow !== 'hidden');
  520. }
  521.  
  522. // for all other elements
  523. function overflowAutoOrScroll(el) {
  524.     var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
  525.     return (overflow === 'scroll' || overflow === 'auto');
  526. }
  527.  
  528.  
  529. /***********************************************
  530.  * HELPERS
  531.  ***********************************************/
  532.  
  533. function addEvent(type, fn) {
  534.     window.addEventListener(type, fn, false);
  535. }
  536.  
  537. function removeEvent(type, fn) {
  538.     window.removeEventListener(type, fn, false);  
  539. }
  540.  
  541. function isNodeName(el, tag) {
  542.     return (el.nodeName||'').toLowerCase() === tag.toLowerCase();
  543. }
  544.  
  545. function directionCheck(x, y) {
  546.     x = (x > 0) ? 1 : -1;
  547.     y = (y > 0) ? 1 : -1;
  548.     if (direction.x !== x || direction.y !== y) {
  549.         direction.x = x;
  550.         direction.y = y;
  551.         que = [];
  552.         lastScroll = 0;
  553.     }
  554. }
  555.  
  556. var deltaBufferTimer;
  557.  
  558. if (window.localStorage && localStorage.SS_deltaBuffer) {
  559.     deltaBuffer = localStorage.SS_deltaBuffer.split(',');
  560. }
  561.  
  562. function isTouchpad(deltaY) {
  563.     if (!deltaY) return;
  564.     if (!deltaBuffer.length) {
  565.         deltaBuffer = [deltaY, deltaY, deltaY];
  566.     }
  567.     deltaY = Math.abs(deltaY)
  568.     deltaBuffer.push(deltaY);
  569.     deltaBuffer.shift();
  570.     clearTimeout(deltaBufferTimer);
  571.     deltaBufferTimer = setTimeout(function () {
  572.         if (window.localStorage) {
  573.             localStorage.SS_deltaBuffer = deltaBuffer.join(',');
  574.         }
  575.     }, 1000);
  576.     return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100);
  577. }
  578.  
  579. function isDivisible(n, divisor) {
  580.     return (Math.floor(n / divisor) == n / divisor);
  581. }
  582.  
  583. function allDeltasDivisableBy(divisor) {
  584.     return (isDivisible(deltaBuffer[0], divisor) &&
  585.             isDivisible(deltaBuffer[1], divisor) &&
  586.             isDivisible(deltaBuffer[2], divisor));
  587. }
  588.  
  589. function isInsideYoutubeVideo(event) {
  590.     var elem = event.target;
  591.     var isControl = false;
  592.     if (document.URL.indexOf ('www.youtube.com/watch') != -1) {
  593.         do {
  594.             isControl = (elem.classList &&
  595.                          elem.classList.contains('html5-video-controls'));
  596.             if (isControl) break;
  597.         } while (elem = elem.parentNode);
  598.     }
  599.     return isControl;
  600. }
  601.  
  602. var requestFrame = (function () {
  603.       return (window.requestAnimationFrame       ||
  604.               window.webkitRequestAnimationFrame ||
  605.               window.mozRequestAnimationFrame    ||
  606.               function (callback, element, delay) {
  607.                  window.setTimeout(callback, delay || (1000/60));
  608.              });
  609. })();
  610.  
  611. var MutationObserver = (window.MutationObserver ||
  612.                         window.WebKitMutationObserver ||
  613.                         window.MozMutationObserver);  
  614.  
  615. var getScrollRoot = (function() {
  616.   var SCROLL_ROOT;
  617.   return function() {
  618.     if (!SCROLL_ROOT) {
  619.       var dummy = document.createElement('div');
  620.       dummy.style.cssText = 'height:10000px;width:1px;';
  621.       document.body.appendChild(dummy);
  622.       var bodyScrollTop  = document.body.scrollTop;
  623.       var docElScrollTop = document.documentElement.scrollTop;
  624.       window.scrollBy(0, 1);
  625.       if (document.body.scrollTop != bodyScrollTop)
  626.         (SCROLL_ROOT = document.body);
  627.       else
  628.         (SCROLL_ROOT = document.documentElement);
  629.       window.scrollBy(0, -1);
  630.       document.body.removeChild(dummy);
  631.     }
  632.     return SCROLL_ROOT;
  633.   };
  634. })();
  635.  
  636.  
  637. /***********************************************
  638.  * PULSE (by Michael Herf)
  639.  ***********************************************/
  640.  
  641. /**
  642.  * Viscous fluid with a pulse for part and decay for the rest.
  643.  * - Applies a fixed force over an interval (a damped acceleration), and
  644.  * - Lets the exponential bleed away the velocity over a longer interval
  645.  * - Michael Herf, http://stereopsis.com/stopping/
  646.  */
  647. function pulse_(x) {
  648.     var val, start, expx;
  649.     // test
  650.     x = x * options.pulseScale;
  651.     if (x < 1) { // acceleartion
  652.         val = x - (1 - Math.exp(-x));
  653.     } else {     // tail
  654.         // the previous animation ended here:
  655.         start = Math.exp(-1);
  656.         // simple viscous drag
  657.         x -= 1;
  658.         expx = 1 - Math.exp(-x);
  659.         val = start + (expx * (1 - start));
  660.     }
  661.     return val * options.pulseNormalize;
  662. }
  663.  
  664. function pulse(x) {
  665.     if (x >= 1) return 1;
  666.     if (x <= 0) return 0;
  667.  
  668.     if (options.pulseNormalize == 1) {
  669.         options.pulseNormalize /= pulse_(1);
  670.     }
  671.     return pulse_(x);
  672. }
  673.  
  674.  
  675. /***********************************************
  676.  * FIRST RUN
  677.  ***********************************************/
  678.  
  679. var userAgent = window.navigator.userAgent;
  680. var isIE      = /Trident/.test(userAgent);
  681. var isEdge    = /Edge/.test(userAgent); // thank you MS
  682. var isChrome  = /chrome/i.test(userAgent) && !isEdge;
  683. var isSafari  = /safari/i.test(userAgent) && !isEdge;
  684. var isMobile  = /mobile/i.test(userAgent);
  685. var isEnabledForBrowser = (isChrome || isSafari || isEdge ) && !isMobile;
  686.  
  687. var wheelEvent;
  688. if ('onwheel' in document.createElement('div'))
  689.     wheelEvent = 'wheel';
  690. else if ('onmousewheel' in document.createElement('div'))
  691.     wheelEvent = 'mousewheel';
  692.  
  693. if (wheelEvent && isEnabledForBrowser) {
  694.     addEvent(wheelEvent, wheel);
  695.     addEvent('mousedown', mousedown);
  696.     addEvent('load', init);
  697. }
  698.  
  699.  
  700. // alert( userAgent );
  701.  
  702. /***********************************************
  703.  * PUBLIC INTERFACE
  704.  ***********************************************/
  705.  
  706. function SmoothScroll(optionsToSet) {
  707.     for (var key in optionsToSet)
  708.         if (defaultOptions.hasOwnProperty(key))
  709.             options[key] = optionsToSet[key];
  710. }
  711. SmoothScroll.destroy = cleanup;
  712.  
  713. if (window.SmoothScrollOptions) // async API
  714.     SmoothScroll(window.SmoothScrollOptions)
  715.  
  716. if ('object' == typeof exports)
  717.     module.exports = SmoothScroll;
  718. else
  719.     window.SmoothScroll = SmoothScroll;
  720.  
  721. })();

Raw Paste


Login or Register to edit or fork this paste. It's free.