From: Colin Marshall Date: Thu, 4 Feb 2016 04:22:19 +0000 (-0700) Subject: Convert offcanvas to ES6 class X-Git-Tag: v6.2.0-rc.1~41^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e19711e2f308abfdc48c5cf5823e4559f124183f;p=thirdparty%2Ffoundation%2Ffoundation-sites.git Convert offcanvas to ES6 class --- diff --git a/js/foundation.offcanvas.js b/js/foundation.offcanvas.js index f53e3941e..b49ae0efc 100644 --- a/js/foundation.offcanvas.js +++ b/js/foundation.offcanvas.js @@ -1,3 +1,5 @@ +'use strict'; + /** * OffCanvas module. * @module foundation.offcanvas @@ -5,26 +7,315 @@ * @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);