client: tableOfContent markdown support

pull/60/head
fantasticit 2022-05-27 23:13:52 +08:00
parent 42e05bec0f
commit c37182f0a8
9 changed files with 42 additions and 17 deletions

View File

@ -1,4 +1,6 @@
export const safeJSONParse = (str, defaultValue = {}) => {
if (typeof str === 'object') return str;
try {
return JSON.parse(str);
} catch (e) {

View File

@ -195,20 +195,29 @@ export const Paste = Extension.create<IPasteOptions>({
return false;
},
clipboardTextSerializer: (slice) => {
const isText = isPureText(slice.content.toJSON());
const json = slice.content.toJSON();
const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0;
if (isText) {
return slice.content.textBetween(0, slice.content.size, '\n\n');
}
if (typeof json === 'object' || isSelectAll) {
return extensionThis.options.prosemirrorToMarkdown({
content: slice.content,
});
} else {
const isText = isPureText(json) && !isSelectAll;
const doc = slice.content;
if (!doc) {
return '';
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;
}
const content = extensionThis.options.prosemirrorToMarkdown({
content: doc,
});
return content;
},
},
}),

View File

@ -51,8 +51,6 @@ export const TableOfContentsWrapper = ({ editor }) => {
setItems(headings);
}, [editor]);
useEffect(handleUpdate, [handleUpdate]);
useEffect(() => {
if (!editor) {
return null;

View File

@ -0,0 +1,9 @@
import { Node } from './node';
export class TableOfContents extends Node {
type = 'tableOfContents';
matching() {
return this.DOMNode.nodeName === 'DIV' && this.DOMNode.classList.contains('tableOfContents');
}
}

View File

@ -34,6 +34,7 @@ import { Status } from './nodes/status';
import { Table } from './nodes/table';
import { TableCell } from './nodes/table-cell';
import { TableHeader } from './nodes/table-header';
import { TableOfContents } from './nodes/table-of-contents';
import { TableRow } from './nodes/table-row';
// 列表
import { TaskList } from './nodes/task-list';
@ -82,6 +83,7 @@ export class Renderer {
TableHeader,
TableRow,
TableCell,
TableOfContents,
// 列表
TaskList,

View File

@ -32,6 +32,7 @@ export const markdownToProsemirror = ({ schema, content, hasTitle }) => {
const parser = new DOMParser();
const { body } = parser.parseFromString(extractImage(html), 'text/html');
body.append(document.createComment(content));
const node = htmlToPromsemirror(body, !hasTitle);

View File

@ -22,6 +22,7 @@ const markdownIframe = createMarkdownContainer('iframe');
const markdownMention = createMarkdownContainer('mention');
const markdownMind = createMarkdownContainer('mind');
const markdownFlow = createMarkdownContainer('flow');
const markdownTableOfContents = createMarkdownContainer('tableOfContents');
const markdown = markdownit('commonmark')
.enable('strikethrough')
@ -44,7 +45,8 @@ const markdown = markdownit('commonmark')
.use(markdownMind)
.use(markdownDocumentReference)
.use(markdownDocumentChildren)
.use(markdownFlow);
.use(markdownFlow)
.use(markdownTableOfContents);
export const markdownToHTML = (rawMarkdown) => {
return sanitize(markdown.render(rawMarkdown), {});

View File

@ -31,6 +31,7 @@ import { Superscript } from 'tiptap/core/extensions/superscript';
import { Table } from 'tiptap/core/extensions/table';
import { TableCell } from 'tiptap/core/extensions/table-cell';
import { TableHeader } from 'tiptap/core/extensions/table-header';
import { TableOfContents } from 'tiptap/core/extensions/table-of-contents';
import { TableRow } from 'tiptap/core/extensions/table-row';
import { TaskItem } from 'tiptap/core/extensions/task-item';
import { TaskList } from 'tiptap/core/extensions/task-list';
@ -147,6 +148,7 @@ const SerializerConfig = {
[Table.name]: renderTable,
[TableCell.name]: renderTableCell,
[TableHeader.name]: renderTableCell,
[TableOfContents.name]: renderCustomContainer('tableOfContents'),
[TableRow.name]: renderTableRow,
[TaskItem.name]: (state, node) => {
state.write(`[${node.attrs.checked ? 'x' : ' '}] `);

View File

@ -3,10 +3,10 @@ import { copy } from 'helpers/copy';
import { safeJSONStringify } from 'helpers/json';
import { Fragment, Node } from 'prosemirror-model';
export function copyNode(nodeOrNodeName: Node);
export function copyNode(nodeOrNodeName: Node | Fragment<any>);
export function copyNode(nodeOrNodeName: string, editor: Editor);
export function copyNode(nodeOrNodeName: string | Node, editor?: Editor) {
let targetNode: null | Node = null;
export function copyNode(nodeOrNodeName: string | Node | Fragment<any>, editor?: Editor) {
let targetNode = null;
if (typeof nodeOrNodeName === 'string') {
const { state } = editor;