File: development/modules/tabs/js/tabs.js
import $ from 'jquery';
import DOMModule from '../../__base/dommodule';
/**
* @module Modules
*/
// PRIVATE METHODS
const handleClick = Symbol('_handleClick');
/**
* Tabbox module
* @class Modules.Tabbox
* @constructor
* @extends Modules._DOMModule
*/
class Tabbox extends DOMModule {
constructor(options) {
super(options);
this.$tabNodes = this.$findChilds('[data-tabbox-action]');
this.$contentNodes = this.$findChilds('[data-tabbox-effect]');
this.$bodyNode = this.$findChilds('.tabbox_body');
this.$maskNode = $('<div></div>').addClass('tabbox_mask');
}
/**
* Creates a new Tabbox instance without the "new" keyword but does not
* initialize it
* @method of
* @static
* @for Modules.Tabbox
* @param {node|string|configs} node Node, CSS selector or configuration object
* @return {Tabbox} A new instance
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* const myTabbox = Tabbox.of('[data-widget=Tabbox]');
* myTabbox.render().startUp();
*/
static of (node) {
return new Tabbox(node);
}
/**
* Finds and initializes all Tabbox on a page at once
* @method findAll
* @static
* @for Modules.Tabbox
* @param {string} selector CSS selector to match nodes against
* @return {array} A list of instances
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* Tabbox.findAll('[data-widget=Tabbox]');
*/
static findAll(selector) {
return $(selector).toArray().map((node) => {
const tabbox = Tabbox.of(node);
tabbox.render().startUp();
return tabbox;
});
}
/**
* Renders missing nodes into the instance and returns it
* @method render
* @for Modules.Tabbox
* @return {this} The instance
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* const myTabbox = Tabbox.of('[data-widget=Tabbox]');
* myTabbox.render();
*/
render() {
const contents = this.$contentNodes.detach();
this.$maskNode.
append(contents).
css('height', '0').
addClass('tabbox_mask--hidden');
this.$bodyNode.append(this.$maskNode);
return this;
}
/**
* Attaches all eventlisteners to the tabbox instance and opens the one tab
* that holds the class `is-active`. If more than one tab in the same
* tabbox hold the class `is-active`, the first one is being activated.
* If none of the tabs in one tabbox hold the class `is-active`, the
* first tab is being activated
* @method startUp
* @for Modules.Tabbox
* @return {undefined} Nothing
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* const myTabbox = Tabbox.of('[data-widget=Tabbox]');
* myTabbox.render().startUp();
*/
startUp() {
const activeTabs = this.$tabNodes.
toArray().
filter((tab) => $(tab).hasClass('is-active'));
if (activeTabs.length > 0) {
this.hideAll();
this.show($(activeTabs[0]));
} else {
this.show(this.$tabNodes.first());
}
this.onClick('[data-tabbox-action]', handleClick);
}
/**
* Sets all tabs to inactive state when one tab is being opened
* @method hideAll
* @for Modules.Tabbox
* @return {undefined} Nothing
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* const myTabbox = Tabbox.of('[data-widget=Tabbox]');
* myTabbox.render().startUp();
*
* myTabbox.hideAll();
*/
hideAll() {
this.$tabNodes.removeClass('is-active');
this.$contentNodes.removeClass('is-active');
}
/**
* Sets the tab and its content to active state
* @method show
* @for Modules.Tabbox
* @param {node} node Node
* @return {undefined} Nothing
*
* @example
* import Tabbox from './modules/tabs/js/tabs';
*
* const myTabbox = Tabbox.of('[data-widget=Tabbox]');
* myTabbox.render().startUp();
*
* myTabbox.show($('[href="#tab-a"]'));
*/
show($tab) {
const ref = $tab.attr('href').split("#")[1];
const $content = $('[id="' + ref +'"]');
if (!$content.length) {
throw `Tabbox: Unable to find matching content for tab "#${ref}"`
}
$content.addClass('is-active');
$tab.addClass('is-active');
this.$maskNode.css({
height: $content.outerHeight()
});
}
// === EVENT HANDLERS ===
[handleClick](event) {
event.preventDefault();
this.hideAll();
this.show($(event.currentTarget));
}
}
export default Tabbox;