PageSourceSearch

https://alumni.lehigh.edu/modules/contrib/klaro/js/klaro.drupal.js?tlu0g7

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