@pie-lib/editable-html 9.5.13 → 10.0.0-beta.1
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/CHANGELOG.md +0 -302
- package/lib/components.js +116 -0
- package/lib/components.js.map +1 -0
- package/lib/editor.js +418 -103
- package/lib/editor.js.map +1 -1
- package/lib/index.js +101 -155
- package/lib/index.js.map +1 -1
- package/lib/new-serialization.js +320 -0
- package/lib/new-serialization.js.map +1 -0
- package/lib/old-serialization.js +330 -0
- package/lib/parse-html.js +1 -1
- package/lib/parse-html.js.map +1 -1
- package/lib/plugins/characters/custom-popper.js +1 -1
- package/lib/plugins/characters/custom-popper.js.map +1 -1
- package/lib/plugins/characters/index.js +21 -19
- package/lib/plugins/characters/index.js.map +1 -1
- package/lib/plugins/characters/utils.js +1 -1
- package/lib/plugins/characters/utils.js.map +1 -1
- package/lib/plugins/hotKeys/index.js +67 -0
- package/lib/plugins/hotKeys/index.js.map +1 -0
- package/lib/plugins/image/alt-dialog.js +1 -6
- package/lib/plugins/image/alt-dialog.js.map +1 -1
- package/lib/plugins/image/component.js +70 -53
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +7 -9
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +83 -27
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/image/insert-image-handler.js +72 -33
- package/lib/plugins/image/insert-image-handler.js.map +1 -1
- package/lib/plugins/index.js +23 -41
- package/lib/plugins/index.js.map +1 -1
- package/lib/plugins/list/index.js +64 -100
- package/lib/plugins/list/index.js.map +1 -1
- package/lib/plugins/math/index.js +86 -60
- package/lib/plugins/math/index.js.map +1 -1
- package/lib/plugins/media/index.js +202 -132
- package/lib/plugins/media/index.js.map +1 -1
- package/lib/plugins/media/media-dialog.js +17 -16
- package/lib/plugins/media/media-dialog.js.map +1 -1
- package/lib/plugins/media/media-toolbar.js +3 -3
- package/lib/plugins/media/media-toolbar.js.map +1 -1
- package/lib/plugins/media/media-wrapper.js +21 -58
- package/lib/plugins/media/media-wrapper.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +3 -3
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +3 -2
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +3 -2
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
- package/lib/plugins/respArea/icons/index.js +13 -15
- package/lib/plugins/respArea/icons/index.js.map +1 -1
- package/lib/plugins/respArea/index.js +87 -53
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +4 -3
- package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
- package/lib/plugins/respArea/utils.js +17 -20
- package/lib/plugins/respArea/utils.js.map +1 -1
- package/lib/plugins/table/icons/index.js +1 -1
- package/lib/plugins/table/icons/index.js.map +1 -1
- package/lib/plugins/table/index.js +381 -212
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/table-toolbar.js +5 -6
- package/lib/plugins/table/table-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/default-toolbar.js +55 -11
- package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/done-button.js +1 -1
- package/lib/plugins/toolbar/done-button.js.map +1 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +186 -232
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/index.js +1 -2
- package/lib/plugins/toolbar/index.js.map +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
- package/lib/plugins/toolbar/toolbar.js +253 -239
- package/lib/plugins/toolbar/toolbar.js.map +1 -1
- package/lib/plugins/utils.js +27 -2
- package/lib/plugins/utils.js.map +1 -1
- package/lib/serialization.js +1 -1
- package/lib/serialization.js.map +1 -1
- package/lib/slate-editor.js +302 -0
- package/lib/test-serializer.js +189 -0
- package/lib/test-serializer.js.map +1 -0
- package/lib/theme.js +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +18 -14
- package/playground/image/data.js +20 -20
- package/playground/image/index.html +22 -20
- package/playground/image/index.jsx +12 -10
- package/playground/index.html +25 -23
- package/playground/mathquill/index.html +23 -20
- package/playground/mathquill/index.jsx +18 -22
- package/playground/prod-test/index.html +24 -20
- package/playground/prod-test/index.jsx +5 -3
- package/playground/schema-override/data.js +10 -10
- package/playground/schema-override/image-plugin.jsx +3 -4
- package/playground/schema-override/index.html +21 -19
- package/playground/schema-override/index.jsx +13 -14
- package/playground/serialization/data.js +10 -10
- package/playground/serialization/image-plugin.jsx +3 -4
- package/playground/serialization/index.html +22 -20
- package/playground/table-examples.html +5 -8
- package/playground/webpack.config.js +10 -10
- package/src/components.js +135 -0
- package/src/editor.jsx +478 -141
- package/src/index.jsx +71 -95
- package/src/new-serialization.jsx +291 -0
- package/src/parse-html.js +1 -1
- package/src/plugins/characters/custom-popper.js +7 -7
- package/src/plugins/characters/index.jsx +33 -34
- package/src/plugins/characters/utils.js +81 -81
- package/src/plugins/hotKeys/index.js +54 -0
- package/src/plugins/image/alt-dialog.jsx +4 -5
- package/src/plugins/image/component.jsx +106 -89
- package/src/plugins/image/image-toolbar.jsx +27 -19
- package/src/plugins/image/index.jsx +75 -43
- package/src/plugins/image/insert-image-handler.js +62 -27
- package/src/plugins/index.jsx +23 -41
- package/src/plugins/list/index.jsx +70 -95
- package/src/plugins/math/index.jsx +102 -82
- package/src/plugins/media/index.jsx +159 -124
- package/src/plugins/media/media-dialog.js +98 -71
- package/src/plugins/media/media-toolbar.jsx +8 -8
- package/src/plugins/media/media-wrapper.jsx +29 -30
- package/src/plugins/respArea/drag-in-the-blank/choice.jsx +21 -19
- package/src/plugins/respArea/drag-in-the-blank/index.jsx +14 -11
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +7 -6
- package/src/plugins/respArea/icons/index.jsx +11 -14
- package/src/plugins/respArea/index.jsx +92 -52
- package/src/plugins/respArea/inline-dropdown/index.jsx +9 -8
- package/src/plugins/respArea/utils.jsx +26 -35
- package/src/plugins/table/icons/index.jsx +17 -11
- package/src/plugins/table/index.jsx +288 -231
- package/src/plugins/table/table-toolbar.jsx +15 -11
- package/src/plugins/toolbar/default-toolbar.jsx +65 -19
- package/src/plugins/toolbar/done-button.jsx +4 -4
- package/src/plugins/toolbar/editor-and-toolbar.jsx +150 -145
- package/src/plugins/toolbar/index.jsx +2 -3
- package/src/plugins/toolbar/toolbar-buttons.jsx +11 -11
- package/src/plugins/toolbar/toolbar.jsx +244 -221
- package/src/plugins/utils.js +21 -4
- package/src/serialization.jsx +32 -32
- package/src/test-serializer.js +139 -0
- package/src/test-serializer.js.rej +20 -0
|
@@ -1,37 +1,53 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Data } from 'slate';
|
|
3
|
-
import Immutable from 'immutable';
|
|
4
2
|
import PropTypes from 'prop-types';
|
|
5
|
-
import EditList from 'slate-edit-list';
|
|
6
3
|
import debug from 'debug';
|
|
4
|
+
import { Editor, Element as SlateElement, Transforms } from 'slate';
|
|
5
|
+
import { jsx } from "slate-hyperscript";
|
|
7
6
|
|
|
8
7
|
const log = debug('@pie-lib:editable-html:plugins:list');
|
|
9
8
|
|
|
10
9
|
const b = (type, next, childNodes) => ({
|
|
11
10
|
object: 'block',
|
|
12
11
|
type,
|
|
13
|
-
nodes: next(childNodes)
|
|
12
|
+
nodes: next(childNodes)
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
export const serialization = {
|
|
17
16
|
deserialize(el, next) {
|
|
18
17
|
const name = el.tagName.toLowerCase();
|
|
18
|
+
const children = el.children.length ? Array.from(el.children) : el.childNodes;
|
|
19
19
|
|
|
20
20
|
if (name === 'li') {
|
|
21
|
-
return
|
|
21
|
+
return jsx(
|
|
22
|
+
'element',
|
|
23
|
+
{
|
|
24
|
+
type: 'li'
|
|
25
|
+
},
|
|
26
|
+
next(children)
|
|
27
|
+
);
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
if (name === 'ul') {
|
|
25
|
-
return
|
|
31
|
+
return jsx(
|
|
32
|
+
'element',
|
|
33
|
+
{
|
|
34
|
+
type: 'ul'
|
|
35
|
+
},
|
|
36
|
+
next(children)
|
|
37
|
+
);
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
if (name === 'ol') {
|
|
29
|
-
return
|
|
41
|
+
return jsx(
|
|
42
|
+
'element',
|
|
43
|
+
{
|
|
44
|
+
type: 'ol'
|
|
45
|
+
},
|
|
46
|
+
next(children)
|
|
47
|
+
);
|
|
30
48
|
}
|
|
31
49
|
},
|
|
32
50
|
serialize(object, children) {
|
|
33
|
-
if (object.object !== 'block') return;
|
|
34
|
-
|
|
35
51
|
if (object.type === 'list_item') {
|
|
36
52
|
return <li>{children}</li>;
|
|
37
53
|
}
|
|
@@ -43,92 +59,65 @@ export const serialization = {
|
|
|
43
59
|
if (object.type === 'ol_list') {
|
|
44
60
|
return <ol>{children}</ol>;
|
|
45
61
|
}
|
|
46
|
-
}
|
|
62
|
+
}
|
|
47
63
|
};
|
|
48
64
|
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// fix outdated schema
|
|
55
|
-
if (core.schema && core.schema.blocks) {
|
|
56
|
-
Object.keys(core.schema.blocks).forEach((key) => {
|
|
57
|
-
const block = core.schema.blocks[key];
|
|
65
|
+
const isBlockActive = (editor, format) => {
|
|
66
|
+
const { selection } = editor;
|
|
67
|
+
if (!selection) return false;
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
const [match] = Array.from(
|
|
70
|
+
Editor.nodes(editor, {
|
|
71
|
+
at: Editor.unhangRange(editor, selection),
|
|
72
|
+
match: node => !Editor.isEditor(node) && SlateElement.isElement(node) && node.type === format
|
|
73
|
+
})
|
|
74
|
+
);
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* This override of the core.changes.wrapInList is needed because the version
|
|
69
|
-
* of immutable that we have does not support getting the element at a specific
|
|
70
|
-
* index with a square bracket (list[0]). We have to use the list.get function instead
|
|
71
|
-
*/
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Returns the highest list of blocks that cover the current selection
|
|
75
|
-
*/
|
|
76
|
-
const getHighestSelectedBlocks = (value) => {
|
|
77
|
-
const range = value.selection;
|
|
78
|
-
const document = value.document;
|
|
76
|
+
return !!match;
|
|
77
|
+
};
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
const createEditList = () => {
|
|
80
|
+
const core = {
|
|
81
|
+
changes: {}
|
|
82
|
+
};
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
core.changes.wrapInList = (editor, format) => {
|
|
85
|
+
const isActive = isBlockActive(editor, format);
|
|
86
|
+
const isList = LIST_TYPES.includes(format);
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
Transforms.unwrapNodes(editor, {
|
|
89
|
+
match: n =>
|
|
90
|
+
!Editor.isEditor(n) &&
|
|
91
|
+
SlateElement.isElement(n) &&
|
|
92
|
+
LIST_TYPES.includes(n.type),
|
|
93
|
+
split: true
|
|
94
|
+
});
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
const newProperties = {
|
|
97
|
+
type: isActive ? 'paragraph' : isList ? 'list_item' : format
|
|
98
|
+
};
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
* Wrap the blocks in the current selection in a new list. Selected
|
|
96
|
-
* lists are merged together.
|
|
97
|
-
*/
|
|
98
|
-
core.changes.wrapInList = function(change, type, data) {
|
|
99
|
-
const selectedBlocks = getHighestSelectedBlocks(change.value);
|
|
100
|
-
|
|
101
|
-
// Wrap in container
|
|
102
|
-
change.wrapBlock({ type: type, data: Data.create(data) }, { normalize: false });
|
|
103
|
-
|
|
104
|
-
// Wrap in list items
|
|
105
|
-
selectedBlocks.forEach(function(node) {
|
|
106
|
-
if (core.utils.isList(node)) {
|
|
107
|
-
// Merge its items with the created list
|
|
108
|
-
node.nodes.forEach(function(_ref) {
|
|
109
|
-
const key = _ref.key;
|
|
110
|
-
return change.unwrapNodeByKey(key, { normalize: false });
|
|
111
|
-
});
|
|
112
|
-
} else if (node.type !== 'list_item') {
|
|
113
|
-
change.wrapBlockByKey(node.key, 'list_item', {
|
|
114
|
-
normalize: false,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
});
|
|
100
|
+
Transforms.setNodes(editor, newProperties);
|
|
118
101
|
|
|
119
|
-
|
|
102
|
+
if (!isActive && isList) {
|
|
103
|
+
const block = { type: format, children: [] };
|
|
104
|
+
Transforms.wrapNodes(editor, block);
|
|
105
|
+
}
|
|
120
106
|
};
|
|
121
107
|
|
|
122
108
|
return core;
|
|
123
109
|
};
|
|
124
110
|
|
|
125
|
-
|
|
111
|
+
const LIST_TYPES = ['ol_list', 'ul_list', 'list_item'];
|
|
112
|
+
|
|
113
|
+
export default options => {
|
|
126
114
|
const { type, icon } = options;
|
|
127
115
|
|
|
128
116
|
const core = createEditList();
|
|
129
117
|
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
core.supports = node => LIST_TYPES.includes(node.type);
|
|
119
|
+
|
|
120
|
+
core.renderNode = props => {
|
|
132
121
|
const { node, attributes, children } = props;
|
|
133
122
|
|
|
134
123
|
switch (node.type) {
|
|
@@ -145,30 +134,16 @@ export default (options) => {
|
|
|
145
134
|
isMark: false,
|
|
146
135
|
type,
|
|
147
136
|
icon,
|
|
148
|
-
isActive:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const current = core.utils.getCurrentList(value);
|
|
153
|
-
return current ? current.type === type : false;
|
|
154
|
-
},
|
|
155
|
-
onClick: (value, onChange) => {
|
|
156
|
-
log('[onClick]', value);
|
|
157
|
-
const inList = core.utils.isSelectionInList(value);
|
|
158
|
-
if (inList) {
|
|
159
|
-
const change = value.change().call(core.changes.unwrapList);
|
|
160
|
-
onChange(change);
|
|
161
|
-
} else {
|
|
162
|
-
const change = value.change().call(core.changes.wrapInList, type);
|
|
163
|
-
onChange(change);
|
|
164
|
-
}
|
|
165
|
-
},
|
|
137
|
+
isActive: isBlockActive,
|
|
138
|
+
onClick: editor => {
|
|
139
|
+
core.changes.wrapInList(editor, type);
|
|
140
|
+
}
|
|
166
141
|
};
|
|
167
142
|
|
|
168
143
|
core.renderNode.propTypes = {
|
|
169
144
|
node: PropTypes.object,
|
|
170
145
|
attributes: PropTypes.object,
|
|
171
|
-
children: PropTypes.func
|
|
146
|
+
children: PropTypes.func
|
|
172
147
|
};
|
|
173
148
|
|
|
174
149
|
return core;
|
|
@@ -1,65 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Editor, Inline, Transforms } from 'slate';
|
|
3
|
+
import { ReactEditor } from 'slate-react';
|
|
4
|
+
import { jsx } from 'slate-hyperscript';
|
|
1
5
|
import Functions from '@material-ui/icons/Functions';
|
|
2
|
-
import { Inline } from 'slate';
|
|
3
6
|
import { MathPreview, MathToolbar } from '@pie-lib/math-toolbar';
|
|
4
7
|
import { wrapMath, unWrapMath } from '@pie-lib/math-rendering';
|
|
5
|
-
import React from 'react';
|
|
6
8
|
import debug from 'debug';
|
|
7
|
-
import SlatePropTypes from 'slate-prop-types';
|
|
8
9
|
import PropTypes from 'prop-types';
|
|
10
|
+
import isEqual from 'lodash/isEqual';
|
|
9
11
|
|
|
10
|
-
import { BLOCK_TAGS } from '../../serialization';
|
|
12
|
+
import { BLOCK_TAGS } from '../../new-serialization';
|
|
11
13
|
const log = debug('@pie-lib:editable-html:plugins:math');
|
|
12
14
|
|
|
13
15
|
const TEXT_NODE = 3;
|
|
14
16
|
|
|
15
17
|
function generateAdditionalKeys(keyData = []) {
|
|
16
|
-
return keyData.map(
|
|
18
|
+
return keyData.map(key => ({
|
|
17
19
|
name: key,
|
|
18
20
|
latex: key,
|
|
19
21
|
write: key,
|
|
20
|
-
label: key
|
|
22
|
+
label: key
|
|
21
23
|
}));
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export const CustomToolbarComp = React.memo(
|
|
25
|
-
|
|
26
|
-
const { node,
|
|
27
|
+
props => {
|
|
28
|
+
const { node, onFocus, onBlur, onClick, editor, nodePath } = props;
|
|
27
29
|
const { pluginProps } = props || {};
|
|
28
30
|
const { math } = pluginProps || {};
|
|
29
31
|
const { keypadMode, customKeys, controlledKeypadMode = true } = math || {};
|
|
30
32
|
|
|
31
|
-
const onDone =
|
|
32
|
-
const update = {
|
|
33
|
-
...node.data.toObject(),
|
|
34
|
-
latex,
|
|
35
|
-
};
|
|
36
|
-
const change = value.change().setNodeByKey(node.key, { data: update });
|
|
37
|
-
|
|
38
|
-
const nextText = value.document.getNextText(node.key);
|
|
39
|
-
|
|
40
|
-
change.moveFocusTo(nextText.key, 0).moveAnchorTo(nextText.key, 0);
|
|
41
|
-
|
|
42
|
-
props.onToolbarDone(change, false);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const onChange = (latex) => {
|
|
33
|
+
const onDone = latex => {
|
|
46
34
|
const update = {
|
|
47
|
-
...node.data
|
|
48
|
-
latex
|
|
35
|
+
...node.data,
|
|
36
|
+
latex
|
|
49
37
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
editor.apply({
|
|
39
|
+
type: 'set_node',
|
|
40
|
+
path: nodePath,
|
|
41
|
+
properties: {
|
|
42
|
+
data: node.data
|
|
43
|
+
},
|
|
44
|
+
newProperties: { data: update }
|
|
45
|
+
});
|
|
46
|
+
ReactEditor.focus(editor);
|
|
47
|
+
Transforms.move(editor, { distance: 1, unit: 'offset' });
|
|
53
48
|
};
|
|
54
49
|
|
|
55
|
-
const latex = node.data.
|
|
50
|
+
const latex = node.data.latex;
|
|
56
51
|
|
|
57
52
|
return (
|
|
58
53
|
<MathToolbar
|
|
59
54
|
autoFocus
|
|
60
55
|
additionalKeys={generateAdditionalKeys(customKeys)}
|
|
61
56
|
latex={latex}
|
|
62
|
-
onChange={onChange}
|
|
63
57
|
onDone={onDone}
|
|
64
58
|
onBlur={onBlur}
|
|
65
59
|
onFocus={onFocus}
|
|
@@ -73,38 +67,51 @@ export const CustomToolbarComp = React.memo(
|
|
|
73
67
|
const { node, pluginProps: { math: { keypadMode, controlledKeypadMode } = {} } = {} } = prev;
|
|
74
68
|
const {
|
|
75
69
|
node: nodeNext,
|
|
76
|
-
pluginProps: {
|
|
70
|
+
pluginProps: {
|
|
71
|
+
math: { keypadMode: keypadModeNext, controlledKeypadMode: controlledKeypadModeNext } = {}
|
|
72
|
+
} = {}
|
|
77
73
|
} = next;
|
|
78
74
|
const keypadModeChanged = keypadMode !== keypadModeNext;
|
|
79
75
|
const controlledKeypadModeChanged = controlledKeypadMode !== controlledKeypadModeNext;
|
|
80
76
|
|
|
81
|
-
const equal = node
|
|
77
|
+
const equal = isEqual(node, nodeNext);
|
|
82
78
|
return equal && !keypadModeChanged && !controlledKeypadModeChanged;
|
|
83
|
-
}
|
|
79
|
+
}
|
|
84
80
|
);
|
|
85
81
|
|
|
86
82
|
CustomToolbarComp.propTypes = {
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
editor: PropTypes.object,
|
|
84
|
+
node: PropTypes.shape({
|
|
85
|
+
type: PropTypes.string,
|
|
86
|
+
children: PropTypes.array,
|
|
87
|
+
data: PropTypes.object
|
|
88
|
+
}).isRequired,
|
|
89
|
+
value: PropTypes.arrayOf(
|
|
90
|
+
PropTypes.shape({
|
|
91
|
+
type: PropTypes.string,
|
|
92
|
+
children: PropTypes.array,
|
|
93
|
+
data: PropTypes.object
|
|
94
|
+
})
|
|
95
|
+
).isRequired,
|
|
89
96
|
onToolbarDone: PropTypes.func,
|
|
90
|
-
onDataChange: PropTypes.func,
|
|
91
97
|
onFocus: PropTypes.func,
|
|
92
98
|
onClick: PropTypes.func,
|
|
93
|
-
onBlur: PropTypes.func
|
|
99
|
+
onBlur: PropTypes.func
|
|
94
100
|
};
|
|
95
101
|
|
|
102
|
+
const mathTypes = ['math', 'mathml'];
|
|
103
|
+
|
|
96
104
|
export default function MathPlugin() {
|
|
97
105
|
return {
|
|
98
106
|
name: 'math',
|
|
99
107
|
toolbar: {
|
|
100
108
|
icon: <Functions />,
|
|
101
|
-
onClick:
|
|
109
|
+
onClick: editor => {
|
|
102
110
|
log('[insertMath]');
|
|
103
111
|
const math = inlineMath();
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
|
|
113
|
+
editor.insertNode(math);
|
|
106
114
|
},
|
|
107
|
-
supports: (node) => node && node.object === 'inline' && node.type === 'math',
|
|
108
115
|
/**
|
|
109
116
|
* Return a react component function
|
|
110
117
|
* @param node {Slate.Node}
|
|
@@ -112,22 +119,36 @@ export default function MathPlugin() {
|
|
|
112
119
|
* @param onDone {(change?: Slate.Change, finishEditing :boolea) => void} - a function to call once the toolbar
|
|
113
120
|
* has made any changes, call with the node.key and a data object.
|
|
114
121
|
*/
|
|
115
|
-
CustomToolbarComp
|
|
122
|
+
CustomToolbarComp
|
|
123
|
+
},
|
|
124
|
+
rules: editor => {
|
|
125
|
+
const { isVoid, isInline } = editor;
|
|
126
|
+
|
|
127
|
+
editor.isVoid = element => {
|
|
128
|
+
return mathTypes.includes(element.type) ? true : isVoid(element);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
editor.isInline = element => {
|
|
132
|
+
return mathTypes.includes(element.type) ? true : isInline(element);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return editor;
|
|
116
136
|
},
|
|
137
|
+
supports: node => mathTypes.includes(node.type),
|
|
117
138
|
schema: {
|
|
118
|
-
document: { match: [{ type: 'math' }] }
|
|
139
|
+
document: { match: [{ type: 'math' }] }
|
|
119
140
|
},
|
|
120
141
|
|
|
121
142
|
pluginStyles: (node, parentNode, p) => {
|
|
122
143
|
if (p) {
|
|
123
144
|
return {
|
|
124
145
|
position: 'absolute',
|
|
125
|
-
top: 'initial'
|
|
146
|
+
top: 'initial'
|
|
126
147
|
};
|
|
127
148
|
}
|
|
128
149
|
},
|
|
129
150
|
|
|
130
|
-
renderNode:
|
|
151
|
+
renderNode: props => {
|
|
131
152
|
if (props.node.type === 'math') {
|
|
132
153
|
log('[renderNode]: data:', props.node.data);
|
|
133
154
|
return <MathPreview {...props} />;
|
|
@@ -137,11 +158,16 @@ export default function MathPlugin() {
|
|
|
137
158
|
* Here for rendering mathml content
|
|
138
159
|
*/
|
|
139
160
|
if (props.node.type === 'mathml') {
|
|
140
|
-
const html = props.node
|
|
141
|
-
|
|
142
|
-
return
|
|
161
|
+
const { data: { html } } = props.node;
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<span>
|
|
165
|
+
<span {...props.attributes} contentEditable={false} dangerouslySetInnerHTML={{ __html: html }} />
|
|
166
|
+
{props.children}
|
|
167
|
+
</span>
|
|
168
|
+
);
|
|
143
169
|
}
|
|
144
|
-
}
|
|
170
|
+
}
|
|
145
171
|
};
|
|
146
172
|
}
|
|
147
173
|
|
|
@@ -150,23 +176,21 @@ MathPlugin.SQUARE_BRACKETS = 'square_brackets';
|
|
|
150
176
|
MathPlugin.DOLLAR = 'dollar';
|
|
151
177
|
MathPlugin.DOUBLE_DOLLAR = 'double_dollar';
|
|
152
178
|
|
|
153
|
-
export const inlineMath = () =>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
});
|
|
179
|
+
export const inlineMath = () => ({
|
|
180
|
+
type: 'math',
|
|
181
|
+
data: {
|
|
182
|
+
latex: ''
|
|
183
|
+
},
|
|
184
|
+
children: [{ text: '' }]
|
|
185
|
+
});
|
|
162
186
|
|
|
163
|
-
const htmlDecode =
|
|
187
|
+
const htmlDecode = input => {
|
|
164
188
|
const doc = new DOMParser().parseFromString(input, 'text/html');
|
|
165
189
|
|
|
166
190
|
return doc.documentElement.textContent;
|
|
167
191
|
};
|
|
168
192
|
|
|
169
|
-
const getTagName =
|
|
193
|
+
const getTagName = el => {
|
|
170
194
|
return ((el && el.tagName) || '').toLowerCase();
|
|
171
195
|
};
|
|
172
196
|
|
|
@@ -177,7 +201,7 @@ const getTagName = (el) => {
|
|
|
177
201
|
* @param input
|
|
178
202
|
* @returns {*}
|
|
179
203
|
*/
|
|
180
|
-
const lessThanHandling =
|
|
204
|
+
const lessThanHandling = input => {
|
|
181
205
|
const arrowSplit = input.split('<');
|
|
182
206
|
|
|
183
207
|
// if we don't have at least 2 characters there's no point in checking
|
|
@@ -201,7 +225,7 @@ const lessThanHandling = (input) => {
|
|
|
201
225
|
};
|
|
202
226
|
|
|
203
227
|
export const serialization = {
|
|
204
|
-
deserialize(el) {
|
|
228
|
+
deserialize(el, children) {
|
|
205
229
|
const tagName = getTagName(el);
|
|
206
230
|
/**
|
|
207
231
|
* This is used for when there's a wrapper over the mathml element.
|
|
@@ -210,7 +234,8 @@ export const serialization = {
|
|
|
210
234
|
* an inline child and the block is of type block
|
|
211
235
|
* This is for legacy content only since our math rendering is valid for the core slate rules
|
|
212
236
|
*/
|
|
213
|
-
const hasMathChild =
|
|
237
|
+
const hasMathChild =
|
|
238
|
+
BLOCK_TAGS[tagName] && el.childNodes.length === 1 && getTagName(el.firstChild) === 'math';
|
|
214
239
|
log('[deserialize] name: ', tagName);
|
|
215
240
|
|
|
216
241
|
/**
|
|
@@ -219,14 +244,12 @@ export const serialization = {
|
|
|
219
244
|
if (tagName === 'math' || (el.dataset && el.dataset.type === 'mathml') || hasMathChild) {
|
|
220
245
|
const newHtml = hasMathChild ? el.innerHTML : el.outerHTML;
|
|
221
246
|
|
|
222
|
-
return {
|
|
223
|
-
object: 'inline',
|
|
224
|
-
isVoid: true,
|
|
247
|
+
return jsx('element', {
|
|
225
248
|
type: 'mathml',
|
|
226
249
|
data: {
|
|
227
|
-
html: newHtml
|
|
228
|
-
}
|
|
229
|
-
};
|
|
250
|
+
html: newHtml
|
|
251
|
+
}
|
|
252
|
+
});
|
|
230
253
|
}
|
|
231
254
|
|
|
232
255
|
if (el.nodeType === TEXT_NODE) {
|
|
@@ -243,24 +266,21 @@ export const serialization = {
|
|
|
243
266
|
const latex = htmlDecode(el.innerHTML);
|
|
244
267
|
const { unwrapped, wrapType } = unWrapMath(latex);
|
|
245
268
|
log('[deserialize]: noBrackets: ', unwrapped, wrapType);
|
|
246
|
-
|
|
247
|
-
|
|
269
|
+
|
|
270
|
+
return jsx('element', {
|
|
248
271
|
type: 'math',
|
|
249
|
-
isVoid: true,
|
|
250
|
-
nodes: [],
|
|
251
272
|
data: {
|
|
252
273
|
latex: unwrapped,
|
|
253
|
-
wrapper: wrapType
|
|
254
|
-
}
|
|
255
|
-
};
|
|
274
|
+
wrapper: wrapType
|
|
275
|
+
}
|
|
276
|
+
});
|
|
256
277
|
}
|
|
257
278
|
},
|
|
258
279
|
serialize(object) {
|
|
259
280
|
if (object.type === 'math') {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const decoded = htmlDecode(lessThanHandling(l));
|
|
281
|
+
const { latex, wrapper } = object.data || {};
|
|
282
|
+
log('[serialize] latex: ', latex);
|
|
283
|
+
const decoded = htmlDecode(lessThanHandling(latex));
|
|
264
284
|
return (
|
|
265
285
|
<span data-latex="" data-raw={decoded}>
|
|
266
286
|
{wrapMath(decoded, wrapper)}
|
|
@@ -272,9 +292,9 @@ export const serialization = {
|
|
|
272
292
|
* Here for rendering mathml content
|
|
273
293
|
*/
|
|
274
294
|
if (object.type === 'mathml') {
|
|
275
|
-
const html = object.data
|
|
295
|
+
const { html } = object.data || {};
|
|
276
296
|
|
|
277
297
|
return <span data-type="mathml" dangerouslySetInnerHTML={{ __html: html }} />;
|
|
278
298
|
}
|
|
279
|
-
}
|
|
299
|
+
}
|
|
280
300
|
};
|