mirror of https://github.com/fantasticit/think.git
tiptap: render object data to attributes, so can copy and paste it
This commit is contained in:
parent
79f40ecb7a
commit
3ca68989f0
|
@ -2,7 +2,7 @@ import { IUser } from '@think/domains';
|
|||
import { mergeAttributes, Node, nodeInputRule } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||
import { ExcalidrawWrapper } from 'tiptap/core/wrappers/excalidraw';
|
||||
import { getDatasetAttribute } from 'tiptap/prose-utils';
|
||||
import { getDatasetAttribute, nodeAttrsToDataset } from 'tiptap/prose-utils';
|
||||
|
||||
const DEFAULT_MIND_DATA = { elements: [] };
|
||||
|
||||
|
@ -56,7 +56,7 @@ export const Excalidraw = Node.create({
|
|||
addOptions() {
|
||||
return {
|
||||
HTMLAttributes: {
|
||||
class: 'mind',
|
||||
class: 'excalidraw',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@ -64,13 +64,13 @@ export const Excalidraw = Node.create({
|
|||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: 'div[class=mind]',
|
||||
tag: 'div[class=excalidraw]',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
||||
renderHTML({ HTMLAttributes, node }) {
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, nodeAttrsToDataset(node))];
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { IUser } from '@think/domains';
|
|||
import { mergeAttributes, Node, nodeInputRule } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||
import { MindWrapper } from 'tiptap/core/wrappers/mind';
|
||||
import { getDatasetAttribute } from 'tiptap/prose-utils';
|
||||
import { getDatasetAttribute, nodeAttrsToDataset } from 'tiptap/prose-utils';
|
||||
|
||||
const DEFAULT_MIND_DATA = {
|
||||
root: { data: { text: '中心节点' }, children: [] },
|
||||
|
@ -77,8 +77,8 @@ export const Mind = Node.create({
|
|||
];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
||||
renderHTML({ HTMLAttributes, node }) {
|
||||
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, nodeAttrsToDataset(node))];
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
|
|
|
@ -23,6 +23,11 @@ interface IPasteOptions {
|
|||
*/
|
||||
htmlToProsemirror: (arg: { schema: Schema; html: string; needTitle: boolean; defaultTitle?: string }) => Node;
|
||||
|
||||
/**
|
||||
* 将 markdown 转换为 html
|
||||
*/
|
||||
markdownToHTML: (arg: string) => string;
|
||||
|
||||
/**
|
||||
* 将 markdown 转换为 prosemirror 节点
|
||||
*/
|
||||
|
@ -41,6 +46,7 @@ export const Paste = Extension.create<IPasteOptions>({
|
|||
addOptions() {
|
||||
return {
|
||||
htmlToProsemirror: (arg) => '',
|
||||
markdownToHTML: (arg) => arg,
|
||||
markdownToProsemirror: (arg) => arg.content,
|
||||
prosemirrorToMarkdown: (arg) => String(arg.content),
|
||||
};
|
||||
|
|
|
@ -66,7 +66,7 @@ import { TrailingNode } from 'tiptap/core/extensions/trailing-node';
|
|||
import { Underline } from 'tiptap/core/extensions/underline';
|
||||
// markdown 支持
|
||||
import { htmlToProsemirror } from 'tiptap/markdown/html-to-prosemirror';
|
||||
import { markdownToProsemirror } from 'tiptap/markdown/markdown-to-prosemirror';
|
||||
import { markdownToHTML, markdownToProsemirror } from 'tiptap/markdown/markdown-to-prosemirror';
|
||||
import { prosemirrorToMarkdown } from 'tiptap/markdown/prosemirror-to-markdown';
|
||||
|
||||
const DocumentWithTitle = Document.extend({
|
||||
|
@ -137,6 +137,7 @@ export const CollaborationKit = [
|
|||
Underline,
|
||||
Paste.configure({
|
||||
htmlToProsemirror,
|
||||
markdownToHTML,
|
||||
markdownToProsemirror,
|
||||
prosemirrorToMarkdown,
|
||||
}),
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Node } from './node';
|
||||
|
||||
export class Excalidraw extends Node {
|
||||
type = 'excalidraw';
|
||||
|
||||
matching() {
|
||||
return this.DOMNode.nodeName === 'DIV' && this.DOMNode.classList.contains('excalidraw');
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import { CodeBlockWrapper } from './nodes/code-block-wrapper';
|
|||
import { Countdown } from './nodes/countdown';
|
||||
import { DocumentChildren } from './nodes/document-children';
|
||||
import { DocumentReference } from './nodes/document-reference';
|
||||
import { Excalidraw } from './nodes/excalidraw';
|
||||
import { Flow } from './nodes/flow';
|
||||
import { HardBreak } from './nodes/hard-break';
|
||||
import { Heading } from './nodes/heading';
|
||||
|
@ -57,6 +58,7 @@ export class Renderer {
|
|||
Attachment,
|
||||
Countdown,
|
||||
Callout,
|
||||
Excalidraw,
|
||||
Iframe,
|
||||
Status,
|
||||
Mention,
|
||||
|
|
|
@ -37,3 +37,5 @@ export const markdownToProsemirror = ({ schema, content, needTitle, defaultTitle
|
|||
|
||||
return node;
|
||||
};
|
||||
|
||||
export { markdownToHTML };
|
||||
|
|
|
@ -21,6 +21,7 @@ const markdownDocumentChildren = createMarkdownContainer('documentChildren');
|
|||
const markdownIframe = createMarkdownContainer('iframe');
|
||||
const markdownMention = createMarkdownContainer('mention');
|
||||
const markdownMind = createMarkdownContainer('mind');
|
||||
const markdownExcalidraw = createMarkdownContainer('excalidraw');
|
||||
const markdownFlow = createMarkdownContainer('flow');
|
||||
const markdownTableOfContents = createMarkdownContainer('tableOfContents');
|
||||
const markdownTitle = createMarkdownContainer('title');
|
||||
|
@ -44,6 +45,7 @@ const markdown = markdownit('commonmark')
|
|||
.use(markdownStatus)
|
||||
.use(markdownMention)
|
||||
.use(markdownMind)
|
||||
.use(markdownExcalidraw)
|
||||
.use(markdownDocumentReference)
|
||||
.use(markdownDocumentChildren)
|
||||
.use(markdownFlow)
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CodeBlock } from 'tiptap/core/extensions/code-block';
|
|||
import { Countdown } from 'tiptap/core/extensions/countdown';
|
||||
import { DocumentChildren } from 'tiptap/core/extensions/document-children';
|
||||
import { DocumentReference } from 'tiptap/core/extensions/document-reference';
|
||||
import { Excalidraw } from 'tiptap/core/extensions/excalidraw';
|
||||
import { Flow } from 'tiptap/core/extensions/flow';
|
||||
import { HardBreak } from 'tiptap/core/extensions/hard-break';
|
||||
import { Heading } from 'tiptap/core/extensions/heading';
|
||||
|
@ -127,6 +128,7 @@ const SerializerConfig = {
|
|||
[Countdown.name]: renderCustomContainer('countdown'),
|
||||
[DocumentChildren.name]: renderCustomContainer('documentChildren'),
|
||||
[DocumentReference.name]: renderCustomContainer('documentReference'),
|
||||
[Excalidraw.name]: renderCustomContainer('excalidraw'),
|
||||
[Flow.name]: renderCustomContainer('flow'),
|
||||
[HardBreak.name]: renderHardBreak,
|
||||
[Heading.name]: defaultMarkdownSerializer.nodes.heading,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { safeJSONParse } from 'helpers/json';
|
||||
import { Node } from 'prosemirror-state';
|
||||
|
||||
/**
|
||||
* 将 JSON 转为字符串
|
||||
|
@ -89,3 +90,32 @@ export const getDatasetAttribute =
|
|||
const toNumber = parseInt(value);
|
||||
return toNumber !== toNumber ? value : toNumber; // 避免 NaN
|
||||
};
|
||||
|
||||
/**
|
||||
* 将节点属性转换为 dataset
|
||||
* @param node
|
||||
* @returns
|
||||
*/
|
||||
export const nodeAttrsToDataset = (node: Node) => {
|
||||
const { attrs } = node;
|
||||
|
||||
return Object.keys(attrs).reduce((accu, key) => {
|
||||
const value = attrs[key];
|
||||
|
||||
if (value == null) {
|
||||
return accu;
|
||||
}
|
||||
|
||||
let encodeValue = '';
|
||||
|
||||
if (typeof value === 'object') {
|
||||
encodeValue = jsonToStr(value);
|
||||
} else {
|
||||
encodeValue = value;
|
||||
}
|
||||
|
||||
accu[key] = encodeValue;
|
||||
|
||||
return accu;
|
||||
}, Object.create(null));
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue