@pie-element/math-templated 5.0.2-esm.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/configure/CHANGELOG.md +19 -0
- package/configure/package.json +5 -5
- package/controller/CHANGELOG.md +25 -0
- package/controller/lib/index.js +1 -1
- package/controller/lib/index.js.map +1 -1
- package/controller/package.json +3 -3
- package/module/configure.js +1 -1
- package/module/controller.js +40 -39
- package/module/element.js +1 -1
- package/module/index.html +1 -1
- package/module/manifest.json +5 -5
- package/module/print.html +1 -1
- package/module/print.js +1 -1
- package/package.json +9 -27
- package/esm/configure.css +0 -847
- package/esm/configure.js +0 -1342
- package/esm/configure.js.map +0 -1
- package/esm/controller.css +0 -847
- package/esm/controller.js +0 -335
- package/esm/controller.js.map +0 -1
- package/esm/element.css +0 -847
- package/esm/element.js +0 -900
- package/esm/element.js.map +0 -1
- package/esm/print.css +0 -847
- package/esm/print.js +0 -905
- package/esm/print.js.map +0 -1
package/esm/element.js
DELETED
|
@@ -1,900 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
import { SessionChangedEvent, ModelSetEvent } from '@pie-framework/pie-player-events';
|
|
4
|
-
import PropTypes from 'prop-types';
|
|
5
|
-
import cx from 'classnames';
|
|
6
|
-
import isEqual from 'lodash/isEqual';
|
|
7
|
-
import isEmpty from 'lodash/isEmpty';
|
|
8
|
-
import { withStyles } from '@material-ui/core/styles';
|
|
9
|
-
import Tooltip from '@material-ui/core/Tooltip';
|
|
10
|
-
import { updateSpans, mq, HorizontalKeypad } from '@pie-lib/math-input';
|
|
11
|
-
import { hasText, hasMedia, Collapsible, UiLayout, PreviewPrompt, Readable, color } from '@pie-lib/render-ui';
|
|
12
|
-
import { renderMath } from '@pie-lib/math-rendering';
|
|
13
|
-
import MathQuill from '@pie-framework/mathquill';
|
|
14
|
-
import { Customizable } from '@pie-lib/mask-markup';
|
|
15
|
-
import CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';
|
|
16
|
-
import _ from 'lodash';
|
|
17
|
-
|
|
18
|
-
function _extends() {
|
|
19
|
-
_extends = Object.assign || function (target) {
|
|
20
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
21
|
-
var source = arguments[i];
|
|
22
|
-
|
|
23
|
-
for (var key in source) {
|
|
24
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
25
|
-
target[key] = source[key];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return target;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
return _extends.apply(this, arguments);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let registered = false; // Define a regex pattern to match {{number}}
|
|
37
|
-
|
|
38
|
-
const REGEX = /(\{\{\d+\}\})/gm;
|
|
39
|
-
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
|
|
40
|
-
// Safari because Chrome on iOS actually uses the Safari rendering engine under the hood due to Apple's restrictions on third-party browser engines.
|
|
41
|
-
// 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.
|
|
42
|
-
// Therefore, even though you're using Chrome, the user agent string will resemble that of Safari on an iPad.
|
|
43
|
-
// Since the regular expression /^((?!chrome|android).)*safari/i checks for the presence of "safari" in the user agent string while excluding "chrome" and "android",
|
|
44
|
-
// it will return true in this case because "safari" is present in the user agent string emulated by Chrome when in iPad mode.
|
|
45
|
-
|
|
46
|
-
const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
47
|
-
|
|
48
|
-
function generateAdditionalKeys(keyData = []) {
|
|
49
|
-
return keyData.map(key => ({
|
|
50
|
-
name: key,
|
|
51
|
-
latex: key,
|
|
52
|
-
write: key,
|
|
53
|
-
label: key
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function getKeyPadWidth(additionalKeys = [], equationEditor) {
|
|
58
|
-
return Math.floor(additionalKeys.length / 5) * 30 + (equationEditor === 'miscellaneous' ? 600 : 500);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function splitByParts(text) {
|
|
62
|
-
// Use the regex pattern to split the text
|
|
63
|
-
const parts = text.split(REGEX); // Filter out empty strings that might result from splitting
|
|
64
|
-
|
|
65
|
-
return parts.filter(part => part);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function prepareForStatic(model, state) {
|
|
69
|
-
const {
|
|
70
|
-
responses,
|
|
71
|
-
disabled,
|
|
72
|
-
markup,
|
|
73
|
-
printMode,
|
|
74
|
-
alwaysShowCorrect
|
|
75
|
-
} = model || {};
|
|
76
|
-
|
|
77
|
-
if (markup) {
|
|
78
|
-
if (state.showCorrect) {
|
|
79
|
-
return Object.keys(responses || {}).reduce((acc, responseKey) => {
|
|
80
|
-
var _responses$responseKe;
|
|
81
|
-
|
|
82
|
-
acc[responseKey] = responses == null ? void 0 : (_responses$responseKe = responses[responseKey]) == null ? void 0 : _responses$responseKe.answer;
|
|
83
|
-
return acc;
|
|
84
|
-
}, {});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const splitted = splitByParts(markup);
|
|
88
|
-
return splitted.reduce((acc, split) => {
|
|
89
|
-
if (split.match(REGEX)) {
|
|
90
|
-
const responseKey = Main.getResponseKey(split);
|
|
91
|
-
const answer = state.session.answers[`r${responseKey}`];
|
|
92
|
-
|
|
93
|
-
if (printMode && !alwaysShowCorrect) {
|
|
94
|
-
const blankSpace = '\\ \\ '.repeat(30) + '\\embed{newLine}[] ';
|
|
95
|
-
return _extends({}, acc, {
|
|
96
|
-
[responseKey]: `\\MathQuillMathField[r${responseKey}]{${blankSpace.repeat(3)}}`
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (disabled) {
|
|
101
|
-
return _extends({}, acc, {
|
|
102
|
-
[responseKey]: `\\embed{answerBlock}[r${responseKey}]`
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return _extends({}, acc, {
|
|
107
|
-
[responseKey]: `\\MathQuillMathField[r${responseKey}]{${answer && answer.value || ''}}`
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return acc;
|
|
112
|
-
}, {});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
class Main extends React.Component {
|
|
117
|
-
// removes {{ and }} and returns only key response. Eg: {{0}} => 0
|
|
118
|
-
constructor(props) {
|
|
119
|
-
super(props);
|
|
120
|
-
|
|
121
|
-
this.handleAnswerBlockDomUpdate = () => {
|
|
122
|
-
const {
|
|
123
|
-
model,
|
|
124
|
-
classes
|
|
125
|
-
} = this.props;
|
|
126
|
-
const {
|
|
127
|
-
session,
|
|
128
|
-
showCorrect
|
|
129
|
-
} = this.state;
|
|
130
|
-
const answers = session.answers;
|
|
131
|
-
|
|
132
|
-
if (this.root && model.disabled && !showCorrect) {
|
|
133
|
-
Object.keys(answers).forEach(answerId => {
|
|
134
|
-
const el = this.root.querySelector(`#${answerId}`);
|
|
135
|
-
const indexEl = this.root.querySelector(`#${answerId}Index`);
|
|
136
|
-
|
|
137
|
-
if (el) {
|
|
138
|
-
let MQ = MathQuill.getInterface(2);
|
|
139
|
-
const answer = answers[answerId];
|
|
140
|
-
el.textContent = answer && answer.value || '';
|
|
141
|
-
|
|
142
|
-
if (model.view) {
|
|
143
|
-
el.parentElement.parentElement.classList.remove(classes.correct);
|
|
144
|
-
el.parentElement.parentElement.classList.remove(classes.incorrect);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
MQ.StaticMath(el);
|
|
148
|
-
indexEl.textContent = 'R';
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
renderMath(this.root);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
this.onSubFieldFocus = id => {
|
|
157
|
-
this.setState({
|
|
158
|
-
activeAnswerBlock: id
|
|
159
|
-
});
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
this.toNodeData = data => {
|
|
163
|
-
if (!data) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const {
|
|
168
|
-
type,
|
|
169
|
-
value
|
|
170
|
-
} = data;
|
|
171
|
-
if (type === 'command' || type === 'cursor') return data;
|
|
172
|
-
if (type === 'answer') return _extends({
|
|
173
|
-
type: 'answer'
|
|
174
|
-
}, data);
|
|
175
|
-
if (value === 'clear') return {
|
|
176
|
-
type: 'clear'
|
|
177
|
-
};
|
|
178
|
-
return {
|
|
179
|
-
type: 'write',
|
|
180
|
-
value
|
|
181
|
-
};
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
this.setInput = input => {
|
|
185
|
-
this.input = input;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
this.onClick = data => {
|
|
189
|
-
const c = this.toNodeData(data);
|
|
190
|
-
|
|
191
|
-
if (c.type === 'clear') {
|
|
192
|
-
this.input.clear();
|
|
193
|
-
} else if (c.type === 'command') {
|
|
194
|
-
if (Array.isArray(c.value)) {
|
|
195
|
-
c.value.forEach(vv => {
|
|
196
|
-
this.input.cmd(vv);
|
|
197
|
-
});
|
|
198
|
-
} else {
|
|
199
|
-
this.input.cmd(c.value);
|
|
200
|
-
}
|
|
201
|
-
} else if (c.type === 'cursor') {
|
|
202
|
-
this.input.keystroke(c.value);
|
|
203
|
-
} else {
|
|
204
|
-
this.input.write(c.value);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
this.input.focus();
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
this.callOnSessionChange = () => {
|
|
211
|
-
const {
|
|
212
|
-
onSessionChange
|
|
213
|
-
} = this.props;
|
|
214
|
-
|
|
215
|
-
if (onSessionChange) {
|
|
216
|
-
onSessionChange(this.state.session);
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
this.toggleShowCorrect = show => {
|
|
221
|
-
this.setState({
|
|
222
|
-
showCorrect: show
|
|
223
|
-
}, this.handleAnswerBlockDomUpdate);
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
this.subFieldChanged = (name, subfieldValue) => {
|
|
227
|
-
updateSpans();
|
|
228
|
-
|
|
229
|
-
if (name) {
|
|
230
|
-
this.setState(state => ({
|
|
231
|
-
session: _extends({}, state.session, {
|
|
232
|
-
answers: _extends({}, state.session.answers, {
|
|
233
|
-
[name]: {
|
|
234
|
-
value: subfieldValue
|
|
235
|
-
}
|
|
236
|
-
})
|
|
237
|
-
})
|
|
238
|
-
}), this.callOnSessionChange);
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
this.getFieldName = (changeField, fields) => {
|
|
243
|
-
const {
|
|
244
|
-
answers
|
|
245
|
-
} = this.state.session;
|
|
246
|
-
|
|
247
|
-
if (Object.keys(answers || {}).length) {
|
|
248
|
-
const keys = Object.keys(answers);
|
|
249
|
-
return keys.find(k => {
|
|
250
|
-
const tf = fields[k];
|
|
251
|
-
return tf && tf.id == changeField.id;
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
this.onBlur = e => {
|
|
257
|
-
const {
|
|
258
|
-
relatedTarget,
|
|
259
|
-
currentTarget
|
|
260
|
-
} = e || {};
|
|
261
|
-
|
|
262
|
-
function getParentWithRoleTooltip(element, depth = 0) {
|
|
263
|
-
// only run this max 16 times
|
|
264
|
-
if (!element || depth >= 16) return null;
|
|
265
|
-
const parent = element.offsetParent;
|
|
266
|
-
if (!parent) return null;
|
|
267
|
-
|
|
268
|
-
if (parent.getAttribute('role') === 'tooltip') {
|
|
269
|
-
return parent;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return getParentWithRoleTooltip(parent, depth + 1);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function getDeepChildDataKeypad(element, depth = 0) {
|
|
276
|
-
var _element$children;
|
|
277
|
-
|
|
278
|
-
// only run this max 4 times
|
|
279
|
-
if (!element || depth >= 4) return null;
|
|
280
|
-
const child = element == null ? void 0 : (_element$children = element.children) == null ? void 0 : _element$children[0];
|
|
281
|
-
if (!child) return null;
|
|
282
|
-
|
|
283
|
-
if (child.attributes && child.attributes['data-keypad']) {
|
|
284
|
-
return child;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return getDeepChildDataKeypad(child, depth + 1);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const parentWithTooltipRole = getParentWithRoleTooltip(relatedTarget);
|
|
291
|
-
const childWithDataKeypad = parentWithTooltipRole ? getDeepChildDataKeypad(parentWithTooltipRole) : null;
|
|
292
|
-
|
|
293
|
-
if (!relatedTarget || !currentTarget || !(childWithDataKeypad != null && childWithDataKeypad.attributes['data-keypad'])) {
|
|
294
|
-
this.setState({
|
|
295
|
-
activeAnswerBlock: ''
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
this.renderTeacherInstructions = () => {
|
|
301
|
-
const {
|
|
302
|
-
model,
|
|
303
|
-
classes
|
|
304
|
-
} = this.props;
|
|
305
|
-
const {
|
|
306
|
-
teacherInstructions,
|
|
307
|
-
animationsDisabled
|
|
308
|
-
} = model || {};
|
|
309
|
-
const showTeacherInstructions = teacherInstructions && (hasText(teacherInstructions) || hasMedia(teacherInstructions));
|
|
310
|
-
const teacherInstructionsDiv = /*#__PURE__*/React.createElement(PreviewPrompt, {
|
|
311
|
-
defaultClassName: "teacher-instructions",
|
|
312
|
-
prompt: teacherInstructions
|
|
313
|
-
});
|
|
314
|
-
return showTeacherInstructions && /*#__PURE__*/React.createElement("div", {
|
|
315
|
-
className: classes.collapsible
|
|
316
|
-
}, !animationsDisabled ? /*#__PURE__*/React.createElement(Collapsible, {
|
|
317
|
-
labels: {
|
|
318
|
-
hidden: 'Show Teacher Instructions',
|
|
319
|
-
visible: 'Hide Teacher Instructions'
|
|
320
|
-
}
|
|
321
|
-
}, teacherInstructionsDiv) : teacherInstructionsDiv);
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
this.renderRationale = () => {
|
|
325
|
-
const {
|
|
326
|
-
model,
|
|
327
|
-
classes
|
|
328
|
-
} = this.props;
|
|
329
|
-
const {
|
|
330
|
-
rationale,
|
|
331
|
-
animationsDisabled
|
|
332
|
-
} = model || {};
|
|
333
|
-
const rationaleDiv = /*#__PURE__*/React.createElement(PreviewPrompt, {
|
|
334
|
-
prompt: rationale
|
|
335
|
-
});
|
|
336
|
-
const showRationale = rationale && (hasText(rationale) || hasMedia(rationale));
|
|
337
|
-
return showRationale && /*#__PURE__*/React.createElement("div", {
|
|
338
|
-
className: classes.collapsible
|
|
339
|
-
}, !animationsDisabled ? /*#__PURE__*/React.createElement(Collapsible, {
|
|
340
|
-
labels: {
|
|
341
|
-
hidden: 'Show Rationale',
|
|
342
|
-
visible: 'Hide Rationale'
|
|
343
|
-
}
|
|
344
|
-
}, rationaleDiv) : rationaleDiv);
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
this.renderPlayerContent = () => {
|
|
348
|
-
const {
|
|
349
|
-
model,
|
|
350
|
-
classes
|
|
351
|
-
} = this.props;
|
|
352
|
-
const {
|
|
353
|
-
activeAnswerBlock,
|
|
354
|
-
showCorrect,
|
|
355
|
-
session
|
|
356
|
-
} = this.state;
|
|
357
|
-
const {
|
|
358
|
-
correctness,
|
|
359
|
-
disabled,
|
|
360
|
-
view,
|
|
361
|
-
responses,
|
|
362
|
-
equationEditor,
|
|
363
|
-
customKeys,
|
|
364
|
-
feedback,
|
|
365
|
-
env: {
|
|
366
|
-
mode
|
|
367
|
-
} = {},
|
|
368
|
-
printMode,
|
|
369
|
-
alwaysShowCorrect
|
|
370
|
-
} = model || {};
|
|
371
|
-
const emptyResponse = isEmpty(responses);
|
|
372
|
-
const additionalKeys = generateAdditionalKeys(customKeys);
|
|
373
|
-
const statics = prepareForStatic(model, this.state) || '';
|
|
374
|
-
const studentPrintMode = printMode && !alwaysShowCorrect;
|
|
375
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
376
|
-
className: classes.inputAndKeypadContainer
|
|
377
|
-
}, /*#__PURE__*/React.createElement(Customizable, {
|
|
378
|
-
disabled: disabled,
|
|
379
|
-
markup: model.markup // TODO remove the need of value?
|
|
380
|
-
,
|
|
381
|
-
value: {},
|
|
382
|
-
customMarkMarkupComponent: id => {
|
|
383
|
-
const responseIsCorrect = mode === 'evaluate' && feedback && feedback[id];
|
|
384
|
-
const MQStatic = /*#__PURE__*/React.createElement(mq.Static, {
|
|
385
|
-
className: classes.static,
|
|
386
|
-
ref: mqStatic => {
|
|
387
|
-
this.mqStatic = mqStatic || this.mqStatic;
|
|
388
|
-
},
|
|
389
|
-
latex: statics[id],
|
|
390
|
-
onSubFieldChange: this.subFieldChanged,
|
|
391
|
-
getFieldName: this.getFieldName,
|
|
392
|
-
setInput: this.setInput,
|
|
393
|
-
onSubFieldFocus: this.onSubFieldFocus,
|
|
394
|
-
onBlur: this.onBlur
|
|
395
|
-
});
|
|
396
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
397
|
-
className: cx(classes.expression, {
|
|
398
|
-
[classes.incorrect]: !emptyResponse && !responseIsCorrect && !showCorrect,
|
|
399
|
-
[classes.correct]: !emptyResponse && (responseIsCorrect || showCorrect),
|
|
400
|
-
[classes.showCorrectness]: !emptyResponse && disabled && correctness && !view,
|
|
401
|
-
[classes.correctAnswerShown]: showCorrect
|
|
402
|
-
})
|
|
403
|
-
}, /*#__PURE__*/React.createElement(Tooltip, {
|
|
404
|
-
ref: ref => this.setTooltipRef(ref),
|
|
405
|
-
enterTouchDelay: 0,
|
|
406
|
-
interactive: true,
|
|
407
|
-
open: activeAnswerBlock === `r${id}`,
|
|
408
|
-
classes: {
|
|
409
|
-
tooltip: classes.keypadTooltip,
|
|
410
|
-
popper: classes.keypadTooltipPopper
|
|
411
|
-
},
|
|
412
|
-
title: Object.keys(session.answers).map(answerId => answerId === activeAnswerBlock && !(showCorrect || disabled) && /*#__PURE__*/React.createElement("div", {
|
|
413
|
-
"data-keypad": true,
|
|
414
|
-
key: answerId,
|
|
415
|
-
className: classes.responseContainer,
|
|
416
|
-
style: {
|
|
417
|
-
width: getKeyPadWidth(additionalKeys, equationEditor)
|
|
418
|
-
}
|
|
419
|
-
}, /*#__PURE__*/React.createElement(HorizontalKeypad, {
|
|
420
|
-
additionalKeys: additionalKeys,
|
|
421
|
-
mode: equationEditor || DEFAULT_KEYPAD_VARIANT,
|
|
422
|
-
onClick: this.onClick
|
|
423
|
-
})) || null)
|
|
424
|
-
}, studentPrintMode ? /*#__PURE__*/React.createElement("div", {
|
|
425
|
-
className: classes.printContainer
|
|
426
|
-
}, MQStatic) : MQStatic));
|
|
427
|
-
}
|
|
428
|
-
}));
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
const _answers = {};
|
|
432
|
-
const {
|
|
433
|
-
model: _model,
|
|
434
|
-
session: _session
|
|
435
|
-
} = props || {};
|
|
436
|
-
const {
|
|
437
|
-
markup,
|
|
438
|
-
alwaysShowCorrect: _alwaysShowCorrect
|
|
439
|
-
} = _model || {};
|
|
440
|
-
const {
|
|
441
|
-
answers: sessionAnswers
|
|
442
|
-
} = _session || {};
|
|
443
|
-
|
|
444
|
-
if (markup) {
|
|
445
|
-
// build out local state model using responses declared in markup
|
|
446
|
-
(markup || '').replace(REGEX, response => {
|
|
447
|
-
const responseKey = Main.getResponseKey(response);
|
|
448
|
-
const sessionAnswerForResponse = sessionAnswers && sessionAnswers[`r${responseKey}`];
|
|
449
|
-
_answers[`r${responseKey}`] = {
|
|
450
|
-
value: (sessionAnswerForResponse == null ? void 0 : sessionAnswerForResponse.value) || ''
|
|
451
|
-
};
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
this.state = {
|
|
456
|
-
session: _extends({}, props.session, {
|
|
457
|
-
answers: _answers
|
|
458
|
-
}),
|
|
459
|
-
activeAnswerBlock: '',
|
|
460
|
-
showCorrect: _alwaysShowCorrect || false
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
UNSAFE_componentWillMount() {
|
|
465
|
-
const {
|
|
466
|
-
classes
|
|
467
|
-
} = this.props;
|
|
468
|
-
|
|
469
|
-
if (typeof window !== 'undefined') {
|
|
470
|
-
let MQ = MathQuill.getInterface(2);
|
|
471
|
-
|
|
472
|
-
if (!registered) {
|
|
473
|
-
MQ.registerEmbed('answerBlock', data => ({
|
|
474
|
-
htmlString: `<div class="${classes.blockContainer}">
|
|
475
|
-
<div class="${classes.blockResponse}" id="${data}Index">R</div>
|
|
476
|
-
<div class="${classes.blockMath}">
|
|
477
|
-
<span id="${data}"></span>
|
|
478
|
-
</div>
|
|
479
|
-
</div>`,
|
|
480
|
-
text: () => 'text',
|
|
481
|
-
latex: () => `\\embed{answerBlock}[${data}]`
|
|
482
|
-
}));
|
|
483
|
-
registered = true;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
489
|
-
const {
|
|
490
|
-
model
|
|
491
|
-
} = this.props;
|
|
492
|
-
const {
|
|
493
|
-
model: nextModel = {}
|
|
494
|
-
} = nextProps || {};
|
|
495
|
-
const {
|
|
496
|
-
markup = '',
|
|
497
|
-
env = {}
|
|
498
|
-
} = model || {};
|
|
499
|
-
const {
|
|
500
|
-
markup: nextMarkup = '',
|
|
501
|
-
env: nextEnv = {},
|
|
502
|
-
alwaysShowCorrect: nextAlwaysShowCorrect = false
|
|
503
|
-
} = nextModel;
|
|
504
|
-
|
|
505
|
-
const isEvaluateMode = env => env && env.mode === 'evaluate';
|
|
506
|
-
|
|
507
|
-
if (!isEvaluateMode(env) || !isEvaluateMode(nextEnv)) {
|
|
508
|
-
this.setState(prevState => _extends({}, prevState.session, {
|
|
509
|
-
showCorrect: false
|
|
510
|
-
}));
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (nextAlwaysShowCorrect) {
|
|
514
|
-
this.setState({
|
|
515
|
-
showCorrect: true
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const matches = markup.match(REGEX);
|
|
520
|
-
const nextMatches = nextMarkup.match(REGEX); // If markup changed, and we no longer have the same response area, the session needs to be updated
|
|
521
|
-
|
|
522
|
-
if (!isEqual(matches, nextMatches)) {
|
|
523
|
-
const newAnswers = {};
|
|
524
|
-
const answers = this.state.session.answers;
|
|
525
|
-
(nextMatches || []).forEach(nextMatch => {
|
|
526
|
-
const responseKey = Main.getResponseKey(nextMatch);
|
|
527
|
-
const sessionAnswerForResponse = answers && answers[`r${responseKey}`]; // build out local state model using responses declared in markup
|
|
528
|
-
|
|
529
|
-
newAnswers[`r${responseKey}`] = {
|
|
530
|
-
value: (sessionAnswerForResponse == null ? void 0 : sessionAnswerForResponse.value) || ''
|
|
531
|
-
};
|
|
532
|
-
});
|
|
533
|
-
this.setState(state => ({
|
|
534
|
-
session: _extends({}, state.session, {
|
|
535
|
-
answers: newAnswers
|
|
536
|
-
})
|
|
537
|
-
}), () => {
|
|
538
|
-
this.props.onSessionChange(this.state.session);
|
|
539
|
-
this.handleAnswerBlockDomUpdate();
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
shouldComponentUpdate(nextProps, nextState) {
|
|
545
|
-
const sameModel = isEqual(this.props.model, nextProps.model);
|
|
546
|
-
const sameState = isEqual(this.state, nextState);
|
|
547
|
-
return !sameModel || !sameState;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
componentDidMount() {
|
|
551
|
-
this.handleAnswerBlockDomUpdate();
|
|
552
|
-
setTimeout(() => renderMath(this.root), 100);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
componentDidUpdate() {
|
|
556
|
-
this.handleAnswerBlockDomUpdate();
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// function for tooltip
|
|
560
|
-
setTooltipRef(ref) {
|
|
561
|
-
// Safari Hack: https://stackoverflow.com/a/42764495/5757635
|
|
562
|
-
setTimeout(() => {
|
|
563
|
-
if (ref && IS_SAFARI) {
|
|
564
|
-
const div = document.querySelector("[role='tooltip']");
|
|
565
|
-
|
|
566
|
-
if (div) {
|
|
567
|
-
const el = div.firstChild;
|
|
568
|
-
el.setAttribute('tabindex', '-1');
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}, 1);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
render() {
|
|
575
|
-
const {
|
|
576
|
-
model,
|
|
577
|
-
classes
|
|
578
|
-
} = this.props;
|
|
579
|
-
const {
|
|
580
|
-
showCorrect
|
|
581
|
-
} = this.state;
|
|
582
|
-
const {
|
|
583
|
-
prompt,
|
|
584
|
-
env: {
|
|
585
|
-
mode,
|
|
586
|
-
role
|
|
587
|
-
} = {},
|
|
588
|
-
extraCSSRules,
|
|
589
|
-
correctness,
|
|
590
|
-
responses,
|
|
591
|
-
language,
|
|
592
|
-
showNote,
|
|
593
|
-
note
|
|
594
|
-
} = model || {};
|
|
595
|
-
const emptyResponse = isEmpty(responses);
|
|
596
|
-
const showCorrectAnswerToggle = !emptyResponse && correctness && correctness.correctness !== 'correct';
|
|
597
|
-
const displayNote = (showCorrect || mode === 'view' && role === 'instructor') && showNote && note;
|
|
598
|
-
return /*#__PURE__*/React.createElement(UiLayout, {
|
|
599
|
-
extraCSSRules: extraCSSRules,
|
|
600
|
-
className: classes.mainContainer,
|
|
601
|
-
ref: r => {
|
|
602
|
-
// eslint-disable-next-line react/no-find-dom-node
|
|
603
|
-
const domNode = ReactDOM.findDOMNode(r);
|
|
604
|
-
this.root = domNode || this.root;
|
|
605
|
-
}
|
|
606
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
607
|
-
className: classes.main
|
|
608
|
-
}, mode === 'gather' && /*#__PURE__*/React.createElement("h2", {
|
|
609
|
-
className: classes.srOnly
|
|
610
|
-
}, "Math Equation Response Question"), /*#__PURE__*/React.createElement("div", {
|
|
611
|
-
className: classes.main
|
|
612
|
-
}, showCorrectAnswerToggle && /*#__PURE__*/React.createElement(CorrectAnswerToggle, {
|
|
613
|
-
language: language,
|
|
614
|
-
className: classes.toggle,
|
|
615
|
-
show: true,
|
|
616
|
-
toggled: showCorrect,
|
|
617
|
-
onToggle: this.toggleShowCorrect
|
|
618
|
-
})), this.renderTeacherInstructions(), prompt && /*#__PURE__*/React.createElement("div", {
|
|
619
|
-
className: classes.promptContainer
|
|
620
|
-
}, /*#__PURE__*/React.createElement(PreviewPrompt, {
|
|
621
|
-
prompt: prompt
|
|
622
|
-
})), /*#__PURE__*/React.createElement(Readable, {
|
|
623
|
-
false: true
|
|
624
|
-
}, this.renderPlayerContent()), displayNote && /*#__PURE__*/React.createElement("div", {
|
|
625
|
-
className: cx(classes.note, 'note'),
|
|
626
|
-
dangerouslySetInnerHTML: {
|
|
627
|
-
__html: note
|
|
628
|
-
}
|
|
629
|
-
}), this.renderRationale()));
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
Main.getResponseKey = response => (response || '').replaceAll('{{', '').replaceAll('}}', '');
|
|
635
|
-
|
|
636
|
-
Main.propTypes = {
|
|
637
|
-
classes: PropTypes.object,
|
|
638
|
-
session: PropTypes.object.isRequired,
|
|
639
|
-
onSessionChange: PropTypes.func,
|
|
640
|
-
model: PropTypes.object.isRequired
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
const styles = theme => ({
|
|
644
|
-
mainContainer: {
|
|
645
|
-
color: color.text(),
|
|
646
|
-
backgroundColor: color.background(),
|
|
647
|
-
display: 'inline-block'
|
|
648
|
-
},
|
|
649
|
-
tooltip: {
|
|
650
|
-
background: `${color.primaryLight()} !important`,
|
|
651
|
-
color: color.text(),
|
|
652
|
-
padding: theme.spacing.unit * 2,
|
|
653
|
-
border: `1px solid ${color.secondary()}`,
|
|
654
|
-
fontSize: '16px',
|
|
655
|
-
'& :not(.MathJax) > table tr': {
|
|
656
|
-
'&:nth-child(2n)': {
|
|
657
|
-
backgroundColor: 'unset !important'
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
},
|
|
661
|
-
tooltipPopper: {
|
|
662
|
-
opacity: 1
|
|
663
|
-
},
|
|
664
|
-
keypadTooltip: {
|
|
665
|
-
fontSize: 'initial',
|
|
666
|
-
background: 'transparent',
|
|
667
|
-
width: '600px',
|
|
668
|
-
marginTop: 0,
|
|
669
|
-
paddingTop: 0
|
|
670
|
-
},
|
|
671
|
-
keypadTooltipPopper: {
|
|
672
|
-
background: 'transparent',
|
|
673
|
-
width: '650px',
|
|
674
|
-
opacity: 1
|
|
675
|
-
},
|
|
676
|
-
promptContainer: {
|
|
677
|
-
marginBottom: theme.spacing.unit * 2
|
|
678
|
-
},
|
|
679
|
-
main: {
|
|
680
|
-
width: '100%',
|
|
681
|
-
position: 'relative',
|
|
682
|
-
backgroundColor: color.background(),
|
|
683
|
-
color: color.text()
|
|
684
|
-
},
|
|
685
|
-
title: {
|
|
686
|
-
fontSize: '1.1rem',
|
|
687
|
-
display: 'block',
|
|
688
|
-
marginTop: theme.spacing.unit * 2,
|
|
689
|
-
marginBottom: theme.spacing.unit
|
|
690
|
-
},
|
|
691
|
-
collapsible: {
|
|
692
|
-
marginBottom: theme.spacing.unit * 2
|
|
693
|
-
},
|
|
694
|
-
responseContainer: {
|
|
695
|
-
zIndex: 10,
|
|
696
|
-
minWidth: '400px',
|
|
697
|
-
marginTop: theme.spacing.unit * 2
|
|
698
|
-
},
|
|
699
|
-
expression: {
|
|
700
|
-
maxWidth: 'fit-content',
|
|
701
|
-
'& > .mq-math-mode': {
|
|
702
|
-
'& > .mq-root-block': {
|
|
703
|
-
'& > .mq-editable-field': {
|
|
704
|
-
minWidth: '10px',
|
|
705
|
-
padding: theme.spacing.unit / 4
|
|
706
|
-
}
|
|
707
|
-
},
|
|
708
|
-
'& sup': {
|
|
709
|
-
top: 0
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
},
|
|
713
|
-
static: {
|
|
714
|
-
'& > .mq-root-block': {
|
|
715
|
-
'& > .mq-editable-field': {
|
|
716
|
-
borderColor: color.text()
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
},
|
|
720
|
-
inputAndKeypadContainer: {
|
|
721
|
-
position: 'relative',
|
|
722
|
-
'& > div > div': {
|
|
723
|
-
display: 'flex',
|
|
724
|
-
alignItems: 'baseline',
|
|
725
|
-
flexWrap: 'wrap'
|
|
726
|
-
},
|
|
727
|
-
'& .mq-overarrow-inner': {
|
|
728
|
-
border: 'none !important',
|
|
729
|
-
padding: '0 !important'
|
|
730
|
-
},
|
|
731
|
-
'& .mq-overarrow-inner-right': {
|
|
732
|
-
display: 'none !important'
|
|
733
|
-
},
|
|
734
|
-
'& .mq-overarrow-inner-left': {
|
|
735
|
-
display: 'none !important'
|
|
736
|
-
},
|
|
737
|
-
'& .mq-overarrow.mq-arrow-both': {
|
|
738
|
-
minWidth: '1.23em',
|
|
739
|
-
'& *': {
|
|
740
|
-
lineHeight: '1 !important'
|
|
741
|
-
},
|
|
742
|
-
'&:before': {
|
|
743
|
-
top: '-0.4em',
|
|
744
|
-
left: '-1px'
|
|
745
|
-
},
|
|
746
|
-
'&:after': {
|
|
747
|
-
top: '-2.4em',
|
|
748
|
-
right: '-1px'
|
|
749
|
-
},
|
|
750
|
-
'&.mq-empty:after': {
|
|
751
|
-
top: '-0.45em'
|
|
752
|
-
}
|
|
753
|
-
},
|
|
754
|
-
'& .mq-overarrow.mq-arrow-right': {
|
|
755
|
-
'&:before': {
|
|
756
|
-
top: '-0.4em',
|
|
757
|
-
right: '-1px'
|
|
758
|
-
}
|
|
759
|
-
},
|
|
760
|
-
'& .mq-longdiv-inner': {
|
|
761
|
-
borderTop: '1px solid !important',
|
|
762
|
-
paddingTop: '1.5px !important'
|
|
763
|
-
},
|
|
764
|
-
'& .mq-parallelogram': {
|
|
765
|
-
lineHeight: 0.85
|
|
766
|
-
}
|
|
767
|
-
},
|
|
768
|
-
showCorrectness: {
|
|
769
|
-
border: '2px solid'
|
|
770
|
-
},
|
|
771
|
-
correctAnswerShown: {
|
|
772
|
-
padding: theme.spacing.unit,
|
|
773
|
-
letterSpacing: '0.5px'
|
|
774
|
-
},
|
|
775
|
-
correct: {
|
|
776
|
-
borderColor: `${color.correct()} !important`
|
|
777
|
-
},
|
|
778
|
-
incorrect: {
|
|
779
|
-
borderColor: `${color.incorrect()} !important`
|
|
780
|
-
},
|
|
781
|
-
blockContainer: {
|
|
782
|
-
margin: `${theme.spacing.unit}px !important`,
|
|
783
|
-
display: 'inline-flex',
|
|
784
|
-
border: '2px solid grey !important'
|
|
785
|
-
},
|
|
786
|
-
blockResponse: {
|
|
787
|
-
flex: 2,
|
|
788
|
-
color: 'grey',
|
|
789
|
-
background: theme.palette.grey['A100'],
|
|
790
|
-
fontSize: '0.8rem !important',
|
|
791
|
-
padding: `${theme.spacing.unit / 2}px !important`,
|
|
792
|
-
display: 'flex',
|
|
793
|
-
alignItems: 'center',
|
|
794
|
-
justifyContent: 'center',
|
|
795
|
-
borderRight: `2px solid ${color.disabled()} !important`
|
|
796
|
-
},
|
|
797
|
-
toggle: {
|
|
798
|
-
color: color.text(),
|
|
799
|
-
marginBottom: theme.spacing.unit * 2
|
|
800
|
-
},
|
|
801
|
-
blockMath: {
|
|
802
|
-
color: color.text(),
|
|
803
|
-
backgroundColor: color.background(),
|
|
804
|
-
padding: `${theme.spacing.unit / 2}px !important`,
|
|
805
|
-
display: 'flex',
|
|
806
|
-
alignItems: 'center',
|
|
807
|
-
justifyContent: 'center',
|
|
808
|
-
flex: 8,
|
|
809
|
-
'& > .mq-math-mode': {
|
|
810
|
-
'& > .mq-hasCursor': {
|
|
811
|
-
'& > .mq-cursor': {
|
|
812
|
-
display: 'none'
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
},
|
|
817
|
-
printContainer: {
|
|
818
|
-
marginBottom: theme.spacing.unit,
|
|
819
|
-
pointerEvents: 'none'
|
|
820
|
-
},
|
|
821
|
-
srOnly: {
|
|
822
|
-
position: 'absolute',
|
|
823
|
-
left: '-10000px',
|
|
824
|
-
top: 'auto',
|
|
825
|
-
width: '1px',
|
|
826
|
-
height: '1px',
|
|
827
|
-
overflow: 'hidden'
|
|
828
|
-
},
|
|
829
|
-
note: {
|
|
830
|
-
marginBottom: theme.spacing.unit * 2
|
|
831
|
-
}
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
var Main$1 = withStyles(styles)(Main);
|
|
835
|
-
|
|
836
|
-
class MathTemplated extends HTMLElement {
|
|
837
|
-
constructor() {
|
|
838
|
-
super();
|
|
839
|
-
this.sessionChangedEventCaller = _.debounce(() => {
|
|
840
|
-
this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), true));
|
|
841
|
-
}, 1000);
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
set model(m) {
|
|
845
|
-
this._model = m;
|
|
846
|
-
this.render();
|
|
847
|
-
this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isSessionComplete(), this._model !== undefined));
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
get model() {
|
|
851
|
-
return this._model;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
set session(s) {
|
|
855
|
-
this._session = s;
|
|
856
|
-
this.render();
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
get session() {
|
|
860
|
-
return this._session;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
isSessionComplete() {
|
|
864
|
-
// a method to check if student answered the question
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
onSessionChange(session) {
|
|
869
|
-
// you can add an extra step here to validate session
|
|
870
|
-
Object.keys(session).map(key => {
|
|
871
|
-
this._session[key] = session[key];
|
|
872
|
-
});
|
|
873
|
-
this.sessionChangedEventCaller();
|
|
874
|
-
this.render();
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
connectedCallback() {
|
|
878
|
-
// TODO set accessibility labels
|
|
879
|
-
this.render();
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
render() {
|
|
883
|
-
if (!this._model || !this._session) {
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
if (this._model && this._session) {
|
|
888
|
-
const el = /*#__PURE__*/React.createElement(Main$1, {
|
|
889
|
-
model: this._model,
|
|
890
|
-
session: this._session,
|
|
891
|
-
onSessionChange: this.onSessionChange.bind(this)
|
|
892
|
-
});
|
|
893
|
-
ReactDOM.render(el, this);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
export { MathTemplated as default };
|
|
900
|
-
//# sourceMappingURL=element.js.map
|