PageSourceSearch

https://www.stromroku.cz/app_themes/common/web-components/cookies-consent/cookies-consent.js?v=965007676

js stromroku.cz collected 2026-10-02 10:30:24 UTC 17,758 bytes, 565 lines download raw bytes

1/**
2 *  Cookie popup v2.3
3 * 
4 *  Cookie settings are send to server endpoint.
5 * 
6 *  Update v2.3
7 *  - added support for Consent Mode 2.0
8 *  - UserData and Personalization cookies added
9 *  - switches for UserData and Personalization cookies are hidden , it's controled by marketing switch
10 *  - modal width responsivity was adjusted
11 *  
12 *  Update v2.2
13 *  - added events consentmodalclose and consentmodalwillnotopen
14 */
15import THEMES from './cookies-consent-themes.js';
16import { chevronDown, chevronLeft } from './svg-icons.js';
17
18const getCookie = (cname) => {
19  var name = cname + "=";
20  var decodedCookie = decodeURIComponent(document.cookie);
21  var ca = decodedCookie.split(';');
22  for (var i = 0; i < ca.length; i++) {
23    var c = ca[i];
24    while (c.charAt(0) == ' ') {
25      c = c.substring(1);
26    }
27    if (c.indexOf(name) == 0) {
28      return c.substring(name.length, c.length);
29    }
30  }
31  return "";
32}
33
34class CookiesConsent extends HTMLElement {
35  constructor() {
36    super();
37
38    this.debug = this.getAttribute("debug") === "true" ? true : false;
39
40    this.shadow = this.attachShadow({ mode: "closed" });
41
42    // style props
43    this.popupTheme = this.getAttribute("theme");
44
45    this.delay = this.hasAttribute("delay") && !isNaN(parseInt(this.getAttribute("delay"), 10)) ? parseInt(this.getAttribute("delay"), 10) : 2000;
46
47    // better props check , hasattribute , attribute names are case insensitive
48    const url = this.getAttribute("url");
49    const cookie = parseInt(this.getAttribute("cookie"), 10);
50    //const cookie = this.hasAttribute("cookie") ? parseInt(this.getAttribute("cookie"), 10) : parseInt(getCookie("CMSCookieLevel"), 10);
51    const isCookieValid = (() => {
52      if (isNaN(cookie)) return false;
53      if (cookie === 0 || cookie === 1000) return true;
54      if (cookie > 300 && cookie < 315) return true;
55      return false;
56    })();
57    const loadedConsent = isCookieValid ? cookie : 0;
58
59    this.dlog('cookie', cookie);
60    this.dlog('consent', loadedConsent);
61
62    let [analytics_storage, ad_storage, ad_user_data, ad_personalization] = (() => {
63      if (loadedConsent === 0) return [false, false, false, false];
64      if (loadedConsent === 1000) return [true, true, true, true];
65      const tempConsent = loadedConsent - 300;
66      return [
67        (tempConsent & 1) ? true : false,
68        (tempConsent & 2) ? true : false,
69        (tempConsent & 4) ? true : false,
70        (tempConsent & 8) ? true : false,
71      ];
72    })();
73
74    const getConsentLevel = () => {
75      if (!analytics_storage && !ad_storage && !ad_user_data && !ad_personalization) return 0;
76      if (analytics_storage && ad_storage && ad_user_data && ad_personalization) return 1000;
77      const tempResult = [
78        analytics_storage ? 1 : 0,
79        ad_storage ? 2 : 0,
80        ad_user_data ? 4 : 0,
81        ad_personalization ? 8 : 0
82      ];
83      return 300 + tempResult.reduce((acc, n) => acc + n, 0);
84    }
85
86    this.dlog('consent constructed');
87
88    this.render();
89
90    const $cookieModal = this.shadow.querySelector("#cookie-modal");
91    const $optionsButton = $cookieModal.querySelector(`[data-control="open-options"]`);
92    const $backButton = $cookieModal.querySelector(`[data-control="back-button"]`);    
93    const $necessaryButton = $cookieModal.querySelector(`[data-control="necessary-button"]`);
94    const $moreOptionsSection = $cookieModal.querySelector(`[data-control="more-options-section"]`);
95    const $acceptAllButton = $cookieModal.querySelector(`[data-control="accept-all"]`);
96    const $denyAllButton = $cookieModal.querySelector(`[data-control="deny-all"]`);
97    const $acceptButton = $cookieModal.querySelector(`[data-control="accept"]`);    
98    const $acceptTechnicaOnlylButton = $cookieModal.querySelector(`[data-control="accept-technical-only"]`);
99    const $switchAnalyticsButton = $cookieModal.querySelector(`[data-control="switch-analytics"]`);
100    const $switchMarketingButton = $cookieModal.querySelector(`[data-control="switch-marketing"]`);
101    const $switchUserDataButton = $cookieModal.querySelector(`[data-control="switch-user-data"]`);
102    const $switchPersonalizationButton = $cookieModal.querySelector(`[data-control
102="switch-personalization"]`);
103
104    const openModal = () => $cookieModal.showModal();
105    const closeModal = () => {
106      $cookieModal.close();
107      const event = new CustomEvent("consentmodalclose", { bubbles: false });
108      window.dispatchEvent(event);
109      this.dlog('dispatch consentmodalclose');
110    }
111
112    if (!isCookieValid) {
113      setTimeout(openModal, this.delay);
114    } else {
115      const event = new CustomEvent("consentmodalwillnotopen", { bubbles: false });
116      window.dispatchEvent(event);
117      this.dlog('dispatch consentmodalwillnotopen');
118    }
119
120    // open on event dispatch, mostly settings button
121    window.addEventListener('openconsentmodal', () => {
122      openModal();
123    });
124
125    if (analytics_storage) $switchAnalyticsButton.classList.add("granted");
126    if (ad_storage) $switchMarketingButton.classList.add("granted");
127    if (ad_user_data) $switchUserDataButton.classList.add("granted");
128    if (ad_personalization) $switchPersonalizationButton.classList.add("granted");
129
130    $cookieModal.addEventListener("click", (e) => {      
131      if (e.target === $optionsButton) {
132        $moreOptionsSection.classList.toggle("open");
133        $acceptAllButton.classList.toggle("disabled");
134        $denyAllButton.classList.toggle("disabled");
135        $optionsButton.classList.toggle("disabled");
136        $backButton.classList.toggle("disabled");
137        $necessaryButton.classList.toggle("disabled");
138        return;
139      }
140
141      if (e.target === $backButton) {
142        $moreOptionsSection.classList.toggle("open");
143        $acceptAllButton.classList.toggle("disabled");
144        $denyAllButton.classList.toggle("disabled");
145        $optionsButton.classList.toggle("disabled");
146        $backButton.classList.toggle("disabled");
147        $necessaryButton.classList.toggle("disabled");
148        return;
149      }      
150
151      if (e.target === $acceptAllButton) {
152        postConsentCookies(1000);
153        analytics_storage = true;
154        ad_storage = true;
155        ad_user_data = true;
156        ad_personalization = true;
157        $switchAnalyticsButton.classList.add("granted");
158        $switchMarketingButton.classList.add("granted");
159        $switchUserDataButton.classList.add("granted");
160        $switchPersonalizationButton.classList.add("granted");
161        closeModal();
162        return;
163      }
164      if (e.target === $acceptButton) {
165        postConsentCookies(getConsentLevel());
166        closeModal();
167        return;
168      }
169      if (e.target === $switchAnalyticsButton) {
170        $switchAnalyticsButton.classList.toggle("granted");
171        analytics_storage = !analytics_storage;
172        return;
173      }
174      if (e.target === $switchMarketingButton) {
175        $switchMarketingButton.classList.toggle("granted");
176        ad_storage = !ad_storage;
177
178        // control of user data and personalization cookies is handled by marketing switch
179        $switchUserDataButton.classList.toggle("granted");
180        $switchPersonalizationButton.classList.toggle("granted");
181        ad_user_data = !ad_user_data;
182        ad_personalization = !ad_personalization;        
183        return;
184      }
185      // if (e.target === $switchUserDataButton) {
186      //   $switchUserDataButton.classList.toggle("granted");
187      //   ad_user_data = !ad_user_data;
188      //   return;
189      // }
190      // if (e.target === $switchPersonalizationButton) {
191      //   $switchPersonalizationButton.classList.toggle("granted");
192      //   ad_personalization = !ad_personalization;
193      //   return;
194      // }
195      if (e.target === $acceptTechnicaOnlylButton || e.target === $necessaryButton || e.target === $denyAllButton) {
196        postConsentCookies(0);
197        analytics_storage = false;
198        ad_storage = false;
199        ad_user_data = false;
200        ad_personalization = false;
201        $switchAnalyticsButton.classList.remove("granted");
202        $switchMarketingButton.classList.remove("granted");
203        $switchUserDataButton.classList.remove("granted");
204        $switchPersonalizationButton.classList.remove("granted");
205        closeModal();
206        return;
207      }
208
209      const $moreButtonElement = e.target.closest(`[data-control
209="more-button"]`); 
210      if ($moreButtonElement) {
211        $moreButtonElement.nextElementSibling.classList.toggle("disabled");
212        $moreButtonElement.classList.toggle("open");
213        return;
214      }
215    });
216
217    async function postData(url = "", data = {}) {
218      const response = await fetch(url, {
219        method: "POST",
220        headers: {
221          "Content-Type": "application/json",
222        },
223        body: JSON.stringify(data),
224      });
225      return response.json();
226    }
227
228    async function postConsentCookies(newLevel = -1000) {
229      const response = await postData(url, { "newCookiesLevel": newLevel });
230
231      // handle response.ok is false
232
233      const event = new CustomEvent("consentupdate", { bubbles: false, detail: { consentLevel: newLevel } });
234      window.dispatchEvent(event);
235    }
236  }
237
238  dlog = (...args) => this.debug && console.log(...args);
239
240  getText(str) {
241    return this.getAttribute(str) || "";
242  }
243
244  placeText(template) {
245    const replacer = (match, p1, p2, p3, offset, string) => {
246      const str = this.getText(p2);
247      if (str === "") return "";
248      return `${p1}${str}${p3}`;
249    }
250    return template.replace(/([^\{\{]*)\{\{ ([^\}\}]*) \}\}(.*)/, replacer);
251  }
252
253  render() {
254    this.shadow.innerHTML = `
255    <dialog id="cookie-modal"  class="cookie-modal">
256    <button data-control="back-button" class="cookie-modal__content_back-text disabled" type="button">${chevronLeft}${this.getText("BackText")}</button>
257  <div class="cookie-modal__content">    
258    <button data-control="necessary-button" class="cookie-modal__content_necessary-text" type="button" style="display:none">${this.getText("OnlyNecessaryText")}</button>   
259    <h2>${this.getText("Name")}</h2>
260    <div class="small-text">      
261        ${this.placeText('<h3>{{ Subtitle }}</h3>')}      
262        ${this.placeText('<p>{{ Text }}</p>')}     
263        ${this.placeText('<h4>{{ Subtitle2 }}</h2>')}      
264        ${this.placeText('<p>{{ Text2 }}</p>')}     
265    </div>
266    <div class="buttons u-center">
267      <button data-control="open-options" class="more-options-btn btn btn-more btn-secondary" type="button">${this.getText("MoreOptionsBTN")}</button>
268      <button data-control="deny-all" class="btn btn-more" type="button">${this.getText("DenyButton")}</button>      
269      <button data-control="accept-all" class="btn btn-more" type="button" autofocus>${this.getText("AcceptButton")}</button>
270    </div>
271    <div class="more-options" data-control="more-options-section">
272      <div class="more-options__option">
273        <div class="more-options__option--text">
274          <p data-control="more-button" class="more-options__option--name">${chevronDown}${this.getText("Technical")}</p>
275          <p class="more-options__option--desc disabled">${this.getText("TechnicalDesc")}</p>
276        </div>
277        <span class="switch tech-cookies granted"></span>
278      </div>
279      <div class="more-options__option">
280        <div class="more-options__option--text">
281          <p data-control="more-button" class="more-options__option--name">${chevronDown}${this.getText("Analytical")}</p>
282          <p class="more-options__option--desc disabled">${this.getText("AnalyticalDesc")}</p>
283        </div>
284        <button class="switch" data-control="switch-analytics" type="button"></button>
285      </div>
286      <div class="more-options__option">
287        <div class="more-options__option--text">
288          <p data-control="more-button" class="more-options__option--name">${chevronDown}${this.getText("Marketing")}</p>
289          <p class="more-options__option--desc disabled">${this.getText("MarketingDesc")}</p>
290        </div>
291        <button class="switch" data-control="switch-marketing" type="button"></button>
292      </div>
293      <div class="more-options__option" style="display:none">
294        <div class="more-options__option--text">
295          <p data-control="more-button" class="more-options__option--name">${chevronDown}${this.getText("UserData")}</p>
296          <p class="more-options__option--desc disabled">${this.getText("UserDataDesc")}</p>
297        </div>
298        <button class="switch" data-control="switch-user-data" type="button"></button>
299      </div>
300      <div class="more-options__option" style="display:none">
301        <div class="more-options__option--text">
302          <p data-control="more-button" class="more-options__option--name">${chevronDown}${this.getText("Personalization")}</p>
303          <p class="more-options__option--desc disabled">${this.getText("PersonalizationDesc")}</p>
304        </div>
305        <button class="switch" data-control="switch-personalization" type="button"></button>
306      </div>
307      <div class="buttons u-center">        
308      ${this.placeText(`<button data-control="accept-technical-only" class="cookie-btn-text" type="button">{{ OnlyNecessary }}</button>`)}               
309        <button data-control="accept" class="btn" type="button">${this.getText("Accept")}</button>
310      </div>
311    </div>
312  </div>
313</dialog>
314
315
316
317<style>
318/*# Cookie modal #*/
319
320*, *:before, *:after {
321    box-sizing: border-box;
322}
323
324.cookie-modal{
325  border: none;
326  overflow: auto;
327  border-radius: 25.5px;
328  background: #fff;
329  padding: 20px 25px;
330  z-index: 11000;
331}
332
333::backdrop {
334  backdrop-filter: blur(3px);      
335  background-color: rgba(0,0,0,0.5);       
336} 
337
338.cookie-modal__content{
339  font-family: 'Montserrat',sans-serif;
340  font-size: 16px;
341  font-weight: normal;
342  color: #000;
343  /*width: 60ch;  */
344  max-width: min(65ch, 90vw);  
345  margin: auto; 
346  position: relative;
347}
348
349.cookie-modal__content h2{
350  margin-top: 30px;
351}
352
353.cookie-modal__content a{
354  text-decoration: none;
355  font-weight: 700;
356  color: #0076ff;
357}
358
359.cookie-modal__content .small-text p{
360  color:#3f3f3f;
361}
362
363.cookie-modal__content_back-text,
364.cookie-modal__content_necessary-text {
365  background: none;
366  color: #000;
367  border: 0;
368  position: absolute;
369  right: 1.5rem;
370  transition: all .15s;
371  cursor: pointer;
372}
373
374.cookie-modal__content_necessary-text {
375  color: #757575;
376}
377
378.cookie-modal__content_back-text svg{
379  width: 1em;
380  height: 0.7em;
381}
382
383.cookie-modal__content_back-text:hover,
384.cookie-modal__content_necessary-text:hover,
385.cookie-modal__content_back-text:hover:after,
386.cookie-modal__content_back-text:hover:before{
387  text-shadow: 1px 0px;
388}
389
390.more-options{
391  height: 0;
392  visibility: hidden;
393  transition: all 1s;
394  overflow: hidden;
395}
396
397.more-options.open{
398  height: auto;
399  visibility: visible;
400  /*padding-top: 1rem;*/
401}
402
403.more-options__option{
404  display: flex;
405  flex-direction: row;
406  justify-content: space-between;
407  background: #e8e8e8;
408  padding: 0 0.5rem 0 1.5rem;
409  margin-bottom: 0.5rem;
410  border-radius: 15px;  
411}
412
413.more-options__option--name {
414  font-weight: 600;
415  cursor: pointer;
416  position: relative;
417  margin-top: 1.1rem;
418}
419
420.more-options__option--name svg{
421  width: 0.7em;
422  margin-right: 0.25em;
423  transition: transform 0.2s
424}
425
426.more-options__option--name.open svg {
427  transform: rotate(180deg);
428}
429
430.more-options__option .switch{
431  width: 55px;
432  height: 25px;
433  background: rgba(172, 168, 168, .8);
434  border-radius: 20px;
435  border: 1px solid rgb(172, 168, 168);
436  display: block;
437  position: relative;
438  cursor: pointer;
439  flex-shrink: 0;
440  margin-top: 0.8rem;
441}
442
443.more-options__option .switch.granted {
444  background: #08768c;
445}
446
447.more-options__option span.switch.granted{
448  background: rgba(8,118,140, 0.5);
449}
450
451
452.more-options__option .switch:after{
453  content: "";
454  height: 25px;
455  width: 25px;
456  border-radius: 20px;
457  border: 1px solid #fff;
458  background: #fff;
459  position: absolute;
460  top: -1px;
461  left: 0;
462  right: 26px;
463  transition: all .45s;
464}
465
466.more-options__option .switch.granted:after {
467  border: 1px solid #08768c;
468  left: 26px;
469  right: 0;
470}
471
472.more-options__option span.switch.granted:after {
473  border: 1px solid #dfdddd;
474  background: #dfdddd;
475}
476
477.btn {
478  background: #000;
479  color: #fff;  
480  display: inline-block;
481  cursor: pointer;
482  font-size: 16px;
483  padding: 1rem 1.9rem;
484  border: none;  
485}
486
487.btn-secondary {  
488  color: #000;
489  background: #fff;  
490}
491
492${this.popupTheme ? THEMES[this.popupTheme] : THEMES.default}
493
494.btn-more {
495  margin-top: 1.25rem;
496  margin-bottom: 1.25rem; 
497}
498
499.more-options .buttons,
500.cookie-modal__content .buttons{
501  margin-top: 1rem;
502  display: flex;
503  gap: 0.7rem;
504  flex-wrap: wrap;
505  justify-content: flex-end;
506}
507
508.more-options .buttons button {
509  margin-bottom: 1rem;
510}
511
512.cookie-btn-text{
513  border: none;
514  background: transparent;
515  text-decoration: underline;
516  color: #08768c;
517  text-shadow: 0px 0px;
518  transition: all .35s;
519  margin-right: 1rem;
520}
521
522.cookie-btn-text:hover{
523  text-shadow: 1px 0px;
524}
525
526@media (max-width: 767px) {
527  .cookie-modal {
528    padding: 2rem;
529  }  
530  .cookie-modal__content{
531    font-size: 14px;
532  }
533  .cookie-modal__content .buttons, .more-options .buttons {
534    display: block;
535  }
536  .btn {
537    display: block;
538    width: 100%;
539  }
540  .more-options__option p, .more-options__option strong .more-options__option a {
541    font-size: 11px;
542  }
543  .more-options__option {
544    padding-left: 1rem;
545  }   
546} 
547
548.disabled {
549  display: none;
550}
551</style>
552    `;
553  }
554}
555
556customElements.define("cookies-consent", CookiesConsent);
557
558window.addEventListener('load', () => {
559  Array.from(document.querySelectorAll('[data-control="open-consent-modal"]')).map(e => e.addEventListener('click', (e) => {
560    e.preventDefault();
561    const event = new CustomEvent("openconsentmodal", { bubbles: false });
562    window.dispatchEvent(event);
563  }));
564});
565

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.