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