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

index f53e3941e9d76011b9ec34394be66f089c2f9272..b49ae0efc772c97033f78c36887585f2d7b5daa6 100644 (file)
@@ -1,3 +1,5 @@
+'use strict';
+
 /**
  * OffCanvas module.
  * @module foundation.offcanvas
  * @requires foundation.util.triggers
  * @requires foundation.util.motion
  */
-!function($, Foundation) {
 
-'use strict';
+export default class OffCanvas {
+  /**
+   * Creates a new instance of an off-canvas wrapper.
+   * @class
+   * @fires OffCanvas#init
+   * @param {Object} element - jQuery object to initialize.
+   * @param {Object} options - Overrides to the default plugin settings.
+   */
+  constructor(element, options) {
+    this.$element = element;
+    this.options = $.extend({}, OffCanvas.defaults, this.$element.data(), options);
+    this.$lastTrigger = $();
 
-/**
- * Creates a new instance of an off-canvas wrapper.
- * @class
- * @fires OffCanvas#init
- * @param {Object} element - jQuery object to initialize.
- * @param {Object} options - Overrides to the default plugin settings.
- */
-function OffCanvas(element, options) {
-  this.$element = element;
-  this.options = $.extend({}, OffCanvas.defaults, this.$element.data(), options);
-  this.$lastTrigger = $();
+    this._init();
+    this._events();
+
+    Foundation.registerPlugin(this, 'OffCanvas');
+  }
+
+  /**
+   * Initializes the off-canvas wrapper by adding the exit overlay (if needed).
+   * @function
+   * @private
+   */
+  _init() {
+    var id = this.$element.attr('id');
+
+    this.$element.attr('aria-hidden', 'true');
+
+    // Find triggers that affect this element and add aria-expanded to them
+    $(document)
+      .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
+      .attr('aria-expanded', 'false')
+      .attr('aria-controls', id);
+
+    // Add a close trigger over the body if necessary
+    if (this.options.closeOnClick) {
+      if ($('.js-off-canvas-exit').length) {
+        this.$exiter = $('.js-off-canvas-exit');
+      } else {
+        var exiter = document.createElement('div');
+        exiter.setAttribute('class', 'js-off-canvas-exit');
+        $('[data-off-canvas-content]').append(exiter);
+
+        this.$exiter = $(exiter);
+      }
+    }
+
+    this.options.isRevealed = this.options.isRevealed || new RegExp(this.options.revealClass, 'g').test(this.$element[0].className);
+
+    if (this.options.isRevealed) {
+      this.options.revealOn = this.options.revealOn || this.$element[0].className.match(/(reveal-for-medium|reveal-for-large)/g)[0].split('-')[2];
+      this._setMQChecker();
+    }
+    if (!this.options.transitionTime) {
+      this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas-wrapper]')[0]).transitionDuration) * 1000;
+    }
+  }
+
+  /**
+   * Adds event handlers to the off-canvas wrapper and the exit overlay.
+   * @function
+   * @private
+   */
+  _events() {
+    this.$element.off('.zf.trigger .zf.offcanvas').on({
+      'open.zf.trigger': this.open.bind(this),
+      'close.zf.trigger': this.close.bind(this),
+      'toggle.zf.trigger': this.toggle.bind(this),
+      'keydown.zf.offcanvas': this._handleKeyboard.bind(this)
+    });
+
+    if (this.options.closeOnClick && this.$exiter.length) {
+      this.$exiter.on({'click.zf.offcanvas': this.close.bind(this)});
+    }
+  }
+
+  /**
+   * Applies event listener for elements that will reveal at certain breakpoints.
+   * @private
+   */
+  _setMQChecker() {
+    var _this = this;
+
+    $(window).on('changed.zf.mediaquery', function() {
+      if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) {
+        _this.reveal(true);
+      } else {
+        _this.reveal(false);
+      }
+    }).one('load.zf.offcanvas', function() {
+      if (Foundation.MediaQuery.atLeast(_this.options.revealOn)) {
+        _this.reveal(true);
+      }
+    });
+  }
+
+  /**
+   * Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
+   * @param {Boolean} isRevealed - true if element should be revealed.
+   * @function
+   */
+  reveal(isRevealed) {
+    var $closer = this.$element.find('[data-close]');
+    if (isRevealed) {
+      this.close();
+      this.isRevealed = true;
+      // if (!this.options.forceTop) {
+      //   var scrollPos = parseInt(window.pageYOffset);
+      //   this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
+      // }
+      // if (this.options.isSticky) { this._stick(); }
+      this.$element.off('open.zf.trigger toggle.zf.trigger');
+      if ($closer.length) { $closer.hide(); }
+    } else {
+      this.isRevealed = false;
+      // if (this.options.isSticky || !this.options.forceTop) {
+      //   this.$element[0].style.transform = '';
+      //   $(window).off('scroll.zf.offcanvas');
+      // }
+      this.$element.on({
+        'open.zf.trigger': this.open.bind(this),
+        'toggle.zf.trigger': this.toggle.bind(this)
+      });
+      if ($closer.length) {
+        $closer.show();
+      }
+    }
+  }
+
+  /**
+   * Opens the off-canvas menu.
+   * @function
+   * @param {Object} event - Event object passed from listener.
+   * @param {jQuery} trigger - element that triggered the off-canvas to open.
+   * @fires OffCanvas#opened
+   */
+  open(event, trigger) {
+    if (this.$element.hasClass('is-open') || this.isRevealed) { return; }
+    var _this = this,
+        $body = $(document.body);
+    $('body').scrollTop(0);
+    // window.pageYOffset = 0;
+
+    // if (!this.options.forceTop) {
+    //   var scrollPos = parseInt(window.pageYOffset);
+    //   this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
+    //   if (this.$exiter.length) {
+    //     this.$exiter[0].style.transform = 'translate(0,' + scrollPos + 'px)';
+    //   }
+    // }
+    /**
+     * Fires when the off-canvas menu opens.
+     * @event OffCanvas#opened
+     */
+    Foundation.Move(this.options.transitionTime, this.$element, function() {
+      $('[data-off-canvas-wrapper]').addClass('is-off-canvas-open is-open-'+ _this.options.position);
+
+      _this.$element
+        .addClass('is-open')
+
+      // if (_this.options.isSticky) {
+      //   _this._stick();
+      // }
+    });
+    this.$element.attr('aria-hidden', 'false')
+        .trigger('opened.zf.offcanvas');
+
+    if (this.options.closeOnClick) {
+      this.$exiter.addClass('is-visible');
+    }
+
+    if (trigger) {
+      this.$lastTrigger = trigger.attr('aria-expanded', 'true');
+    }
+
+    if (this.options.autoFocus) {
+      this.$element.one('finished.zf.animate', function() {
+        _this.$element.find('a, button').eq(0).focus();
+      });
+    }
+
+    if (this.options.trapFocus) {
+      $('[data-off-canvas-content]').attr('tabindex', '-1');
+      this._trapFocus();
+    }
+  }
 
-  this._init();
-  this._events();
+  /**
+   * Traps focus within the offcanvas on open.
+   * @private
+   */
+  _trapFocus() {
+    var focusable = Foundation.Keyboard.findFocusable(this.$element),
+        first = focusable.eq(0),
+        last = focusable.eq(-1);
 
-  Foundation.registerPlugin(this, 'OffCanvas');
+    focusable.off('.zf.offcanvas').on('keydown.zf.offcanvas', function(e) {
+      if (e.which === 9 || e.keycode === 9) {
+        if (e.target === last[0] && !e.shiftKey) {
+          e.preventDefault();
+          first.focus();
+        }
+        if (e.target === first[0] && e.shiftKey) {
+          e.preventDefault();
+          last.focus();
+        }
+      }
+    });
+  }
+
+  /**
+   * Allows the offcanvas to appear sticky utilizing translate properties.
+   * @private
+   */
+  // OffCanvas.prototype._stick = function() {
+  //   var elStyle = this.$element[0].style;
+  //
+  //   if (this.options.closeOnClick) {
+  //     var exitStyle = this.$exiter[0].style;
+  //   }
+  //
+  //   $(window).on('scroll.zf.offcanvas', function(e) {
+  //     console.log(e);
+  //     var pageY = window.pageYOffset;
+  //     elStyle.transform = 'translate(0,' + pageY + 'px)';
+  //     if (exitStyle !== undefined) { exitStyle.transform = 'translate(0,' + pageY + 'px)'; }
+  //   });
+  //   // this.$element.trigger('stuck.zf.offcanvas');
+  // };
+  /**
+   * Closes the off-canvas menu.
+   * @function
+   * @param {Function} cb - optional cb to fire after closure.
+   * @fires OffCanvas#closed
+   */
+  close(cb) {
+    if (!this.$element.hasClass('is-open') || this.isRevealed) { return; }
+
+    var _this = this;
+
+    //  Foundation.Move(this.options.transitionTime, this.$element, function() {
+    $('[data-off-canvas-wrapper]').removeClass(`is-off-canvas-open is-open-${_this.options.position}`);
+    _this.$element.removeClass('is-open');
+      // Foundation._reflow();
+    // });
+    this.$element.attr('aria-hidden', 'true')
+      /**
+       * Fires when the off-canvas menu opens.
+       * @event OffCanvas#closed
+       */
+        .trigger('closed.zf.offcanvas');
+    // if (_this.options.isSticky || !_this.options.forceTop) {
+    //   setTimeout(function() {
+    //     _this.$element[0].style.transform = '';
+    //     $(window).off('scroll.zf.offcanvas');
+    //   }, this.options.transitionTime);
+    // }
+    if (this.options.closeOnClick) {
+      this.$exiter.removeClass('is-visible');
+    }
+
+    this.$lastTrigger.attr('aria-expanded', 'false');
+    if (this.options.trapFocus) {
+      $('[data-off-canvas-content]').removeAttr('tabindex');
+    }
+  }
+
+  /**
+   * Toggles the off-canvas menu open or closed.
+   * @function
+   * @param {Object} event - Event object passed from listener.
+   * @param {jQuery} trigger - element that triggered the off-canvas to open.
+   */
+  toggle(event, trigger) {
+    if (this.$element.hasClass('is-open')) {
+      this.close(event, trigger);
+    }
+    else {
+      this.open(event, trigger);
+    }
+  }
+
+  /**
+   * Handles keyboard input when detected. When the escape key is pressed, the off-canvas menu closes, and focus is restored to the element that opened the menu.
+   * @function
+   * @private
+   */
+  _handleKeyboard(event) {
+    if (event.which !== 27) return;
+
+    event.stopPropagation();
+    event.preventDefault();
+    this.close();
+    this.$lastTrigger.focus();
+  }
+
+  /**
+   * Destroys the offcanvas plugin.
+   * @function
+   */
+  destroy() {
+    this.close();
+    this.$element.off('.zf.trigger .zf.offcanvas');
+    this.$exiter.off('.zf.offcanvas');
+
+    Foundation.unregisterPlugin(this);
+  }
 }
 
 OffCanvas.defaults = {
@@ -88,289 +379,8 @@ OffCanvas.defaults = {
   trapFocus: false
 };
 
-/**
- * Initializes the off-canvas wrapper by adding the exit overlay (if needed).
- * @function
- * @private
- */
-OffCanvas.prototype._init = function() {
-  var id = this.$element.attr('id');
-
-  this.$element.attr('aria-hidden', 'true');
-
-  // Find triggers that affect this element and add aria-expanded to them
-  $(document)
-    .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
-    .attr('aria-expanded', 'false')
-    .attr('aria-controls', id);
-
-  // Add a close trigger over the body if necessary
-  if (this.options.closeOnClick){
-    if($('.js-off-canvas-exit').length){
-      this.$exiter = $('.js-off-canvas-exit');
-    }else{
-      var exiter = document.createElement('div');
-      exiter.setAttribute('class', 'js-off-canvas-exit');
-      $('[data-off-canvas-content]').append(exiter);
-
-      this.$exiter = $(exiter);
-    }
-  }
-
-  this.options.isRevealed = this.options.isRevealed || new RegExp(this.options.revealClass, 'g').test(this.$element[0].className);
-
-  if(this.options.isRevealed){
-    this.options.revealOn = this.options.revealOn || this.$element[0].className.match(/(reveal-for-medium|reveal-for-large)/g)[0].split('-')[2];
-    this._setMQChecker();
-  }
-  if(!this.options.transitionTime){
-    this.options.transitionTime = parseFloat(window.getComputedStyle($('[data-off-canvas-wrapper]')[0]).transitionDuration) * 1000;
-  }
-};
-
-/**
- * Adds event handlers to the off-canvas wrapper and the exit overlay.
- * @function
- * @private
- */
-OffCanvas.prototype._events = function() {
-  this.$element.off('.zf.trigger .zf.offcanvas').on({
-    'open.zf.trigger': this.open.bind(this),
-    'close.zf.trigger': this.close.bind(this),
-    'toggle.zf.trigger': this.toggle.bind(this),
-    'keydown.zf.offcanvas': this._handleKeyboard.bind(this)
-  });
-
-  if (this.options.closeOnClick && this.$exiter.length) {
-    this.$exiter.on({'click.zf.offcanvas': this.close.bind(this)});
-  }
-};
-/**
- * Applies event listener for elements that will reveal at certain breakpoints.
- * @private
- */
-OffCanvas.prototype._setMQChecker = function(){
-  var _this = this;
-
-  $(window).on('changed.zf.mediaquery', function(){
-    if(Foundation.MediaQuery.atLeast(_this.options.revealOn)){
-      _this.reveal(true);
-    }else{
-      _this.reveal(false);
-    }
-  }).one('load.zf.offcanvas', function(){
-    if(Foundation.MediaQuery.atLeast(_this.options.revealOn)){
-      _this.reveal(true);
-    }
-  });
-};
-/**
- * Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
- * @param {Boolean} isRevealed - true if element should be revealed.
- * @function
- */
-OffCanvas.prototype.reveal = function(isRevealed){
-  var $closer = this.$element.find('[data-close]');
-  if(isRevealed){
-    this.close();
-    this.isRevealed = true;
-    // if(!this.options.forceTop){
-    //   var scrollPos = parseInt(window.pageYOffset);
-    //   this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
-    // }
-    // if(this.options.isSticky){ this._stick(); }
-    this.$element.off('open.zf.trigger toggle.zf.trigger');
-    if($closer.length){ $closer.hide(); }
-  }else{
-    this.isRevealed = false;
-    // if(this.options.isSticky || !this.options.forceTop){
-    //   this.$element[0].style.transform = '';
-    //   $(window).off('scroll.zf.offcanvas');
-    // }
-    this.$element.on({
-      'open.zf.trigger': this.open.bind(this),
-      'toggle.zf.trigger': this.toggle.bind(this)
-    });
-    if($closer.length){
-      $closer.show();
-    }
-  }
-};
-
-/**
- * Opens the off-canvas menu.
- * @function
- * @param {Object} event - Event object passed from listener.
- * @param {jQuery} trigger - element that triggered the off-canvas to open.
- * @fires OffCanvas#opened
- */
-OffCanvas.prototype.open = function(event, trigger) {
-  if (this.$element.hasClass('is-open') || this.isRevealed){ return; }
-  var _this = this,
-      $body = $(document.body);
-  $('body').scrollTop(0);
-  // window.pageYOffset = 0;
-
-  // if(!this.options.forceTop){
-  //   var scrollPos = parseInt(window.pageYOffset);
-  //   this.$element[0].style.transform = 'translate(0,' + scrollPos + 'px)';
-  //   if(this.$exiter.length){
-  //     this.$exiter[0].style.transform = 'translate(0,' + scrollPos + 'px)';
-  //   }
-  // }
-  /**
-   * Fires when the off-canvas menu opens.
-   * @event OffCanvas#opened
-   */
-  Foundation.Move(this.options.transitionTime, this.$element, function(){
-    $('[data-off-canvas-wrapper]').addClass('is-off-canvas-open is-open-'+ _this.options.position);
-
-    _this.$element
-      .addClass('is-open')
-
-    // if(_this.options.isSticky){
-    //   _this._stick();
-    // }
-  });
-  this.$element.attr('aria-hidden', 'false')
-      .trigger('opened.zf.offcanvas');
-
-  if(this.options.closeOnClick){
-    this.$exiter.addClass('is-visible');
-  }
-  if(trigger){
-    this.$lastTrigger = trigger.attr('aria-expanded', 'true');
-  }
-  if(this.options.autoFocus){
-    this.$element.one('finished.zf.animate', function(){
-      _this.$element.find('a, button').eq(0).focus();
-    });
-  }
-  if(this.options.trapFocus){
-    $('[data-off-canvas-content]').attr('tabindex', '-1');
-    this._trapFocus();
-  }
-};
-/**
- * Traps focus within the offcanvas on open.
- * @private
- */
-OffCanvas.prototype._trapFocus = function(){
-  var focusable = Foundation.Keyboard.findFocusable(this.$element),
-      first = focusable.eq(0),
-      last = focusable.eq(-1);
-
-  focusable.off('.zf.offcanvas').on('keydown.zf.offcanvas', function(e){
-    if(e.which === 9 || e.keycode === 9){
-      if(e.target === last[0] && !e.shiftKey){
-        e.preventDefault();
-        first.focus();
-      }
-      if(e.target === first[0] && e.shiftKey){
-        e.preventDefault();
-        last.focus();
-      }
-    }
-  });
-};
-/**
- * Allows the offcanvas to appear sticky utilizing translate properties.
- * @private
- */
-// OffCanvas.prototype._stick = function(){
-//   var elStyle = this.$element[0].style;
-//
-//   if(this.options.closeOnClick){
-//     var exitStyle = this.$exiter[0].style;
-//   }
-//
-//   $(window).on('scroll.zf.offcanvas', function(e){
-//     console.log(e);
-//     var pageY = window.pageYOffset;
-//     elStyle.transform = 'translate(0,' + pageY + 'px)';
-//     if(exitStyle !== undefined){ exitStyle.transform = 'translate(0,' + pageY + 'px)'; }
-//   });
-//   // this.$element.trigger('stuck.zf.offcanvas');
-// };
-/**
- * Closes the off-canvas menu.
- * @function
- * @param {Function} cb - optional cb to fire after closure.
- * @fires OffCanvas#closed
- */
-OffCanvas.prototype.close = function(cb) {
-  if(!this.$element.hasClass('is-open') || this.isRevealed){ return; }
-
-  var _this = this;
-
-  //  Foundation.Move(this.options.transitionTime, this.$element, function(){
-  $('[data-off-canvas-wrapper]').removeClass(`is-off-canvas-open is-open-${_this.options.position}`);
-  _this.$element.removeClass('is-open');
-    // Foundation._reflow();
-  // });
-  this.$element.attr('aria-hidden', 'true')
-    /**
-     * Fires when the off-canvas menu opens.
-     * @event OffCanvas#closed
-     */
-      .trigger('closed.zf.offcanvas');
-  // if(_this.options.isSticky || !_this.options.forceTop){
-  //   setTimeout(function(){
-  //     _this.$element[0].style.transform = '';
-  //     $(window).off('scroll.zf.offcanvas');
-  //   }, this.options.transitionTime);
-  // }
-  if(this.options.closeOnClick){
-    this.$exiter.removeClass('is-visible');
-  }
-
-  this.$lastTrigger.attr('aria-expanded', 'false');
-  if(this.options.trapFocus){
-    $('[data-off-canvas-content]').removeAttr('tabindex');
-  }
-
-};
-
-/**
- * Toggles the off-canvas menu open or closed.
- * @function
- * @param {Object} event - Event object passed from listener.
- * @param {jQuery} trigger - element that triggered the off-canvas to open.
- */
-OffCanvas.prototype.toggle = function(event, trigger) {
-  if (this.$element.hasClass('is-open')) {
-    this.close(event, trigger);
-  }
-  else {
-    this.open(event, trigger);
-  }
-};
-
-/**
- * Handles keyboard input when detected. When the escape key is pressed, the off-canvas menu closes, and focus is restored to the element that opened the menu.
- * @function
- * @private
- */
-OffCanvas.prototype._handleKeyboard = function(event) {
-  if (event.which !== 27) return;
-
-  event.stopPropagation();
-  event.preventDefault();
-  this.close();
-  this.$lastTrigger.focus();
-};
-/**
- * Destroys the offcanvas plugin.
- * @function
- */
-OffCanvas.prototype.destroy = function(){
-  this.close();
-  this.$element.off('.zf.trigger .zf.offcanvas');
-  this.$exiter.off('.zf.offcanvas');
-
-  Foundation.unregisterPlugin(this);
-};
-
-Foundation.plugin(OffCanvas, 'OffCanvas');
+// Window exports
+if (window.Foundation) {
+  window.Foundation.plugin(OffCanvas, 'OffCanvas');
+}
 
-}(jQuery, Foundation);