PageSourceSearch

https://gruponovelec.com/_ui/responsive/common/js/jquery.tabs.custom.js

js gruponovelec.com collected 2026-09-29 16:06:13 UTC 16,362 bytes, 300 lines download raw bytes

1/**
2 * Accessible Tabs - jQuery plugin for accessible, unobtrusive tabs
3 * Build to seemlessly work with the CCS-Framework YAML (yaml.de) not depending on YAML though
4 * @requires jQuery - tested with 1.9.1, 1.7 and 1.4.2 but might as well work with older versions
5 *
6 * english article: http://blog.ginader.de/archives/2009/02/07/jQuery-Accessible-Tabs-How-to-make-tabs-REALLY-accessible.php
7 * german article: http://blog.ginader.de/archives/2009/02/07/jQuery-Accessible-Tabs-Wie-man-Tabs-WIRKLICH-zugaenglich-macht.php
8 *
9 * code: http://github.com/ginader/Accessible-Tabs
10 * please report issues at: http://github.com/ginader/Accessible-Tabs/issues
11 *
12 * Copyright (c) 2016 Dirk Ginader (http://dir.kg)
13 * Dual licensed under the MIT and GPL licenses:
14 * http://www.opensource.org/licenses/mit-license.php
15 * http://www.gnu.org/licenses/gpl.html
16 *
17 */
18
19(function($) {
20    var debugMode = false;
21    $.fn.extend({
22        // We assume there could be multiple sets of tabs on a page, so,
23        // the unique id for each invididual tab's heading is identified with params q and r (e.g., id="accessibletabscontent0-2")
24        getUniqueId: function(p, q, r){
25            if (r===undefined) {r='';} else {r='-'+r;}
26            return p + q + r;
27        },
28        // in case a className i.e. currentInfoClass contains more than one className this converts
29        // 'current-info visuallyhidden' to '.current-info.visuallyhidden' to be used as jQuery selector
30        getClassSelectorsFromClassNames: function(className){
31          if(className.indexOf(' ' > -1)){
32            // the className has spaces so it probably contains more than one classNames
33            return '.'+className.split(' ').join('.');
34          }else{
35            return '.'+className;
36          }
37        },
38        accessibleTabs: function(config) {
39            var defaults = {
40                wrapperClass: 'content', // Classname to apply to the div that is wrapped around the original Markup
41                currentClass: 'current', // Classname to apply to the LI of the selected Tab
42                tabhead: 'h4', // Tag or valid Query Selector of the Elements to Transform the Tabs-Navigation from (originals are removed)
43                tabheadClass: 'tabhead', // Classname to apply to the target heading element for each tab div
44                tabbody: '.tabbody', // Tag or valid Query Selector of the Elements to be treated as the Tab Body
45                fx:'show', // can be "fadeIn", "slideDown", "show"
46                fxspeed: 'normal', // speed (String|Number): "slow", "normal", or "fast") or the number of milliseconds to run the animation
47                currentInfoText: 'current tab: ', // text to indicate for screenreaders which tab is the current one
48                currentInfoPosition: 'prepend', // Definition where to insert the Info Text. Can be either "prepend" or "append"
49                currentInfoClass: 'current-info', // Class to apply to the span wrapping the CurrentInfoText
50                tabsListClass:'tabs-list', // Class to apply to the generated list of tabs above the content
51                syncheights:false, // syncs the heights of the tab contents when the SyncHeight plugin is available http://blog.ginader.de/dev/jquery/syncheight/index.php
52                syncHeightMethodName:'syncHeight', // set the Method name of the plugin you want to use to sync the tab contents. Defaults to the SyncHeight plugin: http://github.com/ginader/syncHeight
53                cssClassAvailable:false, // Enable individual css classes for tabs. Gets the appropriate class name of a tabhead element and apply it to the tab list element. Boolean value
54                saveState:false, // save the selected tab into a cookie so it stays selected after a reload. This requires that the wrapping div needs to have an ID (so we know which tab we're saving)
55                autoAnchor:false, // will move over any existing id of a headline in tabs markup so it can be linked to it
56                pagination:false, // adds buttons to each tab to switch to the next/previous tab
57                position:'top', // can be 'top' or 'bottom'. Defines where the tabs list is inserted.
58                wrapInnerNavLinks: '', // inner wrap for a-tags in tab navigation. See http://api.jquery.com/wrapInner/ for further informations
59                firstNavItemClass: 'first', // Classname of the first list item in the tab navigation
60                lastNavItemClass: 'last', // Classname of the last list item in the tab navigation
61                clearfixClass: 'clearfix' // Name of the Class that is used to clear/contain floats
62            };
63            var keyCodes = {
64                37 : -1, //LEFT
65                38 : -1, //UP
66                39 : +1, //RIGHT
67                40 : +1 //DOWN
68            };
69            var positions = {
70                top : 'prepend',
71                bottom : 'append'
72            };
73            this.options = $.extend(defaults, config);
74
75            var tabsCount = 0;
76            if($("body").data('accessibleTabsCount') !== undefined){
77                tabsCount = $("body").data('accessibleTabsCount');
78            }
79            $("body").data('accessibleTabsCount',this.length+tabsCount);
80
81            var o = this;
82            return this.each(function(t) {
83                var el = $(this);
84                var list = '';
85                var tabCount = 0;
86                var ids = [];
87
88                $(el).wrapInner('<div class="'+o.options.wrapperClass+'"></div>');
89
90                $(el).find(o.options.tabhead).each(function(i){
91                    var id = '';
92                    var elId = $(this).attr('id');
93                    if(elId){
94                        // Skip this item if it already exists.
95                        if(elId.indexOf('accessibletabscontent') === 0) {
96                            return;
97                        }
98                        id =' id="'+elId+'"';
99                    }
100                    var tabId = o.getUniqueId('accessibletabscontent', tabsCount+t, i);//get a unique id to assign to this tab's heading
101                    var navItemId = o.getUniqueId('accessibletabsnavigation', tabsCount+t, i);//get a unique id for this navigation item
102                    ids.push(tabId);
103                    
104                    // SNK: support tab head with links
105                    var navItemText = ($(this).children("a").length>0)? $(this).children("a").html() :$(this).html();
106                    var ariaLabel="";
107                    if($(this).attr("aria-label")) {
108						ariaLabel='aria-label="'+$(this).attr("aria-label")+'"';
109					}
110                    
111                    if(o.options.cssClassAvailable === true) {
112                        var cssClass = '';
113                        if($(this).attr('class')) {
114                            cssClass = $(this).attr('class');
115                            cssClass = ' class="'+cssClass+'"';
116                        }
117                        list += '<li id="'+navItemId+'"><a'+id+''+cssClass+' href="#'+tabId+'" '+ariaLabel+'>'+navItemText+'</a></li>';
118                    } else {
119                    	list += '<li id="'+navItemId+'"><a'+id+' href="#'+tabId+'" '+ariaLabel+'>'+navItemText+'</a></li>';
120                    }
121                    $(this).attr({"id": tabId, "class": o.options.tabheadClass, "tabindex": "-1"});//assign the unique id and the tabheadClass class name to this tab's heading
122                    tabCount++;
123                });
124
125                if (o.options.syncheights && $.fn[o.options.syncHeightMethodName]) {
126                    $(el).find(o.options.tabbody)[o.options.syncHeightMethodName]();
127                    $(window).resize(function(){
128                        $(el).find(o.options.tabbody)[o.options.syncHeightMethodName]();
129                    });
130                }
131
132                // Ensure that the call to setup tabs is re-runnable
133                var tabs_selector = o.getClassSelectorsFromClassNames(o.options.tabsListClass);
134                if(!$(el).find(tabs_selector).length) {
135                    $(el)[positions[o.options.position]]('<ul class="'+o.options.clearfixClass+' '+o.options.tabsListClass+' tabamount'+tabCount+'"></ul>');
136                }
137
138                $(el).find(tabs_selector).append(list);
139
140                // initial show first content block and hide the others
141                var content = $(el).find(o.options.tabbody);
142                if (content.length > 0) {
143                    $(content).hide();
144                    $(content[0]).show();
145                }
146                $(el).find("ul"+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+">li:first").addClass(o.options.currentClass).addClass(o.options.firstNavItemClass)
147                  .find('a')[o.options.currentInfoPosition]('<span class="'+o.options.currentInfoClass+'">'+o.options.currentInfoText+'</span>')
148                  .parents("ul"+o.getClassSelectorsFromClassNames(o.options.tabsListClass)).children('li:last').addClass(o.options.lastNavItemClass);
149
150                // SNK: add first and last class to tabhead
151
152				var tabheads = $(el).find(o.options.tabhead);
153				if (tabheads.length > 0) {
154					$(tabheads[0]).addClass(o.options.currentClass).addClass(o.options.firstNavItemClass);
155					$(tabheads[tabheads.length-1]).addClass(o.options.lastNavItemClass);
156				}
157                
158                if (o.options.wrapInnerNavLinks) {
159                  $(el).find('ul'+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+'>li>a').wrapInner(o.options.wrapInnerNavLinks);
160                }
161
162                $(el).find('ul'+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+'>li>a').each(function(i){
163                    $(this).click(function(event){
164                        event.preventDefault();
165                        el.trigger("showTab.accessibleTabs", [$(event.target)]);
166                        if(o.options.saveState && $.cookie){
167                            $.cookie('accessibletab_'+el.attr('id')+'_active',i);
168                        }
169                        $(el).find('ul'+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+'>li.'+o.options.currentClass).removeClass(o.options.currentClass)
170                        .find("span"+o.getClassSelectorsFromClassNames(o.options.currentInfoClass)).remove();
171                        
172                        // SNK: remove current class from tabhead
173						$(el).find(o.options.tabhead).removeClass(o.options.currentClass);
174                        
175                        $(this).blur();
176                        $(el).find(o.options.tabbody+':visible').hide();
177                        $(el).find(o.options.tabbody).eq(i)[o.options.fx](o.options.fxspeed);
178                        $(this)[o.options.currentInfoPosition]('<span class="'+o.options.currentInfoClass+'">'+o.options.currentInfoText+'</span>')
179                        .parent().addClass(o.options.currentClass);
180                        
181                        // SNK: add active class to current tabhead
182						$($(this).attr("href")).addClass(o.options.currentClass);
183                        
184                        //now, only after writing the currentInfoText span to the tab list link, set focus to the tab's heading
185
186                        $($(this).attr("href")).focus().keyup(function(event){
187                            if(keyCodes[event.keyCode]){
188                                o.showAccessibleTab(i+keyCodes[event.keyCode]);
189                                $(this).unbind( "keyup" );
190                            }
191                        });
192
193                        // $(el).find('.accessibletabsanchor').keyup(function(event){
194                        //     if(keyCodes[event.keyCode]){
195                        //         o.showAccessibleTab(i+keyCodes[event.keyCode]);
196                        //     }
197                        // });
198                    });
199
200                    $(this).focus(function(){
201                        $(document).keyup(function(event){
202                            if(keyCodes[event.keyCode]){
203                                o.showAccessibleTab(i+keyCodes[event.keyCode]);
204                            }
205                        });
206                    });
207                    $(this).blur(function(){
208                        $(document).unbind( "keyup" );
209                    });
210
211                });
212
213                if(o.options.saveState && $.cookie){
214                    var savedState = $.cookie('accessibletab_'+el.attr('id')+'_active');
215                    debug($.cookie('accessibletab_'+el.attr('id')+'_active'));
216                    if(savedState !== null){
217                        o.showAccessibleTab(savedState,el.attr('id'));
218                    }
219                }
220
221                if(o.options.autoAnchor && window.location.hash){
222                    var anchorTab = $(o.getClassSelectorsFromClassNames(o.options.tabsListClass)).find(window.location.hash);
223                    if(anchorTab.length){
224                        anchorTab.click();
225                    }
226                }
227
228                if(o.options.pagination){
229                    var m = '<ul class="pagination">';
230                    m +='    <li class="previous"><a href="#{previousAnchor}"><span>{previousHeadline}</span></a></li>';
231                    m +='    <li class="next"><a href="#{nextAnchor}"><span>{nextHeadline}</span></a></li>';
232                    m +='</ul>';
233                    var tabs = $(el).find('.tabbody');
234                    var tabcount = tabs.length;
235                    tabs.each(function(idx){
236                        $(this).append(m);
237                        var next = idx+1;
238                        if(next>=tabcount){next = 0;}
239                        var previous = idx-1;
240                        if(previous<0){previous = tabcount-1;}
241                        var p = $(this).find('.pagination');
242                        var previousEl = p.find('.previous');
243                        previousEl.find('span').text($('#'+ids[previous]).text());
244                        previousEl.find('a').attr('href','#'+ids[previous])
245                        .click(function(event){
246                            event.preventDefault();
247                            $(el).find('.tabs-list a').eq(previous).click();
248                        });
249                        var nextEl = p.find('.next');
250                        nextEl.find('span').text($('#'+ids[next]).text());
251                        nextEl.find('a').attr('href','#'+ids[next])
252                        .click(function(event){
253                            event.preventDefault();
254                            $(el).find('.tabs-list a').eq(next).click();
255                        });
256                    });
257                }
258            });
259        },
260        showAccessibleTab: function(index,id){
261            debug('showAccessibleTab');
262            var o = this;
263            if(id) {
264                var el = $('#'+id);
265                var links = el.find('ul'+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+'>li>a');
266                el.trigger("showTab.accessibleTabs", [links.eq(index)]);
267                links.eq(index).click();
268            } else {
269                return this.each(function() {
270                    var el = $(this);
271                    el.trigger("showTab.accessibleTabs");
272                    var links = el.find('ul'+o.getClassSelectorsFromClassNames(o.options.tabsListClass)+'>li>a');
273                    el.trigger("showTab.accessibleTabs", [links.eq(index)]);
274                    links.eq(index).click();
275                });
276            }
277        },
278        showAccessibleTabSelector: function(selector){
279            debug('showAccessibleTabSelector');
280            var el = $(selector);
281            if(el){
282                if(el.get(0).nodeName.toLowerCase() === 'a'){
283                    el.click();
284                }else{
285                    debug('the selector of a showAccessibleTabSelector() call needs to point to a tabs headline!');
286                }
287            }
288        }
289    });
290    // private Methods
291    function debug(msg,info){
292        if(debugMode && window.console && window.console.log){
293            if(info){
294                window.console.log(info+': ',msg);
295            }else{
296                window.console.log(msg);
297            }
298        }
299    }
300})(jQuery);

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.