PageSourceSearch

https://bahnradweg-sankt-wendeler-land.de/fileadmin/template/js/_1_tabs.js?1671462221

js bahnradweg-sankt-wendeler-land.de collected 2026-10-04 17:01:17 UTC 6,625 bytes, 179 lines download raw bytes

1// utility functions
2if(!Util) function Util () {};
3
4Util.addClass = function(el, className) {
5  var classList = className.split(' ');
6  el.classList.add(classList[0]);
7  if (classList.length > 1) Util.addClass(el, classList.slice(1).join(' '));
8};
9
10Util.removeClass = function(el, className) {
11  var classList = className.split(' ');
12  el.classList.remove(classList[0]);
13  if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(' '));
14};
15
16Util.toggleClass = function(el, className, bool) {
17  if(bool) Util.addClass(el, className);
18  else Util.removeClass(el, className);
19};
20
21Util.setAttributes = function(el, attrs) {
22  for(var key in attrs) {
23    el.setAttribute(key, attrs[key]);
24  }
25};
26
27Util.hasClass = function(el, className) {
28  return el.classList.contains(className);
29};
30
31Util.getChildrenByClassName = function(el, className) {
32  var children = el.children,
33    childrenByClass = [];
34  for (var i = 0; i < children.length; i++) {
35    if (Util.hasClass(children[i], className)) childrenByClass.push(children[i]);
36  }
37  return childrenByClass;
38};
39
40Util.getIndexInArray = function(array, el) {
41  return Array.prototype.indexOf.call(array, el);
42};
43
44
45// File#: _1_tabs
46// Usage: codyhouse.co/license
47(function() {
48	var Tab = function(element) {
49		this.element = element;
50		this.tabList = this.element.getElementsByClassName('js-tabs__controls')[0];
51		this.listItems = this.tabList.getElementsByTagName('li');
52		this.triggers = this.tabList.getElementsByTagName('a');
53		this.panelsList = this.element.getElementsByClassName('js-tabs__panels')[0];
54		this.panels = Util.getChildrenByClassName(this.panelsList, 'js-tabs__panel');
55		this.hideClass = this.element.getAttribute('data-hide-panel-class') ? this.element.getAttribute('data-hide-panel-class') : 'th8-hide';
56		this.customShowClass = this.element.getAttribute('data-show-panel-class') ? this.element.getAttribute('data-show-panel-class') : false;
57		this.layout = this.element.getAttribute('data-tabs-layout') ? this.element.getAttribute('data-tabs-layout') : 'horizontal';
58		// deep linking options
59		this.deepLinkOn = this.element.getAttribute('data-deep-link') == 'on';
60		// init tabs
61		this.initTab();
62	};
63
64	Tab.prototype.initTab = function() {
65		//set initial aria attributes
66		this.tabList.setAttribute('role', 'tablist');
67		Util.addClass(this.element, 'tabs--no-interaction');
68
69		for( var i = 0; i < this.triggers.length; i++) {
70			var bool = (i == 0),
71				panelId = this.panels[i].getAttribute('id');
72			this.listItems[i].setAttribute('role', 'presentation');
73			Util.setAttributes(this.triggers[i], {'role': 'tab', 'aria-selected': bool, 'aria-controls': panelId, 'id': 'tab-'+panelId});
74			Util.addClass(this.triggers[i], 'js-tabs__trigger'); 
75			Util.setAttributes(this.panels[i], {'role': 'tabpanel', 'aria-labelledby': 'tab-'+panelId});
76			Util.toggleClass(this.panels[i], this.hideClass, !bool);
77			if(bool && this.customShowClass) Util.addClass(this.panels[i], this.customShowClass);
78
79			if(!bool) this.triggers[i].setAttribute('tabindex', '-1'); 
80		}
81
82		//listen for Tab events
83		this.initTabEvents();
84
85		// check deep linking option
86		this.initDeepLink();
87	};
88
89	Tab.prototype.initTabEvents = function() {
90		var self = this;
91		//click on a new tab -> select content
92		this.tabList.addEventListener('click', function(event) {
93			if( event.target.closest('.js-tabs__trigger') ) self.triggerTab(event.target.closest('.js-tabs__trigger'), event);
94		});
95		//arrow keys to navigate through tabs 
96		this.tabList.addEventListener('keydown', function(event) {
97			;
98			if( !event.target.closest('.js-tabs__trigger') ) return;
99			if( tabNavigateNext(event, self.layout) ) {
100				event.preventDefault();
101				self.selectNewTab('next');
102			} else if( tabNavigatePrev(event, self.layout) ) {
103				event.preventDefault();
104				self.selectNewTab('prev');
105			}
106		});
107	};
108
109	Tab.prototype.selectNewTab = function(direction) {
110		var selectedTab = this.tabList.querySelector('[aria-selected="true"]'),
111			index = Util.getIndexInArray(this.triggers, selectedTab);
112		index = (direction == 'next') ? index + 1 : index - 1;
113		//make sure index is in the correct interval 
114		//-> from last element go to first using the right arrow, from first element go to last using the left arrow
115		if(index < 0) index = this.listItems.length - 1;
116		if(index >= this.listItems.length) index = 0;	
117		this.triggerTab(this.triggers[index]);
118		this.triggers[index].focus();
119	};
120
121	Tab.prototype.triggerTab = function(tabTrigger, event) {
122		var self = this;
123		event && event.preventDefault();	
124		var index = Util.getIndexInArray(this.triggers, tabTrigger);
125		//no need to do anything if tab was already selected
126		if(this.triggers[index].getAttribute('aria-selected') == 'true') return;
127
128		Util.removeClass(this.element, 'tabs--no-interaction');
129		
130		for( var i = 0; i < this.triggers.length; i++) {
131			var bool = (i == index);
132			Util.toggleClass(this.panels[i], this.hideClass, !bool);
133			if(this.customShowClass) Util.toggleClass(this.panels[i], this.customShowClass, bool);
134			this.triggers[i].setAttribute('aria-selected', bool);
135			bool ? this.triggers[i].setAttribute('tabindex', '0') : this.triggers[i].setAttribute('tabindex', '-1');
136		}
137
138		// update url if deepLink is on
139		if(this.deepLinkOn) {
140			history.replaceState(null, '', '#'+tabTrigger.getAttribute('aria-controls'));
141		}
142	};
143
144	Tab.prototype.initDeepLink = function() {
145		if(!this.deepLinkOn) return;
146		var hash = window.location.hash.substr(1);
147		var self = this;
148		if(!hash || hash == '') return;
149		for(var i = 0; i < this.panels.length; i++) {
150			if(this.panels[i].getAttribute('id') == hash) {
151				this.triggerTab(this.triggers[i], false);
152				setTimeout(function(){self.panels[i].scrollIntoView(true);});
153				break;
154			}
155		};
156	};
157
158	function tabNavigateNext(event, layout) {
159		if(layout == 'horizontal' && (event.keyCode && event.keyCode == 39 || event.key && event.key == 'ArrowRight')) {return true;}
160		else if(layout == 'vertical' && (event.keyCode && event.keyCode == 40 || event.key && event.key == 'ArrowDown')) {return true;}
161		else {return false;}
162	};
163
164	function tabNavigatePrev(event, layout) {
165		if(layout == 'horizontal' && (event.keyCode && event.keyCode == 37 || event.key && event.key == 'ArrowLeft')) {return true;}
166		else if(layout == 'vertical' && (event.keyCode && event.keyCode == 38 || event.key && event.key == 'ArrowUp')) {return true;}
167		else {return false;}
168	};
169
170	window.Tab = Tab;
171	
172	//initialize the Tab objects
173	var tabs = document.getElementsByClassName('js-tabs');
174	if( tabs.length > 0 ) {
175		for( var i = 0; i < tabs.length; i++) {
176			(function(i){new Tab(tabs[i]);})(i);
177		}
178	}
179}());

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.