diff --git a/packages/client/src/tiptap/core/extensions/clipboard.ts b/packages/client/src/tiptap/core/extensions/clipboard.ts new file mode 100644 index 00000000..c1cc6f11 --- /dev/null +++ b/packages/client/src/tiptap/core/extensions/clipboard.ts @@ -0,0 +1,97 @@ +import { Extension } from '@tiptap/core'; +import { Fragment } from 'prosemirror-model'; +import { Plugin, PluginKey } from 'prosemirror-state'; +import { EXTENSION_PRIORITY_HIGHEST } from 'tiptap/core/constants'; +import { copyNode } from 'tiptap/prose-utils'; + +const isPureText = (content): boolean => { + if (!content) return false; + + if (Array.isArray(content)) { + if (content.length > 1) return false; + return isPureText(content[0]); + } + + const child = content['content']; + if (child) { + return isPureText(child); + } + + return content['type'] === 'text'; +}; + +interface IClipboardOptions { + /** + * 将 prosemirror 转换为 markdown + */ + prosemirrorToMarkdown: (arg: { content: Fragment }) => string; +} + +export const Clipboard = Extension.create({ + name: 'clipboard', + priority: EXTENSION_PRIORITY_HIGHEST, + + addOptions() { + return { + prosemirrorToMarkdown: (arg) => String(arg.content), + }; + }, + + addProseMirrorPlugins() { + const extensionThis = this; + + return [ + new Plugin({ + key: new PluginKey('clipboard'), + props: { + handleKeyDown(view, event) { + /** + * Command + C + * Ctrl + C + */ + if ((event.ctrlKey || event.metaKey) && event.keyCode == 67) { + const { state } = view; + // @ts-ignore + const currentNode = state.selection.node; + + if (currentNode) { + event.preventDefault(); + copyNode(currentNode); + return true; + } + } + + return false; + }, + clipboardTextSerializer: (slice) => { + const json = slice.content.toJSON(); + const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0; + + if (typeof json === 'object' || isSelectAll) { + return extensionThis.options.prosemirrorToMarkdown({ + content: slice.content, + }); + } else { + const isText = isPureText(json) && !isSelectAll; + + if (isText) { + return slice.content.textBetween(0, slice.content.size, '\n\n'); + } + + const doc = slice.content; + + if (!doc) { + return ''; + } + + const content = extensionThis.options.prosemirrorToMarkdown({ + content: doc, + }); + return content; + } + }, + }, + }), + ]; + }, +}); diff --git a/packages/client/src/tiptap/core/extensions/paste.ts b/packages/client/src/tiptap/core/extensions/paste.ts index f44b97e0..235e5654 100644 --- a/packages/client/src/tiptap/core/extensions/paste.ts +++ b/packages/client/src/tiptap/core/extensions/paste.ts @@ -5,7 +5,6 @@ import { Fragment, Schema } from 'prosemirror-model'; import { Plugin, PluginKey } from 'prosemirror-state'; import { EXTENSION_PRIORITY_HIGHEST } from 'tiptap/core/constants'; import { - copyNode, handleFileEvent, isInCode, isMarkdown, @@ -36,22 +35,6 @@ interface IPasteOptions { prosemirrorToMarkdown: (arg: { content: Fragment }) => string; } -const isPureText = (content): boolean => { - if (!content) return false; - - if (Array.isArray(content)) { - if (content.length > 1) return false; - return isPureText(content[0]); - } - - const child = content['content']; - if (child) { - return isPureText(child); - } - - return content['type'] === 'text'; -}; - export const Paste = Extension.create({ name: 'paste', priority: EXTENSION_PRIORITY_HIGHEST, @@ -102,13 +85,6 @@ export const Paste = Extension.create({ const { markdownToProsemirror } = extensionThis.options; - console.log('p', { - text, - html, - node, - markdownText, - }); - // 直接复制节点 if (node) { const json = safeJSONParse(node); @@ -178,7 +154,6 @@ export const Paste = Extension.create({ content: normalizeMarkdown(markdownText || text), needTitle: hasTitleExtension && !hasTitle, }); - console.log('p', markdownText, text); let tr = view.state.tr; const selection = tr.selection; @@ -220,50 +195,6 @@ export const Paste = Extension.create({ return false; }, - handleKeyDown(view, event) { - /** - * Command + C - * Ctrl + C - */ - if ((event.ctrlKey || event.metaKey) && event.keyCode == 67) { - const { state } = view; - // @ts-ignore - const currentNode = state.selection.node; - - if (currentNode) { - event.preventDefault(); - copyNode(currentNode); - return true; - } - } - - return false; - }, - clipboardTextSerializer: (slice) => { - const json = slice.content.toJSON(); - const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0; - - if (typeof json === 'object' || isSelectAll) { - return extensionThis.options.prosemirrorToMarkdown({ - content: slice.content, - }); - } else { - const isText = isPureText(json) && !isSelectAll; - - if (isText) { - return slice.content.textBetween(0, slice.content.size, '\n\n'); - } - - const doc = slice.content; - if (!doc) { - return ''; - } - const content = extensionThis.options.prosemirrorToMarkdown({ - content: doc, - }); - return content; - } - }, }, }), ]; diff --git a/packages/client/src/tiptap/core/extensions/selection.ts b/packages/client/src/tiptap/core/extensions/selection.ts index b36b922a..b1a244de 100644 --- a/packages/client/src/tiptap/core/extensions/selection.ts +++ b/packages/client/src/tiptap/core/extensions/selection.ts @@ -103,6 +103,20 @@ export const SelectionExtension = Extension.create({ return decorationSet; }, }, + filterTransaction(tr, state) { + // Prevent prosemirror's mutation observer overriding a node selection with a text selection + // for exact same range - this was cause of being unable to change dates in collab: + // https://product-fabric.atlassian.net/browse/ED-10645 + if ( + state.selection instanceof NodeSelection && + tr.selection instanceof TextSelection && + state.selection.from === tr.selection.from && + state.selection.to === tr.selection.to + ) { + return false; + } + return true; + }, }), new Plugin({ key: new PluginKey('preventSelection'), diff --git a/packages/client/src/tiptap/editor/collaboration/kit.ts b/packages/client/src/tiptap/editor/collaboration/kit.ts index 689da694..9c0a1dad 100644 --- a/packages/client/src/tiptap/editor/collaboration/kit.ts +++ b/packages/client/src/tiptap/editor/collaboration/kit.ts @@ -6,6 +6,7 @@ import { Blockquote } from 'tiptap/core/extensions/blockquote'; import { Bold } from 'tiptap/core/extensions/bold'; import { BulletList } from 'tiptap/core/extensions/bullet-list'; import { Callout } from 'tiptap/core/extensions/callout'; +import { Clipboard } from 'tiptap/core/extensions/clipboard'; import { Code, CodeMarkPlugin } from 'tiptap/core/extensions/code'; import { CodeBlock } from 'tiptap/core/extensions/code-block'; import { Color } from 'tiptap/core/extensions/color'; @@ -88,6 +89,9 @@ export const CollaborationKit = [ Blockquote, Bold, BulletList, + Clipboard.configure({ + prosemirrorToMarkdown, + }), Code, CodeMarkPlugin, CodeBlock, diff --git a/packages/client/src/tiptap/editor/comment/kit.ts b/packages/client/src/tiptap/editor/comment/kit.ts index 20e7dd6d..0ca7319b 100644 --- a/packages/client/src/tiptap/editor/comment/kit.ts +++ b/packages/client/src/tiptap/editor/comment/kit.ts @@ -3,6 +3,7 @@ import { BackgroundColor } from 'tiptap/core/extensions/background-color'; import { Blockquote } from 'tiptap/core/extensions/blockquote'; import { Bold } from 'tiptap/core/extensions/bold'; import { BulletList } from 'tiptap/core/extensions/bullet-list'; +import { Clipboard } from 'tiptap/core/extensions/clipboard'; import { Code } from 'tiptap/core/extensions/code'; import { CodeBlock } from 'tiptap/core/extensions/code-block'; import { Color } from 'tiptap/core/extensions/color'; @@ -18,6 +19,7 @@ import { HardBreak } from 'tiptap/core/extensions/hard-break'; import { Heading } from 'tiptap/core/extensions/heading'; import { HorizontalRule } from 'tiptap/core/extensions/horizontal-rule'; import { HTMLMarks } from 'tiptap/core/extensions/html-marks'; +import { Image } from 'tiptap/core/extensions/image'; import { Indent } from 'tiptap/core/extensions/indent'; import { Italic } from 'tiptap/core/extensions/italic'; import { Katex } from 'tiptap/core/extensions/katex'; @@ -53,6 +55,9 @@ export const CommentKit = [ Blockquote, Bold, BulletList, + Clipboard.configure({ + prosemirrorToMarkdown, + }), Code, CodeBlock, Color, @@ -70,6 +75,7 @@ export const CommentKit = [ HorizontalRule, ...HTMLMarks, Indent, + Image, Italic, Katex, Link,