@pie-lib/editable-html 7.17.4-next.59 → 7.17.4-next.592
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.json +135 -0
- package/CHANGELOG.md +421 -0
- package/lib/editor.js +392 -172
- package/lib/editor.js.map +1 -1
- package/lib/index.js +66 -53
- package/lib/index.js.map +1 -1
- package/lib/parse-html.js.map +1 -1
- package/lib/plugins/characters/custom-popper.js +73 -0
- package/lib/plugins/characters/custom-popper.js.map +1 -0
- package/lib/plugins/characters/index.js +285 -0
- package/lib/plugins/characters/index.js.map +1 -0
- package/lib/plugins/characters/utils.js +381 -0
- package/lib/plugins/characters/utils.js.map +1 -0
- package/lib/plugins/image/alt-dialog.js +119 -0
- package/lib/plugins/image/alt-dialog.js.map +1 -0
- package/lib/plugins/image/component.js +253 -77
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +95 -61
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +62 -20
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/image/insert-image-handler.js +9 -15
- package/lib/plugins/image/insert-image-handler.js.map +1 -1
- package/lib/plugins/index.js +20 -12
- package/lib/plugins/index.js.map +1 -1
- package/lib/plugins/list/index.js +82 -14
- package/lib/plugins/list/index.js.map +1 -1
- package/lib/plugins/math/index.js +50 -55
- package/lib/plugins/math/index.js.map +1 -1
- package/lib/plugins/media/index.js +71 -27
- package/lib/plugins/media/index.js.map +1 -1
- package/lib/plugins/media/media-dialog.js +248 -72
- package/lib/plugins/media/media-dialog.js.map +1 -1
- package/lib/plugins/media/media-toolbar.js +24 -30
- package/lib/plugins/media/media-toolbar.js.map +1 -1
- package/lib/plugins/media/media-wrapper.js +28 -35
- package/lib/plugins/media/media-wrapper.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +68 -46
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +12 -12
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +10 -9
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
- package/lib/plugins/respArea/icons/index.js +11 -11
- package/lib/plugins/respArea/icons/index.js.map +1 -1
- package/lib/plugins/respArea/index.js +58 -42
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +8 -8
- package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
- package/lib/plugins/respArea/utils.js +5 -5
- package/lib/plugins/respArea/utils.js.map +1 -1
- package/lib/plugins/table/icons/index.js +12 -12
- package/lib/plugins/table/icons/index.js.map +1 -1
- package/lib/plugins/table/index.js +83 -27
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/table-toolbar.js +41 -50
- package/lib/plugins/table/table-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/default-toolbar.js +19 -13
- package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/done-button.js +5 -5
- package/lib/plugins/toolbar/done-button.js.map +1 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +62 -45
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/index.js +6 -5
- package/lib/plugins/toolbar/index.js.map +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +49 -52
- package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
- package/lib/plugins/toolbar/toolbar.js +64 -62
- package/lib/plugins/toolbar/toolbar.js.map +1 -1
- package/lib/plugins/utils.js +1 -1
- package/lib/plugins/utils.js.map +1 -1
- package/lib/serialization.js +32 -9
- package/lib/serialization.js.map +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +7 -6
- package/src/editor.jsx +226 -26
- package/src/index.jsx +22 -5
- package/src/plugins/characters/custom-popper.js +48 -0
- package/src/plugins/characters/index.jsx +268 -0
- package/src/plugins/characters/utils.js +447 -0
- package/src/plugins/image/alt-dialog.jsx +69 -0
- package/src/plugins/image/component.jsx +204 -21
- package/src/plugins/image/image-toolbar.jsx +68 -22
- package/src/plugins/image/index.jsx +47 -9
- package/src/plugins/index.jsx +4 -1
- package/src/plugins/list/index.jsx +67 -5
- package/src/plugins/math/index.jsx +31 -37
- package/src/plugins/media/index.jsx +49 -6
- package/src/plugins/media/media-dialog.js +261 -89
- package/src/plugins/respArea/drag-in-the-blank/choice.jsx +28 -1
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +3 -3
- package/src/plugins/respArea/index.jsx +50 -31
- package/src/plugins/table/index.jsx +63 -14
- package/src/plugins/toolbar/default-toolbar.jsx +20 -2
- package/src/plugins/toolbar/editor-and-toolbar.jsx +50 -11
- package/src/plugins/toolbar/index.jsx +1 -0
- package/src/plugins/toolbar/toolbar-buttons.jsx +13 -2
- package/src/plugins/toolbar/toolbar.jsx +18 -3
- package/src/serialization.jsx +19 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import EditTable from 'slate-edit-table';
|
|
3
|
-
import { Block
|
|
3
|
+
import { Block } from 'slate';
|
|
4
4
|
import debug from 'debug';
|
|
5
5
|
import GridOn from '@material-ui/icons/GridOn';
|
|
6
6
|
import TableToolbar from './table-toolbar';
|
|
@@ -78,6 +78,22 @@ TableCell.propTypes = {
|
|
|
78
78
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
+
export const moveFocusToBeginningOfTable = change => {
|
|
82
|
+
const addedTable = change.value.document.findDescendant(
|
|
83
|
+
d => !!d.data && !!d.data.get('newTable')
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (!addedTable) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
change.collapseToStartOf(addedTable);
|
|
91
|
+
|
|
92
|
+
const update = addedTable.data.remove('newTable');
|
|
93
|
+
|
|
94
|
+
change.setNodeByKey(addedTable.key, { data: update });
|
|
95
|
+
};
|
|
96
|
+
|
|
81
97
|
export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
82
98
|
const core = EditTable({
|
|
83
99
|
typeContent: 'div'
|
|
@@ -117,12 +133,32 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
117
133
|
return ancestors.findLast(p => p.type === 'table');
|
|
118
134
|
};
|
|
119
135
|
|
|
136
|
+
core.utils.createTableWithOptions = (row, columns, extra) => {
|
|
137
|
+
const createdTable = core.utils.createTable(row, columns);
|
|
138
|
+
const newTable = Block.create({
|
|
139
|
+
...createdTable.toJSON(),
|
|
140
|
+
...extra
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return newTable;
|
|
144
|
+
};
|
|
145
|
+
|
|
120
146
|
core.toolbar = {
|
|
121
147
|
icon: <GridOn />,
|
|
122
148
|
onClick: (value, onChange) => {
|
|
123
149
|
log('insert table');
|
|
124
|
-
const
|
|
125
|
-
|
|
150
|
+
const change = value.change();
|
|
151
|
+
const newTable = core.utils.createTableWithOptions(2, 2, {
|
|
152
|
+
data: {
|
|
153
|
+
border: '1',
|
|
154
|
+
newTable: true
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
change.insertBlock(newTable);
|
|
159
|
+
|
|
160
|
+
moveFocusToBeginningOfTable(change);
|
|
161
|
+
onChange(change);
|
|
126
162
|
},
|
|
127
163
|
supports: (node, value) =>
|
|
128
164
|
node && node.object === 'block' && core.utils.isSelectionInTable(value),
|
|
@@ -132,7 +168,7 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
132
168
|
customToolbar: (node, value, onToolbarDone) => {
|
|
133
169
|
log('[customToolbar] node.data: ', node.data);
|
|
134
170
|
|
|
135
|
-
const tableBlock = core.utils.getTableBlock(value.document, node
|
|
171
|
+
const tableBlock = core.utils.getTableBlock(value.document, node?.key);
|
|
136
172
|
log('[customToolbar] tableBlock: ', tableBlock);
|
|
137
173
|
|
|
138
174
|
const hasBorder = () =>
|
|
@@ -215,9 +251,16 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
215
251
|
return;
|
|
216
252
|
}
|
|
217
253
|
|
|
254
|
+
const tableAdded = node.findDescendant(d => d.data && d.data.get('newTable'));
|
|
255
|
+
|
|
256
|
+
if (!tableAdded) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const nodeToSearch = node.getParent(tableAdded.key) || node;
|
|
218
261
|
let shouldAddTextAfterNode = false;
|
|
219
|
-
const indexToNotHaveTableOn =
|
|
220
|
-
const indexOfLastTable =
|
|
262
|
+
const indexToNotHaveTableOn = nodeToSearch.nodes.size - 1;
|
|
263
|
+
const indexOfLastTable = nodeToSearch.nodes.findLastIndex(d => d.type === 'table');
|
|
221
264
|
|
|
222
265
|
// if the last table in the document is of type table, we need to do the change
|
|
223
266
|
if (indexOfLastTable === indexToNotHaveTableOn) {
|
|
@@ -228,15 +271,13 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
228
271
|
return;
|
|
229
272
|
}
|
|
230
273
|
|
|
231
|
-
const tableNode = node.nodes.get(indexOfLastTable);
|
|
232
|
-
|
|
233
274
|
return change => {
|
|
234
275
|
if (shouldAddTextAfterNode) {
|
|
235
|
-
const tableJSON =
|
|
276
|
+
const tableJSON = tableAdded.toJSON();
|
|
236
277
|
|
|
237
278
|
// we remove the table node because otherwise we can't add the empty block after it
|
|
238
279
|
// we need a block that contains text in order to do it
|
|
239
|
-
change.removeNodeByKey(
|
|
280
|
+
change.removeNodeByKey(tableAdded.key);
|
|
240
281
|
|
|
241
282
|
const newBlock = Block.create({
|
|
242
283
|
object: 'block',
|
|
@@ -256,12 +297,20 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
256
297
|
if (prevText) {
|
|
257
298
|
// we move focus to the previous text
|
|
258
299
|
change
|
|
259
|
-
.moveFocusTo(prevText.key, prevText.text
|
|
260
|
-
.moveAnchorTo(prevText.key, prevText.text
|
|
300
|
+
.moveFocusTo(prevText.key, prevText.text?.length)
|
|
301
|
+
.moveAnchorTo(prevText.key, prevText.text?.length);
|
|
261
302
|
}
|
|
262
303
|
|
|
263
304
|
// we insert the table block between the first block with text and the last block with text
|
|
264
|
-
change.insertBlock(
|
|
305
|
+
change.insertBlock({
|
|
306
|
+
...tableJSON,
|
|
307
|
+
data: {
|
|
308
|
+
...tableJSON.data,
|
|
309
|
+
newTable: true
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
moveFocusToBeginningOfTable(change);
|
|
265
314
|
});
|
|
266
315
|
}
|
|
267
316
|
};
|
|
@@ -282,7 +331,7 @@ export const parseStyleString = s => {
|
|
|
282
331
|
return result;
|
|
283
332
|
};
|
|
284
333
|
|
|
285
|
-
export const reactAttributes = o => toStyleObject(o, { camelize: true });
|
|
334
|
+
export const reactAttributes = o => toStyleObject(o, { camelize: true, addUnits: false });
|
|
286
335
|
|
|
287
336
|
const attributesToMap = el => (acc, attribute) => {
|
|
288
337
|
const value = el.getAttribute(attribute);
|
|
@@ -14,26 +14,33 @@ const log = debug('@pie-lib:editable-html:plugins:toolbar');
|
|
|
14
14
|
export const ToolbarButton = props => {
|
|
15
15
|
const onToggle = () => {
|
|
16
16
|
const c = props.onToggle(props.value.change(), props);
|
|
17
|
+
|
|
17
18
|
props.onChange(c);
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
if (props.isMark) {
|
|
21
22
|
const isActive = hasMark(props.value, props.type);
|
|
23
|
+
|
|
22
24
|
log('[ToolbarButton] mark:isActive: ', isActive);
|
|
25
|
+
|
|
23
26
|
return (
|
|
24
27
|
<MarkButton active={isActive} label={props.type} onToggle={onToggle} mark={props.type}>
|
|
25
28
|
{props.icon}
|
|
26
29
|
</MarkButton>
|
|
27
30
|
);
|
|
28
31
|
} else {
|
|
32
|
+
const { disabled } = props;
|
|
29
33
|
const isActive = props.isActive
|
|
30
34
|
? props.isActive(props.value, props.type)
|
|
31
35
|
: hasBlock(props.value, props.type);
|
|
36
|
+
|
|
32
37
|
log('[ToolbarButton] block:isActive: ', isActive);
|
|
38
|
+
|
|
33
39
|
return (
|
|
34
40
|
<Button
|
|
35
41
|
active={isActive}
|
|
36
|
-
|
|
42
|
+
disabled={disabled}
|
|
43
|
+
onClick={() => props.onClick(props.value, props.onChange, props.getFocusedValue)}
|
|
37
44
|
extraStyles={props.buttonStyles}
|
|
38
45
|
>
|
|
39
46
|
{props.icon}
|
|
@@ -44,6 +51,7 @@ export const ToolbarButton = props => {
|
|
|
44
51
|
|
|
45
52
|
const isActiveToolbarPlugin = props => plugin => {
|
|
46
53
|
const isDisabled = (props[plugin.name] || {}).disabled;
|
|
54
|
+
|
|
47
55
|
return plugin && plugin.toolbar && !isDisabled;
|
|
48
56
|
};
|
|
49
57
|
|
|
@@ -52,6 +60,7 @@ export const DefaultToolbar = ({
|
|
|
52
60
|
pluginProps,
|
|
53
61
|
value,
|
|
54
62
|
onChange,
|
|
63
|
+
getFocusedValue,
|
|
55
64
|
onDone,
|
|
56
65
|
classes,
|
|
57
66
|
showDone,
|
|
@@ -63,7 +72,15 @@ export const DefaultToolbar = ({
|
|
|
63
72
|
<div className={classes.defaultToolbar}>
|
|
64
73
|
<div className={classes.buttonsContainer}>
|
|
65
74
|
{filtered.map((p, index) => {
|
|
66
|
-
return
|
|
75
|
+
return (
|
|
76
|
+
<ToolbarButton
|
|
77
|
+
{...p}
|
|
78
|
+
key={index}
|
|
79
|
+
value={value}
|
|
80
|
+
onChange={onChange}
|
|
81
|
+
getFocusedValue={getFocusedValue}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
67
84
|
})}
|
|
68
85
|
</div>
|
|
69
86
|
{showDone && !deletable && <DoneButton onClick={onDone} />}
|
|
@@ -77,6 +94,7 @@ DefaultToolbar.propTypes = {
|
|
|
77
94
|
pluginProps: PropTypes.object,
|
|
78
95
|
value: SlatePropTypes.value.isRequired,
|
|
79
96
|
onChange: PropTypes.func.isRequired,
|
|
97
|
+
getFocusedValue: PropTypes.func.isRequired,
|
|
80
98
|
onDone: PropTypes.func.isRequired,
|
|
81
99
|
showDone: PropTypes.bool,
|
|
82
100
|
addArea: PropTypes.bool,
|
|
@@ -17,18 +17,21 @@ export class EditorAndToolbar extends React.Component {
|
|
|
17
17
|
value: SlatePropTypes.value.isRequired,
|
|
18
18
|
plugins: PropTypes.array.isRequired,
|
|
19
19
|
onChange: PropTypes.func.isRequired,
|
|
20
|
+
getFocusedValue: PropTypes.func.isRequired,
|
|
20
21
|
onDone: PropTypes.func.isRequired,
|
|
21
22
|
onDataChange: PropTypes.func,
|
|
22
23
|
toolbarRef: PropTypes.func,
|
|
23
24
|
focusedNode: SlatePropTypes.node,
|
|
24
25
|
readOnly: PropTypes.bool,
|
|
26
|
+
disableScrollbar: PropTypes.bool,
|
|
25
27
|
disableUnderline: PropTypes.bool,
|
|
26
28
|
autoWidth: PropTypes.bool,
|
|
27
29
|
classes: PropTypes.object.isRequired,
|
|
28
30
|
pluginProps: PropTypes.object,
|
|
29
31
|
toolbarOpts: PropTypes.shape({
|
|
30
32
|
position: PropTypes.oneOf(['bottom', 'top']),
|
|
31
|
-
alwaysVisible: PropTypes.bool
|
|
33
|
+
alwaysVisible: PropTypes.bool,
|
|
34
|
+
error: PropTypes.string
|
|
32
35
|
})
|
|
33
36
|
};
|
|
34
37
|
|
|
@@ -48,10 +51,12 @@ export class EditorAndToolbar extends React.Component {
|
|
|
48
51
|
value,
|
|
49
52
|
plugins,
|
|
50
53
|
onChange,
|
|
54
|
+
getFocusedValue,
|
|
51
55
|
onDone,
|
|
52
56
|
focusedNode,
|
|
53
57
|
autoWidth,
|
|
54
58
|
readOnly,
|
|
59
|
+
disableScrollbar,
|
|
55
60
|
disableUnderline,
|
|
56
61
|
pluginProps,
|
|
57
62
|
toolbarOpts,
|
|
@@ -60,12 +65,12 @@ export class EditorAndToolbar extends React.Component {
|
|
|
60
65
|
} = this.props;
|
|
61
66
|
|
|
62
67
|
const inFocus = value.isFocused || (focusedNode !== null && focusedNode !== undefined);
|
|
63
|
-
const holderNames = classNames(
|
|
64
|
-
classes.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
68
|
+
const holderNames = classNames(classes.editorHolder, {
|
|
69
|
+
[classes.editorInFocus]: inFocus,
|
|
70
|
+
[classes.readOnly]: readOnly,
|
|
71
|
+
[classes.disabledUnderline]: disableUnderline,
|
|
72
|
+
[classes.disabledScrollbar]: disableScrollbar
|
|
73
|
+
});
|
|
69
74
|
let clonedChildren = children;
|
|
70
75
|
|
|
71
76
|
if (typeof children !== 'string') {
|
|
@@ -84,9 +89,26 @@ export class EditorAndToolbar extends React.Component {
|
|
|
84
89
|
);
|
|
85
90
|
|
|
86
91
|
return (
|
|
87
|
-
<div
|
|
92
|
+
<div
|
|
93
|
+
className={classNames(
|
|
94
|
+
{
|
|
95
|
+
[classes.noBorder]: toolbarOpts && toolbarOpts.noBorder,
|
|
96
|
+
[classes.error]: toolbarOpts && toolbarOpts.error
|
|
97
|
+
},
|
|
98
|
+
classes.root
|
|
99
|
+
)}
|
|
100
|
+
>
|
|
88
101
|
<div className={holderNames}>
|
|
89
|
-
<div
|
|
102
|
+
<div
|
|
103
|
+
className={classNames(
|
|
104
|
+
{
|
|
105
|
+
[classes.noPadding]: toolbarOpts && toolbarOpts.noBorder
|
|
106
|
+
},
|
|
107
|
+
classes.children
|
|
108
|
+
)}
|
|
109
|
+
>
|
|
110
|
+
{clonedChildren}
|
|
111
|
+
</div>
|
|
90
112
|
</div>
|
|
91
113
|
<Toolbar
|
|
92
114
|
autoWidth={autoWidth}
|
|
@@ -95,6 +117,7 @@ export class EditorAndToolbar extends React.Component {
|
|
|
95
117
|
value={value}
|
|
96
118
|
isFocused={inFocus}
|
|
97
119
|
onChange={onChange}
|
|
120
|
+
getFocusedValue={getFocusedValue}
|
|
98
121
|
onDone={onDone}
|
|
99
122
|
onDataChange={onDataChange}
|
|
100
123
|
toolbarRef={toolbarRef}
|
|
@@ -117,7 +140,8 @@ const style = {
|
|
|
117
140
|
wordBreak: 'break-word',
|
|
118
141
|
overflow: 'visible',
|
|
119
142
|
maxHeight: '500px',
|
|
120
|
-
|
|
143
|
+
// needed in order to be able to put the focus before a void element when it is the first one in the editor
|
|
144
|
+
padding: '5px'
|
|
121
145
|
}
|
|
122
146
|
},
|
|
123
147
|
children: {
|
|
@@ -175,7 +199,13 @@ const style = {
|
|
|
175
199
|
display: 'none'
|
|
176
200
|
}
|
|
177
201
|
},
|
|
178
|
-
|
|
202
|
+
disabledScrollbar: {
|
|
203
|
+
'&::-webkit-scrollbar': {
|
|
204
|
+
display: 'none'
|
|
205
|
+
},
|
|
206
|
+
scrollbarWidth: 'none',
|
|
207
|
+
'-ms-overflow-style': 'none'
|
|
208
|
+
},
|
|
179
209
|
readOnly: {
|
|
180
210
|
'&::before': {
|
|
181
211
|
background: 'transparent',
|
|
@@ -214,6 +244,15 @@ const style = {
|
|
|
214
244
|
backgroundColor: primary
|
|
215
245
|
}
|
|
216
246
|
}
|
|
247
|
+
},
|
|
248
|
+
error: {
|
|
249
|
+
border: '2px solid red'
|
|
250
|
+
},
|
|
251
|
+
noBorder: {
|
|
252
|
+
border: 'none'
|
|
253
|
+
},
|
|
254
|
+
noPadding: {
|
|
255
|
+
padding: 0
|
|
217
256
|
}
|
|
218
257
|
};
|
|
219
258
|
|
|
@@ -15,6 +15,13 @@ const styles = () => ({
|
|
|
15
15
|
},
|
|
16
16
|
active: {
|
|
17
17
|
color: 'black'
|
|
18
|
+
},
|
|
19
|
+
disabled: {
|
|
20
|
+
opacity: 0.7,
|
|
21
|
+
cursor: 'not-allowed',
|
|
22
|
+
'& :hover': {
|
|
23
|
+
color: 'grey'
|
|
24
|
+
}
|
|
18
25
|
}
|
|
19
26
|
});
|
|
20
27
|
|
|
@@ -26,6 +33,7 @@ export class RawButton extends React.Component {
|
|
|
26
33
|
classes: PropTypes.object.isRequired,
|
|
27
34
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
28
35
|
active: PropTypes.bool,
|
|
36
|
+
disabled: PropTypes.bool,
|
|
29
37
|
extraStyles: PropTypes.object
|
|
30
38
|
};
|
|
31
39
|
|
|
@@ -41,8 +49,11 @@ export class RawButton extends React.Component {
|
|
|
41
49
|
};
|
|
42
50
|
|
|
43
51
|
render() {
|
|
44
|
-
const { active, classes, children, extraStyles } = this.props;
|
|
45
|
-
const names = classNames(classes.button,
|
|
52
|
+
const { active, classes, children, disabled, extraStyles } = this.props;
|
|
53
|
+
const names = classNames(classes.button, {
|
|
54
|
+
[classes.active]: active,
|
|
55
|
+
[classes.disabled]: disabled
|
|
56
|
+
});
|
|
46
57
|
|
|
47
58
|
return (
|
|
48
59
|
<div style={extraStyles} className={names} onMouseDown={this.onClick}>
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Change } from 'slate';
|
|
2
3
|
import Delete from '@material-ui/icons/Delete';
|
|
3
4
|
import IconButton from '@material-ui/core/IconButton';
|
|
4
5
|
import PropTypes from 'prop-types';
|
|
5
|
-
import React from 'react';
|
|
6
6
|
import classNames from 'classnames';
|
|
7
7
|
import debug from 'debug';
|
|
8
8
|
import SlatePropTypes from 'slate-prop-types';
|
|
9
9
|
import debounce from 'lodash/debounce';
|
|
10
10
|
|
|
11
|
+
import { DoneButton } from './done-button';
|
|
12
|
+
|
|
11
13
|
import { findSingleNode, findParentNode } from '../utils';
|
|
12
14
|
import { withStyles } from '@material-ui/core/styles';
|
|
13
15
|
import DefaultToolbar from './default-toolbar';
|
|
16
|
+
import { removeDialogs as removeCharacterDialogs } from '../characters';
|
|
14
17
|
|
|
15
18
|
const log = debug('@pie-lib:editable-html:plugins:toolbar');
|
|
16
19
|
|
|
@@ -48,12 +51,13 @@ export class Toolbar extends React.Component {
|
|
|
48
51
|
isFocused: PropTypes.bool,
|
|
49
52
|
autoWidth: PropTypes.bool,
|
|
50
53
|
onChange: PropTypes.func.isRequired,
|
|
54
|
+
getFocusedValue: PropTypes.func.isRequired,
|
|
51
55
|
pluginProps: PropTypes.object,
|
|
52
56
|
toolbarOpts: PropTypes.shape({
|
|
53
57
|
position: PropTypes.oneOf(['bottom', 'top']),
|
|
54
58
|
alignment: PropTypes.oneOf(['left', 'right']),
|
|
55
59
|
alwaysVisible: PropTypes.bool,
|
|
56
|
-
ref: PropTypes.
|
|
60
|
+
ref: PropTypes.func,
|
|
57
61
|
showDone: PropTypes.bool
|
|
58
62
|
}),
|
|
59
63
|
onDataChange: PropTypes.func
|
|
@@ -66,6 +70,10 @@ export class Toolbar extends React.Component {
|
|
|
66
70
|
};
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
componentWillUnmount() {
|
|
74
|
+
removeCharacterDialogs();
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
hasMark = type => {
|
|
70
78
|
const { value } = this.props;
|
|
71
79
|
return value.marks.some(mark => mark.type == type);
|
|
@@ -134,6 +142,7 @@ export class Toolbar extends React.Component {
|
|
|
134
142
|
value,
|
|
135
143
|
autoWidth,
|
|
136
144
|
onChange,
|
|
145
|
+
getFocusedValue,
|
|
137
146
|
isFocused,
|
|
138
147
|
onDone,
|
|
139
148
|
toolbarRef
|
|
@@ -167,6 +176,11 @@ export class Toolbar extends React.Component {
|
|
|
167
176
|
log('[render] plugin: ', plugin);
|
|
168
177
|
|
|
169
178
|
const handleDone = (change, done) => {
|
|
179
|
+
// use handler only if this is an actual Slate Change
|
|
180
|
+
if (!(change instanceof Change)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
170
184
|
let handler = onDone;
|
|
171
185
|
|
|
172
186
|
if (plugin && plugin.toolbar && plugin.toolbar.customToolbar) {
|
|
@@ -241,6 +255,7 @@ export class Toolbar extends React.Component {
|
|
|
241
255
|
pluginProps={pluginProps}
|
|
242
256
|
value={value}
|
|
243
257
|
onChange={onChange}
|
|
258
|
+
getFocusedValue={getFocusedValue}
|
|
244
259
|
showDone={defaultToolbarShowDone}
|
|
245
260
|
onDone={handleDone}
|
|
246
261
|
deletable={deletable}
|
package/src/serialization.jsx
CHANGED
|
@@ -58,7 +58,16 @@ export const parseStyleString = s => {
|
|
|
58
58
|
return result;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
export const
|
|
61
|
+
export const getBase64 = file => {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const reader = new FileReader();
|
|
64
|
+
reader.readAsDataURL(file);
|
|
65
|
+
reader.onload = () => resolve(reader.result);
|
|
66
|
+
reader.onerror = error => reject(error);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const reactAttributes = o => toStyleObject(o, { camelize: true, addUnits: false });
|
|
62
71
|
|
|
63
72
|
const attributesToMap = el => (acc, attribute) => {
|
|
64
73
|
const value = el.getAttribute(attribute);
|
|
@@ -340,7 +349,7 @@ serializer.deserialize = function deserialize(html) {
|
|
|
340
349
|
|
|
341
350
|
let i;
|
|
342
351
|
|
|
343
|
-
for (i = 0; i <
|
|
352
|
+
for (i = 0; i < 3000; i++) {
|
|
344
353
|
json.schema.rules.push({
|
|
345
354
|
match: { object: 'document' },
|
|
346
355
|
nodes: [{ match: { object: 'block' } }]
|
|
@@ -356,7 +365,14 @@ serializer.deserialize = function deserialize(html) {
|
|
|
356
365
|
return null;
|
|
357
366
|
};
|
|
358
367
|
|
|
359
|
-
export const htmlToValue = html =>
|
|
368
|
+
export const htmlToValue = html => {
|
|
369
|
+
try {
|
|
370
|
+
return serializer.deserialize(html);
|
|
371
|
+
} catch (e) {
|
|
372
|
+
console.log("Couldn't parse html: ", e);
|
|
373
|
+
return {};
|
|
374
|
+
}
|
|
375
|
+
};
|
|
360
376
|
|
|
361
377
|
export const valueToHtml = value => serializer.serialize(value);
|
|
362
378
|
|