1/*! 2 * Headhesive.js v1.2.3 - An on-demand sticky header 3 * Author: Copyright (c) Mark Goodyear <@markgdyr> <http://markgoodyear.com> 4 * Url: http://markgoodyear.com/labs/headhesive 5 * License: MIT 6 */ 7(function(root, factory) { 8 if (typeof define === "function" && define.amd) { 9 define([], function() { 10 return factory(); 11 }); 12 } else if (typeof exports === "object") { 13 module.exports = factory(); 14 } else { 15 root.Headhesive = factory(); 16 } 17})(this, function() { 18 "use strict"; 19 var _mergeObj = function(to, from) { 20 for (var p in from) { 21 if (from.hasOwnProperty(p)) { 22 to[p] = typeof from[p] === "object" ? _mergeObj(to[p], from[p]) : from[p]; 23 } 24 } 25 return to; 26 }; 27 var _throttle = function(func, wait) { 28 var _now = Date.now || function() { 29 return new Date().getTime(); 30 }; 31 var context, args, result; 32 var timeout = null; 33 var previous = 0; 34 var later = function() { 35 previous = _now(); 36 timeout = null; 37 result = func.apply(context, args); 38 context = args = null; 39 }; 40 return function() { 41 var now = _now(); 42 var remaining = wait - (now - previous); 43 context = this; 44 args = arguments; 45 if (remaining <= 0) { 46 clearTimeout(timeout); 47 timeout = null; 48 previous = now; 49 result = func.apply(context, args); 50 context = args = null; 51 } else if (!timeout) { 52 timeout = setTimeout(later, remaining); 53 } 54 return result; 55 }; 56 }; 57 var _getScrollY = function() { 58 return window.pageYOffset !== undefined ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; 59 }; 60 var _getElemY = function(elem, side) { 61 var pos = 0; 62 var elemHeight = elem.offsetHeight; 63 while (elem) { 64 pos += elem.offsetTop; 65 elem = elem.offsetParent; 66 } 67 if (side === "bottom") { 68 pos = pos + elemHeight; 69 } 70 return pos; 71 }; 72 var Headhesive = function(elem, options) { 73 if (!("querySelector" in document && "addEventListener" in window)) { 74 return; 75 } 76 this.visible = false; 77 this.options = { 78 offset: 1200, 79 offsetSide: "top", 80 classes: { 81 clone: "headhesive", 82 stick: "headhesive--stick", 83 unstick: "headhesive--unstick" 84 }, 85 throttle: 250, 86 onInit: function() {}, 87 onStick: function() {}, 88 onUnstick: function() {}, 89 onDestroy: function() {} 90 }; 91 this.elem = typeof elem === "string" ? document.querySelector(elem) : elem; 92 this.options = _mergeObj(this.options, options); 93 this.init(); 94 }; 95 Headhesive.prototype = { 96 constructor: Headhesive, 97 init: function() { 98 this.clonedElem = this.elem.cloneNode(true); 99 this.clonedElem.className += " " + this.options.classes.clone; 100 document.body.insertBefore(this.clonedElem, document.body.firstChild); 101 if (typeof this.options.offset === "number") { 102 this.scrollOffset = this.options.offset; 103 } else if (typeof this.options.offset === "string") { 104 this._setScrollOffset(); 105 } else { 106 throw new Error("Invalid offset: " + this.options.offset); 107 } 108 this._throttleUpdate = _throttle(this.update.bind(this), this.options.throttle); 109 this._throttleScrollOffset = _throttle(this._setScrollOffset.bind(this), this.options.throttle); 110 window.addEventListener("scroll", this._throttleUpdate, false); 111 window.addEventListener("resize", this._throttleScrollOffset, false); 112 this.options.onInit.call(this); 113 }, 114 _setScrollOffset: function() { 115 if (typeof this.options.offset === "string") { 116 this.scrollOffset = _getElemY(document.querySelector(this.options.offset), this.options.offsetSide); 117 } 118 }, 119 destroy: function() { 120 document.body.removeChild(this.clonedElem); 121 window.removeEventListener("scroll", this._throttleUpdate); 122 window.removeEventListener("resize", this._throttleScrollOffset); 123 this.options.onDestroy.call(this); 124 }, 125 stick: function() { 126 if (!this.visible) { 127 this.clonedElem.className = this.clonedElem.className.replace(new RegExp("(^|\\s)*" + this.options.classes.unstick + "(\\s|$)*", "g"), ""); 128 this.clonedElem.className += " " + this.options.classes.stick; 129 this.visible = true; 130 this.options.onStick.call(this); 131 } 132 }, 133 unstick: function() { 134 if (this.visible) { 135 this.clonedElem.className = this.clonedElem.className.replace(new RegExp("(^|\\s)*" + this.options.classes.stick + "(\\s|$)*", "g"), ""); 136 this.clonedElem.className += " " + this.options.classes.unstick; 137 this.visible = false;
138 this.options.onUnstick.call(this); 139 } 140 }, 141 update: function() { 142 if (_getScrollY() > this.scrollOffset) { 143 this.stick(); 144 } else { 145 this.unstick(); 146 } 147 } 148 }; 149 return Headhesive; 150 151});
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.