PageSourceSearch

https://apollo-news.net/wp-content/plugins/ad-free-subscription/assets/js/ad-free-subscription.js?ver=1.6.14

js apollo-news.net collected 2026-10-01 11:46:01 UTC 15,558 bytes, 464 lines download raw bytes

1window.adFreeSubscription || (function () {
2
3	window.adFreeSubscription = {
4
5		bannerInitialized: false,
6
7		sendLog: function (message) {
8			if (typeof(adFreeSubscriptionConfig.pluginUrl) === 'undefined') {
9				console.warn('Missing plugin url, cannot send error.');
10				return;
11			}
12
13			// Define the target URL for the AJAX request
14			const url = adFreeSubscriptionConfig.pluginUrl + 'api/api.php';
15			// Prepare the JSON payload
16			const data = { 
17				message: message, 
18				nonce: (typeof adFreeSubscriptionConfig.nonce !== 'undefined' ? adFreeSubscriptionConfig.nonce : null)
19			};
20
21			// Send the POST request using Fetch API
22			fetch(url, {
23				method: 'POST',
24				headers: {
25					'Content-Type': 'application/json'
26				},
27				body: JSON.stringify(data) // Convert the error data to JSON
28			})
29			.then(response => {
30				if (!response.ok) {
31					console.warn(`Server responded with status ${response.status}`);
32				}
33				return response.json(); // Parse the JSON response
34			})
35			.then(data => {
36				console.log('Response from server:', data);
37			})
38			.catch(error => {
39				console.error('Error while posting error to server:', error);
40			});
41		},
42
43		sendInfo: function (message) {
44			if (!adFreeSubscriptionConfig.extendedLogging) {
45				return;
46			}
47			adFreeSubscription.sendLog(message);
48		},
49
50		sendError: function (e) {
51			adFreeSubscription.sendLog(e.toString() + (typeof (e.stack) !== "undefined" ? "\n" + e.stack.toString() : ""));
52		},
53
54		checkElement: async selector => {
55			while (document.querySelector(selector) === null) {
56				await new Promise(resolve => requestAnimationFrame(resolve));
57			}
58			return document.querySelector(selector);
59		},
60
61		onCookiebotReady: function (e) {
62			window.removeEventListener('CookiebotOnDialogInit', adFreeSubscription.onCookiebotReady);
63			console.log('Cookiebot is ready.');
64			if (typeof (CookieConsent) !== 'undefined' && CookieConsent.regulationRegions && CookieConsent.regulationRegions.gdpr) {
65				// Add Switzerland to the list of regulation regions to ensure full ad delivery
66				if (!CookieConsent.regulationRegions.gdpr.includes('ch')) {	
67					CookieConsent.regulationRegions.gdpr.push('ch');
68				}
69			}
70			adFreeSubscription.showBanner();
71		},
72
73		showBanner: function () {
74			if (adFreeSubscription.isAcceptAll()) {
75				return;
76			}
77			console.log('Showing Ad-Free-Subscription banner ...');
78			adFreeSubscription.sendInfo('Showing Ad-Free-Subscription banner ...');
79
80			const banner = document.querySelector('.ad-free-sub-banner-container');
81			if (!banner) {
82				adFreeSubscription.checkElement('.ad-free-sub-banner-container').then((banner) => {
83					banner.style.display = '';
84					adFreeSubscription.initBanner();
85					adFreeSubscription.checkAcceptAllButton();
86				});
87			} else {
88				banner.style.display = '';
89				adFreeSubscription.initBanner();
90				adFreeSubscription.checkAcceptAllButton();
91			}
92		},
93
94		checkAcceptAllButton: function () {
95			const buttonId = 'ad-free-sub-banner-btn-accept-all';
96			const button = document.getElementById(buttonId);
97			
98			if (!button) {
99				adFreeSubscription.sendInfo(`Button with ID '${buttonId}' not found`);
100				return false;
101			}
102			
103			// Check if button is visible
104			const isVisible = button.offsetWidth > 0 && 
105							 button.offsetHeight > 0 && 
106							 getComputedStyle(button).display !== 'none' &&
107							 getComputedStyle(button).visibility !== 'hidden';
108			
109			// Check if button is clickable (not disabled)
110			const isClickable = !button.disabled && 
111							   !button.hasAttribute('disabled') &&
112							   getComputedStyle(button).pointerEvents !== 'none';
113			
114			const isReady = isVisible && isClickable;
115
116			if (isReady) {
117				adFreeSubscription.sendInfo(`Button (${buttonId}) is visible and clickable.`);
118				console.log(`Button (${buttonId}) is visible and clickable.`);
119			} else {
120				adFreeSubscription.sendInfo(`Button (${buttonId}) is not ready.`);
121				console.warn(`Button (${buttonId}) is not ready.`);
122			}
123			
124			return isReady;
125		},
126		
127		getClientId: function () {
128			let clientId = localStorage.getItem("ad-free-subscription-client-id");
129			if (!clientId) {
130			  clientId = crypto.randomUUID();
131			  localStorage.setItem("ad-free-subscription-client-id", clientId);
132			}
133			return clientId;
134		},
135
136		initBanner: function () {
137			if (adFreeSubscription.bannerInitialized) {
138				return;
139			}
140			adFreeSubscription.bannerInitialized = true;
141
142			const acceptAllButton = document.querySelector('#ad-free-sub-banner-btn-accept-all');
143			if (acceptAllButton) {
144				acceptAllButton.addEventListener('click', adFreeSubscription.acceptAll);
145			}
146
147			const revokeLink = document.querySelectorAll('.ad-free-subscription-revoke');
148			if (revokeLink) {
149				revokeLink.forEach(elem => {
150					elem.addEventListener('click', adFreeSubscription.revoke);
151				});
152			}
153
154			const showPartnerLink = document.querySelectorAll('.ad-free-sub-show-partner-link');
155			if (showPartnerLink) {
156				showPartnerLink.forEach(elem => {
157					elem.addEventListener('click', adFreeSubscription.showPartner);
158				})
159			}
160
161			adFreeSubscription.initTcf();
162			const accordion = document.getElementsByClassName("ad-free-sub-accordion-item-button");
163			for (var i = 0; i < accordion.length; i++) {
164				accordion[i].addEventListener("click", adFreeSubscription.toggleAccordtionItem);
165			}
166		},
167
168		toggleAccordtionItem: function () {
169			this.classList.toggle("active");
170			var panel = this.nextElementSibling;
171			if (panel.style.display === "block") {
172				panel.style.display = "none";
173			} else {
174				panel.style.display = "block";
175			}
176		},
177
178		hideBanner: function () {
179			const banner = document.querySelector('.ad-free-sub-banner-container');
180			if (banner) {
181				banner.style.display = 'none';
182			}
183		},
184
185		acceptAll: function (e) {
186			try {
187				if (typeof(CookieConsentIABCMP) === 'undefined') {
188					const error = new Error("CookieConsentIABCMP is not defined. User will see banner again on next page load.");
189					throw error;
190				}
191				CookieConsentIABCMP.initFramework();
192				CookieConsentIABCMP.updateConsentFullOptIn();
193				Cookiebot.submitCustomConsent(true, true, true);
194				adFreeSubscription.sendInfo('Full consent given.');
195			} catch (e) {
196				console.warn("Error when giving full consent.", e);
197				adFreeSubscription.sendError(e);
198			} finally {
199				adFreeSubscription.hideBanner();
200			}
201		},
202
203		isAcceptAll: function () {
204			if (!Cookiebot?.consent) {
205				return false;
206			}
207			return Cookiebot.consent.necessary &&
208				Cookiebot.consent.preferences &&
209				Cookiebot.consent.statistics &&
210				Cookiebot.consent.marketing;
211		},
212
213		revoke: function (e) {
214			e?.preventDefault();
215			window.addEventListener('CookiebotOnDecline', function (e) {
216				window.location.reload();
217			});
218			Cookiebot.withdraw();
219		},
220
221		showPartner: function (e) {
222			e?.preventDefault();
223			const style = document.querySelector("#ad-free-sub-banner-style");
224			const sheet = style.sheet ? style.sheet : style.styleSheet;
225			if (sheet?.cssRules) {
226				for (var i = 0; i < sheet.cssRules.length; i++) {
227					if (sheet.cssRules[i].selectorText === '#CybotCookiebotDialog') {
228						sheet.deleteRule(i);
229						break;
230					}
231				}
232			}
233			window.removeEventListener('CookiebotOnDialogInit', adFreeSubscription.onCookiebotReady);
234			Cookiebot.show();
235
236			const overlay = document.querySelector('#ad-free-sub-banner-container');
237			if (overlay) {
238				overlay.style.display = 'none';
239			}
240		},
241
242		setCookie: function (name, value, days) {
243			var expires = "";
244			if (days) {
245				var date = new Date();
246				date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
247				expires = "; expires=" + date.toUTCString();
248			}
249			document.cookie = name + "=" + (value || "") + expires + "; path=/";
250		},
251
252		getCookie: function (name) {
253			var dc = document.cookie;
254			var prefix = name + "=";
255			var begin = dc.indexOf("; " + prefix);
256			if (begin == -1) {
257				begin = dc.indexOf(prefix);
258				if (begin != 0) return null;
259			}
260			else {
261				begin += 2;
262				var end = document.cookie.indexOf(";", begin);
263				if (end == -1) {
264					end = dc.length;
265				}
266			}
267			return decodeURI(dc.substring(begin + prefix.length, end));
268		},
269
270		initTcf: function () {
271			const configElem = document.querySelector('#CookiebotConfiguration');
272			if (!configElem) {
273				console.warn("No Cookiebot config found!");
274				return;
275			}
276
277			const config = JSON.parse(configElem.textContent);
278			const tcf = config?.Frameworks.IABTCF2;
279			if (!tcf) {
280				console.warn("No IAB TCF2 config found!");
281				return;
282			}
283			const vendors = tcf.AllowedVendors;
284
285			let purposes = tcf.AllowedPurposes;
286			const specialPurposes = tcf.AllowedSpecialPurposes;
287			const features = tcf.AllowedFeatures;
288			let specialFeatures = tcf.AllowedSpecialFeatures;
289
290			const stackedFeatures = adFreeSubscription.resolveStackedFeatures(adFreeSubscriptionTcfPurposes, tcf.AllowedPurposes, tcf.AllowedSpecialFeatures);
291			purposes = purposes.filter(e => !stackedFeatures.some(sf => sf.purposes.includes(e)));
292			specialFeatures = specialFeatures.filter(e => !stackedFeatures.some(sf => sf.specialFeatures.includes(e)));
293
294			adFreeSubscription.displayPurposes(adFreeSubscriptionTcfPurposes, stackedFeatures.map(sf => sf.id), purposes, specialPurposes, features, specialFeatures);
295		},
296
297		resolveStackedFeatures: function (tcfPurposes, actualPurposes, actualSpecialFeatures) {
298			const stackedFeatures = [];
299			for (var i in tcfPurposes.stacks) {
300				const stackedFeature = tcfPurposes.stacks[i];
301				const purposes = stackedFeature.purposes;
302				const specialFeatures = stackedFeature.specialFeatures;
303
304				const isStackedFeature =
305					(purposes.length === 0 || purposes.every(e => actualPurposes.includes(e))) &&
306					(specialFeatures.length === 0 || specialFeatures.every(e => actualSpecialFeatures.includes(e)));
307				if (isStackedFeature) {
308					stackedFeatures.push(stackedFeature);
309				}
310			}
311
312			// Alle Stacked features rausfiltern, die schon in anderen enthalten sind
313			let filtered = [];
314			for (var i in stackedFeatures) {
315				const stackedFeature = stackedFeatures[i];
316				if (stackedFeature.purposes.length > 0 &&
317					stackedFeatures.some(
318						sf => sf.id != stackedFeature.id &&
319							stackedFeature.purposes.every(p => sf.purposes.includes(p)))) {
320					continue;
321				}
322				if (stackedFeature.specialFeatures.length > 0 &&
323					stackedFeatures.some(
324						sf => sf.id != stackedFeature.id &&
325							stackedFeature.specialFeatures.every(p => sf.specialFeatures.includes(p)))) {
326					continue;
327				}
328				filtered.push(stackedFeature);
329			}
330
331			// Sicherstellen, dass Zwecke/Features nur in einem Stack vorkommen
332			let filteredByDuplicate = [];
333			for (var i in actualPurposes) {
334				const actualPurpose = actualPurposes[i];
335				const stackedFeature = filtered.find(sf => sf.purposes.includes(actualPurpose));
336				if (stackedFeature && !filteredByDuplicate.find(sf =>
336 sf.id === stackedFeature.id)) {
337					filteredByDuplicate.push(stackedFeature);
338				}
339			}
340			for (var i in actualSpecialFeatures) {
341				const actualSpecialFeature = actualSpecialFeatures[i];
342				const stackedFeature = filtered.find(sf => sf.specialFeatures.includes(actualSpecialFeature));
343				if (stackedFeature && !filteredByDuplicate.find(sf => sf.id === stackedFeature.id)) {
344					filteredByDuplicate.push(stackedFeature);
345				}
346			}
347			filtered = filteredByDuplicate;
348
349			// // jetzt noch alle mit gleichem namen rausfiltern
350			// let filteredByName = [];
351			// for (var i in filtered) {
352			// 	const stackedFeature = filtered[i];
353			// 	if (!filteredByName.map(sf => sf.name.trim()).includes(stackedFeature.name.trim())) {
354			// 		filteredByName.push(stackedFeature);
355			// 	}
356			// }
357
358			return filtered;
359		},
360
361		displayPurposes: function (tcfPurposes, stackedFeatures, actualPurposes, actualSpecialPurposes, actualFeatures, actualSpecialFeatures) {
362			const accordion = document.querySelector('#ad-free-subscription-purposes');
363			if (!accordion) {
364				console.warn('No accordion for displayling purposes found.');
365				return;
366			}
367
368			// remove old entries
369			const existingItems = document.querySelectorAll('.ad-free-sub-purpose-item:not(.ad-free-sub-purpose-item-necessary)');
370			existingItems.forEach((e) => {
371				accordion.removeChild(e);
372			});
373
374			adFreeSubscription.displayPurposesList(accordion, tcfPurposes.stacks, stackedFeatures);
375			adFreeSubscription.displayPurposesList(accordion, tcfPurposes.purposes, actualPurposes);
376			adFreeSubscription.displayPurposesList(accordion, tcfPurposes.specialPurposes, actualSpecialPurposes);
377			adFreeSubscription.displayPurposesList(accordion, tcfPurposes.features, actualFeatures);
378			adFreeSubscription.displayPurposesList(accordion, tcfPurposes.specialFeatures, actualSpecialFeatures);
379		},
380
381		displayPurposesList: function (accordion, purposesList, currentPurposes) {
382			if (!purposesList) {
383				console.log("No purposes list given.");
384				return;
385			}
386			if (currentPurposes && currentPurposes.length > 0) {
387				for (var i = 0; i < currentPurposes.length; i++) {
388
389					const purposeId = currentPurposes[i];
390					const purpose = purposesList[purposeId];
391					if (!purpose) {
392						console.log("No purpose with id '" + purposeId + "' found.")
393						continue;
394					}
395					const name = purpose.name;
396					const description = purpose.description;
397
398					const item = document.createElement('div');
399					item.classList.add('ad-free-sub-accordion-item');
400					item.classList.add('ad-free-sub-purpose-item');
401
402					const button = document.createElement('button');
403					button.classList.add('ad-free-sub-accordion-item-button');
404					button.textContent = name;
405					item.appendChild(button);
406
407					const content = document.createElement('div');
408					content.classList.add('ad-free-sub-accordion-item-content');
409					content.style.display = 'none';
410					const contentParagraph = document.createElement('p');
411					contentParagraph.textContent = description;
412					content.appendChild(contentParagraph);
413					item.appendChild(content);
414
415					accordion.appendChild(item);
416				}
417			}
418		}
419	};
420
421	if (typeof (Cookiebot) !== 'undefined') {
422		init();
423	} else {
424		document.addEventListener('DOMContentLoaded', init);
425	}
426
427	function init() {
428		console.log("Ad-Free Subscription JS is loaded and ready.");
429
430		if (typeof (Cookiebot) === 'undefined') {
431			console.error("Cookiebot is not defined!");
432			const error = new Error("Cookiebot is not defined!");
433			adFreeSubscription.sendError(error);
434			return;
435		}
436
437		const adFree = typeof (adFreeSubscriptionConfig) !== 'undefined' && adFreeSubscriptionConfig.isAdFreeSubscriber;
438		if (adFree) {
439			console.log("User has a subscription.");
440			if (!Cookiebot.declined) {
441				Cookiebot.submitCustomConsent(false, false, false);
442			}
443		} else if (!adFreeSubscription.isAcceptAll()) {
444			console.log("User has no subscription and hasn't given full consent.");
445			adFreeSubscription.getClientId();
446
447			// If the Cookiebot dialog has not already been initialized, we have to do so before showing the ad-free-banner
448			if (typeof CookiebotDialog !== 'object' || !CookiebotDialog.visible) {
449				window.addEventListener('CookiebotOnDialogInit', adFreeSubscription.onCookiebotReady);
450				// If Cookiebot already has a response (accept/decline) from the user, it won't show up
451				// Therefore we have to force Cookiebot to show up again
452				if (Cookiebot.hasResponse) {
453					console.log("Cookiebot already has a response, showing up Cookiebot ...");
454					Cookiebot.show();
455				}
456				// otherwise, just show the banner
457			} else {
458				adFreeSubscription.showBanner();
459			}
460		} else {
461			console.log("User has no subscription, but has given full consent.");
462		}
463	}
464})();

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.