1
0
mirror of https://github.com/Hutchy68/pivot.git synced 2024-11-10 20:57:17 +01:00
pivot/assets/scripts/foundation/foundation.tab.js
2015-10-01 10:00:26 -04:00

250 lines
8.9 KiB
JavaScript

;(function ($, window, document, undefined) {
'use strict';
Foundation.libs.tab = {
name : 'tab',
version : '5.5.2',
settings : {
active_class : 'active',
callback : function () {},
deep_linking : false,
scroll_to_content : true,
is_hover : false
},
default_tab_hashes : [],
init : function (scope, method, options) {
var self = this,
S = this.S;
// Store the default active tabs which will be referenced when the
// location hash is absent, as in the case of navigating the tabs and
// returning to the first viewing via the browser Back button.
S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () {
self.default_tab_hashes.push(this.hash);
});
// store the initial href, which is used to allow correct behaviour of the
// browser back button when deep linking is turned on.
self.entry_location = window.location.href;
this.bindings(method, options);
this.handle_location_hash_change();
},
events : function () {
var self = this,
S = this.S;
var usual_tab_behavior = function (e, target) {
var settings = S(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
if (!settings.is_hover || Modernizr.touch) {
e.preventDefault();
e.stopPropagation();
self.toggle_active_tab(S(target).parent());
}
};
S(this.scope)
.off('.tab')
// Key event: focus/tab key
.on('keydown.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
var el = this;
var keyCode = e.keyCode || e.which;
// if user pressed tab key
if (keyCode == 9) {
e.preventDefault();
// TODO: Change usual_tab_behavior into accessibility function?
usual_tab_behavior(e, el);
}
})
// Click event: tab title
.on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
var el = this;
usual_tab_behavior(e, el);
})
// Hover event: tab title
.on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) {
var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
if (settings.is_hover) {
self.toggle_active_tab(S(this).parent());
}
});
// Location hash change event
S(window).on('hashchange.fndtn.tab', function (e) {
e.preventDefault();
self.handle_location_hash_change();
});
},
handle_location_hash_change : function () {
var self = this,
S = this.S;
S('[' + this.attr_name() + ']', this.scope).each(function () {
var settings = S(this).data(self.attr_name(true) + '-init');
if (settings.deep_linking) {
// Match the location hash to a label
var hash;
if (settings.scroll_to_content) {
hash = self.scope.location.hash;
} else {
// prefix the hash to prevent anchor scrolling
hash = self.scope.location.hash.replace('fndtn-', '');
}
if (hash != '') {
// Check whether the location hash references a tab content div or
// another element on the page (inside or outside the tab content div)
var hash_element = S(hash);
if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) {
// Tab content div
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent());
} else {
// Not the tab content div. If inside the tab content, find the
// containing tab and toggle it as active.
var hash_tab_container_id = hash_element.closest('.content').attr('id');
if (hash_tab_container_id != undefined) {
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash);
}
}
} else {
// Reference the default tab hashes which were initialized in the init function
for (var ind = 0; ind < self.default_tab_hashes.length; ind++) {
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent());
}
}
}
});
},
toggle_active_tab : function (tab, location_hash) {
var self = this,
S = self.S,
tabs = tab.closest('[' + this.attr_name() + ']'),
tab_link = tab.find('a'),
anchor = tab.children('a').first(),
target_hash = '#' + anchor.attr('href').split('#')[1],
target = S(target_hash),
siblings = tab.siblings(),
settings = tabs.data(this.attr_name(true) + '-init'),
interpret_keyup_action = function (e) {
// Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js
// define current, previous and next (possible) tabs
var $original = $(this);
var $prev = $(this).parents('li').prev().children('[role="tab"]');
var $next = $(this).parents('li').next().children('[role="tab"]');
var $target;
// find the direction (prev or next)
switch (e.keyCode) {
case 37:
$target = $prev;
break;
case 39:
$target = $next;
break;
default:
$target = false
break;
}
if ($target.length) {
$original.attr({
'tabindex' : '-1',
'aria-selected' : null
});
$target.attr({
'tabindex' : '0',
'aria-selected' : true
}).focus();
}
// Hide panels
$('[role="tabpanel"]')
.attr('aria-hidden', 'true');
// Show panel which corresponds to target
$('#' + $(document.activeElement).attr('href').substring(1))
.attr('aria-hidden', null);
},
go_to_hash = function(hash) {
// This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it
// the user would get continually redirected to the default hash.
var is_entry_location = window.location.href === self.entry_location,
default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash :'fndtn-' + self.default_tab_hashes[0].replace('#', '')
if (!(is_entry_location && hash === default_hash)) {
window.location.hash = hash;
}
};
// allow usage of data-tab-content attribute instead of href
if (anchor.data('tab-content')) {
target_hash = '#' + anchor.data('tab-content').split('#')[1];
target = S(target_hash);
}
if (settings.deep_linking) {
if (settings.scroll_to_content) {
// retain current hash to scroll to content
go_to_hash(location_hash || target_hash);
if (location_hash == undefined || location_hash == target_hash) {
tab.parent()[0].scrollIntoView();
} else {
S(target_hash)[0].scrollIntoView();
}
} else {
// prefix the hashes so that the browser doesn't scroll down
if (location_hash != undefined) {
go_to_hash('fndtn-' + location_hash.replace('#', ''));
} else {
go_to_hash('fndtn-' + target_hash.replace('#', ''));
}
}
}
// WARNING: The activation and deactivation of the tab content must
// occur after the deep linking in order to properly refresh the browser
// window (notably in Chrome).
// Clean up multiple attr instances to done once
tab.addClass(settings.active_class).triggerHandler('opened');
tab_link.attr({'aria-selected' : 'true', tabindex : 0});
siblings.removeClass(settings.active_class)
siblings.find('a').attr({'aria-selected' : 'false', tabindex : -1});
target.siblings().removeClass(settings.active_class).attr({'aria-hidden' : 'true', tabindex : -1});
target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex');
settings.callback(tab);
target.triggerHandler('toggled', [target]);
tabs.triggerHandler('toggled', [tab]);
tab_link.off('keydown').on('keydown', interpret_keyup_action );
},
data_attr : function (str) {
if (this.namespace.length > 0) {
return this.namespace + '-' + str;
}
return str;
},
off : function () {},
reflow : function () {}
};
}(jQuery, window, window.document));