PageSourceSearch

https://www.allodons.fr/assets/controllers/deferred_modal_controller-c44558dc.js

js allodons.fr collected 2026-09-26 09:16:38 UTC 4,028 bytes, 99 lines download raw bytes

1import { Controller } from "@hotwired/stimulus";
2
3// Modale d'ATTENTE pour une <dialog> chargée à la demande dans un turbo-frame.
4//
5// ⚠️ UNE MODALE QUI MET DES SECONDES À S'OUVRIR EST UNE MODALE QUI NE S'OUVRE
6// PAS. Le patron « frame vide + `qr-code-modal` qui ouvre la <dialog> dès
7// qu'elle est insérée » n'affiche RIEN tant que le serveur n'a pas répondu : le
8// frame est vide et hors écran. Sur « Rembourser », le serveur lit le SOLDE
9// Stripe de l'association - quelques secondes d'appel réseau pendant lesquelles
10// le clic ne produit aucun effet visible, et pendant lesquelles on reclique.
11//
12// Ce contrôleur ouvre TOUT DE SUITE une doublure (même en-tête, un spinner à la
13// place du contenu) et s'efface dès que le frame répond.
14//
15// ⚠️ DEUX FERMETURES, ET LES DEUX SONT NÉCESSAIRES.
16//
17//   · `turbo:before-frame-render` est le chemin NOMINAL, et il est le seul à
18//     tomber AVANT l'insertion du contenu - donc avant que la vraie <dialog> ne
19//     s'ouvre. Deux modales ouvertes en même temps empilent deux fonds sombres :
20//     l'écran clignote au moment précis où l'on regarde le montant.
21//
22//   · L'attribut `busy` du frame est le FILET, et il couvre ce que l'événement
23//     ne couvre pas : réseau tombé, réponse sans le frame attendu, session
24//     expirée. Turbo le pose à l'ouverture de la requête et le retire quand
25//     elle est finie, QUOI QU'IL SE PASSE - c'est le seul signal terminal dans
26//     tous les cas. Il arrive après le rendu, d'où le premier.
27//
28// ⚠️ ET ELLE SE FERME À LA MAIN. Une doublure qu'on ne peut pas fermer piège
29// l'écran si un cas non prévu la laisse ouverte : elle porte donc son bouton
30// « Annuler » et sa fermeture au clic sur le fond, comme une vraie modale. Le
31// geste qu'elle couvre est un REMBOURSEMENT - un écran figé y coûte plus cher
32// qu'ailleurs.
33//
34// Usage :
35//   <div data-controller="deferred-modal"
36//        data-deferred-modal-frame-value="refund-modal-frame"
37//        data-action="turbo:before-frame-render@document->deferred-modal#hide">
38//     <a href="…" data-turbo-frame="refund-modal-frame"
39//        data-action="click->deferred-modal#show">Rembourser</a>
40//     <dialog data-deferred-modal-target="modal" class="modal">…</dialog>
41//   </div>
42export default class extends Controller {
43  static targets = ["modal"];
44  // Id du turbo-frame surveillé. Sans lui, la doublure se fermerait sur le
45  // rendu de N'IMPORTE QUEL frame de la page - et la fiche don en porte
46  // plusieurs (drawer d'édition, onglets).
47  static values = { frame: String };
48
49  connect() {
50    this.frameObserver = new MutationObserver(() => this.hideWhenFrameIdle());
51  }
52
53  disconnect() {
54    this.frameObserver.disconnect();
55    // La <dialog> vit dans le DOM de la page et le cache Turbo la restaure telle
56    // quelle : la laisser ouverte afficherait un spinner sur un écran qui ne
57    // charge plus rien.
58    this.close();
59  }
60
61  show() {
62    if (!this.hasModalTarget || this.modalTarget.open) return;
63
64    this.modalTarget.showModal();
65
66    // ⚠️ On observe SANS lire `busy` tout de suite. L'ordre entre ce clic et
67    // l'interception de Turbo n'est pas garanti : l'attribut peut n'être posé
68    // qu'après. On ne se fie donc qu'aux CHANGEMENTS - la pose puis le retrait.
69    const frame = this.watchedFrame;
70    if (frame) this.frameObserver.observe(frame, { attributes: true, attributeFilter: ["busy"] });
71  }
72
73  hide(event) {
74    if (!this.concernsWatchedFrame(event)) return;
75
76    this.close();
77  }
78
79  hideWhenFrameIdle() {
80    if (this.watchedFrame?.hasAttribute("busy")) return;
81
82    this.close();
83  }
84
85  close() {
86    this.frameObserver?.disconnect();
87    if (this.hasModalTarget && this.modalTarget.open) this.modalTarget.close();
88  }
89
90  get watchedFrame() {
91    return this.frameValue ? document.getElementById(this.frameValue) : null;
92  }
93
94  concernsWatchedFrame(event) {
95    if (!this.frameValue) return true;
96
97    return event?.target?.id === this.frameValue;
98  }
99}

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.