PageSourceSearch

https://zzf-potsdam.de/modules/contrib/klaro/js/klaro.drupal.js?tm6fwh

js zzf-potsdam.de collected 2026-10-02 06:54:22 UTC 14,378 bytes, 355 lines download raw bytes

1(function (Drupal, drupalSettings) {
2
3  'use strict';
4
5  /**
6   * Initialize Klaro! with custom settings.
7   */
8  Drupal.behaviors.klaro = {
9    config: false,
10    manager: false,
11    observing: false,
12    needCallBehaviors: false,
13    ready: false,
14    attach: function (context, settings) {
15      if (!settings.klaro) {
16        return;
17      }
18      if (typeof klaro === 'undefined') {
19        document.querySelector('#klaro-js').addEventListener("load", () => {
20          Drupal.behaviors.klaro.proceed(context, settings);
21        });
22      }
23      else {
24        Drupal.behaviors.klaro.proceed(context, settings);
25      }
26    },
27    proceed: function(context, settings) {
28      // Bootstrap config once.
29      if (!Drupal.behaviors.klaro.config) {
30        settings.klaro.config.services.forEach(function (service, a_index) {
31          // Set callback for each service.
32          settings.klaro.config.services[a_index].callback = Drupal.behaviors.klaro.serviceCallback;
33          // Create regular expressions from config.
34          service.cookies.forEach(function (cookie, c_index) {
35            settings.klaro.config.services[a_index]['cookies'][c_index] = [new RegExp(cookie[0], 'i'), cookie[1] || '/', cookie[2] || location.host];
36          });
37        });
38
39        Drupal.behaviors.klaro.config = settings.klaro.config;
40      }
41
42      // Decorate wrapperIdentifiers in context.
43      Drupal.behaviors.klaro.klaroDecorateWrapper(context, settings);
44
45      // Remove unused data attributes.
46      context.querySelectorAll('a[data-name]')?.forEach((item) => {
47        item.removeAttribute('data-href');
48      });
49
50      // Store reference to manager once.
51      if (!Drupal.behaviors.klaro.manager) {
52        Drupal.behaviors.klaro.manager = klaro.getManager(Drupal.behaviors.klaro.config);
53      }
54
55      // Loading klaro less intrusive.
56      if (settings.klaro.dialog_mode === 'silent') {
57        Drupal.behaviors.klaro.manager.confirmed = true;
58      }
59
60      // Setup klaro on each attach (support ajax insert commands).
61      klaro.setup(Drupal.behaviors.klaro.config);
62
63      // Observe klaro-element to add aria-features.
64      Drupal.behaviors.klaro.klaroElementObserver();
65
66      // Add accessibility features to the learn more link.
67      let learn_more_link = document.querySelector('a.cm-link.cn-learn-more');
68      if (learn_more_link) {
69        // Add title to learn more link.
70        let label_open_consent_dialog = Drupal.t("Open consent dialog", {},{context: 'klaro'});
71        learn_more_link.setAttribute('title', label_open_consent_dialog);
72        // Add the "button" role to the learn more link.
73        learn_more_link.setAttribute('role', 'button');
74        // Add the attribute aria-haspopup="dialog".
75        learn_more_link.setAttribute('aria-haspopup', 'dialog');
76      }
77
78      // Store reference to manager once.
79      if (!Drupal.behaviors.klaro.manager) {
80        Drupal.behaviors.klaro.manager = klaro.getManager(Drupal.behaviors.klaro.config);
81      }
82
83      if(context === document) {
84        var elements = once('klaro', 'body', context);
85        Array.prototype.forEach.call(elements, function () {
86          // Add toggle dialog button.
87          if (settings.klaro.show_toggle_button && !document.getElementById('klaro_toggle_dialog')) {
88            var button_label = Drupal.t("Manage consents", {},{context: 'klaro'});
89            var button_html = '<button id="klaro_toggle_dialog" aria-label="' + button_label + '" aria-haspopup="dialog" title="'+ button_label + '" type="button" class="klaro_toggle_dialog klaro_toggle_dialog_override" rel="open-consent-manager"></button>';
90            document.body.insertAdjacentHTML('afterbegin', button_html);
91          }
92        });
93      }
94      else {
95        for (var app in Drupal.behaviors.klaro.manager.executedOnce) {
96          if (Drupal.behaviors.klaro.manager.executedOnce[app]) {
97            // (Re-)apply consents on each attach (ajax add_js support)
98            // only if there are elements with data-src left.
99            if (document.querySelectorAll('[data-name="' + app + '"][data-src]:not([src])').length > 0) {
100              Drupal.behaviors.klaro.manager.applyConsents();
101            }
102          }
103        }
104      }
105
106      // Set preview image for contextual consent.
107      var elements = once('klaro-thumbnail', '.klaro.cm-as-context-notice', context);
108      Array.prototype.forEach.call(elements, function (el) {
109        let klaro_elem = (el.closest('.field'))?.querySelector('[data-modified-by-klaro]');
110        let thumbnail = klaro_elem?.getAttribute('data-thumbnail');
111        let title = klaro_elem?.getAttribute('title');
112
113        if (thumbnail) {
114          el.parentElement.style.backgroundImage = 'url(' + thumbnail + ')';
115          el.parentElement.style.backgroundSize = 'cover';
116          el.parentElement.style.backgroundPosition = 'center';
117          el.firstChild.style.backgroundColor = 'rgba(250, 250, 250, 0.75)';
118        }
119
120        if (title) {
121          let title_elem = document.createElement('p');
122          title_elem.textContent = title;
123          el.firstChild.prepend(title_elem);
124        }
125      });
126
127      // Iterate services and replace placeholder texts.
128      Drupal.behaviors.klaro.config.services.forEach(function(service, a_index) {
129        if (service.contextualConsentText) {
130          var elements = once('klaro-text', '[data-type="placeholder"][data-name="' + service.name + '"] div.context-notice > p:first-child', context);
131          if (elements.length > 0) {
132            let title_elem = document.createElement('p');
133            title_elem.innerHTML = service.contextualConsentText;
134            Array.prototype.forEach.call(elements, function (el) {
135              el.parentNode.replaceChild(title_elem.cloneNode(true), el);
136            });
137          }
138        }
139      });
140
141      // Add link to consent manager for contextual consents.
142      var elements = once('klaro-consent-link', '[data-type="placeholder"] div.context-notice');
143      var title = Drupal.t("Open the Consent Management Dialog", {}, {context: 'klaro'});
144      var linktext = Drupal.t("Manage privacy settings", {}, {context: 'klaro'});
145      Array.prototype.forEach.call(elements, function (el) {
146        el.insertAdjacentHTML('beforeend', `<p class="cm-dialog-link"><a href="#" title="${title}" rel="open-consent-manager">${linktext}</a></p>`);
147      });
148
149      // Call Behaviors if needed.
150      if (Drupal.behaviors.klaro.needCallBehaviors && context === document) {
151        Drupal.behaviors.klaro.needCallBehaviors = false;
152        Drupal.attachBehaviors(document, drupalSettings);
153      }
154
155      // Set ready.
156      Drupal.behaviors.klaro.ready = true;
157    },
158
159    /**
160     * A callback for each service that will run at the beginning and on consent change.
161     */
162    serviceCallback: function (consent, service) {
163
164      // If onlyOnce, abort if already executed.
165      if (Drupal.behaviors.klaro.manager && service.onlyOnce && Drupal.behaviors.klaro.manager.executedOnce[service.name]) {
166        return;
167      }
168
169      // Execute callbackCode from config form.
170      if (service.callbackCode.length > 0) {
171        Function('consent', 'service', service.callbackCode)(consent, service);
172      }
173
174      // Do the behaviors only for consent.
175      if (!consent) {
176        return;
177      }
178
179      // Rewrite data-id to id.
180      var elements = document.querySelectorAll('[data-name="' + service.name + '"][data-id]');
181      if (elements.length > 0) {
182        Array.prototype.forEach.call(elements, function(element) {
183          element.setAttribute('id', element.getAttribute('data-id'));
184        });
185        if (Drupal.behaviors.klaro.ready) {
186          Drupal.attachBehaviors(document, drupalSettings);
187        }
188        else {
189          Drupal.behaviors.klaro.needCallBehaviors = true;
190        }
191      }
192
193      let knownBehaviors = Object.keys(Drupal.behaviors);
194      var elements = document.querySelectorAll('[data-name="' + service.name + '"][src]');
195      if (!elements) {
196        return;
197      }
198
199      // #3459261 Fix HtmlMediaElements not loading correctly.
200      var source_tags = document.querySelectorAll('source[data-name="' + service.name + '"]');
201      if (source_tags.length > 0) {
202        var loading_state;
203        for (var i = 0; i < source_tags.length; i++) {
204          loading_state = source_tags[i].parentElement.readyState;
205          if (loading_state == 0 || loading_state == 1) {
206            source_tags[i].parentElement.load();
207          }
208        }
209      }
210
211      function processBehaviors() {
212        for (let name in Drupal.behaviors) {
213          if (knownBehaviors.indexOf(name) === -1) {
214            // Execute newly added behaviors. This is somewhat guesswork, as
215            // the order of execution is undetermined based on file load order.
216            Drupal.behaviors[name].attach(document, drupalSettings);
217            knownBehaviors.push(name);
218          }
219        }
220      }
221
222      Array.prototype.forEach.call(elements, function(element) {
223        if (element.complete) {
224          processBehaviors();
225        }
226        else {
227          element.addEventListener('load', processBehaviors);
228        }
229      });
230    },
231
232    /**
233     * Decorate wrapperIdentifiers in context.
234     */
235    klaroDecorateWrapper: function(context, settings) {
236      // Iterate services and wrapperIdentifier.
237      settings.klaro.config.services.forEach(function(service, a_index) {
238        service.wrapperIdentifier.forEach(function(wrapperIdentifier) {
239          var elements = once('klaro-wrap', wrapperIdentifier, context);
240          Array.prototype.forEach.call(elements, function(el) {
241            if (el) {
242              var wrapper = document.createElement('div');
243              wrapper.setAttribute('data-name', service.name);
244              wrapper.setAttribute('data-original-display', getComputedStyle(el).display);
245              el.parentNode.insertBefore(wrapper, el);
246              wrapper.appendChild(el);
247            }
248          });
249        });
250      });
251    },
252
253    /**
254     * Watch for DOMchanges on klaro-element.
255     */
256    klaroElementObserver: function() {
257      var targetNode = document.getElementById("klaro");
258      if (Drupal.behaviors.klaro.observing || !targetNode) {
259        return;
260      }
261      Drupal.behaviors.klaro.observing = true;
262
263      const config = { childList: true, subtree: true };
264      const callback = (mutationList, observer) => {
265        for (const mutation of mutationList) {
266          if (mutation.type === "childList") {
267            Drupal.behaviors.klaro.klaroElementMutator();
268          }
269        }
270      };
271      // Create an observer instance linked to the callback function
272      const observer = new MutationObserver(callback);
273      observer.observe(targetNode, config);
274      Drupal.behaviors.klaro.klaroElementMutator();
275    },
276
277    /**
278     * Observer klaro element to adapt customizations.
279     */
280    klaroElementMutator: function() {
281
282      // Add minimal accessibility features to the customize consent dialog.
283      var labels = document.querySelectorAll('#klaro label')
284      if (labels.length > 0){
285        for (var i = 0; i < labels.length; i++) {
286          labels[i].setAttribute('onkeydown', 'Drupal.behaviors.klaro.KlaroToggleService(event)');
287          labels[i].setAttribute('aria-labelledby', labels[i].getAttribute('for') + '-title');
288          labels[i].setAttribute('aria-describedby', labels[i].getAttribute('for') + '-description');
289          if (labels[i].previousElementSibling && labels[i].previousElementSibling.tagName == 'INPUT') {
290            labels[i].previousElementSibling.setAttribute('tabindex', '0');
291            labels[i].removeAttribute('tabindex');
292          }
293        }
294        // Set focus to first possible label.
295        document.querySelector('#klaro input:not(:disabled)+label')?.focus();
296      }
297      // Add accessibility features to the preferences dialog : role dialog, aria-modal and aria-labelledby.
298      if (document.querySelector('.cm-modal.cm-klaro')) {
299        var elem = document.querySelector('.cm-modal.cm-klaro');
300        elem.setAttribute('role', 'dialog');
301        elem.setAttribute('aria-modal', 'true');
302        elem.querySelector('.cm-header .title').setAttribute('id', 'cm-modal-title');
303        elem.setAttribute('aria-labelledby', 'cm-modal-title');
304      }
305
306      // Handle close button X.
307      if (drupalSettings.klaro.show_close_button) {
308        if (document.querySelector('#klaro-cookie-notice')) {
309          var elem = document.querySelector('#klaro-cookie-notice');
310        }
311        else if (document.querySelector('.cm-modal.cm-klaro')) {
312          var elem = document.querySelector('.cm-modal.cm-klaro');
313          if ((Drupal.behaviors.klaro.manager.confirmed) && (!Drupal.behaviors.klaro.config.mustConsent)) {
314            elem = false;
315          }
316        }
317
318        if (elem && !document.querySelector('.klaro-close')) {
319          var close_label = Drupal.t("Close dialog and decline all", {},{context: 'klaro'});
320          var close_html = '<button title="' + close_label + '" type="button" class="cn-decline klaro-close" tabindex="0" aria-label="' + close_label + '"></button>';
321          elem.insertAdjacentHTML('beforeend', close_html);;
322          document.querySelector('.klaro-close')?.addEventListener('click', (e) => {
323            Drupal.behaviors.klaro.manager.changeAll(false);
324            Drupal.behaviors.klaro.manager.saveAndApplyConsents();
325          }, false);
326          document.querySelector('.klaro').classList.add('klaro-close-enabled');
327          document.querySelector('.klaro .cookie-modal .cm-modal .hide')?.remove();
328        }
329      }
330
331    },
332    KlaroToggleService: function(event) {
333      if (event.key === "Enter") {
334        event.target.click();
335        event.target.focus();
336      }
337    }
338  };
339
340  /**
341   * Open the Klaro! consent notice from links & buttons.
342   */
343  Drupal.behaviors.klaroLink = {
344    attach: function (context, settings) {
345      var elements = once('klaroLink', '[rel*="open-consent-manager"], [href*="#klaro"], .open-consent-manager', context);
346      Array.prototype.forEach.call(elements, function(element) {
347        element.addEventListener('click', function (event) {
348          klaro.show(Drupal.behaviors.klaro.config);
349          event.preventDefault();
350          return false;
351        });
352      });
353    }
354  };
355})(Drupal, drupalSettings);

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.