/*! 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