Plakken in visuele documentmodus landt als blok onder de regel, niet op de cursor #2138

Closed
opened 2026-09-20 20:55:29 +00:00 by brenno · 0 comments
Owner

Symptoom

In de documenteditor (visuele stand, de default) plakt Cmd/Ctrl+V een stukje tekst niet op de cursorpositie. De geplakte tekst verschijnt als eigen blok onder de regel waarin de cursor staat — of helemaal onderaan het document.

Oorzaak

De plakroute in visuele modus loopt zo:

  1. WysiwygNotesField onderschept Cmd/Ctrl+V (_SanitizedPasteIntent, lib/widgets/markdown_editor/wysiwyg_notes_field.dart ~L243-259) en roept tryConsumePaste aan.
  2. Dat is _smartPaste (lib/widgets/parts/document_editor_layouts.dart ~L78-123): afbeelding → blok, tabel → blok, en voor alle overige tekst _insertPastedMarkdown(resolved.text).
  3. _insertPastedMarkdown (~L128-145) delegeert in visuele modus naar _requestVisualInsert(block: text).
  4. Die triggert _insertMarkdownBlockAtCaret in MarkdownNotesEditor (lib/widgets/markdown_editor/markdown_editor.dart ~L327-342) — het blok-invoegpad dat voor tabellen en afbeeldingen is bedoeld. _blockInsertOffset (~L379-390) zoekt bewust het einde van de regel waarin de cursor staat ("zo landt een tabel niet halverwege een zin") en voegt dáár in; is quill.selection invalide, dan landt het blok op document.length - 1 — helemaal onderaan.

Twee concrete gevolgen:

  • Tekst plakken midden in een zin eindigt onder die zin, niet waar de cursor staat.
  • Een actieve selectie wordt niet vervangen — het blokpad doet geen replace van de selectie.

Extra kwetsbaarheid: _smartPaste is async (klembord-image-check + Clipboard.getData + readClipboardHtml vooraf) en de invoeging loopt via een post-frame callback. Als de Quill-selectie in dat gat invalide wordt (focusverlies), is de fallback het documenteinde.

De bron-stand heeft dit niet: daar plakt _insertPastedMarkdown via _controller.selection op de echte caret. De caret-correcte route bestaat al in dezelfde widget: de fallback in _pasteSanitized doet controller.replaceText(index, length, text, …) — precies wat een gewone tekstplak moet doen.

Reproductie

  1. Document openen in Visueel, cursor midden in een zin zetten.
  2. Tekst plakken met Cmd/Ctrl+V.
  3. Werkelijk: tekst verschijnt op een nieuwe regel onder de zin (of onderaan). Verwacht: inline op de caret, selectie vervangen.

Oplossingsrichting

Splits de plakroute op aard van de inhoud:

  • Inline tekst (ClipboardMarkdownKind.markdown): op de Quill-caret invoegen en de actieve selectie vervangen — hergebruik het bestaande replaceText-pad uit _pasteSanitized (of geef _requestVisualInsert een inline-variant mee die niet via _blockInsertOffset loopt). De markdown→Quill-omzetting via MarkdownQuillCodec.documentFromMarkdown kan blijven, maar de delta moet op de caret landen i.p.v. als nieuw blok.
  • Echte blokken (tabel, afbeelding): het huidige blokpad is correct, behouden.
  • Vang de caret-positie vóór de async klembordlezing (_smartPaste start), zodat een invalide selectie na de await niet stilletjes naar het documenteinde flopt.

Randgeval: is markdownRoundTripsVisually false (fallback naar bronveld in visuele stand), dan is _controller.selection de juiste caret — die tak is al goed.

## Symptoom In de documenteditor (visuele stand, de default) plakt Cmd/Ctrl+V een stukje tekst **niet op de cursorpositie**. De geplakte tekst verschijnt als eigen blok onder de regel waarin de cursor staat — of helemaal onderaan het document. ## Oorzaak De plakroute in visuele modus loopt zo: 1. `WysiwygNotesField` onderschept Cmd/Ctrl+V (`_SanitizedPasteIntent`, `lib/widgets/markdown_editor/wysiwyg_notes_field.dart` ~L243-259) en roept `tryConsumePaste` aan. 2. Dat is `_smartPaste` (`lib/widgets/parts/document_editor_layouts.dart` ~L78-123): afbeelding → blok, tabel → blok, en voor **alle overige tekst** `_insertPastedMarkdown(resolved.text)`. 3. `_insertPastedMarkdown` (~L128-145) delegeert in visuele modus naar `_requestVisualInsert(block: text)`. 4. Die triggert `_insertMarkdownBlockAtCaret` in `MarkdownNotesEditor` (`lib/widgets/markdown_editor/markdown_editor.dart` ~L327-342) — het **blok-invoegpad** dat voor tabellen en afbeeldingen is bedoeld. `_blockInsertOffset` (~L379-390) zoekt bewust het einde van de regel waarin de cursor staat ("zo landt een tabel niet halverwege een zin") en voegt dáár in; is `quill.selection` invalide, dan landt het blok op `document.length - 1` — helemaal onderaan. Twee concrete gevolgen: - Tekst plakken midden in een zin eindigt **onder** die zin, niet waar de cursor staat. - Een actieve selectie wordt **niet vervangen** — het blokpad doet geen `replace` van de selectie. Extra kwetsbaarheid: `_smartPaste` is async (klembord-image-check + `Clipboard.getData` + `readClipboardHtml` vooraf) en de invoeging loopt via een post-frame callback. Als de Quill-selectie in dat gat invalide wordt (focusverlies), is de fallback het documenteinde. De bron-stand heeft dit niet: daar plakt `_insertPastedMarkdown` via `_controller.selection` op de echte caret. De caret-correcte route bestaat al in dezelfde widget: de fallback in `_pasteSanitized` doet `controller.replaceText(index, length, text, …)` — precies wat een gewone tekstplak moet doen. ## Reproductie 1. Document openen in Visueel, cursor midden in een zin zetten. 2. Tekst plakken met Cmd/Ctrl+V. 3. Werkelijk: tekst verschijnt op een nieuwe regel onder de zin (of onderaan). Verwacht: inline op de caret, selectie vervangen. ## Oplossingsrichting Splits de plakroute op aard van de inhoud: - **Inline tekst** (`ClipboardMarkdownKind.markdown`): op de Quill-caret invoegen en de actieve selectie vervangen — hergebruik het bestaande `replaceText`-pad uit `_pasteSanitized` (of geef `_requestVisualInsert` een inline-variant mee die niet via `_blockInsertOffset` loopt). De markdown→Quill-omzetting via `MarkdownQuillCodec.documentFromMarkdown` kan blijven, maar de delta moet op de caret landen i.p.v. als nieuw blok. - **Echte blokken** (tabel, afbeelding): het huidige blokpad is correct, behouden. - Vang de caret-positie **vóór** de async klembordlezing (`_smartPaste` start), zodat een invalide selectie na de await niet stilletjes naar het documenteinde flopt. Randgeval: is `markdownRoundTripsVisually` false (fallback naar bronveld in visuele stand), dan is `_controller.selection` de juiste caret — die tak is al goed.
brenno 2026-09-20 23:36:22 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#2138
No description provided.