vendor: 10,456 bytes, lines 1-426
1/*! 2 * headroom.js v0.10.3 - Give your page some headroom. Hide your header until you need it 3 * Copyright (c) 2019 Nick Williams - http://wicky.nillia.ms/headroom.js 4 * License: MIT 5 */ 6 7(function (global, factory) { 8 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 9 typeof define === 'function' && define.amd ? define(factory) : 10 (global = global || self, global.Headroom = factory()); 11}(this, function () { 'use strict'; 12 13 function isBrowser() { 14 return typeof window !== "undefined"; 15 } 16 17 /** 18 * Used to detect browser support for adding an event listener with options 19 * Credit: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener 20 */ 21 function passiveEventsSupported() { 22 var supported = false; 23 24 try { 25 var options = { 26 // eslint-disable-next-line getter-return 27 get passive() { 28 supported = true; 29 } 30 }; 31 window.addEventListener("test", options, options); 32 window.removeEventListener("test", options, options); 33 } catch (err) { 34 supported = false; 35 } 36 37 return supported; 38 } 39 40 function isSupported() { 41 return !!( 42 isBrowser() && 43 function() {}.bind && 44 "classList" in document.documentElement && 45 Object.assign && 46 Object.keys && 47 requestAnimationFrame 48 ); 49 } 50 51 function isDocument(obj) { 52 return obj.nodeType === 9; // Node.DOCUMENT_NODE === 9 53 } 54 55 function isWindow(obj) { 56 // `obj === window` or `obj instanceof Window` is not sufficient, 57 // as the obj may be the window of an iframe. 58 return obj && obj.document && isDocument(obj.document); 59 } 60 61 function windowScroller(win) { 62 var doc = win.document; 63 var body = doc.body; 64 var html = doc.documentElement; 65 66 return { 67 /** 68 * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/ 69 * @return {Number} the scroll height of the document in pixels 70 */ 71 scrollHeight: function() { 72 return Math.max( 73 body.scrollHeight, 74 html.scrollHeight, 75 body.offsetHeight, 76 html.offsetHeight, 77 body.clientHeight, 78 html.clientHeight 79 ); 80 }, 81 82 /** 83 * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript 84 * @return {Number} the height of the viewport in pixels 85 */ 86 height: function() { 87 return win.innerHeight || html.clientHeight || body.clientHeight; 88 }, 89 90 /** 91 * Gets the Y scroll position 92 * @return {Number} pixels the page has scrolled along the Y-axis 93 */ 94 scrollY: function() { 95 if (win.pageYOffset !== undefined) { 96 return win.pageYOffset; 97 } 98 99 return (html || body.parentNode || body).scrollTop; 100 } 101 }; 102 } 103 104 function elementScroller(element) { 105 return { 106 /** 107 * @return {Number} the scroll height of the element in pixels 108 */ 109 scrollHeight: function() { 110 return Math.max( 111 element.scrollHeight, 112 element.offsetHeight, 113 element.clientHeight 114 ); 115 }, 116 117 /** 118 * @return {Number} the height of the element in pixels 119 */ 120 height: function() { 121 return Math.max(element.offsetHeight, element.clientHeight); 122 }, 123 124 /** 125 * Gets the Y scroll position 126 * @return {Number} pixels the element has scrolled along the Y-axis 127 */ 128 scrollY: function() { 129 return element.scrollTop; 130 } 131 }; 132 } 133 134 function createScroller(element) { 135 return isWindow(element) ? windowScroller(element) : elementScroller(element); 136 } 137 138 /** 139 * @param element EventTarget 140 */ 141 function trackScroll(element, options, callback) { 142 var isPassiveSupported = passiveEventsSupported(); 143 var rafId; 144 var scrolled = false; 145 var scroller = createScroller(element); 146 var lastScrollY = scroller.scrollY(); 147 var details = {}; 148 149 function update() { 150 var scrollY = Math.round(scroller.scrollY()); 151 var height = scroller.height(); 152 var scrollHeight = scroller.scrollHeight(); 153 154 // reuse object for less memory churn 155 details.scrollY = scrollY; 156 details.lastScrollY = lastScrollY; 157 details.direction = scrollY > lastScrollY ? "down" : "up"; 158 details.distance = Math.abs(scrollY - lastScrollY); 159 details.isOutOfBounds = scrollY < 0 || scrollY + height > scrollHeight; 160 details.top = scrollY <= options.offset; 161 details.bottom = scrollY + height >= scrollHeight; 162 details.toleranceExceeded = 163 details.distance > options.tolerance[details.direction]; 164 165 callback(details); 166 167 lastScrollY = scrollY; 168 scrolled = false; 169 } 170 171 function handleScroll() { 172 if (!scrolled) { 173 scrolled = true; 174 rafId = requestAnimationFrame(update); 175 } 176 } 177 178 var eventOptions = isPassiveSupported 179 ? { passive: true, capture: false } 180 : false; 181 element.addEventListener("scroll", handleScroll, eventOptions); 182 183 return { 184 destroy: function() { 185 cancelAnimationFrame(rafId); 186 element.removeEventListener("scroll", handleScroll, eventOptions); 187 } 188 }; 189 } 190 191 function normalizeTolerance(t) { 192 return t === Object(t) ? t : { down: t, up: t }; 193 } 194 195 /** 196 * UI enhancement for fixed headers. 197 * Hides header when scrolling down 198 * Shows header when scrolling up 199 * @constructor 200 * @param {DOMElement} elem the header element 201 * @param {Object} options options for the widget 202 */ 203 function Headroom(elem, options) { 204 options = options || {}; 205 Object.assign(this, Headroom.options, options); 206 this.classes = Object.assign({}, Headroom.options.classes, options.classes); 207 208 this.elem = elem; 209 this.tolerance = normalizeTolerance(this.tolerance); 210 this.initialised = false; 211 this.frozen = false; 212 } 213 Headroom.prototype = { 214 constructor: Headroom, 215 216 /** 217 * Start listening to scrolling 218 * @public 219 */ 220 init: function() { 221 if (Headroom.cutsTheMustard && !this.initialised) { 222 this.addClass("initial"); 223 this.initialised = true; 224 225 // defer event registration to handle browser 226 // potentially restoring previous scroll position 227 setTimeout( 228 function(self) { 229 self.scrollTracker = trackScroll( 230 self.scroller, 231 { offset: self.offset, tolerance: self.tolerance }, 232 self.update.bind(self) 233 ); 234 }, 235 100, 236 this 237 ); 238 } 239 240 return this; 241 }, 242 243 /** 244 * Destroy the widget, clearing up after itself 245 * @public 246 */ 247 destroy: function() { 248 this.initialised = false; 249 Object.keys(this.classes).forEach(this.removeClass, this); 250 this.scrollTracker.destroy(); 251 }, 252 253 /** 254 * Unpin the element 255 * @public 256 */ 257 unpin: function() { 258 if (this.hasClass("pinned") || !this.hasClass("unpinned")) { 259 this.addClass("unpinned"); 260 this.removeClass("pinned"); 261 262 if (this.onUnpin) { 263 this.onUnpin.call(this); 264 } 265 } 266 }, 267 268 /** 269 * Pin the element 270 * @public 271 */ 272 pin: function() { 273 if (this.hasClass("unpinned")) { 274 this.addClass("pinned"); 275 this.removeClass("unpinned"); 276 277 if (this.onPin) { 278 this.onPin.call(this); 279 } 280 } 281 }, 282 283 /** 284 * Freezes the current state of the widget 285 * @public 286 */ 287 freeze: function() { 288 this.frozen = true; 289 this.addClass("frozen"); 290 }, 291 292 /** 293 * Re-enables the default behaviour of the widget 294 * @public 295 */ 296 unfreeze: function() { 297 this.frozen = false; 298 this.removeClass("frozen"); 299 }, 300 301 top: function() { 302 if (!this.hasClass("top")) { 303 this.addClass("top"); 304 this.removeClass("notTop"); 305 306 if (this.onTop) { 307 this.onTop.call(this); 308 } 309 } 310 }, 311 312 notTop: function() { 313 if (!this.hasClass("notTop")) { 314 this.addClass("notTop"); 315 this.removeClass("top"); 316 317 if (this.onNotTop) { 318 this.onNotTop.call(this); 319 } 320 } 321 }, 322 323 bottom: function() { 324 if (!this.hasClass("bottom")) { 325 this.addClass("bottom"); 326 this.removeClass("notBottom"); 327 328 if (this.onBottom) { 329 this.onBottom.call(this); 330 } 331 } 332 }, 333 334 notBottom: function() { 335 if (!this.hasClass("notBottom")) { 336 this.addClass("notBottom"); 337 this.removeClass("bottom"); 338 339 if (this.onNotBottom) { 340 this.onNotBottom.call(this); 341 } 342 } 343 }, 344 345 shouldUnpin: function(details) { 346 var scrollingDown = details.direction === "down"; 347 348 return scrollingDown && !details.top && details.toleranceExceeded; 349 }, 350 351 shouldPin: function(details) { 352 var scrollingUp = details.direction === "up"; 353 354 return (scrollingUp && details.toleranceExceeded) || details.top; 355 }, 356 357 addClass: function(className) { 358 this.elem.classList.add(this.classes[className]); 359 }, 360 361 removeClass: function(className) { 362 this.elem.classList.remove(this.classes[className]); 363 }, 364 365 hasClass: function(className) { 366 return this.elem.classList.contains(this.classes[className]); 367 }, 368 369 update: function(details) { 370 if (details.isOutOfBounds) { 371 // Ignore bouncy scrolling in OSX 372 return; 373 } 374 375 if (this.frozen === true) { 376 return; 377 } 378 379 if (details.top) { 380 this.top(); 381 } else { 382 this.notTop(); 383 } 384 385 if (details.bottom) { 386 this.bottom(); 387 } else { 388 this.notBottom(); 389 } 390 391 if (this.shouldUnpin(details)) { 392 this.unpin(); 393 } else if (this.shouldPin(details)) { 394 this.pin(); 395 } 396 } 397 }; 398 399 /** 400 * Default options 401 * @type {Object} 402 */ 403 Headroom.options = { 404 tolerance: { 405 up: 0, 406 down: 0 407 }, 408 offset: 0, 409 scroller: isBrowser() ? window : null, 410 classes: { 411 frozen: "headroom--frozen", 412 pinned: "headroom--pinned", 413 unpinned: "headroom--unpinned", 414 top: "headroom--top", 415 notTop: "headroom--not-top", 416 bottom: "headroom--bottom", 417 notBottom: "headroom--not-bottom", 418 initial: "headroom" 419 } 420 }; 421 422 Headroom.cutsTheMustard = isSupported(); 423 424 return Headroom; 425 426}));
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.