vendor: 19,263 bytes, lines 1-629
1/*! SmoothScroll v16.1.4 | (c) 2020 Chris Ferdinandi | MIT License | http://github.com/cferdinandi/smooth-scroll */ 2(function (global, factory) { 3 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 4 typeof define === 'function' && define.amd ? define(factory) : 5 (global = global || self, global.SmoothScroll = factory()); 6}(this, (function () { 'use strict'; 7 8 // 9 // Default settings 10 // 11 12 var defaults = { 13 14 // Selectors 15 ignore: '[data-scroll-ignore]', 16 header: null, 17 topOnEmptyHash: true, 18 19 // Speed & Duration 20 speed: 500, 21 speedAsDuration: false, 22 durationMax: null, 23 durationMin: null, 24 clip: true, 25 offset: 0, 26 27 // Easing 28 easing: 'easeInOutCubic', 29 customEasing: null, 30 31 // History 32 updateURL: true, 33 popstate: true, 34 35 // Custom Events 36 emitEvents: true 37 38 }; 39 40 41 // 42 // Utility Methods 43 // 44 45 /** 46 * Check if browser supports required methods 47 * @return {Boolean} Returns true if all required methods are supported 48 */ 49 var supports = function () { 50 return ( 51 'querySelector' in document && 52 'addEventListener' in window && 53 'requestAnimationFrame' in window && 54 'closest' in window.Element.prototype 55 ); 56 }; 57 58 /** 59 * Merge two or more objects together. 60 * @param {Object} objects The objects to merge together 61 * @returns {Object} Merged values of defaults and options 62 */ 63 var extend = function () { 64 var merged = {}; 65 Array.prototype.forEach.call(arguments, function (obj) { 66 for (var key in obj) { 67 if (!obj.hasOwnProperty(key)) return; 68 merged[key] = obj[key]; 69 } 70 }); 71 return merged; 72 }; 73 74 /** 75 * Check to see if user prefers reduced motion 76 * @param {Object} settings Script settings 77 */ 78 var reduceMotion = function () { 79 if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) { 80 return true; 81 } 82 return false; 83 }; 84 85 /** 86 * Get the height of an element. 87 * @param {Node} elem The element to get the height of 88 * @return {Number} The element's height in pixels 89 */ 90 var getHeight = function (elem) { 91 return parseInt(window.getComputedStyle(elem).height, 10); 92 }; 93 94 /** 95 * Escape special characters for use with querySelector 96 * @author Mathias Bynens 97 * @link https://github.com/mathiasbynens/CSS.escape 98 * @param {String} id The anchor ID to escape 99 */ 100 var escapeCharacters = function (id) { 101 102 // Remove leading hash 103 if (id.charAt(0) === '#') { 104 id = id.substr(1); 105 } 106 107 var string = String(id); 108 var length = string.length; 109 var index = -1; 110 var codeUnit; 111 var result = ''; 112 var firstCodeUnit = string.charCodeAt(0); 113 while (++index < length) { 114 codeUnit = string.charCodeAt(index); 115 // Note: thereâs no need to special-case astral symbols, surrogate 116 // pairs, or lone surrogates. 117 118 // If the character is NULL (U+0000), then throw an 119 // `InvalidCharacterError` exception and terminate these steps. 120 if (codeUnit === 0x0000) { 121 throw new InvalidCharacterError( 122 'Invalid character: the input contains U+0000.' 123 ); 124 } 125 126 if ( 127 // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is 128 // U+007F, [â¦] 129 (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || 130 // If the character is the first character and is in the range [0-9] 131 // (U+0030 to U+0039), [â¦] 132 (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || 133 // If the character is the second character and is in the range [0-9] 134 // (U+0030 to U+0039) and the first character is a `-` (U+002D), [â¦] 135 ( 136 index === 1 && 137 codeUnit >= 0x0030 && codeUnit <= 0x0039 && 138 firstCodeUnit === 0x002D 139 ) 140 ) { 141 // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point 142 result += '\\' + codeUnit.toString(16) + ' '; 143 continue; 144 } 145 146 // If the character is not handled by one of the above rules and is 147 // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or 148 // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to 149 // U+005A), or [a-z] (U+0061 to U+007A), [â¦] 150 if ( 151 codeUnit >= 0x0080 || 152 codeUnit === 0x002D || 153 codeUnit === 0x005F || 154 codeUnit >= 0x0030 && codeUnit <= 0x0039 || 155 codeUnit >= 0x0041 && codeUnit <= 0x005A || 156 codeUnit >= 0x0061 && codeUnit <= 0x007A 157 ) { 158 // the character itself 159 result += string.charAt(index); 160 continue; 161 } 162 163 // Otherwise, the escaped character. 164 // http://dev.w3.org/csswg/cssom/#escape-a-character 165 result += '\\' + string.charAt(index); 166 167 } 168 169 // Return sanitized hash 170 return '#' + result; 171 172 }; 173 174 /** 175 * Calculate the easing pattern 176 * @link https://gist.github.com/gre/1650294 177 * @param {Object} settings Easing pattern 178 * @param {Number} time Time animation should take to complete 179 * @returns {Number} 180 */ 181 var easingPattern = function (settings, time) { 182 var pattern; 183 184 // Default Easing Patterns 185 if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity 186 if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity 187 if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration 188 if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity 189 if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity 190 if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration 191 if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity 192 if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity 193 if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration 194 if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity 195 if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity 196 if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration 197 198 // Custom Easing Patterns 199 if (!!settings.customEasing) pattern = settings.customEasing(time); 200 201 return pattern || time; // no easing, no acceleration 202 }; 203 204 /** 205 * Determine the document's height 206 * @returns {Number} 207 */ 208 var getDocumentHeight = function () { 209 return Math.max( 210 document.body.scrollHeight, document.documentElement.scrollHeight, 211 document.body.offsetHeight, document.documentElement.offsetHeight, 212 document.body.clientHeight, document.documentElement.clientHeight 213 ); 214 }; 215 216 /** 217 * Calculate how far to scroll 218 * Clip support added by robjtede - https://github.com/cferdinandi/smooth-scroll/issues/405 219 * @param {Element} anchor The anchor element to scroll to 220 * @param {Number} headerHeight Height of a fixed header, if any 221 * @param {Number} offset Number of pixels by which to offset scroll 222 * @param {Boolean} clip If true, adjust scroll distance to prevent abrupt stops near the bottom of the page 223 * @returns {Number} 224 */ 225 var getEndLocation = function (anchor, headerHeight, offset, clip) { 226 var location = 0; 227 if (anchor.offsetParent) { 228 do { 229 location += anchor.offsetTop; 230 anchor = anchor.offsetParent; 231 } while (anchor); 232 } 233 location = Math.max(location - headerHeight - offset, 0); 234 if (clip) { 235 location = Math.min(location, getDocumentHeight() - window.innerHeight); 236 } 237 return location; 238 }; 239 240 /** 241 * Get the height of the fixed header 242 * @param {Node} header The header 243 * @return {Number} The height of the header 244 */ 245 var getHeaderHeight = function (header) { 246 return !header ? 0 : (getHeight(header) + header.offsetTop); 247 }; 248 249 /** 250 * Calculate the speed to use for the animation 251 * @param {Number} distance The distance to travel 252 * @param {Object} settings The plugin settings 253 * @return {Number} How fast to animate 254 */ 255 var getSpeed = function (distance, settings) { 256 var speed = settings.speedAsDuration ? settings.speed : Math.abs(distance / 1000 * settings.speed); 257 if (settings.durationMax && speed > settings.durationMax) return settings.durationMax; 258 if (settings.durationMin && speed < settings.durationMin) return settings.durationMin; 259 return parseInt(speed, 10); 260 }; 261 262 var setHistory = function (options) { 263 264 // Make sure this should run 265 if (!history.replaceState || !options.updateURL || history.state) return; 266 267 // Get the hash to use 268 var hash = window.location.hash; 269 hash = hash ? hash : ''; 270 271 // Set a default history 272 history.replaceState( 273 { 274 smoothScroll: JSON.stringify(options), 275 anchor: hash ? hash : window.pageYOffset 276 }, 277 document.title, 278 hash ? hash : window.location.href 279 ); 280 281 }; 282 283 /** 284 * Update the URL 285 * @param {Node} anchor The anchor that was scrolled to 286 * @param {Boolean} isNum If true, anchor is a number 287 * @param {Object} options Settings for Smooth Scroll 288 */ 289 var updateURL = function (anchor, isNum, options) { 290 291 // Bail if the anchor is a number 292 if (isNum) return; 293 294 // Verify that pushState is supported and the updateURL option is enabled 295 if (!history.pushState || !options.updateURL) return; 296 297 // Update URL 298 history.pushState( 299 { 300 smoothScroll: JSON.stringify(options), 301 anchor: anchor.id 302 }, 303 document.title, 304 anchor === document.documentElement ? '#top' : '#' + anchor.id 305 ); 306 307 }; 308 309 /** 310 * Bring the anchored element into focus 311 * @param {Node} anchor The anchor element 312 * @param {Number} endLocation The end location to scroll to 313 * @param {Boolean} isNum If true, scroll is to a position rather than an element 314 */ 315 var adjustFocus = function (anchor, endLocation, isNum) { 316 317 // Is scrolling to top of page, blur 318 if (anchor === 0) { 319 document.body.focus(); 320 } 321 322 // Don't run if scrolling to a number on the page 323 if (isNum) return; 324 325 // Otherwise, bring anchor element into focus 326 anchor.focus(); 327 if (document.activeElement !== anchor) { 328 anchor.setAttribute('tabindex', '-1'); 329 anchor.focus(); 330 anchor.style.outline = 'none'; 331 } 332 window.scrollTo(0 , endLocation); 333 334 }; 335 336 /** 337 * Emit a custom event 338 * @param {String} type The event type 339 * @param {Object} options The settings object 340 * @param {Node} anchor The anchor element 341 * @param {Node} toggle The toggle element 342 */ 343 var emitEvent = function (type, options, anchor, toggle) { 344 if (!options.emitEvents || typeof window.CustomEvent !== 'function') return; 345 var event = new CustomEvent(type, { 346 bubbles: true, 347 detail: { 348 anchor: anchor, 349 toggle: toggle 350 } 351 }); 352 document.dispatchEvent(event); 353 }; 354 355 356 // 357 // SmoothScroll Constructor 358 // 359 360 var SmoothScroll = function (selector, options) { 361 362 // 363 // Variables 364 // 365 366 var smoothScroll = {}; // Object for public APIs 367 var settings, toggle, fixedHeader, animationInterval; 368 369 370 // 371 // Methods 372 // 373 374 /** 375 * Cancel a scroll-in-progress 376 */ 377 smoothScroll.cancelScroll = function (noEvent) { 378 cancelAnimationFrame(animationInterval); 379 animationInterval = null; 380 if (noEvent) return; 381 emitEvent('scrollCancel', settings); 382 }; 383 384 /** 385 * Start/stop the scrolling animation 386 * @param {Node|Number} anchor The element or position to scroll to 387 * @param {Element} toggle The element that toggled the scroll event 388 * @param {Object} options 389 */ 390 smoothScroll.animateScroll = function (anchor, toggle, options) { 391 392 // Cancel any in progress scrolls 393 smoothScroll.cancelScroll(); 394 395 // Local settings 396 var _settings = extend(settings || defaults, options || {}); // Merge user options with defaults 397 398 // Selectors and variables 399 var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false; 400 var anchorElem = isNum || !anchor.tagName ? null : anchor; 401 if (!isNum && !anchorElem) return; 402 var startLocation = window.pageYOffset; // Current location on the page 403 if (_settings.header && !fixedHeader) { 404 // Get the fixed header if not already set 405 fixedHeader = document.querySelector(_settings.header); 406 } 407 var headerHeight = getHeaderHeight(fixedHeader); 408 var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof _settings.offset === 'function' ? _settings.offset(anchor, toggle) : _settings.offset), 10), _settings.clip); // Location to scroll to 409 var distance = endLocation - startLocation; // distance to travel 410 var documentHeight = getDocumentHeight(); 411 var timeLapsed = 0; 412 var speed = getSpeed(distance, _settings); 413 var start, percentage, position; 414 415 /** 416 * Stop the scroll animation when it reaches its target (or the bottom/top of page) 417 * @param {Number} position Current position on the page 418 * @param {Number} endLocation Scroll to location 419 * @param {Number} animationInterval How much to scroll on this loop 420 */ 421 var stopAnimateScroll = function (position, endLocation) { 422 423 // Get the current location 424 var currentLocation = window.pageYOffset; 425 426 // Check if the end location has been reached yet (or we've hit the end of the document) 427 if (position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight)) { 428 429 // Clear the animation timer 430 smoothScroll.cancelScroll(true); 431 432 // Bring the anchored element into focus 433 adjustFocus(anchor, endLocation, isNum); 434 435 // Emit a custom event 436 emitEvent('scrollStop', _settings, anchor, toggle); 437 438 // Reset start 439 start = null; 440 animationInterval = null; 441 442 return true; 443 444 } 445 }; 446 447 /** 448 * Loop scrolling animation 449 */ 450 var loopAnimateScroll = function (timestamp) { 451 if (!start) { start = timestamp; } 452 timeLapsed += timestamp - start; 453 percentage = speed === 0 ? 0 : (timeLapsed / speed); 454 percentage = (percentage > 1) ? 1 : percentage; 455 position = startLocation + (distance * easingPattern(_settings, percentage)); 456 window.scrollTo(0, Math.floor(position)); 457 if (!stopAnimateScroll(position, endLocation)) { 458 animationInterval = window.requestAnimationFrame(loopAnimateScroll); 459 start = timestamp; 460 } 461 }; 462 463 /** 464 * Reset position to fix weird iOS bug 465 * @link https://github.com/cferdinandi/smooth-scroll/issues/45 466 */ 467 if (window.pageYOffset === 0) { 468 window.scrollTo(0, 0); 469 } 470 471 // Update the URL 472 updateURL(anchor, isNum, _settings); 473 474 // If the user prefers reduced motion, jump to location 475 if (reduceMotion()) { 476 adjustFocus(anchor, Math.floor(endLocation), false); 477 return; 478 } 479 480 // Emit a custom event 481 emitEvent('scrollStart', _settings, anchor, toggle); 482 483 // Start scrolling animation 484 smoothScroll.cancelScroll(true); 485 window.requestAnimationFrame(loopAnimateScroll); 486 487 }; 488 489 /** 490 * If smooth scroll element clicked, animate scroll 491 */ 492 var clickHandler = function (event) { 493 494 // Don't run if event was canceled but still bubbled up 495 // By @mgreter - https://github.com/cferdinandi/smooth-scroll/pull/462/ 496 if (event.defaultPrevented) return; 497 498 // Don't run if right-click or command/control + click or shift + click 499 if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey) return; 500 501 // Check if event.target has closest() method 502 // By @totegi - https://github.com/cferdinandi/smooth-scroll/pull/401/ 503 if (!('closest' in event.target)) return; 504 505 // Check if a smooth scroll link was clicked 506 toggle = event.target.closest(selector); 507 if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return; 508 509 // Only run if link is an anchor and points to the current page 510 if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return; 511 512 // Get an escaped version of the hash 513 var hash; 514 try { 515 hash = escapeCharacters(decodeURIComponent(toggle.hash)); 516 } catch(e) { 517 hash = escapeCharacters(toggle.hash); 518 } 519 520 // Get the anchored element 521 var anchor; 522 if (hash === '#') { 523 if (!settings.topOnEmptyHash) return; 524 anchor = document.documentElement; 525 } else { 526 anchor = document.querySelector(hash); 527 } 528 anchor = !anchor && hash === '#top' ? document.documentElement : anchor; 529 530 // If anchored element exists, scroll to it 531 if (!anchor) return; 532 event.preventDefault(); 533 setHistory(settings); 534 smoothScroll.animateScroll(anchor, toggle); 535 536 }; 537 538 /** 539 * Animate scroll on popstate events 540 */ 541 var popstateHandler = function () { 542 543 // Stop if history.state doesn't exist (ex. if clicking on a broken anchor link). 544 // fixes `Cannot read property 'smoothScroll' of null` error getting thrown. 545 if (history.state === null) return; 546 547 // Only run if state is a popstate record for this instantiation 548 if (!history.state.smoothScroll || history.state.smoothScroll !== JSON.stringify(settings)) return; 549 550 // Get the anchor 551 var anchor = history.state.anchor; 552 if (typeof anchor === 'string' && anchor) { 553 anchor = document.querySelector(escapeCharacters(history.state.anchor)); 554 if (!anchor) return; 555 } 556 557 // Animate scroll to anchor link 558 smoothScroll.animateScroll(anchor, null, {updateURL: false}); 559 560 }; 561 562 /** 563 * Destroy the current initialization. 564 */ 565 smoothScroll.destroy = function () { 566 567 // If plugin isn't already initialized, stop 568 if (!settings) return; 569 570 // Remove event listeners 571 document.removeEventListener('click', clickHandler, false); 572 window.removeEventListener('popstate', popstateHandler, false); 573 574 // Cancel any scrolls-in-progress 575 smoothScroll.cancelScroll(); 576 577 // Reset variables 578 settings = null; 579 toggle = null; 580 fixedHeader = null; 581 animationInterval = null; 582 583 }; 584 585 /** 586 * Initialize Smooth Scroll 587 * @param {Object} options User settings 588 */ 589 var init = function () { 590 591 // feature test 592 if (!supports()) throw 'Smooth Scroll: This browser does not support the required JavaScript methods and browser APIs.'; 593 594 // Destroy any existing initializations 595 smoothScroll.destroy(); 596 597 // Selectors and variables 598 settings = extend(defaults, options || {}); // Merge user options with defaults 599 fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header 600 601 // When a toggle is clicked, run the click handler 602 document.addEventListener('click', clickHandler, false); 603 604 // If updateURL and popState are enabled, listen for pop events 605 if (settings.updateURL && settings.popstate) { 606 window.addEventListener('popstate', popstateHandler, false); 607 } 608 609 }; 610 611 612 // 613 // Initialize plugin 614 // 615 616 init(); 617 618 619 // 620 // Public APIs 621 // 622 623 return smoothScroll; 624 625 }; 626 627 return SmoothScroll; 628 629})));
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.