@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
package/src/editor.jsx
CHANGED
|
@@ -1,21 +1,327 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Editor as OldSlateEditor,
|
|
4
|
+
findNode,
|
|
5
|
+
getEventRange,
|
|
6
|
+
getEventTransfer,
|
|
7
|
+
useSlateStatic
|
|
8
|
+
} from 'slate-react';
|
|
9
|
+
import RootRef from '@material-ui/core/RootRef';
|
|
3
10
|
|
|
4
11
|
import isEqual from 'lodash/isEqual';
|
|
5
|
-
import * as serialization from './serialization';
|
|
12
|
+
import * as serialization from './new-serialization';
|
|
6
13
|
import PropTypes from 'prop-types';
|
|
7
|
-
import React from 'react';
|
|
8
14
|
import { Value, Block, Inline } from 'slate';
|
|
9
|
-
import {
|
|
15
|
+
import { ALL_PLUGINS, DEFAULT_PLUGINS, buildPlugins, withPlugins } from './plugins';
|
|
10
16
|
import debug from 'debug';
|
|
11
17
|
import { withStyles } from '@material-ui/core/styles';
|
|
12
18
|
import classNames from 'classnames';
|
|
13
19
|
import { color } from '@pie-lib/render-ui';
|
|
14
20
|
import Plain from 'slate-plain-serializer';
|
|
15
21
|
|
|
16
|
-
import { getBase64 } from './serialization';
|
|
22
|
+
import { getBase64, htmlToValue, valueToHtml } from './new-serialization';
|
|
17
23
|
import InsertImageHandler from './plugins/image/insert-image-handler';
|
|
18
24
|
|
|
25
|
+
import isHotkey from 'is-hotkey';
|
|
26
|
+
import { Editable, useFocused, withReact, useSlate, Slate } from 'slate-react';
|
|
27
|
+
import { Editor, Transforms, createEditor, Element as SlateElement } from 'slate';
|
|
28
|
+
import { withHistory } from 'slate-history';
|
|
29
|
+
import { MathPreview } from '@pie-lib/math-toolbar';
|
|
30
|
+
|
|
31
|
+
import { Button, Icon, Toolbar } from './components';
|
|
32
|
+
import EditorAndToolbar from './plugins/toolbar/editor-and-toolbar';
|
|
33
|
+
|
|
34
|
+
const HOTKEYS = {
|
|
35
|
+
'mod+b': 'bold',
|
|
36
|
+
'mod+i': 'italic',
|
|
37
|
+
'mod+u': 'underline',
|
|
38
|
+
'mod+`': 'code'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const LIST_TYPES = ['numbered-list', 'bulleted-list'];
|
|
42
|
+
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify'];
|
|
43
|
+
|
|
44
|
+
const initialValue = [
|
|
45
|
+
{
|
|
46
|
+
type: 'paragraph',
|
|
47
|
+
children: [
|
|
48
|
+
{
|
|
49
|
+
type: 'math',
|
|
50
|
+
data: {
|
|
51
|
+
latex: '\\frac{1}{2}',
|
|
52
|
+
wrapper: 'round_brackets'
|
|
53
|
+
},
|
|
54
|
+
children: [
|
|
55
|
+
{
|
|
56
|
+
text: '\\(\\frac{1}{2}\\)'
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const SlateEditor = editorProps => {
|
|
65
|
+
const { value, plugins } = editorProps;
|
|
66
|
+
const renderElement = useCallback(props => <Element {...props} plugins={plugins} />, []);
|
|
67
|
+
const renderLeaf = useCallback(props => <Leaf {...props} />, []);
|
|
68
|
+
const editor = useMemo(() => withPlugins(createEditor(), plugins), []);
|
|
69
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
70
|
+
const editorRef = useRef(null);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (editorProps.onEditor) {
|
|
74
|
+
editorProps.onEditor(editor);
|
|
75
|
+
}
|
|
76
|
+
}, [editor]);
|
|
77
|
+
|
|
78
|
+
const slateValue = useMemo(() => {
|
|
79
|
+
// Slate throws an error if the value on the initial render is invalid
|
|
80
|
+
// so we directly set the value on the editor in order
|
|
81
|
+
// to be able to trigger normalization on the initial value before rendering
|
|
82
|
+
editor.children = value;
|
|
83
|
+
Editor.normalize(editor, { force: true });
|
|
84
|
+
// We return the normalized internal value so that the rendering can take over from here
|
|
85
|
+
return editor.children;
|
|
86
|
+
}, [editor, value]);
|
|
87
|
+
|
|
88
|
+
const onKeyDown = event => {
|
|
89
|
+
if (event.key === 'Enter' && event.shiftKey === true) {
|
|
90
|
+
editor.insertText('\n');
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
for (const hotkey in HOTKEYS) {
|
|
96
|
+
if (isHotkey(hotkey, event)) {
|
|
97
|
+
event.preventDefault();
|
|
98
|
+
const mark = HOTKEYS[hotkey];
|
|
99
|
+
toggleMark(editor, mark);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const onFocus = () => setIsFocused(true);
|
|
104
|
+
const onBlur = () => {
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
if (!editorRef.current || !editorRef.current.contains(document.activeElement)) {
|
|
107
|
+
setIsFocused(false);
|
|
108
|
+
}
|
|
109
|
+
}, 50);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Slate editor={editor} value={slateValue}>
|
|
114
|
+
<RootRef rootRef={editorRef}>
|
|
115
|
+
<EditorAndToolbar
|
|
116
|
+
{...editorProps}
|
|
117
|
+
editor={editor}
|
|
118
|
+
isFocused={isFocused}
|
|
119
|
+
onDone={() => {
|
|
120
|
+
setIsFocused(false);
|
|
121
|
+
editorProps.onDone(editor);
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
<Editable
|
|
125
|
+
renderElement={renderElement}
|
|
126
|
+
renderLeaf={renderLeaf}
|
|
127
|
+
placeholder="Enter some rich text…"
|
|
128
|
+
spellCheck
|
|
129
|
+
onKeyDown={onKeyDown}
|
|
130
|
+
onFocus={onFocus}
|
|
131
|
+
onBlur={onBlur}
|
|
132
|
+
/>
|
|
133
|
+
</EditorAndToolbar>
|
|
134
|
+
</RootRef>
|
|
135
|
+
</Slate>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const toggleBlock = (editor, format) => {
|
|
140
|
+
const isActive = isBlockActive(
|
|
141
|
+
editor,
|
|
142
|
+
format,
|
|
143
|
+
TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type'
|
|
144
|
+
);
|
|
145
|
+
const isList = LIST_TYPES.includes(format);
|
|
146
|
+
|
|
147
|
+
Transforms.unwrapNodes(editor, {
|
|
148
|
+
match: n =>
|
|
149
|
+
!Editor.isEditor(n) &&
|
|
150
|
+
SlateElement.isElement(n) &&
|
|
151
|
+
LIST_TYPES.includes(n.type) &&
|
|
152
|
+
!TEXT_ALIGN_TYPES.includes(format),
|
|
153
|
+
split: true
|
|
154
|
+
});
|
|
155
|
+
let newProperties;
|
|
156
|
+
if (TEXT_ALIGN_TYPES.includes(format)) {
|
|
157
|
+
newProperties = {
|
|
158
|
+
align: isActive ? undefined : format
|
|
159
|
+
};
|
|
160
|
+
} else {
|
|
161
|
+
newProperties = {
|
|
162
|
+
type: isActive ? 'paragraph' : isList ? 'list_item' : format
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
Transforms.setNodes(editor, newProperties);
|
|
166
|
+
|
|
167
|
+
if (!isActive && isList) {
|
|
168
|
+
const block = { type: format, children: [] };
|
|
169
|
+
Transforms.wrapNodes(editor, block);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const toggleMark = (editor, format) => {
|
|
174
|
+
const isActive = isMarkActive(editor, format);
|
|
175
|
+
|
|
176
|
+
if (isActive) {
|
|
177
|
+
Editor.removeMark(editor, format);
|
|
178
|
+
} else {
|
|
179
|
+
Editor.addMark(editor, format, true);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const isBlockActive = (editor, format, blockType = 'type') => {
|
|
184
|
+
const { selection } = editor;
|
|
185
|
+
if (!selection) return false;
|
|
186
|
+
|
|
187
|
+
const [match] = Array.from(
|
|
188
|
+
Editor.nodes(editor, {
|
|
189
|
+
at: Editor.unhangRange(editor, selection),
|
|
190
|
+
match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n[blockType] === format
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return !!match;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const isMarkActive = (editor, format) => {
|
|
198
|
+
const marks = Editor.marks(editor);
|
|
199
|
+
return marks ? marks[format] === true : false;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const Element = props => {
|
|
203
|
+
const editor = useSlateStatic();
|
|
204
|
+
const focused = useFocused();
|
|
205
|
+
const { attributes, children, element, plugins } = props;
|
|
206
|
+
const style = { textAlign: element.align };
|
|
207
|
+
|
|
208
|
+
const nodeProps = { ...attributes, ...props, node: { ...element }, children };
|
|
209
|
+
const pluginToRender = plugins.find(
|
|
210
|
+
plugin => typeof plugin.supports === 'function' && plugin.supports(element)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (pluginToRender) {
|
|
214
|
+
return pluginToRender.renderNode({ ...nodeProps, editor, focused });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
switch (element.type) {
|
|
218
|
+
case 'block-quote':
|
|
219
|
+
return (
|
|
220
|
+
<blockquote style={style} {...attributes}>
|
|
221
|
+
{children}
|
|
222
|
+
</blockquote>
|
|
223
|
+
);
|
|
224
|
+
case 'bulleted-list':
|
|
225
|
+
return (
|
|
226
|
+
<ul style={style} {...attributes}>
|
|
227
|
+
{children}
|
|
228
|
+
</ul>
|
|
229
|
+
);
|
|
230
|
+
case 'heading-one':
|
|
231
|
+
return (
|
|
232
|
+
<h1 style={style} {...attributes}>
|
|
233
|
+
{children}
|
|
234
|
+
</h1>
|
|
235
|
+
);
|
|
236
|
+
case 'heading-two':
|
|
237
|
+
return (
|
|
238
|
+
<h2 style={style} {...attributes}>
|
|
239
|
+
{children}
|
|
240
|
+
</h2>
|
|
241
|
+
);
|
|
242
|
+
case 'list-item':
|
|
243
|
+
return (
|
|
244
|
+
<li style={style} {...attributes}>
|
|
245
|
+
{children}
|
|
246
|
+
</li>
|
|
247
|
+
);
|
|
248
|
+
case 'numbered-list':
|
|
249
|
+
return (
|
|
250
|
+
<ol style={style} {...attributes}>
|
|
251
|
+
{children}
|
|
252
|
+
</ol>
|
|
253
|
+
);
|
|
254
|
+
default:
|
|
255
|
+
return (
|
|
256
|
+
<div
|
|
257
|
+
style={{
|
|
258
|
+
...style,
|
|
259
|
+
margin: 0
|
|
260
|
+
}}
|
|
261
|
+
{...attributes}
|
|
262
|
+
>
|
|
263
|
+
{children}
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const Leaf = ({ attributes, children, leaf }) => {
|
|
270
|
+
if (leaf.bold) {
|
|
271
|
+
children = <strong>{children}</strong>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (leaf.code) {
|
|
275
|
+
children = <code>{children}</code>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (leaf.italic) {
|
|
279
|
+
children = <em>{children}</em>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (leaf.underline) {
|
|
283
|
+
children = <u>{children}</u>;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (leaf.strikethrough) {
|
|
287
|
+
children = <del>{children}</del>;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return <span {...attributes}>{children}</span>;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const BlockButton = ({ format, icon }) => {
|
|
294
|
+
const editor = useSlate();
|
|
295
|
+
return (
|
|
296
|
+
<Button
|
|
297
|
+
active={isBlockActive(editor, format, TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type')}
|
|
298
|
+
onMouseDown={event => {
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
toggleBlock(editor, format);
|
|
301
|
+
}}
|
|
302
|
+
>
|
|
303
|
+
<Icon>{icon}</Icon>
|
|
304
|
+
</Button>
|
|
305
|
+
);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const MarkButton = ({ format, icon }) => {
|
|
309
|
+
const editor = useSlate();
|
|
310
|
+
return (
|
|
311
|
+
<Button
|
|
312
|
+
active={isMarkActive(editor, format)}
|
|
313
|
+
onMouseDown={event => {
|
|
314
|
+
event.preventDefault();
|
|
315
|
+
toggleMark(editor, format);
|
|
316
|
+
}}
|
|
317
|
+
>
|
|
318
|
+
<Icon>{icon}</Icon>
|
|
319
|
+
</Button>
|
|
320
|
+
);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// old-editable
|
|
324
|
+
|
|
19
325
|
export { ALL_PLUGINS, DEFAULT_PLUGINS, serialization };
|
|
20
326
|
|
|
21
327
|
const log = debug('editable-html:editor');
|
|
@@ -25,41 +331,44 @@ const defaultToolbarOpts = {
|
|
|
25
331
|
alignment: 'left',
|
|
26
332
|
alwaysVisible: false,
|
|
27
333
|
showDone: true,
|
|
28
|
-
doneOn: 'blur'
|
|
334
|
+
doneOn: 'blur'
|
|
29
335
|
};
|
|
30
336
|
|
|
31
337
|
const defaultResponseAreaProps = {
|
|
32
338
|
options: {},
|
|
33
339
|
respAreaToolbar: () => {},
|
|
34
|
-
onHandleAreaChange: () => {}
|
|
340
|
+
onHandleAreaChange: () => {}
|
|
35
341
|
};
|
|
36
342
|
|
|
37
343
|
const defaultLanguageCharactersProps = [];
|
|
38
344
|
|
|
39
|
-
const createToolbarOpts =
|
|
345
|
+
const createToolbarOpts = toolbarOpts => {
|
|
40
346
|
return {
|
|
41
347
|
...defaultToolbarOpts,
|
|
42
|
-
...toolbarOpts
|
|
43
|
-
error,
|
|
348
|
+
...toolbarOpts
|
|
44
349
|
};
|
|
45
350
|
};
|
|
46
351
|
|
|
47
|
-
export class
|
|
352
|
+
export class EditorComponent extends React.Component {
|
|
48
353
|
static propTypes = {
|
|
49
354
|
autoFocus: PropTypes.bool,
|
|
50
|
-
editorRef: PropTypes.func.isRequired,
|
|
51
355
|
onRef: PropTypes.func.isRequired,
|
|
52
356
|
onChange: PropTypes.func.isRequired,
|
|
357
|
+
onEditor: PropTypes.func,
|
|
53
358
|
onFocus: PropTypes.func,
|
|
54
359
|
onBlur: PropTypes.func,
|
|
55
360
|
onKeyDown: PropTypes.func,
|
|
56
|
-
|
|
57
|
-
|
|
361
|
+
value: PropTypes.arrayOf(
|
|
362
|
+
PropTypes.shape({
|
|
363
|
+
type: PropTypes.string,
|
|
364
|
+
children: PropTypes.array,
|
|
365
|
+
data: PropTypes.object
|
|
366
|
+
})
|
|
367
|
+
),
|
|
58
368
|
imageSupport: PropTypes.object,
|
|
59
|
-
disableImageAlignmentButtons: PropTypes.bool,
|
|
60
369
|
uploadSoundSupport: PropTypes.shape({
|
|
61
370
|
add: PropTypes.func,
|
|
62
|
-
delete: PropTypes.func
|
|
371
|
+
delete: PropTypes.func
|
|
63
372
|
}),
|
|
64
373
|
charactersLimit: PropTypes.number,
|
|
65
374
|
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
@@ -77,33 +386,40 @@ export class Editor extends React.Component {
|
|
|
77
386
|
pluginProps: PropTypes.any,
|
|
78
387
|
placeholder: PropTypes.string,
|
|
79
388
|
responseAreaProps: PropTypes.shape({
|
|
80
|
-
type: PropTypes.oneOf([
|
|
389
|
+
type: PropTypes.oneOf([
|
|
390
|
+
'explicit-constructed-response',
|
|
391
|
+
'inline-dropdown',
|
|
392
|
+
'drag-in-the-blank'
|
|
393
|
+
]),
|
|
81
394
|
options: PropTypes.object,
|
|
82
395
|
respAreaToolbar: PropTypes.func,
|
|
83
|
-
onHandleAreaChange: PropTypes.func
|
|
396
|
+
onHandleAreaChange: PropTypes.func
|
|
84
397
|
}),
|
|
85
398
|
languageCharactersProps: PropTypes.arrayOf(
|
|
86
399
|
PropTypes.shape({
|
|
87
400
|
language: PropTypes.string,
|
|
88
401
|
characterIcon: PropTypes.string,
|
|
89
|
-
characters: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))
|
|
90
|
-
})
|
|
402
|
+
characters: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))
|
|
403
|
+
})
|
|
91
404
|
),
|
|
92
405
|
toolbarOpts: PropTypes.shape({
|
|
93
406
|
position: PropTypes.oneOf(['bottom', 'top']),
|
|
94
407
|
alignment: PropTypes.oneOf(['left', 'right']),
|
|
95
408
|
alwaysVisible: PropTypes.bool,
|
|
96
409
|
showDone: PropTypes.bool,
|
|
97
|
-
doneOn: PropTypes.string
|
|
410
|
+
doneOn: PropTypes.string
|
|
98
411
|
}),
|
|
99
|
-
activePlugins: PropTypes.arrayOf(
|
|
100
|
-
const allValid = values.every(
|
|
412
|
+
activePlugins: PropTypes.arrayOf(values => {
|
|
413
|
+
const allValid = values.every(v => ALL_PLUGINS.includes(v));
|
|
101
414
|
|
|
102
|
-
return
|
|
415
|
+
return (
|
|
416
|
+
!allValid &&
|
|
417
|
+
new Error(`Invalid values: ${values}, values must be one of [${ALL_PLUGINS.join(',')}]`)
|
|
418
|
+
);
|
|
103
419
|
}),
|
|
104
420
|
className: PropTypes.string,
|
|
105
421
|
maxImageWidth: PropTypes.number,
|
|
106
|
-
maxImageHeight: PropTypes.number
|
|
422
|
+
maxImageHeight: PropTypes.number
|
|
107
423
|
};
|
|
108
424
|
|
|
109
425
|
static defaultProps = {
|
|
@@ -113,14 +429,14 @@ export class Editor extends React.Component {
|
|
|
113
429
|
onKeyDown: () => {},
|
|
114
430
|
toolbarOpts: defaultToolbarOpts,
|
|
115
431
|
responseAreaProps: defaultResponseAreaProps,
|
|
116
|
-
languageCharactersProps: defaultLanguageCharactersProps
|
|
432
|
+
languageCharactersProps: defaultLanguageCharactersProps
|
|
117
433
|
};
|
|
118
434
|
|
|
119
435
|
constructor(props) {
|
|
120
436
|
super(props);
|
|
121
437
|
this.state = {
|
|
122
438
|
value: props.value,
|
|
123
|
-
toolbarOpts: createToolbarOpts(props.toolbarOpts
|
|
439
|
+
toolbarOpts: createToolbarOpts(props.toolbarOpts)
|
|
124
440
|
};
|
|
125
441
|
|
|
126
442
|
this.onResize = () => {
|
|
@@ -130,31 +446,30 @@ export class Editor extends React.Component {
|
|
|
130
446
|
this.handlePlugins(this.props);
|
|
131
447
|
}
|
|
132
448
|
|
|
133
|
-
handlePlugins =
|
|
449
|
+
handlePlugins = props => {
|
|
134
450
|
const normalizedResponseAreaProps = {
|
|
135
451
|
...defaultResponseAreaProps,
|
|
136
|
-
...props.responseAreaProps
|
|
452
|
+
...props.responseAreaProps
|
|
137
453
|
};
|
|
138
454
|
|
|
139
455
|
this.plugins = buildPlugins(props.activePlugins, {
|
|
140
456
|
math: {
|
|
141
457
|
onClick: this.onMathClick,
|
|
142
458
|
onFocus: this.onPluginFocus,
|
|
143
|
-
onBlur: this.onPluginBlur
|
|
459
|
+
onBlur: this.onPluginBlur
|
|
144
460
|
},
|
|
145
461
|
image: {
|
|
146
|
-
disableImageAlignmentButtons: props.disableImageAlignmentButtons,
|
|
147
462
|
onDelete:
|
|
148
463
|
props.imageSupport &&
|
|
149
464
|
props.imageSupport.delete &&
|
|
150
465
|
((src, done) => {
|
|
151
|
-
props.imageSupport.delete(src,
|
|
466
|
+
props.imageSupport.delete(src, e => {
|
|
152
467
|
done(e, this.state.value);
|
|
153
468
|
});
|
|
154
469
|
}),
|
|
155
470
|
insertImageRequested:
|
|
156
471
|
props.imageSupport &&
|
|
157
|
-
(
|
|
472
|
+
(getHandler => {
|
|
158
473
|
/**
|
|
159
474
|
* The handler is the object through which the outer context
|
|
160
475
|
* communicates file upload events like: fileChosen, cancel, progress
|
|
@@ -165,7 +480,7 @@ export class Editor extends React.Component {
|
|
|
165
480
|
onFocus: this.onPluginFocus,
|
|
166
481
|
onBlur: this.onPluginBlur,
|
|
167
482
|
maxImageWidth: this.props.maxImageWidth,
|
|
168
|
-
maxImageHeight: this.props.maxImageHeight
|
|
483
|
+
maxImageHeight: this.props.maxImageHeight
|
|
169
484
|
},
|
|
170
485
|
toolbar: {
|
|
171
486
|
/**
|
|
@@ -174,22 +489,7 @@ export class Editor extends React.Component {
|
|
|
174
489
|
*/
|
|
175
490
|
disableScrollbar: !!props.disableScrollbar,
|
|
176
491
|
disableUnderline: props.disableUnderline,
|
|
177
|
-
autoWidth: props.autoWidthToolbar
|
|
178
|
-
onDone: () => {
|
|
179
|
-
const { nonEmpty } = props;
|
|
180
|
-
|
|
181
|
-
log('[onDone]');
|
|
182
|
-
this.setState({ toolbarInFocus: false, focusedNode: null });
|
|
183
|
-
this.editor.blur();
|
|
184
|
-
|
|
185
|
-
if (nonEmpty && this.state.value.startText?.text?.length === 0) {
|
|
186
|
-
this.resetValue(true).then(() => {
|
|
187
|
-
this.onEditingDone();
|
|
188
|
-
});
|
|
189
|
-
} else {
|
|
190
|
-
this.onEditingDone();
|
|
191
|
-
}
|
|
192
|
-
},
|
|
492
|
+
autoWidth: props.autoWidthToolbar
|
|
193
493
|
},
|
|
194
494
|
table: {
|
|
195
495
|
onFocus: () => {
|
|
@@ -199,7 +499,7 @@ export class Editor extends React.Component {
|
|
|
199
499
|
onBlur: () => {
|
|
200
500
|
log('[table:onBlur]...');
|
|
201
501
|
this.onPluginBlur();
|
|
202
|
-
}
|
|
502
|
+
}
|
|
203
503
|
},
|
|
204
504
|
responseArea: {
|
|
205
505
|
type: normalizedResponseAreaProps.type,
|
|
@@ -215,15 +515,14 @@ export class Editor extends React.Component {
|
|
|
215
515
|
onBlur: () => {
|
|
216
516
|
log('[table:onBlur]...');
|
|
217
517
|
this.onPluginBlur();
|
|
218
|
-
}
|
|
518
|
+
}
|
|
219
519
|
},
|
|
220
520
|
languageCharacters: props.languageCharactersProps,
|
|
221
521
|
media: {
|
|
222
522
|
focus: this.focus,
|
|
223
|
-
createChange: () => this.state.value.change(),
|
|
224
523
|
onChange: this.onChange,
|
|
225
|
-
uploadSoundSupport: props.uploadSoundSupport
|
|
226
|
-
}
|
|
524
|
+
uploadSoundSupport: props.uploadSoundSupport
|
|
525
|
+
}
|
|
227
526
|
});
|
|
228
527
|
};
|
|
229
528
|
|
|
@@ -236,9 +535,9 @@ export class Editor extends React.Component {
|
|
|
236
535
|
if (this.editor && this.props.autoFocus) {
|
|
237
536
|
Promise.resolve().then(() => {
|
|
238
537
|
if (this.editor) {
|
|
239
|
-
const editorDOM = document.querySelector(
|
|
240
|
-
|
|
241
|
-
|
|
538
|
+
const editorDOM = document.querySelector(
|
|
539
|
+
`[data-key="${this.editor.value.document.key}"]`
|
|
540
|
+
);
|
|
242
541
|
|
|
243
542
|
if (editorDOM) {
|
|
244
543
|
editorDOM.focus();
|
|
@@ -250,11 +549,11 @@ export class Editor extends React.Component {
|
|
|
250
549
|
|
|
251
550
|
componentWillReceiveProps(nextProps) {
|
|
252
551
|
const { toolbarOpts } = this.state;
|
|
253
|
-
const newToolbarOpts = createToolbarOpts(nextProps.toolbarOpts
|
|
552
|
+
const newToolbarOpts = createToolbarOpts(nextProps.toolbarOpts);
|
|
254
553
|
|
|
255
554
|
if (!isEqual(newToolbarOpts, toolbarOpts)) {
|
|
256
555
|
this.setState({
|
|
257
|
-
toolbarOpts: newToolbarOpts
|
|
556
|
+
toolbarOpts: newToolbarOpts
|
|
258
557
|
});
|
|
259
558
|
}
|
|
260
559
|
|
|
@@ -268,13 +567,13 @@ export class Editor extends React.Component {
|
|
|
268
567
|
// so we increase the width to at least 2px in order for the user to see it
|
|
269
568
|
const zeroWidthEls = document.querySelectorAll('[data-slate-zero-width="z"]');
|
|
270
569
|
|
|
271
|
-
Array.from(zeroWidthEls).forEach(
|
|
570
|
+
Array.from(zeroWidthEls).forEach(el => {
|
|
272
571
|
el.style.minWidth = '2px';
|
|
273
572
|
el.style.display = 'inline-block';
|
|
274
573
|
});
|
|
275
574
|
}
|
|
276
575
|
|
|
277
|
-
onPluginBlur =
|
|
576
|
+
onPluginBlur = e => {
|
|
278
577
|
log('[onPluginBlur]', e && e.relatedTarget);
|
|
279
578
|
const target = e && e.relatedTarget;
|
|
280
579
|
|
|
@@ -285,7 +584,7 @@ export class Editor extends React.Component {
|
|
|
285
584
|
});
|
|
286
585
|
};
|
|
287
586
|
|
|
288
|
-
onPluginFocus =
|
|
587
|
+
onPluginFocus = e => {
|
|
289
588
|
log('[onPluginFocus]', e && e.target);
|
|
290
589
|
const target = e && e.target;
|
|
291
590
|
if (target) {
|
|
@@ -300,16 +599,24 @@ export class Editor extends React.Component {
|
|
|
300
599
|
this.stashValue();
|
|
301
600
|
};
|
|
302
601
|
|
|
303
|
-
onMathClick =
|
|
304
|
-
this.editor.change((c) => c.collapseToStartOf(node));
|
|
602
|
+
onMathClick = node => {
|
|
305
603
|
this.setState({ selectedNode: node });
|
|
306
604
|
};
|
|
307
605
|
|
|
308
|
-
onEditingDone =
|
|
606
|
+
onEditingDone = editor => {
|
|
309
607
|
log('[onEditingDone]');
|
|
310
608
|
this.setState({ stashedValue: null, focusedNode: null });
|
|
311
609
|
log('[onEditingDone] value: ', this.state.value);
|
|
312
|
-
this.props.onChange(
|
|
610
|
+
this.props.onChange(editor, true);
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
onDone = editor => {
|
|
614
|
+
const { nonEmpty } = this.props;
|
|
615
|
+
|
|
616
|
+
log('[onDone]');
|
|
617
|
+
this.setState({ toolbarInFocus: false, focusedNode: null });
|
|
618
|
+
|
|
619
|
+
this.onEditingDone(editor);
|
|
313
620
|
};
|
|
314
621
|
|
|
315
622
|
/**
|
|
@@ -320,18 +627,14 @@ export class Editor extends React.Component {
|
|
|
320
627
|
}
|
|
321
628
|
|
|
322
629
|
// Allowing time for onChange to take effect if it is called
|
|
323
|
-
handleBlur =
|
|
630
|
+
handleBlur = resolve => {
|
|
324
631
|
const { nonEmpty } = this.props;
|
|
325
632
|
const {
|
|
326
|
-
toolbarOpts: { doneOn }
|
|
633
|
+
toolbarOpts: { doneOn }
|
|
327
634
|
} = this.state;
|
|
328
635
|
|
|
329
636
|
this.setState({ toolbarInFocus: false, focusedNode: null });
|
|
330
637
|
|
|
331
|
-
if (this.editor) {
|
|
332
|
-
this.editor.blur();
|
|
333
|
-
}
|
|
334
|
-
|
|
335
638
|
if (doneOn === 'blur') {
|
|
336
639
|
if (nonEmpty && this.state.value.startText?.text?.length === 0) {
|
|
337
640
|
this.resetValue(true).then(() => {
|
|
@@ -345,7 +648,7 @@ export class Editor extends React.Component {
|
|
|
345
648
|
}
|
|
346
649
|
};
|
|
347
650
|
|
|
348
|
-
onBlur =
|
|
651
|
+
onBlur = event => {
|
|
349
652
|
log('[onBlur]');
|
|
350
653
|
const target = event.relatedTarget;
|
|
351
654
|
|
|
@@ -353,16 +656,16 @@ export class Editor extends React.Component {
|
|
|
353
656
|
|
|
354
657
|
log('[onBlur] node: ', node);
|
|
355
658
|
|
|
356
|
-
return new Promise(
|
|
659
|
+
return new Promise(resolve => {
|
|
357
660
|
this.setState(
|
|
358
661
|
{ preBlurValue: this.state.value, focusedNode: !node ? null : node },
|
|
359
|
-
this.handleBlur.bind(this, resolve)
|
|
662
|
+
this.handleBlur.bind(this, resolve)
|
|
360
663
|
);
|
|
361
664
|
this.props.onBlur(event);
|
|
362
665
|
});
|
|
363
666
|
};
|
|
364
667
|
|
|
365
|
-
handleDomBlur =
|
|
668
|
+
handleDomBlur = e => {
|
|
366
669
|
const editorDOM = document.querySelector(`[data-key="${this.state.value.document.key}"]`);
|
|
367
670
|
|
|
368
671
|
setTimeout(() => {
|
|
@@ -372,10 +675,13 @@ export class Editor extends React.Component {
|
|
|
372
675
|
return;
|
|
373
676
|
}
|
|
374
677
|
|
|
375
|
-
const editorElement =
|
|
678
|
+
const editorElement =
|
|
679
|
+
!editorDOM || document.activeElement.closest(`[class*="${editorDOM.className}"]`);
|
|
376
680
|
const toolbarElement =
|
|
377
|
-
!this.toolbarRef ||
|
|
378
|
-
|
|
681
|
+
!this.toolbarRef ||
|
|
682
|
+
document.activeElement.closest(`[class*="${this.toolbarRef.className}"]`);
|
|
683
|
+
const isInCurrentComponent =
|
|
684
|
+
this.wrapperRef.contains(editorElement) || this.wrapperRef.contains(toolbarElement);
|
|
379
685
|
|
|
380
686
|
if (!isInCurrentComponent) {
|
|
381
687
|
editorDOM.removeEventListener('blur', this.handleDomBlur);
|
|
@@ -395,7 +701,7 @@ export class Editor extends React.Component {
|
|
|
395
701
|
* Note: The use of promises has been causing issues with MathQuill
|
|
396
702
|
* */
|
|
397
703
|
onFocus = () =>
|
|
398
|
-
new Promise(
|
|
704
|
+
new Promise(resolve => {
|
|
399
705
|
const editorDOM = document.querySelector(`[data-key="${this.state.value.document.key}"]`);
|
|
400
706
|
|
|
401
707
|
log('[onFocus]', document.activeElement);
|
|
@@ -443,7 +749,7 @@ export class Editor extends React.Component {
|
|
|
443
749
|
/**
|
|
444
750
|
* Reset the value if the user didn't click done.
|
|
445
751
|
*/
|
|
446
|
-
resetValue =
|
|
752
|
+
resetValue = force => {
|
|
447
753
|
const { value, focusedNode } = this.state;
|
|
448
754
|
|
|
449
755
|
const stopReset = this.plugins.reduce((s, p) => {
|
|
@@ -459,7 +765,7 @@ export class Editor extends React.Component {
|
|
|
459
765
|
const newValue = Value.fromJSON(this.state.stashedValue.toJSON());
|
|
460
766
|
|
|
461
767
|
log('newValue: ', newValue.document);
|
|
462
|
-
return new Promise(
|
|
768
|
+
return new Promise(resolve => {
|
|
463
769
|
setTimeout(() => {
|
|
464
770
|
this.setState({ value: newValue, stashedValue: null }, () => {
|
|
465
771
|
log('value now: ', this.state.value.document.toJSON());
|
|
@@ -472,16 +778,18 @@ export class Editor extends React.Component {
|
|
|
472
778
|
}
|
|
473
779
|
};
|
|
474
780
|
|
|
475
|
-
onChange = (
|
|
781
|
+
onChange = (editor, done) => {
|
|
476
782
|
log('[onChange]');
|
|
477
|
-
|
|
478
|
-
const { value } = change;
|
|
479
783
|
const { charactersLimit } = this.props;
|
|
784
|
+
const allText = Editor.string(editor, []);
|
|
480
785
|
|
|
481
|
-
if (
|
|
786
|
+
if (allText > charactersLimit) {
|
|
482
787
|
return;
|
|
483
788
|
}
|
|
484
789
|
|
|
790
|
+
const html = valueToHtml(editor);
|
|
791
|
+
const value = htmlToValue(html);
|
|
792
|
+
|
|
485
793
|
this.setState({ value }, () => {
|
|
486
794
|
log('[onChange], call done()');
|
|
487
795
|
|
|
@@ -500,15 +808,15 @@ export class Editor extends React.Component {
|
|
|
500
808
|
};
|
|
501
809
|
|
|
502
810
|
UNSAFE_componentWillReceiveProps(props) {
|
|
503
|
-
if (!props.value
|
|
811
|
+
if (!isEqual(props.value, this.props.value)) {
|
|
504
812
|
this.setState({
|
|
505
813
|
focus: false,
|
|
506
|
-
value: props.value
|
|
814
|
+
value: props.value
|
|
507
815
|
});
|
|
508
816
|
}
|
|
509
817
|
}
|
|
510
818
|
|
|
511
|
-
valueToSize =
|
|
819
|
+
valueToSize = v => {
|
|
512
820
|
if (!v) {
|
|
513
821
|
return;
|
|
514
822
|
}
|
|
@@ -537,11 +845,11 @@ export class Editor extends React.Component {
|
|
|
537
845
|
width: this.valueToSize(width),
|
|
538
846
|
height: this.valueToSize(height),
|
|
539
847
|
minHeight: this.valueToSize(minHeight),
|
|
540
|
-
maxHeight: this.valueToSize(maxHeight)
|
|
848
|
+
maxHeight: this.valueToSize(maxHeight)
|
|
541
849
|
};
|
|
542
850
|
}
|
|
543
851
|
|
|
544
|
-
validateNode =
|
|
852
|
+
validateNode = node => {
|
|
545
853
|
if (node.object !== 'block') return;
|
|
546
854
|
|
|
547
855
|
const last = node.nodes.last();
|
|
@@ -558,25 +866,6 @@ export class Editor extends React.Component {
|
|
|
558
866
|
return undefined;
|
|
559
867
|
};
|
|
560
868
|
|
|
561
|
-
changeData = (key, data) => {
|
|
562
|
-
log('[changeData]. .. ', key, data);
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* HACK ALERT: We should be calling setState here and storing the change data:
|
|
566
|
-
*
|
|
567
|
-
* <code>this.setState({changeData: { key, data}})</code>
|
|
568
|
-
* However this is causing issues with the Mathquill instance. The 'input' event stops firing on the element and no
|
|
569
|
-
* more changes get through. The issues seem to be related to the promises in onBlur/onFocus. But removing these
|
|
570
|
-
* brings it's own problems. A major clean up is planned for this component so I've decided to temporarily settle
|
|
571
|
-
* on this hack rather than spend more time on this.
|
|
572
|
-
*/
|
|
573
|
-
|
|
574
|
-
// Uncomment this line to see the bug described above.
|
|
575
|
-
// this.setState({changeData: {key, data}})
|
|
576
|
-
|
|
577
|
-
this.__TEMPORARY_CHANGE_DATA = { key, data };
|
|
578
|
-
};
|
|
579
|
-
|
|
580
869
|
focus = (pos, node) => {
|
|
581
870
|
const position = pos || 'end';
|
|
582
871
|
|
|
@@ -592,7 +881,10 @@ export class Editor extends React.Component {
|
|
|
592
881
|
const fragment = transfer.fragment;
|
|
593
882
|
const text = transfer.text;
|
|
594
883
|
|
|
595
|
-
if (
|
|
884
|
+
if (
|
|
885
|
+
file &&
|
|
886
|
+
(file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png')
|
|
887
|
+
) {
|
|
596
888
|
if (!this.props.imageSupport) {
|
|
597
889
|
return;
|
|
598
890
|
}
|
|
@@ -604,8 +896,8 @@ export class Editor extends React.Component {
|
|
|
604
896
|
isVoid: true,
|
|
605
897
|
data: {
|
|
606
898
|
loading: false,
|
|
607
|
-
src
|
|
608
|
-
}
|
|
899
|
+
src
|
|
900
|
+
}
|
|
609
901
|
});
|
|
610
902
|
|
|
611
903
|
if (dropContext) {
|
|
@@ -631,7 +923,7 @@ export class Editor extends React.Component {
|
|
|
631
923
|
return;
|
|
632
924
|
}
|
|
633
925
|
const {
|
|
634
|
-
value: { document, selection, startBlock }
|
|
926
|
+
value: { document, selection, startBlock }
|
|
635
927
|
} = change;
|
|
636
928
|
|
|
637
929
|
if (startBlock.isVoid) {
|
|
@@ -642,13 +934,13 @@ export class Editor extends React.Component {
|
|
|
642
934
|
const defaultMarks = document.getInsertMarksAtRange(selection);
|
|
643
935
|
const frag = Plain.deserialize(text, {
|
|
644
936
|
defaultBlock,
|
|
645
|
-
defaultMarks
|
|
937
|
+
defaultMarks
|
|
646
938
|
}).document;
|
|
647
939
|
change.insertFragment(frag);
|
|
648
940
|
}
|
|
649
941
|
};
|
|
650
942
|
|
|
651
|
-
renderPlaceholder =
|
|
943
|
+
renderPlaceholder = props => {
|
|
652
944
|
const { editor } = props;
|
|
653
945
|
const { document } = editor.value;
|
|
654
946
|
|
|
@@ -666,7 +958,7 @@ export class Editor extends React.Component {
|
|
|
666
958
|
whiteSpace: 'nowrap',
|
|
667
959
|
opacity: '0.33',
|
|
668
960
|
pointerEvents: 'none',
|
|
669
|
-
userSelect: 'none'
|
|
961
|
+
userSelect: 'none'
|
|
670
962
|
}}
|
|
671
963
|
>
|
|
672
964
|
{editor.props.placeholder}
|
|
@@ -683,7 +975,7 @@ export class Editor extends React.Component {
|
|
|
683
975
|
className,
|
|
684
976
|
placeholder,
|
|
685
977
|
pluginProps,
|
|
686
|
-
onKeyDown
|
|
978
|
+
onKeyDown
|
|
687
979
|
} = this.props;
|
|
688
980
|
|
|
689
981
|
const { value, focusedNode, toolbarOpts } = this.state;
|
|
@@ -693,22 +985,69 @@ export class Editor extends React.Component {
|
|
|
693
985
|
const names = classNames(
|
|
694
986
|
{
|
|
695
987
|
[classes.withBg]: highlightShape,
|
|
696
|
-
[classes.toolbarOnTop]: toolbarOpts.alwaysVisible && toolbarOpts.position === 'top'
|
|
988
|
+
[classes.toolbarOnTop]: toolbarOpts.alwaysVisible && toolbarOpts.position === 'top'
|
|
697
989
|
},
|
|
698
990
|
className,
|
|
991
|
+
classes.slateEditor
|
|
699
992
|
);
|
|
700
993
|
|
|
701
994
|
return (
|
|
702
|
-
<div
|
|
995
|
+
<div
|
|
996
|
+
ref={ref => (this.wrapperRef = ref)}
|
|
997
|
+
style={{ width: sizeStyle.width }}
|
|
998
|
+
className={names}
|
|
999
|
+
>
|
|
703
1000
|
<SlateEditor
|
|
704
1001
|
plugins={this.plugins}
|
|
705
|
-
|
|
1002
|
+
toolbarRef={r => {
|
|
706
1003
|
if (r) {
|
|
707
|
-
this.
|
|
1004
|
+
this.toolbarRef = r;
|
|
708
1005
|
}
|
|
709
1006
|
}}
|
|
710
|
-
|
|
711
|
-
|
|
1007
|
+
onEditor={this.props.onEditor}
|
|
1008
|
+
value={value}
|
|
1009
|
+
focus={this.focus}
|
|
1010
|
+
onKeyDown={onKeyDown}
|
|
1011
|
+
onChange={this.onChange}
|
|
1012
|
+
getFocusedValue={this.getFocusedValue}
|
|
1013
|
+
onBlur={this.onBlur}
|
|
1014
|
+
onDrop={(event, editor) => this.onDropPaste(event, editor, true)}
|
|
1015
|
+
onPaste={(event, editor) => this.onDropPaste(event, editor)}
|
|
1016
|
+
onFocus={this.onFocus}
|
|
1017
|
+
onEditingDone={this.onEditingDone}
|
|
1018
|
+
onDone={this.onDone}
|
|
1019
|
+
focusedNode={focusedNode}
|
|
1020
|
+
normalize={this.normalize}
|
|
1021
|
+
readOnly={disabled}
|
|
1022
|
+
spellCheck={spellCheck}
|
|
1023
|
+
className={classNames(
|
|
1024
|
+
{
|
|
1025
|
+
[classes.noPadding]: toolbarOpts && toolbarOpts.noBorder
|
|
1026
|
+
},
|
|
1027
|
+
classes.slateEditor
|
|
1028
|
+
)}
|
|
1029
|
+
style={{
|
|
1030
|
+
minHeight: sizeStyle.minHeight,
|
|
1031
|
+
height: sizeStyle.height,
|
|
1032
|
+
maxHeight: sizeStyle.maxHeight
|
|
1033
|
+
}}
|
|
1034
|
+
pluginProps={pluginProps}
|
|
1035
|
+
toolbarOpts={toolbarOpts}
|
|
1036
|
+
placeholder={placeholder}
|
|
1037
|
+
renderPlaceholder={this.renderPlaceholder}
|
|
1038
|
+
/>
|
|
1039
|
+
</div>
|
|
1040
|
+
);
|
|
1041
|
+
|
|
1042
|
+
return (
|
|
1043
|
+
<div
|
|
1044
|
+
ref={ref => (this.wrapperRef = ref)}
|
|
1045
|
+
style={{ width: sizeStyle.width }}
|
|
1046
|
+
className={names}
|
|
1047
|
+
>
|
|
1048
|
+
<OldSlateEditor
|
|
1049
|
+
plugins={this.plugins}
|
|
1050
|
+
toolbarRef={r => {
|
|
712
1051
|
if (r) {
|
|
713
1052
|
this.toolbarRef = r;
|
|
714
1053
|
}
|
|
@@ -727,23 +1066,21 @@ export class Editor extends React.Component {
|
|
|
727
1066
|
normalize={this.normalize}
|
|
728
1067
|
readOnly={disabled}
|
|
729
1068
|
spellCheck={spellCheck}
|
|
730
|
-
autoCorrect={spellCheck}
|
|
731
1069
|
className={classNames(
|
|
732
1070
|
{
|
|
733
|
-
[classes.noPadding]: toolbarOpts && toolbarOpts.noBorder
|
|
1071
|
+
[classes.noPadding]: toolbarOpts && toolbarOpts.noBorder
|
|
734
1072
|
},
|
|
735
|
-
classes.slateEditor
|
|
1073
|
+
classes.slateEditor
|
|
736
1074
|
)}
|
|
737
1075
|
style={{
|
|
738
1076
|
minHeight: sizeStyle.minHeight,
|
|
739
1077
|
height: sizeStyle.height,
|
|
740
|
-
maxHeight: sizeStyle.maxHeight
|
|
1078
|
+
maxHeight: sizeStyle.maxHeight
|
|
741
1079
|
}}
|
|
742
1080
|
pluginProps={pluginProps}
|
|
743
1081
|
toolbarOpts={toolbarOpts}
|
|
744
1082
|
placeholder={placeholder}
|
|
745
1083
|
renderPlaceholder={this.renderPlaceholder}
|
|
746
|
-
onDataChange={this.changeData}
|
|
747
1084
|
/>
|
|
748
1085
|
</div>
|
|
749
1086
|
);
|
|
@@ -753,7 +1090,7 @@ export class Editor extends React.Component {
|
|
|
753
1090
|
// TODO color - hardcoded gray background and keypad colors will need to change too
|
|
754
1091
|
const styles = {
|
|
755
1092
|
withBg: {
|
|
756
|
-
backgroundColor: 'rgba(0,0,0,0.06)'
|
|
1093
|
+
backgroundColor: 'rgba(0,0,0,0.06)'
|
|
757
1094
|
},
|
|
758
1095
|
slateEditor: {
|
|
759
1096
|
fontFamily: 'Roboto, sans-serif',
|
|
@@ -763,10 +1100,10 @@ const styles = {
|
|
|
763
1100
|
width: '100%',
|
|
764
1101
|
borderCollapse: 'collapse',
|
|
765
1102
|
color: color.text(),
|
|
766
|
-
backgroundColor: color.background()
|
|
1103
|
+
backgroundColor: color.background()
|
|
767
1104
|
},
|
|
768
1105
|
'& table:not([border="1"]) tr': {
|
|
769
|
-
borderTop: '1px solid #dfe2e5'
|
|
1106
|
+
borderTop: '1px solid #dfe2e5'
|
|
770
1107
|
// TODO perhaps secondary color for background, for now disable
|
|
771
1108
|
// '&:nth-child(2n)': {
|
|
772
1109
|
// backgroundColor: '#f6f8fa'
|
|
@@ -774,18 +1111,18 @@ const styles = {
|
|
|
774
1111
|
},
|
|
775
1112
|
'& td, th': {
|
|
776
1113
|
padding: '.6em 1em',
|
|
777
|
-
textAlign: 'center'
|
|
1114
|
+
textAlign: 'center'
|
|
778
1115
|
},
|
|
779
1116
|
'& table:not([border="1"]) td, th': {
|
|
780
|
-
border: '1px solid #dfe2e5'
|
|
781
|
-
}
|
|
1117
|
+
border: '1px solid #dfe2e5'
|
|
1118
|
+
}
|
|
782
1119
|
},
|
|
783
1120
|
toolbarOnTop: {
|
|
784
|
-
marginTop: '45px'
|
|
1121
|
+
marginTop: '45px'
|
|
785
1122
|
},
|
|
786
1123
|
noPadding: {
|
|
787
|
-
padding: '0 !important'
|
|
788
|
-
}
|
|
1124
|
+
padding: '0 !important'
|
|
1125
|
+
}
|
|
789
1126
|
};
|
|
790
1127
|
|
|
791
|
-
export default withStyles(styles)(
|
|
1128
|
+
export default withStyles(styles)(EditorComponent);
|