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