@pie-element/math-inline 10.0.1 → 11.0.3-esm.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/element.js ADDED
@@ -0,0 +1,1476 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import debug from 'debug';
4
+ import _ from 'lodash';
5
+ import { SessionChangedEvent, ModelSetEvent } from '@pie-framework/pie-player-events';
6
+ import PropTypes from 'prop-types';
7
+ import CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';
8
+ import { mq, updateSpans, HorizontalKeypad } from '@pie-lib/math-input';
9
+ import { color, hasText, hasMedia, Collapsible, PreviewPrompt, Readable, UiLayout, Feedback } from '@pie-lib/render-ui';
10
+ import { renderMath } from '@pie-lib/math-rendering';
11
+ import { withStyles } from '@material-ui/core/styles';
12
+ import Tooltip from '@material-ui/core/Tooltip';
13
+ import isEqual from 'lodash/isEqual';
14
+ import cx from 'classnames';
15
+ import { MathToolbar } from '@pie-lib/math-toolbar';
16
+ import MathQuill from '@pie-framework/mathquill';
17
+ import isEmpty from 'lodash/isEmpty';
18
+ import Translator from '@pie-lib/translator';
19
+
20
+ function _extends() {
21
+ _extends = Object.assign || function (target) {
22
+ for (var i = 1; i < arguments.length; i++) {
23
+ var source = arguments[i];
24
+
25
+ for (var key in source) {
26
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
27
+ target[key] = source[key];
28
+ }
29
+ }
30
+ }
31
+
32
+ return target;
33
+ };
34
+
35
+ return _extends.apply(this, arguments);
36
+ }
37
+
38
+ const ResponseTypes$1 = {
39
+ advanced: 'Advanced Multi',
40
+ simple: 'Simple'
41
+ };
42
+
43
+ /** NOTE: teacherInstructions, studentInstructions, rationale & scoringType
44
+ * functionalities are not defined yet - the value for those can belong to
45
+ * model or to configure
46
+ */
47
+
48
+ var defaults = {
49
+ model: {
50
+ allowTrailingZerosDefault: false,
51
+ customKeys: [],
52
+ equationEditor: '8',
53
+ expression: '',
54
+ feedback: {
55
+ correct: {
56
+ default: 'Correct',
57
+ type: 'none'
58
+ },
59
+ incorrect: {
60
+ default: 'Incorrect',
61
+ type: 'none'
62
+ },
63
+ partial: {
64
+ default: 'Nearly',
65
+ type: 'none'
66
+ }
67
+ },
68
+ feedbackEnabled: false,
69
+ ignoreOrderDefault: false,
70
+ partialScoring: true,
71
+ prompt: '',
72
+ promptEnabled: true,
73
+ rationale: '',
74
+ rationaleEnabled: true,
75
+ responseType: ResponseTypes$1.advanced,
76
+ responses: [],
77
+ scoringType: 'auto',
78
+ studentInstructionsEnabled: true,
79
+ teacherInstructions: '',
80
+ teacherInstructionsEnabled: true,
81
+ toolbarEditorPosition: 'bottom',
82
+ validationDefault: 'literal'
83
+ },
84
+ configuration: {
85
+ baseInputConfiguration: {
86
+ audio: {
87
+ disabled: false
88
+ },
89
+ video: {
90
+ disabled: false
91
+ },
92
+ image: {
93
+ disabled: false
94
+ },
95
+ textAlign: {
96
+ disabled: true
97
+ },
98
+ showParagraphs: {
99
+ disabled: false
100
+ },
101
+ separateParagraphs: {
102
+ disabled: true
103
+ }
104
+ },
105
+ prompt: {
106
+ settings: true,
107
+ label: 'Prompt',
108
+ inputConfiguration: {
109
+ audio: {
110
+ disabled: false
111
+ },
112
+ video: {
113
+ disabled: false
114
+ },
115
+ image: {
116
+ disabled: false
117
+ }
118
+ },
119
+ required: false
120
+ },
121
+ feedback: {
122
+ settings: true,
123
+ label: 'Feedback'
124
+ },
125
+ responseType: {
126
+ settings: true,
127
+ label: 'Response type'
128
+ },
129
+ rationale: {
130
+ settings: true,
131
+ label: 'Rationale',
132
+ inputConfiguration: {
133
+ audio: {
134
+ disabled: false
135
+ },
136
+ video: {
137
+ disabled: false
138
+ },
139
+ image: {
140
+ disabled: false
141
+ }
142
+ },
143
+ required: false
144
+ },
145
+ settingsPanelDisabled: false,
146
+ spellCheck: {
147
+ label: 'Spellcheck',
148
+ settings: false,
149
+ enabled: true
150
+ },
151
+ scoringType: {
152
+ settings: false,
153
+ label: 'Scoring Type'
154
+ },
155
+ studentInstructions: {
156
+ settings: false,
157
+ label: 'Student Instructions'
158
+ },
159
+ teacherInstructions: {
160
+ settings: true,
161
+ label: 'Teacher Instructions',
162
+ inputConfiguration: {
163
+ audio: {
164
+ disabled: false
165
+ },
166
+ video: {
167
+ disabled: false
168
+ },
169
+ image: {
170
+ disabled: false
171
+ }
172
+ },
173
+ required: false
174
+ },
175
+ partialScoring: {
176
+ settings: false,
177
+ label: 'Allow Partial Scoring'
178
+ },
179
+ ignoreOrder: {
180
+ settings: false,
181
+ label: 'Ignore Order',
182
+ enabled: true
183
+ },
184
+ allowTrailingZeros: {
185
+ settings: false,
186
+ label: 'Allow Trailing Zeros',
187
+ enabled: true
188
+ },
189
+ maxImageWidth: {
190
+ teacherInstructions: 300,
191
+ prompt: 300,
192
+ rationale: 300
193
+ },
194
+ maxImageHeight: {
195
+ teacherInstructions: 300,
196
+ prompt: 300,
197
+ rationale: 300
198
+ },
199
+ withRubric: {
200
+ settings: false,
201
+ label: 'Add Rubric'
202
+ },
203
+ mathMlOptions: {
204
+ mmlOutput: false,
205
+ mmlEditing: false
206
+ },
207
+ language: {
208
+ settings: false,
209
+ label: 'Specify Language',
210
+ enabled: false
211
+ },
212
+ languageChoices: {
213
+ label: 'Language Choices',
214
+ options: []
215
+ }
216
+ }
217
+ };
218
+
219
+ const ResponseTypes = {
220
+ advanced: 'Advanced Multi',
221
+ simple: 'Simple'
222
+ };
223
+
224
+ class SimpleQuestionBlockRaw extends React.Component {
225
+ constructor(props) {
226
+ super(props);
227
+
228
+ this.mathToolBarContainsTarget = e => document.getElementById(this.mathToolBarId).contains(e.target);
229
+
230
+ this.handleClick = e => {
231
+ try {
232
+ if (!this.mathToolBarContainsTarget(e)) {
233
+ this.setState({
234
+ showKeypad: false
235
+ });
236
+ }
237
+ } catch (e) {// console.log(e.toString());
238
+ }
239
+ };
240
+
241
+ this.onFocus = () => {
242
+ const {
243
+ onSubFieldFocus
244
+ } = this.props;
245
+ onSubFieldFocus(this.mathToolBarId);
246
+ };
247
+
248
+ this.mathToolBarId = `math-toolbar-${new Date().getTime()}`;
249
+ }
250
+
251
+ render() {
252
+ const {
253
+ classes,
254
+ model,
255
+ showCorrect,
256
+ session,
257
+ emptyResponse,
258
+ onSimpleResponseChange,
259
+ showKeypad
260
+ } = this.props;
261
+ const {
262
+ config,
263
+ disabled,
264
+ correctness
265
+ } = model || {};
266
+
267
+ if (!config) {
268
+ return;
269
+ }
270
+
271
+ const correct = correctness && correctness.correct;
272
+ const {
273
+ responses,
274
+ equationEditor
275
+ } = config;
276
+ return /*#__PURE__*/React.createElement("div", {
277
+ className: classes.expression,
278
+ "data-keypad": true
279
+ }, showCorrect || disabled ? /*#__PURE__*/React.createElement("div", {
280
+ className: cx(classes.static, {
281
+ [classes.incorrect]: !emptyResponse && !correct && !showCorrect,
282
+ [classes.correct]: !emptyResponse && (correct || showCorrect)
283
+ })
284
+ }, /*#__PURE__*/React.createElement(mq.Static, {
285
+ latex: showCorrect ? responses && responses.length && responses[0].answer : session.response || ''
286
+ })) : /*#__PURE__*/React.createElement("div", {
287
+ id: this.mathToolBarId
288
+ }, /*#__PURE__*/React.createElement(MathToolbar, {
289
+ classNames: {
290
+ editor: classes.responseEditor
291
+ },
292
+ latex: session.response,
293
+ keypadMode: equationEditor,
294
+ onChange: onSimpleResponseChange,
295
+ onDone: () => {},
296
+ onFocus: this.onFocus,
297
+ controlledKeypad: true,
298
+ showKeypad: showKeypad,
299
+ hideDoneButton: true
300
+ })));
301
+ }
302
+
303
+ }
304
+ SimpleQuestionBlockRaw.propTypes = {
305
+ classes: PropTypes.object,
306
+ onSimpleResponseChange: PropTypes.func,
307
+ model: PropTypes.object.isRequired,
308
+ emptyResponse: PropTypes.bool,
309
+ session: PropTypes.object.isRequired,
310
+ showCorrect: PropTypes.bool,
311
+ onSubFieldFocus: PropTypes.func.isRequired,
312
+ showKeypad: PropTypes.bool.isRequired
313
+ };
314
+ const SimpleQuestionBlock = withStyles(theme => ({
315
+ responseEditor: {
316
+ display: 'flex',
317
+ justifyContent: 'center',
318
+ width: 'auto',
319
+ maxWidth: 'fit-content',
320
+ height: 'auto',
321
+ textAlign: 'left',
322
+ padding: theme.spacing.unit,
323
+ '&.mq-math-mode': {
324
+ border: `1px solid ${color.primaryLight()}`
325
+ }
326
+ },
327
+ expression: {
328
+ marginTop: theme.spacing.unit * 2,
329
+ marginBottom: theme.spacing.unit * 2,
330
+ padding: theme.spacing.unit
331
+ },
332
+ static: {
333
+ color: color.text(),
334
+ background: color.background(),
335
+ border: `1px solid ${color.primaryLight()}`,
336
+ width: 'fit-content',
337
+ fontSize: '1rem',
338
+ padding: theme.spacing.unit / 2,
339
+ '& > .mq-math-mode': {
340
+ '& > .mq-hasCursor': {
341
+ '& > .mq-cursor': {
342
+ display: 'none'
343
+ }
344
+ }
345
+ }
346
+ },
347
+ correct: {
348
+ border: `2px solid ${color.correct()} !important`,
349
+ padding: theme.spacing.unit,
350
+ letterSpacing: '0.5px'
351
+ },
352
+ incorrect: {
353
+ border: `2px solid ${color.incorrect()} !important`,
354
+ padding: theme.spacing.unit,
355
+ letterSpacing: '0.5px'
356
+ }
357
+ }))(SimpleQuestionBlockRaw);
358
+
359
+ const {
360
+ translator
361
+ } = Translator;
362
+ let registered = false;
363
+ const NEWLINE_LATEX = /\\newline/g;
364
+ const REGEX = /{{response}}/gm;
365
+ const DEFAULT_KEYPAD_VARIANT = 6; // !!! If you're using Chrome but have selected the "iPad" device in Chrome Developer Tools, the navigator.userAgent string may still report as
366
+ // Safari because Chrome on iOS actually uses the Safari rendering engine under the hood due to Apple's restrictions on third-party browser engines.
367
+ // When you select the "iPad" device in Chrome Developer Tools, you're essentially emulating the behavior of Safari on an iPad, including the user agent string.
368
+ // Therefore, even though you're using Chrome, the user agent string will resemble that of Safari on an iPad.
369
+ // Since the regular expression /^((?!chrome|android).)*safari/i checks for the presence of "safari" in the user agent string while excluding "chrome" and "android",
370
+ // it will return true in this case because "safari" is present in the user agent string emulated by Chrome when in iPad mode.
371
+
372
+ const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
373
+
374
+ function generateAdditionalKeys(keyData = []) {
375
+ return keyData.map(key => ({
376
+ name: key,
377
+ latex: key,
378
+ write: key,
379
+ label: key
380
+ }));
381
+ }
382
+
383
+ function isChildOfCurrentPieElement(child, parent) {
384
+ let node = child;
385
+
386
+ while (node !== null) {
387
+ if (parent && node === parent) {
388
+ return true;
389
+ }
390
+
391
+ node = node.parentNode;
392
+ }
393
+
394
+ return false;
395
+ }
396
+
397
+ function getKeyPadWidth(additionalKeys = [], equationEditor) {
398
+ return Math.floor(additionalKeys.length / 5) * 30 + (equationEditor === 'miscellaneous' ? 600 : 500);
399
+ }
400
+
401
+ function prepareForStatic(model, state) {
402
+ const {
403
+ config,
404
+ disabled
405
+ } = model || {};
406
+ const {
407
+ expression,
408
+ responses,
409
+ printMode,
410
+ alwaysShowCorrect
411
+ } = config || {};
412
+
413
+ if (config && expression) {
414
+ const modelExpression = expression;
415
+
416
+ if (state.showCorrect) {
417
+ return responses && responses.length && responses[0].answer;
418
+ }
419
+
420
+ let answerBlocks = 1; // assume one at least
421
+ // build out local state model using responses declared in expression
422
+
423
+ return (modelExpression || '').replace(REGEX, function () {
424
+ const answer = state.session.answers[`r${answerBlocks}`];
425
+
426
+ if (printMode && !alwaysShowCorrect) {
427
+ const blankSpace = '\\ \\ '.repeat(30) + '\\newline ';
428
+ return `\\MathQuillMathField[r${answerBlocks++}]{${blankSpace.repeat(3)}}`;
429
+ }
430
+
431
+ if (disabled) {
432
+ return `\\embed{answerBlock}[r${answerBlocks++}]`;
433
+ }
434
+
435
+ return `\\MathQuillMathField[r${answerBlocks++}]{${answer && answer.value || ''}}`;
436
+ }).replace(NEWLINE_LATEX, '\\embed{newLine}[]');
437
+ }
438
+ }
439
+
440
+ function parseAnswers(session, model) {
441
+ const answers = {};
442
+
443
+ if (model.config && model.config.expression) {
444
+ let answerBlocks = 1; // assume one at least
445
+ // build out local state model using responses declared in expression
446
+
447
+ (model.config.expression || '').replace(REGEX, () => {
448
+ answers[`r${answerBlocks}`] = {
449
+ value: session && session.answers && session.answers[`r${answerBlocks}`] && session.answers[`r${answerBlocks}`].value || ''
450
+ };
451
+ answerBlocks += 1;
452
+ });
453
+ }
454
+
455
+ return answers;
456
+ }
457
+
458
+ class Main extends React.Component {
459
+ constructor(props) {
460
+ super(props);
461
+
462
+ this.handleAnswerBlockDomUpdate = () => {
463
+ const {
464
+ model,
465
+ classes
466
+ } = this.props;
467
+ const {
468
+ session,
469
+ showCorrect
470
+ } = this.state;
471
+ const answers = session.answers;
472
+
473
+ if (this.root && model.disabled && !showCorrect) {
474
+ Object.keys(answers).forEach(answerId => {
475
+ const el = this.root.querySelector(`#${answerId}`);
476
+ const indexEl = this.root.querySelector(`#${answerId}Index`); // const correct = model.correctness && model.correctness.correct;
477
+
478
+ if (el) {
479
+ let MQ = MathQuill.getInterface(2);
480
+ const answer = answers[answerId];
481
+ el.textContent = answer && answer.value || '';
482
+
483
+ if (!model.view) ; else {
484
+ el.parentElement.parentElement.classList.remove(classes.correct);
485
+ el.parentElement.parentElement.classList.remove(classes.incorrect);
486
+ }
487
+
488
+ MQ.StaticMath(el); // For now, we're not going to be indexing response blocks
489
+ // TODO go back to indexing once we support individual response correctness
490
+ // indexEl.textContent = `R${idx + 1}`;
491
+
492
+ indexEl.textContent = 'R';
493
+ }
494
+ });
495
+ }
496
+
497
+ renderMath(this.root);
498
+ };
499
+
500
+ this.updateAria = () => {
501
+ const {
502
+ classes
503
+ } = this.props;
504
+
505
+ if (this.root) {
506
+ // Update aria-hidden for .mq-selectable elements
507
+ const selectableElements = this.root.querySelectorAll('.mq-selectable');
508
+ selectableElements.forEach(elem => elem.setAttribute('aria-hidden', 'true')); // Update aria-label for textarea elements and add aria-describedby
509
+
510
+ const textareaElements = this.root.querySelectorAll('textarea');
511
+ textareaElements.forEach((elem, index) => {
512
+ elem.setAttribute('aria-label', 'Enter answer.'); // Create a unique id for each instructions element
513
+
514
+ const instructionsId = `instructions-${index}`; // Find the parent element that contains the textarea
515
+
516
+ const parent = elem.closest('.mq-textarea');
517
+
518
+ if (parent) {
519
+ // Create or find the instructions element within the parent
520
+ let instructionsElement = parent.querySelector(`#${instructionsId}`);
521
+
522
+ if (!instructionsElement) {
523
+ instructionsElement = document.createElement('span');
524
+ instructionsElement.id = instructionsId;
525
+ instructionsElement.className = classes.srOnly;
526
+ instructionsElement.textContent = 'This field supports both keypad and keyboard input. Use the keyboard to access and interact with the on-screen math keypad, which accepts LaTeX markup. Use the down arrow key to open the keypad and navigate its buttons. Use the escape key to close the keypad and return to the input field.';
527
+ parent.insertBefore(instructionsElement, elem);
528
+ }
529
+
530
+ elem.setAttribute('aria-describedby', instructionsId);
531
+ }
532
+ });
533
+ }
534
+ };
535
+
536
+ this.focusFirstKeypadElement = () => {
537
+ setTimeout(() => {
538
+ const keypadElement = document.querySelector('[data-keypad]');
539
+
540
+ if (keypadElement) {
541
+ const firstButton = keypadElement.querySelector("button, [role='button']");
542
+
543
+ if (firstButton) {
544
+ firstButton.focus();
545
+ }
546
+ }
547
+ }, 0);
548
+ };
549
+
550
+ this.handleKeyDown = (event, id) => {
551
+ var _this$mqStatic$inputR, _this$mqStatic$inputR2, _document$activeEleme;
552
+
553
+ const isTrigerredFromActualPieElement = isChildOfCurrentPieElement(event.target, this.root);
554
+ const isAnswerInputFocused = this.mqStatic && (_this$mqStatic$inputR = this.mqStatic.inputRef) != null && _this$mqStatic$inputR.current ? (_this$mqStatic$inputR2 = this.mqStatic.inputRef) == null ? void 0 : _this$mqStatic$inputR2.current.contains(document.activeElement) : ((_document$activeEleme = document.activeElement) == null ? void 0 : _document$activeEleme.getAttribute('aria-label')) === 'Enter answer.';
555
+ const {
556
+ key,
557
+ type
558
+ } = event;
559
+ const isClickOrTouchEvent = type === 'click' || type === 'touchstart';
560
+
561
+ if (isAnswerInputFocused && (key === 'ArrowDown' || isClickOrTouchEvent)) {
562
+ if (this.state.activeAnswerBlock !== id && isTrigerredFromActualPieElement) {
563
+ this.cleanupKeyDownListener();
564
+ this.setState({
565
+ activeAnswerBlock: id
566
+ }, () => {
567
+ this.onSubFieldFocus(id);
568
+
569
+ if (key === 'ArrowDown') {
570
+ this.focusFirstKeypadElement();
571
+ }
572
+ });
573
+ }
574
+ } else if (event.key === 'Escape') {
575
+ this.setState({
576
+ activeAnswerBlock: ''
577
+ });
578
+ }
579
+ };
580
+
581
+ this.onSubFieldFocus = id => {
582
+ if (!this.handleEvent) {
583
+ this.handleEvent = event => {
584
+ this.handleKeyDown(event, id);
585
+ };
586
+
587
+ document.addEventListener('keydown', this.handleEvent);
588
+ document.addEventListener('click', this.handleEvent);
589
+ document.addEventListener('touchstart', this.handleEvent);
590
+ }
591
+ };
592
+
593
+ this.cleanupKeyDownListener = () => {
594
+ if (this.handleEvent) {
595
+ document.removeEventListener('keydown', this.handleEvent);
596
+ document.removeEventListener('click', this.handleEvent);
597
+ document.removeEventListener('touchstart', this.handleEvent);
598
+ this.handleEvent = null;
599
+ }
600
+ };
601
+
602
+ this.onDone = () => {};
603
+
604
+ this.onSimpleResponseChange = response => {
605
+ this.setState(state => ({
606
+ session: _extends({}, state.session, {
607
+ response
608
+ })
609
+ }), this.callOnSessionChange);
610
+ };
611
+
612
+ this.toNodeData = data => {
613
+ if (!data) {
614
+ return;
615
+ }
616
+
617
+ const {
618
+ type,
619
+ value
620
+ } = data;
621
+
622
+ if (type === 'command' || type === 'cursor') {
623
+ return data;
624
+ } else if (type === 'answer') {
625
+ return _extends({
626
+ type: 'answer'
627
+ }, data);
628
+ } else if (value === 'clear') {
629
+ return {
630
+ type: 'clear'
631
+ };
632
+ } else {
633
+ return {
634
+ type: 'write',
635
+ value
636
+ };
637
+ }
638
+ };
639
+
640
+ this.setInput = input => {
641
+ this.input = input;
642
+ };
643
+
644
+ this.onClick = data => {
645
+ const c = this.toNodeData(data);
646
+
647
+ if (c.type === 'clear') {
648
+ this.input.clear();
649
+ } else if (c.type === 'command') {
650
+ if (Array.isArray(c.value)) {
651
+ c.value.forEach(vv => {
652
+ this.input.cmd(vv);
653
+ });
654
+ } else {
655
+ this.input.cmd(c.value);
656
+ }
657
+ } else if (c.type === 'cursor') {
658
+ this.input.keystroke(c.value);
659
+ } else {
660
+ this.input.write(c.value);
661
+ }
662
+
663
+ this.input.focus();
664
+ };
665
+
666
+ this.callOnSessionChange = () => {
667
+ const {
668
+ onSessionChange
669
+ } = this.props;
670
+
671
+ if (onSessionChange) {
672
+ onSessionChange(this.state.session);
673
+ }
674
+ };
675
+
676
+ this.toggleShowCorrect = show => {
677
+ this.setState({
678
+ showCorrect: show
679
+ }, this.handleAnswerBlockDomUpdate);
680
+ };
681
+
682
+ this.subFieldChanged = (name, subfieldValue) => {
683
+ updateSpans();
684
+
685
+ if (name) {
686
+ this.setState(state => ({
687
+ session: _extends({}, state.session, {
688
+ completeAnswer: this.mqStatic && this.mqStatic.mathField.latex(),
689
+ answers: _extends({}, state.session.answers, {
690
+ [name]: {
691
+ value: subfieldValue
692
+ }
693
+ })
694
+ })
695
+ }), this.callOnSessionChange);
696
+ }
697
+ };
698
+
699
+ this.getFieldName = (changeField, fields) => {
700
+ const {
701
+ answers
702
+ } = this.state.session;
703
+
704
+ if (Object.keys(answers || {}).length) {
705
+ const keys = Object.keys(answers);
706
+ return keys.find(k => {
707
+ const tf = fields[k];
708
+ return tf && tf.id == changeField.id;
709
+ });
710
+ }
711
+ };
712
+
713
+ this.onBlur = e => {
714
+ const {
715
+ relatedTarget,
716
+ currentTarget
717
+ } = e || {}; // our keypad is in tooltip
718
+ // in this way we see if event was triggered from the keypad
719
+
720
+ const isKeypadOpen = currentTarget && currentTarget.closest('[role=tooltip]');
721
+
722
+ function getParentWithRoleTooltip(element, depth = 0) {
723
+ // only run this max 16 times
724
+ if (!element || depth >= 16) return null;
725
+ const parent = element.offsetParent;
726
+ if (!parent) return null;
727
+
728
+ if (parent.getAttribute('role') === 'tooltip') {
729
+ return parent;
730
+ }
731
+
732
+ return getParentWithRoleTooltip(parent, depth + 1);
733
+ }
734
+
735
+ function getDeepChildDataKeypad(element, depth = 0) {
736
+ var _element$children;
737
+
738
+ // only run this max 4 times
739
+ if (!element || depth >= 4) return null;
740
+ const child = element == null ? void 0 : (_element$children = element.children) == null ? void 0 : _element$children[0];
741
+ if (!child) return null;
742
+
743
+ if (child.attributes && child.attributes['data-keypad']) {
744
+ return child;
745
+ }
746
+
747
+ return getDeepChildDataKeypad(child, depth + 1);
748
+ }
749
+
750
+ const parentWithTooltipRole = getParentWithRoleTooltip(relatedTarget);
751
+ const childWithDataKeypad = parentWithTooltipRole ? getDeepChildDataKeypad(parentWithTooltipRole) : null;
752
+
753
+ if (!relatedTarget || !currentTarget || !(childWithDataKeypad != null && childWithDataKeypad.attributes['data-keypad'])) {
754
+ // if event was trigered from the keypad, avoid closing the keypad
755
+ if (!isKeypadOpen) {
756
+ this.setState({
757
+ activeAnswerBlock: ''
758
+ });
759
+ }
760
+ } // else {
761
+ // // Just for debugging purpose:
762
+ // console.log('\n\nNew childWithDataKeypad', childWithDataKeypad);
763
+ //
764
+ // if (IS_SAFARI) {
765
+ // // (IS_SAFARI && !relatedTarget?.offsetParent?.children[0]?.children[0]?.attributes?.['data-keypad'])
766
+ // console.log('What was being used', relatedTarget?.offsetParent?.children[0]?.children[0]);
767
+ // } else {
768
+ // // (!IS_SAFARI && !relatedTarget?.offsetParent?.children[0]?.attributes?.['data-keypad']) ||
769
+ // console.log('What was being used', relatedTarget?.offsetParent?.children[0]);
770
+ // }
771
+ // }
772
+
773
+ };
774
+
775
+ const {
776
+ model: _model,
777
+ session: _session
778
+ } = props;
779
+
780
+ const _answers = parseAnswers(_session, _model);
781
+
782
+ this.state = {
783
+ session: _extends({}, props.session, {
784
+ answers: _answers
785
+ }),
786
+ activeAnswerBlock: '',
787
+ showCorrect: this.props.model.config.alwaysShowCorrect || false,
788
+ tooltipContainerRef: /*#__PURE__*/React.createRef()
789
+ };
790
+ }
791
+
792
+ UNSAFE_componentWillMount() {
793
+ const {
794
+ classes
795
+ } = this.props;
796
+
797
+ if (typeof window !== 'undefined') {
798
+ let MQ = MathQuill.getInterface(2);
799
+
800
+ if (!registered) {
801
+ MQ.registerEmbed('answerBlock', data => {
802
+ return {
803
+ htmlString: `<div class="${classes.blockContainer}">
804
+ <div class="${classes.blockResponse}" id="${data}Index">R</div>
805
+ <div class="${classes.blockMath}">
806
+ <span id="${data}"></span>
807
+ </div>
808
+ </div>`,
809
+ text: () => 'text',
810
+ latex: () => `\\embed{answerBlock}[${data}]`
811
+ };
812
+ });
813
+ registered = true;
814
+ }
815
+ }
816
+ }
817
+
818
+ countResponseOccurrences(expression) {
819
+ const pattern = /\{\{response\}\}/g;
820
+ const matches = expression == null ? void 0 : expression.match(pattern);
821
+ return matches ? matches.length : 0;
822
+ }
823
+
824
+ UNSAFE_componentWillReceiveProps(nextProps) {
825
+ const {
826
+ config
827
+ } = this.props.model;
828
+ const {
829
+ config: nextConfig = {}
830
+ } = nextProps.model || {};
831
+ const {
832
+ session
833
+ } = this.props;
834
+ const {
835
+ session: nextSession = {}
836
+ } = nextProps || {}; // in case session props changed in parent, we need to catch this and update local state
837
+ // example: when env is changing in pieoneer
838
+
839
+ if (session && nextSession && !isEqual(session.answers, nextSession.answers)) {
840
+ this.setState({
841
+ session: _extends({}, nextSession, {
842
+ answers: parseAnswers(nextSession, this.props.model)
843
+ })
844
+ });
845
+ } // check if the note is the default one for prev language and change to the default one for new language
846
+ // this check is necessary in order to diferanciate between default and authour defined note
847
+ // and only change between languages for default ones
848
+
849
+
850
+ if (config.note && config.language && config.language !== nextConfig.language && config.note === translator.t('mathInline.primaryCorrectWithAlternates', {
851
+ lng: config.language
852
+ })) {
853
+ config.note = translator.t('mathInline.primaryCorrectWithAlternates', {
854
+ lng: nextConfig.language
855
+ });
856
+ }
857
+
858
+ if (config.env && config.env.mode !== 'evaluate' || nextConfig.env && nextConfig.env.mode !== 'evaluate') {
859
+ this.setState(_extends({}, this.state.session, {
860
+ showCorrect: false
861
+ }));
862
+ }
863
+
864
+ if (nextConfig.alwaysShowCorrect) {
865
+ this.setState({
866
+ showCorrect: true
867
+ });
868
+ }
869
+
870
+ if (this.countResponseOccurrences(config.expression) < this.countResponseOccurrences(nextConfig.expression)) {
871
+ setTimeout(() => this.updateAria(), 100);
872
+ }
873
+
874
+ if (config && config.responses && config.responses.length !== nextConfig.responses.length || !config && nextConfig && nextConfig.responses || config && nextConfig && config.expression !== nextConfig.expression) {
875
+ const newAnswers = {};
876
+ const answers = this.state.session.answers;
877
+ let answerBlocks = 1; // assume one at least
878
+ // build out local state model using responses declared in expression
879
+
880
+ (nextConfig.expression || '').replace(REGEX, () => {
881
+ newAnswers[`r${answerBlocks}`] = {
882
+ value: answers && answers[`r${answerBlocks}`] && answers[`r${answerBlocks}`].value || ''
883
+ };
884
+ answerBlocks++;
885
+ });
886
+ this.setState(state => ({
887
+ session: _extends({}, state.session, {
888
+ completeAnswer: this.mqStatic && this.mqStatic.mathField.latex(),
889
+ answers: newAnswers
890
+ })
891
+ }), this.handleAnswerBlockDomUpdate);
892
+ }
893
+ }
894
+
895
+ shouldComponentUpdate(nextProps, nextState) {
896
+ const sameModel = isEqual(this.props.model, nextProps.model);
897
+ const sameState = isEqual(this.state, nextState);
898
+ return !sameModel || !sameState;
899
+ }
900
+
901
+ componentDidMount() {
902
+ this.handleAnswerBlockDomUpdate();
903
+ this.updateAria();
904
+ setTimeout(() => renderMath(this.root), 100);
905
+ }
906
+
907
+ componentDidUpdate(prevProps, prevState) {
908
+ var _prevProps$model, _prevProps$model$conf, _this$props$model, _this$props$model$con;
909
+
910
+ this.handleAnswerBlockDomUpdate();
911
+ const prevResponseType = (_prevProps$model = prevProps.model) == null ? void 0 : (_prevProps$model$conf = _prevProps$model.config) == null ? void 0 : _prevProps$model$conf.responseType;
912
+ const currentResponseType = (_this$props$model = this.props.model) == null ? void 0 : (_this$props$model$con = _this$props$model.config) == null ? void 0 : _this$props$model$con.responseType;
913
+
914
+ if (prevResponseType !== currentResponseType) {
915
+ this.updateAria();
916
+ }
917
+ }
918
+
919
+ componentWillUnmount() {
920
+ if (this.cleanupKeyDownListener) {
921
+ this.cleanupKeyDownListener();
922
+ }
923
+ }
924
+
925
+ setTooltipRef(ref) {
926
+ // Safari Hack: https://stackoverflow.com/a/42764495/5757635
927
+ setTimeout(() => {
928
+ if (ref && IS_SAFARI) {
929
+ const div = document.querySelector("[role='tooltip']");
930
+
931
+ if (div) {
932
+ const el = div.firstChild;
933
+ el.setAttribute('tabindex', '-1');
934
+ }
935
+ }
936
+ }, 1);
937
+ }
938
+
939
+ render() {
940
+ const {
941
+ model,
942
+ classes
943
+ } = this.props;
944
+ const {
945
+ activeAnswerBlock,
946
+ showCorrect,
947
+ session,
948
+ tooltipContainerRef
949
+ } = this.state;
950
+ const {
951
+ config,
952
+ correctness,
953
+ disabled,
954
+ extraCSSRules,
955
+ view,
956
+ teacherInstructions,
957
+ rationale,
958
+ feedback,
959
+ animationsDisabled,
960
+ printMode,
961
+ alwaysShowCorrect,
962
+ language
963
+ } = model || {};
964
+
965
+ if (!config) {
966
+ return null;
967
+ }
968
+
969
+ const {
970
+ showNote,
971
+ note,
972
+ prompt,
973
+ responses,
974
+ responseType,
975
+ equationEditor,
976
+ customKeys,
977
+ id,
978
+ env: {
979
+ mode,
980
+ role
981
+ } = {}
982
+ } = config || {};
983
+ const displayNote = (showCorrect || mode === 'view' && role === 'instructor') && showNote && note;
984
+ const emptyResponse = isEmpty(responses);
985
+ const showCorrectAnswerToggle = !emptyResponse && correctness && correctness.correctness !== 'correct';
986
+ const tooltipModeEnabled = disabled && correctness;
987
+ const additionalKeys = generateAdditionalKeys(customKeys);
988
+ const correct = correctness && correctness.correct;
989
+ const staticLatex = prepareForStatic(model, this.state) || '';
990
+ const viewMode = disabled && !correctness;
991
+ const studentPrintMode = printMode && !alwaysShowCorrect;
992
+ const showRationale = rationale && (hasText(rationale) || hasMedia(rationale));
993
+ const showTeacherInstructions = teacherInstructions && (hasText(teacherInstructions) || hasMedia(teacherInstructions));
994
+ const printView = /*#__PURE__*/React.createElement("div", {
995
+ className: classes.printContainer
996
+ }, /*#__PURE__*/React.createElement(mq.Static, {
997
+ className: classes.static,
998
+ ref: mqStatic => {
999
+ if (mqStatic) this.mqStatic = mqStatic;
1000
+ },
1001
+ latex: staticLatex,
1002
+ onSubFieldChange: this.subFieldChanged,
1003
+ getFieldName: this.getFieldName,
1004
+ setInput: this.setInput,
1005
+ onSubFieldFocus: this.onSubFieldFocus,
1006
+ onBlur: this.onBlur
1007
+ }));
1008
+ const midContent = /*#__PURE__*/React.createElement("div", {
1009
+ className: classes.main
1010
+ }, mode === 'gather' && /*#__PURE__*/React.createElement("h2", {
1011
+ className: classes.srOnly
1012
+ }, "Math Equation Response Question"), viewMode && showTeacherInstructions && (!animationsDisabled ? /*#__PURE__*/React.createElement(Collapsible, {
1013
+ className: classes.collapsible,
1014
+ labels: {
1015
+ hidden: 'Show Teacher Instructions',
1016
+ visible: 'Hide Teacher Instructions'
1017
+ }
1018
+ }, /*#__PURE__*/React.createElement("div", {
1019
+ dangerouslySetInnerHTML: {
1020
+ __html: teacherInstructions
1021
+ }
1022
+ })) : /*#__PURE__*/React.createElement("div", {
1023
+ dangerouslySetInnerHTML: {
1024
+ __html: teacherInstructions
1025
+ }
1026
+ })), prompt && /*#__PURE__*/React.createElement("div", {
1027
+ className: classes.promptContainer
1028
+ }, /*#__PURE__*/React.createElement(PreviewPrompt, {
1029
+ prompt: prompt
1030
+ })), studentPrintMode ? printView : /*#__PURE__*/React.createElement(Readable, {
1031
+ false: true
1032
+ }, /*#__PURE__*/React.createElement("div", {
1033
+ className: classes.inputAndKeypadContainer,
1034
+ tabIndex: 0
1035
+ }, responseType === ResponseTypes.simple && /*#__PURE__*/React.createElement(SimpleQuestionBlock, {
1036
+ onSimpleResponseChange: this.onSimpleResponseChange,
1037
+ showCorrect: showCorrect,
1038
+ emptyResponse: emptyResponse,
1039
+ model: model,
1040
+ session: session,
1041
+ onSubFieldFocus: this.onSubFieldFocus,
1042
+ showKeypad: !!activeAnswerBlock
1043
+ }), responseType === ResponseTypes.advanced && /*#__PURE__*/React.createElement("div", {
1044
+ ref: tooltipContainerRef,
1045
+ className: cx(classes.expression, {
1046
+ [classes.incorrect]: !emptyResponse && !correct && !showCorrect,
1047
+ [classes.correct]: !emptyResponse && (correct || showCorrect),
1048
+ [classes.showCorrectness]: !emptyResponse && disabled && correctness && !view,
1049
+ [classes.correctAnswerShown]: showCorrect,
1050
+ [classes.printCorrect]: printMode && alwaysShowCorrect
1051
+ })
1052
+ }, /*#__PURE__*/React.createElement(Tooltip, {
1053
+ ref: ref => this.setTooltipRef(ref),
1054
+ enterTouchDelay: 0,
1055
+ interactive: true,
1056
+ open: !!activeAnswerBlock,
1057
+ classes: {
1058
+ tooltip: classes.keypadTooltip,
1059
+ popper: classes.keypadTooltipPopper
1060
+ },
1061
+ PopperProps: {
1062
+ container: (tooltipContainerRef == null ? void 0 : tooltipContainerRef.current) || undefined,
1063
+ placement: 'bottom-start',
1064
+ modifiers: {
1065
+ preventOverflow: {
1066
+ enabled: true,
1067
+ boundariesElement: 'body'
1068
+ },
1069
+ flip: {
1070
+ enabled: false
1071
+ }
1072
+ }
1073
+ },
1074
+ title: Object.keys(session.answers).map(answerId => answerId === activeAnswerBlock && !(showCorrect || disabled) && /*#__PURE__*/React.createElement("div", {
1075
+ "data-keypad": true,
1076
+ key: answerId,
1077
+ className: classes.responseContainer,
1078
+ style: {
1079
+ // marginTop: this.mqStatic && this.mqStatic.input.offsetHeight - 20,
1080
+ width: getKeyPadWidth(additionalKeys, equationEditor)
1081
+ }
1082
+ }, /*#__PURE__*/React.createElement(HorizontalKeypad, {
1083
+ additionalKeys: additionalKeys,
1084
+ mode: equationEditor || DEFAULT_KEYPAD_VARIANT,
1085
+ onClick: this.onClick
1086
+ })) || null)
1087
+ }, /*#__PURE__*/React.createElement(mq.Static, {
1088
+ className: classes.static,
1089
+ ref: mqStatic => {
1090
+ if (mqStatic) this.mqStatic = mqStatic;
1091
+ },
1092
+ latex: staticLatex,
1093
+ onSubFieldChange: this.subFieldChanged,
1094
+ getFieldName: this.getFieldName,
1095
+ setInput: this.setInput,
1096
+ onSubFieldFocus: this.onSubFieldFocus,
1097
+ onBlur: this.onBlur
1098
+ }))))), viewMode && displayNote && /*#__PURE__*/React.createElement("div", {
1099
+ className: classes.note,
1100
+ dangerouslySetInnerHTML: {
1101
+ __html: `<strong>Note:</strong> ${note}`
1102
+ }
1103
+ }), viewMode && showRationale && (!animationsDisabled ? /*#__PURE__*/React.createElement(Collapsible, {
1104
+ labels: {
1105
+ hidden: 'Show Rationale',
1106
+ visible: 'Hide Rationale'
1107
+ }
1108
+ }, /*#__PURE__*/React.createElement("div", {
1109
+ dangerouslySetInnerHTML: {
1110
+ __html: rationale
1111
+ }
1112
+ })) : /*#__PURE__*/React.createElement("div", {
1113
+ dangerouslySetInnerHTML: {
1114
+ __html: rationale
1115
+ }
1116
+ })));
1117
+
1118
+ if (tooltipModeEnabled && (showCorrectAnswerToggle || showTeacherInstructions || showRationale || feedback)) {
1119
+ return /*#__PURE__*/React.createElement(UiLayout, {
1120
+ extraCSSRules: extraCSSRules
1121
+ }, /*#__PURE__*/React.createElement(Tooltip, {
1122
+ interactive: true,
1123
+ enterTouchDelay: 0,
1124
+ classes: {
1125
+ tooltip: classes.tooltip,
1126
+ popper: classes.tooltipPopper
1127
+ },
1128
+ title: /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
1129
+ className: classes.main
1130
+ }, showCorrectAnswerToggle && /*#__PURE__*/React.createElement(CorrectAnswerToggle, {
1131
+ language: language,
1132
+ className: classes.toggle,
1133
+ show: true,
1134
+ toggled: showCorrect,
1135
+ onToggle: this.toggleShowCorrect
1136
+ })), showTeacherInstructions && /*#__PURE__*/React.createElement(Collapsible, {
1137
+ className: classes.collapsible,
1138
+ key: "collapsible-teacher-instructions",
1139
+ labels: {
1140
+ hidden: 'Show Teacher Instructions',
1141
+ visible: 'Hide Teacher Instructions'
1142
+ }
1143
+ }, /*#__PURE__*/React.createElement(PreviewPrompt, {
1144
+ prompt: teacherInstructions
1145
+ })), displayNote && hasText(note) && /*#__PURE__*/React.createElement(Collapsible, {
1146
+ className: classes.collapsible,
1147
+ key: "collapsible-note",
1148
+ labels: {
1149
+ hidden: translator.t('common:showNote', {
1150
+ lng: language
1151
+ }),
1152
+ visible: translator.t('common:hideNote', {
1153
+ lng: language
1154
+ })
1155
+ }
1156
+ }, /*#__PURE__*/React.createElement(PreviewPrompt, {
1157
+ prompt: note
1158
+ })), showRationale && /*#__PURE__*/React.createElement(Collapsible, {
1159
+ className: classes.collapsible,
1160
+ key: "collapsible-rationale",
1161
+ labels: {
1162
+ hidden: 'Show Rationale',
1163
+ visible: 'Hide Rationale'
1164
+ }
1165
+ }, /*#__PURE__*/React.createElement(PreviewPrompt, {
1166
+ prompt: rationale
1167
+ })), feedback && /*#__PURE__*/React.createElement(Feedback, {
1168
+ correctness: correctness.correctness,
1169
+ feedback: feedback
1170
+ }))
1171
+ }, /*#__PURE__*/React.createElement("div", {
1172
+ className: classes.mainContainer,
1173
+ ref: r => this.root = r || this.root
1174
+ }, midContent)));
1175
+ }
1176
+
1177
+ return /*#__PURE__*/React.createElement(UiLayout, {
1178
+ id: id,
1179
+ extraCSSRules: extraCSSRules,
1180
+ className: classes.mainContainer,
1181
+ ref: r => {
1182
+ // eslint-disable-next-line react/no-find-dom-node
1183
+ const domNode = ReactDOM.findDOMNode(r);
1184
+ this.root = domNode || this.root;
1185
+ }
1186
+ }, midContent);
1187
+ }
1188
+
1189
+ }
1190
+ Main.propTypes = {
1191
+ classes: PropTypes.object,
1192
+ session: PropTypes.object.isRequired,
1193
+ onSessionChange: PropTypes.func,
1194
+ model: PropTypes.object.isRequired
1195
+ };
1196
+
1197
+ const styles = theme => ({
1198
+ mainContainer: {
1199
+ color: color.text(),
1200
+ backgroundColor: color.background(),
1201
+ display: 'inline-block'
1202
+ },
1203
+ tooltip: {
1204
+ background: `${color.primaryLight()} !important`,
1205
+ color: color.text(),
1206
+ padding: theme.spacing.unit * 2,
1207
+ border: `1px solid ${color.secondary()}`,
1208
+ fontSize: '16px',
1209
+ '& :not(.MathJax) > table tr': {
1210
+ '&:nth-child(2n)': {
1211
+ backgroundColor: 'unset !important'
1212
+ }
1213
+ }
1214
+ },
1215
+ tooltipPopper: {
1216
+ opacity: 1
1217
+ },
1218
+ keypadTooltip: {
1219
+ fontSize: 'initial',
1220
+ background: 'transparent',
1221
+ width: '600px',
1222
+ marginTop: 0,
1223
+ paddingTop: 0
1224
+ },
1225
+ keypadTooltipPopper: {
1226
+ background: 'transparent',
1227
+ width: '650px',
1228
+ opacity: 1
1229
+ },
1230
+ promptContainer: {
1231
+ marginBottom: theme.spacing.unit * 2
1232
+ },
1233
+ main: {
1234
+ width: '100%',
1235
+ position: 'relative',
1236
+ backgroundColor: color.background(),
1237
+ color: color.text()
1238
+ },
1239
+ title: {
1240
+ fontSize: '1.1rem',
1241
+ display: 'block',
1242
+ marginTop: theme.spacing.unit * 2,
1243
+ marginBottom: theme.spacing.unit
1244
+ },
1245
+ note: {
1246
+ paddingBottom: theme.spacing.unit * 2
1247
+ },
1248
+ collapsible: {
1249
+ marginBottom: theme.spacing.unit * 2
1250
+ },
1251
+ responseContainer: {
1252
+ zIndex: 10,
1253
+ // position: 'absolute',
1254
+ // right: 0,
1255
+ minWidth: '400px',
1256
+ marginTop: theme.spacing.unit * 2
1257
+ },
1258
+ expression: {
1259
+ maxWidth: 'fit-content',
1260
+ padding: theme.spacing.unit / 4,
1261
+ '& > .mq-math-mode': {
1262
+ '& > .mq-root-block': {
1263
+ // PD-4803 unset padding as events are not correctly propagated in the proximity of math input
1264
+ paddingRight: '0 !important',
1265
+ paddingLeft: '0 !important',
1266
+ '& > .mq-editable-field': {
1267
+ minWidth: '10px',
1268
+ padding: theme.spacing.unit / 4
1269
+ }
1270
+ },
1271
+ '& sup': {
1272
+ top: 0
1273
+ }
1274
+ }
1275
+ },
1276
+ static: {
1277
+ '& > .mq-root-block': {
1278
+ '& > .mq-editable-field': {
1279
+ borderColor: color.text()
1280
+ }
1281
+ }
1282
+ },
1283
+ inputAndKeypadContainer: {
1284
+ position: 'relative',
1285
+ '& .mq-overarrow-inner': {
1286
+ border: 'none !important',
1287
+ padding: '0 !important'
1288
+ },
1289
+ '& .mq-overarrow-inner-right': {
1290
+ display: 'none !important'
1291
+ },
1292
+ '& .mq-overarrow-inner-left': {
1293
+ display: 'none !important'
1294
+ },
1295
+ '& .mq-overarrow.mq-arrow-both': {
1296
+ minWidth: '1.23em',
1297
+ '& *': {
1298
+ lineHeight: '1 !important'
1299
+ },
1300
+ '&:before': {
1301
+ top: '-0.4em',
1302
+ left: '-1px'
1303
+ },
1304
+ '&:after': {
1305
+ top: '-2.4em',
1306
+ right: '-1px'
1307
+ },
1308
+ '&.mq-empty:after': {
1309
+ top: '-0.45em'
1310
+ }
1311
+ },
1312
+ '& .mq-overarrow.mq-arrow-right': {
1313
+ '&:before': {
1314
+ top: '-0.4em',
1315
+ right: '-1px'
1316
+ }
1317
+ },
1318
+ '& .mq-longdiv-inner': {
1319
+ borderTop: '1px solid !important',
1320
+ paddingTop: '1.5px !important'
1321
+ },
1322
+ '& .mq-parallelogram': {
1323
+ lineHeight: 0.85
1324
+ }
1325
+ },
1326
+ showCorrectness: {
1327
+ border: '2px solid'
1328
+ },
1329
+ correctAnswerShown: {
1330
+ padding: theme.spacing.unit,
1331
+ letterSpacing: '0.5px'
1332
+ },
1333
+ printCorrect: {
1334
+ border: `2px solid ${color.correct()} !important`
1335
+ },
1336
+ correct: {
1337
+ borderColor: `${color.correct()} !important`
1338
+ },
1339
+ incorrect: {
1340
+ borderColor: `${color.incorrect()} !important`
1341
+ },
1342
+ blockContainer: {
1343
+ margin: `${theme.spacing.unit}px !important`,
1344
+ display: 'inline-flex',
1345
+ border: '2px solid grey !important'
1346
+ },
1347
+ blockResponse: {
1348
+ color: 'grey',
1349
+ background: theme.palette.grey['A100'],
1350
+ fontSize: '0.8rem !important',
1351
+ padding: `${theme.spacing.unit / 2}px !important`,
1352
+ display: 'flex',
1353
+ alignItems: 'center',
1354
+ justifyContent: 'center',
1355
+ borderRight: `2px solid ${color.disabled()} !important`,
1356
+ flexShrink: 0,
1357
+ flexGrow: 0,
1358
+ flexBasis: 'auto' // take only the space needed for content + padding
1359
+
1360
+ },
1361
+ toggle: {
1362
+ color: color.text(),
1363
+ marginBottom: theme.spacing.unit * 2
1364
+ },
1365
+ blockMath: {
1366
+ color: color.text(),
1367
+ backgroundColor: color.background(),
1368
+ padding: `${theme.spacing.unit / 2}px !important`,
1369
+ display: 'flex',
1370
+ alignItems: 'center',
1371
+ justifyContent: 'center',
1372
+ flexGrow: 1,
1373
+ // take all the remaining space
1374
+ '& > .mq-math-mode': {
1375
+ '& > .mq-hasCursor': {
1376
+ '& > .mq-cursor': {
1377
+ display: 'none'
1378
+ }
1379
+ }
1380
+ }
1381
+ },
1382
+ printContainer: {
1383
+ marginBottom: theme.spacing.unit,
1384
+ pointerEvents: 'none'
1385
+ },
1386
+ srOnly: {
1387
+ position: 'absolute',
1388
+ left: '-10000px',
1389
+ top: 'auto',
1390
+ width: '1px',
1391
+ height: '1px',
1392
+ overflow: 'hidden'
1393
+ }
1394
+ });
1395
+
1396
+ var Main$1 = withStyles(styles)(Main);
1397
+
1398
+ const log = debug('pie-ui:math-inline');
1399
+ class MathInline extends HTMLElement {
1400
+ constructor() {
1401
+ super();
1402
+ this._configuration = defaults.configuration;
1403
+ this.sessionChangedEventCaller = _.debounce(() => {
1404
+ this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), true));
1405
+ }, 1000);
1406
+ }
1407
+
1408
+ setLangAttribute() {
1409
+ const language = this._model && typeof this._model.language ? this._model.language : '';
1410
+ const lang = language ? language.slice(0, 2) : 'en';
1411
+ this.setAttribute('lang', lang); // set the lang attribute for the nearest parent div with class 'player-container' for MPI items as per PD-2483
1412
+
1413
+ const playerContainer = this.closest('.player-container');
1414
+
1415
+ if (playerContainer) {
1416
+ playerContainer.setAttribute('lang', lang);
1417
+ }
1418
+ }
1419
+
1420
+ set model(m) {
1421
+ this._model = m;
1422
+ this.dispatchEvent(new ModelSetEvent(this._model, true, !!this._model));
1423
+ this.setLangAttribute();
1424
+
1425
+ this._render();
1426
+ }
1427
+
1428
+ set session(s) {
1429
+ this._session = s;
1430
+
1431
+ this._render();
1432
+ }
1433
+
1434
+ get session() {
1435
+ return this._session;
1436
+ }
1437
+
1438
+ set configuration(c) {
1439
+ this._configuration = c;
1440
+
1441
+ this._render();
1442
+ }
1443
+
1444
+ sessionChanged(s) {
1445
+ Object.keys(s).map(key => {
1446
+ this._session[key] = s[key];
1447
+ });
1448
+ this.sessionChangedEventCaller();
1449
+ log('session: ', this._session);
1450
+ }
1451
+
1452
+ connectedCallback() {
1453
+ this.setAttribute('aria-label', 'Math Response Question');
1454
+ this.setAttribute('role', 'region');
1455
+
1456
+ this._render();
1457
+ }
1458
+
1459
+ _render() {
1460
+ if (!this._model || !this._session) {
1461
+ return;
1462
+ }
1463
+
1464
+ const el = /*#__PURE__*/React.createElement(Main$1, {
1465
+ model: this._model,
1466
+ session: this._session,
1467
+ configuration: this._configuration,
1468
+ onSessionChange: this.sessionChanged.bind(this)
1469
+ });
1470
+ ReactDOM.render(el, this);
1471
+ }
1472
+
1473
+ }
1474
+
1475
+ export { Main$1 as Component, MathInline as default };
1476
+ //# sourceMappingURL=element.js.map