vendor/assets/js/foundation.tabs.js.es6 in foundation-rails-6.2.4.0 vs vendor/assets/js/foundation.tabs.js.es6 in foundation-rails-6.3.0.0

- old
+ new

@@ -40,17 +40,18 @@ * @private */ _init() { var _this = this; + this.$element.attr({'role': 'tablist'}); this.$tabTitles = this.$element.find(`.${this.options.linkClass}`); this.$tabContent = $(`[data-tabs-content="${this.$element[0].id}"]`); this.$tabTitles.each(function(){ var $elem = $(this), $link = $elem.find('a'), - isActive = $elem.hasClass('is-active'), + isActive = $elem.hasClass(`${_this.options.linkActiveClass}`), hash = $link[0].hash.slice(1), linkId = $link[0].id ? $link[0].id : `${hash}-label`, $tabContent = $(`#${hash}`); $elem.attr({'role': 'presentation'}); @@ -67,12 +68,42 @@ 'aria-hidden': !isActive, 'aria-labelledby': linkId }); if(isActive && _this.options.autoFocus){ - $link.focus(); + $(window).load(function() { + $('html, body').animate({ scrollTop: $elem.offset().top }, _this.options.deepLinkSmudgeDelay, () => { + $link.focus(); + }); + }); } + + //use browser to open a tab, if it exists in this tabset + if (_this.options.deepLink) { + var anchor = window.location.hash; + //need a hash and a relevant anchor in this tabset + if(anchor.length) { + var $link = $elem.find('[href="'+anchor+'"]'); + if ($link.length) { + _this.selectTab($(anchor)); + + //roll up a little to show the titles + if (_this.options.deepLinkSmudge) { + $(window).load(function() { + var offset = $elem.offset(); + $('html, body').animate({ scrollTop: offset.top }, _this.options.deepLinkSmudgeDelay); + }); + } + + /** + * Fires when the zplugin has deeplinked at pageload + * @event Tabs#deeplink + */ + $elem.trigger('deeplink.zf.tabs', [$link, $(anchor)]); + } + } + } }); if(this.options.matchHeight) { var $images = this.$tabContent.find('img'); @@ -92,14 +123,14 @@ */ _events() { this._addKeyHandler(); this._addClickHandler(); this._setHeightMqHandler = null; - + if (this.options.matchHeight) { this._setHeightMqHandler = this._setHeight.bind(this); - + $(window).on('changed.zf.mediaquery', this._setHeightMqHandler); } } /** @@ -112,30 +143,25 @@ this.$element .off('click.zf.tabs') .on('click.zf.tabs', `.${this.options.linkClass}`, function(e){ e.preventDefault(); e.stopPropagation(); - if ($(this).hasClass('is-active')) { - return; - } _this._handleTabChange($(this)); }); } /** * Adds keyboard event handlers for items within the tabs. * @private */ _addKeyHandler() { var _this = this; - var $firstTab = _this.$element.find('li:first-of-type'); - var $lastTab = _this.$element.find('li:last-of-type'); this.$tabTitles.off('keydown.zf.tabs').on('keydown.zf.tabs', function(e){ if (e.which === 9) return; - + var $element = $(this), $elements = $element.parent('ul').children('li'), $prevElement, $nextElement; @@ -173,45 +199,102 @@ }); }); } /** - * Opens the tab `$targetContent` defined by `$target`. + * Opens the tab `$targetContent` defined by `$target`. Collapses active tab. * @param {jQuery} $target - Tab to open. * @fires Tabs#change * @function */ _handleTabChange($target) { - var $tabLink = $target.find('[role="tab"]'), - hash = $tabLink[0].hash, - $targetContent = this.$tabContent.find(hash), - $oldTab = this.$element. - find(`.${this.options.linkClass}.is-active`) - .removeClass('is-active') - .find('[role="tab"]') - .attr({ 'aria-selected': 'false' }); - $(`#${$oldTab.attr('aria-controls')}`) - .removeClass('is-active') - .attr({ 'aria-hidden': 'true' }); + /** + * Check for active class on target. Collapse if exists. + */ + if ($target.hasClass(`${this.options.linkActiveClass}`)) { + if(this.options.activeCollapse) { + this._collapseTab($target); - $target.addClass('is-active'); + /** + * Fires when the zplugin has successfully collapsed tabs. + * @event Tabs#collapse + */ + this.$element.trigger('collapse.zf.tabs', [$target]); + } + return; + } - $tabLink.attr({'aria-selected': 'true'}); + var $oldTab = this.$element. + find(`.${this.options.linkClass}.${this.options.linkActiveClass}`), + $tabLink = $target.find('[role="tab"]'), + hash = $tabLink[0].hash, + $targetContent = this.$tabContent.find(hash); - $targetContent - .addClass('is-active') - .attr({'aria-hidden': 'false'}); + //close old tab + this._collapseTab($oldTab); + //open new tab + this._openTab($target); + + //either replace or update browser history + if (this.options.deepLink) { + var anchor = $target.find('a').attr('href'); + + if (this.options.updateHistory) { + history.pushState({}, '', anchor); + } else { + history.replaceState({}, '', anchor); + } + } + /** * Fires when the plugin has successfully changed tabs. * @event Tabs#change */ - this.$element.trigger('change.zf.tabs', [$target]); + this.$element.trigger('change.zf.tabs', [$target, $targetContent]); + + //fire to children a mutation event + $targetContent.find("[data-mutate]").trigger("mutateme.zf.trigger"); } /** + * Opens the tab `$targetContent` defined by `$target`. + * @param {jQuery} $target - Tab to Open. + * @function + */ + _openTab($target) { + var $tabLink = $target.find('[role="tab"]'), + hash = $tabLink[0].hash, + $targetContent = this.$tabContent.find(hash); + + $target.addClass(`${this.options.linkActiveClass}`); + + $tabLink.attr({'aria-selected': 'true'}); + + $targetContent + .addClass(`${this.options.panelActiveClass}`) + .attr({'aria-hidden': 'false'}); + } + + /** + * Collapses `$targetContent` defined by `$target`. + * @param {jQuery} $target - Tab to Open. + * @function + */ + _collapseTab($target) { + var $target_anchor = $target + .removeClass(`${this.options.linkActiveClass}`) + .find('[role="tab"]') + .attr({ 'aria-selected': 'false' }); + + $(`#${$target_anchor.attr('aria-controls')}`) + .removeClass(`${this.options.panelActiveClass}`) + .attr({ 'aria-hidden': 'true' }); + } + + /** * Public method for selecting a content pane to display. * @param {jQuery | String} elem - jQuery object or string of the id of the pane to display. * @function */ selectTab(elem) { @@ -243,11 +326,11 @@ this.$tabContent .find(`.${this.options.panelClass}`) .css('height', '') .each(function() { var panel = $(this), - isActive = panel.hasClass('is-active'); + isActive = panel.hasClass(`${this.options.panelActiveClass}`); if (!isActive) { panel.css({'visibility': 'hidden', 'display': 'block'}); } @@ -286,11 +369,40 @@ } } Tabs.defaults = { /** + * Allows the window to scroll to content of pane specified by hash anchor + * @option + * @example false + */ + deepLink: false, + + /** + * Adjust the deep link scroll to make sure the top of the tab panel is visible + * @option + * @example false + */ + deepLinkSmudge: false, + + /** + * Animation time (ms) for the deep link adjustment + * @option + * @example 300 + */ + deepLinkSmudgeDelay: 300, + + /** + * Update the browser history with the open tab + * @option + * @example false + */ + updateHistory: false, + + /** * Allows the window to scroll to content of active pane on load if set to true. + * Not recommended if more than one tab panel per page. * @option * @example false */ autoFocus: false, @@ -307,26 +419,43 @@ * @example false */ matchHeight: false, /** + * Allows active tabs to collapse when clicked. + * @option + * @example false + */ + activeCollapse: false, + + /** * Class applied to `li`'s in tab link list. * @option * @example 'tabs-title' */ linkClass: 'tabs-title', /** + * Class applied to the active `li` in tab link list. + * @option + * @example 'is-active' + */ + linkActiveClass: 'is-active', + + /** * Class applied to the content containers. * @option * @example 'tabs-panel' */ - panelClass: 'tabs-panel' -}; + panelClass: 'tabs-panel', -function checkClass($elem){ - return $elem.hasClass('is-active'); -} + /** + * Class applied to the active content container. + * @option + * @example 'is-active' + */ + panelActiveClass: 'is-active' +}; // Window exports Foundation.plugin(Tabs, 'Tabs'); }(jQuery);