diff --git a/packages/client/src/tiptap/extensions/banner.ts b/packages/client/src/tiptap/extensions/banner.ts index b8ad7d6c..0d8240a9 100644 --- a/packages/client/src/tiptap/extensions/banner.ts +++ b/packages/client/src/tiptap/extensions/banner.ts @@ -24,7 +24,7 @@ export const Banner = Node.create({ type: { default: 'info', rendered: false, - parseHTML: getDatasetAttribute('info'), + parseHTML: getDatasetAttribute('type'), renderHTML: (attributes) => { return { 'data-type': attributes.type, diff --git a/packages/client/src/tiptap/extensions/selection.ts b/packages/client/src/tiptap/extensions/selection.ts index 52a247a1..6a3e769f 100644 --- a/packages/client/src/tiptap/extensions/selection.ts +++ b/packages/client/src/tiptap/extensions/selection.ts @@ -1,7 +1,7 @@ import { Extension } from '@tiptap/core'; import { Plugin, PluginKey, NodeSelection, TextSelection, Selection, AllSelection } from 'prosemirror-state'; import { Decoration, DecorationSet } from 'prosemirror-view'; -import { getCurrentNode, isInCodeBlock } from '../services/node'; +import { getCurrentNode, isInCodeBlock, isInBanner } from '../services/node'; import { EXTENSION_PRIORITY_HIGHEST } from '../constants'; export const selectionPluginKey = new PluginKey('selection'); @@ -56,13 +56,30 @@ export const SelectionExtension = Extension.create({ */ if ((event.ctrlKey || event.metaKey) && (event.keyCode == 65 || event.keyCode == 97)) { const node = getCurrentNode(view.state); + const $head = view.state.selection.$head; + let startPos = null; + let endPos = null; + // 代码块 if (isInCodeBlock(view.state)) { - const { pos, parentOffset } = view.state.selection.$head; + const { pos, parentOffset } = $head; + startPos = pos - parentOffset; + endPos = pos - parentOffset + node.nodeSize - 2; + } + + // 信息框 + if (isInBanner(view.state)) { + // @ts-ignore + const { path = [] } = $head; + startPos = path[2]; + endPos = startPos + path[3].content.size; + } + + if (startPos !== null && endPos !== null) { const newState = view.state; const next = new TextSelection( - newState.doc.resolve(pos - parentOffset + node.nodeSize - 2), //内容结束点 - newState.doc.resolve(pos - parentOffset) // 内容起始点 + newState.doc.resolve(endPos), //内容结束点 + newState.doc.resolve(startPos) // 内容起始点 ); view?.dispatch(newState.tr.setSelection(next)); return true; @@ -71,19 +88,6 @@ export const SelectionExtension = Extension.create({ return false; }, - handleDoubleClickOn(view, pos, node, nodePos, event) { - if (node.type.name === 'codeBlock') { - event.preventDefault(); - const transaction = view.state.tr.setMeta('selectNode', { - fromPos: nodePos, - toPos: nodePos + node.nodeSize, - attrs: { class: 'selected-node' }, - }); - view?.dispatch(transaction); - return false; - } - return true; - }, decorations(state) { return this.getState(state); }, @@ -93,10 +97,6 @@ export const SelectionExtension = Extension.create({ return DecorationSet.empty; }, apply(ctx) { - if (ctx.getMeta('selectNode')) { - const { fromPos, toPos, attrs } = ctx.getMeta('selectNode'); - return DecorationSet.create(ctx.doc, [Decoration.node(fromPos, toPos, attrs)]); - } const { doc, selection } = ctx; const decorationSet = getDecorations(doc, selection); return decorationSet; diff --git a/packages/client/src/tiptap/services/markdown/helpers.ts b/packages/client/src/tiptap/services/markdown/helpers.ts index 686bf1d9..889c17a9 100644 --- a/packages/client/src/tiptap/services/markdown/helpers.ts +++ b/packages/client/src/tiptap/services/markdown/helpers.ts @@ -7,6 +7,10 @@ export const isMarkdown = (text: string): boolean => { const tables = text.match(/^\|(\S)*\|/gm); if (tables && tables.length) return true; + // 自定义 container + const conatiner = text.match(/^:::/gm); + if (conatiner && conatiner.length > 1) return true; + // code-ish const fences = text.match(/^```/gm); if (fences && fences.length > 1) return true; diff --git a/packages/client/src/tiptap/services/node.ts b/packages/client/src/tiptap/services/node.ts index b41fc7ea..a7787da8 100644 --- a/packages/client/src/tiptap/services/node.ts +++ b/packages/client/src/tiptap/services/node.ts @@ -21,25 +21,36 @@ export function isListNode(node: Node): boolean { return isBulletListNode(node) || isOrderedListNode(node) || isTodoListNode(node); } -export function isInTitle(state: EditorState): boolean { +export function getCurrentNode(state: EditorState): Node { + const $head = state.selection.$head; + let node = null; + + for (let d = $head.depth; d > 0; d--) { + node = $head.node(d); + } + + return node; +} + +export function isInCustomNode(state: EditorState, nodeName: string): boolean { + if (!state.schema.nodes[nodeName]) return false; + const $head = state.selection.$head; for (let d = $head.depth; d > 0; d--) { - if ($head.node(d).type === state.schema.nodes.title) { + if ($head.node(d).type === state.schema.nodes[nodeName]) { return true; } } } -export function getCurrentNode(state: EditorState): Node { - const $head = state.selection.$head; - return $head.node($head.depth); -} - export function isInCodeBlock(state: EditorState): boolean { - const $head = state.selection.$head; - for (let d = $head.depth; d > 0; d--) { - if ($head.node(d).type === state.schema.nodes.codeBlock) { - return true; - } - } + return isInCustomNode(state, 'codeBlock'); +} + +export function isInTitle(state: EditorState): boolean { + return isInCustomNode(state, 'title'); +} + +export function isInBanner(state: EditorState): boolean { + return isInCustomNode(state, 'banner'); } diff --git a/packages/client/src/tiptap/wrappers/attachment/index.tsx b/packages/client/src/tiptap/wrappers/attachment/index.tsx index bb6e8ace..71d53a1b 100644 --- a/packages/client/src/tiptap/wrappers/attachment/index.tsx +++ b/packages/client/src/tiptap/wrappers/attachment/index.tsx @@ -141,9 +141,11 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => { if (isEditable && !url) { return ( -
+
- {loading ? '正在上传中' : '请选择文件'} + + {loading ? '正在上传中' : '请选择文件'} +