]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
Convert sticky to ES6 class
authorColin Marshall <colin.michael.marshall@gmail.com>
Thu, 4 Feb 2016 05:32:53 +0000 (22:32 -0700)
committerColin Marshall <colin.michael.marshall@gmail.com>
Thu, 4 Feb 2016 05:32:53 +0000 (22:32 -0700)
js/foundation.sticky.js

index e5f4d4c32362fcedae1b31c45680cc1749319291..e0ae7583c05b06a9b28ae40fcb5605acbd95a025 100644 (file)
@@ -1,19 +1,20 @@
+'use strict';
+
 /**
  * Sticky module.
  * @module foundation.sticky
  * @requires foundation.util.triggers
  * @requires foundation.util.mediaQuery
  */
-!function($, Foundation){
-  'use strict';
 
+export default class Sticky {
   /**
    * Creates a new instance of a sticky thing.
    * @class
    * @param {jQuery} element - jQuery object to make sticky.
    * @param {Object} options - options object passed when creating the element programmatically.
    */
-  function Sticky(element, options){
+  constructor(element, options) {
     this.$element = element;
     this.options = $.extend({}, Sticky.defaults, this.$element.data(), options);
 
 
     Foundation.registerPlugin(this, 'Sticky');
   }
-  Sticky.defaults = {
-    /**
-     * Customizable container template. Add your own classes for styling and sizing.
-     * @option
-     * @example '&lt;div data-sticky-container class="small-6 columns"&gt;&lt;/div&gt;'
-     */
-    container: '<div data-sticky-container></div>',
-    /**
-     * Location in the view the element sticks to.
-     * @option
-     * @example 'top'
-     */
-    stickTo: 'top',
-    /**
-     * If anchored to a single element, the id of that element.
-     * @option
-     * @example 'exampleId'
-     */
-    anchor: '',
-    /**
-     * If using more than one element as anchor points, the id of the top anchor.
-     * @option
-     * @example 'exampleId:top'
-     */
-    topAnchor: '',
-    /**
-     * If using more than one element as anchor points, the id of the bottom anchor.
-     * @option
-     * @example 'exampleId:bottom'
-     */
-    btmAnchor: '',
-    /**
-     * Margin, in `em`'s to apply to the top of the element when it becomes sticky.
-     * @option
-     * @example 1
-     */
-    marginTop: 1,
-    /**
-     * Margin, in `em`'s to apply to the bottom of the element when it becomes sticky.
-     * @option
-     * @example 1
-     */
-    marginBottom: 1,
-    /**
-     * Breakpoint string that is the minimum screen size an element should become sticky.
-     * @option
-     * @example 'medium'
-     */
-    stickyOn: 'medium',
-    /**
-     * Class applied to sticky element, and removed on destruction. Foundation defaults to `sticky`.
-     * @option
-     * @example 'sticky'
-     */
-    stickyClass: 'sticky',
-    /**
-     * Class applied to sticky container. Foundation defaults to `sticky-container`.
-     * @option
-     * @example 'sticky-container'
-     */
-    containerClass: 'sticky-container',
-    /**
-     * Number of scroll events between the plugin's recalculating sticky points. Setting it to `0` will cause it to recalc every scroll event, setting it to `-1` will prevent recalc on scroll.
-     * @option
-     * @example 50
-     */
-    checkEvery: -1
-  };
-
+  
   /**
    * Initializes the sticky element by adding classes, getting/setting dimensions, breakpoints and attributes
    * @function
    * @private
    */
-  Sticky.prototype._init = function(){
+  _init() {
     var $parent = this.$element.parent('[data-sticky-container]'),
         id = this.$element[0].id || Foundation.GetYoDigits(6, 'sticky'),
         _this = this;
 
-    if(!$parent.length){
+    if (!$parent.length) {
       this.wasWrapped = true;
     }
     this.$container = $parent.length ? $parent : $(this.options.container).wrapInner(this.$element);
     this.$container.addClass(this.options.containerClass);
 
-
     this.$element.addClass(this.options.stickyClass)
                  .attr({'data-resize': id});
 
     this.scrollCount = this.options.checkEvery;
     this.isStuck = false;
 
-    if(this.options.anchor !== ''){
+    if (this.options.anchor !== '') {
       this.$anchor = $(`#${this.options.anchor}`);
-    }else{
+    } else {
       this._parsePoints();
     }
 
-    this._setSizes(function(){
+    this._setSizes(function() {
       _this._calc(false);
     });
     this._events(id.split('-').reverse().join('-'));
-  };
+  }
+
   /**
    * If using multiple elements as anchors, calculates the top and bottom pixel values the sticky thing should stick and unstick on.
    * @function
    * @private
    */
-  Sticky.prototype._parsePoints = function(){
+  _parsePoints() {
     var top = this.options.topAnchor,
         btm = this.options.btmAnchor,
         pts = [top, btm],
         breaks = {};
-    if(top && btm){
+    if (top && btm) {
 
-      for(var i = 0, len = pts.length; i < len && pts[i]; i++){
+      for (var i = 0, len = pts.length; i < len && pts[i]; i++) {
         var pt;
-        if(typeof pts[i] === 'number'){
+        if (typeof pts[i] === 'number') {
           pt = pts[i];
-        }else{
+        } else {
           var place = pts[i].split(':'),
               anchor = $(`#${place[0]}`);
 
           pt = anchor.offset().top;
-          if(place[1] && place[1].toLowerCase() === 'bottom'){
+          if (place[1] && place[1].toLowerCase() === 'bottom') {
             pt += anchor[0].getBoundingClientRect().height;
           }
         }
         breaks[i] = pt;
       }
-    }else{
+    } else {
       breaks = {0: 1, 1: document.documentElement.scrollHeight};
     }
 
     this.points = breaks;
     return;
-  };
+  }
 
   /**
    * Adds event handlers for the scrolling element.
    * @private
    * @param {String} id - psuedo-random id for unique scroll event listener.
    */
-  Sticky.prototype._events = function(id){
+  _events(id) {
     var _this = this,
         scrollListener = this.scrollListener = `scroll.zf.${id}`;
-    if(this.isOn){ return; }
-    if(this.canStick){
+    if (this.isOn) { return; }
+    if (this.canStick) {
       this.isOn = true;
       $(window).off(scrollListener)
-               .on(scrollListener, function(e){
-                 if(_this.scrollCount === 0){
+               .on(scrollListener, function(e) {
+                 if (_this.scrollCount === 0) {
                    _this.scrollCount = _this.options.checkEvery;
-                   _this._setSizes(function(){
+                   _this._setSizes(function() {
                      _this._calc(false, window.pageYOffset);
                    });
-                 }else{
+                 } else {
                    _this.scrollCount--;
                    _this._calc(false, window.pageYOffset);
                  }
     }
 
     this.$element.off('resizeme.zf.trigger')
-                 .on('resizeme.zf.trigger', function(e, el){
-                     _this._setSizes(function(){
+                 .on('resizeme.zf.trigger', function(e, el) {
+                     _this._setSizes(function() {
                        _this._calc(false);
-                       if(_this.canStick){
-                         if(!_this.isOn){
+                       if (_this.canStick) {
+                         if (!_this.isOn) {
                            _this._events(id);
                          }
-                       }else if(_this.isOn){
+                       } else if (_this.isOn) {
                          _this._pauseListeners(scrollListener);
                        }
                      });
     });
-  };
+  }
 
   /**
    * Removes event handlers for scroll and change events on anchor.
    * @fires Sticky#pause
    * @param {String} scrollListener - unique, namespaced scroll listener attached to `window`
    */
-  Sticky.prototype._pauseListeners = function(scrollListener){
+  _pauseListeners(scrollListener) {
     this.isOn = false;
     $(window).off(scrollListener);
 
      * @private
      */
      this.$element.trigger('pause.zf.sticky');
-  };
+  }
 
   /**
    * Called on every `scroll` event and on `_init`
    * @param {Boolean} checkSizes - true if plugin should recalculate sizes and breakpoints.
    * @param {Number} scroll - current scroll position passed from scroll event cb function. If not passed, defaults to `window.pageYOffset`.
    */
-  Sticky.prototype._calc = function(checkSizes, scroll){
-    if(checkSizes){ this._setSizes(); }
+  _calc(checkSizes, scroll) {
+    if (checkSizes) { this._setSizes(); }
 
-    if(!this.canStick){
-      if(this.isStuck){
+    if (!this.canStick) {
+      if (this.isStuck) {
         this._removeSticky(true);
       }
       return false;
     }
 
-    if(!scroll){ scroll = window.pageYOffset; }
+    if (!scroll) { scroll = window.pageYOffset; }
 
-    if(scroll >= this.topPoint){
-      if(scroll <= this.bottomPoint){
-        if(!this.isStuck){
+    if (scroll >= this.topPoint) {
+      if (scroll <= this.bottomPoint) {
+        if (!this.isStuck) {
           this._setSticky();
         }
-      }else{
-        if(this.isStuck){
+      } else {
+        if (this.isStuck) {
           this._removeSticky(false);
         }
       }
-    }else{
-      if(this.isStuck){
+    } else {
+      if (this.isStuck) {
         this._removeSticky(true);
       }
     }
-  };
+  }
+
   /**
    * Causes the $element to become stuck.
    * Adds `position: fixed;`, and helper classes.
    * @function
    * @private
    */
-  Sticky.prototype._setSticky = function(){
+  _setSticky() {
     var stickTo = this.options.stickTo,
         mrgn = stickTo === 'top' ? 'marginTop' : 'marginBottom',
         notStuckTo = stickTo === 'top' ? 'bottom' : 'top',
                   * @event Sticky#stuckto
                   */
                  .trigger(`sticky.zf.stuckto:${stickTo}`);
-  };
+  }
 
   /**
    * Causes the $element to become unstuck.
    * @fires Sticky#unstuckfrom
    * @private
    */
-  Sticky.prototype._removeSticky = function(isTop){
+  _removeSticky(isTop) {
     var stickTo = this.options.stickTo,
         stickToTop = stickTo === 'top',
         css = {},
 
     css[mrgn] = 0;
 
-    if((isTop && !stickToTop) || (stickToTop && !isTop)){
+    if ((isTop && !stickToTop) || (stickToTop && !isTop)) {
       css[stickTo] = anchorPt;
       css[notStuckTo] = 0;
-    }else{
+    } else {
       css[stickTo] = 0;
       css[notStuckTo] = anchorPt;
     }
                   * @event Sticky#unstuckfrom
                   */
                  .trigger(`sticky.zf.unstuckfrom:${topOrBottom}`);
-  };
+  }
 
   /**
    * Sets the $element and $container sizes for plugin.
    * @param {Function} cb - optional callback function to fire on completion of `_setBreakPoints`.
    * @private
    */
-  Sticky.prototype._setSizes = function(cb){
+  _setSizes(cb) {
     this.canStick = Foundation.MediaQuery.atLeast(this.options.stickyOn);
-    if(!this.canStick){ cb(); }
+    if (!this.canStick) { cb(); }
     var _this = this,
         newElemWidth = this.$container[0].getBoundingClientRect().width,
         comp = window.getComputedStyle(this.$container[0]),
         pdng = parseInt(comp['padding-right'], 10);
 
-    if(this.$anchor && this.$anchor.length){
+    if (this.$anchor && this.$anchor.length) {
       this.anchorHeight = this.$anchor[0].getBoundingClientRect().height;
-    }else{
+    } else {
       this._parsePoints();
     }
 
                this.$element.css({"left":this.$container.offset().left + parseInt(comp['padding-left'], 10)});
        }
 
-    this._setBreakPoints(newContainerHeight, function(){
-      if(cb){ cb(); }
+    this._setBreakPoints(newContainerHeight, function() {
+      if (cb) { cb(); }
     });
+  }
 
-  };
   /**
    * Sets the upper and lower breakpoints for the element to become sticky/unsticky.
    * @param {Number} elemHeight - px value for sticky.$element height, calculated by `_setSizes`.
    * @param {Function} cb - optional callback function to be called on completion.
    * @private
    */
-  Sticky.prototype._setBreakPoints = function(elemHeight, cb){
-    if(!this.canStick){
-      if(cb){ cb(); }
-      else{ return false; }
+  _setBreakPoints(elemHeight, cb) {
+    if (!this.canStick) {
+      if (cb) { cb(); }
+      else { return false; }
     }
     var mTop = emCalc(this.options.marginTop),
         mBtm = emCalc(this.options.marginBottom),
         // bottomPoint = topPoint + this.anchorHeight || this.points[1],
         winHeight = window.innerHeight;
 
-    if(this.options.stickTo === 'top'){
+    if (this.options.stickTo === 'top') {
       topPoint -= mTop;
       bottomPoint -= (elemHeight + mTop);
-    }else if(this.options.stickTo === 'bottom'){
+    } else if (this.options.stickTo === 'bottom') {
       topPoint -= (winHeight - (elemHeight + mBtm));
       bottomPoint -= (winHeight - mBtm);
-    }else{
+    } else {
       //this would be the stickTo: both option... tricky
     }
 
     this.topPoint = topPoint;
     this.bottomPoint = bottomPoint;
 
-    if(cb){ cb(); }
-  };
+    if (cb) { cb(); }
+  }
 
   /**
    * Destroys the current sticky element.
    * Removes event listeners, JS-added css properties and classes, and unwraps the $element if the JS added the $container.
    * @function
    */
-  Sticky.prototype.destroy = function(){
+  destroy() {
     this._removeSticky(true);
 
     this.$element.removeClass(`${this.options.stickyClass} is-anchored is-at-top`)
     this.$anchor.off('change.zf.sticky');
     $(window).off(this.scrollListener);
 
-    if(this.wasWrapped){
+    if (this.wasWrapped) {
       this.$element.unwrap();
-    }else{
+    } else {
       this.$container.removeClass(this.options.containerClass)
                      .css({
                        height: ''
                      });
     }
     Foundation.unregisterPlugin(this);
-  };
+  }
+}
+
+Sticky.defaults = {
   /**
-   * Helper function to calculate em values
-   * @param Number {em} - number of em's to calculate into pixels
+   * Customizable container template. Add your own classes for styling and sizing.
+   * @option
+   * @example '&lt;div data-sticky-container class="small-6 columns"&gt;&lt;/div&gt;'
    */
-  function emCalc(em){
-    return parseInt(window.getComputedStyle(document.body, null).fontSize, 10) * em;
-  }
-  Foundation.plugin(Sticky, 'Sticky');
-}(jQuery, window.Foundation);
+  container: '<div data-sticky-container></div>',
+  /**
+   * Location in the view the element sticks to.
+   * @option
+   * @example 'top'
+   */
+  stickTo: 'top',
+  /**
+   * If anchored to a single element, the id of that element.
+   * @option
+   * @example 'exampleId'
+   */
+  anchor: '',
+  /**
+   * If using more than one element as anchor points, the id of the top anchor.
+   * @option
+   * @example 'exampleId:top'
+   */
+  topAnchor: '',
+  /**
+   * If using more than one element as anchor points, the id of the bottom anchor.
+   * @option
+   * @example 'exampleId:bottom'
+   */
+  btmAnchor: '',
+  /**
+   * Margin, in `em`'s to apply to the top of the element when it becomes sticky.
+   * @option
+   * @example 1
+   */
+  marginTop: 1,
+  /**
+   * Margin, in `em`'s to apply to the bottom of the element when it becomes sticky.
+   * @option
+   * @example 1
+   */
+  marginBottom: 1,
+  /**
+   * Breakpoint string that is the minimum screen size an element should become sticky.
+   * @option
+   * @example 'medium'
+   */
+  stickyOn: 'medium',
+  /**
+   * Class applied to sticky element, and removed on destruction. Foundation defaults to `sticky`.
+   * @option
+   * @example 'sticky'
+   */
+  stickyClass: 'sticky',
+  /**
+   * Class applied to sticky container. Foundation defaults to `sticky-container`.
+   * @option
+   * @example 'sticky-container'
+   */
+  containerClass: 'sticky-container',
+  /**
+   * Number of scroll events between the plugin's recalculating sticky points. Setting it to `0` will cause it to recalc every scroll event, setting it to `-1` will prevent recalc on scroll.
+   * @option
+   * @example 50
+   */
+  checkEvery: -1
+};
+
+/**
+ * Helper function to calculate em values
+ * @param Number {em} - number of em's to calculate into pixels
+ */
+function emCalc(em) {
+  return parseInt(window.getComputedStyle(document.body, null).fontSize, 10) * em;
+}
+
+// Window exports
+if (window.Foundation) {
+  window.Foundation.plugin(Sticky, 'Sticky');
+}