Restaure et termine le lot tableur resté non committé. Il n'existait que dans un `git stash` (24 fichiers suivis) et en fichiers non suivis (menus.js, formula.js, color-picker.js, tests, fiches) : la 2.53.3 livrée ne le contenait donc pas. Le stash, créé avant le commit BUG-108, n'a jamais été restauré. #180 Redimensionnement au curseur (en-tête de bord miroité + classe de repaint), grille thémée sur les 15 thèmes et les modes contraste élevé / sépia, menu Fichier au niveau des onglets, barre épinglée pleine largeur. #181 Modèle de saisie Google Sheets : sélection ≠ édition (caret masqué sans quitter contenteditable, double-clic / F2 / première frappe qui remplace, Entrée contextuelle, Échap qui restaure) + inventaire priorisé des écarts. #182 Désélection fiable (clic simple sans dépendre du focus), contours de plage non empilés (sélecteur de classes sans point), couleurs texte/fond sur une plage, clic droit qui préserve la sélection multiple. #183 Panneau de couleurs façon Google Sheets : palette 8 × 10, STANDARD, PERSONNALISÉ, coche selon la luminance, sortie `#rrggbb` (une valeur HSL était rejetée par normHex). #184 Peinture de format complète (toutes propriétés, source sans format = réinitialisation), sélection multi-lignes/colonnes depuis les marges, grille étendue : colonnes A → Z d'emblée, lignes ajoutées PAR BLOCS DE 100 au défilement jusqu'à 1000 — matérialiser 1000 lignes d'un coup = ~26 000 cellules câblées par feuille, ce qui épuisait le tas de la suite JSDOM ; index de cellules `ref → td`, court-circuits formule/styles, marqueur data-wired. #185 Barre de menus : les 10 menus Google Sheets (161 entrées, 125 câblées, 36 annoncées indisponibles), ruban façon Sheets, grille unie 1 px dérivée du thème. #186 « Créer un fichier » propose .xlsx et construit un vrai classeur OPC (openpyxl) au lieu d'une charge utile texte illisible. Corrections trouvées en restaurant et en exerçant le lot : - fuite mémoire : écouteur `click` anonyme posé sur #content-area à chaque rendu, jamais retiré — sa fermeture retenait la grille précédente en entier ; - sorties Markdown / HTML / Imprimer de la barre de menus inertes (`data-xlsx-export` jamais réparti, seul `data-xlsx-action` l'était) ; - collision de classe `.xlsx-structure-menu` entre la barre de menus et le menu Structure de la barre d'outils (toute requête tombait sur un nœud masqué) ; - curseur col/row-resize absent quand le pointeur est sur la table elle-même ; - l'export emportait les lignes et colonnes vides du quadrillage (CSV, Markdown, HTML, impression) ; - clic extérieur avalé par la grâce de 250 ms du menu contextuel (destinée au seul appui long tactile) ; - une entrée indisponible laissait la barre de menus ouverte. Tests : pytest 1595 passés / 2 ignorés ; ruff et mypy 0 erreur ; bandit 0 ; 33 suites frontend vertes (xlsx-viewer 163/163, xlsx-menus 19/19, xlsx-formula 14/14) ; E2E complet 132 passés / 12 ignorés ; E2E xlsx-viewer 19/19.
356 lines
17 KiB
Markdown
356 lines
17 KiB
Markdown
# #181 — Éditeur tableur : modèle de saisie Google Sheets & inventaire des écarts
|
||
|
||
> **Statut :** ✅ livré le 2026-10-08 (v2.54.0) — ouvert le 2026-10-05 | **Impact :** 🟡
|
||
> **Références :** [Roadmap](../ROADMAP.md) · [Changelog](../../CHANGELOG.md) ·
|
||
> [#154](./xlsx-ui-redesign.md) · [#155](./xlsx-context-menu.md) ·
|
||
> [#179](./xlsx-menus-179.md) · [#180](./xlsx-sheetbar-180.md)
|
||
|
||
## 1. Constat
|
||
|
||
L'éditeur ne distinguait pas **sélectionner** une cellule et **l'éditer** :
|
||
|
||
- le curseur de texte clignotait en permanence dans la cellule focalisée
|
||
(tout est `contenteditable`, `caret-color` par défaut) ;
|
||
- `Entrée` validait puis faisait `blur()` — le focus **quittait la grille** ;
|
||
- l'indicateur de plage était un simple lavis, sans contour, et les en-têtes
|
||
de la plage sélectionnée n'étaient pas reflétés ;
|
||
- la première frappe **ajoutait** au contenu existant au lieu de le remplacer.
|
||
|
||
Un utilisateur habitué à Google Sheets ou Excel perd le repère : il ne sait
|
||
plus s'il est en train de naviguer ou de saisir.
|
||
|
||
## 2. Livré (A1-A3)
|
||
|
||
### A1 — Deux états distincts : sélection et édition
|
||
|
||
Toutes les cellules portent la classe `xlsx-cell` et démarrent en
|
||
**sélection** (`data-editing=""`) : contour visible, **aucun curseur**. Le
|
||
curseur est masqué via `caret-color: transparent` — donc sans laisser
|
||
`contenteditable`, ce qui préserve le collage, le clic et la frappe native.
|
||
|
||
L'**édition** s'atteint par trois voies, comme dans Google Sheets :
|
||
|
||
| Geste | Effet |
|
||
|---|---|
|
||
| Clic / flèches | sélectionne (pas de curseur) |
|
||
| **Double-clic** | édite **sur place** — `caretRangeFromPoint` place le curseur sous le pointeur |
|
||
| **Première frappe** | édite et **remplace** le contenu (jamais d'ajout) |
|
||
| `F2` | édite, curseur en fin de texte |
|
||
| `Alt`+flèche | saut de ligne dans la cellule |
|
||
| `Échap` | quitte l'édition et **restaure** la valeur |
|
||
|
||
`enterEditing()` / `exitEditing()` centralisent la bascule. Un garde
|
||
`editingRequested` empêche le handler `focus` de la cellule d'annuler l'état
|
||
d'édition que `enterEditing()` vient d'installer (il se déclenche au moment du
|
||
`focus`).
|
||
|
||
### A2 — Sélection multiple et indicateur visuel
|
||
|
||
- `Maj`+flèches étend depuis l'ancre, glisser avec la souris aussi, plus
|
||
`Maj`+clic — le mécanisme existait déjà, il est désormais complet et lisible.
|
||
- Les cellules portent `.xlsx-selected` **et** quatre classes de bord
|
||
(`.xlsx-sel-top/bottom/left/right`) : le bloc est **contouré** exactement
|
||
comme dans Excel/Sheets, au lieu d'un lavis uniforme. Chaque cellule ne
|
||
reçoit que les bords qu'elle porte réellement (les coins n'héritent pas d'un
|
||
bord intérieur).
|
||
- Les en-têtes couverts (lettres `A`, `B`… et numéros `1`, `2`…) reçoivent
|
||
`.xlsx-hdr-selected` : la plage se lit aussi dans les marges.
|
||
|
||
### A3 — `Entrée` contextuelle
|
||
|
||
| État | `Entrée` |
|
||
|---|---|
|
||
| **édition** | valide, puis le focus passe **à la cellule du dessous** |
|
||
| **sélection** | bascule la cellule courante en **mode édition** |
|
||
|
||
`Tab` suit la même logique (validation + déplacement latéral en édition,
|
||
déplacement simple en sélection), et un clic simple après une édition abandonne
|
||
l'état d'édition sans laisser de curseur.
|
||
|
||
## 3. A4 — Inventaire des écarts vs Google Sheets / Excel
|
||
|
||
**Rapprochement exhaustif impossible en une tranche.** L'éditeur couvre déjà
|
||
l'essentiel ; l'inventaire ci-dessous est l'état réel vérifié dans le code au
|
||
2026-10-05.
|
||
|
||
### 3.1 Déjà couvert
|
||
|
||
Édition de cellules · types et formats · recherche **et** remplacement ·
|
||
trier / filtrer · gel des volets · fusions · annuler / rétablir · presse-papiers
|
||
de plage · insertion / suppression de lignes, colonnes et feuilles ·
|
||
graphiques KPI du tableau de bord · commentaires · liens hypertexte (formule
|
||
`=LIEN`) · export (CSV, Markdown, HTML, impression) · impression ·
|
||
collaboration temps réel · import de formats · lecture seule `.xls` / `.ods`.
|
||
|
||
### 3.2 Manquants, par priorité
|
||
|
||
**P1 — usage quotidien**
|
||
|
||
- **Poignée de recopie** (fill handle) : le petit carré en bas à droite de la
|
||
plage, glisser pour remplir séries et formules. Très attendu, absent.
|
||
- **Remplacer** (`Ctrl+H`) : seule la *recherche* existe.
|
||
- **Validation de données** : listes déroulantes, bornes numériques.
|
||
- **Filtre automatique** : l filtrage texte existe, pas les entêtes de filtre
|
||
par colonne.
|
||
- **Tri multi-critères** et options de tri (couleur, taille, valeurs
|
||
personnalisées).
|
||
- **Déplacer lignes / colonnes** par glisser-déposer (l'insertion existe).
|
||
|
||
**P2 — présentation et analyse**
|
||
|
||
- Mise en forme conditionnelle (couleurs, barres de données, jeu d'icônes).
|
||
- **Graphiques** dans le tableur : KPI et relevé de graphiques existants sont
|
||
lus, mais on ne **crée pas** de graphique.
|
||
- Tableaux croisés : lus et affichés, non modifiables.
|
||
- Groupement / dégroupement de lignes et colonnes.
|
||
- Images et formes dans les cellules (ObsiGate a Excalidraw séparé).
|
||
- Protection d'une feuille ou de cellules (lecture seule).
|
||
- Masquer des lignes / colonnes.
|
||
|
||
**P3 — avancé**
|
||
|
||
- Analyse de données : supprimer les doublons, convertir du texte en colonnes,
|
||
supprimer les espaces superflus.
|
||
- Fusion des cellules à l'identique, annotations, suivi des modifications,
|
||
historique des révisions.
|
||
- Macros (les `.xlsm` sont lus et réécrits avec `keep_vba`).
|
||
- Simulation de scénarios, recherche de cible (goal seek).
|
||
- Options de tri avancées (insensible à la casse, séparateur décimal
|
||
personnalisé).
|
||
- Peintures de cellules, texte en art.
|
||
|
||
## 4. Tests
|
||
|
||
`tests/frontend/xlsx-viewer.test.mjs` — **146/146** (10 nouveaux cas #181) :
|
||
sélection sans curseur au clic et aux flèches · double-clic qui édite en place ·
|
||
première frappe qui **remplace** · deuxième frappe qui n'efface pas ·
|
||
`Entrée` qui passe en édition · `Entrée` qui valide et descend sous la cellule ·
|
||
extension `Maj`+flèches avec les quatre bords du contour et les en-têtes
|
||
reflétés · glisser qui peint le même contour · clic simple qui fait tomber
|
||
l'état d'édition · `Échap` qui restaure la valeur.
|
||
|
||
Suites frontend également vertes : `xlsx-menus` 12/12, `unit` 13, `editor-inline`
|
||
44, `toolbar-order`, `mobile-editor` 35, `ai` 100, `pane-manager` 9,
|
||
`validate-imports` 41 modules / 355 exports.
|
||
|
||
## 5. Point d'attention
|
||
|
||
Le `caret-color: transparent` repose sur la prise en charge navigateur
|
||
(`caret-color` est largement disponible). Sur un très ancien moteur, le curseur
|
||
resterait visible en sélection — l'état reste correct, seul l'indicateur
|
||
disparaît.
|
||
|
||
## 6. #182 — Désélection & couleurs sur une plage
|
||
|
||
### 6.1 La sélection « collée »
|
||
|
||
**Symptôme** : après un `Maj`+clic ou un glissement, la plage restait affichée et
|
||
un clic simple ne la supprimait pas.
|
||
|
||
**Cause racine** — la désélection reposait entièrement sur l'événement `focus` de
|
||
la cellule, qui appelle `setActiveCell()` et donc réduit la plage à la cellule
|
||
focalisée. Or le handler `Maj`+clic appelle `e.preventDefault()`, ce qui
|
||
**supprime le déplacement de focus natif du navigateur**. Résultat : après un
|
||
`Maj`+clic, `activeTd` valait la cellule cliquée mais `document.activeElement`
|
||
restait sur l'ancienne. Le clic suivant **sur la cellule déjà focalisée** ne
|
||
déclenchait donc aucun `focus` : la plage ne pouvait plus s'effacer.
|
||
|
||
**Correctif**
|
||
|
||
- le clic simple appelle `setActiveCell(td)` dans `mousedown` : la plage est
|
||
effacée de façon déterministe, sans dépendre du focus ;
|
||
- le `Maj`+clic déplace réellement le focus, sous `suppressSelectionReset` pour
|
||
que le handler `focus` ne rétrécisse pas la plage qui vient d'être étendue ;
|
||
- le glissement ne vole **pas** le focus (comme dans un navigateur) — c'est
|
||
précisément ce vol qui aurait fait disparaître la plage tracée ;
|
||
- `endDrag` restaure la zone Nom sur la **plage** (`A1:B2`) au lieu de la
|
||
cellule d'origine.
|
||
|
||
Le même correctif a guéri le symptôme connexe « la mini-barre de sélection ne
|
||
se cachait plus après un glissement ».
|
||
|
||
### 6.2 Couleurs de texte et de fond
|
||
|
||
Les trois chemins ont été **vérifiés** (charge utile `PUT …/xlsx/style` puis
|
||
peinture locale) sur une plage `A1:B2` obtenue par `Maj`+flèches **et** par
|
||
glissement :
|
||
|
||
| Chemin | Charge utile | Résultat |
|
||
|---|---|---|
|
||
| Menu **Mise en forme** → couleur | `range: "A1:B2"` | 4 cellules peintes |
|
||
| Nuancier du ruban (police) | `range: "A1:B2"` | 4 cellules peintes |
|
||
| Nuancier du ruban (fond) | `range: "A1:B2"` | 4 cellules peintes |
|
||
|
||
Le mécanisme d'écriture était donc correct ; ce qui manquait réellement, c'était
|
||
le **retour visuel** : les deux nuanciers du ruban n'affichaient rien, d'où
|
||
l'impression que la couleur n'était pas appliquée. Ils portent désormais une
|
||
**pastille** (`.xlsx-color-swatch`) qui prend la couleur choisie.
|
||
|
||
### 6.3 Tests
|
||
|
||
`tests/frontend/xlsx-viewer.test.mjs` — **149/149** (+3 cas #182) :
|
||
|
||
- un clic simple réduit toujours une plage « collée » (y compris sur la cellule
|
||
qui porte déjà le focus) ;
|
||
- la zone Nom affiche la plage après un glissement ;
|
||
- couleurs de texte et de fond appliquées aux 4 cellules d'une plage, charge
|
||
utile vérifiée, pastilles synchronisées.
|
||
|
||
> Note d'implémentation : la peinture locale est **asynchrone** (elle suit
|
||
> l'écriture `PUT`), un test qui lit les styles inline doit donc attendre le
|
||
> tour de boucle d'événements.
|
||
|
||
### 6.4 Les contours qui s'empilaient (le point manquant)
|
||
|
||
**Symptôme** : en déplaçant le focus de cellule en cellule, les encadrés de
|
||
l'ancienne cellule **restaient** et s'accumulaient — la grille finit quadrillée.
|
||
|
||
**Cause racine** — le sélecteur de nettoyage était écrit **sans le point** :
|
||
|
||
```js
|
||
// ✘ avant : en CSS, un nom nu est un sélecteur de BALISE (<xlsx-sel-top>)
|
||
panel.querySelectorAll("xlsx-sel-top,xlsx-sel-bottom,...")
|
||
// ✔ après
|
||
panel.querySelectorAll(".xlsx-sel-top,.xlsx-sel-bottom,...")
|
||
```
|
||
|
||
La requête ne renvoyait **aucun** élément, donc `classList.remove(...)` n'était
|
||
jamais appelé et aucun contour n'était effacé. La même famille de faute
|
||
touchait `classList.remove(".xlsx-hdr-selected")` (un point passé comme jeton
|
||
de classe ne correspond à rien) : les en-têtes reflétés n'étaient jamais effacés
|
||
non plus.
|
||
|
||
Le test de non-régression compte les contours dans toute la grille après une
|
||
randonnée au clavier et exige qu'**une seule** cellule soit encadrée.
|
||
|
||
### 6.5 Flèches pendant la saisie
|
||
|
||
Dans Google Sheets comme dans Excel, une flèche pendant la saisie **valide la
|
||
cellule et déplace la sélection** ; le curseur n'est pas parcouru dans le texte
|
||
(`Alt`+flèche sert à insérer un saut de ligne). Notre implémentation laissait
|
||
le curseur se déplacer et la cellule restait figée sous l'encadré — ce qui
|
||
amplifiait la confusion. Corrigé.
|
||
|
||
## 7. #183 — Panneau de couleurs façon Google Sheets
|
||
|
||
### 7.1 Ce qui remplace quoi
|
||
|
||
Le `<input type="color">` natif (ruban **A** / seau, et les deux lignes du menu
|
||
**Mise en forme**) est remplacé par un bouton ouvrant un panneau construit par
|
||
`frontend/js/xlsx/color-picker.js` :
|
||
|
||
| Section | Contenu |
|
||
|---|---|
|
||
| En-tête | icône + **Réinitialiser** (gomme pour le fond, pinceau pour le texte) |
|
||
| Palette | **8 × 10 = 80** pastilles — ligne 1 : 8 gris du noir au blanc ; lignes 2-10 : 8 teintes (rouge, orange, jaune, vert clair, cyan, bleu, violet, magenta) × 9 nuances, du clair au foncé |
|
||
| **STANDARD** | 8 couleurs prédéfinies + crayon |
|
||
| **PERSONNALISÉ** | pastille de la couleur personnalisée, bouton « + », crayon |
|
||
| Pied | **Mise en forme conditionnelle**, et **Couleurs en alternance** (n'apparaît qu'une fois une couleur choisie, comme sur la maquette) |
|
||
|
||
Un clic sur une pastille **referme le panneau** et applique la couleur à la
|
||
cellule ou à la plage sélectionnée. La coche de sélection est blanche ou noire
|
||
selon la luminance de la pastille (`luminanceOf`).
|
||
|
||
### 7.2 Le piège d'encodage
|
||
|
||
La palette est calculée en HSL (lisible) mais **doit sortir en `#rrggbb`** :
|
||
`normHex()` côté viewer n'accepte que l'hexadécimal à 6 chiffres, et une
|
||
valeur `hsl(0, 0%, 1429%)` était donc rejetée **sans erreur** — la pastille se
|
||
peignait à l'écran mais la couleur n'était jamais écrite sur la cellule.
|
||
`hslToHex()` est doncexporté et testé par le contrôle de fumée.
|
||
|
||
### 7.3 Choix assumés
|
||
|
||
- **« + » et les crayons ouvrent le sélecteur natif** : le panneau propose 88
|
||
couleurs curées, le natif reste le seul moyen d'atteindre une teinte
|
||
arbitraire.
|
||
- **Les deux entrées de pied de page sont annoncées, pas fonctionnelles** :
|
||
« Mise en forme conditionnelle » et « Couleurs en alternance » ne sont pas
|
||
livrées (cf. §3.2). Elles appellent `onUnavailable` et affichent un message
|
||
explicite plutôt que d'être des boutons inertes.
|
||
- **Chrome thémé** : uniquement des variables CSS, donc le panneau suit le
|
||
thème actif ; seules les pastilles portent une couleur en ligne, ce sont des
|
||
données.
|
||
|
||
## 8. #184 — Peinture de format, multi-lignes/colonnes, grille A → Z × 1000
|
||
|
||
### 8.1 Peindre le format
|
||
|
||
**Symptôme** : l'outil refusait toute cellule source sans mise en forme
|
||
explicite (« *Veuillez sélectionner une cellule formatée* »). Peindre une
|
||
cellule simple sur une cellule colorée et en grand corps ne produisait donc
|
||
**rien** — c'est le cas le plus courant en pratique.
|
||
|
||
**Deux défauts distincts**
|
||
|
||
1. **Copie partielle** : seuls gras/italique/souligné/barré, couleurs, taille,
|
||
alignement et format de nombre étaient capturés. valign, retour à la ligne,
|
||
rotation et **bordures** ne l'étaient pas — une cellule bordée perdait ses
|
||
bordures en « peignant » la même mise en forme ailleurs.
|
||
2. **Source « neutre » rejetée** : sans propriété capturée, l'arme était
|
||
annulée. Dans Sheets/Excel, une cellule sans mise en forme est une source
|
||
**valide** : elle *réinitialise* la cible.
|
||
|
||
**Correctif** — `captureFormat()` renvoie toujours un jeu **complet** de
|
||
propriétés (y compris `border: "none"`, `font_color: ""`, `fill_color: ""`,
|
||
`number_format: "General"`), donc la cible finit toujours identique à la source,
|
||
et une source neutre vide la cible.
|
||
|
||
**Fuite d'écouteur** : `Échap` ou un second clic sur le bouton désarmaient
|
||
l'arme mais laissaient le gestionnaire « appliquer au prochain clic » en place —
|
||
le clic suivant dans la grille repeignait une vieille mise en forme. Le
|
||
gestionnaire est maintenant retiré par `stopPaint()`.
|
||
|
||
### 8.2 Sélection de plusieurs lignes / colonnes
|
||
|
||
Cliquer un numéro de ligne sélectionnait déjà la ligne entière ; il manquait
|
||
l'extension à **plusieurs** lignes. Le mécanisme :
|
||
|
||
- `mousedown` sur un en-tête sélectionne la ligne / colonne **entière** ;
|
||
- glisser au-dessus d'autres en-tête étend (`A1:Z5`), `Maj`+clic aussi
|
||
(`A1:Z5`) — l'ancre est mémorisée après le glisser ;
|
||
- la sélection réutilise le modèle `{anchor, focus}` d'une plage, donc
|
||
*copier*, *effacer*, *insérer/supprimer*, le menu contextuel et la
|
||
suppression de contenu fonctionnent sans code supplémentaire ;
|
||
- le `click` sur en-tête a été **retiré** : il écrasait la multi-sélection
|
||
juste après le glisser ;
|
||
- une pression **près du bord** de l'en-tête reste le geste de
|
||
**redimensionnement** (partage explicite avec `wireResize`).
|
||
|
||
### 8.3 Grille A → Z, et 1000 lignes à la demande
|
||
|
||
La grille de la feuille affichée est complétée jusqu'à **26 colonnes** (A → Z)
|
||
d'emblée ; les **lignes s'ajoutent par blocs de 100** quand le lecteur approche
|
||
du bas, jusqu'à 1000. Les cellules vides sont de vraies cellules éditables
|
||
(`contentEditable`, `tabIndex`, écouteurs, `data-cell`). L'extension a lieu à
|
||
l'activation d'un onglet, pas au montage : la faire pour toutes les feuilles
|
||
multiplierait les cellules par le nombre d'onglets.
|
||
|
||
**Une feuille tronquée garde son chargement serveur** (« Charger la suite »,
|
||
fenêtre par fenêtre) : ses lignes manquantes sont des données, pas du
|
||
remplissage. Étendre la grille par-dessus aurait dupliqué les lignes et
|
||
supprimait le pied de page — régression de **#153-A9bis**, corrigée en gardant
|
||
les deux mécanismes séparés (les colonnes et les blocs vides pour une feuille
|
||
complète, la fenêtre serveur pour une feuille tronquée).
|
||
|
||
**Pourquoi pas les 1000 lignes d'un coup.** Matérialiser A → Z × 1000 revient à
|
||
**~26 000 cellules câblées** pour la seule feuille visible. Mesuré : ~0,3 Go
|
||
retenus par rendu, non récupérables même après `innerHTML = ""` et GC forcé — la
|
||
suite JSDOM `xlsx-viewer` (163 cas) épuisait le tas vers le 45ᵉ montage. La
|
||
croissance par blocs offre la même étendue sans payer le coût d'un coup.
|
||
|
||
**Trois goulots levés** — toujours utiles sur la grille atteinte :
|
||
|
||
| Goulot | Avant | Après |
|
||
|---|---|---|
|
||
| `findTd` | un `querySelector` par appel → 26 000 requêtes pour une colonne | **index `ref → td`** avec auto-réparation |
|
||
| `refreshPanelFormulas` | `cloneNode` sur chaque cellule, à chaque frappe | court-circuit sur cellule vide sans formule |
|
||
| `applySheetMeta` | toutes les cellules touchées | court-circuit sur celles que le classeur ne style pas |
|
||
|
||
**Sorties.** L'export (CSV / Markdown / HTML / impression) écarte les lignes et
|
||
colonnes vides de queue : sans cela un classeur de deux colonnes exportait les
|
||
26 colonnes du quadrillage.
|
||
|
||
> **Reste à faire.** La virtualisation par fenêtre (ne garder que les lignes
|
||
> visibles et recycler au défilement) remplacerait la croissance par blocs si la
|
||
> grille de 1000 lignes redevenait lourde dans le navigateur. |