| @@ -515,10 +515,8 @@ | ||
| 515 | 515 | const CRYPTX_ATTR_MODE = 'data-cxm'; |
| 516 | 516 | const CRYPTX_ATTR_ITERATIONS = 'data-cxi'; |
| 517 | 517 | const CRYPTX_MAX_DELEGATION_DEPTH = 50; |
| 518 | 518 | |
| 519 | -let cryptxLinkHandlerAttached = false; | |
| 520 | - | |
| 521 | 519 | /** |
| 522 | 520 | * True only when the Web Crypto API is usable (secure context, modern browser) |
| 523 | 521 | * @returns {boolean} |
| 524 | 522 | */ |
| @@ -655,8 +653,20 @@ | ||
| 655 | 653 | } |
| 656 | 654 | |
| 657 | 655 | /** |
| 658 | 656 | * Attaches the single delegated listener. Idempotent. |
| 657 | + * | |
| 658 | + * The "attached" flag lives on the document itself (an expando property), | |
| 659 | + * not in a closure variable. Two things went wrong with a closure variable: | |
| 660 | + * first, any plugin or loader that runs cryptx.js a second time on the same | |
| 661 | + * document -- @swup/scripts-plugin does, Turbo/Hotwire does, any AJAX loader | |
| 662 | + * that brings footer markup along does -- gets a fresh closure and therefore | |
| 663 | + * a second `click` listener on `document`; measured: one click fired | |
| 664 | + * `mailto:` twice. Second, initCryptxLinkHandler(otherDocument) is exported | |
| 665 | + * for exactly this use but never worked, because the closure flag was | |
| 666 | + * already true from the main document and nothing was attached to the one | |
| 667 | + * passed in. Marking the document, not the module, fixes both with the same | |
| 668 | + * few lines. | |
| 659 | 669 | * @param {Object} [targetDocument] |
| 660 | 670 | * @returns {boolean} true when the listener was attached by this call |
| 661 | 671 | */ |
| 662 | 672 | function initCryptxLinkHandler(targetDocument) { |
| @@ -665,14 +675,14 @@ | ||
| 665 | 675 | if (!doc || typeof doc.addEventListener !== 'function') { |
| 666 | 676 | return false; |
| 667 | 677 | } |
| 668 | 678 | |
| 669 | - if (cryptxLinkHandlerAttached) { | |
| 679 | + if (doc.__cryptxLinkHandlerAttached) { | |
| 670 | 680 | return false; |
| 671 | 681 | } |
| 672 | 682 | |
| 673 | 683 | doc.addEventListener('click', handleCryptxLinkClick, false); |
| 674 | - cryptxLinkHandlerAttached = true; | |
| 684 | + doc.__cryptxLinkHandlerAttached = true; | |
| 675 | 685 | |
| 676 | 686 | return true; |
| 677 | 687 | } |
| 678 | 688 | |