Web frame: position does not sync to other viewers when moved/resized #101
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_whiteboard#101
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
When a webframe (iframe-backed object) is moved in tab A, tab B is left in a desynced state: the Konva placeholder card (header + URL label + dark background) moves to the new position, but the actual iframe DOM overlay (the live website content) stays anchored at the old screen coordinates. After tab B is reloaded the two pieces snap back together at the persisted position, so the data is correct on disk — only the live update is broken.
Steps to reproduce
https://example.com). Wait for the iframe to load in both tabs.Expected
In tab B the iframe DOM overlay (live website content) follows the Konva group as it moves, the same way other objects' visuals do.
Actual
In tab B the Konva placeholder card moves but the iframe overlay stays at the old screen position. The two visually drift apart on every drag. Reloading tab B brings them back together at the persisted location.
Root cause (likely)
webframe.jspositions the iframe via an absolutely-positioned<div>overlay outside the Konva stage.updateOverlayPosition(id, group)is the only function that writes the overlay's screenleft/top. It is currently only called on:dragstart/dragendof the group itself,dragstart/dragend/wheel(pan and zoom).The
applySyncUpdatebranch fortype === 'webframe'insync.jsonly patchesexisting.url— it does NOT callWhiteboardWebframe.updateOverlayPosition(id, node)after the position write at the top ofapplySyncUpdate. So a remote position update moves the Konva group but the iframe overlay is never repositioned.Suggested fix
Two complementary changes:
Expose
WhiteboardWebframe.updateOverlayPosition(id, group)(already exported on the module) and haveapplySyncUpdatecall it for any webframe whose position/dimensions changed in the incoming payload, after the Konva group'sx/y/width/heighthave been written. Alternatively, have webframe.js install anode.on('xChange yChange transform')listener that re-runsupdateOverlayPositionon every Konva position change — this is the most general fix and also covers programmatic transforms (resize from the Properties panel, undo/redo, etc.).Ensure the same hook fires when the stage's transform changes programmatically (not just via user drag/wheel). The current
stage.on('dragstart/dragend/wheel')listeners missWhiteboardCanvas.setZoom(...)andstage.position(...)calls — see the related presentation-mode bug for the same root cause manifestation.Acceptance criteria
Spec — Issue #101: Webframe iframe overlay must follow remote position/size updates
Objective
Make the iframe DOM overlay (
#wf-overlay-<id>) on a receiving client follow the Konva placeholder when a remote user drags or resizes a webframe. Persistence is already correct; only the live (debounced WebSocket) update path is broken.Requirements
object.updatedbroadcast.Files to Modify
crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.js— the only file that needs a real change.Files to Leave Alone
crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js— already exposesrefreshOverlay(id)which callsupdateOverlayPositioninternally and reads dimensions from the.bgrect (the source of truth after a sync writes the geometry). It also exposesupdateUrl(id, url)which updates the iframesrcand the.labelKonva text.properties.js,objects.js, server crates — out of scope.Diagnosis
applySyncUpdateinsync.js:node.x(obj.x)/node.y(obj.y)near the top.bg.width/height, header width, placeholder/label widths in the dimensions block.type === 'webframe'branch only patchesexisting.url; never touches the overlay.There is no call to
WhiteboardWebframe.refreshOverlay/updateOverlayPositionanywhere inapplySyncUpdate, which is why a full reload (which reconstructs viacreateWebframe) brings them back together but live updates do not.Mechanism — Option A (chosen)
Add a single
WhiteboardWebframe.refreshOverlay(strId)call insideapplySyncUpdate's existingtype === 'webframe'branch. Run it after the existing geometry writes earlier in the function. Optionally also callWhiteboardWebframe.updateUrl(strId, data.url)so a remote URL change propagates to the iframesrcand.labelwithout a reload (same root-cause class — currently onlyexisting.urlupdates locally).Reject Option B (Konva
xChange/yChange/transformlisteners on the group): more general but invasive — fires on every transient transform tick during a local drag/transform, creating extra DOM writes per frame on the originator.Reject Option C (polling): explicitly out of scope.
Step-by-Step Plan
Step 1 — Patch
applySyncUpdateinsync.jsFile:
crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.jsLocate the existing webframe branch (around lines 666-669):
Replace with:
Dependencies:
strIdis already in scope; the bg/position writes earlier in the function are unconditional and run before this branch.Step 2 — Verify the fix relies only on already-exported pieces
WhiteboardWebframe.refreshOverlayis on the module's public API — no export change needed.WhiteboardWebframe.updateUrlis on the module's public API — no export change needed.updateOverlayPositionreads bg dims as source of truth, so the dimensions block writing tobg.width/heightbefore our branch means the overlay picks up the new size on the same call._hiddenForInteractiondefaults toundefined/falseon the receiver because the receiver never callshideOverlay(id)for a remote drag —stage.on('dragstart.wf_<id>')fires only on local user stage drag, not on programmatic node mutation inapplySyncUpdate.Acceptance Criteria
dragstartand reappears ondragend.srcand.labeltext on the receiver without a reload.Notes / Caveats
refreshOverlayonly updates the wrapper'sstyle.left/top/width/height; the iframe inherits viawidth: 100%; height: 100%. Live page state is preserved.xChange/yChange/transformlisteners on the group at create time. Option A is sufficient and safer.Test Results
Implementation Summary
One file changed (
sync.js), +7/-0 inside the existing webframe branch ofapplySyncUpdate.Root cause
applySyncUpdatewritesnode.x/yand the bg dimensions on every incomingobject.updated, but itstype === 'webframe'branch only patchedexisting.url. The iframe DOM overlay (an absolutely-positioned<div>outside the Konva stage) was never repositioned/resized on the receiver — only the originator's localdragstart/dragendand stagewheellisteners calledupdateOverlayPosition. Reload masked the bug becausecreateWebframereconstructs the overlay from scratch.crates/hero_whiteboard_ui/static/web/js/whiteboard/sync.jsInside the existing webframe branch of
applySyncUpdate:WhiteboardWebframe.updateUrl(strId, data.url)when the URL changes (so a remote URL change updates the iframesrcand the.labelKonva text live, not only on reload).WhiteboardWebframe.refreshOverlay(strId)unconditionally at the end of the branch.refreshOverlayreads dimensions from the.bgrect (which the dimensions block earlier inapplySyncUpdatehas already updated) and writes them onto the wrapper'sstyle.left/top/width/height. The iframe inherits viawidth: 100%; height: 100%, so live page state is preserved across resize.Both helpers were already on
WhiteboardWebframe's public API — no export changes needed.Verification
cargo fmt --all -- --check: cleancargo check --workspace: cleancargo clippy --workspace -- -D warnings: cleancargo test --workspace: passnode --check sync.js: cleanManual smoke test
Notes / scope