Skip to content

Paste a picture into a text block as an inline image (BL-17014) - #8499

Open
StephenMcConnel wants to merge 1 commit into
masterfrom
BL-17014-PasteInlineImageInText
Open

StephenMcConnel wants to merge 1 commit into
masterfrom
BL-17014-PasteInlineImageInText

Conversation

@StephenMcConnel

@StephenMcConnel StephenMcConnel commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Pasting a picture into a text block pasted the picture's file path as text instead of the picture (BL-17014). Ctrl+V in a text block is left to the browser and CKEditor, and most picture copies put the path or URL on the clipboard as text beside the picture: Bloom's own Copy Image, a file copied in Explorer, a browser's "Copy image". So the text is what got pasted. The top-bar Paste button sent the picture to the page's canvas, or pasted the same text when the page had no canvas.

What the PR does

  • With the focus in a text block that can take inline images, pasting a picture (Ctrl+V or the Paste button) adds an inline image to that block holding the picture. The image goes where Insert Image puts one: docked right, at the start of the block.
  • It reuses the canvas paste's round trip through C# (editView/pasteImage). JS posts editView/pasteImage with an id that starts with makeNewInlineImage and is unique to that paste. C# copies the clipboard picture into the book folder as it always has and calls changeImage with that id, which creates the inline image, with the picture already in it, in the block that paste was for. A failed or cancelled paste leaves nothing behind, and one Undo takes back the whole paste (insertInlineImage can now fill in the picture before it records its undo entry).
  • With an inline image selected, the pasted picture replaces its picture instead, through the same command as the image's own "Paste image" button (whose menu already lists Ctrl+V). Bloom leaves an image it has just inserted, pasted or changed selected, so Insert Image followed by a paste fills the new image, and a second paste right after a first replaces it, as on a canvas. Clicking in the text deselects the image.
  • Until the picture arrives, either kind of paste holds a page-content delay, so a save made in the meantime waits for the picture. For a paste over an existing picture this lives in doImageCommand, so the image toolbar's "Paste image" (on canvas pictures too) gets it as well, and a second paste over the same picture before C# has answered the first is dropped (it would only bring the same clipboard picture again).
  • One small C# change: EditingModel.ChangePicture reports whether importing the picture worked, so that OnPasteImage tells the page (removeImageId) when it didn't. Before, a failed import left the page waiting for a picture that never came.
  • A clipboard that holds formatted text as well as a picture (a Word or Excel selection, part of a web page) still pastes as text. The picture there is usually a rendering of that same text.
  • Text blocks that can't take inline images (canvas text boxes, xmatter and data-book fields, image descriptions) keep their old paste behavior. So does a paste with a canvas picture selected: that still replaces the picture (BL-16542), because the target is chosen by the focus, not by where the text selection was left.
  • Behavior change: the Paste button, with the focus in an ordinary text block, used to put the picture on the page's canvas. It now adds an inline image to that block. With the focus anywhere else, it still pastes onto the canvas.

The new code is in bookEdit/js/inlineImagePaste.ts.

Screenshots

A picture pasted into a text block, selected, with its toolbar:

A picture pasted into a text block appears at the block's top right, selected, with its toolbar

Risk Evaluation

These shared paths change:

  • A capture-phase paste listener on the page document sees every paste in the edit page. It returns at once unless the focus is in an eligible text block and the clipboard holds just a picture; only then does it stop the event. Every other paste (text, HTML, pastes in canvas text boxes and form fields) goes on as before.
  • changeImage and removeImageId, which C# calls for every picture change and every failed paste: changeImage gains an early branch for ids that start with makeNewInlineImage, and both end any pending paste for their id (a lookup that does nothing for other ids).
  • doImageCommand's paste, used by the "Paste image" command on every picture, canvas ones included, now holds a save delay and drops a second paste over the same picture until C# has answered.
  • OnPasteImage (C#) now calls RemoveUnneededImageId when importing the picture fails, as it already did for every other failure.
  • pasteImpl (the Paste button) gains a check before its canvas branch.

The insertInlineImage change only moves the undo commit after an optional callback; Insert Image passes none and behaves as before.

Ecosystem Impact

None expected. The pasted picture is an ordinary inline image, the same markup that Insert Image followed by Change Image produces, so Bloom Player, publishing and older versions see nothing new. No API change (the C# change is internal to the edit view), no new dependency, no new localizable strings: the error messages are the existing paste-image ones.

E2E Coverage

No end-to-end test covers this. Driving it needs a picture on the Windows clipboard, which the e2e suite does not set up. Unit tests cover when a paste becomes an inline image or replaces a selected one (the clipboard checks for Ctrl+V and for the Paste button, and which text blocks qualify), the round trip through the paste's id (including two quick pastes, and a paste C# abandons), the page-save delay, and the single undo entry. It was also checked by hand in a running Bloom: an Explorer file copy, a Bloom-style picture plus path, the Paste button, a Word-style clipboard (left as text), and a paste over a selected inline image (replaced in every language, and undone by the Undo button).

Notion Test Suite

None.

Preflight report: https://bloombooks.github.io/dev-process-artifacts/deciders/bloomdesktop-bl-17014-pasteinlineimageintext.html

Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-17014

Devin review


This change is Reviewable

@greptile-apps

greptile-apps Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in Greptile

[Medium impact] The PR appears safe to merge; no new actionable issues were found.

Summary

Adds picture pasting into eligible text blocks and replacement of selected inline pictures.

  • Picture-only pastes add or replace inline images in text blocks.
  • Page saves wait for picture pastes to finish.

Reviews (4) · Last reviewed commit: "Paste a picture into a text block as an ..." · Reviewed by Greptile

Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts
Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts
Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts
@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] Consulted Devin on 2026-10-23 16:35 UTC up to commit f4bc7d7.

  • Bug, a pending picture can be left out of a page save: fixed in f4bc7d7, and Devin's re-review marks it resolved. Thread. Greptile raised the same point; thread.
  • Investigate, picture-only check accepts text-free structured HTML: not an issue; such a paste is meant to give the picture. Thread.
  • One informational note (no test of the Paste button's clipboard check): tests for it were added in f4bc7d7.

Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts Outdated
@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] @greptile-apps review

@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] Consulted Devin on 2026-10-23 17:24 UTC up to commit d7a39a1.

  • Bug, a paste over a selected inline image could let a save keep the old picture (raised on d1b1e7e): fixed in d7a39a1. Thread.
  • Devin's review of d7a39a1 raised nothing new. It still lists that finding and the earlier ones with their old commits; the fixes are in d7a39a1, and their threads are answered and resolved.

Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts Outdated
@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] Consulted Devin on 2026-10-23 17:40 UTC up to commit 690f545.

Re-review clean: nothing new. Devin marks both of its bugs resolved (save during a new paste, save during a paste over a selected image); its two flags are the earlier ones, already answered.

@StephenMcConnel StephenMcConnel left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StephenMcConnel reviewed 7 files and all commit messages, and resolved 3 discussions.
Reviewable status: 0 of 7 files reviewed, all discussions resolved.

@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] @greptile-apps review

Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts
Comment thread src/BloomBrowserUI/bookEdit/js/inlineImagePaste.ts
@StephenMcConnel

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5.5 from Steve McConnel's machine during preflight] Consulted Devin on 2026-10-23 18:30 UTC up to commit 8a7b201.

  • On 696cba0 (the simplification) Devin raised two bugs, both answered as not acting, with reasons: image files without a MIME type (the file-name fallback was removed on purpose) and cancelled pastes keep an entry (it lasts only until the page changes).
  • Its review of 8a7b201 raised nothing new; every finding it lists belongs to an earlier commit and is fixed or answered on its thread.

@StephenMcConnel StephenMcConnel left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StephenMcConnel+CLAU resolved 2 discussions.
Reviewable status: 0 of 10 files reviewed, all discussions resolved.

@StephenMcConnel StephenMcConnel left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StephenMcConnel reviewed 7 files and all commit messages.
Reviewable status: 0 of 10 files reviewed, all discussions resolved.

Pasting a picture into a text block pasted the picture's file path as
text: Ctrl+V there was left to CKEditor, and Bloom's Copy Image, an
Explorer file copy and a browser's "Copy image" all put the path or URL
on the clipboard beside the picture.

Now a paste of just a picture (Ctrl+V, or the top-bar Paste button) goes
to inline images when the focus is in a text block that can take them,
or when an inline image is selected:
- With an inline image selected, the picture replaces its picture,
  through the image's own "Paste image" command (doImageCommand).
- Otherwise it becomes a new inline image in the focused block. JS posts
  editView/pasteImage with an id starting "makeNewInlineImage" and unique
  to the paste; C# imports the picture and calls changeImage with that
  id, which inserts the image with the picture already in it
  (insertInlineImage's setUpPicture), so one Undo takes back the paste
  and a failed paste leaves nothing behind.
- A clipboard with formatted text as well as a picture (Word, Excel)
  still pastes as text. Canvas text boxes, xmatter and data-book fields,
  image descriptions, and a paste with a canvas picture selected behave
  as before.

Every paste of a picture now holds a page-content delay until C#
answers, so a save waits for the picture, and doImageCommand drops a
second paste over the same picture until the first is answered. So that
C# always answers, EditingModel.ChangePicture now reports whether it
worked, and OnPasteImage calls RemoveUnneededImageId when it didn't.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@StephenMcConnel
StephenMcConnel force-pushed the BL-17014-PasteInlineImageInText branch from 8a7b201 to 72f33c5 Compare October 23, 2026 19:55
@StephenMcConnel
StephenMcConnel marked this pull request as ready for review October 23, 2026 19:56
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