PageSourceSearch

https://theicg.co.uk/wp-content/plugins/complianz-gdpr-premium/cookiebanner/js/complianz.js?ver=1707460665

js theicg.co.uk collected 2026-10-04 03:32:58 UTC 74,255 bytes, 2,313 lines download raw bytes

1'use strict';
2/*
3 * Opt in (e.g. EU):
4 * default all scripts disabled.
5 * cookie banner
6 *
7 * Opt out (e.g. US):
8 * default all scripts enabled
9 * opt out cookie banner
10 *
11 * Other regions:
12 * default all scripts enabled
13 * no banner
14 *
15 *
16 * For examples to edit the behaviour of the banner, please see https://github.com/really-Simple-Plugins/complianz-integrations
17 * */
18
19/*
20 * Create an element
21 * @param el
22 * @param content
23 * @returns {*}
24 */
25function cmplz_create_element(el, content) {
26	let obj = document.createElement(el);
27	obj.innerHtml = content;
28	return obj;
29}
30
31/*
32 * Add an event
33 * @param event
34 * @param selector
35 * @param callback
36 * @param context
37 */
38function cmplz_add_event(event, selector, callback ) {
39	document.addEventListener(event, e => {
40		if ( e.target.closest(selector) ) {
41			callback(e);
42		}
43	});
44}
45
46/*
47 * Check if the element is hidden
48 * @param el
49 * @returns {boolean}
50 */
51function cmplz_is_hidden(el) {
52	return (el.offsetParent === null)
53}
54
55function cmplz_html_decode(input) {
56	let doc = new DOMParser().parseFromString(input, "text/html");
57	return doc.documentElement.textContent;
58}
59/**
60 * Consent Area management for shortcode and block editor
61 */
62document.querySelectorAll('.cmplz-consent-area.cmplz-placeholder').forEach(cmplzConsentArea => {
63	cmplzConsentArea.addEventListener('click', e => {
64		let container = e.target;
65		if ( !container.classList.contains('cmplz-consent-area') ) {
66			container = e.target.closest('.cmplz-consent-area.cmplz-placeholder');
67		}
68		if (container) {
69			let consentedService = container.getAttribute('data-service');
70			cmplz_set_service_consent(consentedService, true);
71			cmplzLoadConsentAreaContent(false, consentedService);
72			cmplz_enable_category(null, consentedService);
73			cmplz_set_banner_status('dismissed');
74		}
75
76	});
77
78	document.addEventListener("cmplz_enable_category", function(consentData) {
79		let consentedCategory = consentData.detail.category;
80		let consentedService = consentData.detail.service;
81		cmplzLoadConsentAreaContent(consentedCategory, consentedService)
82	});
83});
84
85function cmplzLoadConsentAreaContent(consentedCategory, consentedService){
86	document.querySelectorAll('.cmplz-consent-area.cmplz-placeholder').forEach(obj => {
87		let category = obj.getAttribute('data-category');
88		let service = obj.getAttribute('data-service');
89		let postId = obj.getAttribute('data-post_id');
90		let blockId = obj.getAttribute('data-block_id');
91		if ( consentedCategory === category || consentedService === service ) {
92			//if not stored yet, load. As features in the user object can be changed on updates, we also check for the version
93			let request = new XMLHttpRequest();
94			request.open('GET', complianz.url+'consent-area/'+postId+'/'+blockId, true);
95			request.setRequestHeader('Content-type', 'application/json');
96			request.send();
97			obj.classList.remove('cmplz-placeholder');
98			request.onload = function() {
99				obj.innerHTML = JSON.parse(request.response);
100				//search for script elements and execute them
101				obj.querySelectorAll('script').forEach(scriptEl => {
102					cmplz_run_script(scriptEl.innerHTML, category, service, 'inline', scriptEl);
103				})
104			};
105		}
106	});
107}
108
109/*
110 * If an anchor is passed for an element which may load only after an ajax call, make sure it will scroll into view.
111 */
112document.addEventListener('cmplz_manage_consent_container_loaded', function(e){
113	let url = window.location.href;
114	if ( url.indexOf('#') != -1 ) {
115		let end_pos = url.lastIndexOf("?") != -1 ? url.lastIndexOf("?") : undefined;
116		let anchor = url.substring(url.indexOf("#") + 1, end_pos);
117		const element = document.getElementById(anchor);
118		if (element) {
119			const y = element.getBoundingClientRect().top + window.pageYOffset - 200;
120			window.scrollTo({top: y, behavior: 'smooth'});
121		}
122	}
123});
124
125/*
126 * prevent caching of the WP Rest API by varnish or other caching tools
127 */
128complianz.locale = complianz.locale + '&token='+Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
129
130/*
131 * CustomEvent() polyfill
132 * https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
133 */
134(function () {
135	if (typeof window.CustomEvent === 'function') return false;
136	function CustomEvent(event, params) {
137		params = params || { bubbles: false, cancelable: false, detail: undefined };
138		let evt = document.createEvent('CustomEvent');
139		evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
140		return evt;
141	}
142	CustomEvent.prototype = window.Event.prototype;
143	window.CustomEvent = CustomEvent;
144})();
145
146var cmplz_banner;//look this one up when the cookiebanner loads.
147var cmplz_banner_container = document.getElementById('cmplz-cookiebanner-container');
148var cmplz_manage_consent_button;
149var cmplz_waiting_inline_scripts = [];
150var cmplz_waiting_scripts = [];
151var cmplz_fired_scripts = [];
152var cmplz_placeholder_class_index = 0;
153var cmplz_all_scripts_hook_fired = false;
154var cmplz_consent_stored_once = false;
155var cmplz_fired_category_events = ['functional'];
156var cmplz_fired_service_events = [];
157var cmplz_categories = [
158	'functional',
159	'preferences',
160	'statistics',
161	'marketing',
162];
163
164/*
165 * Get a cookie by name
166 * @param name
167 * @returns {string}
168 */
169
170window.cmplz_get_cookie = function (name) {
171	if (typeof document === "undefined") {
172		return "";
173	}
174	name = complianz.prefix + name;
175	const cookies = document.cookie.split(';');
176	for ( let i = 0; i < cookies.length; i++ ) {
177		const cookie = cookies[i].trim();
178		if ( cookie.startsWith(name + '=') ) {
179			return cookie.substring(name.length + 1);
180		}
181	}
182	return "";
183};
184
185/*
186 * set a cookie
187 * @param name
188 * @param value
189 * @param use_prefix
190 */
191
192window.cmplz_set_cookie = function(name, value, use_prefix) {
193	if (typeof document === 'undefined') {
194		return;
195	}
196
197	use_prefix = typeof use_prefix !== 'undefined' ? use_prefix : true;
198	const secure = window.location.protocol === "https:" ? ";secure" : '';
199	const date = new Date();
200	date.setTime(date.getTime() + (complianz.cookie_expiry * 24 * 60 * 60 * 1000));
201	const expires = ";expires=" + date.toGMTString();
202
203	const domain = cmplz_get_cookie_domain();
204	const domainString = domain.length > 0 ? `;domain=${domain}` : '';
205
206	const prefix = use_prefix ? complianz.prefix : '';
207	const cookiePath = cmplz_get_cookie_path();
208
209	document.cookie = `${prefix}${name}=${value};SameSite=Lax${secure}${expires}${domainString};path=${cookiePath}`;
210}
211
212/*
213 * Check if needle occurs in the haystack
214 * @param needle
215 * @param haystack
216 * @returns {boolean}
217 */
218window.cmplz_in_array = function(needle, haystack) {
219	return haystack.includes(needle);
220}
221
222/*
223 * Retrieve the highest level of consent that has been given
224 *
225 * */
226
227window.cmplz_highest_accepted_category = function() {
228	const consentedCategories = cmplz_accepted_categories();
229	const priorityCategories = ['marketing', 'statistics', 'preferences'];
230
231	for (let i = 0; i < priorityCategories.length; i++) {
232		if (cmplz_in_array(priorityCategories[i], consentedCategories)) {
233			return priorityCategories[i];
234		}
235	}
236	return 'functional';
237}
238
239/*
240 * Sets all accepted categories as class in body
241 */
242
243const cmplz_set_category_as_body_class = () => {
244	const classList = document.body.classList;
245	for (let i = classList.length - 1; i >= 0; i--) {
246		if (classList[i].startsWith('cmplz-') && classList[i] !== 'cmplz-document') {
247			classList.remove(classList[i]);
248		}
249	}
250	const cats = cmplz_accepted_categories();
251	Object.values(cats).forEach(category => {
252		classList.add('cmplz-' + category);
253	});
254	const services = cmplz_get_all_service_consents();
255	Object.entries(services).forEach(([service, consent]) => {
256		if (consent) {
257			classList.add('cmplz-' + service);
258		}
259	});
260
261	classList.add('cmplz-' + complianz.region, 'cmplz-' + complianz.consenttype);
262	const event = new CustomEvent('cmplz_set_category_as_bodyclass');
263	document.dispatchEvent(event);
264}
265
266const cmplz_append_css = (css) => {
267	const head = document.head || document.getElementsByTagName('head')[0];
268	const style = document.createElement('style');
269	style.setAttribute('type', 'text/css');
270	style.appendChild(document.createTextNode(css));
271	head.appendChild(style);
272}
273
274const cmplz_load_css = (path) => {
275	const head = document.head || document.getElementsByTagName("head")[0];
276	const targetObj = document.createElement("link");
277	targetObj.rel = "stylesheet";
278	targetObj.type = "text/css";
279	targetObj.href = path;
280	head.appendChild(targetObj);
281}
282
283/*
284 * Run script, src or inline
285 * @param script //src or inline script
286 * @param category
287 * @param type
288 */
289
290function cmplz_run_script( script, category, service, type, sourceObj ) {
291	let targetObj = document.createElement("script");
292	if ( type !== 'inline' ) {
293		targetObj.src = script;
294	} else {
295		if (typeof script !== 'string') {
296			script = script.innerHTML;
297		}
298		targetObj.innerHTML = [script, 'cmplzScriptLoaded();'].join('\n');
299	}
300
301	//check if already fired
302	if ( cmplz_in_array( script, cmplz_fired_scripts) ) {
303		return;
304	}
305
306	cmplzCopyAttributes(sourceObj, targetObj);
307	try {
308		if (type!=='inline') {
309			targetObj.onload = function () {
310				cmplz_run_after_all_scripts(category, service);
311				cmplz_maybe_run_waiting_scripts(script, category, service, sourceObj);
312			}
313		} else {
314			window.cmplzScriptLoaded = function() {
315				cmplz_run_after_all_scripts(category, service);
316				cmplz_maybe_run_waiting_scripts(script, category, service, sourceObj);
317			}
318		}
319		document.head.appendChild(targetObj);
320
321	} catch(exception) {
322		//only runs in case of error
323		cmplz_run_after_all_scripts(category, service);
324		throw "Something went wrong " + exception + " while loading "+script;
325	}
326}
327
328/*
329 * Check if there are waiting scripts, and if so, run them.
330 * @param script //src or inline script
331 * @param category
332 */
333
334function cmplz_maybe_run_waiting_scripts( script, category, service, sourceObj ){
335	let waitingScript = cmplz_get_waiting_script(cmplz_waiting_scripts, script);
336	if ( waitingScript ) {
337		cmplz_run_script( waitingScript, category, service, 'src', sourceObj );
338	}
339
340	let waiting_inline_script = cmplz_get_waiting_script(cmplz_waiting_inline_scripts, script);
341	if (waiting_inline_script) {
342		cmplz_run_script(waiting_inline_script, category, service, 'inline', sourceObj);
343	}
344}
345
346const cmplzLazyLoader = () => {
347	// Get all elements with the "lazy-load" class
348	const cmplzLazyLoadElements = document.querySelectorAll('.cmplz-blocked-content-container');
349
350	// Create an Intersection Observer instance
351	const cmplzObserver = new IntersectionObserver((entries, observer) => {
352		entries.forEach((entry) => {
353			if (entry.isIntersecting) {
354				// When the element is in view, load the background image
355				const element = entry.target;
356				let src = element.getAttribute('data-placeholder-image');
357				if ( src ) {
358					const index = element.getAttribute('data-placeholder_class_index');
359					cmplz_append_css('.cmplz-placeholder-' + index + ' {background-image: url(' + src + ') !important;}');
360					cmplz_set_blocked_content_container_aspect_ratio(element, src, index);
361				}
362
363				// Stop observing the element
364				observer.unobserve(element);
365			}
366
367		});
368	});
369
370	// Start observing each lazy-load element
371	cmplzLazyLoadElements.forEach((element) => {
372		cmplzObserver.observe(element);
373	});
374}
375
376/*
377 * Set placeholder image as background on the parent div, set notice, and handle height.
378 *
379 * */
380
381function cmplz_set_blocked_content_container() {
382	//to prevent this function to twice run on an element, we add an attribute to each element that has been processed.
383	//then skip elements with that element.
384	document.querySelectorAll('.cmplz-image').forEach(obj => {
385		if ( obj.classList.contains('cmplz-processed') ) {
386			return;
387		}
388		obj.classList.add('cmplz-processed' );
389		let service = obj.getAttribute('data-service');
390		let category = obj.getAttribute('data-category');
391		let blocked_image_container = obj.parentElement;
392		blocked_image_container.classList.add('cmplz-blocked-content-container');
393		let curIndex = blocked_image_container.getAttribute('data-placeholder_class_index');
394		//handle browser native lazy load feature
395		if (obj.getAttribute('loading') === 'lazy' ) {
396			obj.removeAttribute('loading');
397			obj.setAttribute('data-deferlazy', 1);
398		}
399
400		if ( curIndex == null ) {
401			cmplz_placeholder_class_index++;
402			blocked_image_container.classList.add('cmplz-placeholder-' + cmplz_placeholder_class_index, 'cmplz-blocked-content-container');
403			blocked_image_container.setAttribute('data-placeholder_class_index', cmplz_placeholder_class_index);
404			cmplz_insert_placeholder_text(blocked_image_container, category, service);
405		}
406	});
407
408	document.querySelectorAll('.cmplz-placeholder-element').forEach(obj => {
409		if ( obj.classList.contains('cmplz-processed') ) {
410			return;
411		}
412		obj.classList.add('cmplz-processed' );
413		let service = obj.getAttribute('data-service');
414		let category = obj.getAttribute('data-category');
415
416		//we set this element as container with placeholder image
417		let blocked_content_container;
418		if ( obj.classList.contains('cmplz-iframe')) {
419			//handle browser native lazy load feature
420			if ( obj.getAttribute('loading') === 'lazy' ) {
421				obj.removeAttribute('loading');
422				obj.setAttribute('data-deferlazy', 1);
423			}
424			blocked_content_container = obj.parentElement;
425		} else {
426			blocked_content_container = obj;
427		}
428		let curIndex = blocked_content_container.getAttribute('data-placeholder_class_index');
429		//if the blocked content container class is already added, don't add it again
430		if ( curIndex === null ) {
431			cmplz_placeholder_class_index++;
432			blocked_content_container.classList.add('cmplz-placeholder-' + cmplz_placeholder_class_index, 'cmplz-blocked-content-container');
433			blocked_content_container.setAttribute('data-placeholder_class_index', cmplz_placeholder_class_index);
434			cmplz_insert_placeholder_text(blocked_content_container, category, service);
435			//handle image size for video
436			let src = obj.getAttribute('data-placeholder-image');
437			if (src && typeof src !== 'undefined' && src.length ) {
438				//move src to parent, if needed.
439				blocked_content_container.setAttribute('data-placeholder-image', src);
440			}
441		}
442	});
443
444	cmplzLazyLoader();
445
446	/*
447	 * In some cases, like ajax loaded content, the placeholders are initialized again. In that case, the scripts may need to be fired again as well.
448	 * In case of an opt-out region and Do Not Track, a consent check will return 'allow', because it doesn't take DNT into account
449	 */
450
451	if ( cmplz_has_consent('statistics') ) {
452		cmplz_enable_category('statistics');
453	}
454
455	if ( cmplz_has_consent('marketing') ) {
456		cmplz_enable_category('marketing');
457	}
458}
459
460function cmplz_insert_placeholder_text(container, category, service ){
461	if ( !container.querySelector( ".cmplz-blocked-content-notice" ) ) {
462		let placeholder_text = complianz.placeholdertext;
463		category = category || 'marketing';
464		let body;
465		if ( typeof placeholder_text !== 'undefined' ) {
466			if ( complianz.clean_cookies == 1 ) {
467				//make service human readable
468				let service_nicename = service ? service.replace('-', ' ') : '';
469				service_nicename = service_nicename.charAt(0).toUpperCase() + service_nicename.slice(1);
470				placeholder_text = placeholder_text.replace('{service}', service_nicename);
471				body = cmplz_create_element('div', placeholder_text);
472				body.innerHTML = placeholder_text;
473				body.classList.add('cmplz-blocked-content-notice');
474				let btn = body.querySelector('button');
475				btn.setAttribute('data-service', service);
476				btn.setAttribute('data-category', category);
477				btn.setAttribute( 'aria-label', complianz.aria_label.replace('{service}', service_nicename) );
478				let pageLinks = complianz.page_links[complianz.region];
479				let link = body.querySelector('.cmplz-links a');
480				if ( pageLinks && pageLinks.hasOwnProperty('cookie-statement') ) {
481					link.setAttribute('href', pageLinks['cookie-statement']['url']);
482					if (link.innerText === '{title}') {
483						link.innerText = pageLinks['cookie-statement']['title'];
484					}
485				}
486			} else {
487				let btn = cmplz_create_element('button', '');
488				let category_nicename = complianz.categories.hasOwnProperty(category) ? complianz.categories[category] : 'marketing';
489				btn.innerText = placeholder_text.replace('{category}', category_nicename);
490				btn.classList.add('cmplz-blocked-content-notice', 'cmplz-accept-category', 'cmplz-accept-'+category); //'cmplz-accept-'+category is deprecated
491
492				btn.setAttribute('data-service', service );
493				btn.setAttribute('data-category', category );
494				btn.setAttribute( 'aria-label', complianz.aria_label.replace('{category}', category) );
495				body=btn;
496			}
497
498			if ( container.tagName!=='VIDEO' ) {
499				container.appendChild(body);
500			} else{
501				container.parentElement.appendChild(body);
502			}
503
504		}
505	}
506}
507
508/*
509 * Set the height of an image relative to the width, depending on the image widht/height aspect ratio.
510 *
511 *
512 * */
513
514function cmplz_set_blocked_content_container_aspect_ratio(container, src, placeholder_class_index) {
515	if (container == null) return;
516
517	// Handle image size for video
518	let img = new Image();
519	img.addEventListener("load", function() {
520		let imgWidth = this.naturalWidth || 1;
521		let imgHeight = this.naturalHeight;
522
523		let w = container.clientWidth;
524		let h = imgHeight * (w / imgWidth);
525
526		let heightCSS = src.indexOf('placeholder.jpg') === -1 ? 'height:' + h + 'px;' : '';
527		cmplz_append_css('.cmplz-placeholder-' + placeholder_class_index + ' {' + heightCSS + '}');
528	});
529	img.src = src;
530}
531
532/*
533 * Keep window aspect ratio in sync when window resizes
534 * To lower the number of times this code is executed, it is done with a timeout.
535 *
536 * */
537
538var cmplzResizeTimer;
539window.addEventListener('resize', function(event) {
540	clearTimeout(cmplzResizeTimer);
541	cmplzResizeTimer = setTimeout( cmplz_set_blocked_content_container, 500);
542}, true);
543
544/*
545 * 	we run this function also on an interval, because with ajax loaded content, the placeholders would otherwise not be handled.
546 */
547if ( complianz.block_ajax_content == 1 ) {
548	setInterval(function () {
549		cmplz_set_blocked_content_container();
550	}, 2000);
551}
552
553/*
554 * Check if there are any blocked scripts on the page
555 * @returns {boolean}
556 */
557function cmplz_has_blocked_scripts(){
558	let scriptElements = document.querySelectorAll('script[data-category], script[data-service]');
559	return scriptElements.length>0;
560}
561/*
562 * Enable scripts that were blocked
563 *
564 * */
565
566function cmplz_enable_category(category, service) {
567	if ( complianz.tm_categories == 1 && category !== '') {
568		cmplz_run_tm_event(category);
569	}
570
571	let details = {};
572	details.category = category;
573	details.categories = cmplz_accepted_categories();
574	details.region = complianz.region;
575	let event = new CustomEvent('cmplz_before_category', { detail: details });
576	document.dispatchEvent(event);
577
578	service = typeof service !== 'undefined' ? service : 'do_not_match';
579	if ( category === '' ) category = 'do_not_match';
580
581	if ( category === 'functional' ) {
582		return;
583	}
584	//enable cookies for integrations
585	if ( category === 'marketing' ) {
586		cmplz_set_integrations_cookies();
587	}
588
589	//remove accept cookie notice overlay
590	let selector;
591	if (service !== 'do_not_match') {
592		selector = '.cmplz-blocked-content-notice [data-service="'+service+'"]';
593	} else {
594		selector = complianz.clean_cookies!=1 ? '.cmplz-blocked-content-notice.cmplz-accept-'+category : '.cmplz-blocked-content-notice [data-category="'+category+'"]';
595	}
596	document.querySelectorAll(selector).forEach(obj => {
597		let blockedElementService = obj.getAttribute('data-service');
598		if (obj.parentNode.classList.contains('cmplz-blocked-content-notice')) {
599			obj = obj.parentNode;
600		}
601		//only remove if the service is not explicitly denied
602		if ( !cmplz_is_service_denied(blockedElementService) ) {
603			obj.parentNode.removeChild(obj);
604		}
605	});
606
607	document.querySelectorAll('[data-category="'+category+'"], [data-service="'+service+'"]').forEach(obj => {
608		//if a category is activated, but this specific service is denied, skip.
609		let elementService = obj.getAttribute('data-service');
610		if ( cmplz_is_service_denied(elementService) ) {
611			return;
612		}
613
614		//if native class is included, it isn't blocked, so will have run already
615		if ( obj.getAttribute('data-category') === 'functional' ) {
616			return;
617		}
618
619		if ( obj.classList.contains('cmplz-activated') ) {
620			return;
621		}
622
623		let tagName = obj.tagName;
624		if (tagName==='LINK'){
625			obj.classList.add('cmplz-activated' );
626			let src = obj.getAttribute('data-href');
627			cmplz_load_css( src, category);
628		} else if (tagName ==='IMG'){
629			obj.classList.add('cmplz-activated' );
630			let src = obj.getAttribute('data-src-cmplz');
631			obj.setAttribute('src', src);
632			//handle browser native lazy load feature
633			if ( obj.getAttribute('data-deferlazy') ) {
634				obj.setAttribute('loading', 'lazy');
635			}
636			cmplz_remove_placeholder(obj);
637		}
638		else if (tagName==='IFRAME'){
639			obj.classList.add('cmplz-activated' );
640			let src = obj.getAttribute('data-src-cmplz');
641			let srcAttribute = obj.getAttribute('data-cmplz-target') ? obj.getAttribute('data-cmplz-target') : 'src';
642
643			//check if there's an autoplay value we need to pass on, if it's added later on by javascript
644			let autoplay = cmplz_get_url_parameter(obj.getAttribute(srcAttribute), 'autoplay');
645			if ( autoplay === '1' ) src = src + '&autoplay=1';
646			//handle browser native lazy load feature
647			if ( obj.getAttribute('data-deferlazy') ) {
648				obj.setAttribute('loading', 'lazy');
649			}
650
651			obj.addEventListener('load', () => {
652				cmplz_remove_placeholder(obj);
653			});
654			obj.setAttribute(srcAttribute, src);
655		} else if (obj.classList.contains('cmplz-placeholder-element')) {
656			obj.classList.add('cmplz-activated' );
657			//other services, no iframe, with placeholders
658			//remove the added classes
659			let cssIndex = obj.getAttribute('data-placeholder_class_index');
660			obj.classList.remove('cmplz-blocked-content-container', 'cmplz-placeholder-' + cssIndex);
661		}
662	});
663
664	/*
665	 * Let's activate the scripts
666	 */
667
668	//create list of waiting scripts
669	let scriptElements = document.querySelectorAll('script[data-category="'+category+'"], script[data-service="'+service+'"]');
670	scriptElements.forEach(obj => {
671		let waitfor = obj.getAttribute('data-waitfor');
672		let src = obj.getAttribute('data-cmplz-src');
673		if ( waitfor ) {
674			if ( src ) {
675				cmplz_waiting_scripts[waitfor] = src;
676			} else if ( obj.innerText.length > 0 ) {
677				cmplz_waiting_inline_scripts[waitfor] = obj;
678			}
679		}
680
681		//cleanup after adding it to our waiting or scriptElements list.
682		if (obj.parentElement) {
683			obj.parentElement.removeChild(obj);
684		}
685	});
686
687	//scripts: remove text/plain, and move data-src attribute to src attribute
688	scriptElements.forEach(obj => {
689		//we don't want already activate scripts to fire, but also we don't want scripts that weren't blocked to fire. Hence the check for type
690		let script_mime_type = obj.getAttribute('type');
691		if ( obj.classList.contains('cmplz-activated') || ( !script_mime_type || script_mime_type==='text/javascript' ) ) {
692			return;
693		}
694		obj.classList.add('cmplz-activated' );
695		let src = obj.getAttribute('data-cmplz-src');
696		if ( src ) {
697			obj.removeAttribute('type');
698			//check if this src or txt is in a waiting script. If so, skip.
699			if ( cmplz_is_waiting_script(cmplz_waiting_scripts, src) ) {
700				return;
701			}
702
703			if ( obj.getAttribute('data-post_scribe_id') ) {
704				let psID = '#' + obj.getAttribute('data-post_scribe_id');
705				let postScribeObj = document.querySelector(psID);
706				if ( postScribeObj ) {
707					postScribeObj.innerHtml('');
708					postscribe(psID, '<script src=' + src + '></script>');
709				}
710			} else {
711				cmplz_run_script(src, category, service, 'src', obj );
712			}
713
714		} else if (obj.innerText.length > 0 ) {
715			//check if this src or txt is in a waiting script. If so, skip.
716			if (cmplz_is_waiting_script(cmplz_waiting_inline_scripts, obj.innerText )) {
717				return;
718			}
719
720			cmplz_run_script( obj.innerText, category, service, 'inline', obj );
721		}
722	});
723
724	// if there are no blockable scripts at all, we still want to provide a hook
725	// in most cases, there are blocked scripts, and run_after_all_scripts hook won't be fired yet. In that
726	// case only the category event is fired (if activated), and this function will run
727	// again from the script activation callbacks.
728	cmplz_run_after_all_scripts(category, service);
729}
730
731/*
732 * remove added classes from the blocked content container
733 *
734 * @param obj
735 */
736function cmplz_remove_placeholder(obj) {
737	let blocked_content_container = obj.closest('.cmplz-blocked-content-container');
738	if (blocked_content_container) {
739		let cssIndex = blocked_content_container.getAttribute('data-placeholder_class_index');
740		blocked_content_container.classList.remove('cmplz-blocked-content-container', 'cmplz-placeholder-' + cssIndex);
741	}
742	obj.classList.remove('cmplz-iframe-styles', 'cmplz-iframe', 'video-wrap');
743}
744
745/*
746 * check if the passed source has a waiting script that should be executed, and return it if so.
747 * @param waiting_scripts
748 * @param src
749 * @returns {*}
750 */
751
752function cmplz_get_waiting_script( waiting_scripts, src ) {
753	for ( let waitfor in waiting_scripts ) {
754		if ( waiting_scripts.hasOwnProperty(waitfor)) {
755			if ( src.indexOf(waitfor) !== -1 ) {
756				let output = waiting_scripts[waitfor];
757				delete waiting_scripts[waitfor];
758				return output;
759			}
760		}
761	}
762	return false;
763}
764
765/*
766 * Because we need a key=>value array in javascript, the .length check for an empty array doesn't work.
767 * @param arr
768 * @returns {boolean}
769 */
770
771function cmplz_array_is_empty(arr) {
772	for (let key in arr) {
773		if (arr.hasOwnProperty(key)) {
774			return false;
775		}
776	}
777	return true;
778}
779
780/*
781 * Check if the passed src or script is waiting for another script and should not execute
782 * @param waiting_scripts
783 * @param srcOrScript
784 */
785
786function cmplz_is_waiting_script(waiting_scripts, srcOrScript) {
787	for (let waitfor in waiting_scripts) {
788		if ( waiting_scripts.hasOwnProperty(waitfor) ) {
789			let waitingScript = waiting_scripts[waitfor];
790			if (typeof waitingScript !== 'string') waitingScript = waitingScript.innerText;
791
792			if (srcOrScript.indexOf(waitingScript) !== -1 || waitingScript.indexOf(srcOrScript) !== -1) {
793				return true;
794			}
795		}
796	}
797	return false;
798}
799
800/*
801 * if all scripts have been executed, fire a hook.
802 */
803
804function cmplz_run_after_all_scripts(category, service) {
805	//fire an event so custom scripts can hook into this.
806	let enableService = service!=='do_not_match' && !cmplz_in_array(service, cmplz_fired_service_events );
807	let enableCategory = category!=='do_not_match' && !cmplz_in_array( category, cmplz_fired_category_events );
808	if ( enableCategory ||  enableService ) {
809		if (enableCategory) {
810			cmplz_fired_category_events.push(category);
811		}
812		if (enableService) {
813			cmplz_fired_service_events.push(service);
814		}
815		let details = {};
816		details.category = category;
817		details.service = service;
818		details.categories = cmplz_accepted_categories();
819		details.services = cmplz_get_all_service_consents();
820		details.region = complianz.region;
821
822		let event = new CustomEvent('cmplz_enable_category', { detail: details });
823		document.dispatchEvent(event);
824	}
825
826	if ( !cmplz_all_scripts_hook_fired && cmplz_array_is_empty(cmplz_waiting_inline_scripts) && cmplz_array_is_empty(cmplz_waiting_scripts) ) {
827		let event = new CustomEvent('cmplz_run_after_all_scripts', { detail: category, service:service});
828		document.dispatchEvent(event);
829		cmplz_all_scripts_hook_fired = true;
830	}
831}
832
833/*
834 * Fire an event in Tag Manager
835 *
836 *
837 * */
838
839var cmplz_fired_events = [];
840function cmplz_run_tm_event(category) {
841	if (cmplz_fired_events.indexOf(category) === -1) {
842		cmplz_fired_events.push(category);
843		window.dataLayer = window.dataLayer || [];
844		window.dataLayer.push({
845			'event': 'cmplz_event_'+category
846		});
847		let event = new CustomEvent('cmplz_tag_manager_event', { detail: category });
848		document.dispatchEvent(event);
849	}
850}
851
852/*
853 * Accept all categories
854 */
855window.cmplz_accept_all = function(){
856	cmplz_clear_all_service_consents();
857	cmplz_fire_before_categories_consent(cmplz_categories);
858
859	for (let key in cmplz_categories) {
860		if ( cmplz_categories.hasOwnProperty(key) ) {
861			cmplz_set_consent(cmplz_categories[key], 'allow');
862		}
863	}
864	cmplz_sync_category_checkboxes();
865}
866
867function cmplz_fire_before_categories_consent(categories){
868	let details = {};
869	details.categories = categories;
870	details.region = complianz.region;
871	let event = new CustomEvent('cmplz_before_categories_consent', { detail: details });
872	document.dispatchEvent(event);
873}
874
875window.conditionally_show_banner = function() {
876	//merge userdata with complianz data, in case a b testing is used with user specific cookie banner data
877	//objects are merged so user_data will override data in complianz object
878	complianz = cmplz_merge_object( complianz, cmplz_user_data );
879	//check if we need to redirect to another legal document, for a specific region
880	cmplz_maybe_auto_redirect();
881	cmplz_set_blocked_content_container();
882
883	/*
884	 * Integration with WordPress, tell what kind of consent type we're using, then fire an event
885	 */
886
887	window.wp_consent_type = complianz.consenttype;
888	let event = new CustomEvent('wp_consent_type_defined');
889	document.dispatchEvent( event );
890	event = new CustomEvent('cmplz_before_cookiebanner' );
891	document.dispatchEvent(event);
892	if ( complianz.forceEnableStats == 1 && complianz.consenttype === 'optin' ) {
893		cmplz_set_consent('statistics', 'allow');
894	}
895	let rev_cats = cmplz_categories.reverse();
896	let consented_categories = [];
897	for (let key in rev_cats) {
898		if ( rev_cats.hasOwnProperty(key) ) {
899			let category = cmplz_categories[key];
900			if ( cmplz_has_consent(category) ) {
901				consented_categories.push(category);
902			}
903		}
904	}
905	cmplz_fire_before_categories_consent(consented_categories);
906	for (let key in consented_categories) {
907		if ( rev_cats.hasOwnProperty(key) ) {
908			let category = consented_categories[key];
909			cmplz_enable_category(category);
910		}
911	}
912
913	if ( cmplz_exists_service_consent() ) {
914		//if any service is enabled, allow the general services also, because some services are partially 'general'
915		cmplz_enable_category('', 'general');
916		let services = cmplz_get_services_on_page();
917		for (let key in services) {
918			if ( services.hasOwnProperty(key) ) {
919				let service = services[key].service;
920				let category = services[key].category;
921				if ( cmplz_has_service_consent( service, category )) {
922					document.querySelectorAll('.cmplz-accept-service[data-service="' + service + '"]').forEach(obj => {
923						obj.checked = true;
924					});
925					cmplz_enable_category('', service);
926				}
927			}
928		}
929	}
930
931	cmplz_sync_category_checkboxes();
932	cmplz_integrations_init();
933	cmplz_check_cookie_policy_id();
934	cmplz_set_up_auto_dismiss();
935
936	//if we're on the cookie policy page, we dynamically load the applicable revoke checkbox
937	cmplz_load_manage_consent_container();
938
939	event = new CustomEvent('cmplz_cookie_banner_data', { detail: complianz });
940	document.dispatchEvent(event);
941
942	//if no categories were saved before, we do it now
943	if ( cmplz_get_cookie('saved_categories') === '' ) {
944		//for Non optin/optout visitors, and DNT users, we just track the no-warning option
945		if ( complianz.consenttype !== 'optin' && complianz.consenttype !== 'optout' ) {
946			cmplz_track_status( 'no_warning' );
947		} else if ( cmplz_do_not_track() ) {
948			cmplz_track_status('do_not_track' );
949		}
950	}
951
952	cmplz_set_category_as_body_class();
953	//fire cats event, but do not fire a track, as we do this on exit.
954	cmplz_fire_categories_event();
955	if ( !cmplz_do_not_track() ) {
956		if (complianz.consenttype === 'optin') {
957			if (complianz.forceEnableStats) {
958				cmplz_enable_category('statistics');
959			}
960			console.log('opt-in');
961			show_cookie_banner();
962		} else if (complianz.consenttype === 'optout') {
963			console.log('opt-out');
964			show_cookie_banner();
965		} else {
966			console.log('other consent type, no cookie warning');
967			//on other consent types, all scripts are enabled by default.
968			cmplz_accept_all();
969		}
970	} else {
971		console.log('global privacy control or do not track detected: no banner.');
972		cmplz_track_status( 'do_not_track' );
973	}
974}
975
976/**
977 * Check if User has set either GPC or DNT in the browser.
978 * @returns {boolean}
979 */
980function cmplz_do_not_track(){
981	let dnt = 'doNotTrack' in navigator && navigator.doNotTrack === '1';
982	let gpc = 'globalPrivacyControl' in navigator && navigator.globalPrivacyControl;
983	return !!(complianz.do_not_track_enabled && (gpc || dnt));
984}
985
986/*
987 * Get list of services active on the page
988 * @returns {*[]}
989 */
990function cmplz_get_services_on_page(){
991	let services=[];
992	document.querySelectorAll('[data-service]').forEach(obj => {
993		let service = obj.getAttribute('data-service');
994		let category = obj.getAttribute('data-category');
995		if ( services.indexOf(service)==-1 ) {
996			services.push({
997				'category': category,
998				'service':service,
999			});
1000		}
1001	});
1002	return services;
1003}
1004
1005/*
1006 * Run the actual cookie warning
1007 *
1008 * */
1009
1010window.show_cookie_banner = function () {
1011	let disableCookiebanner = complianz.disable_cookiebanner || cmplz_is_speedbot();
1012	//do not show banner when manage consent area on cookie policy is visible
1013	//when users use only the shortcode, the manage consent container is not active, but the dropdown cookie policy class is.
1014	//when the complianz shortcode is used, the dropdown cookie policy class is loaded late because it's loaded with javascript.
1015	let tmpDismissCookiebanner = false;
1016	if ( document.querySelector('#cmplz-manage-consent-container') || document.querySelector('.cmplz-dropdown-cookiepolicy') ) {
1017		tmpDismissCookiebanner = true;
1018	}
1019
1020	const container = document.getElementById('cmplz-cookiebanner-container');
1021	if (container) {
1022		document.body.prepend(container);
1023	}
1024
1025	let link = document.createElement("link");
1026	let pageLinks = complianz.page_links[complianz.region];
1027	//get correct banner, based on banner_id
1028	cmplz_banner = document.querySelector('.cmplz-cookiebanner.banner-'+complianz.user_banner_id+'.'+complianz.consenttype);
1029	if ( !cmplz_banner ) {
1030		disableCookiebanner = true;
1031	}
1032	cmplz_manage_consent_button = document.querySelector('#cmplz-manage-consent .cmplz-manage-consent.manage-consent-'+complianz.user_banner_id);
1033	let css_file_url = complianz.css_file.replace('{type}', complianz.consenttype ).replace('{banner_id}', complianz.user_banner_id);
1034	if ( complianz.css_file.indexOf('cookiebanner/css/defaults/banner') !== -1 ) {
1035		console.log('Fallback default css file used. Please re-save banner settings, or check file writing permissions in uploads directory');
1036	}
1037
1038	link.href = css_file_url;
1039	link.type = "text/css";
1040	link.rel = "stylesheet";
1041	link.onload = function () {
1042		if ( !disableCookiebanner ) {
1043			cmplz_banner.classList.remove('cmplz-hidden');
1044			cmplz_manage_consent_button.classList.remove('cmplz-hidden');
1045		}
1046	}
1047	document.getElementsByTagName("head")[0].appendChild(link);
1048	if ( cmplz_banner && !disableCookiebanner ) {
1049		cmplz_banner.querySelectorAll('.cmplz-links a:not(.cmplz-external), .cmplz-buttons a:not(.cmplz-external)').forEach(obj => {
1050			let docElement = obj;
1051			docElement.classList.add('cmplz-hidden');
1052			for (let pageType in pageLinks ) {
1053				if (pageLinks.hasOwnProperty(pageType) && docElement.classList.contains(pageType)) {
1054					docElement.setAttribute('href', pageLinks[pageType]['url'] + docElement.getAttribute('data-relative_url'));
1055					if ( docElement.innerText === '{title}') {
1056						docElement.innerText = cmplz_html_decode(pageLinks[pageType]['title']);
1057					}
1058					docElement.classList.remove('cmplz-hidden');
1059				}
1060			}
1061		});
1062
1063		cmplz_set_banner_status();
1064		//we don't use the setBannerStatus function here, as we don't want to save it in a cookie now.
1065		if ( tmpDismissCookiebanner ) {
1066			cmplz_banner.classList.remove('cmplz-show');
1067			cmplz_banner.classList.add('cmplz-dismissed');
1068			cmplz_manage_consent_button.classList.remove('cmplz-dismissed');
1069			cmplz_manage_consent_button.classList.add('cmplz-show');
1070		}
1071	}
1072
1073	let event = new CustomEvent('cmplz_cookie_warning_loaded', {detail: complianz.region});
1074	document.dispatchEvent(event);
1075}
1076/*
1077 * Get the status of the banner: dismissed | show
1078 * @returns {string}
1079 */
1080window.cmplz_get_banner_status = function (){
1081	return cmplz_get_cookie('banner-status');
1082}
1083
1084/*
1085 * Set the banner status so it will be either shown or dismissed, and store it in a cookie.
1086 * @param status (optional)
1087 */
1088
1089window.cmplz_set_banner_status = function ( status ){
1090	let prevStatus = cmplz_get_cookie('banner-status');
1091	status = typeof status !== 'undefined' ? status : prevStatus;
1092	if ( status !== prevStatus ) {
1093		cmplz_set_cookie( 'banner-status', status );
1094	}
1095	if (status.length===0){
1096		status = 'show';
1097	}
1098
1099	if (status==='show') {
1100		prevStatus = 'dismissed';
1101	} else {
1102		prevStatus = 'show';
1103	}
1104
1105	if ( cmplz_banner && status.length>0 ) {
1106		cmplz_banner.classList.remove('cmplz-'+prevStatus);
1107		cmplz_banner.classList.add('cmplz-'+status );
1108		if ( cmplz_manage_consent_button ) {
1109			cmplz_manage_consent_button.classList.add('cmplz-'+prevStatus);
1110			cmplz_manage_consent_button.classList.remove('cmplz-'+status);
1111		}
1112	}
1113
1114	if ( cmplz_banner_container && complianz.soft_cookiewall ) {
1115		cmplz_banner_container.classList.remove('cmplz-'+prevStatus);
1116		cmplz_banner_container.classList.add('cmplz-'+status, 'cmplz-soft-cookiewall' );
1117	}
1118	let event = new CustomEvent('cmplz_banner_status', { detail: status });
1119	document.dispatchEvent(event);
1120	cmplz_start_clean();
1121}
1122
1123/*
1124 * Check if current visitor is a bot
1125 *
1126 * @returns {boolean}
1127 */
1128function cmplz_is_bot(){
1129	let botPattern = "(googlebot\/|Googlebot-Mobile|Google-InspectionTool|Googlebot-Image|Google favicon|Mediapartners-Google|bingbot|slurp|java|wget|curl|Commons-HttpClient|Python-urllib|libwww|httpunit|nutch|phpcrawl|msnbot|jyxobot|FAST-WebCrawler|FAST Enterprise Crawler|biglotron|teoma|convera|seekbot|gigablast|exabot|ngbot|ia_archiver|GingerCrawler|webmon |httrack|webcrawler|grub.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|bibnum.bnf|findlink|msrbot|panscient|yacybot|AISearchBot|IOI|ips-agent|tagoobot|MJ12bot|dotbot|woriobot|yanga|buzzbot|mlbot|yandexbot|purebot|Linguee Bot|Voyager|CyberPatrol|voilabot|baiduspider|citeseerxbot|spbot|twengabot|postrank|turnitinbot|scribdbot|page2rss|sitebot|linkdex|Adidxbot|blekkobot|ezooms|dotbot|Mail.RU_Bot|discobot|heritrix|findthatfile|europarchive.org|NerdByNature.Bot|sistrix crawler|ahrefsbot|Aboundex|domaincrawler|wbsearchbot|summify|ccbot|edisterbot|seznambot|ec2linkfinder|gslfbot|aihitbot|intelium_bot|facebookexternalhit|yeti|RetrevoPageAnalyzer|lb-spider|sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web-archive-net.com.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|seokicks-robot|it2media-domain-crawler|ip-web-crawler.com|siteexplorer.info|elisabot|proximic|changedetection|blexbot|arabot|WeSEE:Search|niki-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|Lipperhey SEO Service|CC Metadata Scaper|g00g1e.net|GrapeshotCrawler|urlappendbot|brainobot|fr-crawler|binlar|SimpleCrawler|Livelapbot|Twitterbot|cXensebot|smtbot|bnf.fr_bot|A6-Indexer|ADmantX|Facebot|Twitterbot|OrangeBot|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|SemrushBot|yoozBot|lipperhey|y!j-asr|Domain Re-Animator Bot|AddThis)";
1130	let reBot = new RegExp(botPattern, 'i');
1131	let userAgent = navigator.userAgent;
1132	return reBot.test(userAgent);
1133}
1134/*
1135 * Check if current visitor is a speedbot
1136 *
1137 * @returns {boolean}
1138 */
1139function cmplz_is_speedbot(){
1140	let userAgent = navigator.userAgent;
1141	let speedBotPattern = "(GTmetrix|pingdom|pingbot|Lighthouse)";
1142	let speedBot = new RegExp(speedBotPattern, 'i');
1143	return speedBot.test(userAgent);
1144}
1145
1146/*
1147 * Check if there is consent for a category or service
1148 * @param category
1149 * @returns {boolean}
1150 */
1151
1152window.cmplz_has_consent = function ( category ){
1153	if ( cmplz_is_bot() ) {
1154		return true;
1155	}
1156
1157	if ( category === 'functional' ) {
1158		return true;
1159	}
1160	let has_consent, value;
1161
1162	//if DNT is detected, we should only return the actual cookie value, and not look at the consenttype
1163	if ( cmplz_do_not_track() ){
1164		value = cmplz_get_cookie(category);
1165		has_consent = (value === 'allow');
1166		return has_consent;
1167	}
1168
1169	/*
1170	 * categories
1171	 */
1172	value = cmplz_get_cookie(category);
1173	if ( (complianz.consenttype === 'optout' || complianz.consenttype === 'other') && value === '') {
1174		//if it's opt out and no cookie is set we should return true
1175		has_consent = true;
1176	} else {
1177		//all other situations, return only true if value is allow
1178		has_consent = (value === 'allow');
1179	}
1180
1181	return has_consent;
1182}
1183
1184/*
1185 * Check if a service has consent
1186 * @param service
1187 * @returns {boolean|*}
1188 */
1189window.cmplz_is_service_denied = function ( service ) {
1190	//Check if it's in the consented services cookie
1191	let consented_services_json = cmplz_get_cookie('consented_services');
1192	let consented_services;
1193	try {
1194		consented_services = JSON.parse(consented_services_json);
1195	} catch (e) {
1196		consented_services = {};
1197	}
1198
1199	if ( !consented_services.hasOwnProperty( service ) ){
1200		return false;
1201	} else {
1202		return !consented_services[service];
1203	}
1204}
1205
1206/*
1207 * Check if a service has consent
1208 * @param service
1209 * @param category
1210 * @returns {boolean|*}
1211 */
1212window.cmplz_has_service_consent = function ( service, category ) {
1213	//Check if it's in the consented services cookie
1214	let consented_services_json = cmplz_get_cookie('consented_services');
1215	let consented_services;
1216	try {
1217		consented_services = JSON.parse(consented_services_json);
1218	} catch (e) {
1219		consented_services = {};
1220	}
1221
1222	if ( !consented_services.hasOwnProperty( service ) ){
1223		//default to the category
1224		return cmplz_has_consent( category );
1225	} else {
1226		return consented_services[service];
1227	}
1228}
1229
1230/*
1231 * check if there's at least one service with consent
1232 * @returns {boolean}
1233 */
1234function cmplz_exists_service_consent(){
1235	let consented_services_json = cmplz_get_cookie('consented_services');
1236	let consented_services;
1237	try {
1238		consented_services = JSON.parse(consented_services_json);
1239		for (const key in consented_services) {
1240			if ( consented_services.hasOwnProperty(key) ) {
1241				if (consented_services[key] == true) {
1242					return true;
1243				}
1244			}
1245		}
1246	} catch (e) {
1247		return false;
1248	}
1249	return false;
1250}
1251
1252/*
1253 * Set consent for a service
1254 * @param service
1255 * @param consented
1256 */
1257function cmplz_set_service_consent( service, consented ){
1258	let consented_services_json = cmplz_get_cookie('consented_services');
1259	let consented_services;
1260	try {
1261		consented_services = JSON.parse(consented_services_json);
1262	} catch (e) {
1263		consented_services = {};
1264	}
1265	consented_services[service] = consented;
1266	cmplz_set_cookie('consented_services', JSON.stringify(consented_services) );
1267	let details = {};
1268	details.service = service;
1269	details.value = consented;
1270	details.region = complianz.region;
1271	//when the status is changed, we may need to fire scripts again, so we reset it.
1272	cmplz_all_scripts_hook_fired = false;
1273	let event = new CustomEvent('cmplz_status_change_service', { detail: details });
1274	document.dispatchEvent(event);
1275}
1276
1277/*
1278 * Remove all service consents
1279 */
1280function cmplz_clear_all_service_consents(){
1281	cmplz_set_cookie('consented_services', '');
1282}
1283
1284/*
1285 * Get all consented or denied services
1286 */
1287
1288function cmplz_get_all_service_consents(){
1289	let consented_services_json = cmplz_get_cookie('consented_services');
1290	let consented_services;
1291	try {
1292		consented_services = JSON.parse(consented_services_json);
1293	} catch (e) {
1294		consented_services = {};
1295	}
1296	return consented_services;
1297}
1298/*
1299 * Get cookie path
1300 * @returns {*}
1301 */
1302function cmplz_get_cookie_path(){
1303	return typeof complianz.cookie_path !== 'undefined' && complianz.cookie_path !== '' ? complianz.cookie_path : '/';
1304}
1305
1306/*
1307 * retrieve domain to set the cookies on
1308 * @returns {string}
1309 */
1310function cmplz_get_cookie_domain() {
1311	if (complianz.set_cookies_on_root == 1 && complianz.cookie_domain.length > 3 && !complianz.cookie_domain.includes('localhost')) {
1312		return complianz.cookie_domain;
1313	}
1314	return '';
1315}
1316
1317/*
1318 * Set consent for a category
1319 * @param category
1320 * @param value
1321 */
1322window.cmplz_set_consent = function (category, value){
1323	cmplz_set_accepted_cookie_policy_id();
1324
1325	//functional is always allow
1326	value = category==='functional' ? 'allow' : value;
1327	let previous_value = cmplz_get_cookie(category);
1328
1329	//keep checkboxes in banner and on cookie policy in sync
1330	//do this before the change check to ensure sync: https://github.com/Really-Simple-Plugins/complianz-gdpr/issues/324
1331	let checked = value === 'allow';
1332	document.querySelectorAll('input.cmplz-'+category).forEach(obj => {
1333		obj.checked = checked;
1334	});
1335
1336	//do not trigger a change event if nothing has changed.
1337	if ( previous_value === value ) {
1338		return;
1339	}
1340
1341	cmplz_set_cookie(category, value);
1342	if ( value === 'allow' ) {
1343		cmplz_enable_category(category);
1344	}
1345
1346	cmplz_wp_set_consent(category, value);
1347	if ( category === 'statistics' ) {
1348		cmplz_wp_set_consent('statistics-anonymous', 'allow');
1349	}
1350
1351	let details = new Object();
1352	details.category = category;
1353	details.value = value;
1354	details.region = complianz.region;
1355	details.categories = cmplz_accepted_categories();
1356	//when the status is changed, we may need to fire scripts again, so we reset it.
1357	cmplz_all_scripts_hook_fired = false;
1358	let event = new CustomEvent('cmplz_status_change', { detail: details });
1359	document.dispatchEvent(event);
1360	if ( category === 'marketing' && value === 'deny' && previous_value === 'allow' ) {
1361		cmplz_integrations_revoke();
1362		//give the code some time to finish, so our track status code can send a signal to the backend.
1363		setTimeout(function(){
1364			cmplz_reload_browser_compatible()
1365		}, 500);
1366	}
1367}
1368
1369/*
1370* In some browsers, like firefox, the reload does not force reload, but keeps cached data, causing e.g. Google Maps to load anyway.
1371*/
1372function cmplz_reload_browser_compatible(){
1373	if( navigator.userAgent.toLowerCase().indexOf('firefox') > -1 ){
1374		const url = new URL(window.location.href);
1375		url.searchParams.set('cmplz-force-reload', Date.now().toString());
1376		window.location.href = url.toString();
1377	} else {
1378		window.location.reload();
1379	}
1380}
1381
1382/*
1383 * We use ajax to check the consenttype based on region, otherwise caching could prevent the user specific warning
1384 *
1385 * */
1386
1387var cmplz_user_data = [];
1388//check if it's already stored
1389if (typeof (Storage) !== "undefined" && sessionStorage.cmplz_user_data) {
1390	cmplz_user_data = JSON.parse(sessionStorage.cmplz_user_data);
1391}
1392
1393//if not stored yet, load. As features in the user object can be changed on updates, we also check for the version
1394if ( complianz.geoip == 1 && (cmplz_user_data.length == 0 || (cmplz_user_data.version !== complianz.version) || (cmplz_user_data.banner_version !== complianz.banner_version)) ) {
1395
1396	let request = new XMLHttpRequest();
1397	let cmplzUserRegion = cmplz_get_url_parameter(window.location.href, 'cmplz_user_region');
1398	cmplzUserRegion = cmplzUserRegion ? '&cmplz_user_region=' + cmplzUserRegion : '';
1399	request.open('GET', complianz.url+'banner?'+complianz.locale+cmplzUserRegion, true);
1400	request.setRequestHeader('Content-type', 'application/json');
1401	request.send();
1402	request.onload = function() {
1403		cmplz_user_data = JSON.parse(request.response);
1404		sessionStorage.cmplz_user_data = JSON.stringify(cmplz_user_data);
1405		conditionally_show_banner();
1406	};
1407} else {
1408	conditionally_show_banner();
1409}
1410
1411/*
1412 *  when ab testing, or using records of consent, we want to keep track of the unique user id
1413 */
1414
1415if ( complianz.store_consent == 1 ) {
1416	var cmplz_id_cookie = cmplz_get_cookie('id');
1417	var cmplz_id_session = '';
1418	var cmplz_id = '';
1419	if (typeof (Storage) !== "undefined" && sessionStorage.cmplz_id) {
1420		cmplz_id_session = JSON.parse(sessionStorage.cmplz_id);
1421	}
1422
1423	if ( cmplz_id_cookie.length == 0 && cmplz_id_session.length > 0 ) {
1424		cmplz_id = cmplz_id_session;
1425		cmplz_set_cookie('id', cmplz_id );
1426	}
1427
1428	if ( cmplz_id_cookie.length > 0 && cmplz_id_session.length == 0 ) {
1429		cmplz_id = cmplz_id_cookie;
1430	}
1431
1432	if ( typeof (Storage) !== "undefined" ) {
1433		sessionStorage.cmplz_id = JSON.stringify(cmplz_id);
1434	}
1435}
1436
1437// visibilitychange and pagehide work in more browsers hence we check if they are supported and try to use them
1438document.addEventListener('visibilitychange', function () {
1439	if ( document.visibilityState === 'hidden' ) {
1440		cmplz_track_status_end();
1441	}
1442});
1443window.addEventListener("pagehide", cmplz_track_status_end, false );
1444window.addEventListener("beforeunload", cmplz_track_status_end, false );
1445
1446function cmplz_track_status_end(){
1447	if ( !cmplz_consent_stored_once ) {
1448		cmplz_track_status();
1449	}
1450}
1451
1452/*
1453 * This creates an API which devs can use to trigger actions in complianz.
1454 */
1455document.addEventListener('cmplz_consent_action', function (e) {
1456	cmplz_set_consent( e.detail.category , 'allow' );
1457	cmplz_fire_categories_event();
1458	cmplz_track_status();
1459});
1460
1461/*
1462 * Deny all categories, and reload if needed.
1463 */
1464window.cmplz_deny_all = function(){
1465	for (let key in cmplz_categories) {
1466		if ( cmplz_categories.hasOwnProperty(key) ) {
1467			cmplz_set_consent(cmplz_categories[key], 'deny');
1468		}
1469	}
1470	let consentLevel = cmplz_highest_accepted_category();
1471	let reload = false;
1472
1473	if (consentLevel !== 'functional' || cmplz_exists_service_consent() ) {
1474		reload = true;
1475	}
1476	if ( cmplz_clear_cookies('cmplz_service') ) {
1477		reload = true;
1478	}
1479
1480	//has to be after the check if should be reloaded, otherwise that check won't work.
1481	cmplz_clear_all_service_consents();
1482	cmplz_integrations_revoke();
1483	cmplz_fire_categories_event();
1484	cmplz_track_status();
1485
1486	let event = new CustomEvent('cmplz_revoke', { detail: reload });
1487	document.dispatchEvent(event);
1488
1489	//we need to let the iab extension handle the reload, otherwise the consent revoke might not be ready yet.
1490	if ( !complianz.tcf_active && reload ) {
1491		cmplz_reload_browser_compatible();
1492	}
1493}
1494
1495/*
1496 * For both opt-in and opt-out, clicking cmplz-accept should result in accepting all categories
1497 */
1498cmplz_add_event('click', '.cmplz-accept', function(e){
1499	e.preventDefault();
1500	setTimeout( () => {
1501		cmplz_accept_all();
1502		cmplz_set_banner_status('dismissed');
1503		cmplz_fire_categories_event();
1504		cmplz_track_status();
1505	},0);
1506});
1507
1508/*
1509 *  Accept marketing cookies by clicking any other link cookie acceptance from a custom link
1510 */
1511
1512//cmplz-accept-marketing is deprecated
1513cmplz_add_event('click', '.cmplz-accept-category, .cmplz-accept-marketing', function(e){
1514	e.preventDefault();
1515	let obj = e.target;
1516	let service = obj.getAttribute('data-service');
1517	let category = obj.getAttribute('data-category');
1518	category = category ? category : 'marketing';
1519	if ( complianz.clean_cookies == 1 && typeof service !== 'undefined' && service ){
1520		cmplz_set_service_consent(service, true);
1521		cmplz_enable_category('', 'general');
1522		cmplz_enable_category('', service);
1523	} else {
1524		//we're activating a category, so do not need service activation here.
1525		// cmplz_enable_category('', 'general');
1526		cmplz_set_consent( category, 'allow' );
1527	}
1528	cmplz_set_banner_status('dismissed');
1529	cmplz_fire_categories_event();
1530	cmplz_track_status();
1531});
1532
1533/*
1534 * Accept a specific service
1535 */
1536cmplz_add_event('click', '.cmplz-accept-service', function(e){
1537	let obj = e.target;
1538	//INPUT should be handled by change event, these are checkboxes on the cookie policy
1539	let tagName = obj.tagName;
1540	if ( tagName === 'INPUT' ) {
1541		return;
1542	}
1543	let service = obj.getAttribute('data-service');
1544	if ( typeof service !== 'undefined' ){
1545		cmplz_set_service_consent(service, true);
1546		cmplz_enable_category('', 'general');
1547		cmplz_enable_category('', service);
1548	}
1549	cmplz_fire_categories_event();
1550	cmplz_track_status();
1551});
1552/*
1553 * Accept a specific service
1554 */
1555cmplz_add_event('change', '.cmplz-accept-service', function(e){
1556	let obj = e.target;
1557	let tagName = obj.tagName;
1558	let service = obj.getAttribute('data-service');
1559	if ( typeof service !== 'undefined' ) {
1560		//inputs are from the consent per service option on the cookie policy.
1561		if ( tagName === 'INPUT' ) {
1562			cmplz_set_banner_status('dismissed');
1563			if ( obj.checked ){
1564				cmplz_set_service_consent(service, true);
1565				cmplz_enable_category('', service);
1566			} else {
1567				cmplz_set_service_consent(service, false);
1568				//give our track status time to finish
1569				setTimeout(function(){
1570					cmplz_reload_browser_compatible()
1571				}, 500);
1572			}
1573			//if not input, it's a placeholder
1574		} else {
1575			e.preventDefault();
1576			cmplz_set_service_consent(service, true);
1577			cmplz_enable_category('', 'general');
1578			cmplz_enable_category('', service);
1579
1580			//give our track status time to finish
1581			setTimeout(function(){
1582				cmplz_reload_browser_compatible()
1583			}, 500);
1584		}
1585	}
1586	cmplz_fire_categories_event();
1587	cmplz_track_status();
1588});
1589
1590
1591
1592/*
1593 * On the banner, clicking a category should fire the category only after the save button is clicked.
1594 *
1595 */
1596cmplz_add_event('click', '.cmplz-save-preferences', function(e){
1597	let obj = e.target;
1598	cmplz_banner = obj.closest('.cmplz-cookiebanner');
1599	let consented_categories = [];
1600
1601	for (let key in cmplz_categories) {
1602		if ( cmplz_categories.hasOwnProperty(key) ) {
1603			let category = cmplz_categories[key];
1604			let categoryElement = cmplz_banner.querySelector('input.cmplz-' + category);
1605			if (categoryElement && categoryElement.checked) {
1606				consented_categories.push(category);
1607			}
1608		}
1609	}
1610	cmplz_fire_before_categories_consent(consented_categories);
1611	for (let key in cmplz_categories) {
1612		if ( cmplz_categories.hasOwnProperty(key) ) {
1613			let category = cmplz_categories[key];
1614			if (consented_categories.includes(category)) {
1615				cmplz_set_consent(category, 'allow');
1616			} else {
1617				cmplz_set_consent(category, 'deny');
1618			}
1619		}
1620	}
1621	cmplz_set_banner_status('dismissed');
1622	cmplz_fire_categories_event();
1623	cmplz_track_status();
1624});
1625
1626cmplz_add_event('click', '.cmplz-close', function(e){
1627	cmplz_set_banner_status('dismissed');
1628});
1629
1630cmplz_add_event('click', '.cmplz-view-preferences', function(e){
1631	let obj = e.target;
1632	cmplz_banner = obj.closest('.cmplz-cookiebanner');
1633	if ( cmplz_banner.querySelector('.cmplz-categories').classList.contains('cmplz-fade-in')) {
1634		cmplz_banner.classList.remove('cmplz-categories-visible');
1635		cmplz_banner.querySelector('.cmplz-categories' ).classList.remove('cmplz-fade-in');
1636		cmplz_banner.querySelector('.cmplz-view-preferences' ).style.display = 'block';
1637		cmplz_banner.querySelector('.cmplz-save-preferences' ).style.display = 'none';
1638	} else {
1639		cmplz_banner.classList.add('cmplz-categories-visible');
1640		cmplz_banner.querySelector('.cmplz-categories' ).classList.add('cmplz-fade-in');
1641		cmplz_banner.querySelector('.cmplz-view-preferences' ).style.display = 'none';
1642		cmplz_banner.querySelector('.cmplz-save-preferences' ).style.display = 'block';
1643	}
1644});
1645/*
1646 * On the cookie policy, clicking a category should fire the category immediately
1647 *
1648 */
1649cmplz_add_event('change', '.cmplz-manage-consent-container .cmplz-category', function(e){
1650	for (let key in cmplz_categories) {
1651		if ( cmplz_categories.hasOwnProperty(key) ) {
1652			let category = cmplz_categories[key];
1653			let categoryElement = document.querySelector('.cmplz-manage-consent-container input.cmplz-' + category);
1654			if (categoryElement) {
1655				if (categoryElement.checked) {
1656					cmplz_set_consent(category, 'allow');
1657				} else {
1658					cmplz_set_consent(category, 'deny');
1659				}
1660				cmplz_set_banner_status('dismissed');
1661				cmplz_fire_categories_event();
1662				cmplz_track_status();
1663			}
1664		}
1665	}
1666
1667});
1668
1669cmplz_add_event('click', '.cmplz-deny', function(e){
1670	e.preventDefault();
1671	cmplz_set_banner_status('dismissed');
1672	cmplz_deny_all();
1673
1674});
1675
1676cmplz_add_event('click', 'button.cmplz-manage-settings', function(e){
1677	e.preventDefault();
1678	let catsContainer = document.querySelector('.cmplz-cookiebanner .cmplz-categories');
1679	let saveSettings = document.querySelector('.cmplz-save-settings');
1680	let manageSettings = document.querySelector('button.cmplz-manage-settings');
1681	if ( !cmplz_is_hidden(catsContainer) ){
1682		saveSettings.style.display='none';
1683		manageSettings.style.display = 'block';
1684		catsContainer.style.display='none';
1685	} else {
1686		saveSettings.style.display = 'block';
1687		manageSettings.style.display='none';
1688		catsContainer.style.display = 'block';
1689	}
1690});
1691
1692cmplz_add_event('click', 'button.cmplz-manage-consent', function(e){
1693	e.preventDefault();
1694	cmplz_set_banner_status('show');
1695});
1696
1697/*
1698 * Handle dismiss on scroll and dismiss on timeout
1699 */
1700function cmplz_set_up_auto_dismiss() {
1701	if ( complianz.consenttype === 'optout' ) {
1702		if ( complianz.dismiss_on_scroll==1 ) {
1703			let onWindowScroll = function(evt) {
1704				if (window.pageYOffset > Math.floor(400)) {
1705					cmplz_set_banner_status('dismissed');
1706					cmplz_fire_categories_event();
1707					cmplz_track_status();
1708					window.removeEventListener('scroll', onWindowScroll);
1709					this.onWindowScroll = null;
1710				}
1711			};
1712			window.addEventListener('scroll', onWindowScroll);
1713		}
1714
1715		let delay = parseInt(complianz.dismiss_timeout);
1716		if ( delay > 0 ) {
1717			window.setTimeout(function () {
1718				cmplz_set_banner_status('dismissed');
1719				cmplz_fire_categories_event();
1720				cmplz_track_status();
1721			}, Math.floor(delay));
1722		}
1723	}
1724}
1725
1726/*
1727 * Fire a event wich passes all consented categories
1728 * Separated from the actual category consent because we want to bundle it in one event
1729 */
1730function cmplz_fire_categories_event(){
1731	let details = new Object();
1732	details.category = cmplz_highest_accepted_category();
1733	details.categories = cmplz_accepted_categories();
1734	details.region = complianz.region;
1735	let event = new CustomEvent('cmplz_fire_categories', { detail: details });
1736	document.dispatchEvent(event);
1737}
1738/*
1739 * Track the status of current consent
1740 * @param status
1741 */
1742
1743function cmplz_track_status( status ) {
1744	let cats = [];
1745	status = typeof status !== 'undefined' ? status : false;
1746
1747	let event = new CustomEvent('cmplz_track_status', { detail: status });
1748	document.dispatchEvent(event);
1749
1750	if ( !status ) {
1751		cats = cmplz_accepted_categories();
1752	} else {
1753		cats = [status];
1754	}
1755	cmplz_set_category_as_body_class();
1756	let saved_cats, saved_services;
1757	try {saved_cats = JSON.parse(cmplz_get_cookie('saved_categories'));} catch (e) {saved_cats = {};}
1758	try {saved_services = JSON.parse(cmplz_get_cookie('saved_services'));} catch (e) {saved_services = {};}
1759	let consented_services = cmplz_get_all_service_consents();
1760
1761	//compare current cats with saved cats. When there are no changes, do nothing.
1762	if (cmplz_equals(saved_cats, cats) && cmplz_equals(saved_services, consented_services)) {
1763		return;
1764	}
1765
1766	if ( complianz.store_consent != 1 || cmplz_is_bot() || cmplz_is_speedbot() ) {
1767		return;
1768	}
1769
1770	//keep track of the fact that the status was saved at least once
1771	cmplz_set_cookie('saved_categories', JSON.stringify(cats));
1772	cmplz_set_cookie('saved_services', JSON.stringify(consented_services));
1773	cmplz_consent_stored_once = true;
1774
1775	let data;
1776	let request = new XMLHttpRequest();
1777	request.open('POST', complianz.url+'track', true);
1778	data = {
1779		'consented_categories': cats,
1780		'consented_services':consented_services,
1781		'consenttype': window.wp_consent_type,//store the source consenttype, as our complianz.consenttype will not include optinstats.
1782	};
1783
1784	request.setRequestHeader('Content-type', 'application/json');
1785	request.send(JSON.stringify(data));
1786
1787}
1788
1789/*
1790 * Get accepted categories
1791 *
1792 * @returns {string}
1793 */
1794function cmplz_accepted_categories() {
1795	let consentedCategories = cmplz_categories;
1796	let consentedTemp = [];
1797
1798	//because array filter changes keys, we make a temp arr
1799	for (let key in consentedCategories) {
1800		if ( consentedCategories.hasOwnProperty(key) ) {
1801			let category = consentedCategories[key];
1802			if (cmplz_has_consent(category)) {
1803				consentedTemp.push(category);
1804			}
1805		}
1806	}
1807
1808	consentedCategories = consentedCategories.filter(function(value, index, consentedCategories){
1809		return cmplz_in_array(value, consentedTemp);
1810	});
1811	return consentedCategories;
1812}
1813
1814/*
1815 * Enable the checkbox for each category which was enabled
1816 *
1817 * */
1818
1819function cmplz_sync_category_checkboxes() {
1820	for ( let key in cmplz_categories ) {
1821		if ( cmplz_categories.hasOwnProperty(key) ) {
1822			let category = cmplz_categories[key];
1823			if ( cmplz_has_consent(category) || category === 'functional' ) {
1824				document.querySelectorAll('input.cmplz-' + category).forEach(obj => {
1825					obj.checked = true;
1826				});
1827			} else {
1828				document.querySelectorAll('input.cmplz-' + category).forEach(obj => {
1829					obj.checked = false;
1830				});
1831			}
1832		}
1833
1834		document.querySelectorAll('.cmplz-accept-service').forEach(obj => {
1835			let service = obj.getAttribute('data-service');
1836			let category = obj.getAttribute('data-category');
1837			if ( cmplz_has_service_consent( service, category ) ) {
1838				obj.checked = true;
1839			} else if ( cmplz_is_service_denied( service ) ) {
1840				obj.checked = false;
1841			} else {
1842				//no consent on service level, check if it's category has consent.
1843				let category = obj.getAttribute('data-category' );
1844				obj.checked = !!cmplz_has_consent(category);
1845			}
1846		});
1847	}
1848}
1849
1850/*
1851 * Merge two objects
1852 *
1853 * */
1854
1855function cmplz_merge_object(userdata, ajax_data) {
1856	let output = {};
1857	//first, we fill the important data.
1858	for (let key in ajax_data) {
1859		if (ajax_data.hasOwnProperty(key)) output[key] = ajax_data[key];
1860	}
1861
1862	//conditionally add static data
1863	for (let key in userdata) {
1864		//only add if not in ajax_data
1865		if (!ajax_data.hasOwnProperty(key) || typeof ajax_data[key] === 'undefined') {
1866			if (userdata.hasOwnProperty(key)) output[key] = userdata[key];
1867		}
1868	}
1869
1870	return output;
1871}
1872
1873/*
1874 * If current cookie policy has changed, reset cookie consent
1875 *
1876 * */
1877
1878function cmplz_check_cookie_policy_id() {
1879	let user_policy_id = cmplz_get_cookie('policy_id');
1880	if (user_policy_id && (parseInt(complianz.current_policy_id) !== parseInt(user_policy_id) ) ) {
1881		cmplz_deny_all();
1882		cmplz_set_banner_status('show');
1883		cmplz_clear_cookies('cmplz');
1884	}
1885}
1886
1887/*
1888 * Clear all our own cookies, to make sure path issues are resolved.
1889 *
1890 *
1891 */
1892function cmplz_clear_cookies (cookie_part) {
1893	if (typeof document === 'undefined') {
1894		return false;
1895	}
1896
1897	let foundCookie = false;
1898	let secure = window.location.protocol === 'https:' ? ';secure' : '';
1899	let expires = 'expires=' + new Date().toGMTString();
1900	let pathParts = location.pathname.replace(/^\/|\/$/g, '').split('/');
1901
1902	// Loop through all cookies
1903	document.cookie.split('; ').forEach(function(cookie) {
1904		let cookieName = cookie.split(';')[0].split('=')[0];
1905
1906		// If the cookie contains cookie_part, try to delete it
1907		if (cookieName.indexOf(cookie_part) !== -1) {
1908			foundCookie = true;
1909			let domainParts = window.location.hostname.split('.');
1910			let skipLast = domainParts.length > 1;
1911
1912			// Clear cookies on root path and subpaths
1913			pathParts.forEach(function(pathPart) {
1914				let path = '/' + pathPart;
1915				document.cookie = encodeURIComponent(cookieName) + '=;SameSite=Lax' + secure + ';' + expires + ';domain=.' + domainParts.join('.') + ';path=' + path;
1916				document.cookie = encodeURIComponent(cookieName) + '=;SameSite=Lax' + secure + ';' + expires + ';domain=.' + domainParts.join('.') + ';path=' + path + '/';
1917			});
1918
1919			// Clear cookies on parent domains
1920			while (domainParts.length > 0) {
1921				let domain = '.' + domainParts.join('.');
1922				domainParts.shift();
1923				if (skipLast && domainParts.length === 1) domainParts.shift();
1924
1925				pathParts.forEach(function(pathPart) {
1926					let path = '/' + pathPart;
1927					document.cookie = encodeURIComponent(cookieName) + '=;SameSite=Lax' + secure + ';' + expires + ';domain=' + domain + ';path=' + path;
1928					document.cookie = encodeURIComponent(cookieName) + '=;SameSite=Lax' + secure + ';' + expires + ';domain=' + domain + ';path=' + path + '/';
1929				});
1930			}
1931		}
1932	});
1933
1934	// To prevent a double reload, we preserve the cookie policy id
1935	cmplz_set_accepted_cookie_policy_id();
1936
1937	return foundCookie;
1938}
1939
1940/*
1941 *
1942 * If a policy is accepted, save this in the user policy id
1943 *
1944 * */
1945
1946function cmplz_set_accepted_cookie_policy_id() {
1947	cmplz_set_cookie('policy_id', complianz.current_policy_id);
1948}
1949
1950/*
1951 * For supported integrations, initialize the not consented state
1952 *
1953 * */
1954
1955function cmplz_integrations_init() {
1956	let cookiesToSet = complianz.set_cookies;
1957	//check if we have scripts that need to be set to true on init.
1958	for (let key in cookiesToSet) {
1959		if (cookiesToSet.hasOwnProperty(key) && cookiesToSet[key][1] === '1') {
1960			cmplz_set_cookie(key, cookiesToSet[key][1], false);
1961		}
1962	}
1963}
1964
1965/*
1966 * For supported integrations, revoke consent
1967 *
1968 * */
1969function cmplz_integrations_revoke() {
1970	let cookiesToSet = complianz.set_cookies;
1971	for (let key in cookiesToSet) {
1972		if (cookiesToSet.hasOwnProperty(key)) {
1973			cmplz_set_cookie(key, cookiesToSet[key][1], false);
1974			if ( cookiesToSet[key][1] == false ){
1975				cmplz_clear_cookies(key);
1976			}
1977		}
1978	}
1979}
1980
1981/*
1982 * For supported integrations, set consent
1983 *
1984 * */
1985
1986function cmplz_set_integrations_cookies() {
1987	let cookiesToSet = complianz.set_cookies;
1988	for (let key in cookiesToSet) {
1989		if (cookiesToSet.hasOwnProperty(key)) {
1990			cmplz_set_cookie(key, cookiesToSet[key][0], false);
1991		}
1992	}
1993}
1994
1995function cmplz_get_url_parameter(sPageURL, sParam) {
1996	if (!sPageURL || typeof sPageURL === 'undefined' || sPageURL.indexOf('?') === -1) {
1997		return false;
1998	}
1999
2000	const queryString = sPageURL.split('?')[1];
2001	if (!queryString) return false;
2002
2003	const sURLVariables = queryString.split('&');
2004	for (let i = 0; i < sURLVariables.length; i++) {
2005		const sParameterName = sURLVariables[i].split('=');
2006		if (sParameterName[0] === sParam) {
2007			return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
2008		}
2009	}
2010
2011	return false;
2012}
2013
2014/*
2015 * If the parameter cmplz_region_redirect =true is passed, find the user's region, and redirect.
2016 */
2017function cmplz_maybe_auto_redirect() {
2018	let redirect = cmplz_get_url_parameter(window.location.href, 'cmplz_region_redirect');
2019	let region = cmplz_get_url_parameter(window.location.href, 'cmplz-region');
2020	if (redirect && !region) {
2021		let newUrl = window.location.href.split('#')[0] + '&cmplz-region=' + complianz.region;
2022		let hash = window.location.hash;
2023		window.location.href = newUrl + hash;
2024	}
2025}
2026
2027/*
2028 * wrapper to set consent for wp consent API. If consent API is not active, do nothing
2029 * @param type
2030 * @param value
2031 */
2032function cmplz_wp_set_consent(type, value) {
2033	//wp consent api integration
2034	if (typeof wp_set_consent == 'function') {
2035		wp_set_consent(type, value);
2036	}
2037}
2038
2039var cmplz_cookie_data = [];
2040var cmplzCleanCookieInterval;
2041function cmplz_start_clean(){
2042	if ( complianz.clean_cookies == 1 ) {
2043		//check if it's already stored
2044		if (typeof (Storage) !== "undefined" ) {
2045			cmplz_cookie_data = JSON.parse( sessionStorage.getItem('cmplz_cookie_data') );
2046		}
2047		//if not stored yet, load. As features in the user object can be changed on updates, we also check for the version
2048		if ( !cmplz_cookie_data || cmplz_cookie_data.length === 0 ) {
2049			let request = new XMLHttpRequest();
2050			request.open('GET', complianz.url+'cookie_data', true);
2051			request.setRequestHeader('Content-type', 'application/json');
2052			request.send();
2053			request.onload = function() {
2054				cmplz_cookie_data = JSON.parse(request.response);
2055				sessionStorage.setItem('cmplz_cookie_data', JSON.stringify(cmplz_cookie_data) );
2056				cmplz_setup_clean_interval();
2057			};
2058		} else {
2059			cmplz_setup_clean_interval();
2060		}
2061	}
2062}
2063
2064/*
2065* Execute the cleanup of cookies
2066*/
2067function cmplz_do_cleanup() {
2068	const consent_categories = ['preferences', 'statistics', 'marketing'];
2069	for (const category of consent_categories) {
2070		if (!cmplz_has_consent(category) && cmplz_cookie_data.hasOwnProperty(category)) {
2071			const services = cmplz_cookie_data[category];
2072
2073			for (const service in services) {
2074				if (!cmplz_has_service_consent(service, category)) {
2075					const cookies = services[service];
2076
2077					for (const item of cookies) {
2078						cmplz_clear_cookies(item);
2079						cmplz_clear_storage(item);
2080					}
2081				}
2082			}
2083		}
2084	}
2085}
2086
2087
2088function cmplz_setup_clean_interval(){
2089	// if the cookie data array is empty, return, nothing to do.
2090	if ( !cmplz_cookie_data ) {
2091		return;
2092	}
2093	//check if it's already activated
2094	if ( cmplzCleanCookieInterval ) {
2095		return;
2096	}
2097	//one straight away, then every second
2098	cmplz_do_cleanup();
2099	cmplzCleanCookieInterval = setInterval(cmplz_do_cleanup, 1000 );
2100}
2101
2102/*
2103 * Clear an item from either session or localstorage
2104 * @param item
2105 */
2106function cmplz_clear_storage(item){
2107	if (typeof (Storage) !== "undefined" ) {
2108		if ( localStorage.getItem(item) ) {
2109			localStorage.removeItem(item);
2110		}
2111		if ( sessionStorage.getItem(item) ) {
2112			sessionStorage.removeItem(item);
2113		}
2114	}
2115}
2116/*
2117 * Load revoke options
2118 */
2119
2120function cmplz_load_manage_consent_container() {
2121	//don't load manage html code in the block editor
2122	let manage_consent_container = document.querySelector('.cmplz-manage-consent-container');
2123	let is_block_editor = false;//document.querySelector('.wp-admin .cmplz-unlinked-mode');
2124	if ( manage_consent_container && !is_block_editor ) {
2125
2126		let request = new XMLHttpRequest();
2127		request.open('GET', complianz.url+'manage_consent_html?'+complianz.locale, true);
2128		request.setRequestHeader('Content-type', 'application/json');
2129		request.send();
2130		request.onload = function() {
2131			let html = JSON.parse(request.response);
2132			manage_consent_container.insertAdjacentHTML( 'beforeend', html );
2133			cmplz_sync_category_checkboxes();
2134			let nojavascript = document.querySelector('#cmplz-manage-consent-container-nojavascript')
2135			nojavascript.style.display = 'none';
2136			manage_consent_container.style.display = 'block';
2137			let event = new CustomEvent('cmplz_manage_consent_container_loaded');
2138			document.dispatchEvent(event);
2139		};
2140	}
2141}
2142
2143/*
2144 * Make slider radio's tabable
2145 */
2146
2147cmplz_add_event('keypress', '.cmplz-banner-slider label', function(e){
2148	let keycode = (e.keyCode ? e.keyCode : e.which);
2149	if (keycode == 32) {
2150		document.activeElement.click();
2151	}
2152});
2153
2154/*
2155 * Make close button closable with enter
2156 */
2157cmplz_add_event('keypress', '.cmplz-cookiebanner .cmplz-header .cmplz-close', function(e){
2158	let keycode = (e.keyCode ? e.keyCode : e.which);
2159	if ( keycode == 13 ) {
2160		document.activeElement.click();
2161	}
2162});
2163
2164/*
2165 * Compare two arrays
2166 * @param array
2167 * @returns {boolean}
2168 */
2169function cmplz_equals (array_1, array_2) {
2170	if ( !Array.isArray(array_1) ) {
2171		array_1 = Object.keys(array_1);
2172		array_2 = Object.keys(array_2);
2173	}
2174	// if the other array is a falsy value, return
2175	if (!array_1 || !array_2)
2176		return false;
2177
2178	// compare lengths - can save a lot of time
2179	if (array_1.length !== array_2.length)
2180		return false;
2181
2182	for (let i = 0, l=array_1.length; i < l; i++) {
2183		// Check if we have nested arrays
2184		if (array_1[i] instanceof Array && array_2[i] instanceof Array) {
2185			// recurse into the nested arrays
2186			if (!cmplz_equals(array_1[i], array_2[i]))
2187				return false;
2188		}
2189		else if (array_1[i] !== array_2[i]) {
2190			return false;
2191		}
2192	}
2193	return true;
2194}
2195
2196/*
2197* Copy all element atributes to the new element
2198*/
2199function cmplzCopyAttributes(source, target) {
2200	const excludes = ['type', 'data-service', 'data-category', 'async'];
2201	Array.from(source.attributes).forEach(attribute => {
2202		if (attribute.nodeName === 'data-script-type' && attribute.nodeValue === 'module') {
2203			target.setAttribute('type', 'module');
2204			target.removeAttribute('data-script-type');
2205		} else if (!excludes.includes(attribute.nodeName)) {
2206			target.setAttribute(attribute.nodeName, attribute.nodeValue);
2207		}
2208	});
2209}
2210
2211
2212/*
2213 * Hooked into jquery
2214 */
2215var cmplz_has_wp_video = document.querySelector('.cmplz-wp-video-shortcode');
2216var cmplz_times_checked = 0;
2217if ('undefined' != typeof window.jQuery) {
2218	jQuery(document).ready(function ($) {
2219		if ( cmplz_has_wp_video ) {
2220			document.addEventListener("cmplz_enable_category", function (consentData) {
2221				cmplz_activate_wp_video();
2222			});
2223
2224			let cmplzInterval = setInterval(function(){
2225				cmplz_times_checked+=1;
2226				if ( document.querySelector('.cmplz-wp-video-shortcode') && cmplz_times_checked<100) {
2227					cmplz_activate_wp_video();
2228				} else {
2229					clearInterval(cmplzInterval);
2230				}
2231			}, 500);
2232		}
2233
2234		/*
2235		 * WordPress legacy shortcode
2236		 */
2237		function cmplz_activate_wp_video(again) {
2238			if ( !document.querySelector('.cmplz-wp-video-shortcode') ) {
2239				return;
2240			}
2241			let categories = cmplz_accepted_categories();
2242			let services = cmplz_get_all_service_consents();
2243			let selectorVideo = '';
2244			let selectorVideos = [];
2245			for (let c_key in categories) {
2246				if (categories.hasOwnProperty(c_key)) {
2247					let category = categories[c_key];
2248					if (category==='functional') {
2249						break;
2250					}
2251					selectorVideos.push('.cmplz-wp-video-shortcode[data-category="'+category+'"]');
2252				}
2253			}
2254			for (let s_key in services) {
2255				if (services.hasOwnProperty(s_key)) {
2256					selectorVideos.push('.cmplz-wp-video-shortcode[data-service="' + s_key + '"]');
2257				}
2258			}
2259			selectorVideo = selectorVideos.join(',');
2260			let should_initialize_video = false;
2261			if ( selectorVideo.length>0 ) {
2262				document.querySelectorAll(selectorVideo).forEach(obj => {
2263					should_initialize_video = true;
2264					obj.setAttribute('controls', 'controls');
2265					obj.classList.add('wp-video-shortcode', 'cmplz-processed');
2266					obj.classList.remove('cmplz-wp-video-shortcode');
2267					obj.closest('.cmplz-wp-video').classList.remove('cmplz-wp-video');
2268
2269					let blocked_notice = obj.closest('.wp-video').querySelector('.cmplz-blocked-content-notice');
2270					if (blocked_notice) {
2271						blocked_notice.parentElement.removeChild(blocked_notice);
2272					}
2273					obj.classList.remove('cmplz-blocked-content-container');
2274				});
2275			}
2276
2277			if ( should_initialize_video ) {
2278				//in normal setup, this should work. e.g. with primavera theme not, then we init per element.
2279				if (window.wp.mediaelement) {
2280					window.wp.mediaelement.initialize()
2281				} else {
2282					let settings={};
2283					settings.videoWidth='100%';
2284					settings.videoHeight='100%';
2285					settings.enableAutosize=true;
2286					$( '.wp-video-shortcode' ).mediaelementplayer( settings );
2287				}
2288			}
2289		}
2290
2291		/*
2292		 * Activate fitvids on the parent element if active
2293		 *  a.o. Beaverbuilder
2294		 */
2295		document.querySelectorAll('.cmplz-video.cmplz-activated').forEach(obj => {
2296			cmplz_activate_fitvids(obj);
2297		});
2298
2299		document.addEventListener("cmplz_enable_category", function (e) {
2300			document.querySelectorAll('.cmplz-video.cmplz-activated').forEach(obj => {
2301				cmplz_activate_fitvids(obj);
2302			});
2303		});
2304
2305		function cmplz_activate_fitvids(obj){
2306			//turn obj into jquery object
2307			let $obj = $(obj);
2308			if (typeof $obj.parent().fitVids === 'function') {
2309				$obj.parent().fitVids();
2310			}
2311		}
2312	});
2313}

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.