mirror of https://github.com/fantasticit/think.git
client: tableOfContent markdown support
parent
42e05bec0f
commit
c37182f0a8
|
@ -1,4 +1,6 @@
|
||||||
export const safeJSONParse = (str, defaultValue = {}) => {
|
export const safeJSONParse = (str, defaultValue = {}) => {
|
||||||
|
if (typeof str === 'object') return str;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JSON.parse(str);
|
return JSON.parse(str);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -195,20 +195,29 @@ export const Paste = Extension.create<IPasteOptions>({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
clipboardTextSerializer: (slice) => {
|
clipboardTextSerializer: (slice) => {
|
||||||
const isText = isPureText(slice.content.toJSON());
|
const json = slice.content.toJSON();
|
||||||
|
const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0;
|
||||||
|
|
||||||
if (isText) {
|
if (typeof json === 'object' || isSelectAll) {
|
||||||
return slice.content.textBetween(0, slice.content.size, '\n\n');
|
return extensionThis.options.prosemirrorToMarkdown({
|
||||||
}
|
content: slice.content,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const isText = isPureText(json) && !isSelectAll;
|
||||||
|
|
||||||
const doc = slice.content;
|
if (isText) {
|
||||||
if (!doc) {
|
return slice.content.textBetween(0, slice.content.size, '\n\n');
|
||||||
return '';
|
}
|
||||||
|
|
||||||
|
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;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -51,8 +51,6 @@ export const TableOfContentsWrapper = ({ editor }) => {
|
||||||
setItems(headings);
|
setItems(headings);
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
useEffect(handleUpdate, [handleUpdate]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ import { Status } from './nodes/status';
|
||||||
import { Table } from './nodes/table';
|
import { Table } from './nodes/table';
|
||||||
import { TableCell } from './nodes/table-cell';
|
import { TableCell } from './nodes/table-cell';
|
||||||
import { TableHeader } from './nodes/table-header';
|
import { TableHeader } from './nodes/table-header';
|
||||||
|
import { TableOfContents } from './nodes/table-of-contents';
|
||||||
import { TableRow } from './nodes/table-row';
|
import { TableRow } from './nodes/table-row';
|
||||||
// 列表
|
// 列表
|
||||||
import { TaskList } from './nodes/task-list';
|
import { TaskList } from './nodes/task-list';
|
||||||
|
@ -82,6 +83,7 @@ export class Renderer {
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
TableCell,
|
TableCell,
|
||||||
|
TableOfContents,
|
||||||
|
|
||||||
// 列表
|
// 列表
|
||||||
TaskList,
|
TaskList,
|
||||||
|
|
|
@ -32,6 +32,7 @@ export const markdownToProsemirror = ({ schema, content, hasTitle }) => {
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const { body } = parser.parseFromString(extractImage(html), 'text/html');
|
const { body } = parser.parseFromString(extractImage(html), 'text/html');
|
||||||
|
|
||||||
body.append(document.createComment(content));
|
body.append(document.createComment(content));
|
||||||
const node = htmlToPromsemirror(body, !hasTitle);
|
const node = htmlToPromsemirror(body, !hasTitle);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ const markdownIframe = createMarkdownContainer('iframe');
|
||||||
const markdownMention = createMarkdownContainer('mention');
|
const markdownMention = createMarkdownContainer('mention');
|
||||||
const markdownMind = createMarkdownContainer('mind');
|
const markdownMind = createMarkdownContainer('mind');
|
||||||
const markdownFlow = createMarkdownContainer('flow');
|
const markdownFlow = createMarkdownContainer('flow');
|
||||||
|
const markdownTableOfContents = createMarkdownContainer('tableOfContents');
|
||||||
|
|
||||||
const markdown = markdownit('commonmark')
|
const markdown = markdownit('commonmark')
|
||||||
.enable('strikethrough')
|
.enable('strikethrough')
|
||||||
|
@ -44,7 +45,8 @@ const markdown = markdownit('commonmark')
|
||||||
.use(markdownMind)
|
.use(markdownMind)
|
||||||
.use(markdownDocumentReference)
|
.use(markdownDocumentReference)
|
||||||
.use(markdownDocumentChildren)
|
.use(markdownDocumentChildren)
|
||||||
.use(markdownFlow);
|
.use(markdownFlow)
|
||||||
|
.use(markdownTableOfContents);
|
||||||
|
|
||||||
export const markdownToHTML = (rawMarkdown) => {
|
export const markdownToHTML = (rawMarkdown) => {
|
||||||
return sanitize(markdown.render(rawMarkdown), {});
|
return sanitize(markdown.render(rawMarkdown), {});
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { Superscript } from 'tiptap/core/extensions/superscript';
|
||||||
import { Table } from 'tiptap/core/extensions/table';
|
import { Table } from 'tiptap/core/extensions/table';
|
||||||
import { TableCell } from 'tiptap/core/extensions/table-cell';
|
import { TableCell } from 'tiptap/core/extensions/table-cell';
|
||||||
import { TableHeader } from 'tiptap/core/extensions/table-header';
|
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 { TableRow } from 'tiptap/core/extensions/table-row';
|
||||||
import { TaskItem } from 'tiptap/core/extensions/task-item';
|
import { TaskItem } from 'tiptap/core/extensions/task-item';
|
||||||
import { TaskList } from 'tiptap/core/extensions/task-list';
|
import { TaskList } from 'tiptap/core/extensions/task-list';
|
||||||
|
@ -147,6 +148,7 @@ const SerializerConfig = {
|
||||||
[Table.name]: renderTable,
|
[Table.name]: renderTable,
|
||||||
[TableCell.name]: renderTableCell,
|
[TableCell.name]: renderTableCell,
|
||||||
[TableHeader.name]: renderTableCell,
|
[TableHeader.name]: renderTableCell,
|
||||||
|
[TableOfContents.name]: renderCustomContainer('tableOfContents'),
|
||||||
[TableRow.name]: renderTableRow,
|
[TableRow.name]: renderTableRow,
|
||||||
[TaskItem.name]: (state, node) => {
|
[TaskItem.name]: (state, node) => {
|
||||||
state.write(`[${node.attrs.checked ? 'x' : ' '}] `);
|
state.write(`[${node.attrs.checked ? 'x' : ' '}] `);
|
||||||
|
|
|
@ -3,10 +3,10 @@ import { copy } from 'helpers/copy';
|
||||||
import { safeJSONStringify } from 'helpers/json';
|
import { safeJSONStringify } from 'helpers/json';
|
||||||
import { Fragment, Node } from 'prosemirror-model';
|
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, editor: Editor);
|
||||||
export function copyNode(nodeOrNodeName: string | Node, editor?: Editor) {
|
export function copyNode(nodeOrNodeName: string | Node | Fragment<any>, editor?: Editor) {
|
||||||
let targetNode: null | Node = null;
|
let targetNode = null;
|
||||||
|
|
||||||
if (typeof nodeOrNodeName === 'string') {
|
if (typeof nodeOrNodeName === 'string') {
|
||||||
const { state } = editor;
|
const { state } = editor;
|
||||||
|
|
Loading…
Reference in New Issue