PageSourceSearch

https://startrektour.com/wp-content/plugins/woocommerce-gdpr-cookies/assets/js/consent-manager.js?ver=2.0.1

js startrektour.com collected 2026-10-02 11:09:16 UTC 18,245 bytes, 606 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function() {
2	var floatingHideStorageKey = 'gdpr_floating_btn_hidden';
3	var cookieName = (window.cnArgs && cnArgs.cookieName) ? cnArgs.cookieName : 'opmc_gdpr_accepted';
4	// Initialize script unblocking on page load based on currently accepted cookies
5	releaseScripts();
6
7	// Show banner if user has not yet made a consent choice
8	if (!hasUserConsented()) {
9		slideDownNotice();
10	}
11
12	// Sync floating button visibility on load
13	syncFloatingButton();
14
15	// Utility to handle AJAX without jQuery
16	function sendConsentAction(action, data) {
17		data = data || {};
18		var payload = new URLSearchParams();
19		payload.append('action', 'gdpr_cookie_action');
20		payload.append('consent_action', action);
21		payload.append('nonce', cnArgs.gdpr_nonce);
22
23		for (var key in data) {
24			if (Object.prototype.hasOwnProperty.call(data, key)) {
25				var value = data[key];
26				// Handle arrays (e.g. categories sent as repeated keys)
27				if (Array.isArray(value)) {
28					value.forEach(function(item) {
29						payload.append(key + '[]', item);
30					});
31				} else {
32					payload.append(key, value);
33				}
34			}
35		}
36
37		return fetch(cnArgs.ajaxurl, {
38			method: 'POST',
39			body: payload,
40			credentials: 'same-origin',
41			headers: {
42				'Content-Type': 'application/x-www-form-urlencoded'
43			}
44		}).then(function(res) {
45			return res.text().then(function(text) {
46				var parsed;
47				try {
48					parsed = text ? JSON.parse(text) : {};
49				} catch (err) {
50					parsed = null;
51				}
52
53				if (!res.ok || !parsed) {
54					throw new Error('Consent request failed');
55				}
56
57				return parsed;
58			});
59		});
60	}
61
62	function slideUpNotice() {
63		var notice = document.getElementById('cookie-notice');
64		if (notice) {
65			notice.style.display = 'none';
66		}
67	}
68
69	function slideDownNotice() {
70		var notice = document.getElementById('cookie-notice');
71		if (notice) {
72			notice.style.display = 'block';
73		}
74	}
75
76	function hasUserConsented() {
77		if (!window.cnArgs) {
78			return hasLegacyConsentCookie();
79		}
80
81		// A stored timestamp indicates the user has previously made a choice.
82		if ( cnArgs.consent_payload && !!cnArgs.consent_payload.timestamp ) {
83			return true;
84		}
85
86		if ( cnArgs.hasConsent ) {
87			return true;
88		}
89
90		return hasLegacyConsentCookie();
91	}
92
93	function hasLegacyConsentCookie() {
94		return readCookie(cookieName) !== null;
95	}
96
97	function readCookie(name) {
98		var parts = ('; ' + document.cookie).split('; ' + name + '=');
99		if (parts.length === 2) {
100			return parts.pop().split(';').shift();
101		}
102		return null;
103	}
104
105	function setLegacyConsentCookie(isAccepted) {
106		var expires = new Date();
107		expires.setTime(expires.getTime() + parseInt(cnArgs.cookieTime || 0, 10) * 1000);
108		document.cookie = cookieName + '=' + (isAccepted ? 'true' : 'false') + ';expires=' + expires.toUTCString() + ';' +
109			(cnArgs.cookieDomain ? 'domain=' + cnArgs.cookieDomain + ';' : '') +
110			(cnArgs.cookiePath ? 'path=' + cnArgs.cookiePath + ';' : 'path=/;') +
111			(cnArgs.secure === 1 || cnArgs.secure === '1' ? 'secure;' : '');
112	}
113
114	function getFallbackConsentPayload(acceptedCategories) {
115		var categories = cnArgs.cookie_categories || {};
116		var consent = {};
117		acceptedCategories = acceptedCategories || [];
118
119		Object.keys(categories).forEach(function(key) {
120			consent[key] = !!categories[key].required || acceptedCategories.indexOf(key) !== -1;
121		});
122
123		consent.timestamp = Math.floor(Date.now() / 1000);
124		consent.version = (cnArgs.consent_payload && cnArgs.consent_payload.version) || '1.0';
125
126		return consent;
127	}
128
129	/**
130	 * Show or hide the persistent floating "Cookie Settings" button.
131	 * It should be visible whenever the banner is hidden (i.e. user has consented).
132	 */
133	function syncFloatingButton() {
134		var btn = document.getElementById('gdpr-floating-btn');
135		if (!btn) return;
136		if (hasUserConsented() && !isFloatingButtonHidden()) {
137			btn.style.display = 'block';
138			btn.setAttribute('aria-hidden', 'false');
139		} else {
140			btn.style.display = 'none';
141			btn.setAttribute('aria-hidden', 'true');
142		}
143	}
144
145	function isFloatingButtonHidden() {
146		try {
147			return window.localStorage.getItem(floatingHideStorageKey) === '1';
148		} catch (e) {
149			return false;
150		}
151	}
152
153	function hideFloatingButtonForUser() {
154		try {
155			window.localStorage.setItem(floatingHideStorageKey, '1');
156		} catch (e) {
157			// Ignore storage errors in restricted modes.
158		}
159		syncFloatingButton();
160	}
161
162	// -----------------------------------------------------------------------
163	// Preferences Modal
164	// -----------------------------------------------------------------------
165
166	function openPreferencesModal() {
167		var modal = document.getElementById('gdpr-preferences-modal');
168		var strings = cnArgs.strings || {};
169		if (!modal) {
170			modal = buildPreferencesModal();
171			document.body.appendChild(modal);
172		}
173
174		// Reset action buttons every time modal opens (modal DOM is reused).
175		var saveBtn = modal.querySelector('#gdpr-save-preferences');
176		if (saveBtn) {
177			saveBtn.disabled = false;
178			saveBtn.textContent = strings.save_preferences || 'Save Preferences';
179		}
180		var acceptAllBtn = modal.querySelector('#gdpr-modal-accept-all');
181		if (acceptAllBtn) {
182			acceptAllBtn.disabled = false;
183		}
184
185		syncCheckboxesToCurrentConsent(modal);
186		modal.style.display = 'flex';
187		document.body.classList.add('gdpr-modal-open');
188	}
189
190	function closePreferencesModal() {
191		var modal = document.getElementById('gdpr-preferences-modal');
192		if (modal) {
193			modal.style.display = 'none';
194		}
195		document.body.classList.remove('gdpr-modal-open');
196	}
197
198	/**
199	 * Build the preferences modal DOM from cnArgs.cookie_categories.
200	 */
201	function buildPreferencesModal() {
202		var categories = cnArgs.cookie_categories || {};
203		var strings = cnArgs.strings || {};
204
205		var overlay = document.createElement('div');
206		overlay.id = 'gdpr-preferences-modal';
207		overlay.setAttribute('role', 'dialog');
208		overlay.setAttribute('aria-modal', 'true');
209		overlay.setAttribute('aria-labelledby', 'gdpr-modal-title');
210
211		var box = document.createElement('div');
212		box.className = 'gdpr-modal-box';
213
214		// --- Header ---
215		var header = document.createElement('div');
216		header.className = 'gdpr-modal-header';
217
218		var title = document.createElement('h2');
219		title.id = 'gdpr-modal-title';
220		title.textContent = strings.modal_title || 'Cookie Preferences';
221
222		var closeBtn = document.createElement('button');
223		closeBtn.className = 'gdpr-modal-close';
224		closeBtn.setAttribute('aria-label', 'Close');
225		closeBtn.innerHTML = '×';
226		closeBtn.addEventListener('click', closePreferencesModal);
227
228		header.appendChild(title);
229		header.appendChild(closeBtn);
230
231		// --- Body ---
232		var body = document.createElement('div');
233		body.className = 'gdpr-modal-body';
234
235		var intro = document.createElement('p');
236		intro.className = 'gdpr-modal-intro';
237		intro.textContent = strings.modal_intro ||
238			'Manage your cookie preferences below. Essential cookies cannot be disabled as they are required for the site to function.';
239		body.appendChild(intro);
240
241		var list = document.createElement('ul');
242		list.className = 'gdpr-category-list';
243
244		Object.keys(categories).forEach(function(key) {
245			var cat = categories[key];
246
247			var item = document.createElement('li');
248			item.className = 'gdpr-category-item';
249
250			var row = document.createElement('div');
251			row.className = 'gdpr-category-row';
252
253			var labelWrap = document.createElement('label');
254			labelWrap.className = 'gdpr-category-label';
255			labelWrap.setAttribute('for', 'gdpr-cat-' + key);
256
257			var checkbox = document.createElement('input');
258			checkbox.type = 'checkbox';
259			checkbox.id = 'gdpr-cat-' + key;
260			checkbox.value = key;
261			checkbox.className = 'gdpr-category-checkbox';
262
263			if (cat.required) {
264				checkbox.checked = true;
265				checkbox.disabled = true;
266			}
267
268			var labelText = document.createElement('span');
269			labelText.className = 'gdpr-category-name';
270			labelText.textContent = cat.label || key;
271
272			labelWrap.appendChild(checkbox);
273			labelWrap.appendChild(labelText);
274
275			var statusBadge = document.createElement('span');
276			if (cat.required) {
277				statusBadge.className = 'gdpr-status-badge gdpr-always-active';
278				statusBadge.textContent = strings.always_active || 'Always Active';
279			} else {
280				statusBadge.className = 'gdpr-status-badge gdpr-status-toggle';
281				statusBadge.setAttribute('data-cat', key);
282				statusBadge.textContent = strings.inactive || 'Inactive';
283			}
284
285			row.appendChild(labelWrap);
286			row.appendChild(statusBadge);
287
288			var desc = document.createElement('p');
289			desc.className = 'gdpr-category-desc';
290			desc.textContent = cat.description || '';
291
292			item.appendChild(row);
293			item.appendChild(desc);
294			list.appendChild(item);
295
296			// Keep status badge text in sync with checkbox state
297			if (!cat.required) {
298				checkbox.addEventListener('change', function() {
299					updateStatusBadge(key, checkbox.checked, strings);
300				});
301			}
302		});
303
304		body.appendChild(list);
305
306		// --- Footer ---
307		var footer = document.createElement('div');
308		footer.className = 'gdpr-modal-footer';
309
310		var saveBtn = document.createElement('button');
311		saveBtn.id = 'gdpr-save-preferences';
312		saveBtn.className = 'gdpr-btn gdpr-btn-primary';
313		saveBtn.textContent = strings.save_preferences || 'Save Preferences';
314
315		var acceptAllBtn = document.createElement('button');
316		acceptAllBtn.id = 'gdpr-modal-accept-all';
317		acceptAllBtn.className = 'gdpr-btn gdpr-btn-secondary';
318		acceptAllBtn.textContent = strings.accept_all || 'Accept All';
319
320		footer.appendChild(saveBtn);
321		footer.appendChild(acceptAllBtn);
322
323		box.appendChild(header);
324		box.appendChild(body);
325		box.appendChild(footer);
326		overlay.appendChild(box);
327
328		// --- Save Preferences ---
329		saveBtn.addEventListener('click', function() {
330			var checked = overlay.querySelectorAll('.gdpr-category-checkbox:checked:not(:disabled)');
331			var selectedCategories = [];
332			checked.forEach(function(cb) {
333				selectedCategories.push(cb.value);
334			});
335
336			saveBtn.disabled = true;
337			saveBtn.textContent = strings.saving || 'Saving...';
338			setLegacyConsentCookie(false);
339			cnArgs.hasConsent = true;
340
341			// 'categories' key becomes 'categories[]' inside sendConsentAction
342			// so PHP receives it as $_POST['categories'] array
343			sendConsentAction('save_preferences', { categories: selectedCategories })
344				.then(function(response) {
345					if (response.success) {
346						cnArgs.consent_payload = response.data.consent;
347						releaseScripts();
348						saveBtn.disabled = false;
349						saveBtn.textContent = strings.save_preferences || 'Save Preferences';
350						closePreferencesModal();
351						slideUpNotice();
352						syncFloatingButton();
353						dispatchSpecificEvent('gdpr_preferences_saved', response.data.consent);
354					} else {
355						// AJAX returned but reported failure — re-enable button
356						cnArgs.consent_payload = getFallbackConsentPayload(selectedCategories);
357						slideUpNotice();
358						syncFloatingButton();
359						closePreferencesModal();
360						saveBtn.disabled = false;
361						saveBtn.textContent = strings.save_preferences || 'Save Preferences';
362					}
363				}, function() {
364					// Network / parse error — re-enable button
365					cnArgs.consent_payload = getFallbackConsentPayload(selectedCategories);
366					slideUpNotice();
367					syncFloatingButton();
368					closePreferencesModal();
369					saveBtn.disabled = false;
370					saveBtn.textContent = strings.save_preferences || 'Save Preferences';
371				});
372		});
373
374		// --- Accept All from inside modal ---
375		acceptAllBtn.addEventListener('click', function() {
376			acceptAllBtn.disabled = true;
377			setLegacyConsentCookie(true);
378			cnArgs.hasConsent = true;
379
380			sendConsentAction('accept_all').then(function(response) {
381				if (response.success) {
382					cnArgs.consent_payload = response.data.consent;
383					releaseScripts();
384					closePreferencesModal();
385					slideUpNotice();
386					syncFloatingButton();
387					dispatchSpecificEvent('gdpr_consent_accepted', response.data.consent);
388
389					if (cnArgs.redirection) {
390						window.location.reload();
391					}
392				} else {
393					cnArgs.consent_payload = getFallbackConsentPayload(Object.keys(cnArgs.cookie_categories || {}));
394					releaseScripts();
395					closePreferencesModal();
396					slideUpNotice();
397					syncFloatingButton();
398				}
399				acceptAllBtn.disabled = false;
400			}, function() {
401				cnArgs.consent_payload = getFallbackConsentPayload(Object.keys(cnArgs.cookie_categories || {}));
402				releaseScripts();
403				closePreferencesModal();
404				slideUpNotice();
405				syncFloatingButton();
406				acceptAllBtn.disabled = false;
407			});
408		});
409
410		// Close on overlay backdrop click
411		overlay.addEventListener('click', function(e) {
412			if (e.target === overlay) {
413				closePreferencesModal();
414			}
415		});
416
417		return overlay;
418	}
419
420	/**
421	 * Update the status badge text for a category.
422	 */
423	function updateStatusBadge(key, isActive, strings) {
424		strings = strings || cnArgs.strings || {};
425		var badge = document.querySelector('.gdpr-status-badge[data-cat="' + key + '"]');
426		if (badge) {
427			if (isActive) {
428				badge.classList.add('gdpr-is-active');
429				badge.textContent = strings.active || 'Active';
430			} else {
431				badge.classList.remove('gdpr-is-active');
432				badge.textContent = strings.inactive || 'Inactive';
433			}
434		}
435	}
436
437	/**
438	 * Sync checkbox states to the current saved consent payload.
439	 */
440	function syncCheckboxesToCurrentConsent(modal) {
441		var consent = cnArgs.consent_payload || {};
442		var strings = cnArgs.strings || {};
443
444		var checkboxes = modal.querySelectorAll('.gdpr-category-checkbox:not(:disabled)');
445		checkboxes.forEach(function(cb) {
446			var isActive = consent[cb.value] === true;
447			cb.checked = isActive;
448			updateStatusBadge(cb.value, isActive, strings);
449		});
450	}
451
452	// -----------------------------------------------------------------------
453	// Banner Button Handlers
454	// -----------------------------------------------------------------------
455
456	// Accept All
457	// stopImmediatePropagation prevents front.js jQuery handler from also firing
458	document.addEventListener('click', function(e) {
459		var target = e.target.closest('.cn-set-cookie[data-cookie-set="accept"]');
460		if (!target) return;
461		e.preventDefault();
462		e.stopImmediatePropagation();
463		setLegacyConsentCookie(true);
464		cnArgs.hasConsent = true;
465
466		sendConsentAction('accept_all').then(function(response) {
467			if (response.success) {
468				slideUpNotice();
469				cnArgs.consent_payload = response.data.consent;
470				releaseScripts();
471				syncFloatingButton();
472				dispatchSpecificEvent('gdpr_consent_accepted', response.data.consent);
473
474				if (cnArgs.redirection) {
475					window.location.reload();
476				}
477			} else {
478				slideUpNotice();
479				cnArgs.consent_payload = getFallbackConsentPayload(Object.keys(cnArgs.cookie_categories || {}));
480				releaseScripts();
481				syncFloatingButton();
482			}
483		}, function() {
484			slideUpNotice();
485			cnArgs.consent_payload = getFallbackConsentPayload(Object.keys(cnArgs.cookie_categories || {}));
486			releaseScripts();
487			syncFloatingButton();
488		});
489	});
490
491	// Reject Non-Essential
492	// stopImmediatePropagation prevents front.js jQuery handler from also firing
493	document.addEventListener('click', function(e) {
494		var target = e.target.closest('.cn-set-cookie[data-cookie-set="refuse"]');
495		if (!target) return;
496		e.preventDefault();
497		e.stopImmediatePropagation();
498		setLegacyConsentCookie(false);
499		cnArgs.hasConsent = true;
500
501		sendConsentAction('reject_non_essential').then(function(response) {
502			if (response.success) {
503				slideUpNotice();
504				cnArgs.consent_payload = response.data.consent;
505				releaseScripts();
506				syncFloatingButton();
507				dispatchSpecificEvent('gdpr_consent_rejected', response.data.consent);
508			} else {
509				slideUpNotice();
510				cnArgs.consent_payload = getFallbackConsentPayload([]);
511				releaseScripts();
512				syncFloatingButton();
513			}
514		}, function() {
515			slideUpNotice();
516			cnArgs.consent_payload = getFallbackConsentPayload([]);
517			releaseScripts();
518			syncFloatingButton();
519		});
520	});
521
522	// Open Preferences Modal — any element with data-gdpr="preferences" or .cn-manage-preferences
523	document.addEventListener('click', function(e) {
524		var target = e.target.closest('[data-gdpr="preferences"], .cn-manage-preferences');
525		if (!target) return;
526		e.preventDefault();
527		openPreferencesModal();
528	});
529
530	// Hide floating button for this browser/user.
531	document.addEventListener('click', function(e) {
532		var target = e.target.closest('.gdpr-floating-hide');
533		if (!target) return;
534		e.preventDefault();
535		e.stopImmediatePropagation();
536		hideFloatingButtonForUser();
537	});
538
539	// Revoke / re-show the banner
540	document.addEventListener('click', function(e) {
541		var target = e.target.closest('.cn-revoke-cookie');
542		if (!target) return;
543		e.preventDefault();
544		slideDownNotice();
545	});
546
547	// Close modal on Escape key
548	document.addEventListener('keydown', function(e) {
549		if (e.key === 'Escape') {
550			closePreferencesModal();
551		}
552	});
553
554	// -----------------------------------------------------------------------
555	// Helpers
556	// -----------------------------------------------------------------------
557
558	function dispatchSpecificEvent(eventName, payload) {
559		var event = new CustomEvent(eventName, { detail: payload });
560		document.dispatchEvent(event);
561	}
562
563	// Script release logic
564	function releaseScripts() {
565		if (!cnArgs.consent_payload) {
566			return;
567		}
568
569		var scripts = document.querySelectorAll(
570			'script[type="text/plain"][data-cookie-category]:not([data-gdpr-executed="true"])'
571		);
572
573		scripts.forEach(function(script) {
574			var category = script.getAttribute('data-cookie-category');
575
576			if (cnArgs.consent_payload[category] === true || category === 'essential') {
577				var newScript = document.createElement('script');
578				newScript.type = 'text/javascript';
579
580				var src = script.getAttribute('src');
581				if (src) {
582					newScript.src = src;
583				}
584
585				Array.from(script.attributes).forEach(function(attr) {
586					var name = attr.name;
587					if (name !== 'type' && name !== 'data-cookie-category' && name !== 'src') {
588						newScript.setAttribute(name, attr.value);
589					}
590				});
591
592				if (script.innerHTML) {
593					newScript.innerHTML = script.innerHTML;
594				}
595
596				newScript.setAttribute('data-gdpr-executed', 'true');
597
598				if (script.parentNode) {
599					script.parentNode.replaceChild(newScript, script);
600				}
601			}
602		});
603
604		dispatchSpecificEvent('gdpr_consent_updated', cnArgs.consent_payload);
605	}
606});

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.