From 1b2030b36aba643d5ee5e06256c504dc0f791c75 Mon Sep 17 00:00:00 2001 From: doodlewind <7312949+doodlewind@users.noreply.github.com> Date: Wed, 23 Apr 2025 04:30:26 +0000 Subject: [PATCH] fix(editor): should not paste in readonly page mode (#11913) ### TL;DR Prevent pasting content when a document is in readonly mode. ### What changed? Added a check in the `PageClipboard` class to prevent pasting operations when the document is in readonly mode. The function now returns early if `this.std.store.readonly` is true, preventing any clipboard operations from being executed. ### How to test? 1. Open a document and add some content 2. Set the document to readonly mode: `document.querySelector('affine-page-root')!.doc.readonly = true` 3. Try to paste content into the document using: - Regular paste operation - Keyboard shortcut (Ctrl+V/Cmd+V) 4. Verify that no content is pasted and the document remains unchanged 5. Set the document back to editable mode and confirm pasting works again ### Why make this change? This change ensures that documents in readonly mode maintain their integrity by preventing unintended modifications through clipboard operations. This is consistent with the expected behavior of readonly documents, where users should not be able to modify content through any means. --- .../root/src/clipboard/page-clipboard.ts | 1 + .../blocksuite/clipboard/clipboard.spec.ts | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/blocksuite/affine/blocks/root/src/clipboard/page-clipboard.ts b/blocksuite/affine/blocks/root/src/clipboard/page-clipboard.ts index e92a3d5e4e..afeecb83ae 100644 --- a/blocksuite/affine/blocks/root/src/clipboard/page-clipboard.ts +++ b/blocksuite/affine/blocks/root/src/clipboard/page-clipboard.ts @@ -80,6 +80,7 @@ export class PageClipboard extends ReadOnlyClipboard { const e = ctx.get('clipboardState').raw; e.preventDefault(); + if (this.std.store.readonly) return; this.std.store.captureSync(); this.std.command .chain() diff --git a/tests/affine-local/e2e/blocksuite/clipboard/clipboard.spec.ts b/tests/affine-local/e2e/blocksuite/clipboard/clipboard.spec.ts index 04e328782a..7e5384db86 100644 --- a/tests/affine-local/e2e/blocksuite/clipboard/clipboard.spec.ts +++ b/tests/affine-local/e2e/blocksuite/clipboard/clipboard.spec.ts @@ -23,6 +23,7 @@ import { import { setSelection } from '@affine-test/kit/utils/selection'; import type { CodeBlockComponent } from '@blocksuite/affine-block-code'; import type { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph'; +import type { PageRootBlockComponent } from '@blocksuite/affine-block-root'; import type { BlockComponent } from '@blocksuite/std'; import { expect, type Page } from '@playwright/test'; @@ -434,3 +435,38 @@ test.describe('paste to code block', () => { await verifyCodeBlockContent(page, 0, markdownText); }); }); + +test.describe('paste in readonly mode', () => { + test('should not paste content when document is in readonly mode', async ({ + page, + }) => { + await createParagraphBlocks(page, ['This is a test paragraph']); + const { blockIds } = await getParagraphIds(page); + const initialParagraphCount = blockIds.length; + + await page.evaluate(() => { + const pageRoot = document.querySelector( + 'affine-page-root' + ) as PageRootBlockComponent; + pageRoot.doc.readonly = true; + }); + + await setSelection(page, blockIds[0], 0, blockIds[0], 4); + await pasteContent(page, { + 'text/plain': ' - Added text that should not appear', + }); + + await verifyParagraphContent(page, 0, 'This is a test paragraph'); + + await pressEnter(page); + await pasteContent(page, { 'text/plain': 'This should not be pasted' }); + + const { blockIds: afterParagraphIds } = await getParagraphIds(page); + expect(afterParagraphIds.length).toBe(initialParagraphCount); + + await setSelection(page, blockIds[0], 0, blockIds[0], 4); + await pasteByKeyboard(page); + + await verifyParagraphContent(page, 0, 'This is a test paragraph'); + }); +});