PageSourceSearch

https://www.toyamatrucking.or.jp/common/js/headroom/Headroom.js

js toyamatrucking.or.jp collected 2026-10-06 13:40:31 UTC 11,235 bytes, 386 lines download raw bytes

1/**
2 * Check if object is part of the DOM
3 * @constructor
4 * @param {Object} obj element to check
5 */
6function isDOMElement(obj) {
7  return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType);
8}
9
10/**
11 * Helper function for extending objects
12 */
13function extend (object /*, objectN ... */) {
14  if(arguments.length <= 0) {
15    throw new Error('Missing arguments in extend function');
16  }
17
18  var result = object || {},
19      key,
20      i;
21
22  for (i = 1; i < arguments.length; i++) {
23    var replacement = arguments[i] || {};
24
25    for (key in replacement) {
26      // Recurse into object except if the object is a DOM element
27      if(typeof result[key] === 'object' && ! isDOMElement(result[key])) {
28        result[key] = extend(result[key], replacement[key]);
29      }
30      else {
31        result[key] = result[key] || replacement[key];
32      }
33    }
34  }
35
36  return result;
37}
38
39/**
40 * Helper function for normalizing tolerance option to object format
41 */
42function normalizeTolerance (t) {
43  return t === Object(t) ? t : { down : t, up : t };
44}
45
46/**
47 * UI enhancement for fixed headers.
48 * Hides header when scrolling down
49 * Shows header when scrolling up
50 * @constructor
51 * @param {DOMElement} elem the header element
52 * @param {Object} options options for the widget
53 */
54function Headroom (elem, options) {
55  options = extend(options, Headroom.options);
56
57  this.lastKnownScrollY = 0;
58  this.elem             = elem;
59  this.tolerance        = normalizeTolerance(options.tolerance);
60  this.classes          = options.classes;
61  this.offset           = options.offset;
62  this.scroller         = options.scroller;
63  this.initialised      = false;
64  this.onPin            = options.onPin;
65  this.onUnpin          = options.onUnpin;
66  this.onTop            = options.onTop;
67  this.onNotTop         = options.onNotTop;
68  this.onBottom         = options.onBottom;
69  this.onNotBottom      = options.onNotBottom;
70}
71Headroom.prototype = {
72  constructor : Headroom,
73
74  /**
75   * Initialises the widget
76   */
77  init : function() {
78    if(!Headroom.cutsTheMustard) {
79      return;
80    }
81
82    this.debouncer = new Debouncer(this.update.bind(this));
83    this.elem.classList.add(this.classes.initial);
84
85    // defer event registration to handle browser 
86    // potentially restoring previous scroll position
87    setTimeout(this.attachEvent.bind(this), 100);
88
89    return this;
90  },
91
92  /**
93   * Unattaches events and removes any classes that were added
94   */
95  destroy : function() {
96    var classes = this.classes;
97
98    this.initialised = false;
99    this.elem.classList.remove(classes.unpinned, classes.pinned, classes.top, classes.notTop, classes.initial);
100    this.scroller.removeEventListener('scroll', this.debouncer, false);
101  },
102
103  /**
104   * Attaches the scroll event
105   * @private
106   */
107  attachEvent : function() {
108    if(!this.initialised){
109      this.lastKnownScrollY = this.getScrollY();
110      this.initialised = true;
111      this.scroller.addEventListener('scroll', this.debouncer, false);
112
113      this.debouncer.handleEvent();
114    }
115  },
116  
117  /**
118   * Unpins the header if it's currently pinned
119   */
120  unpin : function() {
121    var classList = this.elem.classList,
122      classes = this.classes;
123    
124    if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) {
125      classList.add(classes.unpinned);
126      classList.remove(classes.pinned);
127      this.onUnpin && this.onUnpin.call(this);
128    }
129  },
130
131  /**
132   * Pins the header if it's currently unpinned
133   */
134  pin : function() {
135    var classList = this.elem.classList,
136      classes = this.classes;
137    
138    if(classList.contains(classes.unpinned)) {
139      classList.remove(classes.unpinned);
140      classList.add(classes.pinned);
141      this.onPin && this.onPin.call(this);
142    }
143  },
144
145  /**
146   * Handles the top states
147   */
148  top : function() {
149    var classList = this.elem.classList,
150      classes = this.classes;
151    
152    if(!classList.contains(classes.top)) {
153      classList.add(classes.top);
154      classList.remove(classes.notTop);
155      this.onTop && this.onTop.call(this);
156    }
157  },
158
159  /**
160   * Handles the not top state
161   */
162  notTop : function() {
163    var classList = this.elem.classList,
164      classes = this.classes;
165    
166    if(!classList.contains(classes.notTop)) {
167      classList.add(classes.notTop);
168      classList.remove(classes.top);
169      this.onNotTop && this.onNotTop.call(this);
170    }
171  },
172
173  bottom : function() {
174    var classList = this.elem.classList,
175      classes = this.classes;
176    
177    if(!classList.contains(classes.bottom)) {
178      classList.add(classes.bottom);
179      classList.remove(classes.notBottom);
180      this.onBottom && this.onBottom.call(this);
181    }
182  },
183
184  /**
185   * Handles the not top state
186   */
187  notBottom : function() {
188    var classList = this.elem.classList,
189      classes = this.classes;
190    
191    if(!classList.contains(classes.notBottom)) {
192      classList.add(classes.notBottom);
193      classList.remove(classes.bottom);
194      this.onNotBottom && this.onNotBottom.call(this);
195    }
196  },
197
198  /**
199   * Gets the Y scroll position
200   * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
201   * @return {Number} pixels the page has scrolled along the Y-axis
202   */
203  getScrollY : function() {
204    return (this.scroller.pageYOffset !== undefined)
205      ? this.scroller.pageYOffset
206      : (this.scroller.scrollTop !== undefined)
207        ? this.scroller.scrollTop
208        : (document.documentElement || document.body.parentNode || document.body).scrollTop;
209  },
210
211  /**
212   * Gets the height of the viewport
213   * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript
214   * @return {int} the height of the viewport in pixels
215   */
216  getViewportHeight : function () {
217    return window.innerHeight
218      || document.documentElement.clientHeight
219      || document.body.clientHeight;
220  },
221
222  /**
223   * Gets the physical height of the DOM element
224   * @param  {Object}  elm the element to calculate the physical height of which
225   * @return {int}     the physical height of the element in pixels
226   */
227  getElementPhysicalHeight : function (elm) {
228    return Math.max(
229      elm.offsetHeight,
230      elm.clientHeight
231    );
232  },
233
234  /**
235   * Gets the physical height of the scroller element
236   * @return {int} the physical height of the scroller element in pixels
237   */
238  getScrollerPhysicalHeight : function () {
239    return (this.scroller === window || this.scroller === document.body)
240      ? this.getViewportHeight()
241      : this.getElementPhysicalHeight(this.scroller);
242  },
243
244  /**
245   * Gets the height of the document
246   * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/
247   * @return {int} the height of the document in pixels
248   */
249  getDocumentHeight : function () {
250    var body = document.body,
251      documentElement = document.documentElement;
252  
253    return Math.max(
254      body.scrollHeight, documentElement.scrollHeight,
255      body.offsetHeight, documentElement.offsetHeight,
256      body.clientHeight, documentElement.clientHeight
257    );
258  },
259
260  /**
261   * Gets the height of the DOM element
262   * @param  {Object}  elm the element to calculate the height of which
263   * @return {int}     the height of the element in pixels
264   */
265  getElementHeight : function (elm) {
266    return Math.max(
267      elm.scrollHeight,
268      elm.offsetHeight,
269      elm.clientHeight
270    );
271  },
272
273  /**
274   * Gets the height of the scroller element
275   * @return {int} the height of the scroller element in pixels
276   */
277  getScrollerHeight : function () {
278    return (this.scroller === window || this.scroller === document.body)
279      ? this.getDocumentHeight()
280      : this.getElementHeight(this.scroller);
281  },
282
283  /**
284   * determines if the scroll position is outside of document boundaries
285   * @param  {int}  currentScrollY the current y scroll position
286   * @return {bool} true if out of bounds, false otherwise
287   */
288  isOutOfBounds : function (currentScrollY) {
289    var pastTop  = currentScrollY < 0,
290      pastBottom = currentScrollY + this.getScrollerPhysicalHeight() > this.getScrollerHeight();
291    
292    return pastTop || pastBottom;
293  },
294
295  /**
296   * determines if the tolerance has been exceeded
297   * @param  {int} currentScrollY the current scroll y position
298   * @return {bool} true if tolerance exceeded, false otherwise
299   */
300  toleranceExceeded : function (currentScrollY, direction) {
301    return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction];
302  },
303
304  /**
305   * determine if it is appropriate to unpin
306   * @param  {int} currentScrollY the current y scroll position
307   * @param  {bool} toleranceExceeded has the tolerance been exceeded?
308   * @return {bool} true if should unpin, false otherwise
309   */
310  shouldUnpin : function (currentScrollY, toleranceExceeded) {
311    var scrollingDown = currentScrollY > this.lastKnownScrollY,
312      pastOffset = currentScrollY >= this.offset;
313
314    return scrollingDown && pastOffset && toleranceExceeded;
315  },
316
317  /**
318   * determine if it is appropriate to pin
319   * @param  {int} currentScrollY the current y scroll position
320   * @param  {bool} toleranceExceeded has the tolerance been exceeded?
321   * @return {bool} true if should pin, false otherwise
322   */
323  shouldPin : function (currentScrollY, toleranceExceeded) {
324    var scrollingUp  = currentScrollY < this.lastKnownScrollY,
325      pastOffset = currentScrollY <= this.offset;
326
327    return (scrollingUp && toleranceExceeded) || pastOffset;
328  },
329
330  /**
331   * Handles updating the state of the widget
332   */
333  update : function() {
334    var currentScrollY  = this.getScrollY(),
335      scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up',
336      toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection);
337
338    if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX
339      return;
340    }
341
342    if (currentScrollY <= this.offset ) {
343      this.top();
344    } else {
345      this.notTop();
346    }
347
348    if(currentScrollY + this.getViewportHeight() >= this.getScrollerHeight()) {
349      this.bottom();
350    }
351    else {
352      this.notBottom();
353    }
354
355    if(this.shouldUnpin(currentScrollY, toleranceExceeded)) {
356      this.unpin();
357    }
358    else if(this.shouldPin(currentScrollY, toleranceExceeded)) {
359      this.pin();
360    }
361
362    this.lastKnownScrollY = currentScrollY;
363  }
364};
365/**
366 * Default options
367 * @type {Object}
368 */
369Headroom.options = {
370  tolerance : {
371    up : 0,
372    down : 0
373  },
374  offset : 0,
375  scroller: window,
376  classes : {
377    pinned : 'headroom--pinned',
378    unpinned : 'headroom--unpinned',
379    top : 'headroom--top',
380    notTop : 'headroom--not-top',
381    bottom : 'headroom--bottom',
382    notBottom : 'headroom--not-bottom',
383    initial : 'headroom'
384  }
385};
386Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList;

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.