PageSourceSearch

https://www.kreis-kleve.de/modules/contrib/cookies_open_readspeaker/js/cookies_open_readspeaker.js?v=10.6.18

js kreis-kleve.de collected 2026-10-02 11:33:16 UTC 5,854 bytes, 144 lines download raw bytes

1/**
2 * @file
3 * Defines Javascript behaviors for the cookies module.
4 * These are invoked once the user performs a cookie consent
5 * action like: accept / deny / revoke to immediately
6 * react on that with loading a script, video, iframe, etc.
7 * or if consent is revoked, removing existing cookies,
8 * stop tracking or similar.
9 *
10 * This is NOT invoked on each page load, only immediately, when the user
11 * takes concrete action in the COOKiES banner.
12 */
13
14(function (Drupal) {
15  "use strict";
16
17  /**
18   * Define defaults.
19   */
20  Drupal.behaviors.cookies_open_readspeaker = {
21    // id corresponding to the cookies_service.schema->id.
22    id: "open_readspeaker",
23    cssNodeId: "rsmod_Styles",
24    blockSelector: "div[data-block-plugin-id=\"open_readspeaker_block\"]",
25    scriptSelector: "script[data-sid=\"open_readspeaker_external\"]",
26
27    /**
28     * Called when consent was given.
29     */
30    consentGiven: function (context, observer) {
31      // Select the node that will be observed for mutations
32      const targetNode = document.getElementById(this.cssNodeId)?.parentNode ?? document.head;
33      // Start observing the target node
34      observer.observe(targetNode, {childList: true});
35
36      // Find all external script tags for open readspeaker.
37      document.querySelectorAll(this.scriptSelector)
38        .forEach((nodeScript) => {
39          if (nodeScript.getAttribute("type") === "text/javascript") {
40            // No need to replace node because it is already from type text/javascript.
41            return;
42          }
43          // Build new script node.
44          const newNodeScript = document.createElement(nodeScript.tagName);
45          Array.from(nodeScript.attributes)
46            .forEach((attr) => {
47              newNodeScript.setAttribute(attr.name, attr.name === "type" ? "text/javascript" : attr.value);
48            });
49          newNodeScript.innerHTML = nodeScript.innerHTML;
50          // Replace script node so that the javascript is evaluated.
51          nodeScript.replaceWith(newNodeScript);
52        });
53
54      // Show the block
55      document.querySelectorAll(this.blockSelector).forEach((element) => element.style.display = "");
56    },
57
58    /**
59     * Called when consent was denied / revoked.
60     */
61    consentDenied: function (context) {
62      /**
63       * Get an array of all cookie names. Can optionally be filtered by the parameter 'names'.
64       * @param {string[]} names If provided, only check for these cookies.
65       * @returns {string[]} Array with cookie names.
66       */
67      const getCookieNames = (names = []) => decodeURIComponent(document.cookie).split(";")
68        .map(cookie => cookie.trimStart().split("=", 1).toString())
69        .filter(cookieName => names.length > 0 ? names.includes(cookieName) : true);
70      let needReload = false;
71      // Hide the block
72      document.querySelectorAll(this.blockSelector).forEach((element) => element.style.display = "none");
73      // Remove cookies
74      const cookieNames = ["_rspkrLoadCore", "ReadSpeakerSettings"];
75      const paths = ['/', window.location.pathname];
76      getCookieNames(cookieNames).forEach((name) => {
77        paths.forEach(path => {
78          document.cookie = `${name}=;path=${path};max-age=0;`;
79          const domainParts = window.location.hostname.split('.');
80          while (domainParts.length > 1) {
81            const domain = domainParts.join('.');
82            document.cookie = `${name}=;path=${path};domain=${domain};max-age=0;`;
83            domainParts.shift();
84          }
85        });
86        needReload = true;
87      });
88      // Check script types if there were no cookies to delete
89      if (!needReload) {
90        document.querySelectorAll(this.scriptSelector)
91          .forEach((nodeScript) => {
92            if (nodeScript.getAttribute("type") === "text/javascript") {
93              needReload = true;
94            }
95          });
96      }
97      // Reload page
98      if (needReload) {
99        location.reload();
100      }
101    },
102
103    attach: function (context) {
104      const self = this;
105      // Observer to replace readspeaker css if it is set with wrong href link
106      const observer = new MutationObserver((mutationList, observer) => {
107        for (const mutation of mutationList) {
108          if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
109            mutation.addedNodes.forEach(node => {
110              if (node.type === "text/css" && node.nodeName === "LINK" && node.id === self.cssNodeId) {
111                let scriptNode = document.querySelector(self.scriptSelector);
112                if (scriptNode != null) {
113                  let src = scriptNode.src.substring(0, scriptNode.src.lastIndexOf("/") + 1);
114                  let href = node.href;
115                  let newHref = href.replace(/.*(?=\w\/\w\d+\/ReadSpeaker)/, src);
116                  observer.disconnect();
117                  if (newHref !== href) {
118                    let newNode = document.createElement(node.tagName);
119                    Array.from(node.attributes)
120                      .forEach((attr) => {
121                        newNode.setAttribute(attr.name, attr.name === "href" ? newHref : attr.value);
122                      });
123                    newNode.innerHTML = node.innerHTML;
124                    node.replaceWith(newNode);
125                  }
126                }
127              }
128            });
129          }
130        }
131      });
132      document.addEventListener("cookiesjsrUserConsent", function (event) {
133        const service = (typeof event.detail.services === "object") ? event.detail.services : {};
134        if (typeof service[self.id] !== "undefined" && service[self.id]) {
135          // Consent was given:
136          self.consentGiven(context, observer);
137        } else {
138          // Consent was denied/revoked.
139          self.consentDenied(context);
140        }
141      });
142    },
143  };
144})(Drupal);

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.