1/** 2 * Klaro configuration â based on the live Drupal setup, with an opt-out gate. 3 * 4 * Defines the global `window.klaroConfig` that the vendored Klaro.js reads on 5 * load (it auto-renders from the `klaroConfig` global). Most values copy the 6 * Drupal `config/sync/klaro.*.yml` (notice mode, cookie "klaro"/180-day, light 7 * theme, group_by_purpose off, the "Cookie Notice" title and "We use cookiesâ¦" 8 * wording). 9 * 10 * Deliberate divergence from Drupal: the notice now shows a **Reject** button 11 * (`hideDeclineAll: false`) and Google Analytics + Tag Manager are **opt-out** 12 * (`required: false`, `default: true`) instead of always-on `required: true`. 13 * They run by default but a visitor can reject them. The enforcement is in the 14 * container module: the GTM snippet is emitted with contextual-blocking markup 15 * (`type="text/plain" data-name="gtm"`) so Klaro only executes it while the 16 * `gtm` service is consented â reject stops GTM, and therefore GA and every 17 * downstream marketing pixel it fires. Essential services (functional, consent 18 * manager, reCAPTCHA) stay `required: true`. The five embeds remain opt-in. 19 */ 20( function () { 21 'use strict'; 22 23 var data = window.luKlaro || {}; 24 var privacyUrl = data.privacyUrl || '/privacy-policy'; 25 26 window.klaroConfig = { 27 version: 1, 28 elementID: 'klaro', 29 styling: { theme: [ 'light' ] }, 30 noAutoLoad: false, 31 htmlTexts: true, 32 embedded: false, 33 groupByPurpose: false, 34 storageMethod: 'cookie', 35 cookieName: 'klaro', 36 cookieExpiresAfterDays: 180, 37 default: false, 38 mustConsent: false, 39 acceptAll: true, 40 hideDeclineAll: false, 41 hideLearnMore: true, 42 privacyPolicy: privacyUrl, 43 44 translations: { 45 en: { 46 consentModal: { 47 title: 'Use of personal data and cookies', 48 description: 'Please choose the services and 3rd party applications we would like to use.' 49 }, 50 consentNotice: { 51 title: 'Cookie Notice', 52 description: 'We use cookies on this site. By continuing to browse without changing your browser settings to block or delete cookies, you agree to the {privacyPolicy}.', 53 changeDescription: 'There were changes since your last visit, please update your consent.', 54 learnMore: 'Customize' 55 }, 56 privacyPolicy: { 57 name: 'Lawrence Privacy Policy', 58 text: 'To learn more, please read our {privacyPolicy}.' 59 }, 60 ok: 'Accept', 61 save: 'Save', 62 decline: 'Reject', 63 close: 'Close', 64 acceptAll: 'Accept all', 65 acceptSelected: 'Accept selected', 66 purposes: { 67 cms: 'Functional', 68 analytics: 'Analytics', 69 advertising: 'Advertising and Marketing', 70 security: 'Security', 71 external_content: 'Embedded external content' 72 }, 73 service: { 74 disableAll: { 75 title: 'Toggle all services', 76 description: 'Use this switch to enable/disable all services.' 77 }, 78 optOut: { 79 title: '(opt-out)', 80 description: 'This service is loaded by default (opt-out possible).' 81 }, 82 required: { 83 title: '(always required)', 84 description: 'This service is always required.' 85 }, 86 purposes: 'Purposes', 87 purpose: 'Purpose' 88 }, 89 poweredBy: 'Powered by Klaro!' 90 } 91 }, 92 93 // Service NAMES + the full set are kept identical to the live Drupal 94 // Klaro apps (config/sync/klaro.klaro_app.*.yml where status: true): the 95 // consent cookie stores a { serviceName: boolean } map keyed by these 96 // `name`s, so matching them lets a visitor's saved consent carry over at 97 // cutover without re-prompting. Adding, removing, or renaming a service 98 // re-prompts returning visitors. The `required` flags on `ga`/`gtm` 99 // deliberately differ from Drupal (opt-out, not always-on) â that changes 100 // behaviour, not the cookie shape, so carry-over still holds. 101 services: [ 102 { 103 name: 'cms', 104 title: 'Functional', 105 purposes: [ 'cms' ], 106 required: true, 107 default: true, 108 cookies: [ /^_?Ss?ESS/ ] 109 }, 110 { 111 name: 'klaro', 112 title: 'Consent manager', 113 purposes: [ 'cms' ], 114 required: true, 115 default: true, 116 cookies: [ /^klaro/ ] 117 }, 118 { 119 name: 'google_recaptcha', 120 title: 'Google reCAPTCHA', 121 purposes: [ 'security' ], 122 required: true, 123 default: true 124 }, 125 // Opt-out: loaded by default but rejectable. `gtm` gates the GTM 126 // snippet (contextual blocking in container/namespace.php); `ga` is 127 // declared for cookie management and consent display â GA fires via 128 // the container, so rejecting `gtm` already stops it. 129 { 130 name: 'ga', 131 title: 'Google Analytics', 132 purposes: [ 'analytics' ], 133 required: false, 134 default: true, 135 cookies: [ /^_ga(_.*)?$/, /^_gid$/, /^IDE$/ ] 136 }, 137 { 138 name: 'gtm', 139 title: 'Google Tag Manager', 140 purposes: [ 'advertising' ], 141 required: false, 142 default: true 143 }, 144 { name: 'facebook', title: 'Facebook', purposes: [ 'external_content' ], default: false }, 145 { name: 'linkedin', title: 'Linkedin', purposes: [ 'external_content' ], default: false }, 146 { name: 'tiktok', title: 'TikTok', purposes: [ 'external_content' ], default: false }, 147 { name: 'vimeo', title: 'Vimeo', purposes: [ 'external_content' ], default: false }, 148 { name: 'youtube', title: 'YouTube', purposes: [ 'external_content' ], default: false } 149 ] 150 }; 151 152 // Klaro 0.7 does not render the notice's title (it only sets 153 // aria-labelledby="id-cookie-title", referencing an element it never 154 // creates). The live Drupal site shows the title (show_notice_title), so we 155 // inject it once Klaro renders the notice â matching Drupal and resolving the 156 // dangling aria reference. Styled by the `.title` rule in css/klaro.css. 157 var noticeTitle = window.klaroConfig.translations.en.consentNotice.title; 158 159 function injectNoticeTitle() { 160 var body = document.querySelector( '#klaro-cookie-notice .cn-body' ); 161 if ( ! body || document.getElementById( 'id-cookie-title' ) ) { 162 return ! ! document.getElementById( 'id-cookie-title' ); 163 } 164 var heading = document.createElement( 'div' ); 165 heading.id = 'id-cookie-title'; 166 heading.className = 'title'; 167 heading.textContent = noticeTitle; 168 body.insertBefore( heading, body.firstChild ); 169 return true; 170 } 171 172 if ( ! injectNoticeTitle() ) { 173 var observer = new MutationObserver( function () { 174 if ( injectNoticeTitle() ) { 175 observer.disconnect(); 176 } 177 } ); 178 observer.observe( document.documentElement, { childList: true, subtree: true } ); 179 // Klaro renders on load; stop watching after a short window regardless. 180 setTimeout( function () { 181 observer.disconnect(); 182 }, 10000 ); 183 } 184} )();
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.