PageSourceSearch

https://www.korbach.de/output/js/accordion/ikiss-accordion.js

js korbach.de collected 2026-10-02 17:50:09 UTC 7,929 bytes, 278 lines download raw bytes

1;(function ($) {
2
3	var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4	
5	var defaults = { 
6		hashEvents			: 'load hashchange',
7		
8		titleSelector		: '.accordion-title',
9		containerSelector	: '.accordion-container',
10		
11		iconStyle			: 'fal',
12		iconOpen			: 'fa-plus',
13		iconClose			: 'fa-minus',
14		
15		autoOpenFirst		: false,
16		autoClose			: false,
17		
18		wrapInner			: true,
19		activeCls			: 'active',
20		useAnimations		: false
21	};
22	
23	var Plugin = function(rootNode, options) {
24		var me = this,
25			op = $.extend({}, options || {});
26		
27		//Optionen aus den Data-Attributen zuweisen 
28		$.each($(rootNode).data(), function(key, value) {
29			$.map(defaults, function(defValue, defKey) {
30				if (defKey.toLowerCase() == key.toLowerCase()) {
31					op[defKey] = value;
32				}
33			});
34		});
35		
36		$.extend(me, {
37			rootNode	: rootNode,
38			options		: $.extend({}, defaults, op)
39		});
40		
41		me.init();
42	};
43	
44	Plugin.prototype = {
45		
46		init: function() { 
47			var me 	= this,
48				op	= me.options;
49			
50			window.globalIkissAccordionCounter = (window.globalIkissAccordionCounter || 0)+1; 
51			
52			//Ueberschriften suchen und Elemente entsprechend modifizieren (bei dem neuen Accordion nur direkte Titel sammeln, daher Selektor mit > erweitern)
53			if (me.rootNode == document.body) {
54				me.header = $(op.titleSelector, me.rootNode);
55			} else {
56				me.header = $('> '+op.titleSelector, me.rootNode);
57				if (!me.header.length) me.header = $('> div > '+op.titleSelector, me.rootNode);
58			}
59			
60			
61			me.header.each(function(idx, node) {
62				var idKey = '-'+window.globalIkissAccordionCounter+'-'+(idx+1),
63					ctSel = op.containerSelector;
64				
65				if (op.wrapInner) {
66					$(node)
67						.wrapInner('<button id="acc'+idKey+'" aria-controls="sect'+idKey+'" aria-expanded="false" type="button"><span></span><i class="accordion-toggle-button '+op.iconStyle+' '+op.iconOpen+'" aria-hidden="true"></i></button>');
68				} else {
69					$(node)
70						.attr({'id': 'acc'+idKey, 'aria-controls': 'sect'+idKey, 'aria-expanded': 'false', 'tabindex': '0'})
71						.keypress(function(evt) { if (evt.which === 13) { me.onClick.apply(me, arguments); } });
72				}
73				
74				window.photoswipeAccCounter = window.photoswipeAccCounter || 1;
75				
76				$(node)
77					.click(function() { me.onClick.apply(me, arguments); })
78					.next(ctSel)
79					.attr({'id': 'sect'+idKey, 'aria-labelledby': 'acc'+idKey, 'role': 'region'})
80					.css('display', 'none')
81					.find('.photoswipe-gallery')
82					.filter(function() { return $(this).closest(ctSel).get(0) == $(node).next(ctSel).get(0); })
83					.attr('data-photoswipe-group', 'acc-'+(window.photoswipeAccCounter++));
84			});
85			
86			//Beim Fokus mittels TabKey CSS-Klasse setzen
87			me.header.on('focusin', function(e){
88				var me = this;
89				$(window).one('keyup.tabkey', function (e) {
90					if ((e.keyCode ? e.keyCode : e.which) == 9) {
91						$(me).addClass('accordion-tab-focus');
92					}
93				});
94			}).on('focusout', function(e){
95				$(this).removeClass('accordion-tab-focus');
96				$(window).off('keyup.tabkey');
97			});
98			
99			
100			//Erstes Element öffnen?
101			if (op.autoOpenFirst && me.header.length) {
102				me.toggle(me.header[0]);
103			}
104			
105			//Events bei denen der location.hash geprüft werden soll
106			$(window).on(op.hashEvents, function(){ me.checkHash.apply(me, arguments);});
107			
108			//ab jQuery 3.x wird das load event in docready manchmal nicht mehr ausgeführt, daher manueller Aufruf
109			if (document.readyState === 'complete') { 
110				me.checkHash();	
111			}
112		},
113		
114		onClick: function(e) {
115			var me	= this,
116				op	= me.options;
117			
118			var trgHeader = $(e.target).closest(op.titleSelector).get(0);
119			
120			if (!trgHeader)
121				return;
122			
123			e.preventDefault();
124			e.stopPropagation();
125			
126			this.toggle(trgHeader);
127		},
128		
129		open: function(header) {
130			this.toggle(header, 'open');
131		},
132		
133		close: function(header) {
134			this.toggle(header, 'close');
135		},
136		
137		toggle: function(header, forceMode) {
138			var me 		= this,
139				op		= me.options,
140				io		= op.iconOpen,
141				ic		= op.iconClose,
142				mode 	= $(header).hasClass(op.activeCls) ? 'close' : 'open',
143				open	= (mode == 'open' || forceMode == 'open'); 
144			
145			if (open && op.autoClose) {
146				var acHeader = 	(me.rootNode == document.body)
147								? $(op.titleSelector+'.'+op.activeCls, ($(header).closest(op.containerSelector).get(0) || document.body)).get(0)
148								: (me.header.filter('.'+op.activeCls)).get(0); 
149				
150				if (acHeader && acHeader != header) {
151					this.close(acHeader);
152					
153					var offTop 	= parseInt($(header).offset().top, 10),
154						scTop	= parseInt($(header).css('scroll-margin-top'), 10);
155						if (scTop) {
156							offTop -= scTop;	
157						}
158					
159					if (offTop < $(window).scrollTop()) {
160						if (prefersReducedMotion) {
161							$('html, body').scrollTop(offTop);
162						} else {
163							$('html, body').animate({scrollTop: offTop}, 500);
164						}
165					}
166				} 
167			}
168
169			$(header).toggleClass(op.activeCls);
170
171			var $container = $(header).next(op.containerSelector);
172			if (op.useAnimations === true && !prefersReducedMotion) {
173				$container[open ? 'slideDown' : 'slideUp']();
174			} else {
175				$container.css('display', open ? '' : 'none');
176			}
177	
178			if ($('button', header).length) {
179				$('button', header).attr('aria-expanded', open ? 'true': 'false');
180			} else {
181				$(header).attr('aria-expanded', open ? 'true': 'false');
182			}
183			
184			$('i'+(op.wrapInner ? '.accordion-toggle-button' : ''), header).removeClass(open ? io : ic).addClass(open ? ic : io);
185		},
186		
187		checkHash: function() {
188			var me		= this,
189				op		= me.options, 
190				hash	= decodeURI(window.location.hash || ''),
191				hashID	= hash && hash.substr(1),
192				trgEl; 
193			
194			if (hashID) {
195				var els	= me.rootNode.getElementsByTagName("*");
196				for (var i=0, len = els.length; i < len; i++) {
197					if (els[i].getAttribute('id') == hashID || els[i].getAttribute('data-anchor') == hashID) {
198						trgEl = els[i];
199						break;	
200					}	
201				}
202			}
203			
204			if (!trgEl || $(trgEl).hasClass(op.activeCls))
205				return;
206			
207			var ctSelector 	= op.containerSelector,
208				tiSelector 	= op.titleSelector,
209				openHit		= 0;
210			
211			if (me.rootNode == document.body) { 
212				$(trgEl).parentsUntil(me.rootNode, ctSelector).each(function(idx, ct) {
213					me.open($(ct).prev(tiSelector).get(0));
214					openHit = 1;
215				});
216			} else {
217				var ct	= $(trgEl).parentsUntil(me.rootNode, ctSelector).last(),
218					hd	= ct.length ? 0 : $(trgEl).closest(tiSelector).get(0);
219				
220				openHit = 1;
221				
222				me.open(hd ? hd : $(ct).prev(tiSelector).get(0));
223			}
224			
225			if (openHit) {
226				var topPos 	= parseInt($(trgEl).offset().top, 10),
227					scTop	= parseInt($(trgEl).css('scroll-margin-top'), 10) || parseInt($('> button', trgEl).css('scroll-margin-top'), 10);	
228					
229				if (topPos < 10 || window.globalIkissAccordionIsScrolling === true) 
230					return;
231				
232				if (scTop) {
233					topPos -= scTop;	
234				}
235				
236				window.globalIkissAccordionIsScrolling = true;
237				
238				if (prefersReducedMotion) {
239					$('html, body').scrollTop(topPos);
240					window.globalIkissAccordionIsScrolling = false;
241				} else {
242					$('html, body').animate({scrollTop: topPos}, 500);
243				}
244								
245			}
246		}
247		
248	};
249	
250	$.fn.ikissAccordion = function (options) {
251		var pKey = (options && options.pluginKey) || 'ikissAccordion';
252		return this.each(function() {
253			if (!$.data(this, pKey)) {    
254				$.data(this, pKey, new Plugin(this, options));
255			}          
256		});
257	};
258	
259	//Kompatibilität zur alten Accordion Syntax
260	window.ikissAccordion = function(config) {
261		
262		var cf = $.extend({ 
263			titleSelector		: '.toggler-title',
264			containerSelector	: '.toggler-container',
265			openFirstOnLoad		: false, 
266			wrapInner			: false
267		}, config || {});
268		
269		$.extend(cf, {
270			pluginKey		: (cf.titleSelector+'-'+cf.containerSelector).replace(/\./g, ''),
271			autoOpenFirst	: (cf.openFirstOnLoad || cf.autoOpenFirst)
272		});
273		delete cf.openFirstOnLoad;
274		
275		$(document.body).ikissAccordion(cf);
276	};
277	
278})(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.