PageSourceSearch

https://www.lallisandhiggins.com/javascripts/foundation.tab.js

js lallisandhiggins.com collected 2026-10-06 06:14:43 UTC 9,162 bytes, 249 lines download raw bytes

1;(function ($, window, document, undefined) {
2  'use strict';
3
4  Foundation.libs.tab = {
5    name : 'tab',
6
7    version : '5.5.2',
8
9    settings : {
10      active_class : 'active',
11      callback : function () {},
12      deep_linking : false,
13      scroll_to_content : true,
14      is_hover : false
15    },
16
17    default_tab_hashes : [],
18
19    init : function (scope, method, options) {
20      var self = this,
21          S = this.S;
22
23	  // Store the default active tabs which will be referenced when the
24	  // location hash is absent, as in the case of navigating the tabs and
25	  // returning to the first viewing via the browser Back button.
26	  S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () {
27	    self.default_tab_hashes.push(this.hash);
28	  });
29
30      // store the initial href, which is used to allow correct behaviour of the
31      // browser back button when deep linking is turned on.
32      self.entry_location = window.location.href;
33
34      this.bindings(method, options);
35      this.handle_location_hash_change();
36    },
37
38    events : function () {
39      var self = this,
40          S = this.S;
41
42      var usual_tab_behavior =  function (e, target) {
43          var settings = S(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
44          if (!settings.is_hover || Modernizr.touch) {
45            e.preventDefault();
46            e.stopPropagation();
47            self.toggle_active_tab(S(target).parent());
48          }
49        };
50
51      S(this.scope)
52        .off('.tab')
53        // Key event: focus/tab key
54        .on('keydown.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
55          var el = this;
56          var keyCode = e.keyCode || e.which;
57            // if user pressed tab key
58            if (keyCode == 9) { 
59              e.preventDefault();
60              // TODO: Change usual_tab_behavior into accessibility function?
61              usual_tab_behavior(e, el);
62            } 
63        })
64        // Click event: tab title
65        .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
66          var el = this;
67          usual_tab_behavior(e, el);
68        })
69        // Hover event: tab title
70        .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) {
71          var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
72          if (settings.is_hover) {
73            self.toggle_active_tab(S(this).parent());
74          }
75        });
76
77      // Location hash change event
78      S(window).on('hashchange.fndtn.tab', function (e) {
79        e.preventDefault();
80        self.handle_location_hash_change();
81      });
82    },
83
84    handle_location_hash_change : function () {
85
86      var self = this,
87          S = this.S;
88
89      S('[' + this.attr_name() + ']', this.scope).each(function () {
90        var settings = S(this).data(self.attr_name(true) + '-init');
91        if (settings.deep_linking) {
92          // Match the location hash to a label
93          var hash;
94          if (settings.scroll_to_content) {
95            hash = self.scope.location.hash;
96          } else {
97            // prefix the hash to prevent anchor scrolling
98            hash = self.scope.location.hash.replace('fndtn-', '');
99          }
100          if (hash != '') {
101            // Check whether the location hash references a tab content div or
102            // another element on the page (inside or outside the tab content div)
103            var hash_element = S(hash);
104            if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) {
105              // Tab content div
106              self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent());
107            } else {
108              // Not the tab content div. If inside the tab content, find the
109              // containing tab and toggle it as active.
110              var hash_tab_container_id = hash_element.closest('.content').attr('id');
111              if (hash_tab_container_id != undefined) {
112                self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash);
113              }
114            }
115          } else {
116            // Reference the default tab hashes which were initialized in the init function
117            for (var ind = 0; ind < self.default_tab_hashes.length; ind++) {
118              self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent());
119            }
120          }
121        }
122       });
123     },
124
125    toggle_active_tab : function (tab, location_hash) {
126      var self = this,
127          S = self.S,
128          tabs = tab.closest('[' + this.attr_name() + ']'),
129          tab_link = tab.find('a'),
130          anchor = tab.children('a').first(),
131          target_hash = '#' + anchor.attr('href').split('#')[1],
132          target = S(target_hash),
133          siblings = tab.siblings(),
134          settings = tabs.data(this.attr_name(true) + '-init'),
135          interpret_keyup_action = function (e) {
136            // Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js
137
138            // define current, previous and next (possible) tabs
139
140            var $original = $(this);
141            var $prev = $(this).parents('li').prev().children('[role="tab"]');
142            var $next = $(this).parents('li').next().children('[role="tab"]');
143            var $target;
144
145            // find the direction (prev or next)
146
147            switch (e.keyCode) {
148              case 37:
149                $target = $prev;
150                break;
151              case 39:
152                $target = $next;
153                break;
154              default:
155                $target = false
156                  break;
157            }
158
159            if ($target.length) {
160              $original.attr({
161                'tabindex' : '-1',
162                'aria-selected' : null
163              });
164              $target.attr({
165                'tabindex' : '0',
166                'aria-selected' : true
167              }).focus();
168            }
169
170            // Hide panels
171
172            $('[role="tabpanel"]')
173              .attr('aria-hidden', 'true');
174
175            // Show panel which corresponds to target
176
177            $('#' + $(document.activeElement).attr('href').substring(1))
178              .attr('aria-hidden', null);
179
180          },
181          go_to_hash = function(hash) {
182            // This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it
183            // the user would get continually redirected to the default hash.
184            var is_entry_location = window.location.href === self.entry_location,
185                default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash :'fndtn-' + self.default_tab_hashes[0].replace('#', '')
186
187            if (!(is_entry_location && hash === default_hash)) {
188              window.location.hash = hash;
189            }
190          };
191
192      // allow usage of data-tab-content attribute instead of href
193      if (anchor.data('tab-content')) {
194        target_hash = '#' + anchor.data('tab-content').split('#')[1];
195        target = S(target_hash);
196      }
197
198      if (settings.deep_linking) {
199
200        if (settings.scroll_to_content) {
201
202          // retain current hash to scroll to content
203          go_to_hash(location_hash || target_hash);
204
205          if (location_hash == undefined || location_hash == target_hash) {
206            tab.parent()[0].scrollIntoView();
207          } else {
208            S(target_hash)[0].scrollIntoView();
209          }
210        } else {
211          // prefix the hashes so that the browser doesn't scroll down
212          if (location_hash != undefined) {
213            go_to_hash('fndtn-' + location_hash.replace('#', ''));
214          } else {
215            go_to_hash('fndtn-' + target_hash.replace('#', ''));
216          }
217        }
218      }
219
220      // WARNING: The activation and deactivation of the tab content must
221      // occur after the deep linking in order to properly refresh the browser
222      // window (notably in Chrome).
223      // Clean up multiple attr instances to done once
224      tab.addClass(settings.active_class).triggerHandler('opened');
225      tab_link.attr({'aria-selected' : 'true',  tabindex : 0});
226      siblings.removeClass(settings.active_class)
227      siblings.find('a').attr({'aria-selected' : 'false',  tabindex : -1});
228      target.siblings().removeClass(settings.active_class).attr({'aria-hidden' : 'true',  tabindex : -1});
229      target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex');
230      settings.callback(tab);
231      target.triggerHandler('toggled', [target]);
232      tabs.triggerHandler('toggled', [tab]);
233
234      tab_link.off('keydown').on('keydown', interpret_keyup_action );
235    },
236
237    data_attr : function (str) {
238      if (this.namespace.length > 0) {
239        return this.namespace + '-' + str;
240      }
241
242      return str;
243    },
244
245    off : function () {},
246
247    reflow : function () {}
248  };
249}(jQuery, window, window.document));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.