PageSourceSearch

https://www.red.es/modules/contrib/klaro/js/klaro.drupal.js?tkmstj

js red.es collected 2026-09-24 08:27:04 UTC 14,539 bytes, 360 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        try {
172          Function('consent', 'service', service.callbackCode)(consent, service);
173        }
174        catch (error) {
175          console.error('Error executing callback code for service "' + service.name + '":', error);
176        }
177      }
178
179      // Do the behaviors only for consent.
180      if (!consent) {
181        return;
182      }
183
184      // Rewrite data-id to id.
185      var elements = document.querySelectorAll('[data-name="' + service.name + '"][data-id]');
186      if (elements.length > 0) {
187        Array.prototype.forEach.call(elements, function(element) {
188          element.setAttribute('id', element.getAttribute('data-id'));
189        });
190        if (Drupal.behaviors.klaro.ready) {
191          Drupal.attachBehaviors(document, drupalSettings);
192        }
193        else {
194          Drupal.behaviors.klaro.needCallBehaviors = true;
195        }
196      }
197
198      let knownBehaviors = Object.keys(Drupal.behaviors);
199      var elements = document.querySelectorAll('[data-name="' + service.name + '"][src]');
200      if (!elements) {
201        return;
202      }
203
204      // #3459261 Fix HtmlMediaElements not loading correctly.
205      var source_tags = document.querySelectorAll('source[data-name="' + service.name + '"]');
206      if (source_tags.length > 0) {
207        var loading_state;
208        for (var i = 0; i < source_tags.length; i++) {
209          loading_state = source_tags[i].parentElement.readyState;
210          if (loading_state == 0 || loading_state == 1) {
211            source_tags[i].parentElement.load();
212          }
213        }
214      }
215
216      function processBehaviors() {
217        for (let name in Drupal.behaviors) {
218          if (knownBehaviors.indexOf(name) === -1) {
219            // Execute newly added behaviors. This is somewhat guesswork, as
220            // the order of execution is undetermined based on file load order.
221            Drupal.behaviors[name].attach(document, drupalSettings);
222            knownBehaviors.push(name);
223          }
224        }
225      }
226
227      Array.prototype.forEach.call(elements, function(element) {
228        if (element.complete) {
229          processBehaviors();
230        }
231        else {
232          element.addEventListener('load', processBehaviors);
233        }
234      });
235    },
236
237    /**
238     * Decorate wrapperIdentifiers in context.
239     */
240    klaroDecorateWrapper: function(context, settings) {
241      // Iterate services and wrapperIdentifier.
242      settings.klaro.config.services.forEach(function(service, a_index) {
243        service.wrapperIdentifier.forEach(function(wrapperIdentifier) {
244          var elements = once('klaro-wrap', wrapperIdentifier, context);
245          Array.prototype.forEach.call(elements, function(el) {
246            if (el) {
247              var wrapper = document.createElement('div');
248              wrapper.setAttribute('data-name', service.name);
249              wrapper.setAttribute('data-original-display', getComputedStyle(el).display);
250              el.parentNode.insertBefore(wrapper, el);
251              wrapper.appendChild(el);
252            }
253          });
254        });
255      });
256    },
257
258    /**
259     * Watch for DOMchanges on klaro-element.
260     */
261    klaroElementObserver: function() {
262      var targetNode = document.getElementById("klaro");
263      if (Drupal.behaviors.klaro.observing || !targetNode) {
264        return;
265      }
266      Drupal.behaviors.klaro.observing = true;
267
268      const config = { childList: true, subtree: true };
269      const callback = (mutationList, observer) => {
270        for (const mutation of mutationList) {
271          if (mutation.type === "childList") {
272            Drupal.behaviors.klaro.klaroElementMutator();
273          }
274        }
275      };
276      // Create an observer instance linked to the callback function
277      const observer = new MutationObserver(callback);
278      observer.observe(targetNode, config);
279      Drupal.behaviors.klaro.klaroElementMutator();
280    },
281
282    /**
283     * Observer klaro element to adapt customizations.
284     */
285    klaroElementMutator: function() {
286
287      // Add minimal accessibility features to the customize consent dialog.
288      var labels = document.querySelectorAll('#klaro label')
289      if (labels.length > 0){
290        for (var i = 0; i < labels.length; i++) {
291          labels[i].setAttribute('onkeydown', 'Drupal.behaviors.klaro.KlaroToggleService(event)');
292          labels[i].setAttribute('aria-labelledby', labels[i].getAttribute('for') + '-title');
293          labels[i].setAttribute('aria-describedby', labels[i].getAttribute('for') + '-description');
294          if (labels[i].previousElementSibling && labels[i].previousElementSibling.tagName == 'INPUT') {
295            labels[i].previousElementSibling.setAttribute('tabindex', '0');
296            labels[i].removeAttribute('tabindex');
297          }
298        }
299        // Set focus to first possible label.
300        document.querySelector('#klaro input:not(:disabled)+label')?.focus();
301      }
302      // Add accessibility features to the preferences dialog : role dialog, aria-modal and aria-labelledby.
303      if (document.querySelector('.cm-modal.cm-klaro')) {
304        var elem = document.querySelector('.cm-modal.cm-klaro');
305        elem.setAttribute('role', 'dialog');
306        elem.setAttribute('aria-modal', 'true');
307        elem.querySelector('.cm-header .title').setAttribute('id', 'cm-modal-title');
308        elem.setAttribute('aria-labelledby', 'cm-modal-title');
309      }
310
311      // Handle close button X.
312      if (drupalSettings.klaro.show_close_button) {
313        if (document.querySelector('#klaro-cookie-notice')) {
314          var elem = document.querySelector('#klaro-cookie-notice');
315        }
316        else if (document.querySelector('.cm-modal.cm-klaro')) {
317          var elem = document.querySelector('.cm-modal.cm-klaro');
318          if ((Drupal.behaviors.klaro.manager.confirmed) && (!Drupal.behaviors.klaro.config.mustConsent)) {
319            elem = false;
320          }
321        }
322
323        if (elem && !document.querySelector('.klaro-close')) {
324          var close_label = Drupal.t("Close dialog and decline all", {},{context: 'klaro'});
325          var close_html = '<button title="' + close_label + '" type="button" class="cn-decline klaro-close" tabindex="0" aria-label="' + close_label + '"></button>';
326          elem.insertAdjacentHTML('beforeend', close_html);;
327          document.querySelector('.klaro-close')?.addEventListener('click', (e) => {
328            Drupal.behaviors.klaro.manager.changeAll(false);
329            Drupal.behaviors.klaro.manager.saveAndApplyConsents();
330          }, false);
331          document.querySelector('.klaro').classList.add('klaro-close-enabled');
332          document.querySelector('.klaro .cookie-modal .cm-modal .hide')?.remove();
333        }
334      }
335
336    },
337    KlaroToggleService: function(event) {
338      if (event.key === "Enter") {
339        event.target.click();
340        event.target.focus();
341      }
342    }
343  };
344
345  /**
346   * Open the Klaro! consent notice from links & buttons.
347   */
348  Drupal.behaviors.klaroLink = {
349    attach: function (context, settings) {
350      var elements = once('klaroLink', '[rel*="open-consent-manager"], [href*="#klaro"], .open-consent-manager', context);
351      Array.prototype.forEach.call(elements, function(element) {
352        element.addEventListener('click', function (event) {
353          klaro.show(Drupal.behaviors.klaro.config);
354          event.preventDefault();
355          return false;
356        });
357      });
358    }
359  };
360})(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.