From: Chris Oyler Date: Wed, 23 Dec 2015 18:45:11 +0000 (-0800) Subject: fixes #7666 adds option and method for offcanvas to trap focus on open. also ensures... X-Git-Tag: v6.1.1~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b70bf45b078519a887a1cfac5cb7f322d2be926;p=thirdparty%2Ffoundation%2Ffoundation-sites.git fixes #7666 adds option and method for offcanvas to trap focus on open. also ensures event listeners are not applied multiple times if the offcanvas is reinitialized. --- diff --git a/js/foundation.offcanvas.js b/js/foundation.offcanvas.js index b194a7b8a..8c06ca17c 100644 --- a/js/foundation.offcanvas.js +++ b/js/foundation.offcanvas.js @@ -78,7 +78,13 @@ OffCanvas.defaults = { * TODO improve the regex testing for this. * @example reveal-for-large */ - revealClass: 'reveal-for-' + revealClass: 'reveal-for-', + /** + * Triggers optional focus trapping when opening an offcanvas. Sets tabindex of [data-off-canvas-content] to -1 for accessibility purposes. + * @option + * @example true + */ + trapFocus: false }; /** @@ -127,7 +133,7 @@ OffCanvas.prototype._init = function() { * @private */ OffCanvas.prototype._events = function() { - this.$element.on({ + 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), @@ -171,12 +177,17 @@ OffCanvas.prototype.reveal = function(isRevealed){ // 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{ // 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(); } @@ -221,7 +232,7 @@ OffCanvas.prototype.open = function(event, trigger) { this.$element.attr('aria-hidden', 'false') .trigger('opened.zf.offcanvas'); - + if(trigger){ this.$lastTrigger = trigger.attr('aria-expanded', 'true'); } @@ -230,6 +241,32 @@ OffCanvas.prototype.open = function(event, trigger) { _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. @@ -280,6 +317,9 @@ OffCanvas.prototype.close = function(cb) { // } this.$lastTrigger.attr('aria-expanded', 'false'); + if(this.options.trapFocus){ + $('[data-off-canvas-content]').removeAttr('tabindex'); + } };