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