PageSourceSearch

https://my.kpluss.com/ksretail/_ui/responsive/common/js/jquery.tabs.custom.js

js kpluss.com collected 2026-09-24 17:58:46 UTC 12,236 bytes, 317 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) 2007 Dirk Ginader (ginader.de)
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		accessibleTabs: function(config) {
29			var defaults = {
30				wrapperClass: 'content', // Classname to apply to the div that is wrapped around the original Markup
31				currentClass: 'current', // Classname to apply to the LI of the selected Tab
32				tabhead: 'h4', // Tag or valid Query Selector of the Elements to Transform the Tabs-Navigation from (originals are removed)
33				tabheadClass: 'tabhead', // Classname to apply to the target heading element for each tab div
34				tabbody: '.tabbody', // Tag or valid Query Selector of the Elements to be treated as the Tab Body
35				fx:'show', // can be "fadeIn", "slideDown", "show"
36				fxspeed: 'normal', // speed (String|Number): "slow", "normal", or "fast") or the number of milliseconds to run the animation
37				currentInfoText: 'current tab: ', // text to indicate for screenreaders which tab is the current one
38				currentInfoPosition: 'prepend', // Definition where to insert the Info Text. Can be either "prepend" or "append"
39				currentInfoClass: 'current-info', // Class to apply to the span wrapping the CurrentInfoText
40				tabsListClass:'tabs-list', // Class to apply to the generated list of tabs above the content
41				syncheights:false, // syncs the heights of the tab contents when the SyncHeight plugin is available http://blog.ginader.de/dev/jquery/syncheight/index.php
42				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
43				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
44				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)
45				autoAnchor:false, // will move over any existing id of a headline in tabs markup so it can be linked to it
46				pagination:false, // adds buttons to each tab to switch to the next/previous tab
47				position:'top', // can be 'top' or 'bottom'. Defines where the tabs list is inserted.
48				wrapInnerNavLinks: '', // inner wrap for a-tags in tab navigation. See http://api.jquery.com/wrapInner/ for further informations
49				firstNavItemClass: 'first', // Classname of the first list item in the tab navigation
50				lastNavItemClass: 'last', // Classname of the last list item in the tab navigation
51				clearfixClass: 'clearfix' // Name of the Class that is used to clear/contain floats
52			};
53			var keyCodes = {
54				37 : -1, //LEFT
55				38 : -1, //UP
56				39 : +1, //RIGHT 
57				40 : +1 //DOWN
58			};
59			var positions = {
60				top : 'prepend',
61				bottom : 'append'
62			};
63			this.options = $.extend(defaults, config);
64
65			var tabsCount = 0;
66			if($("body").data('accessibleTabsCount') !== undefined){
67				tabsCount = $("body").data('accessibleTabsCount');
68			}
69			$("body").data('accessibleTabsCount',this.size()+tabsCount);
70
71			var o = this;
72			return this.each(function(t) {
73				var el = $(this);
74				var list = '';
75				var tabCount = 0;
76				var ids = [];
77
78				$(el).wrapInner('<div class="'+o.options.wrapperClass+'"></div>');
79				debug($(el).find(o.options.tabhead).children("a"))
80
81				$(el).find(o.options.tabhead).each(function(i){
82
83					debug($(this))
84					var id = '';
85					var elId = $(this).attr('id');
86					if(elId){
87						// Skip this item if it already exists.
88						if(elId.indexOf('accessibletabscontent') === 0) {
89							return;
90						}
91						id =' id="'+elId+'"';
92					}
93					var tabId = o.getUniqueId('accessibletabscontent', tabsCount+t, i);//get a unique id to assign to this tab's heading
94					var navItemId = o.getUniqueId('accessibletabsnavigation', tabsCount+t, i);//get a unique id for this navigation item
95					ids.push(tabId);
96					
97
98					// SNK: support tab head with links
99					var navItemText = ($(this).children("a").length>0)? $(this).children("a").html() :$(this).html() ;
100
101
102					var ariaLabel="";
103
104					if($(this).attr("aria-label")){
105						ariaLabel='aria-label="'+$(this).attr("aria-label")+'"'
106					}
107
108
109					if(o.options.cssClassAvailable === true) {
110						var cssClass = '';
111						if($(this).attr('class')) {
112							cssClass = $(this).attr('class');
113							cssClass = ' class="'+cssClass+'"';
114						}
115						list += '<li id="'+navItemId+'"><a'+id+''+cssClass+' href="#'+tabId+'" '+ariaLabel+'>'+navItemText+'</a></li>';
116					} else {
117					  list += '<li id="'+navItemId+'"><a'+id+' href="#'+tabId+'" '+ariaLabel+'>'+navItemText+'</a></li>';
118					}
119
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.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.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.options.tabsListClass).children('li:last').addClass(o.options.lastNavItemClass);
149
150
151
152				// SNK: add first and last class to tabhead
153
154				var tabheads = $(el).find(o.options.tabhead);
155				if (tabheads.length > 0) {
156					$(tabheads[0]).addClass(o.options.currentClass).addClass(o.options.firstNavItemClass);
157					$(tabheads[tabheads.length-1]).addClass(o.options.lastNavItemClass);
158				}
159
160
161
162
163
164
165
166
167
168
169
170				if (o.options.wrapInnerNavLinks) {
171				  $(el).find('ul.'+o.options.tabsListClass+'>li>a').wrapInner(o.options.wrapInnerNavLinks);
172				}
173
174				$(el).find('ul.'+o.options.tabsListClass+'>li>a').each(function(i){
175					$(this).click(function(event){
176						event.preventDefault();
177						el.trigger("showTab.accessibleTabs", [$(event.target)]);
178						if(o.options.saveState && $.cookie){
179							$.cookie('accessibletab_'+el.attr('id')+'_active',i);
180						}
181						$(el).find('ul.'+o.options.tabsListClass+'>li.'+o.options.currentClass).removeClass(o.options.currentClass)
182						.find("span."+o.options.currentInfoClass).remove();
183
184						// SNK: remove current class from tabhead
185						$(el).find(o.options.tabhead).removeClass(o.options.currentClass);
186						
187
188
189						$(this).blur();
190						$(el).find(o.options.tabbody+':visible').hide();
191						$(el).find(o.options.tabbody).eq(i)[o.options.fx](o.options.fxspeed);
192						$(this)[o.options.currentInfoPosition]('<span class="'+o.options.currentInfoClass+'">'+o.options.currentInfoText+'</span>')
193						.parent().addClass(o.options.currentClass);
194
195
196						// SNK: add active class to current tabhead
197						$($(this).attr("href")).addClass(o.options.currentClass);
198
199
200
201						//now, only after writing the currentInfoText span to the tab list link, set focus to the tab's heading
202
203						$($(this).attr("href")).focus().keyup(function(event){
204							if(keyCodes[event.keyCode]){
205								o.showAccessibleTab(i+keyCodes[event.keyCode]);
206								$(this).unbind( "keyup" );
207							}
208						});
209
210						// $(el).find('.accessibletabsanchor').keyup(function(event){
211						//     if(keyCodes[event.keyCode]){
212						//         o.showAccessibleTab(i+keyCodes[event.keyCode]);
213						//     }
214						// });
215					});
216
217					$(this).focus(function(){
218						$(document).keyup(function(event){
219							if(keyCodes[event.keyCode]){
220								o.showAccessibleTab(i+keyCodes[event.keyCode]);
221							}
222						});
223					});
224					$(this).blur(function(){
225						$(document).unbind( "keyup" );
226					});
227
228				});
229
230				if(o.options.saveState && $.cookie){
231					var savedState = $.cookie('accessibletab_'+el.attr('id')+'_active');
232					debug($.cookie('accessibletab_'+el.attr('id')+'_active'));
233					if(savedState !== null){
234						o.showAccessibleTab(savedState,el.attr('id'));
235					}
236				}
237
238				if(o.options.autoAnchor && window.location.hash){
239					var anchorTab = $('.'+o.options.tabsListClass).find(window.location.hash);
240					if(anchorTab.size()){
241						anchorTab.click();
242					}
243				}
244
245				if(o.options.pagination){
246					var m = '<ul class="pagination">';
247					m +='    <li class="previous"><a href="#{previousAnchor}"><span>{previousHeadline}</span></a></li>';
248					m +='    <li class="next"><a href="#{nextAnchor}"><span>{nextHeadline}</span></a></li>';
249					m +='</ul>';
250					var tabs = $(el).find('.tabbody');
251					var tabcount = tabs.size();
252					tabs.each(function(idx){
253						$(this).append(m);
254						var next = idx+1;
255						if(next>=tabcount){next = 0;}
256						var previous = idx-1;
257						if(previous<0){previous = tabcount-1;}
258						var p = $(this).find('.pagination');
259						var previousEl = p.find('.previous');
260						previousEl.find('span').text($('#'+ids[previous]).text());
261						previousEl.find('a').attr('href','#'+ids[previous])
262						.click(function(event){
263							event.preventDefault();
264							$(el).find('.tabs-list a').eq(previous).click();
265						});
266						var nextEl = p.find('.next');
267						nextEl.find('span').text($('#'+ids[next]).text());
268						nextEl.find('a').attr('href','#'+ids[next])
269						.click(function(event){
270							event.preventDefault();
271							$(el).find('.tabs-list a').eq(next).click();
272						});
273					});
274				}
275			});
276		},
277		showAccessibleTab: function(index,id){
278			debug('showAccessibleTab');
279			var o = this;
280			if(id) {
281				var el = $('#'+id);
282				var links = el.find('ul.'+o.options.tabsListClass+'>li>a');
283				el.trigger("showTab.accessibleTabs", [links.eq(index)]);
284				links.eq(index).click();
285			} else {
286				return this.each(function() {
287					var el = $(this);
288					el.trigger("showTab.accessibleTabs");
289					var links = el.find('ul.'+o.options.tabsListClass+'>li>a');
290					el.trigger("showTab.accessibleTabs", [links.eq(index)]);
291					links.eq(index).click();
292				});
293			}
294		},
295		showAccessibleTabSelector: function(selector){
296			debug('showAccessibleTabSelector');
297			var el = $(selector);
298			if(el){
299				if(el.get(0).nodeName.toLowerCase() === 'a'){
300					el.click();
301				}else{
302					debug('the selector of a showAccessibleTabSelector() call needs to point to a tabs headline!');
303				}
304			}
305		}
306	});
307	// private Methods
308	function debug(msg,info){
309		if(debugMode && window.console && window.console.log){
310			if(info){
311				window.console.log(info+': ',msg);
312			}else{
313				window.console.log(msg);
314			}
315		}
316	}
317})(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.