@seafile/sdoc-editor 0.4.36 → 0.4.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/seafile-api.js +5 -4
- package/dist/basic-sdk/comment/utils/index.js +13 -12
- package/dist/basic-sdk/extension/commons/element-popover/index.js +3 -2
- package/dist/basic-sdk/extension/commons/menu/menu-group.js +3 -2
- package/dist/basic-sdk/extension/core/utils/index.js +8 -0
- package/dist/basic-sdk/extension/plugins/blockquote/menu/index.js +7 -6
- package/dist/basic-sdk/extension/plugins/check-list/menu/index.js +7 -6
- package/dist/basic-sdk/extension/plugins/check-list/render-elem.js +3 -2
- package/dist/basic-sdk/extension/plugins/header/menu/index.js +21 -20
- package/dist/basic-sdk/extension/plugins/image/dialogs/image-previewer.js +7 -6
- package/dist/basic-sdk/extension/plugins/image/helpers.js +13 -8
- package/dist/basic-sdk/extension/plugins/link/render-elem.js +13 -12
- package/dist/basic-sdk/extension/plugins/list/menu/index.js +9 -8
- package/dist/basic-sdk/extension/plugins/table/menu/active-table-menu/common-menu.js +9 -8
- package/dist/basic-sdk/extension/plugins/table/menu/table-context-menu/index.js +13 -12
- package/dist/basic-sdk/extension/plugins/table/menu/table-context-menu/insert-table-element.js +9 -8
- package/dist/basic-sdk/extension/plugins/table/render/render-cell.js +3 -2
- package/dist/basic-sdk/extension/plugins/table/render/table-header/index.css +4 -1
- package/dist/basic-sdk/extension/toolbar/header-toolbar/redo-undo.js +7 -6
- package/dist/basic-sdk/outline/outline-item.js +7 -6
- package/dist/basic-sdk/socket/socket-client.js +49 -48
- package/dist/basic-sdk/socket/socket-manager.js +53 -52
- package/dist/basic-sdk/utils/diff-text.js +21 -20
- package/dist/basic-sdk/utils/event-handler.js +8 -7
- package/dist/basic-sdk/utils/object-utils.js +5 -4
- package/dist/components/doc-operations/collaborators-operation/index.js +5 -4
- package/dist/components/draft-dropdown/index.js +11 -10
- package/dist/components/tip-message/index.js +21 -20
- package/dist/components/toast/toast.js +17 -16
- package/dist/components/toast/toastManager.js +14 -13
- package/dist/components/toast/toaster.js +19 -18
- package/dist/context.js +5 -4
- package/dist/slate-convert/html-to-slate/constants.js +34 -0
- package/dist/slate-convert/html-to-slate/helper.js +54 -0
- package/dist/slate-convert/html-to-slate/index.js +131 -0
- package/dist/slate-convert/html-to-slate/rules/blockquote.js +17 -0
- package/dist/slate-convert/html-to-slate/rules/check-list.js +20 -0
- package/dist/slate-convert/html-to-slate/rules/code-block.js +83 -0
- package/dist/slate-convert/html-to-slate/rules/header.js +17 -0
- package/dist/slate-convert/html-to-slate/rules/image.js +22 -0
- package/dist/slate-convert/html-to-slate/rules/index.js +11 -0
- package/dist/slate-convert/html-to-slate/rules/link.js +22 -0
- package/dist/slate-convert/html-to-slate/rules/list.js +50 -0
- package/dist/slate-convert/html-to-slate/rules/paragraph.js +17 -0
- package/dist/slate-convert/html-to-slate/rules/table.js +38 -0
- package/dist/slate-convert/html-to-slate/rules/text.js +56 -0
- package/dist/slate-convert/index.js +8 -0
- package/dist/slate-convert/md-to-html/index.js +48 -0
- package/dist/slate-convert/md-to-html/sanitize-schema.js +17 -0
- package/dist/slate-convert/md-to-slate/index.js +38 -0
- package/dist/slate-convert/md-to-slate/transform.js +360 -0
- package/dist/slate-convert/slate-to-md/index.js +37 -0
- package/dist/slate-convert/slate-to-md/transform.js +311 -0
- package/dist/utils/is-punctuation-mark.js +44 -0
- package/package.json +21 -6
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import typeOf from 'type-of';
|
|
3
|
+
import { INLINE_LEVEL_TYPES, LIST_ITEM, PARAGRAPH, TOP_LEVEL_TYPES, UNORDERED_LIST } from './constants';
|
|
4
|
+
import rules from './rules';
|
|
5
|
+
const cruftNewline = element => {
|
|
6
|
+
return !(element.nodeName === '#text' && element.nodeValue === '\n');
|
|
7
|
+
};
|
|
8
|
+
const deserializeElement = element => {
|
|
9
|
+
let node;
|
|
10
|
+
const next = elements => {
|
|
11
|
+
if (Object.prototype.toString.call(elements) === '[object NodeList]') {
|
|
12
|
+
elements = Array.from(elements);
|
|
13
|
+
}
|
|
14
|
+
switch (typeOf(elements)) {
|
|
15
|
+
case 'array':
|
|
16
|
+
return deserializeElements(elements);
|
|
17
|
+
case 'object':
|
|
18
|
+
return deserializeElement(elements);
|
|
19
|
+
case 'null':
|
|
20
|
+
case 'undefined':
|
|
21
|
+
return;
|
|
22
|
+
default:
|
|
23
|
+
throw new Error("The `next` argument was called with invalid children: \"".concat(elements, "\"."));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
for (let i = 0; i < rules.length; i++) {
|
|
27
|
+
const rule = rules[i];
|
|
28
|
+
if (!rule) continue;
|
|
29
|
+
const ret = rule(element, next);
|
|
30
|
+
const type = typeOf(ret);
|
|
31
|
+
if (type !== 'array' && type !== 'object' && type !== 'null' && type !== 'undefined') {
|
|
32
|
+
throw new Error("A rule returned an invalid deserialized representation: \"".concat(node, "\"."));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Not eligible for current component processing
|
|
36
|
+
if (ret === undefined) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Empty tags will be discarded and not converted accordingly
|
|
41
|
+
if (ret === null) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Assign the final processing result to node
|
|
46
|
+
node = ret;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// If node is undefined, it means that the label is not processed, and continue to process the child nodes of the element
|
|
51
|
+
return node || next(element.childNodes);
|
|
52
|
+
};
|
|
53
|
+
const deserializeElements = function () {
|
|
54
|
+
let elements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
55
|
+
let isTopLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
56
|
+
let nodes = [];
|
|
57
|
+
elements.filter(cruftNewline).forEach(element => {
|
|
58
|
+
const node = deserializeElement(element);
|
|
59
|
+
switch (typeOf(node)) {
|
|
60
|
+
case 'array':
|
|
61
|
+
const formatNode = isTopLevel ? formatElementNodes(node) : node;
|
|
62
|
+
nodes = nodes.concat(formatNode);
|
|
63
|
+
break;
|
|
64
|
+
case 'object':
|
|
65
|
+
nodes.push(node);
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
// nothing todo
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return nodes;
|
|
73
|
+
};
|
|
74
|
+
const formatElementNodes = nodes => {
|
|
75
|
+
if (nodes.length === 0) {
|
|
76
|
+
return [{
|
|
77
|
+
id: slugid.nice(),
|
|
78
|
+
type: PARAGRAPH,
|
|
79
|
+
children: [{
|
|
80
|
+
text: '',
|
|
81
|
+
id: slugid.nice()
|
|
82
|
+
}]
|
|
83
|
+
}];
|
|
84
|
+
}
|
|
85
|
+
nodes = nodes.reduce((memo, node) => {
|
|
86
|
+
if (TOP_LEVEL_TYPES.includes(node.type)) {
|
|
87
|
+
memo.push(node);
|
|
88
|
+
}
|
|
89
|
+
if (node.type === LIST_ITEM) {
|
|
90
|
+
const newNode = {
|
|
91
|
+
id: slugid.nice(),
|
|
92
|
+
type: UNORDERED_LIST,
|
|
93
|
+
children: [node]
|
|
94
|
+
};
|
|
95
|
+
memo.push(newNode);
|
|
96
|
+
return memo;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The following types will not appear individually during the pasting process
|
|
100
|
+
// code_line
|
|
101
|
+
// table_row | table_cell
|
|
102
|
+
|
|
103
|
+
// text | image | link
|
|
104
|
+
if (!node.type || INLINE_LEVEL_TYPES.includes(node.type)) {
|
|
105
|
+
let prevNode = memo[memo.length - 1];
|
|
106
|
+
if (prevNode && prevNode.type === PARAGRAPH) {
|
|
107
|
+
prevNode.children.push(node);
|
|
108
|
+
return memo;
|
|
109
|
+
}
|
|
110
|
+
const newNode = {
|
|
111
|
+
id: slugid.nice(),
|
|
112
|
+
type: PARAGRAPH,
|
|
113
|
+
children: [node]
|
|
114
|
+
};
|
|
115
|
+
memo.push(newNode);
|
|
116
|
+
return memo;
|
|
117
|
+
}
|
|
118
|
+
return memo;
|
|
119
|
+
}, []);
|
|
120
|
+
return nodes;
|
|
121
|
+
};
|
|
122
|
+
const deserializeHtml = html => {
|
|
123
|
+
const parsed = new DOMParser().parseFromString(html, 'text/html');
|
|
124
|
+
const fragment = parsed.body;
|
|
125
|
+
const children = Array.from(fragment.childNodes);
|
|
126
|
+
let nodes = [];
|
|
127
|
+
nodes = deserializeElements(children, true);
|
|
128
|
+
nodes = formatElementNodes(nodes);
|
|
129
|
+
return nodes;
|
|
130
|
+
};
|
|
131
|
+
export default deserializeHtml;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { BLOCKQUOTE } from '../constants';
|
|
3
|
+
const blockquoteRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName,
|
|
6
|
+
childNodes
|
|
7
|
+
} = element;
|
|
8
|
+
if (nodeName === 'BLOCKQUOTE') {
|
|
9
|
+
return {
|
|
10
|
+
id: slugid.nice(),
|
|
11
|
+
type: BLOCKQUOTE,
|
|
12
|
+
children: parseChild(childNodes)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
};
|
|
17
|
+
export default blockquoteRule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { CHECK_LIST_ITEM } from '../constants';
|
|
3
|
+
const checkListRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName
|
|
6
|
+
} = element;
|
|
7
|
+
if (nodeName === 'INPUT' && element.getAttribute('type') === 'checkbox') {
|
|
8
|
+
return {
|
|
9
|
+
id: slugid.nice(),
|
|
10
|
+
type: CHECK_LIST_ITEM,
|
|
11
|
+
checked: element.getAttribute('checked') !== null,
|
|
12
|
+
children: [{
|
|
13
|
+
id: slugid.nice(),
|
|
14
|
+
text: ''
|
|
15
|
+
}]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
};
|
|
20
|
+
export default checkListRule;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { CODE_BLOCK, CODE_LINE } from '../constants';
|
|
3
|
+
import { genCodeLangs } from '../helper';
|
|
4
|
+
const codeBlockRule = (element, parseChild) => {
|
|
5
|
+
const {
|
|
6
|
+
nodeName,
|
|
7
|
+
childNodes
|
|
8
|
+
} = element;
|
|
9
|
+
if (nodeName === 'PRE') {
|
|
10
|
+
const children = Array.from(childNodes).filter(item => item.nodeName === 'CODE');
|
|
11
|
+
let codeChild = children[0];
|
|
12
|
+
if (codeChild) {
|
|
13
|
+
let lang = codeChild.getAttribute('lang');
|
|
14
|
+
lang = genCodeLangs().find(item => item.value === lang) || 'plaintext';
|
|
15
|
+
return {
|
|
16
|
+
id: slugid.nice(),
|
|
17
|
+
language: lang,
|
|
18
|
+
type: CODE_BLOCK,
|
|
19
|
+
children: parseChild(children)
|
|
20
|
+
};
|
|
21
|
+
} else {
|
|
22
|
+
const lang = 'plaintext';
|
|
23
|
+
const content = childNodes[0].textContent;
|
|
24
|
+
const textArr = content.split('\n').filter(Boolean);
|
|
25
|
+
const children = textArr.map(text => {
|
|
26
|
+
return {
|
|
27
|
+
id: slugid.nice(),
|
|
28
|
+
type: CODE_LINE,
|
|
29
|
+
children: [{
|
|
30
|
+
id: slugid.nice(),
|
|
31
|
+
text: text
|
|
32
|
+
}]
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
id: slugid.nice(),
|
|
37
|
+
language: lang,
|
|
38
|
+
type: CODE_BLOCK,
|
|
39
|
+
children: children
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (nodeName === 'CODE' && element.parentElement.nodeName === 'PRE') {
|
|
44
|
+
const childIsP = Array.from(childNodes).every(n => n.nodeName === 'P');
|
|
45
|
+
if (childIsP) {
|
|
46
|
+
return Array.from(childNodes).map(n => {
|
|
47
|
+
return {
|
|
48
|
+
id: slugid.nice(),
|
|
49
|
+
type: CODE_LINE,
|
|
50
|
+
children: [{
|
|
51
|
+
id: slugid.nice(),
|
|
52
|
+
text: n.textContent
|
|
53
|
+
}]
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const content = element.textContent;
|
|
58
|
+
const hasNewLine = content.indexOf('\n') > -1;
|
|
59
|
+
if (!hasNewLine) {
|
|
60
|
+
return {
|
|
61
|
+
id: slugid.nice(),
|
|
62
|
+
type: CODE_LINE,
|
|
63
|
+
children: [{
|
|
64
|
+
id: slugid.nice(),
|
|
65
|
+
text: element.textContent
|
|
66
|
+
}]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const codes = content.slugid('\n').filter(Boolean);
|
|
70
|
+
return codes.map(item => {
|
|
71
|
+
return {
|
|
72
|
+
id: slugid.nice(),
|
|
73
|
+
type: CODE_LINE,
|
|
74
|
+
children: [{
|
|
75
|
+
id: slugid.nice(),
|
|
76
|
+
text: item
|
|
77
|
+
}]
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
};
|
|
83
|
+
export default codeBlockRule;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { HEADER_LIST, HEADER_TYPE_MAP } from '../constants';
|
|
3
|
+
const headerRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName,
|
|
6
|
+
childNodes
|
|
7
|
+
} = element;
|
|
8
|
+
if (nodeName && HEADER_LIST.includes(nodeName)) {
|
|
9
|
+
return {
|
|
10
|
+
id: slugid.nice(),
|
|
11
|
+
type: HEADER_TYPE_MAP[nodeName],
|
|
12
|
+
children: parseChild(childNodes)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
};
|
|
17
|
+
export default headerRule;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { IMAGE } from '../constants';
|
|
3
|
+
const imageRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName
|
|
6
|
+
} = element;
|
|
7
|
+
if (nodeName === 'IMG') {
|
|
8
|
+
return {
|
|
9
|
+
id: slugid.nice(),
|
|
10
|
+
type: IMAGE,
|
|
11
|
+
data: {
|
|
12
|
+
src: element.getAttribute('src')
|
|
13
|
+
},
|
|
14
|
+
children: [{
|
|
15
|
+
text: '',
|
|
16
|
+
id: slugid.nice()
|
|
17
|
+
}]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
};
|
|
22
|
+
export default imageRule;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import blockquoteRule from './blockquote';
|
|
2
|
+
import codeBlockRule from './code-block';
|
|
3
|
+
import headerRule from './header';
|
|
4
|
+
import imageRule from './image';
|
|
5
|
+
import linkRule from './link';
|
|
6
|
+
import listRule from './list';
|
|
7
|
+
import paragraphRule from './paragraph';
|
|
8
|
+
import tableRule from './table';
|
|
9
|
+
import textRule from './text';
|
|
10
|
+
const rules = [blockquoteRule, codeBlockRule, headerRule, imageRule, linkRule, listRule, tableRule, paragraphRule, textRule];
|
|
11
|
+
export default rules;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { LINK } from '../constants';
|
|
3
|
+
const linkRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName
|
|
6
|
+
} = element;
|
|
7
|
+
const content = element.textContent || element.getAttribute('title') || element.getAttribute('href');
|
|
8
|
+
if (nodeName === 'A') {
|
|
9
|
+
return {
|
|
10
|
+
id: slugid.nice(),
|
|
11
|
+
type: LINK,
|
|
12
|
+
href: element.getAttribute('href'),
|
|
13
|
+
title: element.getAttribute('title'),
|
|
14
|
+
children: [{
|
|
15
|
+
id: slugid.nice(),
|
|
16
|
+
text: content
|
|
17
|
+
}]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
};
|
|
22
|
+
export default linkRule;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { LIST_ITEM, ORDERED_LIST, PARAGRAPH, UNORDERED_LIST } from '../constants';
|
|
3
|
+
const PARAGRAPH_TAGS = ['DIV', 'P'];
|
|
4
|
+
const listRule = (element, parseChild) => {
|
|
5
|
+
const {
|
|
6
|
+
nodeName,
|
|
7
|
+
childNodes
|
|
8
|
+
} = element;
|
|
9
|
+
if (nodeName === 'UL') {
|
|
10
|
+
return {
|
|
11
|
+
id: slugid.nice(),
|
|
12
|
+
type: UNORDERED_LIST,
|
|
13
|
+
children: parseChild(childNodes)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (nodeName === 'OL') {
|
|
17
|
+
return {
|
|
18
|
+
id: slugid.nice(),
|
|
19
|
+
type: ORDERED_LIST,
|
|
20
|
+
children: parseChild(childNodes)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (nodeName === 'LI' && PARAGRAPH_TAGS.includes(element.firstChild.nodeName)) {
|
|
24
|
+
return {
|
|
25
|
+
id: slugid.nice(),
|
|
26
|
+
type: LIST_ITEM,
|
|
27
|
+
children: parseChild(childNodes)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (nodeName === 'LI' && !PARAGRAPH_TAGS.includes(element.firstChild.nodeName)) {
|
|
31
|
+
return {
|
|
32
|
+
id: slugid.nice(),
|
|
33
|
+
type: LIST_ITEM,
|
|
34
|
+
children: [{
|
|
35
|
+
id: slugid.nice(),
|
|
36
|
+
type: PARAGRAPH,
|
|
37
|
+
children: parseChild(childNodes)
|
|
38
|
+
}]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (PARAGRAPH_TAGS.includes(nodeName) && element.parentElement.nodeName === 'LI') {
|
|
42
|
+
return {
|
|
43
|
+
id: slugid.nice(),
|
|
44
|
+
type: PARAGRAPH,
|
|
45
|
+
children: parseChild(childNodes)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
};
|
|
50
|
+
export default listRule;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { PARAGRAPH } from '../constants';
|
|
3
|
+
const paragraphRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName,
|
|
6
|
+
childNodes
|
|
7
|
+
} = element;
|
|
8
|
+
if (nodeName === 'P' && element.parentElement.nodeName !== 'LI') {
|
|
9
|
+
return {
|
|
10
|
+
id: slugid.nice(),
|
|
11
|
+
type: PARAGRAPH,
|
|
12
|
+
children: parseChild(childNodes)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
};
|
|
17
|
+
export default paragraphRule;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
import { TABLE, TABLE_CELL, TABLE_ROW } from '../constants';
|
|
3
|
+
const tableRule = (element, parseChild) => {
|
|
4
|
+
const {
|
|
5
|
+
nodeName,
|
|
6
|
+
childNodes
|
|
7
|
+
} = element;
|
|
8
|
+
if (nodeName === 'TABLE') {
|
|
9
|
+
return {
|
|
10
|
+
id: slugid.nice(),
|
|
11
|
+
type: TABLE,
|
|
12
|
+
children: parseChild(childNodes)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (nodeName === 'THEAD' || nodeName === 'TBODY') {
|
|
16
|
+
return parseChild(childNodes);
|
|
17
|
+
}
|
|
18
|
+
if (nodeName === 'TR' && childNodes.length > 0) {
|
|
19
|
+
// patch
|
|
20
|
+
const children = Array.from(childNodes);
|
|
21
|
+
const hasTdOrTh = children.some(item => item.nodeName === 'TH' || item.nodeName === 'TD');
|
|
22
|
+
if (!hasTdOrTh) return;
|
|
23
|
+
return {
|
|
24
|
+
id: slugid.nice(),
|
|
25
|
+
type: TABLE_ROW,
|
|
26
|
+
children: parseChild(childNodes)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (nodeName === 'TH' || nodeName === 'TD') {
|
|
30
|
+
return {
|
|
31
|
+
id: slugid.nice(),
|
|
32
|
+
type: TABLE_CELL,
|
|
33
|
+
children: parseChild(childNodes)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
};
|
|
38
|
+
export default tableRule;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import slugid from 'slugid';
|
|
2
|
+
const textRule = (element, parseChild) => {
|
|
3
|
+
const {
|
|
4
|
+
nodeName,
|
|
5
|
+
nodeType
|
|
6
|
+
} = element;
|
|
7
|
+
if (nodeName === 'SPAN') {
|
|
8
|
+
return {
|
|
9
|
+
id: slugid.nice(),
|
|
10
|
+
text: element.textContent
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (nodeName === 'STRONG' || nodeName === 'B') {
|
|
14
|
+
return {
|
|
15
|
+
id: slugid.nice(),
|
|
16
|
+
bold: true,
|
|
17
|
+
text: element.textContent
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (nodeName === 'CODE' && element.parentElement.nodeName !== 'PRE') {
|
|
21
|
+
return {
|
|
22
|
+
id: slugid.nice(),
|
|
23
|
+
code: true,
|
|
24
|
+
text: element.textContent
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (nodeName === 'DEL') {
|
|
28
|
+
return {
|
|
29
|
+
id: slugid.nice(),
|
|
30
|
+
delete: true,
|
|
31
|
+
text: element.textContent
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (nodeName === 'I') {
|
|
35
|
+
return {
|
|
36
|
+
id: slugid.nice(),
|
|
37
|
+
italic: true,
|
|
38
|
+
text: element.textContent
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (nodeName === 'INS') {
|
|
42
|
+
return {
|
|
43
|
+
id: slugid.nice(),
|
|
44
|
+
add: true,
|
|
45
|
+
text: element.textContent
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (nodeType === 3) {
|
|
49
|
+
return {
|
|
50
|
+
id: slugid.nice(),
|
|
51
|
+
text: element.textContent
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
};
|
|
56
|
+
export default textRule;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import mdStringToSlate from './md-to-slate';
|
|
2
|
+
import slateToMdString from './slate-to-md';
|
|
3
|
+
import processor from './md-to-html';
|
|
4
|
+
import deserializeHtml from './html-to-slate';
|
|
5
|
+
export { mdStringToSlate, slateToMdString, processor,
|
|
6
|
+
// md string to html
|
|
7
|
+
deserializeHtml // html -> slate notes
|
|
8
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { unified } from 'unified';
|
|
2
|
+
import markdown from 'remark-parse';
|
|
3
|
+
import gfm from 'remark-gfm';
|
|
4
|
+
import math from 'remark-math';
|
|
5
|
+
import breaks from 'remark-breaks';
|
|
6
|
+
import remarkRehype from 'remark-rehype';
|
|
7
|
+
import mathjax from 'rehype-mathjax/browser';
|
|
8
|
+
import rehypeSlug from 'rehype-slug';
|
|
9
|
+
import rehypeRaw from 'rehype-raw';
|
|
10
|
+
import rehypeFormat from 'rehype-format';
|
|
11
|
+
import rehypeSanitize from 'rehype-sanitize';
|
|
12
|
+
import rehypeStringify from 'rehype-stringify';
|
|
13
|
+
import sanitizeSchema from './sanitize-schema';
|
|
14
|
+
|
|
15
|
+
// mdString -> mdast -> html ast -> html
|
|
16
|
+
const processor = unified()
|
|
17
|
+
// Handles markdown basic syntax
|
|
18
|
+
// https://github.com/remarkjs/remark/tree/main
|
|
19
|
+
.use(markdown)
|
|
20
|
+
// Handle markdown extension syntax
|
|
21
|
+
// https://github.com/remarkjs/remark-gfm
|
|
22
|
+
.use(gfm)
|
|
23
|
+
// https://github.com/remarkjs/remark-math
|
|
24
|
+
.use(math)
|
|
25
|
+
// https://github.com/remarkjs/remark-breaks
|
|
26
|
+
.use(breaks).use(remarkRehype, {
|
|
27
|
+
allowDangerousHtml: true
|
|
28
|
+
}) // convert mdast -> hast
|
|
29
|
+
// https://www.npmjs.com/package/rehype-mathjax
|
|
30
|
+
.use(mathjax, {
|
|
31
|
+
displayMath: ['$$', '$$']
|
|
32
|
+
})
|
|
33
|
+
// https://www.npmjs.com/package/rehype-raw
|
|
34
|
+
.use(rehypeRaw)
|
|
35
|
+
// https://www.npmjs.com/package/rehype-format
|
|
36
|
+
.use(rehypeFormat, {
|
|
37
|
+
blanks: ['pre', 'code']
|
|
38
|
+
})
|
|
39
|
+
// https://github.com/rehypejs/rehype-slug
|
|
40
|
+
.use(rehypeSlug)
|
|
41
|
+
// https://github.com/rehypejs/rehype-sanitize
|
|
42
|
+
.use(rehypeSanitize, sanitizeSchema)
|
|
43
|
+
// https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify
|
|
44
|
+
.use(rehypeStringify);
|
|
45
|
+
|
|
46
|
+
// transform rules: https://github.com/syntax-tree/mdast-util-to-hast
|
|
47
|
+
|
|
48
|
+
export default processor;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import deepmerge from 'deepmerge';
|
|
2
|
+
import { defaultSchema } from 'hast-util-sanitize';
|
|
3
|
+
const customSchema = {
|
|
4
|
+
'tagNames': ['input', 'code', 'span', 'div', 'blockquote', 'pre'],
|
|
5
|
+
'attributes': {
|
|
6
|
+
'input': ['type'],
|
|
7
|
+
'li': ['className'],
|
|
8
|
+
'code': ['className'],
|
|
9
|
+
'span': ['className'],
|
|
10
|
+
'div': ['className']
|
|
11
|
+
},
|
|
12
|
+
'protocols': {
|
|
13
|
+
'src': ['http', 'https', 'cid']
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const sanitizeSchema = deepmerge(defaultSchema, customSchema);
|
|
17
|
+
export default sanitizeSchema;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { unified } from 'unified';
|
|
2
|
+
import markdown from 'remark-parse';
|
|
3
|
+
import gfm from 'remark-gfm';
|
|
4
|
+
import math from 'remark-math';
|
|
5
|
+
import { generateDefaultParagraph } from '../../basic-sdk/extension/core';
|
|
6
|
+
import { formatMdToSlate } from './transform';
|
|
7
|
+
|
|
8
|
+
// md string -> md ast
|
|
9
|
+
const getProcessor = () => {
|
|
10
|
+
const processor = unified().use(markdown) // Handles markdown basic syntax
|
|
11
|
+
.use(gfm) // Handle markdown extension syntax
|
|
12
|
+
.use(math); // Handles markdown math formulas
|
|
13
|
+
|
|
14
|
+
return processor;
|
|
15
|
+
};
|
|
16
|
+
const reconciledSlateNodes = nodes => {
|
|
17
|
+
return nodes;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// md string --> md ast --> slate ast
|
|
21
|
+
// https://github.com/syntax-tree/mdast
|
|
22
|
+
const mdStringToSlate = mdString => {
|
|
23
|
+
if (!mdString) return [generateDefaultParagraph()];
|
|
24
|
+
let content = mdString;
|
|
25
|
+
if (typeof mdString === 'number') {
|
|
26
|
+
content = mdString + '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// md string --> md ast
|
|
30
|
+
const root = getProcessor().parse(content);
|
|
31
|
+
|
|
32
|
+
// md ast --> slate ast
|
|
33
|
+
const slateNodes = formatMdToSlate(root.children);
|
|
34
|
+
|
|
35
|
+
// Format the document
|
|
36
|
+
return reconciledSlateNodes(slateNodes);
|
|
37
|
+
};
|
|
38
|
+
export default mdStringToSlate;
|