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