Source: BSTabs.js

/**
                * @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
                */

                /* global $ */
                /* global console */
                /* global EventEmitter */

                /* @depend QfqEvents.js */

                /**
                * Qfq Namespace
                *
                * @namespace QfqNS
                */
                var QfqNS = QfqNS || {};


                (function (n) {
                'use strict';
                /**
                * Tab Constructor.
                *
                * Programatically access Bootstrap nav-tabs.
                *
                * @param {string} tabId HTML id of the element having `nav` and `nav-tabs` classes
                * @constructor
                *
                * @name QfqNS.BSTabs
                */
                n.BSTabs = function (tabId) {
                this.tabId = tabId;
                this._tabContainerLinkSelector = '#' + this.tabId + ' a[data-toggle="tab"]';
                this._tabActiveSelector = '#' + this.tabId + ' .active a[data-toggle="tab"]';
                this.tabs = {};
                this.currentTab = this.getActiveTabFromDOM();
                this.eventEmitter = new EventEmitter();

                // Fill this.tabs
                this.fillTabInformation();

                // Enable update of current tab field
                this.installTabHandlers();
                };

                n.BSTabs.prototype.on = n.EventEmitter.onMixin;

                /**
                * Get active tab from DOM.
                *
                * Used upon object creation to fill the currentTab. It gets the ID of the currently shown tab. It does
                it, by
                * targeting the element in the navigator having the `active` class set.
                *
                * @private
                */
                n.BSTabs.prototype.getActiveTabFromDOM = function () {
                var activeTabAnchors = $(this._tabActiveSelector);
                if (activeTabAnchors.length < 1) {
                // This could be due to the DOM not fully loaded. If that's really the case, then the active tab
                // attribute should be set by the show.bs.tab handler
                return null;
                }

                return activeTabAnchors[0].hash.slice(1);
                };

                /**
                * Fill tabs object.
                *
                * Fill the tabs object using the tab HTML id as attribute name
                *
                * @private
                */
                n.BSTabs.prototype.fillTabInformation = function () {
                var tabLinks = $(this._tabContainerLinkSelector);
                if ($(tabLinks).length === 0) {
                throw new Error("Unable to find a BootStrap container matching: " + this._tabContainerLinkSelector);
                }

                var that = this;
                tabLinks.each(function (index, element) {
                if (element.hash !== "") {
                var tabId = element.hash.slice(1);

                that.tabs[tabId] = {
                index: index,
                element: element
                };
                }
                }
                );
                };

                /**
                * @private
                */
                n.BSTabs.prototype.installTabHandlers = function () {
                $(this._tabContainerLinkSelector)
                .on('show.bs.tab', this.tabShowHandler.bind(this));

                };

                /**
                * Tab Show handler.
                *
                * Sets this.currentTab to the clicked tab and calls all registered tab click handlers.
                *
                * @private
                * @param event
                */
                n.BSTabs.prototype.tabShowHandler = function (event) {
                n.Log.debug('Enter: BSTabs.tabShowHandler()');
                this.currentTab = event.target.hash.slice(1);

                n.Log.debug("BSTabs.tabShowHandler(): invoke user handler(s)");
                this.eventEmitter.emitEvent('bootstrap.tab.shown', n.EventEmitter.makePayload(this, null));
                n.Log.debug('Exit: BSTabs.tabShowHandler()');
                };

                /**
                * Get all tab IDs.
                *
                * @returns {Array}
                *
                * @public
                */
                n.BSTabs.prototype.getTabIds = function () {
                var tabIds = [];
                for (var tabId in this.tabs) {
                if (this.tabs.hasOwnProperty(tabId)) {
                tabIds.push(tabId);
                }
                }
                return tabIds;
                };

                /**
                *
                * @returns {Array}
                *
                * @public
                */
                n.BSTabs.prototype.getTabAnchors = function () {
                var tabLinks = [];
                for (var tabId in this.tabs) {
                if (this.tabs.hasOwnProperty(tabId)) {
                tabLinks.push(this.tabs[tabId].element);
                }
                }

                return tabLinks;
                };

                /**
                * Activate a given tab.
                *
                * @param {string} tabId Id of the tab to activate
                *
                */
                n.BSTabs.prototype.activateTab = function (tabId) {
                if (!this.tabs[tabId]) {
                console.error("Unable to find tab with id: " + tabId);
                return false;
                }

                $(this.tabs[tabId].element).tab('show');
                return true;
                };

                n.BSTabs.prototype.getCurrentTab = function () {
                return this.currentTab;
                };

                n.BSTabs.prototype.getTabName = function (tabId) {
                if (!this.tabs[tabId]) {
                console.error("Unable to find tab with id: " + tabId);
                return null;
                }

                return $(this.tabs[tabId].element).text().trim();
                };

                n.BSTabs.prototype.getActiveTab = function () {
                return this.currentTab;
                };

                n.BSTabs.prototype.getContainingTabIdForFormControl = function (formControlName) {
                var $formControl = $("[name='" + formControlName + "']");
                if ($formControl.length === 0) {
                n.Log.debug("BSTabs.getContainingTabForFormControl(): unable to find form control with name '" +
                formControlName + "'");
                return null;
                }

                var iterator = $formControl[0];
                while (iterator !== null) {
                if (iterator.hasAttribute('role') &&
                iterator.getAttribute('role') === 'tabpanel') {
                return iterator.id || null;
                }

                iterator = iterator.parentElement;
                }

                return null;
                };

                })(QfqNS);