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