@pie-lib/editable-html 10.0.0-beta.7 → 10.0.0
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 +1 -1
- package/CHANGELOG.md +81 -0
- package/LICENSE.md +5 -0
- package/lib/editor.js +410 -543
- package/lib/editor.js.map +1 -1
- package/lib/index.js +200 -101
- package/lib/index.js.map +1 -1
- package/lib/parse-html.js +5 -6
- package/lib/parse-html.js.map +1 -1
- package/lib/plugins/characters/custom-popper.js +12 -2
- package/lib/plugins/characters/custom-popper.js.map +1 -1
- package/lib/plugins/characters/index.js +71 -19
- package/lib/plugins/characters/index.js.map +1 -1
- package/lib/plugins/characters/utils.js.map +1 -1
- package/lib/plugins/html/icons/index.js +38 -0
- package/lib/plugins/html/icons/index.js.map +1 -0
- package/lib/plugins/html/index.js +75 -0
- package/lib/plugins/html/index.js.map +1 -0
- package/lib/plugins/image/alt-dialog.js +26 -0
- package/lib/plugins/image/alt-dialog.js.map +1 -1
- package/lib/plugins/image/component.js +124 -90
- package/lib/plugins/image/component.js.map +1 -1
- package/lib/plugins/image/image-toolbar.js +45 -7
- package/lib/plugins/image/image-toolbar.js.map +1 -1
- package/lib/plugins/image/index.js +91 -113
- package/lib/plugins/image/index.js.map +1 -1
- package/lib/plugins/image/insert-image-handler.js +54 -72
- package/lib/plugins/image/insert-image-handler.js.map +1 -1
- package/lib/plugins/index.js +71 -31
- package/lib/plugins/index.js.map +1 -1
- package/lib/plugins/list/index.js +129 -58
- package/lib/plugins/list/index.js.map +1 -1
- package/lib/plugins/math/index.js +152 -118
- package/lib/plugins/math/index.js.map +1 -1
- package/lib/plugins/media/index.js +185 -168
- package/lib/plugins/media/index.js.map +1 -1
- package/lib/plugins/media/media-dialog.js +197 -110
- package/lib/plugins/media/media-dialog.js.map +1 -1
- package/lib/plugins/media/media-toolbar.js +24 -4
- package/lib/plugins/media/media-toolbar.js.map +1 -1
- package/lib/plugins/media/media-wrapper.js +65 -23
- package/lib/plugins/media/media-wrapper.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +50 -10
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +1 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +22 -9
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +1 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +9 -4
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +1 -1
- package/lib/plugins/respArea/icons/index.js +18 -1
- package/lib/plugins/respArea/icons/index.js.map +1 -1
- package/lib/plugins/respArea/index.js +133 -122
- package/lib/plugins/respArea/index.js.map +1 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +10 -4
- package/lib/plugins/respArea/inline-dropdown/index.js.map +1 -1
- package/lib/plugins/respArea/utils.js +33 -15
- package/lib/plugins/respArea/utils.js.map +1 -1
- package/lib/plugins/table/icons/index.js +7 -0
- package/lib/plugins/table/icons/index.js.map +1 -1
- package/lib/plugins/table/index.js +279 -390
- package/lib/plugins/table/index.js.map +1 -1
- package/lib/plugins/table/table-toolbar.js +47 -14
- package/lib/plugins/table/table-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/default-toolbar.js +63 -51
- package/lib/plugins/toolbar/default-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/done-button.js +9 -1
- package/lib/plugins/toolbar/done-button.js.map +1 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +140 -83
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +1 -1
- package/lib/plugins/toolbar/index.js +5 -0
- package/lib/plugins/toolbar/index.js.map +1 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +39 -8
- package/lib/plugins/toolbar/toolbar-buttons.js.map +1 -1
- package/lib/plugins/toolbar/toolbar.js +261 -225
- package/lib/plugins/toolbar/toolbar.js.map +1 -1
- package/lib/plugins/utils.js +16 -19
- package/lib/plugins/utils.js.map +1 -1
- package/lib/serialization.js +70 -11
- package/lib/serialization.js.map +1 -1
- package/lib/theme.js.map +1 -1
- package/package.json +18 -17
- package/src/editor.jsx +139 -434
- package/src/index.jsx +96 -62
- package/src/plugins/characters/index.jsx +17 -12
- package/src/plugins/html/icons/index.jsx +19 -0
- package/src/plugins/html/index.jsx +68 -0
- package/src/plugins/image/component.jsx +38 -60
- package/src/plugins/image/index.jsx +42 -95
- package/src/plugins/image/insert-image-handler.js +27 -62
- package/src/plugins/index.jsx +39 -21
- package/src/plugins/list/index.jsx +90 -62
- package/src/plugins/math/index.jsx +70 -93
- package/src/plugins/media/index.jsx +117 -146
- package/src/plugins/media/media-dialog.js +9 -10
- package/src/plugins/media/media-wrapper.jsx +27 -29
- package/src/plugins/respArea/drag-in-the-blank/index.jsx +4 -5
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +1 -2
- package/src/plugins/respArea/index.jsx +84 -114
- package/src/plugins/respArea/inline-dropdown/index.jsx +2 -3
- package/src/plugins/respArea/utils.jsx +28 -23
- package/src/plugins/table/index.jsx +214 -334
- package/src/plugins/table/table-toolbar.jsx +4 -3
- package/src/plugins/toolbar/default-toolbar.jsx +30 -48
- package/src/plugins/toolbar/editor-and-toolbar.jsx +114 -114
- package/src/plugins/toolbar/toolbar.jsx +224 -254
- package/src/plugins/utils.js +0 -16
- package/src/serialization.jsx +1 -1
- package/lib/components.js +0 -92
- package/lib/components.js.map +0 -1
- package/lib/new-serialization.js +0 -280
- package/lib/new-serialization.js.map +0 -1
- package/lib/plugins/hotKeys/index.js +0 -60
- package/lib/plugins/hotKeys/index.js.map +0 -1
- package/lib/test-serializer.js +0 -138
- package/lib/test-serializer.js.map +0 -1
- package/src/components.js +0 -135
- package/src/new-serialization.jsx +0 -310
- package/src/plugins/hotKeys/index.js +0 -54
- package/src/test-serializer.js +0 -132
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import EditTable from 'slate-edit-table';
|
|
3
|
+
import { Block } from 'slate';
|
|
3
4
|
import debug from 'debug';
|
|
4
5
|
import GridOn from '@material-ui/icons/GridOn';
|
|
5
6
|
import TableToolbar from './table-toolbar';
|
|
6
7
|
import PropTypes from 'prop-types';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
8
|
+
import SlatePropTypes from 'slate-prop-types';
|
|
9
|
+
import { withStyles } from '@material-ui/core/styles';
|
|
9
10
|
import convert from 'react-attr-converter';
|
|
10
11
|
import { object as toStyleObject } from 'to-style';
|
|
11
|
-
import get from 'lodash/get';
|
|
12
|
-
import omit from 'lodash/omit';
|
|
13
|
-
import reduce from 'lodash/reduce';
|
|
14
12
|
|
|
15
13
|
const log = debug('@pie-lib:editable-html:plugins:table');
|
|
16
14
|
|
|
17
|
-
const Table =
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const Table = withStyles(() => ({
|
|
16
|
+
table: {},
|
|
17
|
+
}))((props) => {
|
|
18
|
+
const nodeAttributes = dataToAttributes(props.node.data);
|
|
20
19
|
|
|
21
20
|
return (
|
|
22
|
-
<table
|
|
23
|
-
{props.
|
|
21
|
+
<table
|
|
22
|
+
className={props.classes.table}
|
|
23
|
+
{...props.attributes}
|
|
24
|
+
{...nodeAttributes}
|
|
25
|
+
onFocus={props.onFocus}
|
|
26
|
+
onBlur={props.onBlur}
|
|
27
|
+
>
|
|
28
|
+
<tbody>{props.children}</tbody>
|
|
24
29
|
</table>
|
|
25
30
|
);
|
|
26
31
|
});
|
|
27
32
|
|
|
28
33
|
Table.propTypes = {
|
|
29
34
|
attributes: PropTypes.object,
|
|
30
|
-
element: PropTypes.object,
|
|
31
35
|
onFocus: PropTypes.func,
|
|
32
36
|
onBlur: PropTypes.func,
|
|
33
|
-
node:
|
|
34
|
-
type: PropTypes.string,
|
|
35
|
-
children: PropTypes.array,
|
|
36
|
-
data: PropTypes.object,
|
|
37
|
-
}),
|
|
37
|
+
node: SlatePropTypes.node,
|
|
38
38
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const TableRow =
|
|
41
|
+
const TableRow = (props) => <tr {...props.attributes}>{props.children}</tr>;
|
|
42
42
|
|
|
43
43
|
TableRow.propTypes = {
|
|
44
44
|
attributes: PropTypes.object,
|
|
@@ -47,35 +47,22 @@ TableRow.propTypes = {
|
|
|
47
47
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
TableBody.propTypes = {
|
|
53
|
-
attributes: PropTypes.object,
|
|
54
|
-
onFocus: PropTypes.func,
|
|
55
|
-
onBlur: PropTypes.func,
|
|
56
|
-
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const useCellStyles = makeStyles({
|
|
50
|
+
const TableCell = withStyles(() => ({
|
|
60
51
|
td: {
|
|
61
52
|
minWidth: '25px',
|
|
62
53
|
},
|
|
63
|
-
})
|
|
54
|
+
}))((props) => {
|
|
55
|
+
const Tag = props.node.data.get('header') ? 'th' : 'td';
|
|
64
56
|
|
|
65
|
-
const
|
|
66
|
-
const classes = useCellStyles();
|
|
67
|
-
const { node } = props;
|
|
68
|
-
const Tag = get(node, 'data.header') ? 'th' : 'td';
|
|
69
|
-
|
|
70
|
-
const nodeAttributes = dataToAttributes(props.element.data);
|
|
57
|
+
const nodeAttributes = dataToAttributes(props.node.data);
|
|
71
58
|
delete nodeAttributes.header;
|
|
72
59
|
|
|
73
60
|
return (
|
|
74
61
|
<Tag
|
|
75
62
|
{...props.attributes}
|
|
76
63
|
{...nodeAttributes}
|
|
77
|
-
colSpan={get(
|
|
78
|
-
className={classes[Tag]}
|
|
64
|
+
colSpan={props.node.data.get('colspan')}
|
|
65
|
+
className={props.classes[Tag]}
|
|
79
66
|
onFocus={props.onFocus}
|
|
80
67
|
onBlur={props.onBlur}
|
|
81
68
|
>
|
|
@@ -85,163 +72,80 @@ const TableCell = React.forwardRef((props) => {
|
|
|
85
72
|
});
|
|
86
73
|
|
|
87
74
|
TableCell.propTypes = {
|
|
88
|
-
node: PropTypes.object,
|
|
89
|
-
element: PropTypes.object,
|
|
90
75
|
attributes: PropTypes.object,
|
|
91
76
|
onFocus: PropTypes.func,
|
|
92
77
|
onBlur: PropTypes.func,
|
|
93
78
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
94
79
|
};
|
|
95
80
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const ancestors = SlateNode.ancestors(editor, Editor.path(editor, editor.selection), {
|
|
102
|
-
reverse: true,
|
|
103
|
-
});
|
|
81
|
+
export const moveFocusToBeginningOfTable = (change) => {
|
|
82
|
+
const addedTable = change.value.document.findDescendant((d) => !!d.data && !!d.data.get('newTable'));
|
|
104
83
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return [ancestor, ancestorPath];
|
|
108
|
-
}
|
|
84
|
+
if (!addedTable) {
|
|
85
|
+
return;
|
|
109
86
|
}
|
|
110
87
|
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const moveToBeginningOfTable = (editor) => {
|
|
115
|
-
const [tableBlock, tablePath] = getAncestorByType(editor, 'table');
|
|
116
|
-
let firstTdPath;
|
|
88
|
+
change.collapseToStartOf(addedTable);
|
|
117
89
|
|
|
118
|
-
|
|
119
|
-
if (descendant.type === 'td') {
|
|
120
|
-
firstTdPath = descendantPath;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
90
|
+
const update = addedTable.data.remove('newTable');
|
|
123
91
|
|
|
124
|
-
|
|
92
|
+
change.setNodeByKey(addedTable.key, { data: update });
|
|
125
93
|
};
|
|
126
94
|
|
|
127
|
-
const TABLE_TYPES = ['tbody', 'tr', 'td', 'table'];
|
|
128
|
-
|
|
129
95
|
export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
130
|
-
const core = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const { normalizeNode } = editor;
|
|
134
|
-
|
|
135
|
-
editor.normalizeNode = (entry) => {
|
|
136
|
-
const [tableNode, tablePath] = entry;
|
|
137
|
-
const tableParent = SlateNode.get(editor, tablePath.slice(0, -1));
|
|
138
|
-
|
|
139
|
-
// If the element is a paragraph, ensure its children are valid.
|
|
140
|
-
if (SlateElement.isElement(tableNode) && tableNode.type === 'table') {
|
|
141
|
-
const emptyBlock = {
|
|
142
|
-
type: 'paragraph',
|
|
143
|
-
children: [{ text: '' }],
|
|
144
|
-
};
|
|
145
|
-
const tableIndex = tablePath.slice(-1)[0];
|
|
146
|
-
|
|
147
|
-
// if table is the first element, we need to add a space before
|
|
148
|
-
// so users can focus before the table
|
|
149
|
-
if (tableIndex === 0) {
|
|
150
|
-
const beforeTablePath = [...tablePath.slice(0, -1), 0];
|
|
151
|
-
|
|
152
|
-
editor.apply({
|
|
153
|
-
type: 'insert_node',
|
|
154
|
-
path: beforeTablePath,
|
|
155
|
-
node: emptyBlock,
|
|
156
|
-
});
|
|
157
|
-
editor.continueNormalization();
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// if table is the last element, we add element after it
|
|
162
|
-
if (tableParent.children.length - 1 === tableIndex) {
|
|
163
|
-
const afterTablePath = [...tablePath.slice(0, -1), tableIndex + 1];
|
|
164
|
-
|
|
165
|
-
editor.apply({
|
|
166
|
-
type: 'insert_node',
|
|
167
|
-
path: afterTablePath,
|
|
168
|
-
node: emptyBlock,
|
|
169
|
-
});
|
|
170
|
-
editor.continueNormalization();
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// if table does not have a tbody, we add it
|
|
175
|
-
if (tableNode.children[0].type !== 'tbody') {
|
|
176
|
-
const tBodyNode = { type: 'tbody', children: [] };
|
|
177
|
-
|
|
178
|
-
Transforms.wrapNodes(editor, tBodyNode, {
|
|
179
|
-
at: {
|
|
180
|
-
anchor: { path: [...tablePath, 0], offset: 0 },
|
|
181
|
-
focus: { path: [...tablePath, tableNode.children.length], offset: 0 },
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
editor.continueNormalization();
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
96
|
+
const core = EditTable({
|
|
97
|
+
typeContent: 'div',
|
|
98
|
+
});
|
|
188
99
|
|
|
189
|
-
|
|
190
|
-
normalizeNode(entry);
|
|
191
|
-
};
|
|
100
|
+
// fix outdated schema
|
|
192
101
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
102
|
+
if (core.schema && core.schema.blocks) {
|
|
103
|
+
Object.keys(core.schema.blocks).forEach((key) => {
|
|
104
|
+
const block = core.schema.blocks[key];
|
|
196
105
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
106
|
+
if (block.parent) {
|
|
107
|
+
if (block.nodes[0].types) {
|
|
108
|
+
block.nodes[0] = {
|
|
109
|
+
type: block.nodes[0].types[0],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
201
112
|
|
|
202
|
-
|
|
203
|
-
|
|
113
|
+
if (block.nodes[0].objects) {
|
|
114
|
+
block.nodes[0] = {
|
|
115
|
+
object: block.nodes[0].objects[0],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
204
118
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
text: '',
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
});
|
|
119
|
+
block.parent = {
|
|
120
|
+
type: block.parent.types[0],
|
|
121
|
+
};
|
|
122
|
+
} else {
|
|
123
|
+
block.nodes[0] = { type: block.nodes[0].types[0] };
|
|
214
124
|
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
215
127
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return
|
|
220
|
-
type: 'table',
|
|
221
|
-
children: [
|
|
222
|
-
{
|
|
223
|
-
type: 'tbody',
|
|
224
|
-
children: tableRows,
|
|
225
|
-
},
|
|
226
|
-
],
|
|
227
|
-
};
|
|
128
|
+
core.utils.getTableBlock = (containerNode, key) => {
|
|
129
|
+
const node = containerNode.getDescendant(key);
|
|
130
|
+
const ancestors = containerNode.getAncestors(key).push(node);
|
|
131
|
+
return ancestors.findLast((p) => p.type === 'table');
|
|
228
132
|
};
|
|
229
133
|
|
|
230
|
-
core.utils.getTableBlock = (editor) => getAncestorByType(editor, 'table');
|
|
231
|
-
|
|
232
|
-
core.utils.isSelectionInTable = (editor) => !!core.utils.getTableBlock(editor);
|
|
233
|
-
|
|
234
134
|
core.utils.createTableWithOptions = (row, columns, extra) => {
|
|
235
135
|
const createdTable = core.utils.createTable(row, columns);
|
|
236
|
-
const newTable = {
|
|
136
|
+
const newTable = Block.create({
|
|
137
|
+
...createdTable.toJSON(),
|
|
138
|
+
...extra,
|
|
139
|
+
});
|
|
237
140
|
|
|
238
141
|
return newTable;
|
|
239
142
|
};
|
|
240
143
|
|
|
241
144
|
core.toolbar = {
|
|
242
145
|
icon: <GridOn />,
|
|
243
|
-
onClick: (
|
|
146
|
+
onClick: (value, onChange) => {
|
|
244
147
|
log('insert table');
|
|
148
|
+
const change = value.change();
|
|
245
149
|
const newTable = core.utils.createTableWithOptions(2, 2, {
|
|
246
150
|
data: {
|
|
247
151
|
border: '1',
|
|
@@ -249,145 +153,65 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
249
153
|
},
|
|
250
154
|
});
|
|
251
155
|
|
|
252
|
-
|
|
253
|
-
|
|
156
|
+
change.insertBlock(newTable);
|
|
157
|
+
|
|
158
|
+
moveFocusToBeginningOfTable(change);
|
|
159
|
+
onChange(change);
|
|
254
160
|
},
|
|
161
|
+
supports: (node, value) => node && node.object === 'block' && core.utils.isSelectionInTable(value),
|
|
255
162
|
/**
|
|
256
163
|
* Note - the node may not be a table node - it may be a node inside a table.
|
|
257
164
|
*/
|
|
258
|
-
customToolbar: (node,
|
|
165
|
+
customToolbar: (node, value, onToolbarDone) => {
|
|
259
166
|
log('[customToolbar] node.data: ', node.data);
|
|
260
167
|
|
|
261
|
-
const
|
|
168
|
+
const tableBlock = core.utils.getTableBlock(value.document, node?.key);
|
|
262
169
|
log('[customToolbar] tableBlock: ', tableBlock);
|
|
263
170
|
|
|
264
|
-
const hasBorder = () => get(tableBlock
|
|
171
|
+
const hasBorder = () => tableBlock.data.get('border') && tableBlock.data.get('border') !== '0';
|
|
265
172
|
const addRow = () => {
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
log('[addRow]');
|
|
269
|
-
|
|
270
|
-
if (trNode) {
|
|
271
|
-
const newTr = { type: 'tr', children: [] };
|
|
272
|
-
const columnsLength = trNode.children.length;
|
|
273
|
-
|
|
274
|
-
for (let i = 0; i < columnsLength; i++) {
|
|
275
|
-
newTr.children.push({
|
|
276
|
-
type: 'td',
|
|
277
|
-
children: [
|
|
278
|
-
{
|
|
279
|
-
text: '',
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
Transforms.insertNodes(editor, [newTr], { at: trPath });
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const removeRow = () => {
|
|
290
|
-
const [tBodyNode, tBodyPath] = getAncestorByType(editor, 'tbody');
|
|
291
|
-
|
|
292
|
-
log('[removeRow]');
|
|
293
|
-
|
|
294
|
-
if (tBodyPath) {
|
|
295
|
-
if (tBodyNode.children.length > 1) {
|
|
296
|
-
const [, trPath] = getAncestorByType(editor, 'tr');
|
|
297
|
-
|
|
298
|
-
log('[removeRow]');
|
|
299
|
-
|
|
300
|
-
if (trPath) {
|
|
301
|
-
Transforms.removeNodes(editor, { at: trPath });
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
173
|
+
const change = core.changes.insertRow(value.change());
|
|
174
|
+
onToolbarDone(change, false);
|
|
305
175
|
};
|
|
306
176
|
|
|
307
177
|
const addColumn = () => {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (tBodyNode) {
|
|
313
|
-
const emptyTd = {
|
|
314
|
-
type: 'td',
|
|
315
|
-
children: [{ text: '' }],
|
|
316
|
-
};
|
|
317
|
-
const trElements = Editor.nodes(editor, {
|
|
318
|
-
at: tBodyPath, // Path of Editor
|
|
319
|
-
match: (node) => 'tr' === node.type,
|
|
320
|
-
});
|
|
178
|
+
const change = core.changes.insertColumn(value.change());
|
|
179
|
+
onToolbarDone(change, false);
|
|
180
|
+
};
|
|
321
181
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
}
|
|
182
|
+
const removeRow = () => {
|
|
183
|
+
const change = core.changes.removeRow(value.change());
|
|
184
|
+
onToolbarDone(change, false);
|
|
328
185
|
};
|
|
329
186
|
|
|
330
187
|
const removeColumn = () => {
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
log('[addColumn]');
|
|
334
|
-
|
|
335
|
-
if (tBodyNode) {
|
|
336
|
-
const currentPath = Editor.path(editor, editor.selection);
|
|
337
|
-
const columnIndex = currentPath[currentPath.length - 2];
|
|
338
|
-
const trElements = Editor.nodes(editor, {
|
|
339
|
-
at: tBodyPath, // Path of Editor
|
|
340
|
-
match: (node) => 'tr' === node.type,
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
for (const [trNode, nodePath] of trElements) {
|
|
344
|
-
if (trNode.children.length > 1) {
|
|
345
|
-
Transforms.removeNodes(editor, { at: [...nodePath, columnIndex] });
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
188
|
+
const change = core.changes.removeColumn(value.change());
|
|
189
|
+
onToolbarDone(change, false);
|
|
349
190
|
};
|
|
350
191
|
|
|
351
192
|
const removeTable = () => {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
editor.apply({
|
|
355
|
-
type: 'remove_node',
|
|
356
|
-
path: tablePath,
|
|
357
|
-
node: tableNode,
|
|
358
|
-
});
|
|
193
|
+
const change = core.changes.removeTable(value.change());
|
|
194
|
+
onToolbarDone(change, false);
|
|
359
195
|
};
|
|
360
196
|
|
|
361
197
|
const toggleBorder = () => {
|
|
362
198
|
const { data } = tableBlock;
|
|
363
|
-
const update =
|
|
364
|
-
...data,
|
|
365
|
-
border: hasBorder() ? '0' : '1',
|
|
366
|
-
};
|
|
367
|
-
const [, tablePath] = getAncestorByType(editor, 'table');
|
|
368
|
-
|
|
199
|
+
const update = data.set('border', hasBorder() ? '0' : '1');
|
|
369
200
|
log('[toggleBorder] update: ', update);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
type: 'set_node',
|
|
373
|
-
path: tablePath,
|
|
374
|
-
properties: {
|
|
375
|
-
data: node.data,
|
|
376
|
-
},
|
|
377
|
-
newProperties: { data: update },
|
|
378
|
-
});
|
|
201
|
+
const change = value.change().setNodeByKey(tableBlock.key, { data: update });
|
|
202
|
+
onToolbarDone(change, false);
|
|
379
203
|
};
|
|
380
204
|
|
|
381
205
|
const onDone = () => {
|
|
382
206
|
log('[onDone] call onToolbarDone...');
|
|
383
|
-
onToolbarDone(true);
|
|
207
|
+
onToolbarDone(null, true);
|
|
384
208
|
};
|
|
385
209
|
|
|
386
210
|
const Tb = () => (
|
|
387
211
|
<TableToolbar
|
|
388
|
-
editor={editor}
|
|
389
212
|
plugins={toolbarPlugins}
|
|
390
213
|
onChange={(c) => onToolbarDone(c, false)}
|
|
214
|
+
value={value}
|
|
391
215
|
onAddRow={addRow}
|
|
392
216
|
onRemoveRow={removeRow}
|
|
393
217
|
onAddColumn={addColumn}
|
|
@@ -402,17 +226,13 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
402
226
|
},
|
|
403
227
|
};
|
|
404
228
|
|
|
405
|
-
core.supports = (node) => TABLE_TYPES.includes(node.type);
|
|
406
|
-
|
|
407
229
|
const Node = (props) => {
|
|
408
230
|
switch (props.node.type) {
|
|
409
231
|
case 'table':
|
|
410
232
|
return <Table {...props} onFocus={opts.onFocus} onBlur={opts.onBlur} />;
|
|
411
|
-
case '
|
|
412
|
-
return <TableBody {...props} onFocus={opts.onFocus} onBlur={opts.onBlur} />;
|
|
413
|
-
case 'tr':
|
|
233
|
+
case 'table_row':
|
|
414
234
|
return <TableRow {...props} />;
|
|
415
|
-
case '
|
|
235
|
+
case 'table_cell':
|
|
416
236
|
return <TableCell {...props} onFocus={opts.onFocus} onBlur={opts.onBlur} />;
|
|
417
237
|
default:
|
|
418
238
|
return null;
|
|
@@ -422,6 +242,74 @@ export default (opts, toolbarPlugins /* : {toolbar: {}}[] */) => {
|
|
|
422
242
|
node: PropTypes.object,
|
|
423
243
|
};
|
|
424
244
|
|
|
245
|
+
core.normalizeNode = (node) => {
|
|
246
|
+
if (node.object !== 'document') {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const tableAdded = node.findDescendant((d) => d.data && d.data.get('newTable'));
|
|
251
|
+
|
|
252
|
+
if (!tableAdded) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const nodeToSearch = node.getParent(tableAdded.key) || node;
|
|
257
|
+
let shouldAddTextAfterNode = false;
|
|
258
|
+
const indexToNotHaveTableOn = nodeToSearch.nodes.size - 1;
|
|
259
|
+
const indexOfLastTable = nodeToSearch.nodes.findLastIndex((d) => d.type === 'table');
|
|
260
|
+
|
|
261
|
+
// if the last table in the document is of type table, we need to do the change
|
|
262
|
+
if (indexOfLastTable === indexToNotHaveTableOn) {
|
|
263
|
+
shouldAddTextAfterNode = true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!shouldAddTextAfterNode) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return (change) => {
|
|
271
|
+
if (shouldAddTextAfterNode) {
|
|
272
|
+
const tableJSON = tableAdded.toJSON();
|
|
273
|
+
|
|
274
|
+
// we remove the table node because otherwise we can't add the empty block after it
|
|
275
|
+
// we need a block that contains text in order to do it
|
|
276
|
+
change.removeNodeByKey(tableAdded.key);
|
|
277
|
+
|
|
278
|
+
const newBlock = Block.create({
|
|
279
|
+
object: 'block',
|
|
280
|
+
type: 'div',
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// we add an empty block but that it's going to be normalized
|
|
284
|
+
// because it will add the empty text to it like it should
|
|
285
|
+
change.insertBlock(newBlock);
|
|
286
|
+
|
|
287
|
+
change.withoutNormalization(() => {
|
|
288
|
+
// we do these changes without normalization
|
|
289
|
+
|
|
290
|
+
// we get the text previous to the new block added
|
|
291
|
+
const prevText = change.value.document.getPreviousText(newBlock.key);
|
|
292
|
+
|
|
293
|
+
if (prevText) {
|
|
294
|
+
// we move focus to the previous text
|
|
295
|
+
change.moveFocusTo(prevText.key, prevText.text?.length).moveAnchorTo(prevText.key, prevText.text?.length);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// we insert the table block between the first block with text and the last block with text
|
|
299
|
+
change.insertBlock({
|
|
300
|
+
...tableJSON,
|
|
301
|
+
data: {
|
|
302
|
+
...tableJSON.data,
|
|
303
|
+
newTable: true,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
moveFocusToBeginningOfTable(change);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
|
|
425
313
|
core.renderNode = Node;
|
|
426
314
|
|
|
427
315
|
return core;
|
|
@@ -454,16 +342,16 @@ const attributesToMap = (el) => (acc, attribute) => {
|
|
|
454
342
|
};
|
|
455
343
|
|
|
456
344
|
const dataToAttributes = (data) => {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
);
|
|
345
|
+
if (!data || !data.get) {
|
|
346
|
+
return {};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return data.reduce((acc, v, name) => {
|
|
350
|
+
if (v) {
|
|
351
|
+
acc[convert(name)] = v;
|
|
352
|
+
}
|
|
353
|
+
return acc;
|
|
354
|
+
}, {});
|
|
467
355
|
};
|
|
468
356
|
|
|
469
357
|
const attributes = ['border', 'cellpadding', 'cellspacing', 'class', 'style'];
|
|
@@ -482,78 +370,70 @@ export const serialization = {
|
|
|
482
370
|
: el.children;
|
|
483
371
|
const c = Array.from(children);
|
|
484
372
|
|
|
485
|
-
return
|
|
486
|
-
'
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
next(c),
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
case 'tbody': {
|
|
495
|
-
return jsx(
|
|
496
|
-
'element',
|
|
497
|
-
{
|
|
498
|
-
type: 'tbody',
|
|
499
|
-
},
|
|
500
|
-
next(el.childNodes),
|
|
501
|
-
);
|
|
373
|
+
return {
|
|
374
|
+
object: 'block',
|
|
375
|
+
type: 'table',
|
|
376
|
+
nodes: next(c),
|
|
377
|
+
data: attributes.reduce(attributesToMap(el), {}),
|
|
378
|
+
};
|
|
502
379
|
}
|
|
503
380
|
|
|
504
381
|
case 'th': {
|
|
505
|
-
return
|
|
506
|
-
'
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
next(el.childNodes),
|
|
512
|
-
);
|
|
382
|
+
return {
|
|
383
|
+
object: 'block',
|
|
384
|
+
type: 'table_cell',
|
|
385
|
+
nodes: next(el.childNodes),
|
|
386
|
+
data: cellAttributes.reduce(attributesToMap(el), { header: true }),
|
|
387
|
+
};
|
|
513
388
|
}
|
|
514
389
|
|
|
515
390
|
case 'tr': {
|
|
516
|
-
return
|
|
517
|
-
'
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
next(Array.from(el.children)),
|
|
522
|
-
);
|
|
391
|
+
return {
|
|
392
|
+
object: 'block',
|
|
393
|
+
type: 'table_row',
|
|
394
|
+
nodes: next(Array.from(el.children)),
|
|
395
|
+
};
|
|
523
396
|
}
|
|
524
397
|
|
|
525
398
|
case 'td': {
|
|
526
|
-
return
|
|
527
|
-
'
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
next(el.childNodes),
|
|
533
|
-
);
|
|
399
|
+
return {
|
|
400
|
+
object: 'block',
|
|
401
|
+
type: 'table_cell',
|
|
402
|
+
nodes: next(Array.from(el.childNodes)),
|
|
403
|
+
data: cellAttributes.reduce(attributesToMap(el), { header: false }),
|
|
404
|
+
};
|
|
534
405
|
}
|
|
535
406
|
}
|
|
536
407
|
},
|
|
537
408
|
serialize(object, children) {
|
|
409
|
+
if (object.object !== 'block') {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
538
413
|
switch (object.type) {
|
|
539
414
|
case 'table': {
|
|
540
415
|
const attributes = dataToAttributes(object.data);
|
|
541
416
|
|
|
542
|
-
return
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
417
|
+
return (
|
|
418
|
+
<table {...attributes}>
|
|
419
|
+
<tbody>{children}</tbody>
|
|
420
|
+
</table>
|
|
421
|
+
);
|
|
546
422
|
}
|
|
547
|
-
|
|
423
|
+
|
|
424
|
+
case 'table_row': {
|
|
548
425
|
return <tr>{children}</tr>;
|
|
549
426
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
return <td {...attributes}>{children}</td>;
|
|
553
|
-
}
|
|
554
|
-
case 'th': {
|
|
427
|
+
|
|
428
|
+
case 'table_cell': {
|
|
555
429
|
const attributes = dataToAttributes(object.data);
|
|
556
|
-
|
|
430
|
+
delete attributes.header;
|
|
431
|
+
|
|
432
|
+
if (object.data.get('header')) {
|
|
433
|
+
return <th {...attributes}>{children}</th>;
|
|
434
|
+
} else {
|
|
435
|
+
return <td {...attributes}>{children}</td>;
|
|
436
|
+
}
|
|
557
437
|
}
|
|
558
438
|
}
|
|
559
439
|
},
|