@pie-lib/editable-html 11.1.1 → 11.2.1-beta.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.md +43 -167
- package/NEXT.CHANGELOG.json +1 -0
- package/package.json +10 -6
- package/src/__tests__/editor.test.jsx +363 -0
- package/src/__tests__/serialization.test.js +291 -0
- package/src/__tests__/utils.js +36 -0
- package/src/block-tags.js +17 -0
- package/src/constants.js +7 -0
- package/src/editor.jsx +303 -49
- package/src/index.jsx +19 -10
- package/src/plugins/characters/index.jsx +11 -3
- package/src/plugins/characters/utils.js +12 -12
- package/src/plugins/css/icons/index.jsx +17 -0
- package/src/plugins/css/index.jsx +346 -0
- package/src/plugins/customPlugin/index.jsx +85 -0
- package/src/plugins/html/index.jsx +9 -6
- package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +51 -0
- package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +27 -0
- package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +44 -0
- package/src/plugins/image/__tests__/component.test.jsx +41 -0
- package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +42 -0
- package/src/plugins/image/__tests__/image-toolbar.test.jsx +11 -0
- package/src/plugins/image/__tests__/index.test.js +95 -0
- package/src/plugins/image/__tests__/insert-image-handler.test.js +113 -0
- package/src/plugins/image/__tests__/mock-change.js +15 -0
- package/src/plugins/image/index.jsx +2 -1
- package/src/plugins/image/insert-image-handler.js +13 -6
- package/src/plugins/index.jsx +248 -5
- package/src/plugins/list/__tests__/index.test.js +54 -0
- package/src/plugins/list/index.jsx +130 -0
- package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +48 -0
- package/src/plugins/math/__tests__/index.test.jsx +245 -0
- package/src/plugins/math/index.jsx +87 -56
- package/src/plugins/media/__tests__/index.test.js +75 -0
- package/src/plugins/media/index.jsx +3 -2
- package/src/plugins/media/media-dialog.js +106 -57
- package/src/plugins/rendering/index.js +31 -0
- package/src/plugins/respArea/drag-in-the-blank/choice.jsx +4 -1
- package/src/plugins/respArea/explicit-constructed-response/index.jsx +10 -8
- package/src/plugins/respArea/index.jsx +53 -7
- package/src/plugins/respArea/inline-dropdown/index.jsx +13 -6
- package/src/plugins/respArea/math-templated/index.jsx +104 -0
- package/src/plugins/respArea/utils.jsx +11 -0
- package/src/plugins/table/CustomTablePlugin.js +113 -0
- package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +44 -0
- package/src/plugins/table/__tests__/index.test.jsx +401 -0
- package/src/plugins/table/__tests__/table-toolbar.test.jsx +42 -0
- package/src/plugins/table/index.jsx +46 -59
- package/src/plugins/table/table-toolbar.jsx +39 -2
- package/src/plugins/textAlign/icons/index.jsx +139 -0
- package/src/plugins/textAlign/index.jsx +23 -0
- package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +923 -0
- package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +20 -0
- package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +36 -0
- package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +46 -0
- package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +94 -0
- package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +37 -0
- package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +51 -0
- package/src/plugins/toolbar/__tests__/toolbar.test.jsx +106 -0
- package/src/plugins/toolbar/default-toolbar.jsx +82 -20
- package/src/plugins/toolbar/done-button.jsx +3 -1
- package/src/plugins/toolbar/editor-and-toolbar.jsx +18 -13
- package/src/plugins/toolbar/toolbar-buttons.jsx +52 -11
- package/src/plugins/toolbar/toolbar.jsx +31 -8
- package/src/serialization.jsx +213 -38
- package/README.md +0 -45
- package/deploy.sh +0 -16
- package/lib/editor.js +0 -1094
- package/lib/editor.js.map +0 -1
- package/lib/index.js +0 -253
- package/lib/index.js.map +0 -1
- package/lib/parse-html.js +0 -16
- package/lib/parse-html.js.map +0 -1
- package/lib/plugins/characters/custom-popper.js +0 -73
- package/lib/plugins/characters/custom-popper.js.map +0 -1
- package/lib/plugins/characters/index.js +0 -300
- package/lib/plugins/characters/index.js.map +0 -1
- package/lib/plugins/characters/utils.js +0 -381
- package/lib/plugins/characters/utils.js.map +0 -1
- package/lib/plugins/html/icons/index.js +0 -38
- package/lib/plugins/html/icons/index.js.map +0 -1
- package/lib/plugins/html/index.js +0 -76
- package/lib/plugins/html/index.js.map +0 -1
- package/lib/plugins/image/alt-dialog.js +0 -129
- package/lib/plugins/image/alt-dialog.js.map +0 -1
- package/lib/plugins/image/component.js +0 -419
- package/lib/plugins/image/component.js.map +0 -1
- package/lib/plugins/image/image-toolbar.js +0 -177
- package/lib/plugins/image/image-toolbar.js.map +0 -1
- package/lib/plugins/image/index.js +0 -262
- package/lib/plugins/image/index.js.map +0 -1
- package/lib/plugins/image/insert-image-handler.js +0 -152
- package/lib/plugins/image/insert-image-handler.js.map +0 -1
- package/lib/plugins/index.js +0 -143
- package/lib/plugins/index.js.map +0 -1
- package/lib/plugins/list/index.js +0 -204
- package/lib/plugins/list/index.js.map +0 -1
- package/lib/plugins/math/index.js +0 -419
- package/lib/plugins/math/index.js.map +0 -1
- package/lib/plugins/media/index.js +0 -384
- package/lib/plugins/media/index.js.map +0 -1
- package/lib/plugins/media/media-dialog.js +0 -668
- package/lib/plugins/media/media-dialog.js.map +0 -1
- package/lib/plugins/media/media-toolbar.js +0 -101
- package/lib/plugins/media/media-toolbar.js.map +0 -1
- package/lib/plugins/media/media-wrapper.js +0 -93
- package/lib/plugins/media/media-wrapper.js.map +0 -1
- package/lib/plugins/respArea/drag-in-the-blank/choice.js +0 -251
- package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +0 -1
- package/lib/plugins/respArea/drag-in-the-blank/index.js +0 -97
- package/lib/plugins/respArea/drag-in-the-blank/index.js.map +0 -1
- package/lib/plugins/respArea/explicit-constructed-response/index.js +0 -55
- package/lib/plugins/respArea/explicit-constructed-response/index.js.map +0 -1
- package/lib/plugins/respArea/icons/index.js +0 -95
- package/lib/plugins/respArea/icons/index.js.map +0 -1
- package/lib/plugins/respArea/index.js +0 -293
- package/lib/plugins/respArea/index.js.map +0 -1
- package/lib/plugins/respArea/inline-dropdown/index.js +0 -70
- package/lib/plugins/respArea/inline-dropdown/index.js.map +0 -1
- package/lib/plugins/respArea/utils.js +0 -110
- package/lib/plugins/respArea/utils.js.map +0 -1
- package/lib/plugins/table/icons/index.js +0 -69
- package/lib/plugins/table/icons/index.js.map +0 -1
- package/lib/plugins/table/index.js +0 -499
- package/lib/plugins/table/index.js.map +0 -1
- package/lib/plugins/table/table-toolbar.js +0 -158
- package/lib/plugins/table/table-toolbar.js.map +0 -1
- package/lib/plugins/toolbar/default-toolbar.js +0 -174
- package/lib/plugins/toolbar/default-toolbar.js.map +0 -1
- package/lib/plugins/toolbar/done-button.js +0 -50
- package/lib/plugins/toolbar/done-button.js.map +0 -1
- package/lib/plugins/toolbar/editor-and-toolbar.js +0 -287
- package/lib/plugins/toolbar/editor-and-toolbar.js.map +0 -1
- package/lib/plugins/toolbar/index.js +0 -34
- package/lib/plugins/toolbar/index.js.map +0 -1
- package/lib/plugins/toolbar/toolbar-buttons.js +0 -161
- package/lib/plugins/toolbar/toolbar-buttons.js.map +0 -1
- package/lib/plugins/toolbar/toolbar.js +0 -352
- package/lib/plugins/toolbar/toolbar.js.map +0 -1
- package/lib/plugins/utils.js +0 -62
- package/lib/plugins/utils.js.map +0 -1
- package/lib/serialization.js +0 -488
- package/lib/serialization.js.map +0 -1
- package/lib/theme.js +0 -9
- package/lib/theme.js.map +0 -1
- package/playground/image/data.js +0 -59
- package/playground/image/index.html +0 -22
- package/playground/image/index.jsx +0 -81
- package/playground/index.html +0 -25
- package/playground/mathquill/index.html +0 -22
- package/playground/mathquill/index.jsx +0 -155
- package/playground/package.json +0 -15
- package/playground/prod-test/index.html +0 -22
- package/playground/prod-test/index.jsx +0 -28
- package/playground/schema-override/data.js +0 -29
- package/playground/schema-override/image-plugin.jsx +0 -41
- package/playground/schema-override/index.html +0 -21
- package/playground/schema-override/index.jsx +0 -97
- package/playground/serialization/data.js +0 -29
- package/playground/serialization/image-plugin.jsx +0 -41
- package/playground/serialization/index.html +0 -22
- package/playground/serialization/index.jsx +0 -12
- package/playground/static.json +0 -3
- package/playground/table-examples.html +0 -70
- package/playground/webpack.config.js +0 -42
- package/static.json +0 -1
|
@@ -36,6 +36,9 @@ const matchVimeoUrl = (url) =>
|
|
|
36
36
|
url,
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
+
const matchDriveUrl = (url) =>
|
|
40
|
+
url && /^https:\/\/drive\.google\.com\/(?:file\/d\/|drive\/(?:u\/\d+\/)?folders\/|uc\?id=)([a-zA-Z0-9_-]+)/.test(url);
|
|
41
|
+
|
|
39
42
|
const matchSoundCloudUrl = (url) => {
|
|
40
43
|
if (!url) {
|
|
41
44
|
return false;
|
|
@@ -74,6 +77,11 @@ const typeMap = {
|
|
|
74
77
|
audio: 'Audio',
|
|
75
78
|
};
|
|
76
79
|
|
|
80
|
+
const tabsTypeMap = {
|
|
81
|
+
uploadFile: 'upload-file',
|
|
82
|
+
insertUrl: 'insert-url',
|
|
83
|
+
};
|
|
84
|
+
|
|
77
85
|
export class MediaDialog extends React.Component {
|
|
78
86
|
static propTypes = {
|
|
79
87
|
classes: PropTypes.object.isRequired,
|
|
@@ -98,7 +106,8 @@ export class MediaDialog extends React.Component {
|
|
|
98
106
|
constructor(props) {
|
|
99
107
|
super(props);
|
|
100
108
|
|
|
101
|
-
const { src, starts,
|
|
109
|
+
const { ends, height, src, starts, type, uploadSoundSupport, url, urlToUse, width } = props;
|
|
110
|
+
const showUploadFile = uploadSoundSupport?.add && uploadSoundSupport?.delete && type !== 'video';
|
|
102
111
|
|
|
103
112
|
this.state = {
|
|
104
113
|
ends: ends || 0,
|
|
@@ -109,12 +118,14 @@ export class MediaDialog extends React.Component {
|
|
|
109
118
|
invalid: false,
|
|
110
119
|
starts: starts || 0,
|
|
111
120
|
width: width || 560,
|
|
112
|
-
|
|
121
|
+
// default selected tab should be upload file if available
|
|
122
|
+
tabValue: showUploadFile ? tabsTypeMap.uploadFile : tabsTypeMap.insertUrl,
|
|
113
123
|
fileUpload: {
|
|
114
124
|
error: null,
|
|
115
125
|
loading: false,
|
|
116
126
|
scheduled: false,
|
|
117
127
|
url: '',
|
|
128
|
+
mimeType: '',
|
|
118
129
|
},
|
|
119
130
|
};
|
|
120
131
|
}
|
|
@@ -173,57 +184,79 @@ export class MediaDialog extends React.Component {
|
|
|
173
184
|
|
|
174
185
|
handleStateChange = (newState) => this.setState(newState, this.formatUrl);
|
|
175
186
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
187
|
+
checkAudio = (value) => {
|
|
188
|
+
if (matchSoundCloudUrl(value)) {
|
|
189
|
+
makeApiRequest(value)
|
|
190
|
+
.then((urlToUse) => {
|
|
191
|
+
this.handleStateChange({
|
|
192
|
+
urlToUse,
|
|
193
|
+
invalid: !urlToUse,
|
|
194
|
+
url: value,
|
|
195
|
+
});
|
|
196
|
+
})
|
|
197
|
+
.catch(log);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
179
200
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
invalid: !urlToUse,
|
|
187
|
-
url: value,
|
|
188
|
-
});
|
|
189
|
-
})
|
|
190
|
-
.catch(log);
|
|
191
|
-
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
} else if (type && type === 'video') {
|
|
195
|
-
if (matchYoutubeUrl(value)) {
|
|
196
|
-
const regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
197
|
-
const match = value.match(regExp);
|
|
198
|
-
const id = match[2];
|
|
199
|
-
const urlToUse = `https://youtube.com/embed/${id}`;
|
|
200
|
-
|
|
201
|
-
log('is youtube');
|
|
202
|
-
|
|
203
|
-
this.handleStateChange({
|
|
204
|
-
urlToUse,
|
|
205
|
-
url: value,
|
|
206
|
-
invalid: false,
|
|
207
|
-
});
|
|
201
|
+
checkVideo = (value) => {
|
|
202
|
+
if (matchYoutubeUrl(value)) {
|
|
203
|
+
const regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
204
|
+
const match = value.match(regExp);
|
|
205
|
+
const id = match[2];
|
|
206
|
+
const urlToUse = `https://youtube.com/embed/${id}`;
|
|
208
207
|
|
|
209
|
-
|
|
210
|
-
}
|
|
208
|
+
log('is youtube');
|
|
211
209
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
this.handleStateChange({
|
|
211
|
+
urlToUse,
|
|
212
|
+
url: value,
|
|
213
|
+
invalid: false,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
215
216
|
|
|
216
|
-
|
|
217
|
+
if (matchVimeoUrl(value)) {
|
|
218
|
+
const id = value.replace(/.*vimeo.com\/(.*)/g, '$1');
|
|
219
|
+
const urlToUse = `https://player.vimeo.com/video/${id}`;
|
|
217
220
|
|
|
218
|
-
|
|
219
|
-
urlToUse,
|
|
220
|
-
url: value,
|
|
221
|
-
ends: null,
|
|
222
|
-
invalid: false,
|
|
223
|
-
});
|
|
221
|
+
log('is vimeo');
|
|
224
222
|
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
this.handleStateChange({
|
|
224
|
+
urlToUse,
|
|
225
|
+
url: value,
|
|
226
|
+
ends: null,
|
|
227
|
+
invalid: false,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (matchDriveUrl(value)) {
|
|
232
|
+
// https://drive.google.com/file/d/11QkK_gUO068amNvZBm9cxZpKX74WYb8q/view
|
|
233
|
+
const id = value.replace(
|
|
234
|
+
/^https:\/\/drive\.google\.com\/(?:file\/d\/|drive\/(?:u\/\d+\/)?folders\/|uc\?id=)([a-zA-Z0-9_-]+)\/.*/,
|
|
235
|
+
'$1',
|
|
236
|
+
);
|
|
237
|
+
const urlToUse = `https://drive.google.com/file/d/${id}/preview`;
|
|
238
|
+
|
|
239
|
+
log('is google drive');
|
|
240
|
+
|
|
241
|
+
this.handleStateChange({
|
|
242
|
+
urlToUse,
|
|
243
|
+
url: value,
|
|
244
|
+
ends: null,
|
|
245
|
+
invalid: false,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
urlChange = (e) => {
|
|
251
|
+
const { value } = e.target || {};
|
|
252
|
+
const { type } = this.props;
|
|
253
|
+
|
|
254
|
+
if (type && type === 'audio') {
|
|
255
|
+
this.checkAudio();
|
|
256
|
+
return;
|
|
257
|
+
} else if (type && type === 'video') {
|
|
258
|
+
this.checkVideo(value);
|
|
259
|
+
return;
|
|
227
260
|
}
|
|
228
261
|
|
|
229
262
|
this.handleStateChange({
|
|
@@ -238,7 +271,7 @@ export class MediaDialog extends React.Component {
|
|
|
238
271
|
handleDone = (val) => {
|
|
239
272
|
const { handleClose } = this.props;
|
|
240
273
|
const { tabValue, fileUpload } = this.state;
|
|
241
|
-
const isInsertURL = tabValue ===
|
|
274
|
+
const isInsertURL = tabValue === tabsTypeMap.insertUrl;
|
|
242
275
|
|
|
243
276
|
if (!val) {
|
|
244
277
|
if (fileUpload.url) {
|
|
@@ -303,6 +336,7 @@ export class MediaDialog extends React.Component {
|
|
|
303
336
|
fileUpload: {
|
|
304
337
|
...this.state.fileUpload,
|
|
305
338
|
url: dataURL,
|
|
339
|
+
mimeType: fileChosen.type,
|
|
306
340
|
},
|
|
307
341
|
});
|
|
308
342
|
};
|
|
@@ -364,19 +398,33 @@ export class MediaDialog extends React.Component {
|
|
|
364
398
|
...this.state.fileUpload,
|
|
365
399
|
loading: false,
|
|
366
400
|
url: '',
|
|
401
|
+
mimeType: '',
|
|
367
402
|
},
|
|
368
403
|
});
|
|
369
404
|
};
|
|
370
405
|
|
|
371
406
|
render() {
|
|
372
407
|
const { classes, open, disablePortal, type, edit, uploadSoundSupport } = this.props;
|
|
373
|
-
const {
|
|
408
|
+
const {
|
|
409
|
+
ends,
|
|
410
|
+
height,
|
|
411
|
+
invalid,
|
|
412
|
+
starts,
|
|
413
|
+
width,
|
|
414
|
+
url,
|
|
415
|
+
mimeType,
|
|
416
|
+
formattedUrl,
|
|
417
|
+
updating,
|
|
418
|
+
tabValue,
|
|
419
|
+
fileUpload,
|
|
420
|
+
} = this.state;
|
|
374
421
|
const isYoutube = matchYoutubeUrl(url);
|
|
375
|
-
const isInsertURL = tabValue ===
|
|
376
|
-
const isUploadMedia = tabValue ===
|
|
422
|
+
const isInsertURL = tabValue === tabsTypeMap.insertUrl;
|
|
423
|
+
const isUploadMedia = tabValue === tabsTypeMap.uploadFile;
|
|
377
424
|
const submitIsDisabled = isInsertURL
|
|
378
425
|
? invalid || url === null || url === undefined
|
|
379
426
|
: !fileUpload.url || fileUpload.scheduled;
|
|
427
|
+
const showUploadFile = uploadSoundSupport?.add && uploadSoundSupport?.delete && type !== 'video';
|
|
380
428
|
|
|
381
429
|
return (
|
|
382
430
|
<Dialog
|
|
@@ -399,10 +447,11 @@ export class MediaDialog extends React.Component {
|
|
|
399
447
|
this.setState({ tabValue: value });
|
|
400
448
|
}}
|
|
401
449
|
>
|
|
402
|
-
<MuiTab
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
450
|
+
{showUploadFile ? <MuiTab value={tabsTypeMap.uploadFile} label="Upload file" /> : null}
|
|
451
|
+
<MuiTab
|
|
452
|
+
value={tabsTypeMap.insertUrl}
|
|
453
|
+
label={type === 'video' ? 'Insert YouTube, Vimeo, or Google Drive URL' : 'Insert SoundCloud URL'}
|
|
454
|
+
/>
|
|
406
455
|
</MuiTabs>
|
|
407
456
|
</div>
|
|
408
457
|
{isInsertURL && (
|
|
@@ -499,8 +548,8 @@ export class MediaDialog extends React.Component {
|
|
|
499
548
|
{fileUpload.url ? (
|
|
500
549
|
<>
|
|
501
550
|
<div className={classes.row}>
|
|
502
|
-
<audio controls="controls">
|
|
503
|
-
<source type=
|
|
551
|
+
<audio controls="controls" controlsList="nodownload">
|
|
552
|
+
<source type={mimeType} src={fileUpload.url} />
|
|
504
553
|
</audio>
|
|
505
554
|
<IconButton aria-label="delete" className={classes.deleteIcon} onClick={this.handleRemoveFile}>
|
|
506
555
|
<ActionDelete />
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
};
|
|
@@ -7,11 +7,14 @@ import { renderMath } from '@pie-lib/math-rendering';
|
|
|
7
7
|
import { withStyles } from '@material-ui/core/styles';
|
|
8
8
|
import classnames from 'classnames';
|
|
9
9
|
|
|
10
|
-
import { GripIcon } from '
|
|
10
|
+
import { GripIcon } from '@pie-lib/icons';
|
|
11
11
|
|
|
12
12
|
const useStyles = withStyles((theme) => ({
|
|
13
13
|
content: {
|
|
14
14
|
border: `solid 0px ${theme.palette.primary.main}`,
|
|
15
|
+
'& mjx-frac': {
|
|
16
|
+
fontSize: '120% !important',
|
|
17
|
+
},
|
|
15
18
|
},
|
|
16
19
|
chip: {
|
|
17
20
|
minWidth: '90px',
|
|
@@ -9,25 +9,26 @@ const ExplicitConstructedResponse = (props) => {
|
|
|
9
9
|
{...attributes}
|
|
10
10
|
style={{
|
|
11
11
|
display: 'inline-flex',
|
|
12
|
-
|
|
12
|
+
visibility: props.isFocused ? 'hidden' : 'visible',
|
|
13
|
+
minHeight: '55px',
|
|
13
14
|
minWidth: '178px',
|
|
14
15
|
position: 'relative',
|
|
15
|
-
margin: '0 5px',
|
|
16
16
|
cursor: 'pointer',
|
|
17
17
|
}}
|
|
18
18
|
>
|
|
19
19
|
<div
|
|
20
20
|
style={{
|
|
21
21
|
display: 'inline-flex',
|
|
22
|
-
|
|
23
|
-
minHeight: '
|
|
24
|
-
height: '
|
|
25
|
-
|
|
22
|
+
width: '100%',
|
|
23
|
+
minHeight: '46px',
|
|
24
|
+
height: '46px',
|
|
25
|
+
backgroundColor: '#FFF',
|
|
26
26
|
border: `1px solid ${error ? 'red' : '#C0C3CF'}`,
|
|
27
27
|
boxSizing: 'border-box',
|
|
28
|
-
borderRadius: '
|
|
28
|
+
borderRadius: '4px',
|
|
29
29
|
overflow: 'hidden',
|
|
30
|
-
padding: '
|
|
30
|
+
padding: '12px 21px',
|
|
31
|
+
marginLeft: '4px',
|
|
31
32
|
}}
|
|
32
33
|
dangerouslySetInnerHTML={{
|
|
33
34
|
__html: value || '<div> </div>',
|
|
@@ -41,6 +42,7 @@ ExplicitConstructedResponse.propTypes = {
|
|
|
41
42
|
attributes: PropTypes.object,
|
|
42
43
|
error: PropTypes.any,
|
|
43
44
|
value: PropTypes.string,
|
|
45
|
+
isFocused: PropTypes.bool,
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
export default ExplicitConstructedResponse;
|
|
@@ -5,6 +5,7 @@ import isUndefined from 'lodash/isUndefined';
|
|
|
5
5
|
import InlineDropdown from './inline-dropdown';
|
|
6
6
|
import DragInTheBlank from './drag-in-the-blank';
|
|
7
7
|
import ExplicitConstructedResponse from './explicit-constructed-response';
|
|
8
|
+
import MathTemplated from './math-templated';
|
|
8
9
|
import { getDefaultElement } from './utils';
|
|
9
10
|
import { ToolbarIcon } from './icons';
|
|
10
11
|
|
|
@@ -14,6 +15,7 @@ const lastIndexMap = {};
|
|
|
14
15
|
const elTypesMap = {
|
|
15
16
|
'inline-dropdown': 'inline_dropdown',
|
|
16
17
|
'explicit-constructed-response': 'explicit_constructed_response',
|
|
18
|
+
'math-templated': 'math_templated',
|
|
17
19
|
'drag-in-the-blank': 'drag_in_the_blank',
|
|
18
20
|
};
|
|
19
21
|
const elTypesArray = Object.values(elTypesMap);
|
|
@@ -70,6 +72,13 @@ export default function ResponseAreaPlugin(opts) {
|
|
|
70
72
|
change.moveFocusTo(nextText.key, 0).moveAnchorTo(nextText.key, 0);
|
|
71
73
|
}
|
|
72
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
|
+
}
|
|
73
82
|
|
|
74
83
|
onChange(change);
|
|
75
84
|
}
|
|
@@ -83,7 +92,11 @@ export default function ResponseAreaPlugin(opts) {
|
|
|
83
92
|
name: 'response_area',
|
|
84
93
|
toolbar,
|
|
85
94
|
filterPlugins: (node, plugins) => {
|
|
86
|
-
if (
|
|
95
|
+
if (
|
|
96
|
+
node.type === 'explicit_constructed_response' ||
|
|
97
|
+
node.type === 'math_templated' ||
|
|
98
|
+
node.type === 'drag_in_the_blank'
|
|
99
|
+
) {
|
|
87
100
|
return [];
|
|
88
101
|
}
|
|
89
102
|
|
|
@@ -97,7 +110,7 @@ export default function ResponseAreaPlugin(opts) {
|
|
|
97
110
|
onChange(change);
|
|
98
111
|
},
|
|
99
112
|
renderNode(props) {
|
|
100
|
-
const { attributes, node: n } = props;
|
|
113
|
+
const { attributes, node: n, isFocused } = props;
|
|
101
114
|
|
|
102
115
|
if (n.type === 'explicit_constructed_response') {
|
|
103
116
|
const data = n.data.toJSON();
|
|
@@ -110,12 +123,34 @@ export default function ResponseAreaPlugin(opts) {
|
|
|
110
123
|
return (
|
|
111
124
|
<ExplicitConstructedResponse
|
|
112
125
|
attributes={attributes}
|
|
126
|
+
isFocused={isFocused}
|
|
113
127
|
value={data.value}
|
|
114
128
|
error={error && error[data.index] && error[data.index][0]}
|
|
115
129
|
/>
|
|
116
130
|
);
|
|
117
131
|
}
|
|
118
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
|
+
|
|
119
154
|
if (n.type === 'drag_in_the_blank') {
|
|
120
155
|
const data = n.data.toJSON();
|
|
121
156
|
|
|
@@ -152,11 +187,7 @@ export default function ResponseAreaPlugin(opts) {
|
|
|
152
187
|
const currentRespAreaList = change.value.document.filterDescendants(isOfCurrentType);
|
|
153
188
|
const oldRespAreaList = editor.value.document.filterDescendants(isOfCurrentType);
|
|
154
189
|
|
|
155
|
-
|
|
156
|
-
toolbar.disabled = true;
|
|
157
|
-
} else {
|
|
158
|
-
toolbar.disabled = false;
|
|
159
|
-
}
|
|
190
|
+
toolbar.disabled = currentRespAreaList.size >= opts.maxResponseAreas;
|
|
160
191
|
|
|
161
192
|
const arrayToFilter = oldRespAreaList.size > currentRespAreaList.size ? oldRespAreaList : currentRespAreaList;
|
|
162
193
|
const arrayToUseForFilter = arrayToFilter === oldRespAreaList ? currentRespAreaList : oldRespAreaList;
|
|
@@ -205,6 +236,16 @@ export const serialization = {
|
|
|
205
236
|
value: el.dataset.value,
|
|
206
237
|
},
|
|
207
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
|
+
};
|
|
208
249
|
case 'drag_in_the_blank':
|
|
209
250
|
return {
|
|
210
251
|
object: 'inline',
|
|
@@ -235,6 +276,11 @@ export const serialization = {
|
|
|
235
276
|
|
|
236
277
|
return <span data-type="explicit_constructed_response" data-index={data.index} data-value={data.value} />;
|
|
237
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
|
+
}
|
|
238
284
|
case 'drag_in_the_blank': {
|
|
239
285
|
const data = object.data.toJSON();
|
|
240
286
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Chevron } from '
|
|
3
|
+
import { Chevron } from '@pie-lib/icons';
|
|
4
4
|
|
|
5
5
|
const InlineDropdown = ({ attributes, selectedItem }) => {
|
|
6
6
|
// TODO: Investigate
|
|
@@ -27,6 +27,7 @@ const InlineDropdown = ({ attributes, selectedItem }) => {
|
|
|
27
27
|
boxSizing: 'border-box',
|
|
28
28
|
borderRadius: '3px',
|
|
29
29
|
position: 'relative',
|
|
30
|
+
alignItems: 'center',
|
|
30
31
|
}}
|
|
31
32
|
>
|
|
32
33
|
<div
|
|
@@ -36,12 +37,18 @@ const InlineDropdown = ({ attributes, selectedItem }) => {
|
|
|
36
37
|
padding: '0 25px 0 8px',
|
|
37
38
|
whiteSpace: 'nowrap',
|
|
38
39
|
textOverflow: 'ellipsis',
|
|
39
|
-
lineHeight: '35px',
|
|
40
40
|
}}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
>
|
|
42
|
+
<span
|
|
43
|
+
style={{
|
|
44
|
+
display: 'inline-block',
|
|
45
|
+
verticalAlign: 'middle',
|
|
46
|
+
}}
|
|
47
|
+
dangerouslySetInnerHTML={{
|
|
48
|
+
__html: html,
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
45
52
|
<Chevron
|
|
46
53
|
direction="down"
|
|
47
54
|
style={{
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { withStyles } from '@material-ui/core/styles';
|
|
4
|
+
import { mq } from '@pie-lib/math-input';
|
|
5
|
+
|
|
6
|
+
const MathTemplated = ({ attributes, value, classes, keyToDisplay }) => (
|
|
7
|
+
<span {...attributes} className={classes.spanContainer}>
|
|
8
|
+
<div className={classes.responseBox}>{keyToDisplay}</div>
|
|
9
|
+
<div className={classes.mathBlock}>
|
|
10
|
+
<mq.Static latex={value} />
|
|
11
|
+
</div>
|
|
12
|
+
</span>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
MathTemplated.propTypes = {
|
|
16
|
+
attributes: PropTypes.object,
|
|
17
|
+
classes: PropTypes.object.isRequired,
|
|
18
|
+
value: PropTypes.string,
|
|
19
|
+
keyToDisplay: PropTypes.string,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const styles = (theme) => ({
|
|
23
|
+
responseBox: {
|
|
24
|
+
background: theme.palette.grey['A100'],
|
|
25
|
+
color: theme.palette.grey['A700'],
|
|
26
|
+
display: 'inline-flex',
|
|
27
|
+
borderRight: '2px solid #C0C3CF',
|
|
28
|
+
boxSizing: 'border-box',
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
fontSize: '12px',
|
|
31
|
+
minHeight: '36px',
|
|
32
|
+
height: '100%',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
fontFamily: 'Symbola, Times New Roman, serif',
|
|
35
|
+
padding: '0 2px',
|
|
36
|
+
},
|
|
37
|
+
spanContainer: {
|
|
38
|
+
display: 'inline-flex',
|
|
39
|
+
border: '1px solid #C0C3CF',
|
|
40
|
+
margin: '1px 5px',
|
|
41
|
+
cursor: 'pointer',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
justifyContent: 'center',
|
|
44
|
+
minWidth: '50px',
|
|
45
|
+
minHeight: '36px',
|
|
46
|
+
height: 'fit-content',
|
|
47
|
+
},
|
|
48
|
+
mathBlock: {
|
|
49
|
+
flex: 8,
|
|
50
|
+
color: 'var(--pie-text, black)',
|
|
51
|
+
padding: '4px !important',
|
|
52
|
+
display: 'flex',
|
|
53
|
+
alignItems: 'center',
|
|
54
|
+
justifyContent: 'center',
|
|
55
|
+
backgroundColor: 'var(--pie-background, rgba(255, 255, 255, 0))',
|
|
56
|
+
'& > .mq-math-mode sup.mq-nthroot': {
|
|
57
|
+
fontSize: '70% !important',
|
|
58
|
+
verticalAlign: '1em !important',
|
|
59
|
+
},
|
|
60
|
+
'& > .mq-math-mode .mq-sqrt-stem': {
|
|
61
|
+
borderTop: '0.07em solid',
|
|
62
|
+
marginLeft: '-1.5px',
|
|
63
|
+
marginTop: '-2px !important',
|
|
64
|
+
paddingTop: '5px !important',
|
|
65
|
+
},
|
|
66
|
+
'& .mq-overarrow-inner': {
|
|
67
|
+
paddingTop: '0 !important',
|
|
68
|
+
border: 'none !important',
|
|
69
|
+
},
|
|
70
|
+
'& .mq-overarrow.mq-arrow-both': {
|
|
71
|
+
marginTop: '0px',
|
|
72
|
+
minWidth: '1.23em',
|
|
73
|
+
'& *': {
|
|
74
|
+
lineHeight: '1 !important',
|
|
75
|
+
},
|
|
76
|
+
'&:before': {
|
|
77
|
+
top: '-0.4em',
|
|
78
|
+
left: '-1px',
|
|
79
|
+
},
|
|
80
|
+
'&:after': {
|
|
81
|
+
top: '0px !important',
|
|
82
|
+
position: 'absolute !important',
|
|
83
|
+
right: '-2px',
|
|
84
|
+
},
|
|
85
|
+
'&.mq-empty:after': {
|
|
86
|
+
top: '-0.45em',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
'& .mq-overarrow.mq-arrow-right': {
|
|
90
|
+
'&:before': {
|
|
91
|
+
top: '-0.4em',
|
|
92
|
+
right: '-1px',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
'& .mq-overarrow-inner-right': {
|
|
96
|
+
display: 'none !important',
|
|
97
|
+
},
|
|
98
|
+
'& .mq-overarrow-inner-left': {
|
|
99
|
+
display: 'none !important',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export default withStyles(styles)(MathTemplated);
|
|
@@ -42,6 +42,14 @@ export const defaultECR = (index) =>
|
|
|
42
42
|
index,
|
|
43
43
|
},
|
|
44
44
|
});
|
|
45
|
+
export const defaultMT = (index) =>
|
|
46
|
+
Inline.create({
|
|
47
|
+
type: 'math_templated',
|
|
48
|
+
isVoid: true,
|
|
49
|
+
data: {
|
|
50
|
+
index,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
45
53
|
|
|
46
54
|
export const defaultDIB = (opts, index) =>
|
|
47
55
|
Inline.create({
|
|
@@ -69,6 +77,9 @@ export const getDefaultElement = (opts, index) => {
|
|
|
69
77
|
case 'explicit-constructed-response':
|
|
70
78
|
return defaultECR(index);
|
|
71
79
|
|
|
80
|
+
case 'math-templated':
|
|
81
|
+
return defaultMT(index);
|
|
82
|
+
|
|
72
83
|
case 'drag-in-the-blank':
|
|
73
84
|
return defaultDIB(opts, index);
|
|
74
85
|
|