Skip to content

Commit 0e68021

Browse files
committed
fix: handle SuperDoc context-menu paste
1 parent ed9a9f6 commit 0e68021

2 files changed

Lines changed: 43 additions & 8 deletions

File tree

packages/super-editor/src/editors/v1/core/InputRule.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,32 @@ export function sanitizeHtml(html, forbiddenTags = ['meta', 'svg', 'script', 'st
647647
* @returns {Boolean} Whether the paste was handled.
648648
*/
649649
export function handleClipboardPaste({ editor, view }, html, plainText) {
650+
const rawHtml = html || '';
651+
const isSuperdocHtml = isSuperdocOriginClipboardHtml(rawHtml);
652+
const embeddedBodySectPr = isSuperdocHtml ? extractBodySectPrFromHtml(rawHtml) : null;
653+
let pasteHtml = rawHtml;
654+
655+
let superdocSliceData = extractSliceFromHtml(rawHtml);
656+
if (superdocSliceData) {
657+
superdocSliceData = applySuperdocClipboardMedia(editor, null, superdocSliceData);
658+
try {
659+
if (handleSuperdocSlicePaste(superdocSliceData, editor, view, embeddedBodySectPr)) return true;
660+
} catch (err) {
661+
console.warn('Failed to paste SuperDoc slice, falling back to HTML:', err);
662+
}
663+
}
664+
665+
if (isSuperdocHtml) {
666+
pasteHtml = stripSliceFromHtml(rawHtml);
667+
}
668+
650669
let source;
651670

652-
if (!html) {
671+
if (!pasteHtml) {
653672
source = 'plain-text';
654-
} else if (isWordHtml(html)) {
673+
} else if (isWordHtml(pasteHtml)) {
655674
source = 'word-html';
656-
} else if (isGoogleDocsHtml(html)) {
675+
} else if (isGoogleDocsHtml(pasteHtml)) {
657676
source = 'google-docs';
658677
} else {
659678
source = 'browser-html';
@@ -667,15 +686,15 @@ export function handleClipboardPaste({ editor, view }, html, plainText) {
667686
return handlePlainTextUrlPaste(editor, view, plainText, detected);
668687
}
669688
case 'word-html':
670-
if (editor.options.mode === 'docx' && !isSuperdocOriginClipboardHtml(html)) {
671-
return handleDocxPaste(html, editor, view);
689+
if (editor.options.mode === 'docx' && !isSuperdocHtml) {
690+
return handleDocxPaste(pasteHtml, editor, view);
672691
}
673-
return handleHtmlPaste(html, editor);
692+
return handleHtmlPaste(pasteHtml, editor);
674693
case 'google-docs':
675-
return handleGoogleDocsHtml(html, editor, view);
694+
return handleGoogleDocsHtml(pasteHtml, editor, view);
676695
// falls through to browser-html handling when not in DOCX mode
677696
case 'browser-html':
678-
return handleHtmlPaste(html, editor);
697+
return handleHtmlPaste(pasteHtml, editor);
679698
}
680699

681700
return false;

packages/super-editor/src/editors/v1/core/InputRule.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
isWordHtml,
3333
isSuperdocOriginClipboardHtml,
3434
} from './InputRule.js';
35+
import { embedSliceInHtml } from './helpers/superdocClipboardSlice.js';
3536

3637
const createEditorContext = (initialDoc) => {
3738
const baseState = EditorState.create({ schema, doc: initialDoc });
@@ -179,6 +180,21 @@ describe('InputRule helpers', () => {
179180
expect(handled).toBe(true);
180181
});
181182

183+
it('pastes embedded SuperDoc slice data before falling back to hidden slice HTML', () => {
184+
const { editor, view } = createEditorContext(doc(p('Base')));
185+
const sourceDoc = doc(p('Slice content'));
186+
const sliceJson = JSON.stringify(sourceDoc.slice(0, sourceDoc.content.size).toJSON());
187+
const html = embedSliceInHtml('<p>Visible fallback</p>', sliceJson);
188+
189+
const handled = handleClipboardPaste({ editor, view }, html, 'Slice content');
190+
191+
const text = view.state.doc.textContent;
192+
expect(handled).toBe(true);
193+
expect(text).toContain('Slice content');
194+
expect(text).not.toContain('Visible fallback');
195+
expect(text).not.toMatch(/eyJ[A-Za-z0-9+/=]{20,}/);
196+
});
197+
182198
it('falls back to browser HTML handling for Word HTML outside docx mode', () => {
183199
const { editor } = createEditorContext(doc(p('Base')));
184200
const html = '<meta name="Generator" content="Microsoft Word"><p>Content</p>';

0 commit comments

Comments
 (0)