Skip to content

fix: undo a drag activity on the page you are given, not the one we remembered (BL-13502) - #441

Open
JohnThomson wants to merge 1 commit into
alphafrom
undo-prepare-activity-scope
Open

fix: undo a drag activity on the page you are given, not the one we remembered (BL-13502)#441
JohnThomson wants to merge 1 commit into
alphafrom
undo-prepare-activity-scope

Conversation

@JohnThomson

@JohnThomson JohnThomson commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

The problem. prepareActivity records where each draggable started, keeping a reference to the element:

positionsToRestore.push({ x: elt.style.left, y: elt.style.top, elt });

undoPrepareActivity(page) then restored through those references, so it put back the page it had prepared whichever page you passed it — and before that stopped whatever was playing and emptied the record. Only the rest of it cleaned the page it was given.

Inside the player that never shows: it only ever undoes the page it prepared. Bloom desktop hands it a detached copy — that is how a toolbox tool takes its markup off the copy of the page being saved, and Bloom now saves whenever the page changes. Two faults came out of that, pulling in opposite directions:

  • the live page was put back mid-game, so a tester's every drag undid itself about a quarter of a second later and a drag activity could not be played at all; and
  • the copy was not put back, so a save made during play recorded the draggables wherever the tester had left them, overwriting the book's authored start positions.

Both were verified in a running Bloom. Gathering the page while an item was dragged to 333/444 left the live element back at its authored 60/240, and returned content containing class="… bloom-draggedToTarget" style="left: 333px; top: 444px" — which is what would have been written to the book.

The change. Both faults are the same mistake — acting on the remembered elements instead of the page you were given — so they go together. Positions are recorded against the draggable's id and restored by looking that id up in the page passed in, which does the right thing for the prepared page and for a copy of it alike. Stopping playback, and forgetting the record, stay tied to the prepared page: they end the session, and cleaning a copy is not the end of anything.

Nothing changes for the player. ActivityManager.showingPage stops the previous activity before starting the next, so the page being undone is the prepared one and every branch behaves exactly as before. showCorrect and performTryAgain pass the page they already have.

Tests cover both faults and the two ways of getting the fix wrong: undoing a copy restores the copy, undoing a copy leaves the live page's drags alone, undoing the prepared page still restores it, and cleaning a copy does not cost the live page its own restore later. Full suite green: 158 tests.

Found while working on BloomDesktop BL-13502, which is where the copy-of-the-page save comes from. That PR currently works around the first fault by not watching the page while a game is in its Play tab — which does nothing for the second, since an explicit save gathers the page directly. Once this is merged and the dependency bumped, the workaround comes out and both are fixed properly.

🤖 Generated with Claude Code


This change is Reviewable

@JohnThomson
JohnThomson force-pushed the undo-prepare-activity-scope branch from ea858c5 to e152e34 Compare September 4, 2026 22:17
@JohnThomson JohnThomson changed the title fix: keep undoPrepareActivity out of pages it was not given (BL-13502) fix: undo a drag activity on the page you are given, not the one we remembered (BL-13502) Sep 4, 2026
…emembered (BL-13502)

prepareActivity records where each draggable started. undoPrepareActivity then
restored those positions through the element references it had kept, so it put
back the page it had prepared no matter which page you passed it -- and, before
that, stopped whatever was playing and emptied the record.

Inside the player that never shows, because it only ever undoes the page it
prepared. Bloom desktop hands it a detached COPY: that is how a toolbox tool
takes its markup off the copy of the page being saved, and Bloom saves whenever
the page changes. Two things went wrong from that, and they pull in opposite
directions:

  - the live page was put back mid-game, so a tester's every drag undid itself
    a moment later and the activity could not be played; and
  - the copy was NOT put back, so a save made during play recorded the page
    with the draggables wherever the tester had left them, and the book's
    authored start positions were overwritten.

Both are the same mistake -- acting on the remembered elements rather than the
given page -- so both go together. Positions are recorded against the
draggable's id and restored by looking that id up in the page passed in, which
does the right thing for the prepared page and for a copy of it alike. Stopping
playback, and forgetting the record, stay tied to the prepared page: they end
the session, and cleaning a copy is not the end of anything.

The restore walks the page's draggables once and asks a Map what it recorded
for each, rather than searching the page once per recorded id (John Thomson's
suggestion). One pass instead of one per draggable, and no selector built out
of an id -- though that last is worth little on its own, since getTarget and
others still interpolate the same ids.

Nothing changes for the player. ActivityManager.showingPage stops the previous
activity before starting the next, so the page being undone is the prepared one
and every branch behaves as before. showCorrect and performTryAgain pass the
page they already have.

Tests cover both faults and the two ways of getting them wrong: undoing a copy
restores the copy, undoing a copy leaves the live page's drags alone, undoing
the prepared page still restores it, and cleaning a copy does not cost the live
page its own restore later.
@JohnThomson
JohnThomson force-pushed the undo-prepare-activity-scope branch from ab837a6 to 9ba5b99 Compare September 4, 2026 22:42
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