Skip to content

🐛 fix(touch-pointer): repère du zoom (#41) et teardown des plugins (#42) - #71

Merged
jefBinomed merged 2 commits into
developfrom
fix/zoom-referentiel
Aug 13, 2026
Merged

🐛 fix(touch-pointer): repère du zoom (#41) et teardown des plugins (#42)#71
jefBinomed merged 2 commits into
developfrom
fix/zoom-referentiel

Conversation

@jefBinomed

Copy link
Copy Markdown
Collaborator

Corrige les deux bugs du plugin touch-pointer qui restaient réellement d'actualité, après re-test des 5 bugs ouverts sur l'app réelle (les trois autres — #46, #47, #48 — ont été fermés, preuves à l'appui, dans leurs issues respectives).

#41 — le zoom projetait la slide hors de l'écran

_toggleZoom calculait sa translation à partir de window.innerWidth/innerHeight, alors qu'il applique le transform sur #slideViewFrame. En vue presenter, ce frame n'occupe que 3/5 de la largeur : les deux repères ne coïncident pas.

Mesuré avant correctif, pour une fenêtre de 1280 px :

section (conteneur) : x =   8 →  760
frame après zoom    : x = 835 → 2339
transform           : translateX(1203px) translateY(691px) scale(2)

La zone de slide devenait entièrement blanche, sans moyen de revenir en arrière.

Correctif

  • géométrie extraite dans touch-pointer/zoom.ts, testable sans layout (jsdom n'en calcule pas) : t = s · (centre − point), dans le repère du frame ;
  • translation plafonnée à (s − 1) · taille / 2, pour que le frame agrandi recouvre toujours sa boîte — sans ce plafond, un clic en coin décolle un bord et laisse apparaître du vide ;
  • _toggleZoom reçoit les pourcentages bruts et les convertit contre le rect du frame ;
  • overflow: hidden sur #slideViewSection, en filet de sécurité : même en cas de régression future de la géométrie, plus rien ne peut peindre hors du cadre.

#42 — teardown incomplet du plugin

Le symptôme décrit dans l'issue (pointer.remove() sans effet) est corrigé depuis le passage au shadow DOM : 3 cycles activer/désactiver laissent bien 0 pointeur. Mais le reste du teardown ne suivait pas.

Mesuré sur l'app réelle, avant correctif :

cycle 1 → callbacks = 1
cycle 2 → callbacks = 2
cycle 3 → callbacks = 3

Chaque événement du plugin repartait donc en autant d'exemplaires qu'il y avait eu de cycles. Après correctif, callbacks plafonne à 1.

Correctif

  • Plugin.unload() (classe de base) purge les callbacks et repasse initialized à false ; les surcharges appellent super.unload() ;
  • touch-pointer : clearInterval du timer de masquage, restauration des styles posés sur le frame (dimensions, transition, curseur), remise à zéro du transform — désactiver en état zoomé laissait sinon la slide hors cadre ;
  • touch-pointer : le handler message était enregistré via une lambda inline, donc impossible à détacher ; référence stabilisée ;
  • keyboard et touch : même traitement. Ils n'étaient pas concernés tant que unload() était un no-op, mais la base remet désormais initialized à false : sans détacher leurs listeners, une réactivation les doublerait.

Tests

  • 8 cas unitaires sur computeZoomTransform, dont une propriété de recouvrement balayant toutes les positions de clic ;
  • 3 cas sur _toggleZoom, dont un reproduisant la disproportion fenêtre/frame de la vue presenter ;
  • contrat de Plugin.unload(), 6 cas de teardown sur touch-pointer, détachement des listeners sur keyboard et touch ;
  • régression sur pluginService couvrant trois cycles complets ;
  • un e2e golden-path (14-plugins) qui asserte que le frame zoomé recouvre sa section — vérifié rouge sans le correctif (covers: false), vert avec.

./scripts/verify.sh : typecheck, lint, coverage, e2e, build et docs OK.

⚠️ npm audit remonte 5 vulnérabilités high (nanoid, postcss, socket.io-parser, undici) — vérifié : identiques sur develop, donc préexistantes et hors périmètre de cette PR. Elles méritent leur propre passe de mise à jour.

Closes #41
Closes #42

Le zoom du plugin touch-pointer calculait sa translation à partir de
window.innerWidth/innerHeight alors qu'il applique le transform sur
#slideViewFrame. En vue presenter, le frame n'occupe que 3/5 de la
largeur : mesuré avant correctif, la slide était projetée en x=835..2339
pour une fenêtre de 1280, soit entièrement hors de l'écran.

- extraction de la géométrie dans touch-pointer/zoom.ts, testable sans
  layout (jsdom n'en calcule pas) : t = s · (centre − point), dans le
  repère du frame ;
- plafonnement de la translation à (s − 1) · taille / 2, pour que le
  frame agrandi recouvre toujours sa boîte — sans quoi un clic en coin
  décolle un bord et laisse apparaître du vide ;
- _toggleZoom reçoit désormais les pourcentages bruts et les convertit
  contre le rect du frame, plus contre la fenêtre ;
- overflow: hidden sur #slideViewSection en filet de sécurité.

Tests : 8 cas unitaires sur la fonction pure (dont une propriété de
recouvrement balayant toutes les positions de clic), 3 cas sur
_toggleZoom, et un e2e golden-path vérifié rouge sans le correctif.
Le pointeur quittait bien le DOM à la désactivation — le symptôme décrit
dans l'issue est corrigé depuis le passage au shadow DOM — mais le reste
du teardown ne suivait pas. Mesuré sur l'app réelle, trois cycles
activer/désactiver faisaient grimper `callbacks` à 1, 2 puis 3 : chaque
événement du plugin repartait en autant d'exemplaires.

- Plugin.unload() (classe de base) purge les callbacks et repasse
  `initialized` à false ; les surcharges appellent super.unload() ;
- touch-pointer : clearInterval du timer de masquage, restauration des
  styles posés sur le frame (dimensions, transition, curseur) et remise
  à zéro du transform — désactiver en état zoomé laissait sinon la slide
  hors cadre, sans retour possible ;
- touch-pointer : le handler `message` était enregistré via une lambda
  inline, donc impossible à détacher — référence stabilisée ;
- keyboard et touch : même traitement. Ils n'étaient pas concernés tant
  que unload() était un no-op, mais la base remet désormais
  `initialized` à false : sans détacher, une réactivation doublerait
  leurs listeners.

Tests : contrat de la classe de base, 6 cas de teardown sur
touch-pointer, détachement des listeners sur keyboard et touch, et une
régression sur pluginService couvrant trois cycles complets.
@jefBinomed
jefBinomed force-pushed the fix/zoom-referentiel branch from de3f442 to d423236 Compare August 13, 2026 11:41
@jefBinomed
jefBinomed merged commit 5a9afd6 into develop Aug 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant