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
Open
fix: undo a drag activity on the page you are given, not the one we remembered (BL-13502)#441JohnThomson wants to merge 1 commit into
JohnThomson wants to merge 1 commit into
Conversation
JohnThomson
force-pushed
the
undo-prepare-activity-scope
branch
from
September 4, 2026 22:17
ea858c5 to
e152e34
Compare
…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
force-pushed
the
undo-prepare-activity-scope
branch
from
September 4, 2026 22:42
ab837a6 to
9ba5b99
Compare
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.
The problem.
prepareActivityrecords where each draggable started, keeping a reference to the element: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:
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.showingPagestops the previous activity before starting the next, so the page being undone is the prepared one and every branch behaves exactly as before.showCorrectandperformTryAgainpass 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