🐛 fix(touch-pointer): repère du zoom (#41) et teardown des plugins (#42) - #71
Merged
Conversation
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
force-pushed
the
fix/zoom-referentiel
branch
from
August 13, 2026 11:41
de3f442 to
d423236
Compare
This was referenced Aug 13, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
_toggleZoomcalculait sa translation à partir dewindow.innerWidth/innerHeight, alors qu'il applique letransformsur#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 :
La zone de slide devenait entièrement blanche, sans moyen de revenir en arrière.
Correctif
touch-pointer/zoom.ts, testable sans layout (jsdom n'en calcule pas) :t = s · (centre − point), dans le repère du frame ;(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 ;_toggleZoomreçoit les pourcentages bruts et les convertit contre le rect du frame ;overflow: hiddensur#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 :
Chaque événement du plugin repartait donc en autant d'exemplaires qu'il y avait eu de cycles. Après correctif,
callbacksplafonne à 1.Correctif
Plugin.unload()(classe de base) purge les callbacks et repasseinitializedàfalse; les surcharges appellentsuper.unload();clearIntervaldu timer de masquage, restauration des styles posés sur le frame (dimensions, transition, curseur), remise à zéro dutransform— désactiver en état zoomé laissait sinon la slide hors cadre ;messageétait enregistré via une lambda inline, donc impossible à détacher ; référence stabilisée ;unload()était un no-op, mais la base remet désormaisinitializedàfalse: sans détacher leurs listeners, une réactivation les doublerait.Tests
computeZoomTransform, dont une propriété de recouvrement balayant toutes les positions de clic ;_toggleZoom, dont un reproduisant la disproportion fenêtre/frame de la vue presenter ;Plugin.unload(), 6 cas de teardown sur touch-pointer, détachement des listeners sur keyboard et touch ;pluginServicecouvrant trois cycles complets ;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 auditremonte 5 vulnérabilités high (nanoid, postcss, socket.io-parser, undici) — vérifié : identiques surdevelop, donc préexistantes et hors périmètre de cette PR. Elles méritent leur propre passe de mise à jour.Closes #41
Closes #42