@pie-lib/editable-html-tip-tap 1.0.2 → 1.0.4

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.
Files changed (165) hide show
  1. package/lib/components/CharacterPicker.js +221 -0
  2. package/lib/components/CharacterPicker.js.map +1 -0
  3. package/lib/components/EditableHtml.js +323 -0
  4. package/lib/components/EditableHtml.js.map +1 -0
  5. package/lib/components/MenuBar.js +694 -0
  6. package/lib/components/MenuBar.js.map +1 -0
  7. package/lib/components/TiptapContainer.js +90 -0
  8. package/lib/components/TiptapContainer.js.map +1 -0
  9. package/lib/components/buttons/done-button.js +53 -0
  10. package/lib/components/characters/characterUtils.js +112 -0
  11. package/lib/components/characters/characterUtils.js.map +1 -0
  12. package/lib/components/characters/custom-popper.js +73 -0
  13. package/lib/components/characters/custom-popper.js.map +1 -0
  14. package/lib/components/common/done-button.js +53 -0
  15. package/lib/components/common/done-button.js.map +1 -0
  16. package/lib/components/common/toolbar-buttons.js +194 -0
  17. package/lib/components/icons/CssIcon.js +37 -0
  18. package/lib/components/icons/CssIcon.js.map +1 -0
  19. package/lib/components/icons/RespArea.js +95 -0
  20. package/lib/components/icons/RespArea.js.map +1 -0
  21. package/lib/components/icons/TableIcons.js +69 -0
  22. package/lib/components/icons/TableIcons.js.map +1 -0
  23. package/lib/components/icons/TextAlign.js +194 -0
  24. package/lib/components/icons/TextAlign.js.map +1 -0
  25. package/lib/components/icons/index.js +194 -0
  26. package/lib/components/image/AltDialog.js +129 -0
  27. package/lib/components/image/ImageToolbar.js +177 -0
  28. package/lib/components/image/ImageToolbar.js.map +1 -0
  29. package/lib/components/image/InsertImageHandler.js +115 -0
  30. package/lib/components/image/InsertImageHandler.js.map +1 -0
  31. package/lib/components/image/alt-dialog.js +2 -0
  32. package/lib/components/media/MediaDialog.js +709 -0
  33. package/lib/components/media/MediaDialog.js.map +1 -0
  34. package/lib/components/media/MediaToolbar.js +101 -0
  35. package/lib/components/media/MediaToolbar.js.map +1 -0
  36. package/lib/components/media/MediaWrapper.js +93 -0
  37. package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js +94 -0
  38. package/lib/components/respArea/DragInTheBlank/DragInTheBlank.js.map +1 -0
  39. package/lib/components/respArea/DragInTheBlank/choice.js +289 -0
  40. package/lib/components/respArea/DragInTheBlank/choice.js.map +1 -0
  41. package/lib/components/respArea/DragInTheBlank.js +94 -0
  42. package/lib/components/respArea/ExplicitConstructedResponse.js +120 -0
  43. package/lib/components/respArea/ExplicitConstructedResponse.js.map +1 -0
  44. package/lib/components/respArea/InlineDropdown.js +126 -0
  45. package/lib/components/respArea/InlineDropdown.js.map +1 -0
  46. package/lib/components/respArea/ToolbarIcon.js +105 -0
  47. package/lib/components/respArea/ToolbarIcon.js.map +1 -0
  48. package/lib/components/respArea/choice.js +2 -0
  49. package/lib/constants.js.map +1 -0
  50. package/lib/extensions/component.js +5 -5
  51. package/lib/extensions/component.js.map +1 -0
  52. package/lib/extensions/css.js.map +1 -0
  53. package/lib/extensions/custom-toolbar-wrapper.js +2 -4
  54. package/lib/extensions/custom-toolbar-wrapper.js.map +1 -0
  55. package/lib/extensions/extended-table.js +30 -0
  56. package/lib/extensions/extended-table.js.map +1 -0
  57. package/lib/extensions/image.js +2 -8
  58. package/lib/extensions/image.js.map +1 -0
  59. package/lib/extensions/index.js +52 -0
  60. package/lib/extensions/index.js.map +1 -0
  61. package/lib/extensions/math.js.map +1 -0
  62. package/lib/extensions/media.js +7 -7
  63. package/lib/extensions/media.js.map +1 -0
  64. package/lib/extensions/responseArea.js +7 -7
  65. package/lib/extensions/responseArea.js.map +1 -0
  66. package/lib/index.js +16 -1481
  67. package/lib/index.js.map +1 -0
  68. package/lib/plugins/index.js +8 -80
  69. package/lib/styles/editorContainerStyles.js +200 -0
  70. package/lib/styles/editorContainerStyles.js.map +1 -0
  71. package/lib/theme.js.map +1 -0
  72. package/lib/utils/size.js +34 -0
  73. package/lib/utils/size.js.map +1 -0
  74. package/package.json +1 -1
  75. package/src/components/CharacterPicker.jsx +185 -0
  76. package/src/components/EditableHtml.jsx +306 -0
  77. package/src/components/MenuBar.jsx +630 -0
  78. package/src/components/TiptapContainer.jsx +96 -0
  79. package/src/components/characters/characterUtils.js +127 -0
  80. package/src/{plugins/image/image-toolbar.jsx → components/image/ImageToolbar.jsx} +2 -2
  81. package/src/{plugins/image/insert-image-handler.js → components/image/InsertImageHandler.js} +0 -1
  82. package/src/{plugins/media/media-dialog.js → components/media/MediaDialog.js} +2 -2
  83. package/src/{plugins/respArea/drag-in-the-blank → components/respArea/DragInTheBlank}/choice.jsx +1 -1
  84. package/src/{plugins/respArea/inline-dropdown/index.jsx → components/respArea/InlineDropdown.jsx} +1 -1
  85. package/src/components/respArea/ToolbarIcon.jsx +68 -0
  86. package/src/extensions/component.jsx +2 -2
  87. package/src/extensions/custom-toolbar-wrapper.jsx +6 -7
  88. package/src/extensions/extended-table.js +27 -0
  89. package/src/extensions/image.js +2 -2
  90. package/src/extensions/index.js +76 -0
  91. package/src/extensions/media.js +12 -7
  92. package/src/extensions/responseArea.js +7 -7
  93. package/src/index.jsx +3 -1440
  94. package/src/styles/editorContainerStyles.js +203 -0
  95. package/src/utils/size.js +32 -0
  96. package/src/__tests__/editor.test.jsx +0 -363
  97. package/src/__tests__/serialization.test.js +0 -291
  98. package/src/block-tags.js +0 -17
  99. package/src/editor.jsx +0 -1197
  100. package/src/extensions/characters.js +0 -46
  101. package/src/old-index.jsx +0 -162
  102. package/src/parse-html.js +0 -8
  103. package/src/plugins/README.md +0 -27
  104. package/src/plugins/characters/index.jsx +0 -284
  105. package/src/plugins/characters/utils.js +0 -447
  106. package/src/plugins/css/index.jsx +0 -340
  107. package/src/plugins/customPlugin/index.jsx +0 -85
  108. package/src/plugins/html/icons/index.jsx +0 -19
  109. package/src/plugins/html/index.jsx +0 -72
  110. package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +0 -51
  111. package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +0 -27
  112. package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +0 -44
  113. package/src/plugins/image/__tests__/component.test.jsx +0 -41
  114. package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +0 -42
  115. package/src/plugins/image/__tests__/image-toolbar.test.jsx +0 -11
  116. package/src/plugins/image/__tests__/index.test.js +0 -95
  117. package/src/plugins/image/__tests__/insert-image-handler.test.js +0 -113
  118. package/src/plugins/image/__tests__/mock-change.js +0 -15
  119. package/src/plugins/image/component.jsx +0 -343
  120. package/src/plugins/image/index.jsx +0 -227
  121. package/src/plugins/index.jsx +0 -377
  122. package/src/plugins/list/__tests__/index.test.js +0 -54
  123. package/src/plugins/list/index.jsx +0 -305
  124. package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +0 -48
  125. package/src/plugins/math/__tests__/index.test.jsx +0 -245
  126. package/src/plugins/math/index.jsx +0 -379
  127. package/src/plugins/media/__tests__/index.test.js +0 -75
  128. package/src/plugins/media/index.jsx +0 -325
  129. package/src/plugins/rendering/index.js +0 -31
  130. package/src/plugins/respArea/index.jsx +0 -299
  131. package/src/plugins/respArea/math-templated/index.jsx +0 -104
  132. package/src/plugins/respArea/utils.jsx +0 -90
  133. package/src/plugins/table/CustomTablePlugin.js +0 -113
  134. package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +0 -44
  135. package/src/plugins/table/__tests__/index.test.jsx +0 -401
  136. package/src/plugins/table/__tests__/table-toolbar.test.jsx +0 -42
  137. package/src/plugins/table/index.jsx +0 -427
  138. package/src/plugins/table/table-toolbar.jsx +0 -136
  139. package/src/plugins/textAlign/index.jsx +0 -23
  140. package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +0 -923
  141. package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +0 -20
  142. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +0 -36
  143. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +0 -46
  144. package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +0 -94
  145. package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +0 -37
  146. package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +0 -51
  147. package/src/plugins/toolbar/__tests__/toolbar.test.jsx +0 -106
  148. package/src/plugins/toolbar/default-toolbar.jsx +0 -206
  149. package/src/plugins/toolbar/editor-and-toolbar.jsx +0 -257
  150. package/src/plugins/toolbar/index.jsx +0 -23
  151. package/src/plugins/toolbar/toolbar.jsx +0 -338
  152. package/src/plugins/utils.js +0 -31
  153. package/src/serialization.jsx +0 -621
  154. /package/src/{plugins → components}/characters/custom-popper.js +0 -0
  155. /package/src/{plugins/toolbar → components/common}/done-button.jsx +0 -0
  156. /package/src/{plugins/toolbar → components/common}/toolbar-buttons.jsx +0 -0
  157. /package/src/{plugins/css/icons/index.jsx → components/icons/CssIcon.jsx} +0 -0
  158. /package/src/{plugins/respArea/icons/index.jsx → components/icons/RespArea.jsx} +0 -0
  159. /package/src/{plugins/table/icons/index.jsx → components/icons/TableIcons.jsx} +0 -0
  160. /package/src/{plugins/textAlign/icons/index.jsx → components/icons/TextAlign.jsx} +0 -0
  161. /package/src/{plugins/image/alt-dialog.jsx → components/image/AltDialog.jsx} +0 -0
  162. /package/src/{plugins/media/media-toolbar.jsx → components/media/MediaToolbar.jsx} +0 -0
  163. /package/src/{plugins/media/media-wrapper.jsx → components/media/MediaWrapper.jsx} +0 -0
  164. /package/src/{plugins/respArea/drag-in-the-blank/index.jsx → components/respArea/DragInTheBlank/DragInTheBlank.jsx} +0 -0
  165. /package/src/{plugins/respArea/explicit-constructed-response/index.jsx → components/respArea/ExplicitConstructedResponse.jsx} +0 -0
@@ -1,325 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom';
3
- import { Inline } from 'slate';
4
- import TheatersIcon from '@material-ui/icons/Theaters';
5
- import VolumeUpIcon from '@material-ui/icons/VolumeUp';
6
- import debug from 'debug';
7
-
8
- import MediaDialog from './media-dialog';
9
- import MediaToolbar from './media-toolbar';
10
- import MediaWrapper from './media-wrapper';
11
-
12
- const log = debug('@pie-lib:editable-html:plugins:image');
13
-
14
- const removeDialogs = () => {
15
- const prevDialogs = document.querySelectorAll('.insert-media-dialog');
16
-
17
- prevDialogs.forEach((s) => s.remove());
18
- };
19
-
20
- export const insertDialog = (props) => {
21
- const newEl = document.createElement('div');
22
- const { type, callback, opts, ...rest } = props;
23
- const initialBodyOverflow = document.body.style.overflow;
24
-
25
- removeDialogs();
26
-
27
- newEl.className = 'insert-media-dialog';
28
- document.body.style.overflow = 'hidden';
29
-
30
- const handleClose = (val, data) => {
31
- callback(val, data);
32
- newEl.remove();
33
- document.body.style.overflow = initialBodyOverflow;
34
- };
35
-
36
- const el = (
37
- <MediaDialog
38
- {...rest}
39
- uploadSoundSupport={opts.uploadSoundSupport}
40
- type={type}
41
- disablePortal={true}
42
- open={true}
43
- handleClose={handleClose}
44
- />
45
- );
46
-
47
- ReactDOM.render(el, newEl);
48
-
49
- document.body.appendChild(newEl);
50
- };
51
-
52
- const types = ['audio', 'video'];
53
-
54
- export default function MediaPlugin(type, opts) {
55
- const toolbar = {
56
- icon: type === 'audio' ? <VolumeUpIcon /> : <TheatersIcon />,
57
- ariaLabel: type === 'audio' ? 'Insert audio' : 'Insert video',
58
- onClick: (value, onChange) => {
59
- log('[toolbar] onClick');
60
- const inline = Inline.create({
61
- type: type,
62
- isVoid: true,
63
- data: {
64
- editing: false,
65
- ends: undefined,
66
- height: undefined,
67
- title: undefined,
68
- starts: undefined,
69
- src: undefined,
70
- url: undefined,
71
- width: undefined,
72
- },
73
- });
74
-
75
- const change = value.change().insertInline(inline);
76
- onChange(change);
77
- insertDialog({
78
- type,
79
- opts,
80
- callback: (val, data) => {
81
- const nodeIsThere = change.value.document.findDescendant((d) => d.key === inline.key);
82
-
83
- if (nodeIsThere) {
84
- if (!val) {
85
- const c = change.removeNodeByKey(inline.key);
86
- onChange(c, () => opts.focus());
87
- } else {
88
- const c = change.setNodeByKey(inline.key, { data });
89
- onChange(c, () => opts.focus('beginning', nodeIsThere));
90
- }
91
- } else {
92
- opts.focus();
93
- }
94
- },
95
- });
96
- },
97
- supports: (node) => node.object === 'inline' && node.type === type,
98
- };
99
-
100
- return {
101
- name: type,
102
- toolbar,
103
- deleteNode: (e, node, value, onChange) => {
104
- e.preventDefault();
105
- const change = value.change().removeNodeByKey(node.key);
106
-
107
- onChange(change);
108
- },
109
- renderNode(props) {
110
- if (props.node.type === type) {
111
- const { node, key } = props;
112
- const { data } = node;
113
- const jsonData = data.toJSON();
114
- const { src, height, width, editing, tag, ...rest } = jsonData;
115
- const handleEdit = () => {
116
- const change = opts.createChange();
117
- const c = change.setNodeByKey(key, {
118
- data: {
119
- ...jsonData,
120
- editing: true,
121
- },
122
- });
123
-
124
- opts.onChange(c, () => {
125
- insertDialog({
126
- ...jsonData,
127
- edit: true,
128
- type,
129
- opts,
130
- callback: (val, data) => {
131
- const { key } = node;
132
-
133
- const nodeIsThere = change.value.document.findDescendant(
134
- (d) => d.type === type && d.data.get('editing'),
135
- );
136
-
137
- if (nodeIsThere && val) {
138
- const c = change.setNodeByKey(key, { data, editing: false });
139
- opts.onChange(c, () => opts.focus('beginning', nodeIsThere));
140
- } else {
141
- opts.focus();
142
- }
143
- },
144
- });
145
- });
146
- };
147
- const handleDelete = () => {
148
- const change = opts.createChange();
149
- const c = change.removeNodeByKey(node.key);
150
-
151
- opts.onChange(c);
152
- };
153
- const style = {};
154
-
155
- if (width) {
156
- style.width = `${width}px`;
157
- }
158
-
159
- if (height) {
160
- style.height = `${height}px`;
161
- }
162
-
163
- if (tag === 'audio') {
164
- return (
165
- <MediaWrapper editor data-type={type} width={style.width} {...rest}>
166
- <audio controls="controls" controlsList="nodownload">
167
- <source type="audio/mp3" src={src} />
168
- </audio>
169
- <MediaToolbar hideEdit onRemove={handleDelete} />
170
- </MediaWrapper>
171
- );
172
- }
173
-
174
- return (
175
- <MediaWrapper editor data-type={type} width={style.width} {...rest}>
176
- <iframe
177
- frameBorder="0"
178
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
179
- allowFullScreen
180
- src={src}
181
- editing={editing ? 1 : 0}
182
- {...rest}
183
- {...style}
184
- />
185
- <MediaToolbar onEdit={handleEdit} onRemove={handleDelete} />
186
- </MediaWrapper>
187
- );
188
- }
189
- },
190
- normalizeNode: (node) => {
191
- const textNodeMap = {};
192
- const updateNodesArray = [];
193
- let index = 0;
194
-
195
- if (node.object !== 'document') return;
196
-
197
- node.findDescendant((d) => {
198
- if (d.object === 'text') {
199
- textNodeMap[index] = d;
200
- }
201
-
202
- const isMedia = types.indexOf(d.type) >= 0;
203
-
204
- if (isMedia) {
205
- if (index > 0 && textNodeMap[index - 1] && textNodeMap[index - 1].text === '') {
206
- updateNodesArray.push(textNodeMap[index - 1]);
207
- }
208
- }
209
-
210
- index++;
211
- });
212
-
213
- if (!updateNodesArray.length) return;
214
-
215
- return (change) => {
216
- change.withoutNormalization(() => {
217
- updateNodesArray.forEach((n) => change.insertTextByKey(n.key, 0, ' '));
218
- });
219
- };
220
- },
221
- };
222
- }
223
-
224
- export const serialization = {
225
- deserialize(el /*, next*/) {
226
- let type = el.dataset && el.dataset.type;
227
- let tag = 'iframe';
228
- let src;
229
- const typeIndex = types.indexOf(type);
230
-
231
- if (typeIndex < 0) {
232
- if (el instanceof Element && el.tagName.toLowerCase() === 'audio') {
233
- type = 'audio';
234
- tag = 'audio';
235
- src = el.firstChild?.getAttribute('src');
236
- } else {
237
- return;
238
- }
239
- }
240
-
241
- const { ends, starts, title, editing, url } = el.dataset || {};
242
-
243
- log('deserialize: ', name);
244
- const width = parseInt(el.getAttribute('width'), 10) || null;
245
- const height = parseInt(el.getAttribute('height'), 10) || null;
246
-
247
- const out = {
248
- object: 'inline',
249
- type: type,
250
- isVoid: true,
251
- data: {
252
- tag,
253
- src: src || el.getAttribute('src'),
254
- editing,
255
- ends,
256
- height,
257
- starts,
258
- title,
259
- width,
260
- url,
261
- },
262
- };
263
- log('return object: ', out);
264
- return out;
265
- },
266
- serialize(object /*, children*/) {
267
- const typeIndex = types.indexOf(object.type);
268
-
269
- if (typeIndex < 0) return;
270
-
271
- const type = types[typeIndex];
272
-
273
- const { data } = object;
274
- const editing = data.get('editing');
275
- const tag = data.get('tag');
276
- const ends = data.get('ends');
277
- const src = data.get('src');
278
- const starts = data.get('starts');
279
- const title = data.get('title');
280
- const width = data.get('width');
281
- const height = data.get('height');
282
- const url = data.get('url');
283
- const style = {};
284
-
285
- if (width) {
286
- style.width = `${width}px`;
287
- }
288
-
289
- if (height) {
290
- style.height = `${height}px`;
291
- }
292
-
293
- const divProps = {
294
- 'data-editing': editing,
295
- 'data-ends': ends,
296
- 'data-starts': starts,
297
- 'data-title': title,
298
- 'data-url': url,
299
- };
300
- const props = {
301
- ...style,
302
- src,
303
- };
304
-
305
- if (tag === 'audio') {
306
- return (
307
- <audio controls="controls" controlsList="nodownload">
308
- <source type="audio/mp3" src={src} />
309
- </audio>
310
- );
311
- }
312
-
313
- return (
314
- <iframe
315
- data-type={type}
316
- src={src}
317
- {...divProps}
318
- frameBorder="0"
319
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
320
- allowFullScreen
321
- {...props}
322
- />
323
- );
324
- },
325
- };
@@ -1,31 +0,0 @@
1
- import React from 'react';
2
-
3
- /**
4
- * Plugin to render the normal divs and spans with attributes (if they are provided)
5
- */
6
- export default () => {
7
- return {
8
- name: 'renderingPlugin',
9
- renderNode: (props) => {
10
- const { attributes, children, node } = props;
11
-
12
- if (node.object !== 'block' && node.object !== 'inline') {
13
- return;
14
- }
15
-
16
- const Tag = node.object === 'block' ? 'div' : 'span';
17
- const style = { position: 'relative' };
18
- const extraAttributes = node.data.get('attributes');
19
-
20
- return React.createElement(
21
- Tag,
22
- {
23
- ...attributes,
24
- ...extraAttributes,
25
- style: style,
26
- },
27
- children,
28
- );
29
- },
30
- };
31
- };
@@ -1,299 +0,0 @@
1
- import React from 'react';
2
- import debug from 'debug';
3
- import isUndefined from 'lodash/isUndefined';
4
-
5
- import InlineDropdown from './inline-dropdown';
6
- import DragInTheBlank from './drag-in-the-blank';
7
- import ExplicitConstructedResponse from './explicit-constructed-response';
8
- import MathTemplated from './math-templated';
9
- import { getDefaultElement } from './utils';
10
- import { ToolbarIcon } from './icons';
11
-
12
- const log = debug('@pie-lib:editable-html:plugins:respArea');
13
-
14
- const lastIndexMap = {};
15
- const elTypesMap = {
16
- 'inline-dropdown': 'inline_dropdown',
17
- 'explicit-constructed-response': 'explicit_constructed_response',
18
- 'math-templated': 'math_templated',
19
- 'drag-in-the-blank': 'drag_in_the_blank',
20
- };
21
- const elTypesArray = Object.values(elTypesMap);
22
-
23
- export default function ResponseAreaPlugin(opts) {
24
- const isOfCurrentType = (d) => d.type === opts.type || d.type === elTypesMap[opts.type];
25
-
26
- const toolbar = {
27
- icon: <ToolbarIcon />,
28
- buttonStyles: {
29
- margin: '0 20px 0 auto',
30
- },
31
- onClick: (value, onChange) => {
32
- log('[toolbar] onClick');
33
- const change = value.change();
34
- const currentRespAreaList = change.value.document.filterDescendants(isOfCurrentType);
35
-
36
- if (currentRespAreaList.size >= opts.maxResponseAreas) {
37
- return;
38
- }
39
-
40
- const type = opts.type.replace(/-/g, '_');
41
- const prevIndex = lastIndexMap[type];
42
- const newIndex = prevIndex === 0 ? prevIndex : prevIndex + 1;
43
- const newInline = getDefaultElement(opts, newIndex);
44
-
45
- lastIndexMap[type] += 1;
46
-
47
- if (newInline) {
48
- if (change.value.selection.startKey || change.value.selection.endKey) {
49
- change.insertInline(newInline);
50
- } else {
51
- // If the markup is empty and there's no focus
52
- const lastText = value.document.getLastText();
53
-
54
- if (!lastText) {
55
- return;
56
- }
57
- const parentNode = value.document.getParent(lastText.key);
58
-
59
- if (parentNode) {
60
- const index = parentNode.nodes.indexOf(lastText.key);
61
-
62
- if (parentNode.isVoid) return;
63
-
64
- change.insertNodeByKey(parentNode.key, index + 1, newInline);
65
- }
66
- }
67
-
68
- if (newInline.type === 'drag_in_the_blank') {
69
- const nextText = change.value.document.getNextText(newInline.key);
70
-
71
- if (nextText) {
72
- change.moveFocusTo(nextText.key, 0).moveAnchorTo(nextText.key, 0);
73
- }
74
- }
75
- if (newInline.type === 'math_templated') {
76
- const nextText = change.value.document.getNextText(newInline.key);
77
-
78
- if (nextText) {
79
- change.moveFocusTo(nextText.key, 0).moveAnchorTo(nextText.key, 0);
80
- }
81
- }
82
-
83
- onChange(change);
84
- }
85
- },
86
- customToolbar: opts.respAreaToolbar,
87
- supports: (node) => node.object === 'inline' && elTypesArray.indexOf(node.type) >= 0,
88
- showDone: false,
89
- };
90
-
91
- return {
92
- name: 'response_area',
93
- toolbar,
94
- filterPlugins: (node, plugins) => {
95
- if (
96
- node.type === 'explicit_constructed_response' ||
97
- node.type === 'math_templated' ||
98
- node.type === 'drag_in_the_blank'
99
- ) {
100
- return [];
101
- }
102
-
103
- return plugins.filter((p) => p.name !== 'response_area');
104
- },
105
- deleteNode: (e, node, value, onChange) => {
106
- e.preventDefault();
107
-
108
- const change = value.change().removeNodeByKey(node.key);
109
-
110
- onChange(change);
111
- },
112
- renderNode(props) {
113
- const { attributes, node: n, isFocused } = props;
114
-
115
- if (n.type === 'explicit_constructed_response') {
116
- const data = n.data.toJSON();
117
- let error;
118
-
119
- if (opts.error) {
120
- error = opts.error();
121
- }
122
-
123
- return (
124
- <ExplicitConstructedResponse
125
- attributes={attributes}
126
- isFocused={isFocused}
127
- value={data.value}
128
- error={error && error[data.index] && error[data.index][0]}
129
- />
130
- );
131
- }
132
-
133
- if (n.type === 'math_templated') {
134
- const data = n.data.toJSON();
135
- let error;
136
-
137
- if (opts.error) {
138
- error = opts.error();
139
- }
140
-
141
- // add 1 to index to display R 1 instead of R 0
142
- const keyToDisplay = `R ${parseInt(data.index) + 1}`;
143
-
144
- return (
145
- <MathTemplated
146
- attributes={attributes}
147
- keyToDisplay={keyToDisplay}
148
- value={data.value || ''}
149
- error={error && error[data.index] && error[data.index][0]}
150
- />
151
- );
152
- }
153
-
154
- if (n.type === 'drag_in_the_blank') {
155
- const data = n.data.toJSON();
156
-
157
- return <DragInTheBlank attributes={attributes} data={data} n={n} nodeProps={props} opts={opts} />;
158
- }
159
-
160
- if (n.type === 'inline_dropdown') {
161
- const data = n.data.toJSON();
162
-
163
- return <InlineDropdown attributes={attributes} selectedItem={data.value} />;
164
- }
165
- },
166
- onChange(change, editor) {
167
- const type = opts.type.replace(/-/g, '_');
168
-
169
- if (isUndefined(lastIndexMap[type])) {
170
- lastIndexMap[type] = 0;
171
-
172
- change.value.document.forEachDescendant((d) => {
173
- if (d.type === type) {
174
- const newIndex = parseInt(d.data.get('index'), 10);
175
-
176
- if (newIndex > lastIndexMap[type]) {
177
- lastIndexMap[type] = newIndex;
178
- }
179
- }
180
- });
181
- }
182
-
183
- if (!editor.value) {
184
- return;
185
- }
186
-
187
- const currentRespAreaList = change.value.document.filterDescendants(isOfCurrentType);
188
- const oldRespAreaList = editor.value.document.filterDescendants(isOfCurrentType);
189
-
190
- toolbar.disabled = currentRespAreaList.size >= opts.maxResponseAreas;
191
-
192
- const arrayToFilter = oldRespAreaList.size > currentRespAreaList.size ? oldRespAreaList : currentRespAreaList;
193
- const arrayToUseForFilter = arrayToFilter === oldRespAreaList ? currentRespAreaList : oldRespAreaList;
194
-
195
- const elementsWithChangedStatus = arrayToFilter.filter(
196
- (d) => !arrayToUseForFilter.find((e) => e.data.get('index') === d.data.get('index')),
197
- );
198
-
199
- if (elementsWithChangedStatus.size && oldRespAreaList.size > currentRespAreaList.size) {
200
- opts.onHandleAreaChange(elementsWithChangedStatus);
201
- }
202
- },
203
- onDrop(event, change, editor) {
204
- const closestEl = event.target.closest('[data-key]');
205
- const inline = editor.value.document.findDescendant((d) => d.key === closestEl.dataset.key);
206
-
207
- if (inline.type === 'drag_in_the_blank') {
208
- return false;
209
- }
210
- },
211
- };
212
- }
213
-
214
- export const serialization = {
215
- deserialize(el) {
216
- const type = el.dataset && el.dataset.type;
217
-
218
- switch (type) {
219
- case 'inline_dropdown':
220
- return {
221
- object: 'inline',
222
- type: 'inline_dropdown',
223
- isVoid: true,
224
- data: {
225
- index: el.dataset.index,
226
- value: el.dataset.value,
227
- },
228
- };
229
- case 'explicit_constructed_response':
230
- return {
231
- object: 'inline',
232
- type: 'explicit_constructed_response',
233
- isVoid: true,
234
- data: {
235
- index: el.dataset.index,
236
- value: el.dataset.value,
237
- },
238
- };
239
- case 'math_templated':
240
- return {
241
- object: 'inline',
242
- type: 'math_templated',
243
- isVoid: true,
244
- data: {
245
- index: el.dataset.index,
246
- value: el.dataset.value,
247
- },
248
- };
249
- case 'drag_in_the_blank':
250
- return {
251
- object: 'inline',
252
- type: 'drag_in_the_blank',
253
- isVoid: true,
254
- data: {
255
- index: el.dataset.index,
256
- id: el.dataset.id,
257
- value: el.dataset.value,
258
- inTable: el.dataset.inTable,
259
- },
260
- };
261
- }
262
- },
263
- serialize(object) {
264
- if (object.object !== 'inline') {
265
- return;
266
- }
267
-
268
- switch (object.type) {
269
- case 'inline_dropdown': {
270
- const data = object.data.toJSON();
271
-
272
- return <span data-type="inline_dropdown" data-index={data.index} data-value={data.value} />;
273
- }
274
- case 'explicit_constructed_response': {
275
- const data = object.data.toJSON();
276
-
277
- return <span data-type="explicit_constructed_response" data-index={data.index} data-value={data.value} />;
278
- }
279
- case 'math_templated': {
280
- const data = object.data.toJSON();
281
-
282
- return <span data-type="math_templated" data-index={data.index} data-value={data.value} />;
283
- }
284
- case 'drag_in_the_blank': {
285
- const data = object.data.toJSON();
286
-
287
- return (
288
- <span
289
- data-type="drag_in_the_blank"
290
- data-index={data.index}
291
- data-id={data.id}
292
- data-value={data.value}
293
- data-in-table={data.inTable}
294
- />
295
- );
296
- }
297
- }
298
- },
299
- };