foundation.tab.js
6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*jslint unparam: true, browser: true, indent: 2 */
;(function ($, window, document, undefined) {
'use strict';
Foundation.libs.tab = {
name : 'tab',
version : '5.2.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;
this.bindings(method, options);
this.handle_location_hash_change();
// 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() + '] > dd.active > a', this.scope).each(function () {
self.default_tab_hashes.push(this.hash);
});
},
events : function () {
var self = this,
S = this.S;
S(this.scope)
.off('.tab')
// Click event: tab title
.on('click.fndtn.tab', '[' + this.attr_name() + '] > dd > a', function (e) {
var settings = S(this).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(this).parent());
}
})
// Hover event: tab title
.on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > dd > 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 = self.scope.location.hash;
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('tab-content')) {
// Tab content div
self.toggle_active_tab($('[' + self.attr_name() + '] > dd > 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() + '] > dd > a[href=#' + hash_tab_container_id + ']').parent(), hash);
}
}
} else {
// Reference the default tab hashes which were initialized in the init function
for (var ind in self.default_tab_hashes) {
self.toggle_active_tab($('[' + self.attr_name() + '] > dd > a[href=' + self.default_tab_hashes[ind] + ']').parent());
}
}
}
});
},
toggle_active_tab: function (tab, location_hash) {
var S = this.S,
tabs = tab.closest('[' + this.attr_name() + ']'),
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');
// allow usage of data-tab-content attribute instead of href
if (S(this).data(this.data_attr('tab-content'))) {
target_hash = '#' + S(this).data(this.data_attr('tab-content')).split('#')[1];
target = S(target_hash);
}
if (settings.deep_linking) {
// Get the scroll Y position prior to moving to the hash ID
var cur_ypos = $('body,html').scrollTop();
// Update the location hash to preserve browser history
// Note that the hash does not need to correspond to the
// tab content ID anchor; it can be an ID inside or outside of the tab
// content div.
if (location_hash != undefined) {
window.location.hash = location_hash;
} else {
window.location.hash = target_hash;
}
if (settings.scroll_to_content) {
// If the user is requesting the content of a tab, then scroll to the
// top of the title area; otherwise, scroll to the element within
// the content area as defined by the hash value.
if (location_hash == undefined || location_hash == target_hash) {
tab.parent()[0].scrollIntoView();
} else {
S(target_hash)[0].scrollIntoView();
}
} else {
// Adjust the scrollbar to the Y position prior to setting the hash
// Only do this for the tab content anchor, otherwise there will be
// conflicts with in-tab anchor links nested in the tab-content div
if (location_hash == undefined || location_hash == target_hash) {
$('body,html').scrollTop(cur_ypos);
}
}
}
// 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).
tab.addClass(settings.active_class).triggerHandler('opened');
siblings.removeClass(settings.active_class);
target.siblings().removeClass(settings.active_class).end().addClass(settings.active_class);
settings.callback(tab);
target.triggerHandler('toggled', [tab]);
tabs.triggerHandler('toggled', [target]);
},
data_attr: function (str) {
if (this.namespace.length > 0) {
return this.namespace + '-' + str;
}
return str;
},
off : function () {},
reflow : function () {}
};
}(jQuery, this, this.document));