text: ﻿/*!
   * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it
   * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js
   * License: MIT
   */
  
  (function(root, factory) {
    'use strict';
  
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module.
      define([], factory);
    }
    else if (typeof exports === 'object') {
      // COMMONJS
      module.exports = factory();
    }
    else {
      // BROWSER
      root.Headroom = factory();
    }
  }(this, function() {
    'use strict';
  
    /* exported features */
    
    var features = {
      bind : !!(function(){}.bind),
      classList : 'classList' in document.documentElement,
      rAF : !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame)
    };
    window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
    
    /**
     * Handles debouncing of events via requestAnimationFrame
     * @see http://www.html5rocks.com/en/tutorials/speed/animations/
     * @param {Function} callback The callback to handle whichever event
     */
    function Debouncer (callback) {
      this.callback = callback;
      this.ticking = false;
    }
    Debouncer.prototype = {
      constructor : Debouncer,
    
      /**
       * dispatches the event to the supplied callback
       * @private
       */
      update : function() {
        this.callback && this.callback();
        this.ticking = false;
      },
    
      /**
       * ensures events don't get stacked
       * @private
       */
      requestTick : function() {
        if(!this.ticking) {
          requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
          this.ticking = true;
        }
      },
    
      /**
       * Attach this as the event listeners
       */
      handleEvent : function() {
        this.requestTick();
      }
    };
    /**
     * Check if object is part of the DOM
     * @constructor
     * @param {Object} obj element to check
     */
    function isDOMElement(obj) {
      return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType);
    }
    
    /**
     * Helper function for extending objects
     */
    function extend (object /*, objectN ... */) {
      if(arguments.length <= 0) {
        throw new Error('Missing arguments in extend function');
      }
    
      var result = object || {},
          key,
          i;
    
      for (i = 1; i < arguments.length; i++) {
        var replacement = arguments[i] || {};
    
        for (key in replacement) {
          // Recurse into object except if the object is a DOM element
          if(typeof result[key] === 'object' && ! isDOMElement(result[key])) {
            result[key] = extend(result[key], replacement[key]);
          }
          else {
            result[key] = result[key] || replacement[key];
          }
        }
      }
    
      return result;
    }
    
    /**
     * Helper function for normalizing tolerance option to object format
     */
    function normalizeTolerance (t) {
      return t === Object(t) ? t : { down : t, up : t };
    }
    
    /**
     * UI enhancement for fixed headers.
     * Hides header when scrolling down
     * Shows header when scrolling up
     * @constructor
     * @param {DOMElement} elem the header element
     * @param {Object} options options for the widget
     */
    function Headroom (elem, options) {
      options = extend(options, Headroom.options);
    
      this.lastKnownScrollY = 0;
      this.elem             = elem;
      this.tolerance        = normalizeTolerance(options.tolerance);
      this.classes          = options.classes;
      this.offset           = options.offset;
      this.scroller         = options.scroller;
      this.initialised      = false;
      this.onPin            = options.onPin;
      this.onUnpin          = options.onUnpin;
      this.onTop            = options.onTop;
      this.onNotTop         = options.onNotTop;
      this.onBottom         = options.onBottom;
      this.onNotBottom      = options.onNotBottom;
    }
    Headroom.prototype = {
      constructor : Headroom,
    
      /**
       * Initialises the widget
       */
      init : function() {
        if(!Headroom.cutsTheMustard) {
          return;
        }
    
        this.debouncer = new Debouncer(this.update.bind(this));
        this.elem.classList.add(this.classes.initial);
    
        // defer event registration to handle browser
        // potentially restoring previous scroll position
        setTimeout(this.attachEvent.bind(this), 100);
    
        return this;
      },
    
      /**
       * Unattaches events and removes any classes that were added
       */
      destroy : function() {
        var classes = this.classes;
    
        this.initialised = false;
    
        for (var key in classes) {
          if(classes.hasOwnProperty(key)) {
            this.elem.classList.remove(classes[key]);
          }
        }
    
        this.scroller.removeEventListener('scroll', this.debouncer, false);
      },
    
      /**
       * Attaches the scroll event
       * @private
       */
      attachEvent : function() {
        if(!this.initialised){
          this.lastKnownScrollY = this.getScrollY();
          this.initialised = true;
          this.scroller.addEventListener('scroll', this.debouncer, false);
    
          this.debouncer.handleEvent();
        }
      },
    
      /**
       * Unpins the header if it's currently pinned
       */
      unpin : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) {
          classList.add(classes.unpinned);
          classList.remove(classes.pinned);
          this.onUnpin && this.onUnpin.call(this);
        }
      },
    
      /**
       * Pins the header if it's currently unpinned
       */
      pin : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(classList.contains(classes.unpinned)) {
          classList.remove(classes.unpinned);
          classList.add(classes.pinned);
          this.onPin && this.onPin.call(this);
        }
      },
    
      /**
       * Handles the top states
       */
      top : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(!classList.contains(classes.top)) {
          classList.add(classes.top);
          classList.remove(classes.notTop);
          this.onTop && this.onTop.call(this);
        }
      },
    
      /**
       * Handles the not top state
       */
      notTop : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(!classList.contains(classes.notTop)) {
          classList.add(classes.notTop);
          classList.remove(classes.top);
          this.onNotTop && this.onNotTop.call(this);
        }
      },
    
      bottom : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(!classList.contains(classes.bottom)) {
          classList.add(classes.bottom);
          classList.remove(classes.notBottom);
          this.onBottom && this.onBottom.call(this);
        }
      },
    
      /**
       * Handles the not top state
       */
      notBottom : function() {
        var classList = this.elem.classList,
          classes = this.classes;
    
        if(!classList.contains(classes.notBottom)) {
          classList.add(classes.notBottom);
          classList.remove(classes.bottom);
          this.onNotBottom && this.onNotBottom.call(this);
        }
      },
    
      /**
       * Gets the Y scroll position
       * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
       * @return {Number} pixels the page has scrolled along the Y-axis
       */
      getScrollY : function() {
        return (this.scroller.pageYOffset !== undefined)
          ? this.scroller.pageYOffset
          : (this.scroller.scrollTop !== undefined)
            ? this.scroller.scrollTop
            : (document.documentElement || document.body.parentNode || document.body).scrollTop;
      },
    
      /**
       * Gets the height of the viewport
       * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript
       * @return {int} the height of the viewport in pixels
       */
      getViewportHeight : function () {
        return window.innerHeight
          || document.documentElement.clientHeight
          || document.body.clientHeight;
      },
    
      /**
       * Gets the physical height of the DOM element
       * @param  {Object}  elm the element to calculate the physical height of which
       * @return {int}     the physical height of the element in pixels
       */
      getElementPhysicalHeight : function (elm) {
        return Math.max(
          elm.offsetHeight,
          elm.clientHeight
        );
      },
    
      /**
       * Gets the physical height of the scroller element
       * @return {int} the physical height of the scroller element in pixels
       */
      getScrollerPhysicalHeight : function () {
        return (this.scroller === window || this.scroller === document.body)
          ? this.getViewportHeight()
          : this.getElementPhysicalHeight(this.scroller);
      },
    
      /**
       * Gets the height of the document
       * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/
       * @return {int} the height of the document in pixels
       */
      getDocumentHeight : function () {
        var body = document.body,
          documentElement = document.documentElement;
    
        return Math.max(
          body.scrollHeight, documentElement.scrollHeight,
          body.offsetHeight, documentElement.offsetHeight,
          body.clientHeight, documentElement.clientHeight
        );
      },
    
      /**
       * Gets the height of the DOM element
       * @param  {Object}  elm the element to calculate the height of which
       * @return {int}     the height of the element in pixels
       */
      getElementHeight : function (elm) {
        return Math.max(
          elm.scrollHeight,
          elm.offsetHeight,
          elm.clientHeight
        );
      },
    
      /**
       * Gets the height of the scroller element
       * @return {int} the height of the scroller element in pixels
       */
      getScrollerHeight : function () {
        return (this.scroller === window || this.scroller === document.body)
          ? this.getDocumentHeight()
          : this.getElementHeight(this.scroller);
      },
    
      /**
       * determines if the scroll position is outside of document boundaries
       * @param  {int}  currentScrollY the current y scroll position
       * @return {bool} true if out of bounds, false otherwise
       */
      isOutOfBounds : function (currentScrollY) {
        var pastTop  = currentScrollY < 0,
          pastBottom = currentScrollY + this.getScrollerPhysicalHeight() > this.getScrollerHeight();
    
        return pastTop || pastBottom;
      },
    
      /**
       * determines if the tolerance has been exceeded
       * @param  {int} currentScrollY the current scroll y position
       * @return {bool} true if tolerance exceeded, false otherwise
       */
      toleranceExceeded : function (currentScrollY, direction) {
        return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction];
      },
    
      /**
       * determine if it is appropriate to unpin
       * @param  {int} currentScrollY the current y scroll position
       * @param  {bool} toleranceExceeded has the tolerance been exceeded?
       * @return {bool} true if should unpin, false otherwise
       */
      shouldUnpin : function (currentScrollY, toleranceExceeded) {
        var scrollingDown = currentScrollY > this.lastKnownScrollY,
          pastOffset = currentScrollY >= this.offset;
    
        return scrollingDown && pastOffset && toleranceExceeded;
      },
    
      /**
       * determine if it is appropriate to pin
       * @param  {int} currentScrollY the current y scroll position
       * @param  {bool} toleranceExceeded has the tolerance been exceeded?
       * @return {bool} true if should pin, false otherwise
       */
      shouldPin : function (currentScrollY, toleranceExceeded) {
        var scrollingUp  = currentScrollY < this.lastKnownScrollY,
          pastOffset = currentScrollY <= this.offset;
    
        return (scrollingUp && toleranceExceeded) || pastOffset;
      },
    
      /**
       * Handles updating the state of the widget
       */
      update : function() {
        var currentScrollY  = this.getScrollY(),
          scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up',
          toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection);
    
        if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX
          return;
        }
    
        if (currentScrollY <= this.offset ) {
          this.top();
        } else {
          this.notTop();
        }
    
        if(currentScrollY + this.getViewportHeight() >= this.getScrollerHeight()) {
          this.bottom();
        }
        else {
          this.notBottom();
        }
    
        if(this.shouldUnpin(currentScrollY, toleranceExceeded)) {
          this.unpin();
        }
        else if(this.shouldPin(currentScrollY, toleranceExceeded)) {
          this.pin();
        }
    
        this.lastKnownScrollY = currentScrollY;
      }
    };
    /**
     * Default options
     * @type {Object}
     */
      if (CSS.supports("-webkit-backdrop-filter","var(--color)") || CSS.supports("-webkit-backdrop-filter:var(--color)") )  {
  		var elem = window
      } else {
  		var elem = document.querySelector('container')
      }
  
    Headroom.options = {
      tolerance : {
        up : 10,
        down : 10
      },
      offset : 60,
  	scroller: elem,
      classes : {
        pinned : 'headroom--pinned',
        unpinned : 'headroom--unpinned',
        top : 'headroom--top',
        notTop : 'headroom--not-top',
        bottom : 'headroom--bottom',
        notBottom : 'headroom--not-bottom',
        initial : 'headroom'
      }
    };
    Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList;
  
    return Headroom;
  }));
  
  // grab an element
  var myElement = document.querySelector("body");
  // construct an instance of Headroom, passing the element
  var headroom  = new Headroom(myElement);
  // initialise
  headroom.init(); 
  