vendor: 13,011 bytes, lines 1-429
1'use strict'; 2 3// polyfill 4function polyfill() { 5 // aliases 6 var w = window; 7 var d = document; 8 9 // return if scroll behavior is supported and polyfill is not forced 10 if ( 11 'scrollBehavior' in d.documentElement.style && 12 w.__forceSmoothScrollPolyfill__ !== true 13 ) { 14 return; 15 } 16 17 // globals 18 var Element = w.HTMLElement || w.Element; 19 var SCROLL_TIME = 468; 20 21 // object gathering original scroll methods 22 var original = { 23 scroll: w.scroll || w.scrollTo, 24 scrollBy: w.scrollBy, 25 elementScroll: Element.prototype.scroll || scrollElement, 26 scrollIntoView: Element.prototype.scrollIntoView 27 }; 28 29 // define timing method 30 var now = 31 w.performance && w.performance.now 32 ? w.performance.now.bind(w.performance) 33 : Date.now; 34 35 /** 36 * indicates if a the current browser is made by Microsoft 37 * @method isMicrosoftBrowser 38 * @param {String} userAgent 39 * @returns {Boolean} 40 */ 41 function isMicrosoftBrowser(userAgent) { 42 var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/']; 43 44 return new RegExp(userAgentPatterns.join('|')).test(userAgent); 45 } 46 47 /* 48 * IE has rounding bug rounding down clientHeight and clientWidth and 49 * rounding up scrollHeight and scrollWidth causing false positives 50 * on hasScrollableSpace 51 */ 52 var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0; 53 54 /** 55 * changes scroll position inside an element 56 * @method scrollElement 57 * @param {Number} x 58 * @param {Number} y 59 * @returns {undefined} 60 */ 61 function scrollElement(x, y) { 62 this.scrollLeft = x; 63 this.scrollTop = y; 64 } 65 66 /** 67 * returns result of applying ease math function to a number 68 * @method ease 69 * @param {Number} k 70 * @returns {Number} 71 */ 72 function ease(k) { 73 return 0.5 * (1 - Math.cos(Math.PI * k)); 74 } 75 76 /** 77 * indicates if a smooth behavior should be applied 78 * @method shouldBailOut 79 * @param {Number|Object} firstArg 80 * @returns {Boolean} 81 */ 82 function shouldBailOut(firstArg) { 83 if ( 84 firstArg === null || 85 typeof firstArg !== 'object' || 86 firstArg.behavior === undefined || 87 firstArg.behavior === 'auto' || 88 firstArg.behavior === 'instant' 89 ) { 90 // first argument is not an object/null 91 // or behavior is auto, instant or undefined 92 return true; 93 } 94 95 if (typeof firstArg === 'object' && firstArg.behavior === 'smooth') { 96 // first argument is an object and behavior is smooth 97 return false; 98 } 99 100 // throw error when behavior is not supported 101 throw new TypeError( 102 'behavior member of ScrollOptions ' + 103 firstArg.behavior + 104 ' is not a valid value for enumeration ScrollBehavior.' 105 ); 106 } 107 108 /** 109 * indicates if an element has scrollable space in the provided axis 110 * @method hasScrollableSpace 111 * @param {Node} el 112 * @param {String} axis 113 * @returns {Boolean} 114 */ 115 function hasScrollableSpace(el, axis) { 116 if (axis === 'Y') { 117 return el.clientHeight + ROUNDING_TOLERANCE < el.scrollHeight; 118 } 119 120 if (axis === 'X') { 121 return el.clientWidth + ROUNDING_TOLERANCE < el.scrollWidth; 122 } 123 } 124 125 /** 126 * indicates if an element has a scrollable overflow property in the axis 127 * @method canOverflow 128 * @param {Node} el 129 * @param {String} axis 130 * @returns {Boolean} 131 */ 132 function canOverflow(el, axis) { 133 var overflowValue = w.getComputedStyle(el, null)['overflow' + axis]; 134 135 return overflowValue === 'auto' || overflowValue === 'scroll'; 136 } 137 138 /** 139 * indicates if an element can be scrolled in either axis 140 * @method isScrollable 141 * @param {Node} el 142 * @param {String} axis 143 * @returns {Boolean} 144 */ 145 function isScrollable(el) { 146 var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y'); 147 var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X'); 148 149 return isScrollableY || isScrollableX; 150 } 151 152 /** 153 * finds scrollable parent of an element 154 * @method findScrollableParent 155 * @param {Node} el 156 * @returns {Node} el 157 */ 158 function findScrollableParent(el) { 159 while (el !== d.body && isScrollable(el) === false) { 160 el = el.parentNode || el.host; 161 } 162 163 return el; 164 } 165 166 /** 167 * self invoked function that, given a context, steps through scrolling 168 * @method step 169 * @param {Object} context 170 * @returns {undefined} 171 */ 172 function step(context) { 173 var time = now(); 174 var value; 175 var currentX; 176 var currentY; 177 var elapsed = (time - context.startTime) / SCROLL_TIME; 178 179 // avoid elapsed times higher than one 180 elapsed = elapsed > 1 ? 1 : elapsed; 181 182 // apply easing to elapsed time 183 value = ease(elapsed); 184 185 currentX = context.startX + (context.x - context.startX) * value; 186 currentY = context.startY + (context.y - context.startY) * value; 187 188 context.method.call(context.scrollable, currentX, currentY); 189 190 // scroll more if we have not reached our destination 191 if (currentX !== context.x || currentY !== context.y) { 192 w.requestAnimationFrame(step.bind(w, context)); 193 } 194 } 195 196 /** 197 * scrolls window or element with a smooth behavior 198 * @method smoothScroll 199 * @param {Object|Node} el 200 * @param {Number} x 201 * @param {Number} y 202 * @returns {undefined} 203 */ 204 function smoothScroll(el, x, y) { 205 var scrollable; 206 var startX; 207 var startY; 208 var method; 209 var startTime = now(); 210 211 // define scroll context 212 if (el === d.body) { 213 scrollable = w; 214 startX = w.scrollX || w.pageXOffset; 215 startY = w.scrollY || w.pageYOffset; 216 method = original.scroll; 217 } else { 218 scrollable = el; 219 startX = el.scrollLeft; 220 startY = el.scrollTop; 221 method = scrollElement; 222 } 223 224 // scroll looping over a frame 225 step({ 226 scrollable: scrollable, 227 method: method, 228 startTime: startTime, 229 startX: startX, 230 startY: startY, 231 x: x, 232 y: y 233 }); 234 } 235 236 // ORIGINAL METHODS OVERRIDES 237 // w.scroll and w.scrollTo 238 w.scroll = w.scrollTo = function() { 239 // avoid action when no arguments are passed 240 if (arguments[0] === undefined) { 241 return; 242 } 243 244 // avoid smooth behavior if not required 245 if (shouldBailOut(arguments[0]) === true) { 246 original.scroll.call( 247 w, 248 arguments[0].left !== undefined 249 ? arguments[0].left 250 : typeof arguments[0] !== 'object' 251 ? arguments[0] 252 : w.scrollX || w.pageXOffset, 253 // use top prop, second argument if present or fallback to scrollY 254 arguments[0].top !== undefined 255 ? arguments[0].top 256 : arguments[1] !== undefined 257 ? arguments[1] 258 : w.scrollY || w.pageYOffset 259 ); 260 261 return; 262 } 263 264 // LET THE SMOOTHNESS BEGIN! 265 smoothScroll.call( 266 w, 267 d.body, 268 arguments[0].left !== undefined 269 ? ~~arguments[0].left 270 : w.scrollX || w.pageXOffset, 271 arguments[0].top !== undefined 272 ? ~~arguments[0].top 273 : w.scrollY || w.pageYOffset 274 ); 275 }; 276 277 // w.scrollBy 278 w.scrollBy = function() { 279 // avoid action when no arguments are passed 280 if (arguments[0] === undefined) { 281 return; 282 } 283 284 // avoid smooth behavior if not required 285 if (shouldBailOut(arguments[0])) { 286 original.scrollBy.call( 287 w, 288 arguments[0].left !== undefined 289 ? arguments[0].left 290 : typeof arguments[0] !== 'object' ? arguments[0] : 0, 291 arguments[0].top !== undefined 292 ? arguments[0].top 293 : arguments[1] !== undefined ? arguments[1] : 0 294 ); 295 296 return; 297 } 298 299 // LET THE SMOOTHNESS BEGIN! 300 smoothScroll.call( 301 w, 302 d.body, 303 ~~arguments[0].left + (w.scrollX || w.pageXOffset), 304 ~~arguments[0].top + (w.scrollY || w.pageYOffset) 305 ); 306 }; 307 308 // Element.prototype.scroll and Element.prototype.scrollTo 309 Element.prototype.scroll = Element.prototype.scrollTo = function() { 310 // avoid action when no arguments are passed 311 if (arguments[0] === undefined) { 312 return; 313 } 314 315 // avoid smooth behavior if not required 316 if (shouldBailOut(arguments[0]) === true) { 317 // if one number is passed, throw error to match Firefox implementation 318 if (typeof arguments[0] === 'number' && arguments[1] === undefined) { 319 throw new SyntaxError('Value could not be converted'); 320 } 321 322 original.elementScroll.call( 323 this, 324 // use left prop, first number argument or fallback to scrollLeft 325 arguments[0].left !== undefined 326 ? ~~arguments[0].left 327 : typeof arguments[0] !== 'object' ? ~~arguments[0] : this.scrollLeft, 328 // use top prop, second argument or fallback to scrollTop 329 arguments[0].top !== undefined 330 ? ~~arguments[0].top 331 : arguments[1] !== undefined ? ~~arguments[1] : this.scrollTop 332 ); 333 334 return; 335 } 336 337 var left = arguments[0].left; 338 var top = arguments[0].top; 339 340 // LET THE SMOOTHNESS BEGIN! 341 smoothScroll.call( 342 this, 343 this, 344 typeof left === 'undefined' ? this.scrollLeft : ~~left, 345 typeof top === 'undefined' ? this.scrollTop : ~~top 346 ); 347 }; 348 349 // Element.prototype.scrollBy 350 Element.prototype.scrollBy = function() { 351 // avoid action when no arguments are passed 352 if (arguments[0] === undefined) { 353 return; 354 } 355 356 // avoid smooth behavior if not required 357 if (shouldBailOut(arguments[0]) === true) { 358 original.elementScroll.call( 359 this, 360 arguments[0].left !== undefined 361 ? ~~arguments[0].left + this.scrollLeft 362 : ~~arguments[0] + this.scrollLeft, 363 arguments[0].top !== undefined 364 ? ~~arguments[0].top + this.scrollTop 365 : ~~arguments[1] + this.scrollTop 366 ); 367 368 return; 369 } 370 371 this.scroll({ 372 left: ~~arguments[0].left + this.scrollLeft, 373 top: ~~arguments[0].top + this.scrollTop, 374 behavior: arguments[0].behavior 375 }); 376 }; 377 378 // Element.prototype.scrollIntoView 379 Element.prototype.scrollIntoView = function() { 380 // avoid smooth behavior if not required 381 if (shouldBailOut(arguments[0]) === true) { 382 original.scrollIntoView.call( 383 this, 384 arguments[0] === undefined ? true : arguments[0] 385 ); 386 387 return; 388 } 389 390 // LET THE SMOOTHNESS BEGIN! 391 var scrollableParent = findScrollableParent(this); 392 var parentRects = scrollableParent.getBoundingClientRect(); 393 var clientRects = this.getBoundingClientRect(); 394 395 if (scrollableParent !== d.body) { 396 // reveal element inside parent 397 smoothScroll.call( 398 this, 399 scrollableParent, 400 scrollableParent.scrollLeft + clientRects.left - parentRects.left, 401 scrollableParent.scrollTop + clientRects.top - parentRects.top 402 ); 403 404 // reveal parent in viewport unless is fixed 405 if (w.getComputedStyle(scrollableParent).position !== 'fixed') { 406 w.scrollBy({ 407 left: parentRects.left, 408 top: parentRects.top, 409 behavior: 'smooth' 410 }); 411 } 412 } else { 413 // reveal element in viewport 414 w.scrollBy({ 415 left: clientRects.left, 416 top: clientRects.top, 417 behavior: 'smooth' 418 }); 419 } 420 }; 421} 422 423if (typeof exports === 'object' && typeof module !== 'undefined') { 424 // commonjs 425 module.exports = { polyfill: polyfill }; 426} else { 427 // global 428 polyfill(); 429}
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.