@pie-element/inline-dropdown 8.0.2-esm.0 → 8.1.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/esm/configure.js DELETED
@@ -1,1552 +0,0 @@
1
- import { ModelUpdatedEvent, InsertImageEvent, DeleteImageEvent, InsertSoundEvent, DeleteSoundEvent } from '@pie-framework/pie-configure-events';
2
- import React from 'react';
3
- import ReactDOM from 'react-dom';
4
- import PropTypes from 'prop-types';
5
- import EditableHtml, { ALL_PLUGINS } from '@pie-lib/editable-html';
6
- import { layout, InputContainer, AlertDialog, settings } from '@pie-lib/config-ui';
7
- import { renderMath } from '@pie-lib/math-rendering';
8
- import { color } from '@pie-lib/render-ui';
9
- import cloneDeep from 'lodash/cloneDeep';
10
- import isEqual from 'lodash/isEqual';
11
- import isUndefined from 'lodash/isUndefined';
12
- import isEmpty from 'lodash/isEmpty';
13
- import reduce from 'lodash/reduce';
14
- import max from 'lodash/max';
15
- import { withStyles } from '@material-ui/core/styles';
16
- import Tooltip from '@material-ui/core/Tooltip';
17
- import Typography from '@material-ui/core/Typography';
18
- import ExpansionPanel from '@material-ui/core/ExpansionPanel';
19
- import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
20
- import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
21
- import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
22
- import Info from '@material-ui/icons/Info';
23
- import classnames from 'classnames';
24
- import AddIcon from '@material-ui/icons/Add';
25
- import CheckIcon from '@material-ui/icons/Check';
26
- import CloseIcon from '@material-ui/icons/Close';
27
- import EditIcon from '@material-ui/icons/Edit';
28
- import IconButton from '@material-ui/core/IconButton';
29
- import debug from 'debug';
30
- import defaults from 'lodash/defaults';
31
- import escape from 'lodash/escape';
32
-
33
- function _extends() {
34
- _extends = Object.assign || function (target) {
35
- for (var i = 1; i < arguments.length; i++) {
36
- var source = arguments[i];
37
-
38
- for (var key in source) {
39
- if (Object.prototype.hasOwnProperty.call(source, key)) {
40
- target[key] = source[key];
41
- }
42
- }
43
- }
44
-
45
- return target;
46
- };
47
-
48
- return _extends.apply(this, arguments);
49
- }
50
-
51
- const generateValidationMessage = config => {
52
- const {
53
- maxResponseAreas,
54
- maxResponseAreaChoices
55
- } = config;
56
- const responseAreasMessage = '\nThere should be at least 1 ' + (maxResponseAreas ? `and at most ${maxResponseAreas} ` : '') + 'response area' + (maxResponseAreas ? 's' : '') + ' defined.' + (maxResponseAreaChoices ? `\nThere should be at most ${maxResponseAreaChoices} choices defined per response area.` : '');
57
- const message = 'Validation requirements:' + responseAreasMessage;
58
- return message;
59
- };
60
- const getPluginProps = (props = {}, baseInputConfiguration = {}) => _extends({}, baseInputConfiguration, props);
61
-
62
- class MenuItemComp extends React.Component {
63
- constructor(...args) {
64
- super(...args);
65
-
66
- this.onRemoveClick = e => {
67
- const {
68
- onRemoveChoice
69
- } = this.props;
70
- e.preventDefault();
71
- e.stopPropagation();
72
- onRemoveChoice();
73
- };
74
-
75
- this.onEditClick = e => {
76
- const {
77
- onEditChoice
78
- } = this.props;
79
- e.preventDefault();
80
- e.stopPropagation();
81
- onEditChoice();
82
- };
83
- }
84
-
85
- render() {
86
- const {
87
- classes,
88
- correct,
89
- onClick,
90
- value
91
- } = this.props;
92
- return /*#__PURE__*/React.createElement("div", {
93
- className: classes.wrapper
94
- }, correct && /*#__PURE__*/React.createElement("div", {
95
- className: classes.selectedIcon,
96
- onClick: onClick
97
- }, /*#__PURE__*/React.createElement(CheckIcon, {
98
- fontSize: "inherit"
99
- })), /*#__PURE__*/React.createElement("div", {
100
- className: classnames(classes.valueHolder, {
101
- [classes.correct]: correct
102
- }),
103
- onClick: onClick,
104
- dangerouslySetInnerHTML: {
105
- __html: value
106
- }
107
- }), /*#__PURE__*/React.createElement("div", {
108
- className: classes.actionButtons
109
- }, /*#__PURE__*/React.createElement(IconButton, {
110
- className: classes.iconButton,
111
- onClick: this.onEditClick,
112
- size: "small",
113
- "aria-label": "Edit"
114
- }, /*#__PURE__*/React.createElement(EditIcon, {
115
- fontSize: "inherit"
116
- })), /*#__PURE__*/React.createElement(IconButton, {
117
- className: classes.iconButton,
118
- onClick: this.onRemoveClick,
119
- size: "small",
120
- "aria-label": "Remove"
121
- }, /*#__PURE__*/React.createElement(CloseIcon, {
122
- fontSize: "inherit"
123
- }))));
124
- }
125
-
126
- }
127
-
128
- MenuItemComp.propTypes = {
129
- classes: PropTypes.object.isRequired,
130
- correct: PropTypes.bool.isRequired,
131
- onClick: PropTypes.func.isRequired,
132
- onRemoveChoice: PropTypes.func.isRequired,
133
- onEditChoice: PropTypes.func.isRequired,
134
- value: PropTypes.string.isRequired
135
- };
136
- const MenuItem = withStyles(theme => ({
137
- wrapper: {
138
- display: 'flex',
139
- alignItems: 'flex-start',
140
- position: 'relative',
141
- background: theme.palette.common.white,
142
- borderBottom: `1px solid ${theme.palette.grey[400]}`,
143
- '&:last-child': {
144
- borderRadius: '0 0 4px 4px'
145
- }
146
- },
147
- correct: {
148
- background: color.correctSecondary()
149
- },
150
- actionButtons: {
151
- margin: theme.spacing.unit / 2,
152
- display: 'flex'
153
- },
154
- iconButton: {
155
- fontSize: theme.typography.fontSize,
156
- padding: theme.spacing.unit / 2,
157
- color: theme.palette.common.black
158
- },
159
- selectedIcon: {
160
- display: 'flex',
161
- justifyContent: 'center',
162
- color: theme.palette.common.white,
163
- fontSize: theme.typography.fontSize,
164
- fontStyle: 'normal',
165
- position: 'absolute',
166
- transform: 'translate(0, -50%)',
167
- backgroundColor: color.correct(),
168
- borderRadius: '50%',
169
- top: theme.spacing.unit * 2,
170
- left: theme.spacing.unit,
171
- zIndex: 3
172
- },
173
- valueHolder: {
174
- flex: 1,
175
- padding: theme.spacing.unit * 0.75,
176
- paddingLeft: theme.spacing.unit * 3.5
177
- }
178
- }))(MenuItemComp);
179
-
180
- const findSlateNode = key => {
181
- return window.document.querySelector('[data-key="' + key + '"]');
182
- };
183
-
184
- const createElementFromHTML$2 = htmlString => {
185
- const div = document.createElement('div');
186
- div.innerHTML = (htmlString || '').trim();
187
- return div;
188
- };
189
-
190
- class RespAreaToolbar extends React.Component {
191
- constructor(...args) {
192
- super(...args);
193
- this.clickedInside = false;
194
- this.preventDone = false;
195
- this.state = {
196
- respAreaMarkup: '',
197
- editedChoiceIndex: -1
198
- };
199
-
200
- this.onRespAreaChange = respAreaMarkup => {
201
- this.setState({
202
- respAreaMarkup
203
- });
204
- };
205
-
206
- this.onAddChoice = () => {
207
- if (this.editorRef) {
208
- this.editorRef.finishEditing();
209
- }
210
- };
211
-
212
- this.onDone = val => {
213
- var _choices$editedChoice;
214
-
215
- const {
216
- choices,
217
- node,
218
- value,
219
- onAddChoice,
220
- onToolbarDone
221
- } = this.props;
222
- const {
223
- editedChoiceIndex
224
- } = this.state;
225
- const onlyText = createElementFromHTML$2(val).textContent.trim();
226
-
227
- if (editedChoiceIndex >= 0 && choices != null && (_choices$editedChoice = choices[editedChoiceIndex]) != null && _choices$editedChoice.correct) {
228
- const update = _extends({}, node.data.toJSON(), {
229
- value: val
230
- });
231
-
232
- const change = value.change().setNodeByKey(node.key, {
233
- data: update
234
- });
235
- onToolbarDone(change, false);
236
- }
237
-
238
- if (!isEmpty(onlyText)) {
239
- onAddChoice(node.data.get('index'), val, editedChoiceIndex);
240
- }
241
-
242
- this.setState({
243
- editedChoiceIndex: -1
244
- });
245
- };
246
-
247
- this.onSelectChoice = (newValue, index) => {
248
- const {
249
- node,
250
- value,
251
- onToolbarDone,
252
- onSelectChoice
253
- } = this.props;
254
-
255
- const update = _extends({}, node.data.toJSON(), {
256
- value: newValue
257
- });
258
-
259
- const change = value.change().setNodeByKey(node.key, {
260
- data: update
261
- });
262
- const nextText = value.document.getNextText(node.key);
263
- change.moveFocusTo(nextText.key, 0).moveAnchorTo(nextText.key, 0);
264
- onToolbarDone(change, false);
265
- onSelectChoice(index);
266
- };
267
-
268
- this.onRemoveChoice = (val, index) => {
269
- const {
270
- node,
271
- value,
272
- onToolbarDone,
273
- onRemoveChoice
274
- } = this.props;
275
-
276
- if (isEqual(val, node.data.get('value'))) {
277
- const update = _extends({}, node.data.toJSON(), {
278
- value: null
279
- });
280
-
281
- const change = value.change().setNodeByKey(node.key, {
282
- data: update
283
- });
284
- onToolbarDone(change, false);
285
- }
286
-
287
- onRemoveChoice(index);
288
- };
289
-
290
- this.onEditChoice = (val, index) => {
291
- this.onRespAreaChange(val);
292
- this.setState({
293
- editedChoiceIndex: index
294
- });
295
- };
296
-
297
- this.onKeyDown = event => {
298
- if (event.key === 'Enter') {
299
- this.preventDone = false;
300
- this.onAddChoice(); // Cancelling event
301
-
302
- return false;
303
- }
304
- };
305
-
306
- this.onBlur = () => {
307
- if (this.clickedInside) {
308
- this.clickedInside = false;
309
- return;
310
- }
311
-
312
- const {
313
- node,
314
- choices,
315
- onCheck,
316
- onToolbarDone,
317
- value
318
- } = this.props;
319
- const correctResponse = (choices || []).find(choice => choice.correct);
320
- this.onAddChoice();
321
-
322
- if (!choices || choices && choices.length < 2 || !correctResponse) {
323
- onCheck(() => {
324
- const change = value.change();
325
- change.removeNodeByKey(node.get('key'));
326
- onToolbarDone(change, false);
327
- });
328
- }
329
- };
330
-
331
- this.onClickInside = () => {
332
- this.clickedInside = true;
333
- };
334
-
335
- this.focusInput = () => {
336
- // we need to focus the input so that math is saved even without pressing the green checkmark
337
- const slateEditorRef = this.editorRef && this.editorRef.rootRef && this.editorRef.rootRef.slateEditor;
338
- const inputRef = slateEditorRef && slateEditorRef.editorRef && slateEditorRef.editorRef.element;
339
-
340
- if (inputRef) {
341
- inputRef.focus();
342
- }
343
- };
344
- }
345
-
346
- componentDidMount() {
347
- const {
348
- node
349
- } = this.props;
350
- const domNode = findSlateNode(node.key);
351
-
352
- if (domNode) {
353
- //eslint-disable-next-line
354
- const domNodeRect = domNode.getBoundingClientRect();
355
- const editor = domNode.closest('[data-slate-editor]');
356
- const editorRect = editor.getBoundingClientRect();
357
- const top = domNodeRect.top - editorRect.top;
358
- const left = domNodeRect.left - editorRect.left;
359
- this.setState({
360
- toolbarStyle: {
361
- position: 'absolute',
362
- top: `${top + domNodeRect.height + 60}px`,
363
- left: `${left + 25}px`
364
- }
365
- });
366
- }
367
- }
368
-
369
- componentDidUpdate() {
370
- //eslint-disable-next-line
371
- const domNode = ReactDOM.findDOMNode(this);
372
- renderMath(domNode);
373
- }
374
-
375
- render() {
376
- const {
377
- classes,
378
- choices,
379
- spellCheck,
380
- uploadSoundSupport,
381
- mathMlOptions = {},
382
- baseInputConfiguration = {},
383
- responseAreaInputConfiguration = {}
384
- } = this.props;
385
- const {
386
- respAreaMarkup,
387
- toolbarStyle
388
- } = this.state;
389
-
390
- if (!toolbarStyle) {
391
- return null;
392
- }
393
-
394
- return /*#__PURE__*/React.createElement("div", {
395
- className: classes.responseContainer,
396
- style: _extends({}, toolbarStyle, {
397
- backgroundColor: '#E0E1E6'
398
- }),
399
- onMouseDown: this.onClickInside
400
- }, /*#__PURE__*/React.createElement("div", {
401
- className: classes.itemBuilder
402
- }, /*#__PURE__*/React.createElement(EditableHtml, {
403
- ref: ref => {
404
- if (ref) {
405
- this.editorRef = ref;
406
- }
407
- },
408
- autoFocus: true,
409
- autoSave: true,
410
- className: classes.respArea,
411
- toolbarOpts: {
412
- position: 'top',
413
- alwaysVisible: false,
414
- showDone: false,
415
- doneOn: 'blur'
416
- },
417
- markup: respAreaMarkup,
418
- onKeyDown: this.onKeyDown,
419
- languageCharactersProps: [{
420
- language: 'spanish'
421
- }, {
422
- language: 'special'
423
- }],
424
- onChange: respAreaMarkup => {
425
- if (this.preventDone) {
426
- return;
427
- }
428
-
429
- this.onRespAreaChange(respAreaMarkup);
430
- },
431
- onDone: val => {
432
- if (this.preventDone) {
433
- return;
434
- }
435
-
436
- this.onDone(val);
437
- },
438
- onBlur: e => {
439
- if (!e.relatedTarget) {
440
- return;
441
- }
442
-
443
- const isInInsertCharacter = !!(e.relatedTarget && e.relatedTarget.closest('.insert-character-dialog'));
444
- const isInDoneButton = !!(e.relatedTarget && e.relatedTarget.closest('[aria-label="Done"]'));
445
- this.preventDone = isInInsertCharacter || isInDoneButton;
446
-
447
- if (isInInsertCharacter || isInDoneButton) {
448
- this.clickedInside = true;
449
- }
450
-
451
- this.onBlur(e);
452
- },
453
- placeholder: "Add Choice",
454
- pluginProps: getPluginProps(responseAreaInputConfiguration == null ? void 0 : responseAreaInputConfiguration.inputConfiguration, baseInputConfiguration),
455
- spellCheck: spellCheck,
456
- uploadSoundSupport: uploadSoundSupport,
457
- mathMlOptions: mathMlOptions
458
- }), /*#__PURE__*/React.createElement(IconButton, {
459
- className: classes.addButton,
460
- onMouseDown: () => this.focusInput(),
461
- onClick: () => this.onAddChoice(),
462
- size: "small",
463
- "aria-label": "Add"
464
- }, /*#__PURE__*/React.createElement(AddIcon, {
465
- fontSize: "inherit"
466
- }))), choices && /*#__PURE__*/React.createElement("div", {
467
- className: classes.choicesHolder
468
- }, choices.map(({
469
- label,
470
- correct
471
- }, index) => /*#__PURE__*/React.createElement(MenuItem, {
472
- key: index,
473
- onClick: () => this.onSelectChoice(label, index),
474
- onRemoveChoice: () => this.onRemoveChoice(label, index),
475
- onEditChoice: () => this.onEditChoice(label, index),
476
- value: label,
477
- correct: correct
478
- }))));
479
- }
480
-
481
- }
482
- RespAreaToolbar.propTypes = {
483
- classes: PropTypes.object,
484
- node: PropTypes.object,
485
- uploadSoundSupport: PropTypes.object,
486
- onDone: PropTypes.func,
487
- choices: PropTypes.array,
488
- onAddChoice: PropTypes.func.isRequired,
489
- onCheck: PropTypes.func,
490
- onRemoveChoice: PropTypes.func.isRequired,
491
- onSelectChoice: PropTypes.func.isRequired,
492
- onToolbarDone: PropTypes.func.isRequired,
493
- value: PropTypes.shape({
494
- change: PropTypes.func.isRequired,
495
- document: PropTypes.shape({
496
- getNextText: PropTypes.func.isRequired
497
- })
498
- }),
499
- spellCheck: PropTypes.bool
500
- };
501
- const StyledRespAreaToolbar = withStyles(theme => ({
502
- responseContainer: {
503
- boxShadow: theme.shadows[2],
504
- borderRadius: '4px',
505
- width: '400px'
506
- },
507
- respArea: {
508
- borderRadius: '4px',
509
- backgroundColor: theme.palette.common.white,
510
- '& [data-slate-editor="true"]': {
511
- minHeight: 'initial !important'
512
- }
513
- },
514
- addButton: {
515
- fontSize: theme.typography.fontSize + 2,
516
- padding: theme.spacing.unit / 2,
517
- color: theme.palette.common.black,
518
- position: 'absolute',
519
- top: '50%',
520
- right: theme.spacing.unit * 2,
521
- transform: 'translate(0, -50%)'
522
- },
523
- choicesHolder: {
524
- display: 'flex',
525
- flexDirection: 'column',
526
- '& > div:last-child': {
527
- border: 'none'
528
- }
529
- },
530
- itemBuilder: {
531
- padding: theme.spacing.unit / 2,
532
- position: 'relative'
533
- }
534
- }))(RespAreaToolbar);
535
-
536
- const styles$1 = theme => ({
537
- responseArea: {
538
- paddingBottom: theme.spacing.unit * 2.5
539
- },
540
- errorText: {
541
- fontSize: theme.typography.fontSize - 2,
542
- color: theme.palette.error.main,
543
- paddingTop: theme.spacing.unit
544
- }
545
- });
546
-
547
- class ResponseAreaComponent extends React.Component {
548
- componentDidMount() {
549
- // eslint-disable-next-line react/no-find-dom-node
550
- const domNode = ReactDOM.findDOMNode(this);
551
- renderMath(domNode);
552
- }
553
-
554
- render() {
555
- const {
556
- editableHtmlProps,
557
- responseAreasError,
558
- responseAreaChoicesError,
559
- classes
560
- } = this.props;
561
- return /*#__PURE__*/React.createElement("div", {
562
- className: classes.responseArea
563
- }, /*#__PURE__*/React.createElement(EditableHtml, editableHtmlProps), responseAreasError && /*#__PURE__*/React.createElement("div", {
564
- className: classes.errorText
565
- }, responseAreasError), responseAreaChoicesError && /*#__PURE__*/React.createElement("div", {
566
- className: classes.errorText
567
- }, responseAreaChoicesError));
568
- }
569
-
570
- }
571
-
572
- ResponseAreaComponent.propTypes = {
573
- editableHtmlProps: PropTypes.object.isRequired,
574
- classes: PropTypes.object.isRequired,
575
- responseAreasError: PropTypes.string,
576
- responseAreaChoicesError: PropTypes.string
577
- };
578
- var ResponseAreaComponent$1 = withStyles(styles$1)(ResponseAreaComponent);
579
-
580
- const {
581
- toggle,
582
- Panel,
583
- dropdown
584
- } = settings;
585
-
586
- const styles = theme => ({
587
- promptHolder: {
588
- width: '100%',
589
- paddingTop: theme.spacing.unit * 2,
590
- marginBottom: theme.spacing.unit * 2
591
- },
592
- choiceRationaleHolder: {
593
- width: '100%',
594
- paddingTop: theme.spacing.unit / 2,
595
- marginBottom: theme.spacing.unit * 2
596
- },
597
- markup: {
598
- minHeight: '100px',
599
- width: '100%',
600
- '& [data-slate-editor="true"]': {
601
- minHeight: '100px'
602
- }
603
- },
604
- choiceConfiguration: {
605
- paddingTop: theme.spacing.unit * 2,
606
- paddingBottom: theme.spacing.unit * 2
607
- },
608
- text: {
609
- fontSize: theme.typography.fontSize + 2,
610
- marginRight: theme.spacing.unit
611
- },
612
- rationaleLabel: {
613
- display: 'flex',
614
- alignItems: 'center',
615
- whiteSpace: 'break-spaces',
616
- color: color.disabled(),
617
- padding: 0,
618
- fontSize: theme.typography.fontSize - 2,
619
- lineHeight: 1
620
- },
621
- rationaleChoices: {
622
- marginBottom: theme.spacing.unit * 2.5
623
- },
624
- panelDetails: {
625
- display: 'block',
626
- paddingTop: 0,
627
- paddingBottom: 0
628
- },
629
- flexContainer: {
630
- display: 'flex',
631
- alignItems: 'center',
632
- marginBottom: theme.spacing.unit
633
- },
634
- tooltip: {
635
- fontSize: theme.typography.fontSize - 2,
636
- whiteSpace: 'pre',
637
- maxWidth: '500px'
638
- },
639
- errorText: {
640
- fontSize: theme.typography.fontSize - 2,
641
- color: theme.palette.error.main,
642
- paddingTop: theme.spacing.unit
643
- }
644
- });
645
-
646
- const createElementFromHTML$1 = htmlString => {
647
- const div = document.createElement('div');
648
- div.innerHTML = (htmlString || '').trim();
649
- return div;
650
- };
651
-
652
- class Main extends React.Component {
653
- constructor(...args) {
654
- super(...args);
655
- this.state = {
656
- warning: {
657
- open: false
658
- }
659
- };
660
-
661
- this.onModelChange = newVal => {
662
- this.props.onModelChanged(_extends({}, this.props.model, newVal));
663
- };
664
-
665
- this.onPromptChanged = prompt => {
666
- this.onModelChange({
667
- prompt
668
- });
669
- };
670
-
671
- this.onRationaleChanged = rationale => {
672
- this.onModelChange({
673
- rationale
674
- });
675
- };
676
-
677
- this.onChoiceRationaleChanged = (index, choice) => {
678
- const {
679
- model
680
- } = this.props;
681
- const indexOfChoice = model.choices && model.choices[index] && model.choices[index].findIndex(elem => elem.label === choice.label && elem.value === choice.value);
682
- model.choices[index] && model.choices[index].splice(indexOfChoice, 1, choice);
683
- this.onModelChange(model);
684
- };
685
-
686
- this.onTeacherInstructionsChanged = teacherInstructions => {
687
- this.onModelChange({
688
- teacherInstructions
689
- });
690
- };
691
-
692
- this.onMarkupChanged = slateMarkup => {
693
- this.onModelChange({
694
- slateMarkup
695
- });
696
- };
697
-
698
- this.onCheck = callback => {
699
- this.setState({
700
- warning: {
701
- open: true,
702
- text: 'Response areas with under 2 options or with no correct answers will be discarded.',
703
- onClose: () => {
704
- this.setState({
705
- warning: {
706
- open: false
707
- }
708
- });
709
- },
710
- onConfirm: () => {
711
- this.setState({
712
- warning: {
713
- open: false
714
- }
715
- }, callback);
716
- }
717
- }
718
- });
719
- };
720
-
721
- this.onChange = markup => {
722
- const {
723
- respAreaChoices
724
- } = this.state;
725
- const domMarkup = createElementFromHTML$1(markup);
726
- const allRespAreas = domMarkup.querySelectorAll('[data-type="inline_dropdown"]');
727
- const allChoices = {};
728
- allRespAreas.forEach(el => {
729
- allChoices[el.dataset.index] = el.dataset.value || '';
730
- });
731
- const existingRespAreaChoices = reduce(respAreaChoices, (obj, choices, key) => {
732
- if (!isUndefined(allChoices[key])) {
733
- obj[key] = respAreaChoices[key];
734
- }
735
-
736
- return obj;
737
- }, {});
738
- const newRespAreaChoices = {};
739
- let shouldWarn = false;
740
- allRespAreas.forEach((el, index) => {
741
- const newChoices = existingRespAreaChoices[el.dataset.index] || [];
742
-
743
- if (newChoices.length < 2 || !newChoices.find(c => c.correct)) {
744
- el.remove();
745
- shouldWarn = true;
746
- } else {
747
- newRespAreaChoices[index] = existingRespAreaChoices[el.dataset.index] || [];
748
- el.dataset.index = index;
749
- }
750
- });
751
-
752
- if (shouldWarn) {
753
- this.setState({
754
- warning: {
755
- open: true,
756
- text: 'Response areas with under 2 options or with no correct answers will be discarded.',
757
- onClose: () => {
758
- this.setState({
759
- warning: {
760
- open: false
761
- }
762
- });
763
- },
764
- onConfirm: () => {
765
- this.setState({
766
- warning: {
767
- open: false
768
- }
769
- }, () => this.onModelChange({
770
- choices: cloneDeep(newRespAreaChoices),
771
- slateMarkup: domMarkup.innerHTML
772
- }));
773
- }
774
- }
775
- });
776
- } else {
777
- this.onModelChange({
778
- choices: cloneDeep(newRespAreaChoices),
779
- slateMarkup: domMarkup.innerHTML
780
- });
781
- }
782
- };
783
-
784
- this.onAddChoice = (index, label, choiceIndex) => {
785
- var _respAreaChoices$inde;
786
-
787
- const {
788
- respAreaChoices
789
- } = this.state;
790
- const {
791
- maxResponseAreaChoices
792
- } = this.props.configuration;
793
-
794
- if (respAreaChoices[index] && respAreaChoices[index].length >= maxResponseAreaChoices) {
795
- this.setState({
796
- warning: {
797
- open: true,
798
- text: `There are only ${maxResponseAreaChoices} answers allowed per choice.`,
799
- onClose: undefined,
800
- onConfirm: () => {
801
- this.setState({
802
- warning: {
803
- open: false
804
- }
805
- });
806
- }
807
- }
808
- });
809
- return;
810
- }
811
-
812
- if (!respAreaChoices[index]) {
813
- respAreaChoices[index] = [];
814
- } // check for duplicate answer, but exclude the one that is currently edited
815
-
816
-
817
- if ((respAreaChoices[index] || []).find((r, idx) => r.label === label && idx !== choiceIndex)) {
818
- // show warning for duplicated answers
819
- this.setState({
820
- warning: {
821
- open: true,
822
- text: 'Duplicate answers are not allowed.',
823
- onClose: undefined,
824
- onConfirm: () => {
825
- this.setState({
826
- warning: {
827
- open: false
828
- }
829
- });
830
- }
831
- }
832
- });
833
- return;
834
- }
835
-
836
- if (choiceIndex >= 0 && (_respAreaChoices$inde = respAreaChoices[index]) != null && _respAreaChoices$inde[choiceIndex]) {
837
- // we need to update the choice label with the new value
838
- respAreaChoices[index][choiceIndex].label = label;
839
- } else {
840
- // add a new choice
841
- const value = respAreaChoices[index] && max(respAreaChoices[index].map(c => parseInt(c.value)).filter(val => !isNaN(val))) || 0;
842
- respAreaChoices[index].push({
843
- label,
844
- value: `${value + 1}`,
845
- correct: false
846
- });
847
- }
848
-
849
- this.onModelChange({
850
- choices: cloneDeep(respAreaChoices)
851
- });
852
- };
853
-
854
- this.onRemoveChoice = (respIndex, index) => {
855
- const {
856
- respAreaChoices
857
- } = this.state;
858
- respAreaChoices[respIndex].splice(index, 1);
859
- this.onModelChange({
860
- choices: cloneDeep(respAreaChoices)
861
- });
862
- };
863
-
864
- this.onSelectChoice = (respIndex, selectedIndex) => {
865
- const {
866
- respAreaChoices
867
- } = this.state;
868
- respAreaChoices[respIndex] = respAreaChoices[respIndex].map((choice, index) => _extends({}, choice, {
869
- correct: index === selectedIndex
870
- }));
871
- this.onModelChange({
872
- choices: cloneDeep(respAreaChoices)
873
- });
874
- };
875
- }
876
-
877
- componentDidMount() {
878
- const {
879
- model: {
880
- choices
881
- }
882
- } = this.props;
883
- this.setState({
884
- respAreaChoices: cloneDeep(choices)
885
- });
886
- }
887
-
888
- UNSAFE_componentWillReceiveProps(nProps) {
889
- const newState = {};
890
-
891
- if (!isEqual(nProps.model.choices, this.props.model.choices) || !isEqual(nProps.model.choices, this.state.respAreaChoices)) {
892
- newState.respAreaChoices = cloneDeep(nProps.model.choices);
893
- }
894
-
895
- if (!isEmpty(newState)) {
896
- this.setState(newState);
897
- }
898
- }
899
-
900
- componentDidUpdate() {
901
- //eslint-disable-next-line
902
- const domNode = ReactDOM.findDOMNode(this);
903
- renderMath(domNode);
904
- }
905
-
906
- render() {
907
- const {
908
- warning
909
- } = this.state;
910
- const {
911
- classes,
912
- model,
913
- configuration,
914
- onConfigurationChanged,
915
- imageSupport,
916
- uploadSoundSupport
917
- } = this.props;
918
- const {
919
- baseInputConfiguration = {},
920
- choiceRationale = {},
921
- contentDimensions = {},
922
- lockChoiceOrder = {},
923
- maxResponseAreas,
924
- maxImageWidth = {},
925
- maxImageHeight = {},
926
- partialScoring = {},
927
- prompt = {},
928
- rationale = {},
929
- settingsPanelDisabled,
930
- spellCheck = {},
931
- teacherInstructions = {},
932
- template = {},
933
- withRubric = {},
934
- mathMlOptions = {},
935
- language = {},
936
- languageChoices = {},
937
- responseAreaInputConfiguration = {}
938
- } = configuration || {};
939
- const {
940
- choiceRationaleEnabled,
941
- choices,
942
- errors,
943
- extraCSSRules,
944
- promptEnabled,
945
- rationaleEnabled,
946
- spellCheckEnabled,
947
- teacherInstructionsEnabled,
948
- toolbarEditorPosition
949
- } = model || {};
950
- const {
951
- prompt: promptError,
952
- rationale: rationaleError,
953
- responseAreasError,
954
- responseAreaChoicesError,
955
- teacherInstructions: teacherInstructionsError
956
- } = errors || {};
957
- const defaultImageMaxWidth = maxImageWidth && maxImageWidth.prompt;
958
- const defaultImageMaxHeight = maxImageHeight && maxImageHeight.prompt;
959
-
960
- const renderChoiceRationale = () => (Object.keys(choices) || []).map((key, index) => /*#__PURE__*/React.createElement("div", {
961
- key: key,
962
- className: classes.rationaleChoices
963
- }, /*#__PURE__*/React.createElement(ExpansionPanel, null, /*#__PURE__*/React.createElement(ExpansionPanelSummary, {
964
- expandIcon: /*#__PURE__*/React.createElement(ExpandMoreIcon, null)
965
- }, /*#__PURE__*/React.createElement(Typography, {
966
- className: classes.text
967
- }, `Rationale for response area #${index + 1}`)), /*#__PURE__*/React.createElement(ExpansionPanelDetails, {
968
- className: classes.panelDetails
969
- }, (choices[key] || []).map(choice => /*#__PURE__*/React.createElement(React.Fragment, {
970
- key: choice.label
971
- }, /*#__PURE__*/React.createElement("span", {
972
- className: classes.rationaleLabel,
973
- dangerouslySetInnerHTML: {
974
- __html: `${rationale.label} for ${choice.label} (${choice.correct ? 'correct' : 'incorrect'})`
975
- }
976
- }), /*#__PURE__*/React.createElement(InputContainer, {
977
- className: classes.choiceRationaleHolder
978
- }, /*#__PURE__*/React.createElement(EditableHtml, {
979
- className: classes.prompt,
980
- markup: choice.rationale || '',
981
- spellCheck: spellCheckEnabled,
982
- onChange: c => this.onChoiceRationaleChanged(key, _extends({}, choice, {
983
- rationale: c
984
- })),
985
- imageSupport: imageSupport,
986
- maxImageWidth: maxImageWidth && maxImageWidth.rationale || defaultImageMaxWidth,
987
- maxImageHeight: maxImageHeight && maxImageHeight.rationale || defaultImageMaxHeight,
988
- uploadSoundSupport: uploadSoundSupport,
989
- mathMlOptions: mathMlOptions
990
- }))))))));
991
-
992
- const toolbarOpts = {
993
- position: toolbarEditorPosition === 'top' ? 'top' : 'bottom'
994
- };
995
- const validationMessage = generateValidationMessage(configuration);
996
- const panelSettings = {
997
- partialScoring: partialScoring.settings && toggle(partialScoring.label),
998
- lockChoiceOrder: lockChoiceOrder.settings && toggle(lockChoiceOrder.label),
999
- 'language.enabled': language.settings && toggle(language.label, true),
1000
- language: language.settings && language.enabled && dropdown(languageChoices.label, languageChoices.options)
1001
- };
1002
- const panelProperties = {
1003
- teacherInstructionsEnabled: teacherInstructions.settings && toggle(teacherInstructions.label),
1004
- rationaleEnabled: rationale.settings && toggle(rationale.label),
1005
- choiceRationaleEnabled: choiceRationale.settings && toggle(choiceRationale.label),
1006
- promptEnabled: prompt.settings && toggle(prompt.label),
1007
- spellCheckEnabled: spellCheck.settings && toggle(spellCheck.label),
1008
- rubricEnabled: (withRubric == null ? void 0 : withRubric.settings) && toggle(withRubric == null ? void 0 : withRubric.label)
1009
- };
1010
-
1011
- const getPluginProps = (props = {}) => _extends({}, baseInputConfiguration, props);
1012
-
1013
- return /*#__PURE__*/React.createElement(layout.ConfigLayout, {
1014
- extraCSSRules: extraCSSRules,
1015
- dimensions: contentDimensions,
1016
- hideSettings: settingsPanelDisabled,
1017
- settings: /*#__PURE__*/React.createElement(Panel, {
1018
- model: model,
1019
- configuration: configuration,
1020
- onChangeModel: model => this.onModelChange(model),
1021
- onChangeConfiguration: configuration => onConfigurationChanged(configuration, true),
1022
- groups: {
1023
- Settings: panelSettings,
1024
- Properties: panelProperties
1025
- }
1026
- })
1027
- }, teacherInstructionsEnabled && /*#__PURE__*/React.createElement(InputContainer, {
1028
- label: teacherInstructions.label,
1029
- className: classes.promptHolder
1030
- }, /*#__PURE__*/React.createElement(EditableHtml, {
1031
- className: classes.prompt,
1032
- markup: model.teacherInstructions || '',
1033
- onChange: this.onTeacherInstructionsChanged,
1034
- imageSupport: imageSupport,
1035
- nonEmpty: false,
1036
- error: teacherInstructionsError,
1037
- toolbarOpts: toolbarOpts,
1038
- pluginProps: getPluginProps(teacherInstructions == null ? void 0 : teacherInstructions.inputConfiguration),
1039
- spellCheck: spellCheckEnabled,
1040
- maxImageWidth: maxImageWidth && maxImageWidth.teacherInstructions || defaultImageMaxWidth,
1041
- maxImageHeight: maxImageHeight && maxImageHeight.teacherInstructions || defaultImageMaxHeight,
1042
- uploadSoundSupport: uploadSoundSupport,
1043
- languageCharactersProps: [{
1044
- language: 'spanish'
1045
- }, {
1046
- language: 'special'
1047
- }],
1048
- mathMlOptions: mathMlOptions
1049
- }), teacherInstructionsError && /*#__PURE__*/React.createElement("div", {
1050
- className: classes.errorText
1051
- }, teacherInstructionsError)), promptEnabled && /*#__PURE__*/React.createElement(InputContainer, {
1052
- label: prompt.label,
1053
- className: classes.promptHolder
1054
- }, /*#__PURE__*/React.createElement(EditableHtml, {
1055
- className: classes.prompt,
1056
- markup: model.prompt,
1057
- onChange: this.onPromptChanged,
1058
- imageSupport: imageSupport,
1059
- nonEmpty: false,
1060
- disableUnderline: true,
1061
- error: promptError,
1062
- toolbarOpts: toolbarOpts,
1063
- pluginProps: getPluginProps(prompt == null ? void 0 : prompt.inputConfiguration),
1064
- spellCheck: spellCheckEnabled,
1065
- maxImageWidth: defaultImageMaxWidth,
1066
- maxImageHeight: defaultImageMaxHeight,
1067
- uploadSoundSupport: uploadSoundSupport,
1068
- languageCharactersProps: [{
1069
- language: 'spanish'
1070
- }, {
1071
- language: 'special'
1072
- }],
1073
- mathMlOptions: mathMlOptions
1074
- }), promptError && /*#__PURE__*/React.createElement("div", {
1075
- className: classes.errorText
1076
- }, promptError)), /*#__PURE__*/React.createElement("div", {
1077
- className: classes.flexContainer
1078
- }, /*#__PURE__*/React.createElement(Typography, {
1079
- className: classes.text,
1080
- component: 'div'
1081
- }, "Define Template, Choices, and Correct Responses"), /*#__PURE__*/React.createElement(Tooltip, {
1082
- classes: {
1083
- tooltip: classes.tooltip
1084
- },
1085
- disableFocusListener: true,
1086
- disableTouchListener: true,
1087
- placement: 'right',
1088
- title: validationMessage
1089
- }, /*#__PURE__*/React.createElement(Info, {
1090
- fontSize: 'small',
1091
- color: 'primary'
1092
- }))), /*#__PURE__*/React.createElement(ResponseAreaComponent$1, {
1093
- responseAreasError: responseAreasError,
1094
- responseAreaChoicesError: responseAreaChoicesError,
1095
- editableHtmlProps: {
1096
- pluginProps: getPluginProps(template == null ? void 0 : template.inputConfiguration),
1097
- activePlugins: ALL_PLUGINS,
1098
- toolbarOpts: {
1099
- position: 'top'
1100
- },
1101
- responseAreaProps: {
1102
- type: 'inline-dropdown',
1103
- options: {
1104
- duplicates: true
1105
- },
1106
- maxResponseAreas: maxResponseAreas,
1107
- respAreaToolbar: (node, value, onToolbarDone) => {
1108
- const {
1109
- respAreaChoices
1110
- } = this.state;
1111
- return () => /*#__PURE__*/React.createElement(StyledRespAreaToolbar, {
1112
- onAddChoice: this.onAddChoice,
1113
- onCheck: this.onCheck,
1114
- onRemoveChoice: index => this.onRemoveChoice(node.data.get('index'), index),
1115
- onSelectChoice: index => this.onSelectChoice(node.data.get('index'), index),
1116
- node: node,
1117
- value: value,
1118
- onToolbarDone: onToolbarDone,
1119
- choices: respAreaChoices[node.data.get('index')],
1120
- spellCheck: spellCheckEnabled,
1121
- uploadSoundSupport: uploadSoundSupport,
1122
- mathMlOptions: mathMlOptions,
1123
- baseInputConfiguration: baseInputConfiguration,
1124
- responseAreaInputConfiguration: responseAreaInputConfiguration
1125
- });
1126
- }
1127
- },
1128
- spellCheck: spellCheckEnabled,
1129
- className: classes.markup,
1130
- markup: model.slateMarkup || '',
1131
- onChange: this.onChange,
1132
- imageSupport: imageSupport,
1133
- disableImageAlignmentButtons: true,
1134
- disabled: false,
1135
- highlightShape: false,
1136
- error: responseAreasError,
1137
- uploadSoundSupport: uploadSoundSupport,
1138
- languageCharactersProps: [{
1139
- language: 'spanish'
1140
- }, {
1141
- language: 'special'
1142
- }],
1143
- mathMlOptions: mathMlOptions
1144
- }
1145
- }), choiceRationaleEnabled && renderChoiceRationale(), rationaleEnabled && /*#__PURE__*/React.createElement(InputContainer, {
1146
- label: rationale.label,
1147
- className: classes.promptHolder
1148
- }, /*#__PURE__*/React.createElement(EditableHtml, {
1149
- className: classes.prompt,
1150
- markup: model.rationale || '',
1151
- onChange: this.onRationaleChanged,
1152
- imageSupport: imageSupport,
1153
- error: rationaleError,
1154
- toolbarOpts: toolbarOpts,
1155
- pluginProps: getPluginProps(rationale == null ? void 0 : rationale.inputConfiguration),
1156
- spellCheck: spellCheckEnabled,
1157
- maxImageWidth: maxImageWidth && maxImageWidth.rationale || defaultImageMaxWidth,
1158
- maxImageHeight: maxImageHeight && maxImageHeight.rationale || defaultImageMaxHeight,
1159
- uploadSoundSupport: uploadSoundSupport,
1160
- languageCharactersProps: [{
1161
- language: 'spanish'
1162
- }, {
1163
- language: 'special'
1164
- }],
1165
- mathMlOptions: mathMlOptions
1166
- }), rationaleError && /*#__PURE__*/React.createElement("div", {
1167
- className: classes.errorText
1168
- }, rationaleError)), /*#__PURE__*/React.createElement(AlertDialog, {
1169
- open: warning.open,
1170
- title: "Warning",
1171
- text: warning.text,
1172
- onClose: warning.onClose,
1173
- onConfirm: warning.onConfirm
1174
- }));
1175
- }
1176
-
1177
- }
1178
- Main.propTypes = {
1179
- configuration: PropTypes.object.isRequired,
1180
- model: PropTypes.object.isRequired,
1181
- disableSidePanel: PropTypes.bool,
1182
- onModelChanged: PropTypes.func.isRequired,
1183
- onConfigurationChanged: PropTypes.func.isRequired,
1184
- classes: PropTypes.object.isRequired,
1185
- imageSupport: PropTypes.shape({
1186
- add: PropTypes.func.isRequired,
1187
- delete: PropTypes.func.isRequired
1188
- }),
1189
- uploadSoundSupport: PropTypes.shape({
1190
- add: PropTypes.func.isRequired,
1191
- delete: PropTypes.func.isRequired
1192
- })
1193
- };
1194
- const Styled = withStyles(styles)(Main);
1195
-
1196
- var sensibleDefaults = {
1197
- model: {
1198
- alternateResponse: {},
1199
- choiceRationaleEnabled: true,
1200
- choices: {},
1201
- disabled: false,
1202
- displayType: 'block',
1203
- markup: '',
1204
- mode: 'gather',
1205
- prompt: '',
1206
- promptEnabled: true,
1207
- rationale: '',
1208
- rationaleEnabled: true,
1209
- shuffle: true,
1210
- studentInstructionsEnabled: true,
1211
- teacherInstructions: '',
1212
- teacherInstructionsEnabled: true,
1213
- toolbarEditorPosition: 'bottom'
1214
- },
1215
- configuration: {
1216
- baseInputConfiguration: {
1217
- audio: {
1218
- disabled: false
1219
- },
1220
- video: {
1221
- disabled: false
1222
- },
1223
- image: {
1224
- disabled: false
1225
- },
1226
- h3: {
1227
- disabled: true
1228
- },
1229
- blockquote: {
1230
- disabled: true
1231
- },
1232
- textAlign: {
1233
- disabled: true
1234
- },
1235
- showParagraphs: {
1236
- disabled: false
1237
- },
1238
- separateParagraphs: {
1239
- disabled: true
1240
- }
1241
- },
1242
- prompt: {
1243
- settings: true,
1244
- label: 'Prompt',
1245
- required: false,
1246
- inputConfiguration: {
1247
- audio: {
1248
- disabled: false
1249
- },
1250
- video: {
1251
- disabled: false
1252
- },
1253
- image: {
1254
- disabled: false
1255
- }
1256
- }
1257
- },
1258
- responseAreaInputConfiguration: {
1259
- inputConfiguration: {
1260
- audio: {
1261
- disabled: true
1262
- },
1263
- video: {
1264
- disabled: true
1265
- },
1266
- image: {
1267
- disabled: true
1268
- },
1269
- table: {
1270
- disabled: true
1271
- },
1272
- ul_list: {
1273
- disabled: true
1274
- },
1275
- ol_list: {
1276
- disabled: true
1277
- }
1278
- }
1279
- },
1280
- settingsPanelDisabled: false,
1281
- spellCheck: {
1282
- label: 'Spellcheck',
1283
- settings: false,
1284
- enabled: true
1285
- },
1286
- lockChoiceOrder: {
1287
- settings: true,
1288
- label: 'Lock Choice Order'
1289
- },
1290
- partialScoring: {
1291
- settings: false,
1292
- label: 'Allow Partial Scoring'
1293
- },
1294
- rationale: {
1295
- settings: true,
1296
- label: 'Rationale',
1297
- required: false,
1298
- inputConfiguration: {
1299
- audio: {
1300
- disabled: false
1301
- },
1302
- video: {
1303
- disabled: false
1304
- },
1305
- image: {
1306
- disabled: false
1307
- }
1308
- }
1309
- },
1310
- teacherInstructions: {
1311
- settings: true,
1312
- label: 'Teacher Instructions',
1313
- required: false,
1314
- inputConfiguration: {
1315
- audio: {
1316
- disabled: false
1317
- },
1318
- video: {
1319
- disabled: false
1320
- },
1321
- image: {
1322
- disabled: false
1323
- }
1324
- }
1325
- },
1326
- template: {
1327
- inputConfiguration: {
1328
- audio: {
1329
- disabled: false
1330
- },
1331
- video: {
1332
- disabled: false
1333
- },
1334
- image: {
1335
- disabled: false
1336
- }
1337
- }
1338
- },
1339
- choiceRationale: {
1340
- settings: true,
1341
- label: 'Choice Rationale'
1342
- },
1343
- toolbarEditorPosition: {
1344
- settings: false,
1345
- label: 'Toolbar Editor Position'
1346
- },
1347
- maxResponseAreas: 10,
1348
- maxResponseAreaChoices: 10,
1349
- maxImageWidth: {
1350
- teacherInstructions: 300,
1351
- prompt: 300,
1352
- rationale: 300
1353
- },
1354
- maxImageHeight: {
1355
- teacherInstructions: 300,
1356
- prompt: 300,
1357
- rationale: 300
1358
- },
1359
- withRubric: {
1360
- settings: false,
1361
- label: 'Add Rubric'
1362
- },
1363
- mathMlOptions: {
1364
- mmlOutput: false,
1365
- mmlEditing: false
1366
- },
1367
- language: {
1368
- settings: false,
1369
- label: 'Specify Language',
1370
- enabled: false
1371
- },
1372
- languageChoices: {
1373
- label: 'Language Choices',
1374
- options: []
1375
- }
1376
- }
1377
- };
1378
-
1379
- const tSymbols = 'imes|riangle|an|heta|herefore'; // do not remove \n from \nthroot, \nparallel, \ncong, \napprox, \neq, \ne or \nsim
1380
-
1381
- const nSymbols = 'throot|parallel|cong|approx|eq|e|sim'; // match all \t and \n that are not part of math symbols that starts with \t or \n
1382
-
1383
- const matchTabAndNewLine = new RegExp(`(\\t(?!${tSymbols}))|(\\n(?!${nSymbols}))|(\\\\t(?!${tSymbols}))|(\\\\n(?!${nSymbols}))`, 'g');
1384
- const removeUnwantedCharacters = markup => markup.replace(matchTabAndNewLine, '').replace(/\\"/g, '"').replace(/\\\//g, '/');
1385
- const createElementFromHTML = htmlString => {
1386
- const div = document.createElement('div');
1387
- div.innerHTML = htmlString.trim();
1388
- return div;
1389
- };
1390
- const processMarkup = markup => {
1391
- const newMarkup = removeUnwantedCharacters(markup);
1392
- const slateMarkup = createElementFromHTML(newMarkup);
1393
- slateMarkup.querySelectorAll('[data-type="inline_dropdown"]').forEach(s => {
1394
- s.replaceWith(`{{${s.dataset.index}}}`);
1395
- });
1396
- return slateMarkup.innerHTML;
1397
- };
1398
- const REGEX = /\{\{(\d+)\}\}/g;
1399
- const createSlateMarkup = (markup, choices) => {
1400
- const newMarkup = removeUnwantedCharacters(markup);
1401
-
1402
- const createSelect = index => {
1403
- let correctChoice = choices[index] && choices[index].find(c => c.correct);
1404
-
1405
- if (!correctChoice || !correctChoice.value) {
1406
- correctChoice = {
1407
- id: '',
1408
- value: '',
1409
- label: ''
1410
- };
1411
- }
1412
-
1413
- return `<span data-type="inline_dropdown" data-index="${index}" data-value="${escape(correctChoice.label)}"></span>`;
1414
- };
1415
-
1416
- return newMarkup.replace(REGEX, (match, g) => {
1417
- return createSelect(g);
1418
- });
1419
- };
1420
-
1421
- const log = debug('multiple-choice:configure');
1422
- class InlineDropdown extends HTMLElement {
1423
- constructor() {
1424
- super();
1425
- this._model = InlineDropdown.prepareModel();
1426
- this._configuration = sensibleDefaults.configuration;
1427
- this.onModelChanged = this.onModelChanged.bind(this);
1428
- this.onConfigurationChanged = this.onConfigurationChanged.bind(this);
1429
- }
1430
-
1431
- set model(s) {
1432
- this._model = InlineDropdown.prepareModel(s);
1433
-
1434
- this._render();
1435
- }
1436
-
1437
- set configuration(c) {
1438
- var _c$language;
1439
-
1440
- this._configuration = defaults(c, sensibleDefaults.configuration); // if language:enabled is true, then the corresponding default item model should include a language value;
1441
- // if it is false, then the language field should be omitted from the item model.
1442
- // if a default item model includes a language value (e.g., en_US) and the corresponding authoring view settings have language:settings = true,
1443
- // then (a) language:enabled should also be true, and (b) that default language value should be represented in languageChoices[] (as a key).
1444
-
1445
- if ((_c$language = c.language) != null && _c$language.enabled) {
1446
- var _c$languageChoices, _c$languageChoices$op;
1447
-
1448
- if ((_c$languageChoices = c.languageChoices) != null && (_c$languageChoices$op = _c$languageChoices.options) != null && _c$languageChoices$op.length) {
1449
- this._model.language = c.languageChoices.options[0].value;
1450
- }
1451
- } else if (c.language.settings && this._model.language) {
1452
- this._configuration.language.enabled = true;
1453
-
1454
- if (!this._configuration.languageChoices.options || !this._configuration.languageChoices.options.length) {
1455
- this._configuration.languageChoices.options = [];
1456
- } // check if the language is already included in the languageChoices.options array
1457
- // and if not, then add it.
1458
-
1459
-
1460
- if (!this._configuration.languageChoices.options.find(option => option.value === this._model.language)) {
1461
- this._configuration.languageChoices.options.push({
1462
- value: this._model.language,
1463
- label: this._model.language
1464
- });
1465
- }
1466
- } else {
1467
- delete this._model.language;
1468
- }
1469
-
1470
- this._render();
1471
- }
1472
-
1473
- set disableSidePanel(s) {
1474
- this._disableSidePanel = s;
1475
-
1476
- this._render();
1477
- }
1478
-
1479
- dispatchModelUpdated(reset) {
1480
- const resetValue = !!reset;
1481
- this.dispatchEvent(new ModelUpdatedEvent(this._model, resetValue));
1482
- }
1483
-
1484
- onModelChanged(m, reset) {
1485
- this._model = InlineDropdown.prepareModel(m);
1486
-
1487
- this._render();
1488
-
1489
- this.dispatchModelUpdated(reset);
1490
- }
1491
-
1492
- onConfigurationChanged(c) {
1493
- this._configuration = c;
1494
-
1495
- this._render();
1496
- }
1497
- /** @param {done, progress, file} handler */
1498
-
1499
-
1500
- insertImage(handler) {
1501
- this.dispatchEvent(new InsertImageEvent(handler));
1502
- }
1503
-
1504
- onDeleteImage(src, done) {
1505
- this.dispatchEvent(new DeleteImageEvent(src, done));
1506
- }
1507
-
1508
- insertSound(handler) {
1509
- this.dispatchEvent(new InsertSoundEvent(handler));
1510
- }
1511
-
1512
- onDeleteSound(src, done) {
1513
- this.dispatchEvent(new DeleteSoundEvent(src, done));
1514
- }
1515
-
1516
- _render() {
1517
- log('_render');
1518
- let element = /*#__PURE__*/React.createElement(Styled, {
1519
- model: this._model,
1520
- configuration: this._configuration,
1521
- onModelChanged: this.onModelChanged,
1522
- onConfigurationChanged: this.onConfigurationChanged,
1523
- disableSidePanel: this._disableSidePanel,
1524
- imageSupport: {
1525
- add: this.insertImage.bind(this),
1526
- delete: this.onDeleteImage.bind(this)
1527
- },
1528
- uploadSoundSupport: {
1529
- add: this.insertSound.bind(this),
1530
- delete: this.onDeleteSound.bind(this)
1531
- }
1532
- });
1533
- ReactDOM.render(element, this);
1534
- }
1535
-
1536
- }
1537
-
1538
- InlineDropdown.prepareModel = (model = {}) => {
1539
- const currModal = _extends({}, sensibleDefaults.model, model);
1540
-
1541
- const slateMarkup = model.slateMarkup || createSlateMarkup(currModal.markup, currModal.choices);
1542
- const markup = processMarkup(slateMarkup);
1543
- return _extends({}, currModal, {
1544
- slateMarkup,
1545
- markup
1546
- /*...processedMarkup,*/
1547
-
1548
- });
1549
- };
1550
-
1551
- export { InlineDropdown as default };
1552
- //# sourceMappingURL=configure.js.map