docs: record the prefill seam and the optional local config

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-07-17 14:30:48 +02:00
co-authored by Claude Opus 4.8
parent 2e60bd08d8
commit 23e58b17ee
3 changed files with 114 additions and 18 deletions
+31
View File
@@ -50,6 +50,37 @@ runtime à installer) :
> Pense aussi à **fermer les anciens onglets de la liste** avant de recharger :
> une page orpheline rend les clics inertes.
### Configuration (optionnelle)
Le formulaire de la mairie demande un **organisateur** et un **email** : ils sont
personnels, donc absents du dépôt. Pour qu'ils soient pré-remplis :
```sh
cp extension/config.local.json.example extension/config.local.json
```
puis édite le fichier (il est gitignoré, il ne partira jamais sur le dépôt) :
```json
{
"organisateur": "L'Atelier du Huit",
"email": "contact@atelier-huit.fr"
}
```
Ce fichier est **facultatif**. Sans lui, tout le reste est pré-rempli (titre,
dates, heures, lieu, thème, tarifs) : seuls l'organisateur et l'email restent
vides, et le bandeau du formulaire te le dit.
> ⚠️ Ce fichier ne surcharge que `organisateur` et `email`. Les autres valeurs
> par défaut (thème « Culture », tarifs « Gratuit », adresse **et coordonnées**
> du café) vont ensemble et vivent dans `extension/config.js` : c'est là qu'on
> les change. Y mettre un `cafe` partiel produirait des coordonnées invalides.
> **Après avoir créé ou modifié `config.local.json`** : recharge le module dans
> `about:debugging`. L'extension lit le fichier au réveil de son arrière-plan,
> pas à chaque ouverture du formulaire.
### Vérifier l'extension
```sh
+55
View File
@@ -126,3 +126,58 @@ deux avals du parseur ont chacun le leur : la liste affiche l'adresse pour ne pa
montrer une ligne vide (cas majoritaire), le content script décide s'il pose
**aussi** les coordonnées (`input_18`). Écrire l'adresse dans le payload
détruirait le signal « pas de lieu » dont il a besoin.
## 2026-07-17 — [T1] Pré-remplissage : content scripts classiques + `globalThis`
Le formulaire mairie est pré-rempli par deux content scripts (`config.js`,
`formulaire-valeurs.js`, `formulaire-mairie.js`), **classiques — pas des modules
ESM** — qui communiquent par des namespaces `globalThis` (`EchoConfig`,
`EchoFormulaire`).
**Pourquoi pas ESM :** un content script n'est pas un module (`import` y lève une
`SyntaxError`), et le `import()` dynamique y est cassé côté Firefox (bugs ouverts
1803950 / 1536094). Restait à convertir la couture `transfert.js`, figée le
2026-07-14 : non.
⚠️ **`config.js` et `formulaire-valeurs.js` n'ont NI `import` NI `export`, et
c'est délibéré — ne pas « corriger ».** Un fichier sans les deux est valide **à la
fois** comme script classique (content script, background) et comme module ESM
(`import "./config.js"` depuis `presentation.js` et depuis `bun test`). C'est ce
qui permet à `presentation.js` de partager l'adresse du café **sans build**. Le
jour où quelqu'un y ajoute un `export`, les content scripts cassent
silencieusement.
**Corollaire : l'ordre des tableaux `js` du manifest EST la dépendance**
(`config` → `valeurs` → `mairie`), testé dans `extension.test.ts`.
**`CLE_EVENEMENT_EN_ATTENTE` est dupliquée** dans `formulaire-valeurs.js`
(l'original vit dans `transfert.js`, en ESM, inatteignable depuis un content
script classique). Un **test de dérive** garantit l'égalité des deux.
**Config (a) : défauts committés + `config.local.json` optionnel.** Les défauts
(thème, tarifs, café) sont dans `config.js` ; seuls organisateur et email sont
personnels et vivent dans `config.local.json` (gitignoré). Le fichier n'est
**pas requis** : un clone frais doit marcher, il laisserait sinon l'extension
cassée par défaut. Absent ou invalide → défauts nus, manque **signalé** dans le
bandeau, jamais d'exception.
**C'est le background qui lit `config.local.json`**, puis le passe par le
storage. Un content script ne pourrait le `fetch(runtime.getURL(...))` que si le
fichier était en `web_accessible_resources` — ce qui **exposerait l'email à la
page de la mairie**. Le fichier étant optionnel, il ne peut pas non plus être
listé dans un tableau `js` (Firefox refuse d'installer si un fichier déclaré
manque) : `fetch` + repli est la seule voie.
**On ne remplit que ce qu'on sait ; le reste est dit, jamais inventé.** Pas
d'heure « 00:00 » pour une journée entière, pas de `lat|lng` deviné pour un lieu
hors café, pas d'organisateur par défaut. Ce qui manque part dans le bandeau
(`aCompleter`). En particulier, **`input_6_35` (accessibilité) est laissé
intact** : `RECHERCHE.md` le dit « fixe », mais la machine ne sait pas si le lieu
est accessible — cocher au hasard sur un formulaire **modéré** serait exactement
le « champ rempli faux » qu'on veut éviter.
**Séparation calcul / DOM** : `formulaire-valeurs.js` est pur et testé (les dates
sont le vrai risque, invisible sous `TZ=Europe/Paris`) ; `formulaire-mairie.js`
est fin, impur et **non testé unitairement** — aucun harnais DOM dans le repo, et
happy-dom n'émulerait de toute façon pas Gravity Forms. C'est le test humain qui
tranche.
+28 -18
View File
@@ -45,24 +45,34 @@ Content script qui **remplit le DOM par id**, puis **l'utilisateur soumet à la
### Mapping des champs (ids confirmés présents dans le HTML)
| id DOM | name | Contenu | Source |
|---|---|---|---|
| `#input_6_42` | `input_42` | Organisateur | config (« L'Atelier du Huit ») |
| `#input_6_41` | `input_41` | Email | config |
| `#input_6_1` | `input_1` | Titre | SUMMARY |
| `#input_6_3` | `input_3` | Description (textarea) | DESCRIPTION |
| `#input_6_20` | `input_20` | Thème (select) | mapping (voir §3) |
| `#input_6_31` | `input_31` | Date début `jj/mm/aaaa` | DTSTART |
| `#input_6_32` | `input_32` | Date fin `jj/mm/aaaa` | DTEND |
| `#input_6_38_1` / `#input_6_38_2` | `input_38[]` | Heure début [HH, MM] | DTSTART |
| `#input_6_39_1` / `#input_6_39_2` | `input_39[]` | Heure fin [HH, MM] | DTEND |
| `#input_6_35` (`_1`) | `input_35.1` | Accessibilité (case) | fixe |
| `#input_6_36` | `input_36` | Public ciblé | optionnel |
| `#input_6_40` | `input_40` | Tarifs | défaut « Gratuit » |
| `#nova_address` | `nova_address` | Adresse texte | défaut café |
| `#input_6_18` | `input_18` | `lat\|lng\|adresse` (hidden) | défaut café |
| `#input_6_34` | `input_34` | **Image (file)** | ⚠️ non remplissable par script (sécurité) → manuel |
| `#input_6_23`, `#input_6_43` | | Honeypot | laisser vide |
> ⚠️ **La colonne « balise réelle » a été payée par un bug** (2026-07-17). Le
> corps de la tâche T1 affirmait « Heures = 2 **selects** » : c'est **faux**, ce
> sont des `<input type="number">`. Le code l'a suivi et les 4 champs d'heures
> ont échoué (`champ.options` undefined → TypeError). **Ne pas déduire le type
> d'un champ de son intitulé : le HTML est la seule source de vérité.** Types
> ci-dessous vérifiés sur la page réelle le 2026-07-17.
| id DOM | name | Balise réelle | Contenu | Source |
|---|---|---|---|---|
| `#input_6_42` | `input_42` | `input[type=text]` | Organisateur | config (« L'Atelier du Huit ») |
| `#input_6_41` | `input_41` | `input[type=email]` | Email | config |
| `#input_6_1` | `input_1` | `input[type=text]` | Titre | SUMMARY |
| `#input_6_3` | `input_3` | `textarea` | Description | DESCRIPTION |
| `#input_6_20` | `input_20` | **`select`** | Thème | mapping (voir §3) |
| `#input_6_31` | `input_31` | `input[type=text]` (datepicker) | Date début `jj/mm/aaaa` | DTSTART |
| `#input_6_32` | `input_32` | `input[type=text]` (datepicker) | Date fin `jj/mm/aaaa` | DTEND |
| `#input_6_38_1` / `#input_6_38_2` | `input_38[]` | **`input[type=number]`** (`min/max`, placeholder `HH`/`MM`) | Heure début [HH, MM] | DTSTART |
| `#input_6_39_1` / `#input_6_39_2` | `input_39[]` | **`input[type=number]`** | Heure fin [HH, MM] | DTEND |
| `#input_6_35` (`_1`) | `input_35.1` | `input[type=checkbox]` | Accessibilité | ⚠️ laissé **intact** : la machine ne sait pas si le lieu est accessible |
| `#input_6_36` | `input_36` | | Public ciblé | optionnel |
| `#input_6_40` | `input_40` | **`textarea`** | Tarifs | défaut « Gratuit » |
| `#nova_address` | `nova_address` | `input[type=text]` | Adresse texte | défaut café |
| `#input_6_18` | `input_18` | `input[type=hidden]` | `lat\|lng\|adresse` | défaut café |
| `#input_6_34` | `input_34` | `input[type=file]` | **Image** | ⚠️ non remplissable par script (sécurité) → manuel |
| `#input_6_23`, `#input_6_43` | | | Honeypot | laisser vide |
Les 4 champs d'heures acceptent le **zéro-padding** (`"09"`, `"00"`) : une suite
de chiffres est un *valid floating-point number* au sens HTML.
**Défaut café** : `8 Rue du Pré Vicinal 31270 Cugnaux`
`input_18` = `43.53753132806989|1.342981890597508|8 Rue du Pré Vicinal 31270 Cugnaux`