PageSourceSearch

https://internationalnewsledger.com/js/controllers/alertDialog.js?v9e91e12689728780f01d6dd9a70eb5c9bae56d64

js internationalnewsledger.com collected 2026-09-29 11:35:39 UTC 6,450 bytes, 221 lines download raw bytes

1import dialogController from "./dialog.js";
2import { postJson, EMAIL_REGEX } from "../utils/fetchUtils.js";
3
4const COOKIE_NAME = 'alert-dialog-suppressed';
5const AUTO_SHOW_DELAY_MS = 5000;
6const ERROR_GENERIC = 'An error occurred. Please try again later.';
7
8window.AlertDialog = {
9  controller: null,
10  openDialog: function () {
11    if (this.controller) {
12      this.controller.open();
13    } else {
14      console.error("Alert dialog controller is not initialized");
15    }
16  }
17};
18
19export default class extends dialogController {
20  static targets = [
21    "emailInput", "userEmail", "errorMessage",
22    "subscribeForm", "checkEmail", "welcomeBack", "welcomeBackEmail",
23    "activated", "alreadyActivated", "activateErrorMessage",
24    "deactivated", "alreadyDeactivated", "deactivateErrorMessage"
25  ];
26
27  #submittedSuccessfully = false;
28  #openedFromQueryParam = false;
29  #autoShowTimer = null;
30  #autoShowIdleId = null;
31  #closeListener = null;
32
33  open() {
34    this.emailInputTargets.forEach(target => target.value = "");
35    this.errorMessageTargets.forEach(target => target.innerText = "");
36    this.subscribeFormTarget.classList.remove("hidden");
37    this.checkEmailTarget.classList.add("hidden");
38    this.welcomeBackTarget.classList.add("hidden");
39    this.hideAllStatusMessages();
40    this.modalTarget.show();
41  }
42
43  connect() {
44    window.AlertDialog.controller = this;
45
46    this.#closeListener = this.#onModalClose.bind(this);
47    this.modalTarget.addEventListener("close", this.#closeListener);
48
49    this.#openedFromQueryParam = this.#showMessageFromQueryParam();
50
51    if (!this.#openedFromQueryParam && !this.#hasSuppressCookie() && !this.#isPhone()) {
52      this.#autoShowTimer = setTimeout(() => this.#openWhenIdle(), AUTO_SHOW_DELAY_MS);
53    }
54  }
55
56  disconnect() {
57    if (window.AlertDialog.controller === this) {
58      window.AlertDialog.controller = null;
59    }
60
61    if (this.#closeListener) {
62      this.modalTarget.removeEventListener("close", this.#closeListener);
63      this.#closeListener = null;
64    }
65
66    if (this.#autoShowTimer) {
67      clearTimeout(this.#autoShowTimer);
68      this.#autoShowTimer = null;
69    }
70
71    if (this.#autoShowIdleId && "cancelIdleCallback" in window) {
72      cancelIdleCallback(this.#autoShowIdleId);
73      this.#autoShowIdleId = null;
74    }
75  }
76
77  #openWhenIdle() {
78    if ("requestIdleCallback" in window) {
79      this.#autoShowIdleId = requestIdleCallback(() => this.open(), { timeout: 2000 });
80    } else {
81      this.open();
82    }
83  }
84
85  #onModalClose() {
86    this.enableBodyScroll();
87
88    if (this.#autoShowTimer) {
89      clearTimeout(this.#autoShowTimer);
90      this.#autoShowTimer = null;
91    }
92
93    if (this.#openedFromQueryParam) return;
94
95    if (this.#submittedSuccessfully) {
96      this.#suppressIndefinitely();
97    } else {
98      this.#suppressFor24h();
99    }
100  }
101
102  #isPhone() {
103    return window.matchMedia("(max-width: 767px)").matches;
104  }
105
106  #hasSuppressCookie() {
107    return document.cookie.split(';').some(c => c.trim().startsWith(`${COOKIE_NAME}=`));
108  }
109
110  #suppressFor24h() {
111    const expires = new Date(Date.now() + 24 * 60 * 60 * 1000).toUTCString();
112    document.cookie = `${COOKIE_NAME}=1; expires=${expires}; path=/; SameSite=Lax`;
113  }
114
115  #suppressIndefinitely() {
116    const expires = new Date('2099-01-01').toUTCString();
117    document.cookie = `${COOKIE_NAME}=1; expires=${expires}; path=/; SameSite=Lax`;
118  }
119
120  #showMessageFromQueryParam() {
121    const urlParams = new URLSearchParams(window.location.search);
122    const status = urlParams.get("alert-status");
123
124    const statusElement = status && {
125      "activated": this.activatedTarget,
126      "already_activated": this.alreadyActivatedTarget,
127      "activation_error": this.activateErrorMessageTarget,
128      "deactivated": this.deactivatedTarget,
129      "already_deactivated": this.alreadyDeactivatedTarget,
130      "deactivation_error": this.deactivateErrorMessageTarget
131    }[status];
132
133    if (statusElement) {
134      this.open();
135      this.subscribeFormTarget.classList.add("hidden");
136      this.hideAllStatusMessages();
137      statusElement.classList.remove("hidden");
138      return true;
139    }
140
141    return false;
142  }
143
144  hideAllStatusMessages() {
145    [
146      this.activatedTarget,
147      this.alreadyActivatedTarget,
148      this.activateErrorMessageTarget,
149      this.deactivatedTarget,
150      this.alreadyDeactivatedTarget,
151      this.deactivateErrorMessageTarget
152    ].forEach(target => target.classList.add("hidden"));
153  }
154
155  async submit(event) {
156    event.preventDefault();
157
158    const form = event.target;
159    const emailInput = form.querySelector('[data-alert-dialog-target="emailInput"]');
160    const errorMessage = form.querySelector('[data-alert-dialog-target="errorMessage"]');
161    const fullnameInput = form.querySelector('[data-alert-dialog-target="fullnameInput"]');
162    const timestampInput = form.querySelector('[data-alert-dialog-target="timestampInput"]');
163    const submitButton = form.querySelector('button[type="submit"]');
164
165    errorMessage.innerText = "";
166
167    const email = emailInput.value.trim();
168
169    if (!EMAIL_REGEX.test(email)) {
170      errorMessage.innerText = "Please enter a valid email address";
171      return;
172    }
173
174    submitButton.disabled = true;
175
176    try {
177      const response = await postJson('/alerts', {
178        email,
179        fullname: fullnameInput.value,
180        timestamp: timestampInput.value,
181      });
182
183      if (response.ok) {
184        this.#showCheckEmail(email);
185        return;
186      }
187
188      if (response.status === 409) {
189        this.#showWelcomeBack(email);
190        return;
191      }
192
193      errorMessage.innerText = response.status === 422
194        ? "Please enter a valid email address"
195        : ERROR_GENERIC;
196    } catch {
197      errorMessage.innerText = ERROR_GENERIC;
198    } finally {
199      submitButton.disabled = false;
200    }
201  }
202
203  #showCheckEmail(email) {
204    this.#submittedSuccessfully = true;
205    this.subscribeFormTargets.forEach(target => target.classList.add('hidden'));
206    this.userEmailTarget.innerText = email;
207    this.checkEmailTarget.classList.remove('hidden');
208  }
209
210  #showWelcomeBack(email) {
211    this.subscribeFormTargets.forEach(target => target.classList.add('hidden'));
212    this.welcomeBackEmailTarget.innerText = email;
213    this.welcomeBackTarget.classList.remove('hidden');
214  }
215
216  showForm(event) {
217    event.preventDefault();
218    this.subscribeFormTarget.classList.remove('hidden');
219    this.checkEmailTarget.classList.add('hidden');
220  }
221}

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.