PageSourceSearch

https://antenne-trier.com/wp-content/plugins/any-external-link/assets/js/frontend.js?ver=1.6.2

js antenne-trier.com collected 2026-10-05 09:45:12 UTC 7,026 bytes, 284 lines download raw bytes

1(function () {
2	'use strict';
3
4	if (typeof aelSettings === 'undefined') {
5		return;
6	}
7
8	var PROCESSED_ATTR = 'data-ael-processed';
9	var EXTERNAL_ATTR = 'data-ael-external';
10	var MODAL_ID = 'ael-external-link-modal';
11	var pendingUrl = '';
12	var pendingTarget = '';
13	var behavior = aelSettings.linkBehavior || 'both';
14	var showIcon = behavior !== 'modal_only';
15	var showModal = behavior !== 'icon_only';
16	var siteHost = normalizeHost(aelSettings.siteHost || window.location.hostname);
17
18	function normalizeHost(host) {
19		if (!host) {
20			return '';
21		}
22
23		return String(host).toLowerCase().replace(/^www\./, '');
24	}
25
26	function getLinkHost(href) {
27		try {
28			return normalizeHost(new URL(href, window.location.href).hostname);
29		} catch (error) {
30			return '';
31		}
32	}
33
34	function isSkippableScheme(href) {
35		return /^(mailto:|tel:|javascript:|#)/i.test(href);
36	}
37
38	function isExternalLink(link) {
39		if (!link || link.tagName !== 'A') {
40			return false;
41		}
42
43		var href = link.getAttribute('href');
44
45		if (!href || isSkippableScheme(href) || link.hasAttribute('download') || link.closest('[data-ael-ignore]')) {
46			return false;
47		}
48
49		var linkHost = getLinkHost(href);
50
51		return linkHost && linkHost !== siteHost;
52	}
53
54	function applyNewTabAttributes(link) {
55		if (!aelSettings.openInNewTab) {
56			return;
57		}
58
59		link.setAttribute('target', '_blank');
60
61		var rel = (link.getAttribute('rel') || '').split(/\s+/).filter(Boolean);
62		var relSet = {};
63
64		rel.forEach(function (item) {
65			relSet[item] = true;
66		});
67
68		relSet.noopener = true;
69		relSet.noreferrer = true;
70		link.setAttribute('rel', Object.keys(relSet).join(' '));
71	}
72
73	function createIcon() {
74		var icon = document.createElement('span');
75		icon.className = 'ael-external-icon';
76		icon.setAttribute('aria-hidden', 'true');
77
78		if (aelSettings.iconType === 'emoji') {
79			icon.textContent = ' ↗';
80			return icon;
81		}
82
83		icon.innerHTML =
84			'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" aria-hidden="true">' +
85			'<path d="M14 3h7v7h-2V6.41l-9.29 9.3-1.42-1.42 9.3-9.29H14V3z"></path>' +
86			'<path d="M5 5h6v2H7v10h10v-4h2v6H5V5z"></path>' +
87			'</svg>';
88
89		return icon;
90	}
91
92	function markLink(link) {
93		if (link.getAttribute(PROCESSED_ATTR) === '1') {
94			return;
95		}
96
97		link.setAttribute(PROCESSED_ATTR, '1');
98
99		if (!isExternalLink(link)) {
100			return;
101		}
102
103		link.classList.add('ael-external-link');
104
105		var existingIcon = link.querySelector('.ael-external-icon');
106
107		if (showIcon) {
108			if (!existingIcon) {
109				link.appendChild(createIcon());
110			}
111		} else if (existingIcon) {
112			existingIcon.remove();
113		}
114
115		if (showModal) {
116			link.setAttribute(EXTERNAL_ATTR, '1');
117			return;
118		}
119
120		applyNewTabAttributes(link);
121	}
122
123	function processLinks(root) {
124		var scope = root && root.querySelectorAll ? root : document;
125		scope.querySelectorAll('a[href]').forEach(markLink);
126	}
127
128	function ensureModal() {
129		if (!showModal || document.getElementById(MODAL_ID)) {
130			return;
131		}
132
133		var modal = document.createElement('div');
134		modal.id = MODAL_ID;
135		modal.className = 'ael-modal';
136		modal.setAttribute('role', 'dialog');
137		modal.setAttribute('aria-modal', 'true');
138		modal.setAttribute('aria-labelledby', 'ael-modal-title');
139		modal.setAttribute('aria-describedby', 'ael-modal-message');
140		modal.hidden = true;
141		modal.innerHTML =
142			'<div class="ael-modal__backdrop" data-ael-close></div>' +
143			'<div class="ael-modal__panel" role="document">' +
144			'<h2 id="ael-modal-title" class="ael-modal__title"></h2>' +
145			'<p id="ael-modal-message" class="ael-modal__message"></p>' +
146			'<p id="ael-modal-url" class="ael-modal__url" hidden></p>' +
147			'<div class="ael-modal__actions">' +
148			'<button type="button" class="ael-modal__button ael-modal__button--secondary" data-ael-cancel></button>' +
149			'<button type="button" class="ael-modal__button ael-modal__button--primary" data-ael-confirm></button>' +
150			'</div></div>';
151
152		document.body.appendChild(modal);
153
154		modal.querySelector('[data-ael-close]').addEventListener('click', closeModal);
155		modal.querySelector('[data-ael-cancel]').addEventListener('click', closeModal);
156		modal.querySelector('[data-ael-confirm]').addEventListener('click', confirmNavigation);
157
158		document.addEventListener('keydown', function (event) {
159			if (event.key === 'Escape' && !modal.hidden) {
160				closeModal();
161			}
162		});
163	}
164
165	function openModal(url) {
166		ensureModal();
167
168		var modal = document.getElementById(MODAL_ID);
169		var title = modal.querySelector('.ael-modal__title');
170		var message = modal.querySelector('.ael-modal__message');
171		var urlNode = modal.querySelector('.ael-modal__url');
172		var confirmButton = modal.querySelector('[data-ael-confirm]');
173		var cancelButton = modal.querySelector('[data-ael-cancel]');
174
175		title.textContent = aelSettings.modalTitle || 'Externer Link';
176		message.textContent = aelSettings.modalMessage || '';
177		confirmButton.textContent = aelSettings.confirmLabel || 'Weiter';
178		cancelButton.textContent = aelSettings.cancelLabel || 'Abbrechen';
179
180		if (aelSettings.showUrl) {
181			urlNode.hidden = false;
182			urlNode.textContent = url;
183		} else {
184			urlNode.hidden = true;
185			urlNode.textContent = '';
186		}
187
188		modal.hidden = false;
189		document.documentElement.classList.add('ael-modal-open');
190		confirmButton.focus();
191	}
192
193	function closeModal() {
194		var modal = document.getElementById(MODAL_ID);
195
196		if (!modal) {
197			return;
198		}
199
200		modal.hidden = true;
201		document.documentElement.classList.remove('ael-modal-open');
202		pendingUrl = '';
203		pendingTarget = '';
204	}
205
206	function confirmNavigation() {
207		if (!pendingUrl) {
208			closeModal();
209			return;
210		}
211
212		var url = pendingUrl;
213		var target = pendingTarget;
214		closeModal();
215
216		if (target === '_blank') {
217			window.open(url, '_blank', 'noopener,noreferrer');
218			return;
219		}
220
221		window.location.href = url;
222	}
223
224	function handleClick(event) {
225		if (!showModal) {
226			return;
227		}
228
229		var link = event.target.closest('a[href]');
230
231		if (!link || link.getAttribute(EXTERNAL_ATTR) !== '1') {
232			return;
233		}
234
235		event.preventDefault();
236		event.stopPropagation();
237
238		pendingUrl = link.href;
239		pendingTarget = aelSettings.openInNewTab ? '_blank' : (link.getAttribute('target') || '_self');
240		openModal(pendingUrl);
241	}
242
243	function initObserver() {
244		if (!window.MutationObserver) {
245			return;
246		}
247
248		new MutationObserver(function (mutations) {
249			mutations.forEach(function (mutation) {
250				if (mutation.type !== 'childList') {
251					return;
252				}
253
254				mutation.addedNodes.forEach(function (node) {
255					if (node.nodeType !== 1) {
256						return;
257					}
258
259					if (node.matches && node.matches('a[href]')) {
260						markLink(node);
261					}
262
263					processLinks(node);
264				});
265			});
266		}).observe(document.documentElement, { childList: true, subtree: true });
267	}
268
269	function init() {
270		processLinks(document);
271		ensureModal();
272		initObserver();
273
274		if (showModal) {
275			document.addEventListener('click', handleClick, true);
276		}
277	}
278
279	if (document.readyState === 'loading') {
280		document.addEventListener('DOMContentLoaded', init);
281	} else {
282		init();
283	}
284})();

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.