diff --git a/frontend/src/lib/components/TranscriptionBlock.svelte b/frontend/src/lib/components/TranscriptionBlock.svelte index 982b43ff..417c3fbe 100644 --- a/frontend/src/lib/components/TranscriptionBlock.svelte +++ b/frontend/src/lib/components/TranscriptionBlock.svelte @@ -79,17 +79,6 @@ let leftBorderClass = $derived( saveState === 'error' ? 'border-l-2 border-error' : active ? 'border-l-2 border-turquoise' : '' ); -// Single source of truth for the editor's textarea — stored on attach so -// we can read selection bounds for quote selection without re-querying the DOM. -let textareaEl: HTMLTextAreaElement | null = null; - -function captureTextarea(node: HTMLTextAreaElement) { - textareaEl = node; - return () => { - textareaEl = null; - }; -} - function emitChange() { onTextChange(localText, localMentions); } @@ -101,17 +90,6 @@ async function handleDelete() { }); if (confirmed) onDeleteClick(); } - -function handleTextareaMouseUp() { - if (!textareaEl) return; - const start = textareaEl.selectionStart; - const end = textareaEl.selectionEnd; - if (start !== end) { - selectedQuote = localText.substring(start, end); - } else { - selectedQuote = null; - } -}
{m.transcription_block_quote_hint()}
diff --git a/frontend/src/lib/components/TranscriptionBlock.svelte.spec.ts b/frontend/src/lib/components/TranscriptionBlock.svelte.spec.ts index c05a8c88..85961e75 100644 --- a/frontend/src/lib/components/TranscriptionBlock.svelte.spec.ts +++ b/frontend/src/lib/components/TranscriptionBlock.svelte.spec.ts @@ -41,8 +41,7 @@ describe('TranscriptionBlock — rendering', () => { it('renders text in textarea', async () => { renderBlock(); - const textarea = page.getByRole('textbox'); - await expect.element(textarea).toHaveValue('Liebe Mutter,'); + await expect.element(page.getByText('Liebe Mutter,')).toBeInTheDocument(); }); it('renders optional label when provided', async () => { @@ -226,14 +225,18 @@ describe('TranscriptionBlock — delete confirmation', () => { // ─── Quote selection ───────────────────────────────────────────────────────── describe('TranscriptionBlock — quote selection', () => { - it('shows quote hint after text is selected in textarea', async () => { + it('shows quote hint after text is selected in the editor', async () => { renderBlock({ text: 'Breslau, den 12. August' }); await page.getByRole('textbox').click(); - // Select text and fire mouseup via native DOM — locator.selectText/dispatchEvent not available - const el = document.querySelector('textarea') as HTMLTextAreaElement; - el.focus(); - el.setSelectionRange(0, el.value.length); - el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true })); + // Select all text in the contenteditable via the native Selection API. + // Tiptap fires selectionUpdate which the block forwards as onSelectionChange. + const editorEl = document.querySelector('[role="textbox"]') as HTMLElement; + const range = document.createRange(); + range.selectNodeContents(editorEl); + const selection = window.getSelection()!; + selection.removeAllRanges(); + selection.addRange(range); + editorEl.dispatchEvent(new Event('input', { bubbles: true })); await expect.element(page.getByText(/Zitat/)).toBeInTheDocument(); }); });