1(() => { 2 "use strict"; 3 4 if (globalThis.mlAltchaAccessibility?.initialized) { 5 return; 6 } 7 8 const config = globalThis.mlAltchaA11y || {}; 9 const cspNonce = document.currentScript?.nonce 10 || document.querySelector("script[nonce], style[nonce]")?.nonce 11 || ""; 12 const messages = { 13 code: "An additional verification is required.", 14 error: "The verification could not be completed. Please submit the form again.", 15 expired: "The verification expired. Please submit the form again.", 16 verified: "The input was verified. The form is being submitted.", 17 verifying: "The input is being verified. Please wait.", 18 ...(config.messages || {}), 19 }; 20 const timeouts = { 21 code: Number(config.timeouts?.code) || 300000, 22 submit: Number(config.timeouts?.submit) || 15000, 23 verification: Number(config.timeouts?.verification) || 180000, 24 }; 25 const shadowStyles = ` 26:host { 27 color-scheme: only light; 28 --altcha-border-color: #595959 !important; 29 --altcha-border-width: 2px !important; 30 --altcha-border-radius: 6px !important; 31 --altcha-color-base: #ffffff !important; 32 --altcha-color-base-content: #1a1a1a !important; 33 --altcha-color-error: #b42318 !important; 34 --altcha-color-error-content: #ffffff !important; 35 --altcha-color-neutral: #e5e7eb !important; 36 --altcha-color-neutral-content: #1f2937 !important; 37 --altcha-color-primary: #1d1dc9 !important; 38 --altcha-color-primary-content: #ffffff !important; 39 --altcha-color-success: #137333 !important; 40 --altcha-color-success-content: #ffffff !important; 41 --altcha-checkbox-border-color: #595959 !important; 42 --altcha-checkbox-outline-color: #1d1dc9 !important; 43 --altcha-spinner-color: #1a1a1a !important; 44} 45 46.altcha-overlay-close, 47.altcha-popover-close { 48 display: none !important; 49 pointer-events: none !important; 50} 51 52.altcha-overlay-backdrop, 53.altcha-popover-backdrop { 54 background: rgb(15 23 42 / 62%) !important; 55 opacity: 1 !important; 56 z-index: 2147483646 !important; 57} 58 59.altcha[data-display="overlay"], 60.altcha-popover[data-display="overlay"] { 61 animation: none !important; 62 opacity: 1 !important; 63 top: 50% !important; 64 z-index: 2147483647 !important; 65} 66 67.altcha-main { 68 background: #ffffff !important; 69 border-color: #595959 !important; 70 color: #1a1a1a !important; 71} 72 73.altcha-main label, 74.altcha-footer, 75.altcha-footer p { 76 color: #1a1a1a !important; 77} 78 79.altcha-checkbox input { 80 background: #ffffff !important; 81 border-color: #595959 !important; 82} 83 84.altcha-checkbox input:checked { 85 background: #137333 !important; 86 border-color: #137333 !important; 87} 88 89.altcha-checkbox input:checked + svg { 90 color: #ffffff !important; 91} 92 93.altcha-button { 94 background: #1d1dc9 !important; 95 border-color: #1d1dc9 !important; 96 color: #ffffff !important; 97} 98 99.altcha-button-secondary { 100 background: #ffffff !important; 101 border-color: #595959 !important; 102 color: #1f2937 !important; 103} 104 105.altcha-input { 106 background: #ffffff !important; 107 border-color: #595959 !important; 108 color: #1a1a1a !important; 109} 110 111.altcha-footer, 112.altcha-logo { 113 opacity: 1 !important; 114} 115 116.altcha:focus-visible, 117.altcha :focus-visible, 118.altcha-popover:focus-visible, 119.altcha-popover :focus-visible { 120 outline: 3px solid #1d1dc9 !important; 121 outline-offset: 3px !important; 122} 123 124.altcha .altcha-footer a, 125.altcha .altcha-footer a:visited, 126.altcha a.altcha-logo, 127.altcha a.altcha-logo:visited { 128 align-items: center; 129 background: none !important; 130 color: inherit !important; 131 display: inline-flex; 132 min-height: 24px; 133 text-decoration: underline; 134 text-decoration-thickness: 2px; 135 text-underline-offset: 2px; 136} 137 138.altcha .altcha-footer a:hover, 139.altcha a.altcha-logo:hover { 140 color: #1d1dc9 !important; 141} 142 143@media (prefers-reduced-motion: reduce) { 144 .altcha[data-display="overlay"], 145 .altcha-popover[data-display="overlay"], 146 .altcha-overlay-backdrop, 147 .altcha-popover-backdrop, 148 .altcha-spinner { 149 animation: none !important; 150 transition: none !important; 151 } 152} 153`; 154 155 const controllers = new WeakMap(); 156 const controllerInstances = new Set(); 157 const activeModalInstances = new Set(); 158 const inertRegistry = new Map(); 159 let nextInstanceId = 0; 160 let documentObserver = null; 161 162 function normalizeLocale(value) { 163 return String(value || "en-US").replace(/_/g, "-").toLowerCase(); 164 } 165 166 function registerLocale() { 167 const altcha = globalThis.$altcha; 168 const widgetMessages = config.widget; 169 if (!altcha?.i18n?.set || !widgetMessages || typeof widgetMessages !== "object") { 170 return; 171 } 172 173 const locale = normalizeLocale(config.locale || document.documentElement.lang || navigator.language); 174 const language = locale.split("-")[0]; 175 for (const key of new Set([language, locale])) { 176 const existing = altcha.i18n.get?.(key) || {}; 177 altcha.i18n.set(key, { ...existing, ...widgetMessages }); 178 } 179 } 180 181 function syncPageLock() { 182 const active = activeModalInstances.size > 0; 183 document.documentElement.classList.toggle("ml-altcha-modal-active", active); 184 document.body?.classList.toggle("ml-altcha-overlay-active", active);
185 syncBackgroundInert(); 186 } 187 188 function getTopActiveController() { 189 const active = [...activeModalInstances]; 190 return active.length ? active[active.length - 1] : null; 191 } 192 193 function getDeepActiveElement() { 194 let active = document.activeElement; 195 while (active?.shadowRoot?.activeElement) { 196 active = active.shadowRoot.activeElement; 197 } 198 return active; 199 } 200 201 function isVisible(element) { 202 if (!(element instanceof HTMLElement) || element.hidden) { 203 return false; 204 } 205 const style = getComputedStyle(element); 206 return style.display !== "none" && style.visibility !== "hidden"; 207 } 208 209 function queueTask(callback) { 210 if (typeof queueMicrotask === "function") { 211 queueMicrotask(callback); 212 } else { 213 Promise.resolve().then(callback); 214 } 215 } 216 217 function isActiveSurface(element, controller) { 218 if ( 219 element === controller.widget 220 || element === controller.statusRegion 221 || element === controller.alertRegion 222 || element === controller.feedback 223 || element === controller.dialogElement 224 || (controller.dialogElement && element.contains(controller.dialogElement)) 225 ) { 226 return true; 227 } 228 return element.matches?.( 229 ".altcha-popover, .altcha-popover-backdrop, .altcha-overlay-backdrop" 230 ); 231 } 232
233 function restoreBackground() { 234 for (const [element, state] of inertRegistry) { 235 element.inert = state.inert; 236 if (!state.hadInertAttribute) { 237 element.removeAttribute("inert"); 238 } 239 } 240 inertRegistry.clear(); 241 } 242 243 function syncBackgroundInert() { 244 restoreBackground(); 245 const controller = getTopActiveController(); 246 if (!controller?.modalActive || !controller.widget.isConnected) { 247 return; 248 } 249 250 let current = controller.widget; 251 while (current && current !== document.body) { 252 const parent = current.parentElement; 253 if (!parent) { 254 break; 255 } 256 257 for (const sibling of parent.children) { 258 if ( 259 sibling === current 260 || !(sibling instanceof HTMLElement) 261 || isActiveSurface(sibling, controller) 262 ) { 263 continue; 264 } 265 266 inertRegistry.set(sibling, { 267 hadInertAttribute: sibling.hasAttribute("inert"), 268 inert: Boolean(sibling.inert), 269 }); 270 sibling.inert = true; 271 sibling.setAttribute("inert", ""); 272 } 273 current = parent; 274 } 275 } 276 277 function visitWidgets(root, callback) { 278 if (!(root instanceof Element) && root !== document) { 279 return; 280 } 281 if (root instanceof Element && root.matches("altcha-widget")) { 282 callback(root); 283 } 284 root.querySelectorAll?.("altcha-widget").forEach(callback); 285 } 286 287 function attachWidget(widget) { 288 if (!(widget instanceof HTMLElement) || controllers.has(widget)) { 289 return controllers.get(widget) || null; 290 } 291 292 const controller = new MlAltchaAccessibility(widget); 293 controllers.set(widget, controller); 294 controllerInstances.add(controller); 295 controller.init(); 296 return controller; 297 } 298 299 function destroyRemovedWidgets(root) { 300 visitWidgets(root, (widget) => { 301 if (!widget.isConnected) { 302 controllers.get(widget)?.destroy(); 303 } 304 }); 305 } 306 307 function releaseControllersForEvent(event, restoreFocus) { 308 const eventTarget = event.target instanceof Element ? event.target : null; 309 for (const controller of controllerInstances) { 310 if ( 311 controller.form 312 && (eventTarget === controller.form || eventTarget?.contains(controller.form)) 313 ) { 314 controller.completeSubmission(restoreFocus); 315 } 316 } 317 } 318 319 function releaseAll(resetWidgets = false) { 320 for (const controller of controllerInstances) { 321 if (resetWidgets) { 322 controller.resetForPageRestore(); 323 } else { 324 controller.finishModal(false); 325 } 326 } 327 } 328 329 function handleDocumentKeyDown(event) { 330 getTopActiveController()?.handleKeyDown(event); 331 } 332 333 function initialize() { 334 if (!document.body || documentObserver) { 335 return; 336 } 337 338 visitWidgets(document, attachWidget); 339 documentObserver = new MutationObserver((records) => { 340 for (const record of records) { 341 record.addedNodes.forEach((node) => visitWidgets(node, attachWidget)); 342 record.removedNodes.forEach((node) => destroyRemovedWidgets(node)); 343 } 344 syncBackgroundInert(); 345 getTopActiveController()?.refreshDialog(); 346 }); 347 documentObserver.observe(document.body, { childList: true, subtree: true }); 348 349 document.addEventListener("keydown", handleDocumentKeyDown, true); 350 document.addEventListener("wpcf7mailsent", (event) => releaseControllersForEvent(event, true)); 351 document.addEventListener("wpcf7mailfailed", (event) => releaseControllersForEvent(event, true)); 352 document.addEventListener("wpcf7invalid", (event) => releaseControllersForEvent(event, true)); 353 document.addEventListener("wpcf7spam", (event) => releaseControllersForEvent(event, true)); 354 document.addEventListener("wpcf7submit", (event) => releaseControllersForEvent(event, true)); 355 window.addEventListener("pagehide", () => releaseAll(false)); 356 window.addEventListener("pageshow", (event) => { 357 if (event.persisted) { 358 releaseAll(true); 359 } 360 }); 361 } 362 363 class MlAltchaAccessibility { 364 constructor(widget) { 365 this.widget = widget; 366 this.form = widget.closest("form"); 367 this.instanceId = `ml-altcha-${++nextInstanceId}`; 368 this.announcementTimers = new Map(); 369 this.modalActive = false;
370 this.destroyed = false; 371 this.failureHandled = false; 372 this.suppressStateChange = false; 373 this.currentLabel = messages.verifying; 374 375 this.handleFormReset = this.handleFormReset.bind(this); 376 this.handleFormSubmit = this.handleFormSubmit.bind(this); 377 this.handleStateChange = this.handleStateChange.bind(this); 378 } 379 380 init() { 381 this.widget.setAttribute("data-ml-altcha-a11y", "true"); 382 this.installShadowStyles(); 383 this.createAnnouncements(); 384 this.createFeedback(); 385 386 this.widget.addEventListener("statechange", this.handleStateChange); 387 this.form?.addEventListener("submit", this.handleFormSubmit, true); 388 this.form?.addEventListener("reset", this.handleFormReset, true); 389 390 window.requestAnimationFrame(() => { 391 this.installShadowStyles(); 392 const state = this.widget.getState?.(); 393 if (state && state !== "unverified") { 394 this.handleStateChange({ detail: { state } }); 395 } 396 }); 397 } 398 399 destroy() { 400 if (this.destroyed) { 401 return; 402 } 403 this.destroyed = true; 404 this.clearTimers(); 405 this.finishModal(this.modalActive); 406 if (this.shadowStyleFrame) { 407 window.cancelAnimationFrame(this.shadowStyleFrame); 408 } 409 this.widget.removeEventListener("statechange", this.handleStateChange); 410 this.form?.removeEventListener("submit", this.handleFormSubmit, true); 411 this.form?.removeEventListener("reset", this.handleFormReset, true); 412 this.statusRegion?.remove(); 413 this.alertRegion?.remove(); 414 this.feedback?.remove(); 415 this.widget.removeAttribute("data-ml-altcha-a11y"); 416 controllerInstances.delete(this); 417 controllers.delete(this.widget); 418 } 419 420 installShadowStyles(attempt = 0) { 421 if (this.destroyed) { 422 return; 423 } 424 const shadowRoot = this.widget.shadowRoot; 425 if (shadowRoot) { 426 if (!shadowRoot.querySelector("[data-ml-altcha-a11y-styles]")) { 427 const style = document.createElement("style"); 428 style.setAttribute("data-ml-altcha-a11y-styles", "true"); 429 if (cspNonce) { 430 style.nonce = cspNonce; 431 } 432 style.textContent = shadowStyles; 433 shadowRoot.append(style); 434 } 435 return; 436 } 437 if (attempt < 20) { 438 this.shadowStyleFrame = window.requestAnimationFrame(() => { 439 this.installShadowStyles(attempt + 1); 440 }); 441 } 442 } 443 444 createAnnouncements() { 445 this.statusRegion = document.createElement("div"); 446 this.statusRegion.id = `${this.instanceId}-status`; 447 this.statusRegion.className = "ml-altcha-assistive-status"; 448 this.statusRegion.setAttribute("role", "status"); 449 this.statusRegion.setAttribute("aria-live", "polite"); 450 this.statusRegion.setAttribute("aria-atomic", "true"); 451 452 this.alertRegion = document.createElement("div"); 453 this.alertRegion.id = `${this.instanceId}-alert`; 454 this.alertRegion.className = "ml-altcha-assistive-status"; 455 this.alertRegion.setAttribute("role", "alert"); 456 this.alertRegion.setAttribute("aria-live", "assertive"); 457 this.alertRegion.setAttribute("aria-atomic", "true"); 458 459 this.widget.insertAdjacentElement("afterend", this.statusRegion); 460 this.statusRegion.insertAdjacentElement("afterend", this.alertRegion); 461 } 462 463 createFeedback() { 464 this.feedback = document.createElement("p"); 465 this.feedback.className = "ml-altcha-feedback"; 466 this.feedback.hidden = true; 467 if (!this.form && this.widget.parentElement === document.body) { 468 this.feedback.setAttribute("data-global", "true"); 469 } 470 this.alertRegion.insertAdjacentElement("afterend", this.feedback); 471 } 472 473 handleFormSubmit(event) { 474 if (this.widget.getState?.() !== "verified") { 475 this.previouslyFocused = event.submitter instanceof HTMLElement 476 ? event.submitter 477 : getDeepActiveElement(); 478 return; 479 } 480 481 if (this.form?.matches(".wpcf7-form") || this.form?.closest(".wpcf7")) { 482 return; 483 } 484 485 window.setTimeout(() => this.completeSubmission(true), 0); 486 } 487 488 handleFormReset() { 489 window.setTimeout(() => this.resetForPageRestore(), 0); 490 } 491 492 handleStateChange(event) { 493 if (this.destroyed || this.suppressStateChange) { 494 return; 495 } 496 const state = event?.detail?.state || this.widget.getState?.(); 497 498 switch (state) { 499 case "verifying": 500 this.failureHandled = false;
501 this.feedback.hidden = true; 502 this.feedback.textContent = ""; 503 this.alertRegion.textContent = ""; 504 this.startModal(messages.verifying); 505 this.announce(this.statusRegion, messages.verifying); 506 this.startVerificationTimer(timeouts.verification); 507 break; 508 case "code": 509 this.startModal(messages.code); 510 this.announce(this.statusRegion, messages.code); 511 this.startVerificationTimer(timeouts.code); 512 break; 513 case "verified": 514 this.clearVerificationTimer(); 515 this.currentLabel = messages.verified; 516 this.refreshDialog(); 517 this.announce(this.statusRegion, messages.verified); 518 this.startSubmitTimer(); 519 break; 520 case "expired": 521 this.failAndUnlock(messages.expired); 522 break; 523 case "error": 524 this.failAndUnlock(messages.error); 525 break; 526 case "unverified": 527 if (this.modalActive) { 528 this.finishModal(!this.failureHandled); 529 } 530 if (!this.failureHandled) { 531 this.feedback.hidden = true; 532 this.feedback.textContent = ""; 533 } 534 break; 535 default: 536 break; 537 } 538 } 539 540 startModal(label) { 541 this.currentLabel = label; 542 if (!this.modalActive) { 543 this.modalActive = true; 544 this.previouslyFocused = this.previouslyFocused instanceof HTMLElement 545 ? this.previouslyFocused 546 : getDeepActiveElement(); 547 this.formAriaBusy = this.form?.getAttribute("aria-busy") ?? null; 548 activeModalInstances.add(this); 549 syncPageLock(); 550 this.form?.setAttribute("aria-busy", "true"); 551 } 552 553 this.refreshDialog(); 554 window.requestAnimationFrame(() => { 555 this.refreshDialog(); 556 this.focusDialog(); 557 }); 558 } 559 560 finishModal(restoreFocus) { 561 activeModalInstances.delete(this); 562 syncPageLock(); 563 if (!this.modalActive) { 564 return; 565 } 566 567 this.modalActive = false; 568 this.clearTimers(); 569 if (this.form) { 570 if (this.formAriaBusy === null) { 571 this.form.removeAttribute("aria-busy"); 572 } else { 573 this.form.setAttribute("aria-busy", this.formAriaBusy); 574 } 575 } 576 this.releaseDialog(); 577 578 if ( 579 restoreFocus 580 && this.previouslyFocused instanceof HTMLElement 581 && this.previouslyFocused.isConnected 582 ) { 583 queueTask(() => this.previouslyFocused.focus({ preventScroll: true })); 584 } 585 } 586 587 refreshDialog() { 588 if (!this.modalActive) { 589 return; 590 } 591 const dialog = this.getDialog(); 592 if (!dialog) { 593 return; 594 } 595 596 if (this.dialogElement !== dialog) { 597 this.releaseDialog(); 598 this.dialogElement = dialog; 599 this.dialogAttributes = Object.fromEntries( 600 ["role", "aria-modal", "aria-label", "aria-busy", "tabindex"] 601 .map((attribute) => [attribute, dialog.getAttribute(attribute)]) 602 ); 603 } 604 605 dialog.setAttribute("role", "dialog"); 606 dialog.setAttribute("aria-modal", "true"); 607 dialog.setAttribute("aria-label", this.currentLabel); 608 dialog.setAttribute( 609 "aria-busy", 610 this.widget.getState?.() === "verifying" ? "true" : "false" 611 ); 612 dialog.setAttribute("tabindex", "-1"); 613 } 614 615 getDialog() { 616 if (this.widget.getState?.() === "code") { 617 const popovers = document.querySelectorAll(".altcha-popover"); 618 const visiblePopover = [...popovers].find(isVisible); 619 if (visiblePopover) { 620 return visiblePopover; 621 } 622 } 623 return this.getWidgetRoot().querySelector(".altcha"); 624 } 625 626 getWidgetRoot() { 627 return this.widget.shadowRoot || this.widget; 628 } 629 630 focusDialog() { 631 if (!this.modalActive) { 632 return; 633 } 634 635 const dialog = this.getDialog(); 636 if (!dialog) { 637 return; 638 } 639 if (this.widget.getState?.() === "code") { 640 const input = dialog.querySelector(".altcha-code-challenge input, .altcha-input"); 641 if (isVisible(input)) { 642 input.focus({ preventScroll: true }); 643 return; 644 } 645 } 646 dialog.focus({ preventScroll: true }); 647 } 648 649 releaseDialog() { 650 if (!this.dialogElement || !this.dialogAttributes) { 651 this.dialogElement = null; 652 this.dialogAttributes = null; 653 return; 654 } 655 656 for (const [attribute, value] of Object.entries(this.dialogAttributes)) { 657 if (value === null) { 658 this.dialogElement.removeAttribute(attribute); 659 } else { 660 this.dialogElement.setAttribute(attribute, value); 661 } 662 } 663 this.dialogElement = null; 664 this.dialogAttributes = null; 665 } 666 667 handleKeyDown(event) { 668 if (!this.modalActive) { 669 return; 670 } 671 if (event.key === "Escape") { 672 event.preventDefault(); 673 event.stopImmediatePropagation(); 674 this.announce( 675 this.statusRegion, 676 messages[this.widget.getState?.()] || messages.verifying 677 ); 678 this.focusDialog(); 679 return; 680 } 681 if (event.key !== "Tab") { 682 return; 683 } 684 685 const focusable = this.getFocusableElements(); 686 if (!focusable.length || this.widget.getState?.() === "verifying") { 687 event.preventDefault(); 688 this.focusDialog(); 689 return; 690 } 691 692 const active = getDeepActiveElement(); 693 const currentIndex = focusable.indexOf(active); 694 const nextIndex = event.shiftKey 695 ? (currentIndex <= 0 ? focusable.length - 1 : currentIndex - 1) 696 : (currentIndex === focusable.length - 1 ? 0 : currentIndex + 1); 697 event.preventDefault(); 698 focusable[nextIndex].focus({ preventScroll: true }); 699 } 700 701 getFocusableElements() { 702 const elements = this.getDialog()?.querySelectorAll( 703 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable="true"], [tabindex]:not
703([tabindex="-1"])' 704 ) || []; 705 return [...elements].filter(isVisible); 706 } 707 708 startVerificationTimer(timeout) { 709 this.clearVerificationTimer(); 710 this.verificationTimer = window.setTimeout( 711 () => this.failAndUnlock(messages.error), 712 timeout 713 ); 714 } 715 716 clearVerificationTimer() { 717 if (this.verificationTimer) { 718 window.clearTimeout(this.verificationTimer); 719 this.verificationTimer = null; 720 } 721 } 722 723 startSubmitTimer() { 724 if (this.submitTimer) { 725 window.clearTimeout(this.submitTimer); 726 } 727 this.submitTimer = window.setTimeout( 728 () => this.failAndUnlock(messages.error), 729 timeouts.submit 730 ); 731 } 732 733 clearTimers() { 734 this.clearVerificationTimer(); 735 if (this.submitTimer) { 736 window.clearTimeout(this.submitTimer); 737 this.submitTimer = null; 738 } 739 for (const timer of this.announcementTimers.values()) { 740 window.clearTimeout(timer); 741 } 742 this.announcementTimers.clear(); 743 } 744 745 safelyResetWidget() { 746 this.suppressStateChange = true; 747 try { 748 this.widget.hide?.(); 749 this.widget.reset?.(); 750 } catch (error) { 751 console.error("ML_altcha could not reset the ALTCHA widget.", error); 752 } finally { 753 queueTask(() => { 754 this.suppressStateChange = false; 755 }); 756 } 757 } 758 759 failAndUnlock(message) { 760 if (this.failureHandled) { 761 return; 762 } 763 this.failureHandled = true; 764 this.clearTimers(); 765 this.safelyResetWidget(); 766 this.finishModal(true); 767 this.feedback.textContent = message; 768 this.feedback.hidden = false; 769 this.announce(this.alertRegion, message); 770 } 771 772 completeSubmission(restoreFocus) { 773 if (!this.modalActive) { 774 return; 775 } 776 try { 777 this.widget.hide?.(); 778 } catch { 779 // The document may already be navigating away. 780 } 781 this.finishModal(restoreFocus); 782 } 783 784 resetForPageRestore() { 785 this.failureHandled = false; 786 this.safelyResetWidget(); 787 this.finishModal(false); 788 this.feedback.hidden = true; 789 this.feedback.textContent = ""; 790 this.statusRegion.textContent = ""; 791 this.alertRegion.textContent = ""; 792 } 793 794 announce(region, message) { 795 if (!region) { 796 return; 797 } 798 const existingTimer = this.announcementTimers.get(region); 799 if (existingTimer) { 800 window.clearTimeout(existingTimer); 801 } 802 region.textContent = ""; 803 const timer = window.setTimeout(() => { 804 region.textContent = message; 805 this.announcementTimers.delete(region); 806 }, 20); 807 this.announcementTimers.set(region, timer); 808 } 809 } 810 811 globalThis.mlAltchaAccessibility = Object.freeze({ 812 initialized: true, 813 attach: attachWidget, 814 getController: (widget) => controllers.get(widget) || null, 815 releaseAll, 816 }); 817 818 registerLocale(); 819 if (document.readyState === "loading") { 820 document.addEventListener("DOMContentLoaded", initialize, { once: true }); 821 } else { 822 initialize(); 823 } 824})();
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.