/*! hash-tabs - v1.0.4 - 2016-05-15 * https://github.com/srsgores/hash-tabs * Copyright (c) 2016 Sean Goresht; Licensed MIT */ // Generated by CoffeeScript 1.10.0 /* hash-tabs hash-tabs.coffee @author Sean @note Created on 2014-06-07 by PhpStorm @note uses Codoc @see https://github.com/coffeedoc/codo */ (function() { var slice = [].slice; (function($, window) { /* Class for creating accessible tabs with jQuery @example create tabs from nav and container element $(".myTabContainer").hashTabs(); */ var HashTabs; return HashTabs = (function() { HashTabs.prototype.defaults = { tabPanelSelector: "section", tabNavSelector: "nav", tabButtonSelector: "a", /* @property [Integer] initial tab's index to show when the tabs are initialized @note Initial tab will default to first tab, or index of 0 @note You must provide a non-negative Integer within the range of the current active tabs */ initialTabIndex: 0, /* @property [String] (optional) initial tab's `id` or hash to show when tabs are initialized @example tab2 @note You must provide a non-negative Integer within the range of the current active tabs */ initialTabId: null, /* @property [String] class to append to initialized hash tabs @note Styles are applied using the `.hash-tabs` class. Expect unexpected output if you override this setting */ tabContainerClass: "hash-tabs", /* @property [Boolean] whether keyboard navigation is enabled @note anchor tag tab element must be selected (using tab) in order for keyboard navigation to work @note keyboard navigation binds to the left and right arrow keys on the keyboard */ keyboard: true, /* @property [Boolean] whether to apply smooth scrolling, in which the screen scrolls up to the top of the tab navigation panel when any tab is clicked @note Enabling smooth scrolling will override the default browser behaviour, in which the browser "jumps" to the top of an anchor */ smoothScroll: { enabled: false, offset: 100, duration: 1000 }, /* @property [Boolean] whether to enable html5 history API to navigate back/forwards amongst selected tabs @note Defaults to `false` on non-html5-supported browsers */ history: true, debug: false }; /* Construct a new instance of HashTabs @param [*jQuery] el tab container selector @param [Array] options array for constructing new tabs */ function HashTabs(el, options) { this.options = $.extend({}, this.defaults, options); this.$selector = $(el); if (this.$selector.length < 1) { throw new ReferenceError("The selector passed in does not contain any items"); } this.generateTabs(this.$selector); if (this.options.debug === true) { console.dir(this.$selector); } } /* Generate tabs based off of a selector @param [*jQuery] $tabContainer tab container jQuery object */ HashTabs.prototype.generateTabs = function($tabContainer) { var self; $tabContainer.addClass(this.options.tabContainerClass); this.$tabNav = $tabContainer.find(this.options.tabNavSelector).attr({ "role": "tablist" }); this.$contentPanes = $tabContainer.find(this.options.tabPanelSelector); self = this; this.$tabButtons = this.$tabNav.find(this.options.tabButtonSelector).each(function(index) { var $associatedTab; $(this).attr({ "id": index, "role": "tab", "aria-selected": false, "aria-expanded": false, "aria-controls": $(this)[0].hash, "tab-index": -1 }); $associatedTab = self.$contentPanes.filter($(this)[0].hash); $associatedTab[0].correspondingTabButton = $(this); $(this)[0].index = index; return $(this)[0].correspondingTabContent = $associatedTab; }); this.tabsLength = this.$tabButtons.length; this.$tabPanes = $tabContainer.find(this.options.tabPanelSelector).hide().each(function() { return $(this).attr({ "role": "tabpanel", "aria-labeledby": $(this)[0].correspondingTabButton[0].id }); }); this.$activeTab = this.$tabPanes.eq(this.options.initialTabToShow); this.$activeTabButton = this.$tabButtons.eq(this.options.initialTabToShow); this.listenClick(this.$tabButtons); this.updateHash(); if (this.options.keyboard === true) { this.listenKeyboard(); } if (this.options.history === true) { return this.enableHistory(); } }; /* Listen to click events on the tab anchor elements, showing the corresponding tab, and adding WAI-ARIA attributes @param [*jQuery] $tabButtons all tab anchor tags on a tabset @return [*jQuery] $tabButtons */ HashTabs.prototype.listenClick = function($tabButtons) { var self; self = this; return $tabButtons.on("click", function(e) { var ref, targetHash, targetHref; if (self.options.debug === true) { console.log("Active tab is "); if (self.options.debug === true) { console.dir(self.$activeTab); } } self.$previousTab = self.$activeTab.hide(); self.$previousTabButton = self.$activeTabButton.removeClass("active").attr({ "tab-index": -1, "aria-selected": false, "aria-expanded": false }); $(this).addClass("active").attr({ "tab-index": 0, "aria-selected": true, "aria-expanded": true }); self.$activeTabButton = $(this); self.$activeTab = (ref = $(this)[0].correspondingTabContent) != null ? ref.show() : void 0; if (self.options.smoothScroll.enabled === true) { $("html, body").stop().animate({ scrollTop: self.$tabNav.offset().top - self.options.smoothScroll.offset }, self.options.smoothScroll.duration); } if (self.options.keyboard === true) { if ($(this)[0].href === ("#" + (self.options.initialTabId != null)) || $(this)[0].index === self.options.initialTabIndex) { false; } targetHref = $(this)[0].href; targetHash = targetHref.split("#")[1]; if (self.options.debug === true) { console.log("Pushed state " + targetHref); } if ((window.history != null) && self.options.history === true) { history.pushState(self.options, "HashTabs", "#" + targetHash); } else { window.location.hash = targetHash; } return false; } }); }; /* Update the document's current URL to match that of the initially-configured and selected tab @note Only fired once, when plugin initialized */ HashTabs.prototype.updateHash = function() { var currentHashURL; currentHashURL = document.location.hash; if (currentHashURL !== "") { return this.triggerTab(currentHashURL); } else { if (this.options.initialTabId != null) { return this.triggerTab(this.options.initialTabId); } else { return this.triggerTabByIndex(this.options.initialTabIndex); } } }; HashTabs.prototype.enableHistory = function() { return $(window).on("popstate", (function(_this) { return function(e) { var previousTabUrl; if (_this.options.debug === true) { console.dir(e); } if (e.originalEvent.state != null) { previousTabUrl = location.hash; if (_this.options.debug === true) { console.log("Pushing url " + previousTabUrl); } return _this.triggerTab(previousTabUrl); } }; })(this)); }; /* Trigger a given tab, provided its `id` @param [String] url the hash or `id` of the corresponding tab and anchor @note A corresponding anchor (``) tag with the corresponding hash must be present in the tab navigation element @example trigger section element (tab) with id "chocolates" in tab container element ".myTabs" $(".myTabs").hashTabs("triggerTab", "chocolates") // triggers tab with id #chocolates */ HashTabs.prototype.triggerTab = function(url) { return this.$tabButtons.filter("[href*='" + url + "']").trigger("click"); }; /* Trigger a given tab, provided its index @param [Integer] non-negative integer, corresponding to the (nth + 1) tab to display @note A corresponding anchor (``) tag with the corresponding hash must be present in the tab navigation element @example trigger 3rd tab with in tab container ".myTabs" $(".myTabs").hashTabs("triggerTabByIndex", 3) // triggers tab with index 3 */ HashTabs.prototype.triggerTabByIndex = function(index) { var condition; condition = null; if (this.options.debug === true) { console.log("Triggering tab with index " + index); } switch (condition) { case index < 0: condition = "is a negative number, and you cannot trigger a tab with a negative index. Please choose an index within"; break; case index > this.tabsLength: condition = "is larger than"; break; default: condition = "is either not a non-negative integer or is outside of"; } if (index > this.tabsLength || index < 0 || !(/^\d+$/.test(index))) { throw new Error("Cannot show tab of index " + index + ", as it " + condition + " the current amount of tabs (" + this.tabsLength + ")."); } return this.$tabButtons.eq(index).trigger("click"); }; /* Listen to keypress events of the left and right arrow keys, to enable keyboard tab navigation @note tabs will *cycle* in a clockwise direction**. For example, if you are on the last tab to the right, selecting next will fold back over to the first tab (0) to the left */ HashTabs.prototype.listenKeyboard = function() { var self; self = this; return this.$tabButtons.on("keydown", function(event) { if (self.options.debug === true) { console.log("Pressed key " + event.keyCode); } switch (event.keyCode) { case 37 || 38: return self.selectPrevious(); case 39 || 40: return self.selectNext(); default: if (self.options.debug === true) { return console.log("keypress of " + event.keyCode + " was false"); } } }); }; /* Select and trigger clicking of the left-most tab of the currently-active tab @example trigger previous tab to current tab (0 is default) $(".myTabs").hashTabs("selectPrevious") // triggers left-most tab to current tab */ HashTabs.prototype.selectPrevious = function() { var previousTabIndex; previousTabIndex = this.$activeTabButton[0].index - 1; if (previousTabIndex === -1) { return this.triggerTabByIndex(this.tabsLength - 1); } else { return this.triggerTabByIndex(previousTabIndex); } }; /* Select and trigger clicking of the right-most tab of the currently-active tab @example trigger next tab to current tab (0 is default) $(".myTabs").hashTabs("selectNext") // triggers right-most tab to current tab */ HashTabs.prototype.selectNext = function() { var nextTabIndex; if (this.options.debug === true) { console.dir([this.$activeTabButton, this.$activeTabButton[0].index]); } nextTabIndex = this.$activeTabButton[0].index + 1; if (nextTabIndex === this.tabsLength) { return this.triggerTabByIndex(0); } else { return this.triggerTabByIndex(nextTabIndex); } }; /* Add and configure HashTabs to be within the jQuery namespace @param [String] option Method name to trigger @overload args @param [Object] customized jQuery options to set in the new instance of HashTabs @see https://gist.github.com/rjz/3610858 */ $.fn.extend({ hashTabs: function() { var args, option; option = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; return this.each(function() { var $this, data; $this = $(this); data = $this.data("hashTabs"); if (!data) { $this.data("hashTabs", (data = new HashTabs(this, option))); } if (typeof option === "string") { return data[option].apply(data, args); } }); } }); return HashTabs; })(); })(window.jQuery, window); }).call(this); //# sourceMappingURL=jquery.hash-tabs.js.map