PageSourceSearch

https://deltagas.com/modules/contrib/sitewide_alert/js/init.js?v=10.6.17

js deltagas.com collected 2026-10-05 18:01:08 UTC 8,456 bytes, 270 lines download raw bytes

1(function (Drupal, drupalSettings, once) {
2  const sitewideAlertsSelector = '[data-sitewide-alert]';
3
4  const shouldShowOnThisPage = (pages = [], negate = true) => {
5    if (pages.length === 0) {
6      return true;
7    }
8
9    let pagePathMatches = false;
10    const currentPath = window.location.pathname;
11
12    for (let i = 0; i < pages.length; i++) {
13      const baseUrl = drupalSettings.path.baseUrl.slice(0, -1);
14      const page = baseUrl + pages[i];
15      // Check if we have to deal with a wild card.
16      if (page.charAt(page.length - 1) === '*') {
17        if (currentPath.startsWith(page.substring(0, page.length - 1))) {
18          pagePathMatches = true;
19          break;
20        }
21      } else if (page === currentPath) {
22        pagePathMatches = true;
23        break;
24      }
25    }
26
27    return negate ? !pagePathMatches : pagePathMatches;
28  };
29
30  const alertWasDismissed = (alert) => {
31    if (!(`alert-dismissed-${alert.uuid}` in window.localStorage)) {
32      return false;
33    }
34
35    const dismissedAtTimestamp = Number(
36      window.localStorage.getItem(`alert-dismissed-${alert.uuid}`)
37    );
38
39    // If the visitor has already dismissed the alert, but we are supposed to ignore dismissals before a set date.
40    return dismissedAtTimestamp >= alert.dismissalIgnoreBefore;
41  };
42
43  const dismissAlert = (alert) => {
44    window.localStorage.setItem(
45      `alert-dismissed-${alert.uuid}`,
46      String(Math.round(new Date().getTime() / 1000))
47    );
48    document
49      .querySelectorAll(`[data-uuid="${alert.uuid}"]`)
50      .forEach((alert) => {
51        alert.dispatchEvent(
52          new CustomEvent('sitewide-alert-dismissed', {
53            bubbles: true,
54            composed: true
55          })
56        );
57        removeAlert(alert);
58      });
59  };
60
61  const buildAlertElement = (alert) => {
62    const alertElement = document.createElement('div');
63    alertElement.innerHTML = alert.renderedAlert;
64
65    if (alert.dismissible) {
66      const dismissButtons =
67        alertElement.getElementsByClassName('js-dismiss-button');
68      for (let i = 0; i < dismissButtons.length; i++) {
69        dismissButtons[i].addEventListener('click', () => dismissAlert(alert));
70      }
71    }
72
73    return alertElement.firstElementChild;
74  };
75
76  const removeAlert = (alert) => {
77    alert.dispatchEvent(
78      new CustomEvent('sitewide-alert-removed', {
79        bubbles: true,
80        composed: true
81      })
82    );
83
84    alert.remove();
85  };
86
87  const fetchAlerts = () => {
88    return fetch(
89      `${
90        window.location.origin +
91        drupalSettings.path.baseUrl +
92        drupalSettings.path.pathPrefix
93      }sitewide_alert/load`
94    )
95      .then((res) => res.json())
96      .then(
97        (result) => result.sitewideAlerts,
98        // Note: it's important to handle errors here
99        // instead of a catch() block so that we don't swallow
100        // exceptions from actual bugs in components.
101        (error) => {
102          console.error(error);
103        }
104      );
105  };
106
107  const removeStaleAlerts = (alerts) => {
108    const roots = document.querySelectorAll(sitewideAlertsSelector);
109    roots.forEach((root) => {
110      const existingAlerts = root.querySelectorAll('[data-uuid]');
111
112      // We have to convert and filter existing alerts based on newly fetched alerts.
113      // This can be done by comparing uuids.
114      // If the uuid can't be found in fetched alerts,
115      // the alert with the same uuid should be removed.
116      const alertsToBeRemoved = Array.from(existingAlerts).filter(
117        (alert) => !alerts.includes(alert.getAttribute('data-uuid'))
118      );
119
120      alertsToBeRemoved.forEach((alert) => removeAlert(alert));
121    });
122  };
123
124  const initAlerts = () => {
125    const roots = document.querySelectorAll(sitewideAlertsSelector);
126    // Fetch alerts and prepare rendering.
127    fetchAlerts().then((alerts) => {
128      removeStaleAlerts(alerts);
129      alerts.forEach((alert) => {
130        // Check if alert has been dismissed.
131        const dismissed = alertWasDismissed(alert);
132        // Check if current page is one of the pages the alert should be shown on or not.
133        const showOnThisPage = shouldShowOnThisPage(
134          alert.showOnPages,
135          alert.negateShowOnPages
136        );
137        roots.forEach((root) => {
138          // Check for existing alert element.
139          const existingAlertElement = root.querySelector(
140            `[data-uuid="${alert.uuid}"]`
141          );
142
143          if (showOnThisPage && !dismissed) {
144            const renderableAlertElement = buildAlertElement(alert);
145            // To prevent an alert from being rendered multiple times
146            // replace the old alert with the new one when new alerts are being fetched.
147            existingAlertElement
148              ? root.replaceChild(renderableAlertElement, existingAlertElement)
149              : root.appendChild(renderableAlertElement);
150
151            renderableAlertElement.dispatchEvent(
152              new CustomEvent('sitewide-alert-rendered', {
153                bubbles: true,
154                composed: true
155              })
156            );
157
158            return;
159          }
160
161          // Remove alert if it is on the page and should no longer be.
162          if ((dismissed || !showOnThisPage) && existingAlertElement) {
163            removeAlert(existingAlertElement);
164          }
165        });
166      });
167    });
168  };
169
170  /**
171   * Check if window.history pushstate is available
172   * @returns {boolean}
173   */
174  const supportsHistoryPushState = () => {
175    return (
176      'pushState' in window.history && window.history['pushState'] !== null
177    );
178  };
179
180  /**
181   * Check if window.history replaceState is available
182   * @returns {boolean}
183   */
184  const supportsHistoryReplaceState = () => {
185    return (
186      'replaceState' in window.history &&
187      window.history['replaceState'] !== null
188    );
189  };
190
191  /**
192   * Add Proxy to standard pushState function to fire CustomEvent.
193   *
194   * Nor history.pushState either history.replaceState will trigger a popstate event.
195   * Therefor a proxy behaviour is added to trigger a CustomEvent whenever the history is changed.
196   *
197   * @see https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
198   * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event
199   */
200  const proxyPushState = () => {
201    if (supportsHistoryPushState()) {
202      window.history.pushState = new Proxy(window.history.pushState, {
203        apply(target, thisArg, argArray) {
204          // triggerEvent
205          triggerHistoryEvent(thisArg, argArray);
206          // execute original
207          return target.apply(thisArg, argArray);
208        }
209      });
210    }
211    if (supportsHistoryReplaceState()) {
212      window.history.replaceState = new Proxy(window.history.replaceState, {
213        apply(target, thisArg, argArray) {
214          // triggerEvent
215          triggerHistoryEvent(thisArg, argArray);
216          // execute original
217          return target.apply(thisArg, argArray);
218        }
219      });
220    }
221  };
222
223  /**
224   * Trigger CustomEvent sitewidealerts.popstate.
225   *
226   * @param thisArg
227   * @param argArray
228   */
229  const triggerHistoryEvent = (thisArg, argArray) => {
230    const event = new CustomEvent('sitewidealerts.popstate', {
231      detail: { state: thisArg, options: argArray }
232    });
233    window.dispatchEvent(event);
234  };
235
236  /**
237   * Reinitialize the alters on A: CustomEvent and B: Standard popstate.
238   *
239   * @see shouldShowOnThisPage
240   * @see initAlerts
241   */
242  const historyListener = () => {
243    window.addEventListener('sitewidealerts.popstate', () => initAlerts());
244    window.addEventListener('popstate', () => initAlerts());
245  };
246
247  Drupal.behaviors.sitewide_alert_init = {
248    attach: (context) => {
249      once('sitewide_alerts_init', 'html', context).forEach(() => {
250        // On load.
251        initAlerts();
252        proxyPushState();
253        historyListener();
254        if (drupalSettings.sitewideAlert.automaticRefresh === true) {
255          const interval = setInterval(
256            () => initAlerts(),
257            drupalSettings.sitewideAlert.refreshInterval < 1000
258              ? 1000
259              : drupalSettings.sitewideAlert.refreshInterval
260          );
261          // Clear interval if automatic refresh has been turned off.
262          // Only do this if an interval has previously been set.
263          if (!drupalSettings.sitewideAlert.automaticRefresh) {
264            clearInterval(interval);
265          }
266        }
267      });
268    }
269  };
270})(Drupal, drupalSettings, once);

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.