@khanacademy/perseus 21.6.0 → 22.0.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/dist/article-renderer.d.ts +6 -0
- package/dist/components/highlighting/ui/highlight-set-renderer.d.ts +14 -0
- package/dist/components/highlighting/ui/highlighting-ui.d.ts +17 -0
- package/dist/components/i18n-context.d.ts +16 -0
- package/dist/components/input-with-examples.d.ts +6 -0
- package/dist/components/math-input.d.ts +22 -2
- package/dist/components/number-input.d.ts +6 -0
- package/dist/es/index.js +863 -485
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +312 -0
- package/dist/es/strings.js.map +1 -0
- package/dist/hint-renderer.d.ts +6 -0
- package/dist/hints-renderer.d.ts +6 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1083 -523
- package/dist/index.js.map +1 -1
- package/dist/multi-items/multi-renderer.d.ts +6 -0
- package/dist/perseus-types.d.ts +3 -2
- package/dist/renderer.d.ts +2 -0
- package/dist/server-item-renderer.d.ts +6 -0
- package/dist/strings.d.ts +190 -0
- package/dist/strings.js +395 -119
- package/dist/strings.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/util/answer-types.d.ts +4 -12
- package/dist/util.d.ts +2 -1
- package/dist/widgets/categorizer.d.ts +8 -1
- package/dist/widgets/definition.d.ts +6 -0
- package/dist/widgets/deprecated-standin/index.d.ts +6 -0
- package/dist/widgets/explanation.d.ts +6 -0
- package/dist/widgets/expression.d.ts +12 -1
- package/dist/widgets/graded-group-answer-bar.d.ts +6 -0
- package/dist/widgets/graded-group.d.ts +6 -0
- package/dist/widgets/group.d.ts +6 -0
- package/dist/widgets/image.d.ts +6 -0
- package/dist/widgets/input-number.d.ts +8 -1
- package/dist/widgets/interactive-graph.d.ts +6 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +21 -0
- package/dist/widgets/interactive-graphs/locked-point.d.ts +1 -1
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +1 -0
- package/dist/widgets/label-image/marker.d.ts +6 -0
- package/dist/widgets/label-image.d.ts +6 -0
- package/dist/widgets/matcher.d.ts +6 -0
- package/dist/widgets/matrix.d.ts +9 -1
- package/dist/widgets/molecule.d.ts +6 -0
- package/dist/widgets/number-line.d.ts +6 -0
- package/dist/widgets/numeric-input.d.ts +8 -1
- package/dist/widgets/passage-ref-target.d.ts +6 -0
- package/dist/widgets/passage-ref.d.ts +6 -0
- package/dist/widgets/passage.d.ts +6 -0
- package/dist/widgets/plotter.d.ts +6 -0
- package/dist/widgets/radio/choice-a11y-text.d.ts +2 -1
- package/dist/widgets/radio/radio.d.ts +8 -1
- package/dist/widgets/radio/util.d.ts +2 -1
- package/dist/widgets/table.d.ts +7 -0
- package/dist/widgets/unit.d.ts +8 -1
- package/dist/widgets/video.d.ts +6 -0
- package/dist/widgets.d.ts +2 -1
- package/package.json +18 -6
- package/dist/widgets/label-image/strings.d.ts +0 -3
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ var KAS = require('@khanacademy/kas');
|
|
|
6
6
|
var mathInput = require('@khanacademy/math-input');
|
|
7
7
|
var PerseusLinter = require('@khanacademy/perseus-linter');
|
|
8
8
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
9
|
-
var i18n = require('@khanacademy/wonder-blocks-i18n');
|
|
10
9
|
var Tooltip$1 = require('@khanacademy/wonder-blocks-tooltip');
|
|
11
10
|
var classNames = require('classnames');
|
|
12
11
|
var React = require('react');
|
|
@@ -64,7 +63,6 @@ function _interopNamespace(e) {
|
|
|
64
63
|
|
|
65
64
|
var KAS__namespace = /*#__PURE__*/_interopNamespace(KAS);
|
|
66
65
|
var PerseusLinter__namespace = /*#__PURE__*/_interopNamespace(PerseusLinter);
|
|
67
|
-
var i18n__namespace = /*#__PURE__*/_interopNamespace(i18n);
|
|
68
66
|
var Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip$1);
|
|
69
67
|
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
|
|
70
68
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
@@ -102,6 +100,290 @@ function _extends() {
|
|
|
102
100
|
return _extends.apply(this, arguments);
|
|
103
101
|
}
|
|
104
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The translated strings that are used to render Perseus.
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Mock strings for the Perseus package, to be used for tests and Storybook.
|
|
109
|
+
*/
|
|
110
|
+
const mockStrings = {
|
|
111
|
+
closeKeypad: "close math keypad",
|
|
112
|
+
openKeypad: "open math keypad",
|
|
113
|
+
removeHighlight: "Remove highlight",
|
|
114
|
+
addHighlight: "Add highlight",
|
|
115
|
+
hintPos: _ref => {
|
|
116
|
+
let {
|
|
117
|
+
pos
|
|
118
|
+
} = _ref;
|
|
119
|
+
return `Hint #${pos}`;
|
|
120
|
+
},
|
|
121
|
+
errorRendering: _ref2 => {
|
|
122
|
+
let {
|
|
123
|
+
error
|
|
124
|
+
} = _ref2;
|
|
125
|
+
return `Error rendering: ${error}`;
|
|
126
|
+
},
|
|
127
|
+
APPROXIMATED_PI_ERROR: "Your answer is close, but you may " + "have approximated pi. Enter your " + "answer as a multiple of pi, like " + "<code>12\\ \\text{pi}</code> or " + "<code>2/3\\ \\text{pi}</code>",
|
|
128
|
+
EXTRA_SYMBOLS_ERROR: "We could not understand your " + "answer. Please check your answer for extra " + "text or symbols.",
|
|
129
|
+
NEEDS_TO_BE_SIMPLFIED_ERROR: "Your answer is almost correct, " + "but it needs to be simplified.",
|
|
130
|
+
MISSING_PERCENT_ERROR: "Your answer is almost correct, " + "but it is missing a " + "<code>\\%</code> at the end.",
|
|
131
|
+
MULTIPLICATION_SIGN_ERROR: "I'm a computer. I only understand " + "multiplication if you use an asterisk " + "(*) as the multiplication sign.",
|
|
132
|
+
WRONG_CASE_ERROR: "Your answer includes use of a variable with the wrong case.",
|
|
133
|
+
WRONG_LETTER_ERROR: "Your answer includes a wrong variable letter.",
|
|
134
|
+
invalidSelection: "Make sure you select something for every row.",
|
|
135
|
+
ERROR_TITLE: "Oops!",
|
|
136
|
+
ERROR_MESSAGE: "Sorry, I don't understand that!",
|
|
137
|
+
hints: "Hints",
|
|
138
|
+
getAnotherHint: "Get another hint",
|
|
139
|
+
deprecatedStandin: "Sorry, this part of the question is no longer available. 😅 Don't worry, you won't be graded on this part. Keep going!",
|
|
140
|
+
keepTrying: "Keep trying",
|
|
141
|
+
tryAgain: "Try again",
|
|
142
|
+
check: "Check",
|
|
143
|
+
correctExcited: "Correct!",
|
|
144
|
+
nextQuestion: "Next question",
|
|
145
|
+
skipToTitle: _ref3 => {
|
|
146
|
+
let {
|
|
147
|
+
title
|
|
148
|
+
} = _ref3;
|
|
149
|
+
return `Skip to ${title}`;
|
|
150
|
+
},
|
|
151
|
+
current: "Current",
|
|
152
|
+
correct: "Correct",
|
|
153
|
+
correctSelected: "Correct (selected)",
|
|
154
|
+
correctCrossedOut: "Correct (but you crossed it out)",
|
|
155
|
+
incorrect: "Incorrect",
|
|
156
|
+
incorrectSelected: "Incorrect (selected)",
|
|
157
|
+
hideExplanation: "Hide explanation",
|
|
158
|
+
explain: "Explain",
|
|
159
|
+
INVALID_MESSAGE_PREFIX: "We couldn't grade your answer.",
|
|
160
|
+
DEFAULT_INVALID_MESSAGE_1: "It looks like you left something blank or ",
|
|
161
|
+
DEFAULT_INVALID_MESSAGE_2: "entered in an invalid answer.",
|
|
162
|
+
integerExample: "an integer, like $6$",
|
|
163
|
+
properExample: "a *proper* fraction, like $1/2$ or $6/10$",
|
|
164
|
+
simplifiedProperExample: "a *simplified proper* fraction, like $3/5$",
|
|
165
|
+
improperExample: "an *improper* fraction, like $10/7$ or $14/8$",
|
|
166
|
+
simplifiedImproperExample: "a *simplified improper* fraction, like $7/4$",
|
|
167
|
+
mixedExample: "a mixed number, like $1\\ 3/4$",
|
|
168
|
+
decimalExample: "an *exact* decimal, like $0.75$",
|
|
169
|
+
percentExample: "a percent, like $12.34\\%$",
|
|
170
|
+
piExample: "a multiple of pi, like $12\\ \\text{pi}$ or $2/3\\ \\text{pi}$",
|
|
171
|
+
yourAnswer: "**Your answer should be** ",
|
|
172
|
+
yourAnswerLabel: "Your answer:",
|
|
173
|
+
addPoints: "Click to add points",
|
|
174
|
+
addVertices: "Click to add vertices",
|
|
175
|
+
tapMultiple: "Tap each dot on the image to select all answers that apply.",
|
|
176
|
+
tapSingle: "Tap each dot on the image to select an answer.",
|
|
177
|
+
clickMultiple: "Click each dot on the image to select all answers that apply.",
|
|
178
|
+
clickSingle: "Click each dot on the image to select an answer.",
|
|
179
|
+
choices: "Choices:",
|
|
180
|
+
answers: _ref4 => {
|
|
181
|
+
let {
|
|
182
|
+
num
|
|
183
|
+
} = _ref4;
|
|
184
|
+
return num === 1 ? `${num} answer` : `${num} answers`;
|
|
185
|
+
},
|
|
186
|
+
hideAnswersToggleLabel: "Hide answer choices",
|
|
187
|
+
moves: _ref5 => {
|
|
188
|
+
let {
|
|
189
|
+
num
|
|
190
|
+
} = _ref5;
|
|
191
|
+
return num === 1 ? `Moves: ${num}` : `Moves: ${num}`;
|
|
192
|
+
},
|
|
193
|
+
clickTiles: "Click on the tiles to change the lights.",
|
|
194
|
+
turnOffLights: "You must turn on all of the lights to continue.",
|
|
195
|
+
fillAllCells: "Make sure you fill in all cells in the matrix.",
|
|
196
|
+
molecularDrawing: _ref6 => {
|
|
197
|
+
let {
|
|
198
|
+
content
|
|
199
|
+
} = _ref6;
|
|
200
|
+
return `A molecular structure drawing. SMILES notation: ${content}`;
|
|
201
|
+
},
|
|
202
|
+
switchDirection: "Switch direction",
|
|
203
|
+
circleOpen: "Make circle open",
|
|
204
|
+
circleFilled: "Make circle filled",
|
|
205
|
+
numDivisions: "Number of divisions:",
|
|
206
|
+
divisions: _ref7 => {
|
|
207
|
+
let {
|
|
208
|
+
divRangeString
|
|
209
|
+
} = _ref7;
|
|
210
|
+
return `Please make sure the number of divisions is in the range ${divRangeString}.`;
|
|
211
|
+
},
|
|
212
|
+
lineRange: _ref8 => {
|
|
213
|
+
let {
|
|
214
|
+
lineRange
|
|
215
|
+
} = _ref8;
|
|
216
|
+
return `lines ${lineRange}`;
|
|
217
|
+
},
|
|
218
|
+
lineNumber: _ref9 => {
|
|
219
|
+
let {
|
|
220
|
+
lineNumber
|
|
221
|
+
} = _ref9;
|
|
222
|
+
return `line ${lineNumber}`;
|
|
223
|
+
},
|
|
224
|
+
symbolPassage: _ref10 => {
|
|
225
|
+
let {
|
|
226
|
+
questionSymbol,
|
|
227
|
+
questionNumber
|
|
228
|
+
} = _ref10;
|
|
229
|
+
return `The symbol ${questionSymbol} indicates that question ${questionNumber} references this portion of the passage.`;
|
|
230
|
+
},
|
|
231
|
+
symbolQuestion: _ref11 => {
|
|
232
|
+
let {
|
|
233
|
+
sentenceSymbol
|
|
234
|
+
} = _ref11;
|
|
235
|
+
return ` The symbol ${sentenceSymbol} indicates that the following sentence is referenced in a question.`;
|
|
236
|
+
},
|
|
237
|
+
lineLabel: "Line",
|
|
238
|
+
beginningPassage: "Beginning of reading passage.",
|
|
239
|
+
beginningFootnotes: "Beginning of reading passage footnotes.",
|
|
240
|
+
endPassage: "End of reading passage.",
|
|
241
|
+
questionMarker: _ref12 => {
|
|
242
|
+
let {
|
|
243
|
+
number
|
|
244
|
+
} = _ref12;
|
|
245
|
+
return `[Marker for question ${number}]`;
|
|
246
|
+
},
|
|
247
|
+
circleMarker: _ref13 => {
|
|
248
|
+
let {
|
|
249
|
+
number
|
|
250
|
+
} = _ref13;
|
|
251
|
+
return `[Circle marker ${number}]`;
|
|
252
|
+
},
|
|
253
|
+
sentenceMarker: _ref14 => {
|
|
254
|
+
let {
|
|
255
|
+
number
|
|
256
|
+
} = _ref14;
|
|
257
|
+
return `[Sentence ${number}]`;
|
|
258
|
+
},
|
|
259
|
+
dragHandles: "Drag handles to make graph",
|
|
260
|
+
tapAddPoints: "Tap to add points",
|
|
261
|
+
false: "False",
|
|
262
|
+
true: "True",
|
|
263
|
+
no: "No",
|
|
264
|
+
yes: "Yes",
|
|
265
|
+
chooseCorrectNum: "Please choose the correct number of answers.",
|
|
266
|
+
notNoneOfTheAbove: "'None of the above' may not be selected when other answers are selected.",
|
|
267
|
+
noneOfTheAbove: "None of the above",
|
|
268
|
+
chooseNumAnswers: _ref15 => {
|
|
269
|
+
let {
|
|
270
|
+
numCorrect
|
|
271
|
+
} = _ref15;
|
|
272
|
+
return `Choose ${numCorrect} answers:`;
|
|
273
|
+
},
|
|
274
|
+
chooseAllAnswers: "Choose all answers that apply:",
|
|
275
|
+
chooseOneAnswer: "Choose 1 answer:",
|
|
276
|
+
choiceCheckedCorrect: _ref16 => {
|
|
277
|
+
let {
|
|
278
|
+
letter
|
|
279
|
+
} = _ref16;
|
|
280
|
+
return `(Choice ${letter}, Checked, Correct)`;
|
|
281
|
+
},
|
|
282
|
+
choiceCrossedOutCorrect: _ref17 => {
|
|
283
|
+
let {
|
|
284
|
+
letter
|
|
285
|
+
} = _ref17;
|
|
286
|
+
return `(Choice ${letter}, Crossed out, Correct)`;
|
|
287
|
+
},
|
|
288
|
+
choiceCorrect: _ref18 => {
|
|
289
|
+
let {
|
|
290
|
+
letter
|
|
291
|
+
} = _ref18;
|
|
292
|
+
return `(Choice ${letter}, Correct)`;
|
|
293
|
+
},
|
|
294
|
+
choiceCheckedIncorrect: _ref19 => {
|
|
295
|
+
let {
|
|
296
|
+
letter
|
|
297
|
+
} = _ref19;
|
|
298
|
+
return `(Choice ${letter}, Checked, Incorrect)`;
|
|
299
|
+
},
|
|
300
|
+
choiceCrossedOutIncorrect: _ref20 => {
|
|
301
|
+
let {
|
|
302
|
+
letter
|
|
303
|
+
} = _ref20;
|
|
304
|
+
return `(Choice ${letter}, Crossed out, Incorrect)`;
|
|
305
|
+
},
|
|
306
|
+
choiceIncorrect: _ref21 => {
|
|
307
|
+
let {
|
|
308
|
+
letter
|
|
309
|
+
} = _ref21;
|
|
310
|
+
return `(Choice ${letter}, Incorrect)`;
|
|
311
|
+
},
|
|
312
|
+
choiceChecked: _ref22 => {
|
|
313
|
+
let {
|
|
314
|
+
letter
|
|
315
|
+
} = _ref22;
|
|
316
|
+
return `(Choice ${letter}, Checked)`;
|
|
317
|
+
},
|
|
318
|
+
choiceCrossedOut: _ref23 => {
|
|
319
|
+
let {
|
|
320
|
+
letter
|
|
321
|
+
} = _ref23;
|
|
322
|
+
return `(Choice ${letter}, Crossed out)`;
|
|
323
|
+
},
|
|
324
|
+
choice: _ref24 => {
|
|
325
|
+
let {
|
|
326
|
+
letter
|
|
327
|
+
} = _ref24;
|
|
328
|
+
return `(Choice ${letter})`;
|
|
329
|
+
},
|
|
330
|
+
crossOut: "Cross out",
|
|
331
|
+
crossOutOption: "Cross out option",
|
|
332
|
+
crossOutChoice: _ref25 => {
|
|
333
|
+
let {
|
|
334
|
+
letter
|
|
335
|
+
} = _ref25;
|
|
336
|
+
return `Cross out Choice ${letter}`;
|
|
337
|
+
},
|
|
338
|
+
bringBack: "Bring back",
|
|
339
|
+
openMenuForChoice: _ref26 => {
|
|
340
|
+
let {
|
|
341
|
+
letter
|
|
342
|
+
} = _ref26;
|
|
343
|
+
return `Open menu for Choice ${letter}`;
|
|
344
|
+
},
|
|
345
|
+
letters: "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z",
|
|
346
|
+
rightArrow: "Reaction arrow pointing to the right.",
|
|
347
|
+
dontUnderstandUnits: "I couldn't understand those units.",
|
|
348
|
+
checkSigFigs: "Check your significant figures.",
|
|
349
|
+
answerNumericallyIncorrect: "That answer is numerically incorrect.",
|
|
350
|
+
checkUnits: "Check your units.",
|
|
351
|
+
dontUnderstand: "I don't understand that",
|
|
352
|
+
loading: "Loading...",
|
|
353
|
+
videoTranscript: "See video transcript",
|
|
354
|
+
somethingWrong: "Something went wrong.",
|
|
355
|
+
videoWrapper: "Khan Academy video wrapper"
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* PerseusI18nContext provides a way to set the strings and locale that are
|
|
360
|
+
* used inside the Perseus package.
|
|
361
|
+
*
|
|
362
|
+
*/
|
|
363
|
+
// @ts-expect-error - TS2322 - Type 'Context<{ strings: {}; locale: string; }>' is not assignable to type 'Context<I18nContextType>'.
|
|
364
|
+
const PerseusI18nContext = /*#__PURE__*/React__namespace.createContext(process.env.NODE_ENV === "test" || process.env.STORYBOOK ? {
|
|
365
|
+
strings: mockStrings,
|
|
366
|
+
locale: "en"
|
|
367
|
+
} :
|
|
368
|
+
// We want to return null here, not an empty object, so that we
|
|
369
|
+
// are will throw an error when attempting to access the
|
|
370
|
+
// undefined locale or strings, making it easier to debug.
|
|
371
|
+
null);
|
|
372
|
+
function PerseusI18nContextProvider(_ref) {
|
|
373
|
+
let {
|
|
374
|
+
children,
|
|
375
|
+
strings,
|
|
376
|
+
locale
|
|
377
|
+
} = _ref;
|
|
378
|
+
return /*#__PURE__*/React__namespace.createElement(PerseusI18nContext.Provider, {
|
|
379
|
+
value: {
|
|
380
|
+
strings,
|
|
381
|
+
locale
|
|
382
|
+
}
|
|
383
|
+
}, children);
|
|
384
|
+
}
|
|
385
|
+
const usePerseusI18n = () => React.useContext(PerseusI18nContext);
|
|
386
|
+
|
|
105
387
|
const debounce = (func, delay) => {
|
|
106
388
|
let timer = null;
|
|
107
389
|
return function () {
|
|
@@ -117,24 +399,11 @@ const debounce = (func, delay) => {
|
|
|
117
399
|
};
|
|
118
400
|
};
|
|
119
401
|
|
|
120
|
-
const customKeyTranslator = {
|
|
121
|
-
...mathInput.keyTranslator,
|
|
122
|
-
// If there's something in the input that can become part of a
|
|
123
|
-
// fraction, typing "/" puts it in the numerator. If not, typing
|
|
124
|
-
// "/" does nothing. In that case, enter a \frac.
|
|
125
|
-
FRAC: mathQuill => {
|
|
126
|
-
const contents = mathQuill.latex();
|
|
127
|
-
mathQuill.typedText("/");
|
|
128
|
-
if (mathQuill.latex() === contents) {
|
|
129
|
-
mathQuill.cmd("\\frac");
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
402
|
// A WYSIWYG math input that calls `onChange(LaTeX-string)`
|
|
135
|
-
class
|
|
403
|
+
class InnerMathInput extends React__namespace.Component {
|
|
404
|
+
static contextType = PerseusI18nContext;
|
|
136
405
|
// @ts-expect-error - TS2564 - Property 'mouseDown' has no initializer and is not definitely assigned in the constructor.
|
|
137
|
-
|
|
406
|
+
mouseDown;
|
|
138
407
|
__mathFieldWrapperRef = null;
|
|
139
408
|
__mathField = null;
|
|
140
409
|
static defaultProps = {
|
|
@@ -166,6 +435,22 @@ class MathInput extends React__namespace.Component {
|
|
|
166
435
|
}
|
|
167
436
|
insert = value => {
|
|
168
437
|
const input = this.mathField();
|
|
438
|
+
const {
|
|
439
|
+
locale
|
|
440
|
+
} = this.context;
|
|
441
|
+
const customKeyTranslator = {
|
|
442
|
+
...mathInput.getKeyTranslator(locale),
|
|
443
|
+
// If there's something in the input that can become part of a
|
|
444
|
+
// fraction, typing "/" puts it in the numerator. If not, typing
|
|
445
|
+
// "/" does nothing. In that case, enter a \frac.
|
|
446
|
+
FRAC: mathQuill => {
|
|
447
|
+
const contents = mathQuill.latex();
|
|
448
|
+
mathQuill.typedText("/");
|
|
449
|
+
if (mathQuill.latex() === contents) {
|
|
450
|
+
mathQuill.cmd("\\frac");
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
|
169
454
|
const inputModifier = customKeyTranslator[value];
|
|
170
455
|
if (inputModifier) {
|
|
171
456
|
inputModifier(input, value);
|
|
@@ -188,8 +473,11 @@ class MathInput extends React__namespace.Component {
|
|
|
188
473
|
};
|
|
189
474
|
mathField = () => {
|
|
190
475
|
if (!this.__mathField && this.__mathFieldWrapperRef) {
|
|
476
|
+
const {
|
|
477
|
+
locale
|
|
478
|
+
} = this.context;
|
|
191
479
|
// Initialize MathQuill.MathField instance
|
|
192
|
-
this.__mathField = mathInput.createMathField(this.__mathFieldWrapperRef, baseConfig => ({
|
|
480
|
+
this.__mathField = mathInput.createMathField(this.__mathFieldWrapperRef, this.props.mathInputStrings, baseConfig => ({
|
|
193
481
|
...baseConfig,
|
|
194
482
|
handlers: {
|
|
195
483
|
edit: debounce(mathField => {
|
|
@@ -206,7 +494,7 @@ class MathInput extends React__namespace.Component {
|
|
|
206
494
|
// Use the specified symbol to represent multiplication
|
|
207
495
|
// TODO(alex): Add an option to disallow variables, in
|
|
208
496
|
// which case 'x' should get converted to '\\times'
|
|
209
|
-
if (mathInput.convertDotToTimesByLocale(this.props.convertDotToTimes)) {
|
|
497
|
+
if (mathInput.convertDotToTimesByLocale(locale, this.props.convertDotToTimes)) {
|
|
210
498
|
value = value.replace(/\\cdot/g, "\\times");
|
|
211
499
|
|
|
212
500
|
// Preserve cursor position in the common case:
|
|
@@ -266,7 +554,10 @@ class MathInput extends React__namespace.Component {
|
|
|
266
554
|
focused: false
|
|
267
555
|
});
|
|
268
556
|
handleKeypadPress = (key, e) => {
|
|
269
|
-
const
|
|
557
|
+
const {
|
|
558
|
+
locale
|
|
559
|
+
} = this.context;
|
|
560
|
+
const translator = mathInput.getKeyTranslator(locale)[key];
|
|
270
561
|
const mathField = this.mathField();
|
|
271
562
|
if (mathField) {
|
|
272
563
|
if (translator) {
|
|
@@ -342,7 +633,7 @@ class MathInput extends React__namespace.Component {
|
|
|
342
633
|
focused: false,
|
|
343
634
|
active: false
|
|
344
635
|
}) : /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
|
|
345
|
-
"aria-label": this.state.keypadOpen ?
|
|
636
|
+
"aria-label": this.state.keypadOpen ? this.context.strings.closeKeypad : this.context.strings.openKeypad,
|
|
346
637
|
"aria-checked": this.state.keypadOpen,
|
|
347
638
|
role: "switch",
|
|
348
639
|
onClick: () => this.state.keypadOpen ? this.closeKeypad() : this.openKeypad()
|
|
@@ -351,6 +642,26 @@ class MathInput extends React__namespace.Component {
|
|
|
351
642
|
}, props))))));
|
|
352
643
|
}
|
|
353
644
|
}
|
|
645
|
+
|
|
646
|
+
// We need to have two contexts (one for Perseus and one for MathInput), so we
|
|
647
|
+
// add a wrapper around the MathInput component to provide the MathInput context
|
|
648
|
+
// to it.
|
|
649
|
+
class MathInput extends React__namespace.Component {
|
|
650
|
+
static contextType = mathInput.MathInputI18nContext;
|
|
651
|
+
inputRef = /*#__PURE__*/React__namespace.createRef();
|
|
652
|
+
focus() {
|
|
653
|
+
this.inputRef.current?.focus();
|
|
654
|
+
}
|
|
655
|
+
insert(value) {
|
|
656
|
+
this.inputRef.current?.insert(value);
|
|
657
|
+
}
|
|
658
|
+
render() {
|
|
659
|
+
return /*#__PURE__*/React__namespace.createElement(InnerMathInput, _extends({}, this.props, {
|
|
660
|
+
ref: this.inputRef,
|
|
661
|
+
mathInputStrings: this.context.strings
|
|
662
|
+
}));
|
|
663
|
+
}
|
|
664
|
+
}
|
|
354
665
|
const MathInputIcon = _ref => {
|
|
355
666
|
let {
|
|
356
667
|
hovered,
|
|
@@ -547,6 +858,8 @@ const Log = {
|
|
|
547
858
|
};
|
|
548
859
|
|
|
549
860
|
class PerseusError extends Error {
|
|
861
|
+
kind;
|
|
862
|
+
metadata;
|
|
550
863
|
constructor(message, kind, options) {
|
|
551
864
|
super(message);
|
|
552
865
|
this.kind = kind;
|
|
@@ -1264,16 +1577,6 @@ const MAXERROR_EPSILON = Math.pow(2, -42);
|
|
|
1264
1577
|
// TOOD(kevinb): Figure out how this relates to KEScore in
|
|
1265
1578
|
// perseus-all-package/types.js and see if there's a way to
|
|
1266
1579
|
// unify these types.
|
|
1267
|
-
const errors = {
|
|
1268
|
-
APPROXIMATED_PI_ERROR: i18n__namespace._("Your answer is close, but you may " + "have approximated pi. Enter your " + "answer as a multiple of pi, like " + "<code>12\\ \\text{pi}</code> or " + "<code>2/3\\ \\text{pi}</code>"),
|
|
1269
|
-
EXTRA_SYMBOLS_ERROR: i18n__namespace._("We could not understand your " + "answer. Please check your answer for extra " + "text or symbols."),
|
|
1270
|
-
NEEDS_TO_BE_SIMPLFIED_ERROR: i18n__namespace._("Your answer is almost correct, " + "but it needs to be simplified."),
|
|
1271
|
-
MISSING_PERCENT_ERROR: i18n__namespace._("Your answer is almost correct, " + "but it is missing a " + "<code>\\%</code> at the end."),
|
|
1272
|
-
MULTIPLICATION_SIGN_ERROR: i18n__namespace._("I'm a computer. I only understand " + "multiplication if you use an asterisk " + "(*) as the multiplication sign."),
|
|
1273
|
-
WRONG_CASE_ERROR: i18n__namespace._("Your answer includes use of a variable with the wrong case."),
|
|
1274
|
-
WRONG_LETTER_ERROR: i18n__namespace._("Your answer includes a wrong variable letter.")
|
|
1275
|
-
};
|
|
1276
|
-
|
|
1277
1580
|
/*
|
|
1278
1581
|
* Answer types
|
|
1279
1582
|
*
|
|
@@ -1346,7 +1649,7 @@ const KhanAnswerTypes = {
|
|
|
1346
1649
|
*/
|
|
1347
1650
|
predicate: {
|
|
1348
1651
|
defaultForms: "integer, proper, improper, mixed, decimal",
|
|
1349
|
-
createValidatorFunctional: function (predicate, options) {
|
|
1652
|
+
createValidatorFunctional: function (predicate, options, strings) {
|
|
1350
1653
|
// Extract the options from the given solution object
|
|
1351
1654
|
options = ___default["default"].extend({
|
|
1352
1655
|
simplify: "required",
|
|
@@ -1735,12 +2038,12 @@ const KhanAnswerTypes = {
|
|
|
1735
2038
|
} else if (form === "percent") {
|
|
1736
2039
|
// Otherwise, an error was returned
|
|
1737
2040
|
score.empty = true;
|
|
1738
|
-
score.message =
|
|
2041
|
+
score.message = strings.MISSING_PERCENT_ERROR;
|
|
1739
2042
|
} else {
|
|
1740
2043
|
if (options.simplify !== "enforced") {
|
|
1741
2044
|
score.empty = true;
|
|
1742
2045
|
}
|
|
1743
|
-
score.message =
|
|
2046
|
+
score.message = strings.NEEDS_TO_BE_SIMPLFIED_ERROR;
|
|
1744
2047
|
}
|
|
1745
2048
|
// The return false below stops the looping of the
|
|
1746
2049
|
// callback since predicate check succeeded.
|
|
@@ -1749,7 +2052,7 @@ const KhanAnswerTypes = {
|
|
|
1749
2052
|
}
|
|
1750
2053
|
if (piApprox && predicate(val, Math.abs(val * 0.001))) {
|
|
1751
2054
|
score.empty = true;
|
|
1752
|
-
score.message =
|
|
2055
|
+
score.message = strings.APPROXIMATED_PI_ERROR;
|
|
1753
2056
|
}
|
|
1754
2057
|
}
|
|
1755
2058
|
});
|
|
@@ -1765,7 +2068,7 @@ const KhanAnswerTypes = {
|
|
|
1765
2068
|
});
|
|
1766
2069
|
if (!interpretedGuess) {
|
|
1767
2070
|
score.empty = true;
|
|
1768
|
-
score.message =
|
|
2071
|
+
score.message = strings.EXTRA_SYMBOLS_ERROR;
|
|
1769
2072
|
return score;
|
|
1770
2073
|
}
|
|
1771
2074
|
}
|
|
@@ -1788,10 +2091,10 @@ const KhanAnswerTypes = {
|
|
|
1788
2091
|
type: "predicate"
|
|
1789
2092
|
})];
|
|
1790
2093
|
},
|
|
1791
|
-
createValidatorFunctional: function (correctAnswer, options) {
|
|
2094
|
+
createValidatorFunctional: function (correctAnswer, options, strings) {
|
|
1792
2095
|
return KhanAnswerTypes.predicate.createValidatorFunctional(
|
|
1793
2096
|
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
1794
|
-
...KhanAnswerTypes.number.convertToPredicate(correctAnswer, options));
|
|
2097
|
+
...KhanAnswerTypes.number.convertToPredicate(correctAnswer, options), strings);
|
|
1795
2098
|
}
|
|
1796
2099
|
},
|
|
1797
2100
|
/*
|
|
@@ -1856,7 +2159,7 @@ const KhanAnswerTypes = {
|
|
|
1856
2159
|
}
|
|
1857
2160
|
return solution;
|
|
1858
2161
|
},
|
|
1859
|
-
createValidatorFunctional: function (solution, options) {
|
|
2162
|
+
createValidatorFunctional: function (solution, options, strings) {
|
|
1860
2163
|
return function (guess) {
|
|
1861
2164
|
const score = {
|
|
1862
2165
|
empty: false,
|
|
@@ -1907,7 +2210,7 @@ const KhanAnswerTypes = {
|
|
|
1907
2210
|
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
1908
2211
|
score.ungraded = true;
|
|
1909
2212
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
1910
|
-
score.message = result.wrongVariableCase ?
|
|
2213
|
+
score.message = result.wrongVariableCase ? strings.WRONG_CASE_ERROR : strings.WRONG_LETTER_ERROR;
|
|
1911
2214
|
// Don't tell the use they're "almost there" in this case, that may not be true and isn't helpful.
|
|
1912
2215
|
// @ts-expect-error - TS2339 - Property 'suppressAlmostThere' does not exist on type '{ readonly empty: false; readonly correct: false; readonly message: string | null | undefined; readonly guess: any; readonly ungraded: false; }'.
|
|
1913
2216
|
score.suppressAlmostThere = true;
|
|
@@ -1933,7 +2236,7 @@ const KhanAnswerTypes = {
|
|
|
1933
2236
|
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
1934
2237
|
score.ungraded = true;
|
|
1935
2238
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
1936
|
-
score.message =
|
|
2239
|
+
score.message = strings.MULTIPLICATION_SIGN_ERROR;
|
|
1937
2240
|
} else if (resultX.message) {
|
|
1938
2241
|
// TODO(aasmund): I18nize `score.message`
|
|
1939
2242
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
@@ -1947,9 +2250,6 @@ const KhanAnswerTypes = {
|
|
|
1947
2250
|
}
|
|
1948
2251
|
};
|
|
1949
2252
|
|
|
1950
|
-
const ERROR_TITLE = i18n__namespace._("Oops!");
|
|
1951
|
-
const ERROR_MESSAGE = i18n__namespace._("Sorry, I don't understand that!");
|
|
1952
|
-
|
|
1953
2253
|
// Map of international operator names to their English equivalents
|
|
1954
2254
|
const englishOperators = {
|
|
1955
2255
|
arctg: "arctan",
|
|
@@ -1976,8 +2276,34 @@ const deriveKeypadVersion = apiOptions => {
|
|
|
1976
2276
|
// can remove this `virtualKeypadVersion` field entirely.
|
|
1977
2277
|
return apiOptions.nativeKeypadProxy != null ? "REACT_NATIVE_KEYPAD" : "MATH_INPUT_KEYPAD_V2";
|
|
1978
2278
|
};
|
|
2279
|
+
/**
|
|
2280
|
+
* Get the character used for separating decimals.
|
|
2281
|
+
*/
|
|
2282
|
+
const getDecimalSeparator = locale => {
|
|
2283
|
+
switch (locale) {
|
|
2284
|
+
// TODO(somewhatabstract): Remove this when Chrome supports the `ka`
|
|
2285
|
+
// locale properly.
|
|
2286
|
+
// https://github.com/formatjs/formatjs/issues/1526#issuecomment-559891201
|
|
2287
|
+
//
|
|
2288
|
+
// Supported locales in Chrome:
|
|
2289
|
+
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/icu/scripts/chrome_ui_languages.list
|
|
2290
|
+
case "ka":
|
|
2291
|
+
return ",";
|
|
2292
|
+
default:
|
|
2293
|
+
const numberWithDecimalSeparator = 1.1;
|
|
2294
|
+
// TODO(FEI-3647): Update to use .formatToParts() once we no longer have to
|
|
2295
|
+
// support Safari 12.
|
|
2296
|
+
const match = new Intl.NumberFormat(locale).format(numberWithDecimalSeparator)
|
|
2297
|
+
// 0x661 is ARABIC-INDIC DIGIT ONE
|
|
2298
|
+
// 0x6F1 is EXTENDED ARABIC-INDIC DIGIT ONE
|
|
2299
|
+
.match(/[^\d\u0661\u06F1]/);
|
|
2300
|
+
return match?.[0] ?? ".";
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
|
|
1979
2304
|
// The new, MathQuill input expression widget
|
|
1980
2305
|
class Expression extends React__namespace.Component {
|
|
2306
|
+
static contextType = PerseusI18nContext;
|
|
1981
2307
|
_isMounted = false;
|
|
1982
2308
|
|
|
1983
2309
|
//#region Previously a class extension
|
|
@@ -2001,9 +2327,11 @@ class Expression extends React__namespace.Component {
|
|
|
2001
2327
|
*/
|
|
2002
2328
|
static validate(userInput, rubric) {
|
|
2003
2329
|
let onInputError = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
|
|
2330
|
+
let strings = arguments.length > 3 ? arguments[3] : undefined;
|
|
2331
|
+
let locale = arguments.length > 4 ? arguments[4] : undefined;
|
|
2004
2332
|
const options = ___default["default"].clone(rubric);
|
|
2005
2333
|
___default["default"].extend(options, {
|
|
2006
|
-
decimal_separator:
|
|
2334
|
+
decimal_separator: getDecimalSeparator(locale)
|
|
2007
2335
|
});
|
|
2008
2336
|
const createValidator = answer => {
|
|
2009
2337
|
// We give options to KAS.parse here because it is parsing the
|
|
@@ -2026,7 +2354,7 @@ class Expression extends React__namespace.Component {
|
|
|
2026
2354
|
return KhanAnswerTypes.expression.createValidatorFunctional(expression.expr, ___default["default"]({}).extend(options, {
|
|
2027
2355
|
simplify: answer.simplify,
|
|
2028
2356
|
form: answer.form
|
|
2029
|
-
}));
|
|
2357
|
+
}), strings);
|
|
2030
2358
|
};
|
|
2031
2359
|
|
|
2032
2360
|
// Find the first answer form that matches the user's input and that
|
|
@@ -2173,7 +2501,7 @@ class Expression extends React__namespace.Component {
|
|
|
2173
2501
|
if (!this.parse(this.props.value, this.props).parsed) {
|
|
2174
2502
|
const apiResult = this.props.apiOptions.onInputError(null,
|
|
2175
2503
|
// reserved for some widget identifier
|
|
2176
|
-
this.props.value,
|
|
2504
|
+
this.props.value, this.context.strings.ERROR_TITLE);
|
|
2177
2505
|
if (apiResult !== false) {
|
|
2178
2506
|
this.setState({
|
|
2179
2507
|
invalid: true
|
|
@@ -2197,7 +2525,7 @@ class Expression extends React__namespace.Component {
|
|
|
2197
2525
|
scoring,
|
|
2198
2526
|
...rubric
|
|
2199
2527
|
} = _ref;
|
|
2200
|
-
const score = Expression.validate(this.getUserInput(), rubric, onInputError || function () {});
|
|
2528
|
+
const score = Expression.validate(this.getUserInput(), rubric, onInputError || function () {}, this.context.strings, this.context.locale);
|
|
2201
2529
|
|
|
2202
2530
|
// "scoring" is a flag that indicates when we are checking answers.
|
|
2203
2531
|
// otherwise, we may just be checking validity after changes.
|
|
@@ -2229,7 +2557,7 @@ class Expression extends React__namespace.Component {
|
|
|
2229
2557
|
// make it so that solution answers with ','s or '.'s work
|
|
2230
2558
|
const options = ___default["default"].pick(props || this.props, "functions");
|
|
2231
2559
|
___default["default"].extend(options, {
|
|
2232
|
-
decimal_separator:
|
|
2560
|
+
decimal_separator: getDecimalSeparator(this.context.locale)
|
|
2233
2561
|
});
|
|
2234
2562
|
return KAS__namespace.parse(normalizeTex(value), options);
|
|
2235
2563
|
};
|
|
@@ -2318,6 +2646,10 @@ class Expression extends React__namespace.Component {
|
|
|
2318
2646
|
"perseus-widget-expression": true,
|
|
2319
2647
|
"show-error-tooltip": this.state.showErrorTooltip
|
|
2320
2648
|
});
|
|
2649
|
+
const {
|
|
2650
|
+
ERROR_MESSAGE,
|
|
2651
|
+
ERROR_TITLE
|
|
2652
|
+
} = this.context.strings;
|
|
2321
2653
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
2322
2654
|
className: className,
|
|
2323
2655
|
onBlur: () => this.state.invalid && this.setState({
|
|
@@ -2744,7 +3076,7 @@ function keScoreFromPerseusScore(score, guess, state) {
|
|
|
2744
3076
|
* Return the first valid interpretation of 'text' as a number, in the form
|
|
2745
3077
|
* {value: 2.3, exact: true}.
|
|
2746
3078
|
*/
|
|
2747
|
-
function firstNumericalParse$1(text) {
|
|
3079
|
+
function firstNumericalParse$1(text, strings) {
|
|
2748
3080
|
// TODO(alpert): This is sort of hacky...
|
|
2749
3081
|
let first;
|
|
2750
3082
|
const val = KhanAnswerTypes.predicate.createValidatorFunctional(function (ans) {
|
|
@@ -2754,7 +3086,7 @@ function firstNumericalParse$1(text) {
|
|
|
2754
3086
|
simplify: "optional",
|
|
2755
3087
|
inexact: true,
|
|
2756
3088
|
forms: "integer, proper, improper, pi, log, mixed, decimal"
|
|
2757
|
-
});
|
|
3089
|
+
}, strings);
|
|
2758
3090
|
val(text);
|
|
2759
3091
|
return first;
|
|
2760
3092
|
}
|
|
@@ -8566,8 +8898,12 @@ const KhanColors = {
|
|
|
8566
8898
|
// DrawingTransform is responsible for transforming from "math coordinates"
|
|
8567
8899
|
// (on the Cartesian plane) to "canvas coordinates" in pixels.
|
|
8568
8900
|
class DrawingTransform {
|
|
8569
|
-
|
|
8901
|
+
raphael;
|
|
8570
8902
|
|
|
8903
|
+
// Scale is measured in pixels per unit on the Cartesian plane.
|
|
8904
|
+
xScale;
|
|
8905
|
+
yScale;
|
|
8906
|
+
bounds;
|
|
8571
8907
|
constructor(raphael, initialScale, bounds) {
|
|
8572
8908
|
this.raphael = raphael;
|
|
8573
8909
|
this.bounds = bounds;
|
|
@@ -8632,6 +8968,10 @@ class DrawingTransform {
|
|
|
8632
8968
|
// Defines the bounds of the visible area of a graph, in Cartesian coordinates.
|
|
8633
8969
|
// GraphBounds is immutable.
|
|
8634
8970
|
class GraphBounds {
|
|
8971
|
+
xMin;
|
|
8972
|
+
xMax;
|
|
8973
|
+
yMin;
|
|
8974
|
+
yMax;
|
|
8635
8975
|
constructor(xRange, yRange) {
|
|
8636
8976
|
this.xMin = xRange[0];
|
|
8637
8977
|
this.xMax = xRange[1];
|
|
@@ -8735,26 +9075,35 @@ function polar(r, th) {
|
|
|
8735
9075
|
return [r[0] * Math.cos(th), r[1] * Math.sin(th)];
|
|
8736
9076
|
}
|
|
8737
9077
|
class Graphie$1 {
|
|
9078
|
+
el;
|
|
8738
9079
|
#bounds;
|
|
8739
9080
|
#drawingTransform;
|
|
8740
9081
|
|
|
8741
9082
|
// The primary drawing layer
|
|
8742
|
-
|
|
9083
|
+
raphael;
|
|
8743
9084
|
// The layer that all visuals with mouse handlers are drawn into
|
|
8744
|
-
|
|
9085
|
+
mouselayer;
|
|
9086
|
+
_mouselayerWrapper;
|
|
9087
|
+
_visiblelayerWrapper;
|
|
8745
9088
|
isMobile = false;
|
|
8746
9089
|
// Set up some reasonable defaults
|
|
8747
9090
|
currentStyle = {
|
|
8748
9091
|
"stroke-width": 2,
|
|
8749
9092
|
fill: "none"
|
|
8750
9093
|
};
|
|
8751
|
-
|
|
9094
|
+
range;
|
|
9095
|
+
scale;
|
|
9096
|
+
dimensions;
|
|
8752
9097
|
// TODO(benchristel): xpixels and ypixels are never used by this class, but
|
|
8753
9098
|
// other code reaches in to access them :(
|
|
8754
9099
|
// Refactor to accessor methods that look at this.dimensions.
|
|
9100
|
+
xpixels;
|
|
9101
|
+
ypixels;
|
|
9102
|
+
|
|
8755
9103
|
// set by Movables
|
|
8756
9104
|
// TODO(benchristel): consider putting this state on the Movable instead of
|
|
8757
9105
|
// on the Graphie
|
|
9106
|
+
isDragging;
|
|
8758
9107
|
constructor(el) {
|
|
8759
9108
|
this.el = el;
|
|
8760
9109
|
$__default["default"](el).css("position", "relative");
|
|
@@ -10286,6 +10635,8 @@ const getClipPoint = function (graph, coord, angle) {
|
|
|
10286
10635
|
*/
|
|
10287
10636
|
|
|
10288
10637
|
class WrappedDrawing {
|
|
10638
|
+
graphie;
|
|
10639
|
+
initialPoint;
|
|
10289
10640
|
constructor(graphie, initialPoint) {
|
|
10290
10641
|
this.graphie = graphie;
|
|
10291
10642
|
this.initialPoint = initialPoint;
|
|
@@ -10346,6 +10697,8 @@ const DEFAULT_OPTIONS$2 = {
|
|
|
10346
10697
|
mouselayer: false
|
|
10347
10698
|
};
|
|
10348
10699
|
class WrappedPath extends WrappedDrawing {
|
|
10700
|
+
wrapper;
|
|
10701
|
+
visibleShape;
|
|
10349
10702
|
constructor(graphie, points, options) {
|
|
10350
10703
|
const initialPoint = graphie.scalePoint(___default["default"].head(points));
|
|
10351
10704
|
super(graphie, initialPoint);
|
|
@@ -10368,6 +10721,7 @@ class WrappedPath extends WrappedDrawing {
|
|
|
10368
10721
|
|
|
10369
10722
|
class Arrowhead$1 extends WrappedPath {
|
|
10370
10723
|
static scale = 1.4;
|
|
10724
|
+
center;
|
|
10371
10725
|
constructor(graphie, style) {
|
|
10372
10726
|
// Points that define the arrowhead
|
|
10373
10727
|
const center = [0.75, 0];
|
|
@@ -10413,6 +10767,9 @@ const DEFAULT_OPTIONS$1 = {
|
|
|
10413
10767
|
disableMouseEventsOnWrapper: false
|
|
10414
10768
|
};
|
|
10415
10769
|
class WrappedEllipse extends WrappedDrawing {
|
|
10770
|
+
initialPoint;
|
|
10771
|
+
wrapper;
|
|
10772
|
+
visibleShape;
|
|
10416
10773
|
constructor(graphie, center, radii, options) {
|
|
10417
10774
|
super(graphie, center);
|
|
10418
10775
|
options = ___default["default"].extend({}, DEFAULT_OPTIONS$1, options);
|
|
@@ -10460,6 +10817,9 @@ const DEFAULT_OPTIONS = {
|
|
|
10460
10817
|
mouselayer: false
|
|
10461
10818
|
};
|
|
10462
10819
|
class WrappedLine extends WrappedDrawing {
|
|
10820
|
+
initialLength;
|
|
10821
|
+
wrapper;
|
|
10822
|
+
visibleShape;
|
|
10463
10823
|
constructor(graphie, start, end, options) {
|
|
10464
10824
|
// Always make the line as large as possible and horizontal; this
|
|
10465
10825
|
// simplifies a lot of the transforms, e.g., we can rotate by exactly the
|
|
@@ -13753,6 +14113,9 @@ const DEFAULT_STATE$3 = {
|
|
|
13753
14113
|
mouseTarget: null
|
|
13754
14114
|
};
|
|
13755
14115
|
class Movable {
|
|
14116
|
+
graphie;
|
|
14117
|
+
state;
|
|
14118
|
+
prevState;
|
|
13756
14119
|
// TODO(benchristel): delete _listenerMap; it's unused
|
|
13757
14120
|
_listenerMap = {};
|
|
13758
14121
|
constructor(graphie, options) {
|
|
@@ -13878,12 +14241,12 @@ class Movable {
|
|
|
13878
14241
|
* Fire an onSomething type event to all functions in listeners
|
|
13879
14242
|
*/
|
|
13880
14243
|
_fireEvent(listeners) {
|
|
13881
|
-
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
13882
|
-
args[_key - 1] = arguments[_key];
|
|
13883
|
-
}
|
|
13884
14244
|
if (listeners == null) {
|
|
13885
14245
|
return;
|
|
13886
14246
|
}
|
|
14247
|
+
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
14248
|
+
args[_key - 1] = arguments[_key];
|
|
14249
|
+
}
|
|
13887
14250
|
for (const listener of listeners) {
|
|
13888
14251
|
listener.call(this, ...args);
|
|
13889
14252
|
}
|
|
@@ -15016,8 +15379,12 @@ const DEFAULT_STATE$1 = {
|
|
|
15016
15379
|
// tooltipResetFunctions, but never remove them.
|
|
15017
15380
|
const tooltipResetFunctions = [];
|
|
15018
15381
|
class MovablePoint$4 {
|
|
15382
|
+
graphie;
|
|
15383
|
+
movable;
|
|
15384
|
+
state;
|
|
15019
15385
|
// @ts-expect-error - TS2564: Property 'prevState' has no initializer and is not definitely assigned in the constructor.
|
|
15020
|
-
|
|
15386
|
+
prevState;
|
|
15387
|
+
_tooltip;
|
|
15021
15388
|
_listenerMap = {};
|
|
15022
15389
|
constructor(graphie, movable, options) {
|
|
15023
15390
|
this.graphie = graphie;
|
|
@@ -16706,6 +17073,7 @@ const Status = {
|
|
|
16706
17073
|
FAILED: "failed"
|
|
16707
17074
|
};
|
|
16708
17075
|
class ImageLoader extends React__namespace.Component {
|
|
17076
|
+
img;
|
|
16709
17077
|
constructor(props) {
|
|
16710
17078
|
super(props);
|
|
16711
17079
|
this.state = {
|
|
@@ -16942,6 +17310,7 @@ function defaultPreloader(dimensions) {
|
|
|
16942
17310
|
}));
|
|
16943
17311
|
}
|
|
16944
17312
|
class SvgImage extends React__namespace.Component {
|
|
17313
|
+
_isMounted;
|
|
16945
17314
|
static defaultProps = {
|
|
16946
17315
|
constrainHeight: false,
|
|
16947
17316
|
onUpdate: () => {},
|
|
@@ -17387,6 +17756,7 @@ class SvgImage extends React__namespace.Component {
|
|
|
17387
17756
|
* have been loaded. This tracking is facilitated by the AssetContext.
|
|
17388
17757
|
*/
|
|
17389
17758
|
class Tex extends React__namespace.Component {
|
|
17759
|
+
_hasRendered;
|
|
17390
17760
|
static defaultProps = {
|
|
17391
17761
|
onRender: () => {},
|
|
17392
17762
|
setAssetStatus: (src, status) => {}
|
|
@@ -17428,13 +17798,14 @@ class Tex extends React__namespace.Component {
|
|
|
17428
17798
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
17429
17799
|
class Zoomable extends React__namespace.Component {
|
|
17430
17800
|
// @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
|
|
17431
|
-
|
|
17801
|
+
_isMounted;
|
|
17432
17802
|
// @ts-expect-error - TS2564 - Property '_observer' has no initializer and is not definitely assigned in the constructor.
|
|
17433
|
-
|
|
17803
|
+
_observer;
|
|
17434
17804
|
// @ts-expect-error - TS2564 - Property '_measuringInitialized' has no initializer and is not definitely assigned in the constructor.
|
|
17435
|
-
|
|
17805
|
+
_measuringInitialized;
|
|
17806
|
+
_originalWidth;
|
|
17436
17807
|
// @ts-expect-error - TS2564 - Property '_node' has no initializer and is not definitely assigned in the constructor.
|
|
17437
|
-
|
|
17808
|
+
_node;
|
|
17438
17809
|
static defaultProps = {
|
|
17439
17810
|
animateHeight: false,
|
|
17440
17811
|
readyToMeasure: true,
|
|
@@ -17793,13 +18164,15 @@ function _noop() {}
|
|
|
17793
18164
|
*/
|
|
17794
18165
|
class InteractionTracker {
|
|
17795
18166
|
// @ts-expect-error - TS2564 - Property '_tracked' has no initializer and is not definitely assigned in the constructor.
|
|
17796
|
-
|
|
18167
|
+
_tracked;
|
|
17797
18168
|
// @ts-expect-error - TS2564 - Property 'setting' has no initializer and is not definitely assigned in the constructor.
|
|
17798
|
-
|
|
18169
|
+
setting;
|
|
18170
|
+
track;
|
|
18171
|
+
trackApi;
|
|
17799
18172
|
// @ts-expect-error - TS2564 - Property 'widgetID' has no initializer and is not definitely assigned in the constructor.
|
|
17800
|
-
|
|
18173
|
+
widgetID;
|
|
17801
18174
|
// @ts-expect-error - TS2564 - Property 'widgetType' has no initializer and is not definitely assigned in the constructor.
|
|
17802
|
-
|
|
18175
|
+
widgetType;
|
|
17803
18176
|
constructor(trackApi, widgetType, widgetID, setting) {
|
|
17804
18177
|
if (!trackApi) {
|
|
17805
18178
|
this.track = _noop;
|
|
@@ -17911,6 +18284,7 @@ var Severity = /*#__PURE__*/function (Severity) {
|
|
|
17911
18284
|
* to the left of where it belongs. And if there is more
|
|
17912
18285
|
**/
|
|
17913
18286
|
class Lint extends React__namespace.Component {
|
|
18287
|
+
_positionTimeout;
|
|
17914
18288
|
state = {
|
|
17915
18289
|
tooltipAbove: true
|
|
17916
18290
|
};
|
|
@@ -18367,7 +18741,7 @@ const rules$1 = {
|
|
|
18367
18741
|
// just a stub for testing.
|
|
18368
18742
|
return /*#__PURE__*/React__namespace.createElement("em", {
|
|
18369
18743
|
key: state.key
|
|
18370
|
-
},
|
|
18744
|
+
}, `[Widget: ${node.id}]`);
|
|
18371
18745
|
}
|
|
18372
18746
|
},
|
|
18373
18747
|
blockMath: {
|
|
@@ -18855,9 +19229,8 @@ const getWidget = name => {
|
|
|
18855
19229
|
}
|
|
18856
19230
|
|
|
18857
19231
|
// Allow widgets to specify a widget directly or via a function
|
|
18858
|
-
if (widgets[name]
|
|
18859
|
-
|
|
18860
|
-
return widgets[name].getWidget();
|
|
19232
|
+
if (widgets[name]?.getWidget) {
|
|
19233
|
+
return widgets[name].getWidget?.();
|
|
18861
19234
|
}
|
|
18862
19235
|
return widgets[name].widget;
|
|
18863
19236
|
};
|
|
@@ -19009,7 +19382,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
19009
19382
|
options: newEditorProps
|
|
19010
19383
|
});
|
|
19011
19384
|
};
|
|
19012
|
-
const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
19385
|
+
const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
19013
19386
|
const type = widgetInfo.type;
|
|
19014
19387
|
const widgetExports = widgets[type];
|
|
19015
19388
|
if (widgetExports == null) {
|
|
@@ -19030,7 +19403,7 @@ const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
|
19030
19403
|
transform = widgetExports.transform || ___default["default"].identity;
|
|
19031
19404
|
}
|
|
19032
19405
|
// widgetInfo.options are the widgetEditor's props:
|
|
19033
|
-
return transform(widgetInfo.options, problemNum);
|
|
19406
|
+
return transform(widgetInfo.options, strings, problemNum);
|
|
19034
19407
|
};
|
|
19035
19408
|
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
19036
19409
|
if (!traverseRenderer) {
|
|
@@ -19374,24 +19747,26 @@ const isIdPathPrefix = function (prefixArray, wholeArray) {
|
|
|
19374
19747
|
* scoring, state serialization/deserialization, and focus management.
|
|
19375
19748
|
*/
|
|
19376
19749
|
class Renderer extends React__namespace.Component {
|
|
19750
|
+
_currentFocus;
|
|
19377
19751
|
// @ts-expect-error - TS2564 - Property '_foundTextNodes' has no initializer and is not definitely assigned in the constructor.
|
|
19378
|
-
|
|
19752
|
+
_foundTextNodes;
|
|
19379
19753
|
// @ts-expect-error - TS2564 - Property '_interactionTrackers' has no initializer and is not definitely assigned in the constructor.
|
|
19380
|
-
|
|
19754
|
+
_interactionTrackers;
|
|
19381
19755
|
// @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
|
|
19382
|
-
|
|
19756
|
+
_isMounted;
|
|
19383
19757
|
// @ts-expect-error - TS2564 - Property '_isTwoColumn' has no initializer and is not definitely assigned in the constructor.
|
|
19758
|
+
_isTwoColumn;
|
|
19384
19759
|
|
|
19385
19760
|
// The i18n linter.
|
|
19386
|
-
|
|
19761
|
+
_translationLinter;
|
|
19387
19762
|
_widgetContainers = new Map();
|
|
19388
|
-
|
|
19763
|
+
lastRenderedMarkdown;
|
|
19389
19764
|
// @ts-expect-error - TS2564 - Property 'reuseMarkdown' has no initializer and is not definitely assigned in the constructor.
|
|
19390
|
-
|
|
19765
|
+
reuseMarkdown;
|
|
19391
19766
|
// @ts-expect-error - TS2564 - Property 'translationIndex' has no initializer and is not definitely assigned in the constructor.
|
|
19392
|
-
|
|
19767
|
+
translationIndex;
|
|
19393
19768
|
// @ts-expect-error - TS2564 - Property 'widgetIds' has no initializer and is not definitely assigned in the constructor.
|
|
19394
|
-
|
|
19769
|
+
widgetIds;
|
|
19395
19770
|
static defaultProps = {
|
|
19396
19771
|
content: "",
|
|
19397
19772
|
widgets: {},
|
|
@@ -19590,9 +19965,12 @@ class Renderer extends React__namespace.Component {
|
|
|
19590
19965
|
problemNum
|
|
19591
19966
|
} = props;
|
|
19592
19967
|
const widgetsStartProps = {};
|
|
19968
|
+
const {
|
|
19969
|
+
strings
|
|
19970
|
+
} = this.props;
|
|
19593
19971
|
wonderStuffCore.entries(allWidgetInfo).forEach(_ref => {
|
|
19594
19972
|
let [key, widgetInfo] = _ref;
|
|
19595
|
-
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, problemNum);
|
|
19973
|
+
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, strings, problemNum);
|
|
19596
19974
|
});
|
|
19597
19975
|
|
|
19598
19976
|
// Call the onWidgetStartProps callback if it exists
|
|
@@ -21058,6 +21436,7 @@ class TextInput extends React__namespace.Component {
|
|
|
21058
21436
|
value: "",
|
|
21059
21437
|
disabled: false
|
|
21060
21438
|
};
|
|
21439
|
+
id;
|
|
21061
21440
|
constructor(props) {
|
|
21062
21441
|
super(props);
|
|
21063
21442
|
if (props.id) {
|
|
@@ -21383,6 +21762,7 @@ const {
|
|
|
21383
21762
|
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
21384
21763
|
} = Util;
|
|
21385
21764
|
class InputWithExamples extends React__namespace.Component {
|
|
21765
|
+
static contextType = PerseusI18nContext;
|
|
21386
21766
|
static defaultProps = {
|
|
21387
21767
|
type: "text",
|
|
21388
21768
|
shouldShowExamples: true,
|
|
@@ -21505,7 +21885,8 @@ class InputWithExamples extends React__namespace.Component {
|
|
|
21505
21885
|
id: this._getUniqueId()
|
|
21506
21886
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
21507
21887
|
content: examplesContent,
|
|
21508
|
-
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "input-with-examples")
|
|
21888
|
+
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "input-with-examples"),
|
|
21889
|
+
strings: this.context.strings
|
|
21509
21890
|
})));
|
|
21510
21891
|
}
|
|
21511
21892
|
_handleFocus = () => {
|
|
@@ -21653,35 +22034,36 @@ const answerTypes = {
|
|
|
21653
22034
|
}
|
|
21654
22035
|
};
|
|
21655
22036
|
const formExamples$1 = {
|
|
21656
|
-
integer: function (options) {
|
|
21657
|
-
return
|
|
22037
|
+
integer: function (options, strings) {
|
|
22038
|
+
return strings.integerExample;
|
|
21658
22039
|
},
|
|
21659
|
-
proper: function (options) {
|
|
22040
|
+
proper: function (options, strings) {
|
|
21660
22041
|
if (options.simplify === "optional") {
|
|
21661
|
-
return
|
|
22042
|
+
return strings.properExample;
|
|
21662
22043
|
}
|
|
21663
|
-
return
|
|
22044
|
+
return strings.simplifiedProperExample;
|
|
21664
22045
|
},
|
|
21665
|
-
improper: function (options) {
|
|
22046
|
+
improper: function (options, strings) {
|
|
21666
22047
|
if (options.simplify === "optional") {
|
|
21667
|
-
return
|
|
22048
|
+
return strings.improperExample;
|
|
21668
22049
|
}
|
|
21669
|
-
return
|
|
22050
|
+
return strings.simplifiedImproperExample;
|
|
21670
22051
|
},
|
|
21671
|
-
mixed: function (options) {
|
|
21672
|
-
return
|
|
22052
|
+
mixed: function (options, strings) {
|
|
22053
|
+
return strings.mixedExample;
|
|
21673
22054
|
},
|
|
21674
|
-
decimal: function (options) {
|
|
21675
|
-
return
|
|
22055
|
+
decimal: function (options, strings) {
|
|
22056
|
+
return strings.decimalExample;
|
|
21676
22057
|
},
|
|
21677
|
-
percent: function (options) {
|
|
21678
|
-
return
|
|
22058
|
+
percent: function (options, strings) {
|
|
22059
|
+
return strings.percentExample;
|
|
21679
22060
|
},
|
|
21680
|
-
pi: function (options) {
|
|
21681
|
-
return
|
|
22061
|
+
pi: function (options, strings) {
|
|
22062
|
+
return strings.piExample;
|
|
21682
22063
|
}
|
|
21683
22064
|
};
|
|
21684
22065
|
class InputNumber extends React__namespace.Component {
|
|
22066
|
+
static contextType = PerseusI18nContext;
|
|
21685
22067
|
static defaultProps = {
|
|
21686
22068
|
currentValue: "",
|
|
21687
22069
|
size: "normal",
|
|
@@ -21795,21 +22177,19 @@ class InputNumber extends React__namespace.Component {
|
|
|
21795
22177
|
};
|
|
21796
22178
|
simpleValidate = (rubric, onInputError) => {
|
|
21797
22179
|
onInputError = onInputError || function () {};
|
|
21798
|
-
return InputNumber.validate(this.getUserInput(), rubric, onInputError);
|
|
22180
|
+
return InputNumber.validate(this.getUserInput(), rubric, this.context.strings, onInputError);
|
|
21799
22181
|
};
|
|
21800
22182
|
examples = () => {
|
|
22183
|
+
const {
|
|
22184
|
+
strings
|
|
22185
|
+
} = this.context;
|
|
21801
22186
|
const type = this.props.answerType;
|
|
21802
22187
|
const forms = answerTypes[type].forms.split(/\s*,\s*/);
|
|
21803
|
-
const examples = ___default["default"].map(forms,
|
|
21804
|
-
|
|
21805
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
21806
|
-
// eslint-disable-next-line @babel/no-invalid-this
|
|
21807
|
-
return formExamples$1[form](this.props);
|
|
21808
|
-
}, this);
|
|
21809
|
-
return [i18n__namespace._("**Your answer should be** ")].concat(examples);
|
|
22188
|
+
const examples = ___default["default"].map(forms, form => formExamples$1[form](this.props, strings));
|
|
22189
|
+
return [strings.yourAnswer].concat(examples);
|
|
21810
22190
|
};
|
|
21811
|
-
static validate(state, rubric) {
|
|
21812
|
-
let onInputError = arguments.length >
|
|
22191
|
+
static validate(state, rubric, strings) {
|
|
22192
|
+
let onInputError = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};
|
|
21813
22193
|
if (rubric.answerType == null) {
|
|
21814
22194
|
rubric.answerType = "number";
|
|
21815
22195
|
}
|
|
@@ -21823,7 +22203,7 @@ class InputNumber extends React__namespace.Component {
|
|
|
21823
22203
|
inexact: rubric.inexact || undefined,
|
|
21824
22204
|
maxError: rubric.maxError,
|
|
21825
22205
|
forms: answerTypes[rubric.answerType].forms
|
|
21826
|
-
});
|
|
22206
|
+
}, strings);
|
|
21827
22207
|
|
|
21828
22208
|
// We may have received TeX; try to parse it before grading.
|
|
21829
22209
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
@@ -21938,14 +22318,16 @@ const answerFormButtons = [{
|
|
|
21938
22318
|
content: "\u03C0"
|
|
21939
22319
|
}];
|
|
21940
22320
|
const formExamples = {
|
|
21941
|
-
integer: () =>
|
|
21942
|
-
proper: form => form.simplify === "optional" ?
|
|
21943
|
-
improper: form => form.simplify === "optional" ?
|
|
21944
|
-
mixed: () =>
|
|
21945
|
-
decimal: () =>
|
|
21946
|
-
pi: () =>
|
|
22321
|
+
integer: (form, strings) => strings.integerExample,
|
|
22322
|
+
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
22323
|
+
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
22324
|
+
mixed: (form, strings) => strings.mixedExample,
|
|
22325
|
+
decimal: (form, strings) => strings.decimalExample,
|
|
22326
|
+
pi: (form, strings) => strings.piExample
|
|
21947
22327
|
};
|
|
21948
22328
|
class NumericInput extends React__namespace.Component {
|
|
22329
|
+
static contextType = PerseusI18nContext;
|
|
22330
|
+
inputRef;
|
|
21949
22331
|
static defaultProps = {
|
|
21950
22332
|
currentValue: "",
|
|
21951
22333
|
size: "normal",
|
|
@@ -21989,7 +22371,7 @@ class NumericInput extends React__namespace.Component {
|
|
|
21989
22371
|
}
|
|
21990
22372
|
return answerStrings[0];
|
|
21991
22373
|
}
|
|
21992
|
-
static validate(userInput, rubric) {
|
|
22374
|
+
static validate(userInput, rubric, strings) {
|
|
21993
22375
|
const defaultAnswerForms = answerFormButtons.map(e => e["value"])
|
|
21994
22376
|
// Don't default to validating the answer as a pi answer
|
|
21995
22377
|
// if answerForm isn't set on the answer
|
|
@@ -22015,7 +22397,7 @@ class NumericInput extends React__namespace.Component {
|
|
|
22015
22397
|
// TODO(merlob) backfill / delete
|
|
22016
22398
|
maxError: answer.maxError,
|
|
22017
22399
|
forms: validatorForms
|
|
22018
|
-
});
|
|
22400
|
+
}, strings);
|
|
22019
22401
|
};
|
|
22020
22402
|
|
|
22021
22403
|
// We may have received TeX; try to parse it before grading.
|
|
@@ -22098,13 +22480,12 @@ class NumericInput extends React__namespace.Component {
|
|
|
22098
22480
|
};
|
|
22099
22481
|
});
|
|
22100
22482
|
let examples = ___default["default"].map(forms, form => {
|
|
22101
|
-
|
|
22102
|
-
return formExamples[form.name](form);
|
|
22483
|
+
return formExamples[form.name](form, this.context.strings);
|
|
22103
22484
|
});
|
|
22104
22485
|
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
22105
22486
|
// versions of the same format
|
|
22106
22487
|
examples = ___default["default"].uniq(examples);
|
|
22107
|
-
return [
|
|
22488
|
+
return [this.context.strings.yourAnswer].concat(examples);
|
|
22108
22489
|
};
|
|
22109
22490
|
shouldShowExamples = () => {
|
|
22110
22491
|
const noFormsAccepted = this.props.answerForms?.length === 0;
|
|
@@ -22116,7 +22497,7 @@ class NumericInput extends React__namespace.Component {
|
|
|
22116
22497
|
return !noFormsAccepted && !allFormsAccepted;
|
|
22117
22498
|
};
|
|
22118
22499
|
simpleValidate = rubric => {
|
|
22119
|
-
return NumericInput.validate(this.getUserInput(), rubric);
|
|
22500
|
+
return NumericInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
22120
22501
|
};
|
|
22121
22502
|
focus = () => {
|
|
22122
22503
|
this.inputRef?.focus();
|
|
@@ -22162,7 +22543,7 @@ class NumericInput extends React__namespace.Component {
|
|
|
22162
22543
|
render() {
|
|
22163
22544
|
let labelText = this.props.labelText;
|
|
22164
22545
|
if (labelText == null || labelText === "") {
|
|
22165
|
-
labelText =
|
|
22546
|
+
labelText = this.context.strings.yourAnswerLabel;
|
|
22166
22547
|
}
|
|
22167
22548
|
|
|
22168
22549
|
// To right align a custom keypad we need to wrap it.
|
|
@@ -22309,11 +22690,12 @@ var NumericInput$1 = {
|
|
|
22309
22690
|
/* eslint-disable react/sort-comp */
|
|
22310
22691
|
const EN_DASH$1 = "\u2013";
|
|
22311
22692
|
class PassageRef extends React__namespace.Component {
|
|
22693
|
+
static contextType = PerseusI18nContext;
|
|
22312
22694
|
displayName = "PassageRef";
|
|
22313
22695
|
// @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
|
|
22314
|
-
|
|
22696
|
+
_isMounted;
|
|
22315
22697
|
// @ts-expect-error - TS2564 - Property '_throttledUpdateRange' has no initializer and is not definitely assigned in the constructor.
|
|
22316
|
-
|
|
22698
|
+
_throttledUpdateRange;
|
|
22317
22699
|
static defaultProps = {
|
|
22318
22700
|
passageNumber: 1,
|
|
22319
22701
|
referenceNumber: 1,
|
|
@@ -22333,18 +22715,21 @@ class PassageRef extends React__namespace.Component {
|
|
|
22333
22715
|
return removeDenylistProps(this.props);
|
|
22334
22716
|
};
|
|
22335
22717
|
render() {
|
|
22718
|
+
const {
|
|
22719
|
+
strings
|
|
22720
|
+
} = this.context;
|
|
22336
22721
|
const lineRange = this.state.lineRange;
|
|
22337
22722
|
let lineRangeOutput;
|
|
22338
22723
|
if (!lineRange) {
|
|
22339
|
-
lineRangeOutput =
|
|
22724
|
+
lineRangeOutput = strings.lineRange({
|
|
22340
22725
|
lineRange: `?${EN_DASH$1}?`
|
|
22341
22726
|
});
|
|
22342
22727
|
} else if (lineRange[0] === lineRange[1]) {
|
|
22343
|
-
lineRangeOutput =
|
|
22344
|
-
lineNumber: lineRange[0]
|
|
22728
|
+
lineRangeOutput = strings.lineNumber({
|
|
22729
|
+
lineNumber: String(lineRange[0])
|
|
22345
22730
|
});
|
|
22346
22731
|
} else {
|
|
22347
|
-
lineRangeOutput =
|
|
22732
|
+
lineRangeOutput = strings.lineRange({
|
|
22348
22733
|
lineRange: lineRange[0] + EN_DASH$1 + lineRange[1]
|
|
22349
22734
|
});
|
|
22350
22735
|
}
|
|
@@ -22784,7 +23169,7 @@ class Icon extends React__namespace.Component {
|
|
|
22784
23169
|
}
|
|
22785
23170
|
}
|
|
22786
23171
|
|
|
22787
|
-
function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
23172
|
+
function getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings) {
|
|
22788
23173
|
// There are two pieces of metadata we want to add to each a11yText:
|
|
22789
23174
|
// whether the answer was checked/crossed-out/neither, and whether the
|
|
22790
23175
|
// answer is correct/incorrect/not-yet-revealed.
|
|
@@ -22793,45 +23178,45 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
|
22793
23178
|
// we've just enumerated all 9 possibilities as separate strings.
|
|
22794
23179
|
if (showCorrectness && correct) {
|
|
22795
23180
|
if (checked) {
|
|
22796
|
-
return
|
|
23181
|
+
return strings.choiceCheckedCorrect({
|
|
22797
23182
|
letter
|
|
22798
23183
|
});
|
|
22799
23184
|
}
|
|
22800
23185
|
if (crossedOut) {
|
|
22801
|
-
return
|
|
23186
|
+
return strings.choiceCrossedOutCorrect({
|
|
22802
23187
|
letter
|
|
22803
23188
|
});
|
|
22804
23189
|
}
|
|
22805
|
-
return
|
|
23190
|
+
return strings.choiceCorrect({
|
|
22806
23191
|
letter
|
|
22807
23192
|
});
|
|
22808
23193
|
}
|
|
22809
23194
|
if (showCorrectness && !correct) {
|
|
22810
23195
|
if (checked) {
|
|
22811
|
-
return
|
|
23196
|
+
return strings.choiceCheckedIncorrect({
|
|
22812
23197
|
letter
|
|
22813
23198
|
});
|
|
22814
23199
|
}
|
|
22815
23200
|
if (crossedOut) {
|
|
22816
|
-
return
|
|
23201
|
+
return strings.choiceCrossedOutIncorrect({
|
|
22817
23202
|
letter
|
|
22818
23203
|
});
|
|
22819
23204
|
}
|
|
22820
|
-
return
|
|
23205
|
+
return strings.choiceIncorrect({
|
|
22821
23206
|
letter
|
|
22822
23207
|
});
|
|
22823
23208
|
}
|
|
22824
23209
|
if (checked) {
|
|
22825
|
-
return
|
|
23210
|
+
return strings.choiceChecked({
|
|
22826
23211
|
letter
|
|
22827
23212
|
});
|
|
22828
23213
|
}
|
|
22829
23214
|
if (crossedOut) {
|
|
22830
|
-
return
|
|
23215
|
+
return strings.choiceCrossedOut({
|
|
22831
23216
|
letter
|
|
22832
23217
|
});
|
|
22833
23218
|
}
|
|
22834
|
-
return
|
|
23219
|
+
return strings.choice({
|
|
22835
23220
|
letter
|
|
22836
23221
|
});
|
|
22837
23222
|
}
|
|
@@ -22878,18 +23263,8 @@ const styles$z = aphrodite.StyleSheet.create({
|
|
|
22878
23263
|
* "choice letter". (For example, in English, `getChoiceLetter(0)` is "A",
|
|
22879
23264
|
* `getChoiceLetter(1)` is "B", etc.)
|
|
22880
23265
|
*/
|
|
22881
|
-
function getChoiceLetter(pos) {
|
|
22882
|
-
|
|
22883
|
-
* front of multiple-choice options. For instance, a multiple-choice
|
|
22884
|
-
* question with three options would display
|
|
22885
|
-
* (A) first option
|
|
22886
|
-
* (B) second option
|
|
22887
|
-
* (C) third option
|
|
22888
|
-
* There must be spaces between each of the different characters. The
|
|
22889
|
-
* characters will show up next to options in the order that they are
|
|
22890
|
-
* listed here. Most multiple choice questions have 5 or fewer options.
|
|
22891
|
-
*/
|
|
22892
|
-
const lettersString = i18n__namespace._("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
|
|
23266
|
+
function getChoiceLetter(pos, strings) {
|
|
23267
|
+
const lettersString = strings.letters;
|
|
22893
23268
|
const letters = lettersString.split(" ");
|
|
22894
23269
|
if (pos < letters.length) {
|
|
22895
23270
|
// If the position we need is listed in the localized string, use that.
|
|
@@ -22953,7 +23328,10 @@ function ChoiceInner(props) {
|
|
|
22953
23328
|
showCorrectness,
|
|
22954
23329
|
correct
|
|
22955
23330
|
} = props;
|
|
22956
|
-
const
|
|
23331
|
+
const {
|
|
23332
|
+
strings
|
|
23333
|
+
} = usePerseusI18n();
|
|
23334
|
+
const letter = getChoiceLetter(pos, strings);
|
|
22957
23335
|
if (!showCorrectness) {
|
|
22958
23336
|
return letter;
|
|
22959
23337
|
}
|
|
@@ -23099,24 +23477,24 @@ const styles$w = aphrodite.StyleSheet.create({
|
|
|
23099
23477
|
* ChoiceIcon visualizations but is meant to make the distinctions
|
|
23100
23478
|
* between the states more immediately clear to users.
|
|
23101
23479
|
*/
|
|
23102
|
-
function renderText(checked, correct, crossedOut) {
|
|
23480
|
+
function renderText(checked, correct, crossedOut, strings) {
|
|
23103
23481
|
if (correct) {
|
|
23104
23482
|
// For correct answers, we surface checked _or_ crossedOut state,
|
|
23105
23483
|
// because any interaction with the correct answer is noteworthy!
|
|
23106
23484
|
if (checked) {
|
|
23107
|
-
return
|
|
23485
|
+
return strings.correctSelected;
|
|
23108
23486
|
}
|
|
23109
23487
|
if (crossedOut) {
|
|
23110
|
-
return
|
|
23488
|
+
return strings.correctCrossedOut;
|
|
23111
23489
|
}
|
|
23112
|
-
return
|
|
23490
|
+
return strings.correct;
|
|
23113
23491
|
}
|
|
23114
23492
|
// But, for incorrect answers, we only surface checked state,
|
|
23115
23493
|
// because crossing out an incorrect answer is not noteworthy.
|
|
23116
23494
|
if (checked) {
|
|
23117
|
-
return
|
|
23495
|
+
return strings.incorrectSelected;
|
|
23118
23496
|
}
|
|
23119
|
-
return
|
|
23497
|
+
return strings.incorrect;
|
|
23120
23498
|
}
|
|
23121
23499
|
const OptionStatus = function (props) {
|
|
23122
23500
|
const {
|
|
@@ -23126,6 +23504,9 @@ const OptionStatus = function (props) {
|
|
|
23126
23504
|
previouslyAnswered,
|
|
23127
23505
|
reviewMode
|
|
23128
23506
|
} = props;
|
|
23507
|
+
const {
|
|
23508
|
+
strings
|
|
23509
|
+
} = usePerseusI18n();
|
|
23129
23510
|
|
|
23130
23511
|
// Option status is shown only in review mode, or for incorrectly
|
|
23131
23512
|
// answered items.
|
|
@@ -23145,7 +23526,7 @@ const OptionStatus = function (props) {
|
|
|
23145
23526
|
}
|
|
23146
23527
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
23147
23528
|
className: aphrodite.css(styles$v.text, textStyle)
|
|
23148
|
-
}, renderText(checked, correct, crossedOut));
|
|
23529
|
+
}, renderText(checked, correct, crossedOut, strings));
|
|
23149
23530
|
};
|
|
23150
23531
|
const styles$v = aphrodite.StyleSheet.create({
|
|
23151
23532
|
text: {
|
|
@@ -23192,6 +23573,9 @@ const Choice = function (props) {
|
|
|
23192
23573
|
forwardedRef
|
|
23193
23574
|
} = props;
|
|
23194
23575
|
const [isInputFocused, setIsInputFocused] = React.useState(false);
|
|
23576
|
+
const {
|
|
23577
|
+
strings
|
|
23578
|
+
} = usePerseusI18n();
|
|
23195
23579
|
React.useEffect(() => {
|
|
23196
23580
|
if (isInputFocused && disabled) {
|
|
23197
23581
|
setIsInputFocused(false);
|
|
@@ -23220,8 +23604,8 @@ const Choice = function (props) {
|
|
|
23220
23604
|
// However, we don't want to do this when we're in review mode in the
|
|
23221
23605
|
// content library.
|
|
23222
23606
|
const showDimmed = !reviewMode && apiOptions.readOnly || crossedOut;
|
|
23223
|
-
const letter = getChoiceLetter(pos);
|
|
23224
|
-
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness);
|
|
23607
|
+
const letter = getChoiceLetter(pos, strings);
|
|
23608
|
+
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings);
|
|
23225
23609
|
const idFactory = wonderBlocksCore.useUniqueIdWithMock(`choice`);
|
|
23226
23610
|
const choiceId = idFactory.get(letter);
|
|
23227
23611
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -23326,15 +23710,15 @@ const Choice = function (props) {
|
|
|
23326
23710
|
close
|
|
23327
23711
|
} = _ref2;
|
|
23328
23712
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksPopover.PopoverContent, {
|
|
23329
|
-
title:
|
|
23330
|
-
content:
|
|
23713
|
+
title: strings.crossOut,
|
|
23714
|
+
content: strings.crossOutOption,
|
|
23331
23715
|
closeButtonVisible: true,
|
|
23332
23716
|
actions: /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksLayout.Strut, {
|
|
23333
23717
|
size: wonderBlocksTokens.spacing.medium_16
|
|
23334
23718
|
}), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
23335
23719
|
kind: "primary",
|
|
23336
|
-
"aria-label":
|
|
23337
|
-
letter: getChoiceLetter(pos)
|
|
23720
|
+
"aria-label": strings.crossOutChoice({
|
|
23721
|
+
letter: getChoiceLetter(pos, strings)
|
|
23338
23722
|
}),
|
|
23339
23723
|
disabled: apiOptions.readOnly || reviewMode,
|
|
23340
23724
|
onClick: () => {
|
|
@@ -23354,7 +23738,7 @@ const Choice = function (props) {
|
|
|
23354
23738
|
}
|
|
23355
23739
|
close();
|
|
23356
23740
|
}
|
|
23357
|
-
}, crossedOut ?
|
|
23741
|
+
}, crossedOut ? strings.bringBack : strings.crossOut))
|
|
23358
23742
|
});
|
|
23359
23743
|
}
|
|
23360
23744
|
}, _ref3 => {
|
|
@@ -23363,8 +23747,8 @@ const Choice = function (props) {
|
|
|
23363
23747
|
} = _ref3;
|
|
23364
23748
|
return /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
|
|
23365
23749
|
onClick: open,
|
|
23366
|
-
"aria-label":
|
|
23367
|
-
letter: getChoiceLetter(pos)
|
|
23750
|
+
"aria-label": strings.openMenuForChoice({
|
|
23751
|
+
letter: getChoiceLetter(pos, strings)
|
|
23368
23752
|
}),
|
|
23369
23753
|
style: {
|
|
23370
23754
|
alignSelf: "center",
|
|
@@ -23414,6 +23798,9 @@ const ChoiceNoneAbove = function (props) {
|
|
|
23414
23798
|
forwardedRef,
|
|
23415
23799
|
...rest
|
|
23416
23800
|
} = props;
|
|
23801
|
+
const {
|
|
23802
|
+
strings
|
|
23803
|
+
} = usePerseusI18n();
|
|
23417
23804
|
const choiceProps = {
|
|
23418
23805
|
...rest,
|
|
23419
23806
|
content: showContent ? content :
|
|
@@ -23430,7 +23817,8 @@ const ChoiceNoneAbove = function (props) {
|
|
|
23430
23817
|
// just to render a string
|
|
23431
23818
|
React__namespace.createElement(Renderer, {
|
|
23432
23819
|
key: "noneOfTheAboveRenderer",
|
|
23433
|
-
content:
|
|
23820
|
+
content: strings.noneOfTheAbove,
|
|
23821
|
+
strings: strings
|
|
23434
23822
|
})
|
|
23435
23823
|
};
|
|
23436
23824
|
return /*#__PURE__*/React__namespace.createElement(Choice$1, _extends({}, choiceProps, {
|
|
@@ -23450,16 +23838,16 @@ const {
|
|
|
23450
23838
|
|
|
23451
23839
|
// exported for tests
|
|
23452
23840
|
|
|
23453
|
-
function getInstructionsText(multipleSelect, countChoices, numCorrect) {
|
|
23841
|
+
function getInstructionsText(multipleSelect, countChoices, numCorrect, strings) {
|
|
23454
23842
|
if (multipleSelect) {
|
|
23455
23843
|
if (countChoices) {
|
|
23456
|
-
return
|
|
23457
|
-
numCorrect: numCorrect
|
|
23844
|
+
return strings.chooseNumAnswers({
|
|
23845
|
+
numCorrect: String(numCorrect)
|
|
23458
23846
|
});
|
|
23459
23847
|
}
|
|
23460
|
-
return
|
|
23848
|
+
return strings.chooseAllAnswers;
|
|
23461
23849
|
}
|
|
23462
|
-
return
|
|
23850
|
+
return strings.chooseOneAnswer;
|
|
23463
23851
|
}
|
|
23464
23852
|
const BaseRadio = function (props) {
|
|
23465
23853
|
const {
|
|
@@ -23474,6 +23862,9 @@ const BaseRadio = function (props) {
|
|
|
23474
23862
|
isLastUsedWidget,
|
|
23475
23863
|
registerFocusFunction
|
|
23476
23864
|
} = props;
|
|
23865
|
+
const {
|
|
23866
|
+
strings
|
|
23867
|
+
} = usePerseusI18n();
|
|
23477
23868
|
|
|
23478
23869
|
// useEffect doesn't have previous props
|
|
23479
23870
|
const prevReviewModeRubric = React.useRef();
|
|
@@ -23580,7 +23971,7 @@ const BaseRadio = function (props) {
|
|
|
23580
23971
|
const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
23581
23972
|
const className = classNames__default["default"]("perseus-widget-radio", !editMode && "perseus-rendered-radio", aphrodite.css(styles$t.radio, styles$t.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$t.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$t.radioContainerLastHighlighted));
|
|
23582
23973
|
const instructionsClassName = classNames__default["default"]("instructions", aphrodite.css(styles$t.instructions, isMobile && styles$t.instructionsMobile));
|
|
23583
|
-
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
|
|
23974
|
+
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
|
|
23584
23975
|
const responsiveClassName = aphrodite.css(styles$t.responsiveFieldset);
|
|
23585
23976
|
const fieldset = /*#__PURE__*/React__namespace.createElement("fieldset", {
|
|
23586
23977
|
className: `perseus-widget-radio-fieldset ${responsiveClassName}`
|
|
@@ -23803,8 +24194,9 @@ const styles$t = aphrodite.StyleSheet.create({
|
|
|
23803
24194
|
// RenderProps is the return type for radio.jsx#transform
|
|
23804
24195
|
|
|
23805
24196
|
class Radio$1 extends React__namespace.Component {
|
|
24197
|
+
static contextType = PerseusI18nContext;
|
|
23806
24198
|
// @ts-expect-error - TS2564 - Property 'focusFunction' has no initializer and is not definitely assigned in the constructor.
|
|
23807
|
-
|
|
24199
|
+
focusFunction;
|
|
23808
24200
|
static defaultProps = {
|
|
23809
24201
|
choices: [],
|
|
23810
24202
|
multipleSelect: false,
|
|
@@ -23813,7 +24205,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
23813
24205
|
linterContext: PerseusLinter.linterContextDefault,
|
|
23814
24206
|
showSolutions: "none"
|
|
23815
24207
|
};
|
|
23816
|
-
static validate(userInput, rubric) {
|
|
24208
|
+
static validate(userInput, rubric, strings) {
|
|
23817
24209
|
const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
23818
24210
|
return sum + (selected ? 1 : 0);
|
|
23819
24211
|
}, 0);
|
|
@@ -23826,7 +24218,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
23826
24218
|
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
23827
24219
|
return {
|
|
23828
24220
|
type: "invalid",
|
|
23829
|
-
message:
|
|
24221
|
+
message: strings.chooseCorrectNum
|
|
23830
24222
|
};
|
|
23831
24223
|
// If NOTA and some other answer are checked, ...
|
|
23832
24224
|
}
|
|
@@ -23834,7 +24226,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
23834
24226
|
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
23835
24227
|
return {
|
|
23836
24228
|
type: "invalid",
|
|
23837
|
-
message:
|
|
24229
|
+
message: strings.notNoneOfTheAbove
|
|
23838
24230
|
};
|
|
23839
24231
|
}
|
|
23840
24232
|
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
@@ -23968,7 +24360,8 @@ class Radio$1 extends React__namespace.Component {
|
|
|
23968
24360
|
..._this.props.linterContext,
|
|
23969
24361
|
// @ts-expect-error - TS2322 - Type '{ blockHighlight: true; contentType: string; highlightLint: boolean; paths: readonly string[]; stack: readonly string[]; }' is not assignable to type 'LinterContextProps'.
|
|
23970
24362
|
blockHighlight: true
|
|
23971
|
-
}
|
|
24363
|
+
},
|
|
24364
|
+
strings: _this.context.strings
|
|
23972
24365
|
});
|
|
23973
24366
|
};
|
|
23974
24367
|
})();
|
|
@@ -24041,7 +24434,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24041
24434
|
return Radio$1.getUserInputFromProps(this.props);
|
|
24042
24435
|
};
|
|
24043
24436
|
simpleValidate = rubric => {
|
|
24044
|
-
return Radio$1.validate(this.getUserInput(), rubric);
|
|
24437
|
+
return Radio$1.validate(this.getUserInput(), rubric, this.context.strings);
|
|
24045
24438
|
};
|
|
24046
24439
|
|
|
24047
24440
|
/**
|
|
@@ -24110,6 +24503,9 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24110
24503
|
const {
|
|
24111
24504
|
choices
|
|
24112
24505
|
} = this.props;
|
|
24506
|
+
const {
|
|
24507
|
+
strings
|
|
24508
|
+
} = this.context;
|
|
24113
24509
|
let choiceStates;
|
|
24114
24510
|
if (this.props.static) {
|
|
24115
24511
|
choiceStates = choices.map(choice => ({
|
|
@@ -24164,11 +24560,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
24164
24560
|
}));
|
|
24165
24561
|
}
|
|
24166
24562
|
const choicesProp = choices.map((choice, i) => {
|
|
24167
|
-
const content = choice.isNoneOfTheAbove && !choice.content ?
|
|
24168
|
-
// we use i18n._ instead of $_ here because the content
|
|
24169
|
-
// sent to a renderer needs to be a string, not a react
|
|
24170
|
-
// node (/renderable/fragment).
|
|
24171
|
-
i18n__namespace._("None of the above") : choice.content;
|
|
24563
|
+
const content = choice.isNoneOfTheAbove && !choice.content ? strings.noneOfTheAbove : choice.content;
|
|
24172
24564
|
const {
|
|
24173
24565
|
selected,
|
|
24174
24566
|
crossedOut,
|
|
@@ -24226,14 +24618,8 @@ const {
|
|
|
24226
24618
|
random
|
|
24227
24619
|
} = Util;
|
|
24228
24620
|
|
|
24229
|
-
// Represents choices that we automatically re-order if encountered.
|
|
24230
|
-
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
24231
|
-
// found.
|
|
24232
|
-
// Note 2: these are internationalized when compared later on.
|
|
24233
|
-
const ReversedChoices = [[i18n__namespace._("False"), i18n__namespace._("True")], [i18n__namespace._("No"), i18n__namespace._("Yes")]];
|
|
24234
|
-
|
|
24235
24621
|
// Transforms the choices for display.
|
|
24236
|
-
const _choiceTransform = (widgetOptions, problemNum) => {
|
|
24622
|
+
const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
24237
24623
|
const _maybeRandomize = function (array) {
|
|
24238
24624
|
const randomSeed = problemNum === undefined ? random : problemNum;
|
|
24239
24625
|
// NOTE: `problemNum` will only be set when the radio widget is
|
|
@@ -24262,6 +24648,11 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24262
24648
|
return newChoices;
|
|
24263
24649
|
};
|
|
24264
24650
|
const enforceOrdering = choices => {
|
|
24651
|
+
// Represents choices that we automatically re-order if encountered.
|
|
24652
|
+
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
24653
|
+
// found.
|
|
24654
|
+
// Note 2: these are internationalized when compared later on.
|
|
24655
|
+
const ReversedChoices = [[strings.false, strings.true], [strings.no, strings.yes]];
|
|
24265
24656
|
const content = choices.map(c => c.content);
|
|
24266
24657
|
if (ReversedChoices.some(reversed => ___default["default"].isEqual(content, reversed))) {
|
|
24267
24658
|
return [choices[1], choices[0]];
|
|
@@ -24288,8 +24679,8 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24288
24679
|
// 1) we randomize the order first
|
|
24289
24680
|
_maybeRandomize(choices)));
|
|
24290
24681
|
};
|
|
24291
|
-
const transform = (widgetOptions, problemNum) => {
|
|
24292
|
-
const choices = _choiceTransform(widgetOptions, problemNum);
|
|
24682
|
+
const transform = (widgetOptions, strings, problemNum) => {
|
|
24683
|
+
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24293
24684
|
const numCorrect = ___default["default"].reduce(widgetOptions.choices, function (memo, choice) {
|
|
24294
24685
|
return choice.correct ? memo + 1 : memo;
|
|
24295
24686
|
}, 0);
|
|
@@ -24362,6 +24753,7 @@ const WidgetJsonifyDeprecated = {
|
|
|
24362
24753
|
|
|
24363
24754
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
24364
24755
|
class Categorizer extends React__namespace.Component {
|
|
24756
|
+
static contextType = PerseusI18nContext;
|
|
24365
24757
|
static defaultProps = {
|
|
24366
24758
|
items: [],
|
|
24367
24759
|
categories: [],
|
|
@@ -24410,7 +24802,8 @@ class Categorizer extends React__namespace.Component {
|
|
|
24410
24802
|
key: i
|
|
24411
24803
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
24412
24804
|
content: category,
|
|
24413
|
-
linterContext: this.props.linterContext
|
|
24805
|
+
linterContext: this.props.linterContext,
|
|
24806
|
+
strings: this.context.strings
|
|
24414
24807
|
}));
|
|
24415
24808
|
}))), /*#__PURE__*/React__namespace.createElement("tbody", null, indexedItems.map(indexedItem => {
|
|
24416
24809
|
const item = indexedItem[0];
|
|
@@ -24422,7 +24815,8 @@ class Categorizer extends React__namespace.Component {
|
|
|
24422
24815
|
// @ts-expect-error - TS2322 - Type 'string | number' is not assignable to type 'string | undefined'.
|
|
24423
24816
|
, {
|
|
24424
24817
|
content: item,
|
|
24425
|
-
linterContext: this.props.linterContext
|
|
24818
|
+
linterContext: this.props.linterContext,
|
|
24819
|
+
strings: this.context.strings
|
|
24426
24820
|
})), self.props.categories.map((catName, catNum) => {
|
|
24427
24821
|
const selected = self.props.values[itemNum] === catNum;
|
|
24428
24822
|
return /*#__PURE__*/React__namespace.createElement("td", {
|
|
@@ -24466,9 +24860,9 @@ class Categorizer extends React__namespace.Component {
|
|
|
24466
24860
|
this.props.trackInteraction();
|
|
24467
24861
|
}
|
|
24468
24862
|
simpleValidate = rubric => {
|
|
24469
|
-
return Categorizer.validate(this.getUserInput(), rubric);
|
|
24863
|
+
return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
|
|
24470
24864
|
};
|
|
24471
|
-
static validate(userInput, rubric) {
|
|
24865
|
+
static validate(userInput, rubric, strings) {
|
|
24472
24866
|
let completed = true;
|
|
24473
24867
|
let allCorrect = true;
|
|
24474
24868
|
rubric.values.forEach((value, i) => {
|
|
@@ -24482,7 +24876,7 @@ class Categorizer extends React__namespace.Component {
|
|
|
24482
24876
|
if (!completed) {
|
|
24483
24877
|
return {
|
|
24484
24878
|
type: "invalid",
|
|
24485
|
-
message:
|
|
24879
|
+
message: strings.invalidSelection
|
|
24486
24880
|
};
|
|
24487
24881
|
}
|
|
24488
24882
|
return {
|
|
@@ -24796,6 +25190,7 @@ var CSProgram$1 = {
|
|
|
24796
25190
|
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
24797
25191
|
|
|
24798
25192
|
class Definition extends React__namespace.Component {
|
|
25193
|
+
static contextType = PerseusI18nContext;
|
|
24799
25194
|
static defaultProps = {
|
|
24800
25195
|
togglePrompt: "define me",
|
|
24801
25196
|
definition: "definition goes here"
|
|
@@ -24828,7 +25223,8 @@ class Definition extends React__namespace.Component {
|
|
|
24828
25223
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
24829
25224
|
apiOptions: this.props.apiOptions,
|
|
24830
25225
|
content: this.props.definition,
|
|
24831
|
-
widgets: this.props.widgets
|
|
25226
|
+
widgets: this.props.widgets,
|
|
25227
|
+
strings: this.context.strings
|
|
24832
25228
|
})),
|
|
24833
25229
|
opened: activeDefinitionId === this.props.widgetId,
|
|
24834
25230
|
onClose: () => setActiveDefinitionId(null),
|
|
@@ -24874,6 +25270,7 @@ var Definition$1 = {
|
|
|
24874
25270
|
// The props are type `any` on purpose so that this can receive props
|
|
24875
25271
|
// from any deprecated widget
|
|
24876
25272
|
class DeprecatedStandin extends React__default["default"].Component {
|
|
25273
|
+
static contextType = PerseusI18nContext;
|
|
24877
25274
|
static validate(userInput, rubric) {
|
|
24878
25275
|
// Since this mean to replace an existing widget the learner
|
|
24879
25276
|
// WILL earn points for this widget
|
|
@@ -24897,7 +25294,7 @@ class DeprecatedStandin extends React__default["default"].Component {
|
|
|
24897
25294
|
paddingBottom: 8
|
|
24898
25295
|
}
|
|
24899
25296
|
}, /*#__PURE__*/React__default["default"].createElement(Banner__default["default"], {
|
|
24900
|
-
text:
|
|
25297
|
+
text: this.context.strings.deprecatedStandin,
|
|
24901
25298
|
kind: "info",
|
|
24902
25299
|
layout: "full-width"
|
|
24903
25300
|
}));
|
|
@@ -25014,6 +25411,7 @@ function mediaQueryIsMatched(mediaQuery) {
|
|
|
25014
25411
|
return window.matchMedia(mediaQuery).matches;
|
|
25015
25412
|
}
|
|
25016
25413
|
class Explanation extends React__namespace.Component {
|
|
25414
|
+
static contextType = PerseusI18nContext;
|
|
25017
25415
|
static defaultProps = {
|
|
25018
25416
|
showPrompt: "Explain",
|
|
25019
25417
|
hidePrompt: "Hide explanation",
|
|
@@ -25098,7 +25496,8 @@ class Explanation extends React__namespace.Component {
|
|
|
25098
25496
|
apiOptions: this.props.apiOptions,
|
|
25099
25497
|
content: this.props.explanation,
|
|
25100
25498
|
widgets: this.props.widgets,
|
|
25101
|
-
linterContext: this.props.linterContext
|
|
25499
|
+
linterContext: this.props.linterContext,
|
|
25500
|
+
strings: this.context.strings
|
|
25102
25501
|
})))));
|
|
25103
25502
|
}
|
|
25104
25503
|
getUserInput = () => {
|
|
@@ -25161,6 +25560,7 @@ var Explanation$1 = {
|
|
|
25161
25560
|
};
|
|
25162
25561
|
|
|
25163
25562
|
class GradedGroupAnswerBar extends React__namespace.Component {
|
|
25563
|
+
static contextType = PerseusI18nContext;
|
|
25164
25564
|
render() {
|
|
25165
25565
|
const {
|
|
25166
25566
|
apiOptions,
|
|
@@ -25168,6 +25568,13 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25168
25568
|
onCheckAnswer,
|
|
25169
25569
|
onNextQuestion
|
|
25170
25570
|
} = this.props;
|
|
25571
|
+
const {
|
|
25572
|
+
keepTrying,
|
|
25573
|
+
tryAgain,
|
|
25574
|
+
check,
|
|
25575
|
+
correctExcited,
|
|
25576
|
+
nextQuestion
|
|
25577
|
+
} = this.context.strings;
|
|
25171
25578
|
const answerBarStyle = {
|
|
25172
25579
|
...styles$o.answerBar,
|
|
25173
25580
|
backgroundColor: answerBarState === "CORRECT" ? wonderBlocksTokens.color.offWhite : "white",
|
|
@@ -25182,10 +25589,10 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25182
25589
|
style: {
|
|
25183
25590
|
marginLeft: 8
|
|
25184
25591
|
}
|
|
25185
|
-
},
|
|
25592
|
+
}, keepTrying)) : /*#__PURE__*/React__namespace.createElement("span", null); // empty span keeps the button on the right side
|
|
25186
25593
|
|
|
25187
25594
|
if (answerBarState !== "CORRECT") {
|
|
25188
|
-
const buttonLabel = answerBarState === "INCORRECT" ?
|
|
25595
|
+
const buttonLabel = answerBarState === "INCORRECT" ? tryAgain : check;
|
|
25189
25596
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
25190
25597
|
style: answerBarStyle
|
|
25191
25598
|
}, message, /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
@@ -25208,13 +25615,13 @@ class GradedGroupAnswerBar extends React__namespace.Component {
|
|
|
25208
25615
|
}
|
|
25209
25616
|
}))), /*#__PURE__*/React__namespace.createElement("span", {
|
|
25210
25617
|
role: "alert",
|
|
25211
|
-
"aria-label":
|
|
25618
|
+
"aria-label": correctExcited,
|
|
25212
25619
|
style: {
|
|
25213
25620
|
marginLeft: 8
|
|
25214
25621
|
}
|
|
25215
|
-
},
|
|
25622
|
+
}, correctExcited)), onNextQuestion && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
25216
25623
|
onClick: onNextQuestion
|
|
25217
|
-
},
|
|
25624
|
+
}, nextQuestion));
|
|
25218
25625
|
}
|
|
25219
25626
|
}
|
|
25220
25627
|
const fontSize = 17;
|
|
@@ -25270,10 +25677,6 @@ const getNextState = (currentState, answerable) => {
|
|
|
25270
25677
|
}
|
|
25271
25678
|
};
|
|
25272
25679
|
|
|
25273
|
-
// Prepended to all invalid messages to make the widget messages a bit clearer
|
|
25274
|
-
const INVALID_MESSAGE_PREFIX = i18n__namespace._("We couldn't grade your answer.");
|
|
25275
|
-
const DEFAULT_INVALID_MESSAGE = i18n__namespace._("It looks like you left something blank or ") + i18n__namespace._("entered in an invalid answer.");
|
|
25276
|
-
|
|
25277
25680
|
// exports has no 'transform'
|
|
25278
25681
|
|
|
25279
25682
|
// A Graded Group is more or less a Group widget that displays a check
|
|
@@ -25281,6 +25684,7 @@ const DEFAULT_INVALID_MESSAGE = i18n__namespace._("It looks like you left someth
|
|
|
25281
25684
|
// the stuff inside and displays feedback about whether the inputted answer was
|
|
25282
25685
|
// correct or not.
|
|
25283
25686
|
class GradedGroup extends React__namespace.Component {
|
|
25687
|
+
static contextType = PerseusI18nContext;
|
|
25284
25688
|
static defaultProps = {
|
|
25285
25689
|
title: "",
|
|
25286
25690
|
content: "",
|
|
@@ -25342,8 +25746,13 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25342
25746
|
// eslint-disable-next-line react/no-string-refs
|
|
25343
25747
|
// @ts-expect-error - TS2339 - Property 'score' does not exist on type 'ReactInstance'.
|
|
25344
25748
|
const score = this.refs.renderer.score();
|
|
25749
|
+
const {
|
|
25750
|
+
INVALID_MESSAGE_PREFIX,
|
|
25751
|
+
DEFAULT_INVALID_MESSAGE_1,
|
|
25752
|
+
DEFAULT_INVALID_MESSAGE_2
|
|
25753
|
+
} = this.context.strings;
|
|
25345
25754
|
const status = score.type === "points" ? score.total === score.earned ? GRADING_STATUSES.correct : GRADING_STATUSES.incorrect : GRADING_STATUSES.invalid;
|
|
25346
|
-
const message = score.type === "points" ? score.message || "" : score.message ? `${INVALID_MESSAGE_PREFIX} ${score.message}` : `${INVALID_MESSAGE_PREFIX} ${
|
|
25755
|
+
const message = score.type === "points" ? score.message || "" : score.message ? `${INVALID_MESSAGE_PREFIX} ${score.message}` : `${INVALID_MESSAGE_PREFIX} ${DEFAULT_INVALID_MESSAGE_1}${DEFAULT_INVALID_MESSAGE_2}`;
|
|
25347
25756
|
this.setState({
|
|
25348
25757
|
status: status,
|
|
25349
25758
|
message: message,
|
|
@@ -25405,8 +25814,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25405
25814
|
color: "#526f03"
|
|
25406
25815
|
}
|
|
25407
25816
|
}));
|
|
25408
|
-
|
|
25409
|
-
gradeStatus = i18n__namespace._("Correct");
|
|
25817
|
+
gradeStatus = this.context.strings.correct;
|
|
25410
25818
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25411
25819
|
// TODO(jeremy): update to a WB colour
|
|
25412
25820
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
@@ -25415,8 +25823,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25415
25823
|
color: "#ff5454"
|
|
25416
25824
|
}
|
|
25417
25825
|
}));
|
|
25418
|
-
|
|
25419
|
-
gradeStatus = i18n__namespace._("Incorrect");
|
|
25826
|
+
gradeStatus = this.context.strings.incorrect;
|
|
25420
25827
|
}
|
|
25421
25828
|
const mobileClass = this.props.inGradedGroupSet ? aphrodite.css(styles$n.gradedGroupInSet) : aphrodite.css(styles$n.gradedGroup);
|
|
25422
25829
|
const classes = classNames__default["default"]({
|
|
@@ -25446,7 +25853,8 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25446
25853
|
readOnly
|
|
25447
25854
|
},
|
|
25448
25855
|
onInteractWithWidget: this._onInteractWithWidget,
|
|
25449
|
-
linterContext: this.props.linterContext
|
|
25856
|
+
linterContext: this.props.linterContext,
|
|
25857
|
+
strings: this.context.strings
|
|
25450
25858
|
})), !apiOptions.isMobile && icon && /*#__PURE__*/React__namespace.createElement("div", {
|
|
25451
25859
|
className: "group-icon"
|
|
25452
25860
|
}, icon), !apiOptions.isMobile && gradeStatus && /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -25460,14 +25868,14 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25460
25868
|
kind: "secondary",
|
|
25461
25869
|
disabled: this.props.apiOptions.readOnly,
|
|
25462
25870
|
onClick: this._checkAnswer
|
|
25463
|
-
},
|
|
25871
|
+
}, this.context.strings.check), !apiOptions.isMobile && isCorrect && this.props.onNextQuestion && /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
|
|
25464
25872
|
kind: "secondary",
|
|
25465
25873
|
disabled: this.props.apiOptions.readOnly,
|
|
25466
25874
|
onClick: this.props.onNextQuestion,
|
|
25467
25875
|
style: {
|
|
25468
25876
|
marginLeft: 5
|
|
25469
25877
|
}
|
|
25470
|
-
},
|
|
25878
|
+
}, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("button", {
|
|
25471
25879
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
25472
25880
|
tabIndex: "0",
|
|
25473
25881
|
className: aphrodite.css(styles$n.explanationTitle),
|
|
@@ -25481,11 +25889,12 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25481
25889
|
showHint: false
|
|
25482
25890
|
});
|
|
25483
25891
|
}
|
|
25484
|
-
},
|
|
25892
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, this.props.hint, {
|
|
25485
25893
|
// eslint-disable-next-line react/no-string-refs
|
|
25486
25894
|
ref: "hints-renderer",
|
|
25487
25895
|
apiOptions: apiOptions,
|
|
25488
|
-
linterContext: this.props.linterContext
|
|
25896
|
+
linterContext: this.props.linterContext,
|
|
25897
|
+
strings: this.context.strings
|
|
25489
25898
|
}))) :
|
|
25490
25899
|
/*#__PURE__*/
|
|
25491
25900
|
// Not using Button here bc the styles won't work.
|
|
@@ -25503,7 +25912,7 @@ class GradedGroup extends React__namespace.Component {
|
|
|
25503
25912
|
});
|
|
25504
25913
|
},
|
|
25505
25914
|
className: aphrodite.css(styles$n.showHintLink)
|
|
25506
|
-
},
|
|
25915
|
+
}, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React__namespace.createElement(GradedGroupAnswerBar, {
|
|
25507
25916
|
apiOptions: apiOptions,
|
|
25508
25917
|
answerBarState: answerBarState,
|
|
25509
25918
|
onCheckAnswer: this._checkAnswer,
|
|
@@ -25575,6 +25984,7 @@ var GradedGroup$1 = {
|
|
|
25575
25984
|
};
|
|
25576
25985
|
|
|
25577
25986
|
class Indicators extends React__namespace.Component {
|
|
25987
|
+
static contextType = PerseusI18nContext;
|
|
25578
25988
|
handleKeyDown = (e, i) => {
|
|
25579
25989
|
if (e.key === "Enter" || e.key === " ") {
|
|
25580
25990
|
this.props.onChangeCurrentGroup(i);
|
|
@@ -25594,7 +26004,7 @@ class Indicators extends React__namespace.Component {
|
|
|
25594
26004
|
key: title
|
|
25595
26005
|
}, /*#__PURE__*/React__namespace.createElement(Clickable__default["default"], {
|
|
25596
26006
|
role: "button",
|
|
25597
|
-
"aria-label":
|
|
26007
|
+
"aria-label": this.context.strings.skipToTitle({
|
|
25598
26008
|
title
|
|
25599
26009
|
}),
|
|
25600
26010
|
style: styles$m.indicatorButton,
|
|
@@ -25612,7 +26022,7 @@ class Indicators extends React__namespace.Component {
|
|
|
25612
26022
|
style: styles$m.indicatorDotActive
|
|
25613
26023
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
25614
26024
|
className: aphrodite.css(a11y.srOnly)
|
|
25615
|
-
},
|
|
26025
|
+
}, this.context.strings.current)));
|
|
25616
26026
|
}));
|
|
25617
26027
|
}));
|
|
25618
26028
|
}
|
|
@@ -25624,7 +26034,7 @@ class Indicators extends React__namespace.Component {
|
|
|
25624
26034
|
// are currently a little confusing.
|
|
25625
26035
|
class GradedGroupSet extends React__namespace.Component {
|
|
25626
26036
|
// @ts-expect-error - TS2564 - Property '_childGroup' has no initializer and is not definitely assigned in the constructor.
|
|
25627
|
-
|
|
26037
|
+
_childGroup;
|
|
25628
26038
|
static defaultProps = {
|
|
25629
26039
|
gradedGroups: [],
|
|
25630
26040
|
linterContext: PerseusLinter.linterContextDefault
|
|
@@ -25703,7 +26113,7 @@ class GradedGroupSet extends React__namespace.Component {
|
|
|
25703
26113
|
}
|
|
25704
26114
|
const currentGroup = this.props.gradedGroups[this.state.currentGroup];
|
|
25705
26115
|
if (!currentGroup) {
|
|
25706
|
-
return /*#__PURE__*/React__namespace.createElement("span", null,
|
|
26116
|
+
return /*#__PURE__*/React__namespace.createElement("span", null, "No current group...");
|
|
25707
26117
|
}
|
|
25708
26118
|
const numGroups = this.props.gradedGroups.length;
|
|
25709
26119
|
const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
|
|
@@ -25826,6 +26236,7 @@ const styles$m = aphrodite.StyleSheet.create({
|
|
|
25826
26236
|
* ButtonGroup is an aesthetically pleasing group of buttons.
|
|
25827
26237
|
*/
|
|
25828
26238
|
class ButtonGroup extends React__namespace.Component {
|
|
26239
|
+
container;
|
|
25829
26240
|
static defaultProps = {
|
|
25830
26241
|
value: null,
|
|
25831
26242
|
allowEmpty: true
|
|
@@ -26675,6 +27086,8 @@ class FunctionGrapher extends React__namespace.Component {
|
|
|
26675
27086
|
|
|
26676
27087
|
/* Widget and editor. */
|
|
26677
27088
|
class Grapher extends React__namespace.Component {
|
|
27089
|
+
horizHairline;
|
|
27090
|
+
vertHairline;
|
|
26678
27091
|
static defaultProps = DEFAULT_GRAPHER_PROPS;
|
|
26679
27092
|
render() {
|
|
26680
27093
|
const type = this.props.plot.type;
|
|
@@ -26881,6 +27294,8 @@ var Grapher$1 = {
|
|
|
26881
27294
|
// exports has no 'transform'
|
|
26882
27295
|
|
|
26883
27296
|
class Group extends React__namespace.Component {
|
|
27297
|
+
static contextType = PerseusI18nContext;
|
|
27298
|
+
rendererRef;
|
|
26884
27299
|
static defaultProps = {
|
|
26885
27300
|
content: "",
|
|
26886
27301
|
widgets: {},
|
|
@@ -26997,7 +27412,8 @@ class Group extends React__namespace.Component {
|
|
|
26997
27412
|
findExternalWidgets: this.props.findWidgets,
|
|
26998
27413
|
reviewMode: !!this.props.reviewModeRubric,
|
|
26999
27414
|
onInteractWithWidget: onInteractWithWidget,
|
|
27000
|
-
linterContext: this.props.linterContext
|
|
27415
|
+
linterContext: this.props.linterContext,
|
|
27416
|
+
strings: this.context.strings
|
|
27001
27417
|
}), this.props.icon &&
|
|
27002
27418
|
/*#__PURE__*/
|
|
27003
27419
|
// @ts-expect-error - TS2339 - Property 'icon' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
|
|
@@ -27202,6 +27618,7 @@ const DEFAULT_ALIGNMENT = "block";
|
|
|
27202
27618
|
// there is no transform as part of exports
|
|
27203
27619
|
|
|
27204
27620
|
class ImageWidget extends React__namespace.Component {
|
|
27621
|
+
static contextType = PerseusI18nContext;
|
|
27205
27622
|
static defaultProps = {
|
|
27206
27623
|
alignment: DEFAULT_ALIGNMENT,
|
|
27207
27624
|
title: "",
|
|
@@ -27290,7 +27707,8 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27290
27707
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27291
27708
|
content: this.props.alt,
|
|
27292
27709
|
apiOptions: apiOptions,
|
|
27293
|
-
linterContext: this.props.linterContext
|
|
27710
|
+
linterContext: this.props.linterContext,
|
|
27711
|
+
strings: this.context.strings
|
|
27294
27712
|
}));
|
|
27295
27713
|
}
|
|
27296
27714
|
|
|
@@ -27350,7 +27768,8 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27350
27768
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27351
27769
|
content: title + this.props.caption,
|
|
27352
27770
|
apiOptions: apiOptions,
|
|
27353
|
-
linterContext: this.props.linterContext
|
|
27771
|
+
linterContext: this.props.linterContext,
|
|
27772
|
+
strings: this.context.strings
|
|
27354
27773
|
})));
|
|
27355
27774
|
}
|
|
27356
27775
|
return /*#__PURE__*/React__namespace.createElement("figure", {
|
|
@@ -27368,7 +27787,8 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27368
27787
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27369
27788
|
content: this.props.title,
|
|
27370
27789
|
apiOptions: apiOptions,
|
|
27371
|
-
linterContext: this.props.linterContext
|
|
27790
|
+
linterContext: this.props.linterContext,
|
|
27791
|
+
strings: this.context.strings
|
|
27372
27792
|
}));
|
|
27373
27793
|
}
|
|
27374
27794
|
if (this.props.caption) {
|
|
@@ -27380,7 +27800,8 @@ class ImageWidget extends React__namespace.Component {
|
|
|
27380
27800
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
27381
27801
|
content: this.props.caption,
|
|
27382
27802
|
apiOptions: apiOptions,
|
|
27383
|
-
linterContext: this.props.linterContext
|
|
27803
|
+
linterContext: this.props.linterContext,
|
|
27804
|
+
strings: this.context.strings
|
|
27384
27805
|
}));
|
|
27385
27806
|
}
|
|
27386
27807
|
return /*#__PURE__*/React__namespace.createElement("figure", {
|
|
@@ -28050,10 +28471,13 @@ function numSteps$1(range, step) {
|
|
|
28050
28471
|
return Math.floor((range[1] - range[0]) / step);
|
|
28051
28472
|
}
|
|
28052
28473
|
class Graph extends React__namespace.Component {
|
|
28474
|
+
protractor;
|
|
28475
|
+
ruler;
|
|
28476
|
+
_graphie;
|
|
28053
28477
|
// @ts-expect-error - TS2564 - Property '_hasSetupGraphieThisUpdate' has no initializer and is not definitely assigned in the constructor.
|
|
28054
|
-
|
|
28478
|
+
_hasSetupGraphieThisUpdate;
|
|
28055
28479
|
// @ts-expect-error - TS2564 - Property '_shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
28056
|
-
|
|
28480
|
+
_shouldSetupGraphie;
|
|
28057
28481
|
static defaultProps = {
|
|
28058
28482
|
labels: ["x", "y"],
|
|
28059
28483
|
range: [[-10, 10], [-10, 10]],
|
|
@@ -28322,6 +28746,123 @@ class Graph extends React__namespace.Component {
|
|
|
28322
28746
|
}
|
|
28323
28747
|
}
|
|
28324
28748
|
|
|
28749
|
+
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
28750
|
+
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
28751
|
+
|
|
28752
|
+
// Range is replaced within this file with Interval, but it is used elsewhere
|
|
28753
|
+
// and exported from the package, so we need to keep it around.
|
|
28754
|
+
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
28755
|
+
const ItemExtras = [
|
|
28756
|
+
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
28757
|
+
"calculator",
|
|
28758
|
+
// The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
|
|
28759
|
+
"chi2Table",
|
|
28760
|
+
// The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
|
|
28761
|
+
"financialCalculatorMonthlyPayment",
|
|
28762
|
+
// The user might benefit from a total amount calculator. Provided on Khan Academy when true
|
|
28763
|
+
"financialCalculatorTotalAmount",
|
|
28764
|
+
// The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
|
|
28765
|
+
"financialCalculatorTimeToPayOff",
|
|
28766
|
+
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
28767
|
+
"periodicTable",
|
|
28768
|
+
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
28769
|
+
"periodicTableWithKey",
|
|
28770
|
+
// The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
|
|
28771
|
+
"tTable",
|
|
28772
|
+
// The user might benefit from using a statistics Z Table like https://www.ztable.net/
|
|
28773
|
+
"zTable"];
|
|
28774
|
+
|
|
28775
|
+
// prettier-ignore
|
|
28776
|
+
|
|
28777
|
+
// prettier-ignore
|
|
28778
|
+
|
|
28779
|
+
// prettier-ignore
|
|
28780
|
+
|
|
28781
|
+
// prettier-ignore
|
|
28782
|
+
|
|
28783
|
+
// prettier-ignore
|
|
28784
|
+
|
|
28785
|
+
// prettier-ignore
|
|
28786
|
+
|
|
28787
|
+
// prettier-ignore
|
|
28788
|
+
|
|
28789
|
+
// prettier-ignore
|
|
28790
|
+
|
|
28791
|
+
// prettier-ignore
|
|
28792
|
+
|
|
28793
|
+
// prettier-ignore
|
|
28794
|
+
|
|
28795
|
+
// prettier-ignore
|
|
28796
|
+
|
|
28797
|
+
// prettier-ignore
|
|
28798
|
+
|
|
28799
|
+
// prettier-ignore
|
|
28800
|
+
|
|
28801
|
+
// prettier-ignore
|
|
28802
|
+
|
|
28803
|
+
// prettier-ignore
|
|
28804
|
+
|
|
28805
|
+
// prettier-ignore
|
|
28806
|
+
|
|
28807
|
+
// prettier-ignore
|
|
28808
|
+
|
|
28809
|
+
// prettier-ignore
|
|
28810
|
+
|
|
28811
|
+
// prettier-ignore
|
|
28812
|
+
|
|
28813
|
+
// prettier-ignore
|
|
28814
|
+
|
|
28815
|
+
// prettier-ignore
|
|
28816
|
+
|
|
28817
|
+
// prettier-ignore
|
|
28818
|
+
|
|
28819
|
+
// prettier-ignore
|
|
28820
|
+
|
|
28821
|
+
// prettier-ignore
|
|
28822
|
+
|
|
28823
|
+
// prettier-ignore
|
|
28824
|
+
|
|
28825
|
+
// prettier-ignore
|
|
28826
|
+
|
|
28827
|
+
// prettier-ignore
|
|
28828
|
+
|
|
28829
|
+
// prettier-ignore
|
|
28830
|
+
|
|
28831
|
+
// prettier-ignore
|
|
28832
|
+
|
|
28833
|
+
// prettier-ignore
|
|
28834
|
+
|
|
28835
|
+
// prettier-ignore
|
|
28836
|
+
|
|
28837
|
+
// prettier-ignore
|
|
28838
|
+
|
|
28839
|
+
// prettier-ignore
|
|
28840
|
+
|
|
28841
|
+
// prettier-ignore
|
|
28842
|
+
|
|
28843
|
+
// prettier-ignore
|
|
28844
|
+
|
|
28845
|
+
// prettier-ignore
|
|
28846
|
+
|
|
28847
|
+
//prettier-ignore
|
|
28848
|
+
|
|
28849
|
+
// A background image applied to various widgets.
|
|
28850
|
+
|
|
28851
|
+
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28852
|
+
const lockedFigureColors = {
|
|
28853
|
+
blue: "#3D7586",
|
|
28854
|
+
green: "#447A53",
|
|
28855
|
+
gray: "#5D5F66",
|
|
28856
|
+
grayH: "#3B3D45",
|
|
28857
|
+
grayI: "#21242C",
|
|
28858
|
+
purple: "#594094",
|
|
28859
|
+
purpleD: "#8351E8",
|
|
28860
|
+
pink: "#B25071",
|
|
28861
|
+
orange: "#946700",
|
|
28862
|
+
red: "#D92916"
|
|
28863
|
+
};
|
|
28864
|
+
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28865
|
+
|
|
28325
28866
|
const LockedLine = props => {
|
|
28326
28867
|
const {
|
|
28327
28868
|
color,
|
|
@@ -28338,7 +28879,7 @@ const LockedLine = props => {
|
|
|
28338
28879
|
line = /*#__PURE__*/React__namespace.createElement(LineType, {
|
|
28339
28880
|
point1: point1.coord,
|
|
28340
28881
|
point2: point2.coord,
|
|
28341
|
-
color:
|
|
28882
|
+
color: lockedFigureColors[color],
|
|
28342
28883
|
style: lineStyle
|
|
28343
28884
|
});
|
|
28344
28885
|
} else {
|
|
@@ -28352,8 +28893,8 @@ const LockedLine = props => {
|
|
|
28352
28893
|
y: point1.coord[1],
|
|
28353
28894
|
svgCircleProps: {
|
|
28354
28895
|
style: {
|
|
28355
|
-
fill: point1.filled ?
|
|
28356
|
-
stroke:
|
|
28896
|
+
fill: point1.filled ? lockedFigureColors[point1.color] : wonderBlocksTokens.color.white,
|
|
28897
|
+
stroke: lockedFigureColors[point1.color],
|
|
28357
28898
|
strokeWidth: wonderBlocksTokens.spacing.xxxxSmall_2
|
|
28358
28899
|
}
|
|
28359
28900
|
}
|
|
@@ -28362,8 +28903,8 @@ const LockedLine = props => {
|
|
|
28362
28903
|
y: point2.coord[1],
|
|
28363
28904
|
svgCircleProps: {
|
|
28364
28905
|
style: {
|
|
28365
|
-
fill: point2.filled ?
|
|
28366
|
-
stroke:
|
|
28906
|
+
fill: point2.filled ? lockedFigureColors[point2.color] : wonderBlocksTokens.color.white,
|
|
28907
|
+
stroke: lockedFigureColors[point2.color],
|
|
28367
28908
|
strokeWidth: wonderBlocksTokens.spacing.xxxxSmall_2
|
|
28368
28909
|
}
|
|
28369
28910
|
}
|
|
@@ -28382,8 +28923,8 @@ const LockedPoint = props => {
|
|
|
28382
28923
|
y: y,
|
|
28383
28924
|
svgCircleProps: {
|
|
28384
28925
|
style: {
|
|
28385
|
-
fill: filled ?
|
|
28386
|
-
stroke:
|
|
28926
|
+
fill: filled ? lockedFigureColors[color] : wonderBlocksTokens.color.white,
|
|
28927
|
+
stroke: lockedFigureColors[color],
|
|
28387
28928
|
strokeWidth: wonderBlocksTokens.spacing.xxxxSmall_2
|
|
28388
28929
|
}
|
|
28389
28930
|
}
|
|
@@ -28739,7 +29280,8 @@ const MovableLine = props => {
|
|
|
28739
29280
|
const defaultGraphConfig = {
|
|
28740
29281
|
range: [[0, 1], [0, 1]],
|
|
28741
29282
|
snapStep: [1, 1],
|
|
28742
|
-
markings: "none"
|
|
29283
|
+
markings: "none",
|
|
29284
|
+
showTooltips: false
|
|
28743
29285
|
};
|
|
28744
29286
|
const GraphConfigContext = /*#__PURE__*/React.createContext(defaultGraphConfig);
|
|
28745
29287
|
function useGraphConfig() {
|
|
@@ -28753,7 +29295,8 @@ const StyledMovablePoint = props => {
|
|
|
28753
29295
|
const {
|
|
28754
29296
|
range,
|
|
28755
29297
|
snapStep,
|
|
28756
|
-
markings
|
|
29298
|
+
markings,
|
|
29299
|
+
showTooltips
|
|
28757
29300
|
} = useGraphConfig();
|
|
28758
29301
|
const hitboxRef = React.useRef(null);
|
|
28759
29302
|
const {
|
|
@@ -28761,6 +29304,13 @@ const StyledMovablePoint = props => {
|
|
|
28761
29304
|
onMove,
|
|
28762
29305
|
color = wonderBlocksTokens.color.blue
|
|
28763
29306
|
} = props;
|
|
29307
|
+
|
|
29308
|
+
// WB Tooltip requires a color name for the background color.
|
|
29309
|
+
// Since the color in props is a hex value, a reverse lookup is needed.
|
|
29310
|
+
const wbColorName = Object.entries(wonderBlocksTokens.color).find(_ref => {
|
|
29311
|
+
let [_, value] = _ref;
|
|
29312
|
+
return value === color;
|
|
29313
|
+
})?.[0] ?? "blue";
|
|
28764
29314
|
const {
|
|
28765
29315
|
dragging
|
|
28766
29316
|
} = mafs.useMovable({
|
|
@@ -28778,19 +29328,20 @@ const StyledMovablePoint = props => {
|
|
|
28778
29328
|
const [[_, horizontalStartY]] = useTransform([0, yMin]);
|
|
28779
29329
|
const [[__, horizontalEndY]] = useTransform([0, yMax]);
|
|
28780
29330
|
const showHairlines = dragging && markings !== "none";
|
|
28781
|
-
|
|
29331
|
+
const hairlines = /*#__PURE__*/React__namespace.createElement("g", null, /*#__PURE__*/React__namespace.createElement("line", {
|
|
28782
29332
|
x1: verticalStartX,
|
|
28783
29333
|
y1: y,
|
|
28784
29334
|
x2: verticalEndX,
|
|
28785
29335
|
y2: y,
|
|
28786
|
-
stroke:
|
|
29336
|
+
stroke: color
|
|
28787
29337
|
}), /*#__PURE__*/React__namespace.createElement("line", {
|
|
28788
29338
|
x1: x,
|
|
28789
29339
|
y1: horizontalStartY,
|
|
28790
29340
|
x2: x,
|
|
28791
29341
|
y2: horizontalEndY,
|
|
28792
|
-
stroke:
|
|
28793
|
-
}))
|
|
29342
|
+
stroke: color
|
|
29343
|
+
}));
|
|
29344
|
+
const svgForPoint = /*#__PURE__*/React__namespace.createElement("g", {
|
|
28794
29345
|
ref: hitboxRef,
|
|
28795
29346
|
className: pointClasses,
|
|
28796
29347
|
tabIndex: 0,
|
|
@@ -28823,7 +29374,15 @@ const StyledMovablePoint = props => {
|
|
|
28823
29374
|
fill: color
|
|
28824
29375
|
},
|
|
28825
29376
|
"data-testid": "movable-point__center"
|
|
28826
|
-
}))
|
|
29377
|
+
}));
|
|
29378
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
29379
|
+
autoUpdate: true,
|
|
29380
|
+
backgroundColor: wbColorName,
|
|
29381
|
+
content: `(${point[0]}, ${point[1]})`,
|
|
29382
|
+
contentStyle: {
|
|
29383
|
+
color: "white"
|
|
29384
|
+
}
|
|
29385
|
+
}, svgForPoint) : svgForPoint);
|
|
28827
29386
|
};
|
|
28828
29387
|
|
|
28829
29388
|
const SegmentGraph = props => {
|
|
@@ -29727,6 +30286,7 @@ const getNumericFormat = KhanMath.getNumericFormat;
|
|
|
29727
30286
|
* Optionally takes a size ("mini", "small", "normal")
|
|
29728
30287
|
*/
|
|
29729
30288
|
class NumberInput extends React__namespace.Component {
|
|
30289
|
+
static contextType = PerseusI18nContext;
|
|
29730
30290
|
static propTypes = {
|
|
29731
30291
|
value: PropTypes__default["default"].number,
|
|
29732
30292
|
format: PropTypes__default["default"].string,
|
|
@@ -29813,7 +30373,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29813
30373
|
const placeholder = this.props.placeholder;
|
|
29814
30374
|
return ___default["default"].isFinite(placeholder) ? +placeholder : null;
|
|
29815
30375
|
}
|
|
29816
|
-
const result = firstNumericalParse(value);
|
|
30376
|
+
const result = firstNumericalParse(value, this.context.strings);
|
|
29817
30377
|
return ___default["default"].isFinite(result) ? result : this.props.value;
|
|
29818
30378
|
};
|
|
29819
30379
|
|
|
@@ -29844,7 +30404,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
29844
30404
|
if (value == null) {
|
|
29845
30405
|
return true;
|
|
29846
30406
|
}
|
|
29847
|
-
const val = firstNumericalParse(value);
|
|
30407
|
+
const val = firstNumericalParse(value, this.context.strings);
|
|
29848
30408
|
const checkValidity = this.props.checkValidity;
|
|
29849
30409
|
return ___default["default"].isFinite(val) && checkValidity(val);
|
|
29850
30410
|
};
|
|
@@ -30643,7 +31203,8 @@ const MafsGraph = props => {
|
|
|
30643
31203
|
value: {
|
|
30644
31204
|
range: state.range,
|
|
30645
31205
|
snapStep: state.snapStep,
|
|
30646
|
-
markings: props.markings
|
|
31206
|
+
markings: props.markings,
|
|
31207
|
+
showTooltips: !!props.showTooltips
|
|
30647
31208
|
}
|
|
30648
31209
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
30649
31210
|
style: {
|
|
@@ -30744,10 +31305,25 @@ const makeInvalidTypeError = (functionName, graphType) => {
|
|
|
30744
31305
|
// There's no transform function in exports
|
|
30745
31306
|
|
|
30746
31307
|
class LegacyInteractiveGraph extends React__namespace.Component {
|
|
31308
|
+
static contextType = PerseusI18nContext;
|
|
31309
|
+
angle;
|
|
31310
|
+
circle;
|
|
31311
|
+
graphie;
|
|
31312
|
+
horizHairline;
|
|
31313
|
+
line;
|
|
31314
|
+
lines;
|
|
31315
|
+
parabola;
|
|
31316
|
+
pointA;
|
|
31317
|
+
pointB;
|
|
31318
|
+
pointC;
|
|
30747
31319
|
// @ts-expect-error - TS2564 - Property 'points' has no initializer and is not definitely assigned in the constructor.
|
|
30748
|
-
|
|
31320
|
+
points;
|
|
31321
|
+
polygon;
|
|
30749
31322
|
// @ts-expect-error - TS2564 - Property 'shouldResetGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
30750
|
-
|
|
31323
|
+
shouldResetGraphie;
|
|
31324
|
+
sinusoid;
|
|
31325
|
+
trashCan;
|
|
31326
|
+
vertHairline;
|
|
30751
31327
|
static defaultProps = {
|
|
30752
31328
|
labels: ["x", "y"],
|
|
30753
31329
|
range: [[-10, 10], [-10, 10]],
|
|
@@ -31885,9 +32461,9 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
31885
32461
|
// isClickToAddPoints() only applies to points and polygons
|
|
31886
32462
|
if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
|
|
31887
32463
|
if (this.props.graph.type === "point") {
|
|
31888
|
-
instructions =
|
|
32464
|
+
instructions = this.context.strings.addPoints;
|
|
31889
32465
|
} else if (this.props.graph.type === "polygon") {
|
|
31890
|
-
instructions =
|
|
32466
|
+
instructions = this.context.strings.addVertices;
|
|
31891
32467
|
}
|
|
31892
32468
|
} else {
|
|
31893
32469
|
instructions = undefined;
|
|
@@ -31965,7 +32541,8 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
31965
32541
|
ref: this.mafsRef,
|
|
31966
32542
|
gridStep: gridStep,
|
|
31967
32543
|
snapStep: snapStep,
|
|
31968
|
-
box: box
|
|
32544
|
+
box: box,
|
|
32545
|
+
showTooltips: !!this.props.showTooltips
|
|
31969
32546
|
}));
|
|
31970
32547
|
}
|
|
31971
32548
|
return /*#__PURE__*/React__namespace.createElement(LegacyInteractiveGraph, _extends({
|
|
@@ -33492,6 +34069,9 @@ var globalStyles = /*#__PURE__*/Object.freeze({
|
|
|
33492
34069
|
});
|
|
33493
34070
|
|
|
33494
34071
|
const AnswerChoices = props => {
|
|
34072
|
+
const {
|
|
34073
|
+
strings
|
|
34074
|
+
} = usePerseusI18n();
|
|
33495
34075
|
const onAnswerChange = selected => {
|
|
33496
34076
|
const {
|
|
33497
34077
|
choices,
|
|
@@ -33511,6 +34091,7 @@ const AnswerChoices = props => {
|
|
|
33511
34091
|
value: content,
|
|
33512
34092
|
label: /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
33513
34093
|
content: content,
|
|
34094
|
+
strings: strings,
|
|
33514
34095
|
inline: true
|
|
33515
34096
|
})
|
|
33516
34097
|
});
|
|
@@ -33541,14 +34122,13 @@ const AnswerChoices = props => {
|
|
|
33541
34122
|
}));
|
|
33542
34123
|
};
|
|
33543
34124
|
|
|
33544
|
-
const strings = {
|
|
33545
|
-
hideAnswersToggleLabel: i18n__namespace._("Hide answer choices")
|
|
33546
|
-
};
|
|
33547
|
-
|
|
33548
34125
|
const HideAnswersToggle = props => {
|
|
33549
34126
|
const idFactory = wonderBlocksCore.useUniqueIdWithMock();
|
|
33550
34127
|
const switchId = idFactory.get("hide-answers-toggle");
|
|
33551
34128
|
const labelId = idFactory.get("hide-answers-label");
|
|
34129
|
+
const {
|
|
34130
|
+
strings
|
|
34131
|
+
} = usePerseusI18n();
|
|
33552
34132
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
33553
34133
|
style: styles$g.switchWrapper
|
|
33554
34134
|
}, /*#__PURE__*/React__namespace.createElement(Switch__default["default"], {
|
|
@@ -33589,9 +34169,12 @@ const AnswerPill = props => {
|
|
|
33589
34169
|
hovered
|
|
33590
34170
|
} = props;
|
|
33591
34171
|
const idFactory = wonderBlocksCore.useUniqueIdWithMock();
|
|
33592
|
-
const
|
|
33593
|
-
|
|
33594
|
-
|
|
34172
|
+
const {
|
|
34173
|
+
strings
|
|
34174
|
+
} = usePerseusI18n();
|
|
34175
|
+
const answerString = selectedAnswers.length > 1 ? strings.answers({
|
|
34176
|
+
num: selectedAnswers.length
|
|
34177
|
+
}) : selectedAnswers[0];
|
|
33595
34178
|
|
|
33596
34179
|
// It should no longer be possible to interact with an answer after it
|
|
33597
34180
|
// has been labeled (answered) correctly.
|
|
@@ -33620,6 +34203,7 @@ const AnswerPill = props => {
|
|
|
33620
34203
|
style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
|
|
33621
34204
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
33622
34205
|
content: answerString,
|
|
34206
|
+
strings: strings,
|
|
33623
34207
|
inline: true
|
|
33624
34208
|
}));
|
|
33625
34209
|
});
|
|
@@ -33646,8 +34230,9 @@ function shouldReduceMotion() {
|
|
|
33646
34230
|
}
|
|
33647
34231
|
const MARKER_SIZE = 24;
|
|
33648
34232
|
class Marker extends React__namespace.Component {
|
|
34233
|
+
static contextType = PerseusI18nContext;
|
|
33649
34234
|
// The marker icon element.
|
|
33650
|
-
|
|
34235
|
+
_icon;
|
|
33651
34236
|
static defaultProps = {
|
|
33652
34237
|
selected: []
|
|
33653
34238
|
};
|
|
@@ -33717,10 +34302,8 @@ class Marker extends React__namespace.Component {
|
|
|
33717
34302
|
const markerDisabled = showCorrectness === "correct";
|
|
33718
34303
|
const active = hovered || focused;
|
|
33719
34304
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
33720
|
-
style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
|
|
33721
|
-
|
|
33722
|
-
,
|
|
33723
|
-
"aria-label": markerDisabled ? i18n__namespace._("Correct!") : label
|
|
34305
|
+
style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive],
|
|
34306
|
+
"aria-label": markerDisabled ? this.context.strings.correctExcited : label
|
|
33724
34307
|
}, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React__namespace.createElement(AnswerPill, {
|
|
33725
34308
|
selectedAnswers: selected,
|
|
33726
34309
|
showCorrectness: showCorrectness,
|
|
@@ -33820,8 +34403,9 @@ const styles$e = aphrodite.StyleSheet.create({
|
|
|
33820
34403
|
*/
|
|
33821
34404
|
|
|
33822
34405
|
class LabelImage extends React__namespace.Component {
|
|
34406
|
+
static contextType = PerseusI18nContext;
|
|
33823
34407
|
// The rendered markers on the question image for labeling.
|
|
33824
|
-
|
|
34408
|
+
_markers;
|
|
33825
34409
|
static gradeMarker(marker) {
|
|
33826
34410
|
const score = {
|
|
33827
34411
|
hasAnswers: false,
|
|
@@ -34307,8 +34891,11 @@ class LabelImage extends React__namespace.Component {
|
|
|
34307
34891
|
multipleAnswers,
|
|
34308
34892
|
hideChoicesFromInstructions: hideChoices
|
|
34309
34893
|
} = this.props;
|
|
34310
|
-
const
|
|
34311
|
-
|
|
34894
|
+
const {
|
|
34895
|
+
strings
|
|
34896
|
+
} = this.context;
|
|
34897
|
+
const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
|
|
34898
|
+
const choicesString = strings.choices;
|
|
34312
34899
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
34313
34900
|
className: classNames__default["default"]("perseus-label-image-widget-instructions", aphrodite.css(styles$d.instructions))
|
|
34314
34901
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -34319,7 +34906,8 @@ class LabelImage extends React__namespace.Component {
|
|
|
34319
34906
|
className: aphrodite.css(styles$d.instructionsChoice),
|
|
34320
34907
|
key: index
|
|
34321
34908
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
34322
|
-
content: choice
|
|
34909
|
+
content: choice,
|
|
34910
|
+
strings: strings
|
|
34323
34911
|
})))));
|
|
34324
34912
|
}
|
|
34325
34913
|
render() {
|
|
@@ -34494,12 +35082,13 @@ class Placeholder extends React__namespace.Component {
|
|
|
34494
35082
|
// Usual flow: Static -> Dragging -> Animating -> Static
|
|
34495
35083
|
// [Dis|en]abling: Static|Dragging|Animating -> Disabled -> Static
|
|
34496
35084
|
class Draggable extends React__namespace.Component {
|
|
35085
|
+
static contextType = PerseusI18nContext;
|
|
34497
35086
|
// Handler returned by requestAnimationFrame.
|
|
34498
35087
|
animationFrameRequest = null;
|
|
34499
35088
|
// @ts-expect-error - TS2564 - Property 'isMouseMoveUpBound' has no initializer and is not definitely assigned in the constructor.
|
|
34500
|
-
|
|
35089
|
+
isMouseMoveUpBound;
|
|
34501
35090
|
// @ts-expect-error - TS2564 - Property '_mounted' has no initializer and is not definitely assigned in the constructor.
|
|
34502
|
-
|
|
35091
|
+
_mounted;
|
|
34503
35092
|
static defaultProps = {
|
|
34504
35093
|
includePadding: true,
|
|
34505
35094
|
type: ItemState.STATIC,
|
|
@@ -34602,7 +35191,8 @@ class Draggable extends React__namespace.Component {
|
|
|
34602
35191
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
34603
35192
|
content: this.props.content,
|
|
34604
35193
|
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "draggable"),
|
|
34605
|
-
onRender: this.props.onRender
|
|
35194
|
+
onRender: this.props.onRender,
|
|
35195
|
+
strings: this.context.strings
|
|
34606
35196
|
}));
|
|
34607
35197
|
}
|
|
34608
35198
|
componentDidUpdate(prevProps) {
|
|
@@ -35156,6 +35746,7 @@ const {
|
|
|
35156
35746
|
} = Util;
|
|
35157
35747
|
const HACKY_CSS_CLASSNAME = "perseus-widget-matcher";
|
|
35158
35748
|
class Matcher extends React__namespace.Component {
|
|
35749
|
+
static contextType = PerseusI18nContext;
|
|
35159
35750
|
static propTypes = {
|
|
35160
35751
|
apiOptions: ApiOptions.propTypes,
|
|
35161
35752
|
labels: PropTypes__default["default"].array,
|
|
@@ -35235,12 +35826,14 @@ class Matcher extends React__namespace.Component {
|
|
|
35235
35826
|
className: aphrodite.css(styles$b.column, styles$b.columnLabel)
|
|
35236
35827
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
35237
35828
|
content: this.props.labels[0] || "...",
|
|
35238
|
-
linterContext: this.props.linterContext
|
|
35829
|
+
linterContext: this.props.linterContext,
|
|
35830
|
+
strings: this.context.strings
|
|
35239
35831
|
})), /*#__PURE__*/React__namespace.createElement("th", {
|
|
35240
35832
|
className: aphrodite.css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
|
|
35241
35833
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
35242
35834
|
content: this.props.labels[1] || "...",
|
|
35243
|
-
linterContext: this.props.linterContext
|
|
35835
|
+
linterContext: this.props.linterContext,
|
|
35836
|
+
strings: this.context.strings
|
|
35244
35837
|
}))), /*#__PURE__*/React__namespace.createElement("tr", {
|
|
35245
35838
|
className: aphrodite.css(styles$b.row)
|
|
35246
35839
|
}, /*#__PURE__*/React__namespace.createElement("td", {
|
|
@@ -35452,8 +36045,9 @@ const getMatrixSize = function (matrix) {
|
|
|
35452
36045
|
return matrixSize;
|
|
35453
36046
|
};
|
|
35454
36047
|
class Matrix extends React__namespace.Component {
|
|
36048
|
+
static contextType = PerseusI18nContext;
|
|
35455
36049
|
// @ts-expect-error - TS2564 - Property 'cursorPosition' has no initializer and is not definitely assigned in the constructor.
|
|
35456
|
-
|
|
36050
|
+
cursorPosition;
|
|
35457
36051
|
static defaultProps = {
|
|
35458
36052
|
matrixBoardSize: [3, 3],
|
|
35459
36053
|
answers: [[]],
|
|
@@ -35463,6 +36057,57 @@ class Matrix extends React__namespace.Component {
|
|
|
35463
36057
|
apiOptions: ApiOptions.defaults,
|
|
35464
36058
|
linterContext: PerseusLinter.linterContextDefault
|
|
35465
36059
|
};
|
|
36060
|
+
static validate(state, rubric, strings) {
|
|
36061
|
+
const solution = rubric.answers;
|
|
36062
|
+
const supplied = state.answers;
|
|
36063
|
+
const solutionSize = getMatrixSize(solution);
|
|
36064
|
+
const suppliedSize = getMatrixSize(supplied);
|
|
36065
|
+
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
36066
|
+
const createValidator = KhanAnswerTypes.number.createValidatorFunctional;
|
|
36067
|
+
let message = null;
|
|
36068
|
+
let hasEmptyCell = false;
|
|
36069
|
+
let incorrect = false;
|
|
36070
|
+
___default["default"](suppliedSize[0]).times(row => {
|
|
36071
|
+
___default["default"](suppliedSize[1]).times(col => {
|
|
36072
|
+
if (supplied[row][col] == null || supplied[row][col].toString().length === 0) {
|
|
36073
|
+
hasEmptyCell = true;
|
|
36074
|
+
}
|
|
36075
|
+
if (!incorrectSize) {
|
|
36076
|
+
const validator = createValidator(solution[row][col], {
|
|
36077
|
+
simplify: true
|
|
36078
|
+
}, strings);
|
|
36079
|
+
const result = validator(supplied[row][col]);
|
|
36080
|
+
if (result.message) {
|
|
36081
|
+
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
36082
|
+
message = result.message;
|
|
36083
|
+
}
|
|
36084
|
+
if (!result.correct) {
|
|
36085
|
+
incorrect = true;
|
|
36086
|
+
}
|
|
36087
|
+
}
|
|
36088
|
+
});
|
|
36089
|
+
});
|
|
36090
|
+
if (hasEmptyCell) {
|
|
36091
|
+
return {
|
|
36092
|
+
type: "invalid",
|
|
36093
|
+
message: strings.fillAllCells
|
|
36094
|
+
};
|
|
36095
|
+
}
|
|
36096
|
+
if (incorrectSize) {
|
|
36097
|
+
return {
|
|
36098
|
+
type: "points",
|
|
36099
|
+
earned: 0,
|
|
36100
|
+
total: 1,
|
|
36101
|
+
message: null
|
|
36102
|
+
};
|
|
36103
|
+
}
|
|
36104
|
+
return {
|
|
36105
|
+
type: "points",
|
|
36106
|
+
earned: incorrect ? 0 : 1,
|
|
36107
|
+
total: 1,
|
|
36108
|
+
message: message
|
|
36109
|
+
};
|
|
36110
|
+
}
|
|
35466
36111
|
state = {
|
|
35467
36112
|
enterTheMatrix: 0
|
|
35468
36113
|
};
|
|
@@ -35505,7 +36150,8 @@ class Matrix extends React__namespace.Component {
|
|
|
35505
36150
|
className: "matrix-prefix"
|
|
35506
36151
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
35507
36152
|
content: this.props.prefix,
|
|
35508
|
-
linterContext: this.props.linterContext
|
|
36153
|
+
linterContext: this.props.linterContext,
|
|
36154
|
+
strings: this.context.strings
|
|
35509
36155
|
})), /*#__PURE__*/React__namespace.createElement("div", {
|
|
35510
36156
|
className: "matrix-input"
|
|
35511
36157
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -35620,7 +36266,8 @@ class Matrix extends React__namespace.Component {
|
|
|
35620
36266
|
className: "matrix-suffix"
|
|
35621
36267
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
35622
36268
|
content: this.props.suffix,
|
|
35623
|
-
linterContext: this.props.linterContext
|
|
36269
|
+
linterContext: this.props.linterContext,
|
|
36270
|
+
strings: this.context.strings
|
|
35624
36271
|
})));
|
|
35625
36272
|
}
|
|
35626
36273
|
getInputPaths = () => {
|
|
@@ -35759,63 +36406,9 @@ class Matrix extends React__namespace.Component {
|
|
|
35759
36406
|
};
|
|
35760
36407
|
};
|
|
35761
36408
|
simpleValidate = rubric => {
|
|
35762
|
-
|
|
35763
|
-
return Matrix.validate(this.getUserInput(), rubric);
|
|
36409
|
+
return Matrix.validate(this.getUserInput(), rubric, this.context.strings);
|
|
35764
36410
|
};
|
|
35765
36411
|
}
|
|
35766
|
-
___default["default"].extend(Matrix, {
|
|
35767
|
-
validate: function (state, rubric) {
|
|
35768
|
-
const solution = rubric.answers;
|
|
35769
|
-
const supplied = state.answers;
|
|
35770
|
-
const solutionSize = getMatrixSize(solution);
|
|
35771
|
-
const suppliedSize = getMatrixSize(supplied);
|
|
35772
|
-
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
35773
|
-
const createValidator = KhanAnswerTypes.number.createValidatorFunctional;
|
|
35774
|
-
let message = null;
|
|
35775
|
-
let hasEmptyCell = false;
|
|
35776
|
-
let incorrect = false;
|
|
35777
|
-
___default["default"](suppliedSize[0]).times(row => {
|
|
35778
|
-
___default["default"](suppliedSize[1]).times(col => {
|
|
35779
|
-
if (supplied[row][col] == null || supplied[row][col].toString().length === 0) {
|
|
35780
|
-
hasEmptyCell = true;
|
|
35781
|
-
}
|
|
35782
|
-
if (!incorrectSize) {
|
|
35783
|
-
const validator = createValidator(solution[row][col], {
|
|
35784
|
-
simplify: true
|
|
35785
|
-
});
|
|
35786
|
-
const result = validator(supplied[row][col]);
|
|
35787
|
-
if (result.message) {
|
|
35788
|
-
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
35789
|
-
message = result.message;
|
|
35790
|
-
}
|
|
35791
|
-
if (!result.correct) {
|
|
35792
|
-
incorrect = true;
|
|
35793
|
-
}
|
|
35794
|
-
}
|
|
35795
|
-
});
|
|
35796
|
-
});
|
|
35797
|
-
if (hasEmptyCell) {
|
|
35798
|
-
return {
|
|
35799
|
-
type: "invalid",
|
|
35800
|
-
message: i18n__namespace._("Make sure you fill in all cells in the matrix.")
|
|
35801
|
-
};
|
|
35802
|
-
}
|
|
35803
|
-
if (incorrectSize) {
|
|
35804
|
-
return {
|
|
35805
|
-
type: "points",
|
|
35806
|
-
earned: 0,
|
|
35807
|
-
total: 1,
|
|
35808
|
-
message: null
|
|
35809
|
-
};
|
|
35810
|
-
}
|
|
35811
|
-
return {
|
|
35812
|
-
type: "points",
|
|
35813
|
-
earned: incorrect ? 0 : 1,
|
|
35814
|
-
total: 1,
|
|
35815
|
-
message: message
|
|
35816
|
-
};
|
|
35817
|
-
}
|
|
35818
|
-
});
|
|
35819
36412
|
const propTransform$1 = editorProps => {
|
|
35820
36413
|
// Remove answers before passing to widget
|
|
35821
36414
|
const blankAnswers = ___default["default"](editorProps.matrixBoardSize[0]).times(function () {
|
|
@@ -36779,6 +37372,7 @@ const parse$1 = SmilesParser.parse;
|
|
|
36779
37372
|
const ParseError = SmilesParser.ParseError;
|
|
36780
37373
|
const borderSize = 30;
|
|
36781
37374
|
class Molecule extends React__namespace.Component {
|
|
37375
|
+
static contextType = PerseusI18nContext;
|
|
36782
37376
|
state = {
|
|
36783
37377
|
parsedSmiles: null,
|
|
36784
37378
|
error: null
|
|
@@ -36855,8 +37449,8 @@ class Molecule extends React__namespace.Component {
|
|
|
36855
37449
|
// eslint-disable-next-line react/no-string-refs
|
|
36856
37450
|
,
|
|
36857
37451
|
ref: "canvas"
|
|
36858
|
-
},
|
|
36859
|
-
content: this.props.smiles
|
|
37452
|
+
}, this.context.strings.molecularDrawing({
|
|
37453
|
+
content: this.props.smiles || ""
|
|
36860
37454
|
}));
|
|
36861
37455
|
if (this.state.error) {
|
|
36862
37456
|
content = /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -37035,6 +37629,7 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
37035
37629
|
return results;
|
|
37036
37630
|
});
|
|
37037
37631
|
class NumberLine extends React__namespace.Component {
|
|
37632
|
+
static contextType = PerseusI18nContext;
|
|
37038
37633
|
static defaultProps = {
|
|
37039
37634
|
range: [0, 10],
|
|
37040
37635
|
labelStyle: "decimal",
|
|
@@ -37347,18 +37942,21 @@ class NumberLine extends React__namespace.Component {
|
|
|
37347
37942
|
return NumberLine.validate(this.getUserInput(), rubric);
|
|
37348
37943
|
};
|
|
37349
37944
|
render() {
|
|
37945
|
+
const {
|
|
37946
|
+
strings
|
|
37947
|
+
} = this.context;
|
|
37350
37948
|
const divisionRange = this.props.divisionRange;
|
|
37351
37949
|
const divRangeString = divisionRange[0] + EN_DASH + divisionRange[1];
|
|
37352
37950
|
const invalidNumDivisions = this.props.numDivisions < divisionRange[0] || this.props.numDivisions > divisionRange[1];
|
|
37353
37951
|
const inequalityControls = /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("input", {
|
|
37354
37952
|
type: "button",
|
|
37355
37953
|
className: "simple-button",
|
|
37356
|
-
value:
|
|
37954
|
+
value: strings.switchDirection,
|
|
37357
37955
|
onClick: this.handleReverse
|
|
37358
37956
|
}), /*#__PURE__*/React__namespace.createElement("input", {
|
|
37359
37957
|
type: "button",
|
|
37360
37958
|
className: "simple-button",
|
|
37361
|
-
value: ___default["default"](["le", "ge"]).contains(this.props.rel) ?
|
|
37959
|
+
value: ___default["default"](["le", "ge"]).contains(this.props.rel) ? strings.circleOpen : strings.circleFilled,
|
|
37362
37960
|
onClick: this.handleToggleStrict
|
|
37363
37961
|
}));
|
|
37364
37962
|
let tickCtrl;
|
|
@@ -37369,7 +37967,7 @@ class NumberLine extends React__namespace.Component {
|
|
|
37369
37967
|
} else {
|
|
37370
37968
|
Input = NumberInput;
|
|
37371
37969
|
}
|
|
37372
|
-
tickCtrl = /*#__PURE__*/React__namespace.createElement("label", null,
|
|
37970
|
+
tickCtrl = /*#__PURE__*/React__namespace.createElement("label", null, strings.numDivisions, " ", /*#__PURE__*/React__namespace.createElement(Input
|
|
37373
37971
|
// eslint-disable-next-line react/no-string-refs
|
|
37374
37972
|
, {
|
|
37375
37973
|
ref: "tick-ctrl",
|
|
@@ -37386,9 +37984,9 @@ class NumberLine extends React__namespace.Component {
|
|
|
37386
37984
|
className: "perseus-widget " + "perseus-widget-interactive-number-line"
|
|
37387
37985
|
}, tickCtrl, !this.isValid() ? /*#__PURE__*/React__namespace.createElement("div", {
|
|
37388
37986
|
className: "perseus-error"
|
|
37389
|
-
},
|
|
37987
|
+
}, "Invalid number line configuration.") : this.props.isTickCtrl && invalidNumDivisions ? /*#__PURE__*/React__namespace.createElement("div", {
|
|
37390
37988
|
className: "perseus-error"
|
|
37391
|
-
},
|
|
37989
|
+
}, strings.divisions({
|
|
37392
37990
|
divRangeString: divRangeString
|
|
37393
37991
|
})) : this._renderGraphie(), !this.props.static && this.props.isInequality && inequalityControls);
|
|
37394
37992
|
}
|
|
@@ -37520,8 +38118,9 @@ const PropTypePosition = PropTypes__default["default"].shape({
|
|
|
37520
38118
|
top: PropTypes__default["default"].number
|
|
37521
38119
|
});
|
|
37522
38120
|
class Card extends React__namespace.Component {
|
|
38121
|
+
static contextType = PerseusI18nContext;
|
|
37523
38122
|
// @ts-expect-error - TS2564 - Property 'mouseMoveUpBound' has no initializer and is not definitely assigned in the constructor.
|
|
37524
|
-
|
|
38123
|
+
mouseMoveUpBound;
|
|
37525
38124
|
static propTypes = {
|
|
37526
38125
|
floating: PropTypes__default["default"].bool.isRequired,
|
|
37527
38126
|
animating: PropTypes__default["default"].bool,
|
|
@@ -37580,7 +38179,8 @@ class Card extends React__namespace.Component {
|
|
|
37580
38179
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|
|
37581
38180
|
className: className.join(" ")
|
|
37582
38181
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, _extends({}, rendererProps, {
|
|
37583
|
-
linterContext: this.props.linterContext
|
|
38182
|
+
linterContext: this.props.linterContext,
|
|
38183
|
+
strings: this.context.strings
|
|
37584
38184
|
}))));
|
|
37585
38185
|
}
|
|
37586
38186
|
shouldComponentUpdate(nextProps, nextState) {
|
|
@@ -38853,6 +39453,7 @@ const styles$8 = aphrodite.StyleSheet.create({
|
|
|
38853
39453
|
|
|
38854
39454
|
/* eslint-disable react/no-unsafe */
|
|
38855
39455
|
class HighlightSetRenderer extends React__namespace.PureComponent {
|
|
39456
|
+
static contextType = PerseusI18nContext;
|
|
38856
39457
|
state = {
|
|
38857
39458
|
hoveredHighlightKey: null,
|
|
38858
39459
|
hoveringTooltipFor: null
|
|
@@ -38942,7 +39543,7 @@ class HighlightSetRenderer extends React__namespace.PureComponent {
|
|
|
38942
39543
|
}
|
|
38943
39544
|
const hoveredHighlight = this.props.highlights[hoveredHighlightKey];
|
|
38944
39545
|
return /*#__PURE__*/React__namespace.createElement(HighlightTooltip, {
|
|
38945
|
-
label:
|
|
39546
|
+
label: this.context.strings.removeHighlight,
|
|
38946
39547
|
focusNode: hoveredHighlight.domRange.endContainer,
|
|
38947
39548
|
focusOffset: hoveredHighlight.domRange.endOffset,
|
|
38948
39549
|
offsetParent: this.props.offsetParent,
|
|
@@ -39113,6 +39714,7 @@ class SelectionTracker extends React__namespace.PureComponent {
|
|
|
39113
39714
|
* `HighlightingUI`.
|
|
39114
39715
|
*/
|
|
39115
39716
|
class HighlightingUI extends React__namespace.PureComponent {
|
|
39717
|
+
static contextType = PerseusI18nContext;
|
|
39116
39718
|
_handleAddHighlight(highlightToAdd) {
|
|
39117
39719
|
this.props.onAddHighlight(highlightToAdd);
|
|
39118
39720
|
|
|
@@ -39169,7 +39771,7 @@ class HighlightingUI extends React__namespace.PureComponent {
|
|
|
39169
39771
|
onRemoveHighlight: this.props.onRemoveHighlight,
|
|
39170
39772
|
zIndexes: this.props.zIndexes
|
|
39171
39773
|
}), this._selectionIsValid(trackedSelection) && !userIsMouseSelecting && /*#__PURE__*/React__namespace.createElement(HighlightTooltip, {
|
|
39172
|
-
label:
|
|
39774
|
+
label: this.context.strings.addHighlight,
|
|
39173
39775
|
onClick: () => this._handleAddHighlight(trackedSelection.proposedHighlight),
|
|
39174
39776
|
focusNode: trackedSelection.focusNode,
|
|
39175
39777
|
focusOffset: trackedSelection.focusOffset,
|
|
@@ -39192,6 +39794,7 @@ class HighlightingUI extends React__namespace.PureComponent {
|
|
|
39192
39794
|
* them amenable to binary search - see `findBoundaryWordIndex` in ranges.js.
|
|
39193
39795
|
*/
|
|
39194
39796
|
class WordIndexer extends React__namespace.PureComponent {
|
|
39797
|
+
_container;
|
|
39195
39798
|
/* eslint-enable react/sort-comp */
|
|
39196
39799
|
|
|
39197
39800
|
componentDidMount() {
|
|
@@ -39311,7 +39914,8 @@ class WordIndexer extends React__namespace.PureComponent {
|
|
|
39311
39914
|
*/
|
|
39312
39915
|
class HighlightableContent extends React__namespace.PureComponent {
|
|
39313
39916
|
// References to the mounted container and content divs.
|
|
39314
|
-
|
|
39917
|
+
_container;
|
|
39918
|
+
_content;
|
|
39315
39919
|
state = {
|
|
39316
39920
|
wordRanges: []
|
|
39317
39921
|
};
|
|
@@ -39472,7 +40076,7 @@ class RefStart extends React__namespace.Component {
|
|
|
39472
40076
|
render() {
|
|
39473
40077
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
39474
40078
|
style: REF_STYLE
|
|
39475
|
-
},
|
|
40079
|
+
}, "_");
|
|
39476
40080
|
}
|
|
39477
40081
|
|
|
39478
40082
|
// @ts-expect-error - TS2322 - Type '() => React.ReactNode' is not assignable to type '() => ReactElement<any, string | JSXElementConstructor<any>>'.
|
|
@@ -39484,9 +40088,24 @@ class RefEnd extends React__namespace.Component {
|
|
|
39484
40088
|
render() {
|
|
39485
40089
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
39486
40090
|
style: REF_STYLE
|
|
39487
|
-
},
|
|
40091
|
+
}, "_");
|
|
39488
40092
|
}
|
|
39489
40093
|
}
|
|
40094
|
+
const AltText = _ref => {
|
|
40095
|
+
let {
|
|
40096
|
+
id,
|
|
40097
|
+
number
|
|
40098
|
+
} = _ref;
|
|
40099
|
+
const {
|
|
40100
|
+
strings
|
|
40101
|
+
} = usePerseusI18n();
|
|
40102
|
+
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
40103
|
+
key: "alt-text",
|
|
40104
|
+
className: "perseus-sr-only"
|
|
40105
|
+
}, strings[id]({
|
|
40106
|
+
number
|
|
40107
|
+
}));
|
|
40108
|
+
};
|
|
39490
40109
|
const rules = {
|
|
39491
40110
|
newline: SimpleMarkdown__default["default"].defaultRules.newline,
|
|
39492
40111
|
paragraph: SimpleMarkdown__default["default"].defaultRules.paragraph,
|
|
@@ -39655,12 +40274,10 @@ const rules = {
|
|
|
39655
40274
|
"aria-hidden": "true"
|
|
39656
40275
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
39657
40276
|
style: SQUARE_LABEL_STYLE
|
|
39658
|
-
}, node.content)), /*#__PURE__*/React__namespace.createElement(
|
|
39659
|
-
|
|
39660
|
-
className: "perseus-sr-only"
|
|
39661
|
-
}, i18n__namespace.$_("[Marker for question %(number)s]", {
|
|
40277
|
+
}, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
40278
|
+
id: "questionMarker",
|
|
39662
40279
|
number: node.content
|
|
39663
|
-
})
|
|
40280
|
+
}), node.space ? "\u00A0" : null];
|
|
39664
40281
|
}
|
|
39665
40282
|
},
|
|
39666
40283
|
circleLabel: {
|
|
@@ -39681,12 +40298,10 @@ const rules = {
|
|
|
39681
40298
|
"aria-hidden": true
|
|
39682
40299
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
39683
40300
|
style: CIRCLE_LABEL_STYLE
|
|
39684
|
-
}, node.content)), /*#__PURE__*/React__namespace.createElement(
|
|
39685
|
-
|
|
39686
|
-
className: "perseus-sr-only"
|
|
39687
|
-
}, i18n__namespace.$_("[Circle marker %(number)s]", {
|
|
40301
|
+
}, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
40302
|
+
id: "circleMarker",
|
|
39688
40303
|
number: node.content
|
|
39689
|
-
})
|
|
40304
|
+
}), node.space ? "\u00A0" : null];
|
|
39690
40305
|
}
|
|
39691
40306
|
},
|
|
39692
40307
|
squareBracketRef: {
|
|
@@ -39706,12 +40321,10 @@ const rules = {
|
|
|
39706
40321
|
key: "visual-brackets",
|
|
39707
40322
|
className: "perseus-passage-bracket-label",
|
|
39708
40323
|
"aria-hidden": "true"
|
|
39709
|
-
}, "[", node.content, "]"), /*#__PURE__*/React__namespace.createElement(
|
|
39710
|
-
|
|
39711
|
-
className: "perseus-sr-only"
|
|
39712
|
-
}, i18n__namespace.$_("[Sentence %(number)s]", {
|
|
40324
|
+
}, "[", node.content, "]"), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
40325
|
+
id: "sentenceMarker",
|
|
39713
40326
|
number: node.content
|
|
39714
|
-
})
|
|
40327
|
+
}), node.space ? "\u00A0" : null];
|
|
39715
40328
|
}
|
|
39716
40329
|
},
|
|
39717
40330
|
highlight: {
|
|
@@ -39811,6 +40424,7 @@ var PassageMarkdown = {
|
|
|
39811
40424
|
// A fake paragraph to measure the line height of the passage,
|
|
39812
40425
|
// so we can adapt to browser zoom
|
|
39813
40426
|
class LineHeightMeasurer extends React__namespace.Component {
|
|
40427
|
+
_line;
|
|
39814
40428
|
measureLineHeight() {
|
|
39815
40429
|
if (!this._line) {
|
|
39816
40430
|
return 0;
|
|
@@ -39843,10 +40457,13 @@ const styles$6 = aphrodite.StyleSheet.create({
|
|
|
39843
40457
|
// Information about a passage reference, used in inter-widgets.
|
|
39844
40458
|
|
|
39845
40459
|
class Passage extends React__namespace.Component {
|
|
40460
|
+
static contextType = PerseusI18nContext;
|
|
40461
|
+
_contentRef;
|
|
40462
|
+
_lineHeightMeasurerRef;
|
|
39846
40463
|
// @ts-expect-error - TS2564 - Property '_onResize' has no initializer and is not definitely assigned in the constructor.
|
|
39847
|
-
|
|
40464
|
+
_onResize;
|
|
39848
40465
|
// @ts-expect-error - TS2564 - Property '_stylesAppiedTimer' has no initializer and is not definitely assigned in the constructor.
|
|
39849
|
-
|
|
40466
|
+
_stylesAppiedTimer;
|
|
39850
40467
|
static defaultProps = {
|
|
39851
40468
|
passageTitle: "",
|
|
39852
40469
|
passageText: "",
|
|
@@ -40101,15 +40718,18 @@ class Passage extends React__namespace.Component {
|
|
|
40101
40718
|
_renderInstructions(parseState) {
|
|
40102
40719
|
const firstQuestionNumber = parseState.firstQuestionRef;
|
|
40103
40720
|
const firstSentenceRef = parseState.firstSentenceRef;
|
|
40721
|
+
const {
|
|
40722
|
+
strings
|
|
40723
|
+
} = this.context;
|
|
40104
40724
|
let instructions = "";
|
|
40105
40725
|
if (firstQuestionNumber) {
|
|
40106
|
-
instructions +=
|
|
40726
|
+
instructions += strings.symbolPassage({
|
|
40107
40727
|
questionSymbol: "[[" + firstQuestionNumber + "]]",
|
|
40108
40728
|
questionNumber: firstQuestionNumber
|
|
40109
40729
|
});
|
|
40110
40730
|
}
|
|
40111
40731
|
if (firstSentenceRef) {
|
|
40112
|
-
instructions +=
|
|
40732
|
+
instructions += strings.symbolQuestion({
|
|
40113
40733
|
sentenceSymbol: "[" + firstSentenceRef + "]"
|
|
40114
40734
|
});
|
|
40115
40735
|
}
|
|
@@ -40155,6 +40775,9 @@ class Passage extends React__namespace.Component {
|
|
|
40155
40775
|
return PassageMarkdown.output(parsed);
|
|
40156
40776
|
}
|
|
40157
40777
|
render() {
|
|
40778
|
+
const {
|
|
40779
|
+
strings
|
|
40780
|
+
} = this.context;
|
|
40158
40781
|
let lineNumbers;
|
|
40159
40782
|
const nLines = this.state.nLines;
|
|
40160
40783
|
if (this.props.showLineNumbers && nLines) {
|
|
@@ -40163,9 +40786,7 @@ class Passage extends React__namespace.Component {
|
|
|
40163
40786
|
lineNumbers = ___default["default"].range(1, nLines + 1).map(lineN => {
|
|
40164
40787
|
const lineAt = lineN + this.state.startLineNumbersAfter;
|
|
40165
40788
|
if (lineAt === 4) {
|
|
40166
|
-
|
|
40167
|
-
// I18N: a label next to a reading passage to denote the line number
|
|
40168
|
-
const translatedLine = i18n__namespace._("Line ");
|
|
40789
|
+
const translatedLine = strings.lineLabel;
|
|
40169
40790
|
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
40170
40791
|
key: "line-marker",
|
|
40171
40792
|
className: "line-marker"
|
|
@@ -40195,13 +40816,14 @@ class Passage extends React__namespace.Component {
|
|
|
40195
40816
|
className: "passage-title"
|
|
40196
40817
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
40197
40818
|
content: this.props.passageTitle,
|
|
40198
|
-
linterContext: this.props.linterContext
|
|
40819
|
+
linterContext: this.props.linterContext,
|
|
40820
|
+
strings: strings
|
|
40199
40821
|
})), lineNumbers && /*#__PURE__*/React__namespace.createElement("div", {
|
|
40200
40822
|
className: "line-numbers",
|
|
40201
40823
|
"aria-hidden": true
|
|
40202
40824
|
}, lineNumbers), !hasTitle && /*#__PURE__*/React__namespace.createElement("h3", {
|
|
40203
40825
|
className: "perseus-sr-only"
|
|
40204
|
-
},
|
|
40826
|
+
}, strings.beginningPassage), /*#__PURE__*/React__namespace.createElement("div", {
|
|
40205
40827
|
className: "passage-text"
|
|
40206
40828
|
}, this.shouldRenderJipt() ?
|
|
40207
40829
|
/*#__PURE__*/
|
|
@@ -40209,16 +40831,17 @@ class Passage extends React__namespace.Component {
|
|
|
40209
40831
|
// content to a <Renderer /> which knows how
|
|
40210
40832
|
// to handle rendering JIPT text.
|
|
40211
40833
|
React__namespace.createElement(Renderer, {
|
|
40212
|
-
content: this.props.passageText
|
|
40834
|
+
content: this.props.passageText,
|
|
40835
|
+
strings: strings
|
|
40213
40836
|
}) : this._renderContent(parsedContent)), this._hasFootnotes() && [/*#__PURE__*/React__namespace.createElement("h4", {
|
|
40214
40837
|
key: "footnote-start",
|
|
40215
40838
|
className: "perseus-sr-only"
|
|
40216
|
-
},
|
|
40839
|
+
}, strings.beginningFootnotes), /*#__PURE__*/React__namespace.createElement("div", {
|
|
40217
40840
|
key: "footnotes",
|
|
40218
40841
|
className: "footnotes"
|
|
40219
40842
|
}, this._renderFootnotes())], /*#__PURE__*/React__namespace.createElement("div", {
|
|
40220
40843
|
className: "perseus-sr-only"
|
|
40221
|
-
},
|
|
40844
|
+
}, strings.endPassage))));
|
|
40222
40845
|
}
|
|
40223
40846
|
}
|
|
40224
40847
|
var Passage$1 = {
|
|
@@ -40233,6 +40856,7 @@ var Passage$1 = {
|
|
|
40233
40856
|
|
|
40234
40857
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
40235
40858
|
class PassageRefTarget extends React__namespace.Component {
|
|
40859
|
+
static contextType = PerseusI18nContext;
|
|
40236
40860
|
static defaultProps = {
|
|
40237
40861
|
content: "",
|
|
40238
40862
|
linterContext: PerseusLinter.linterContextDefault
|
|
@@ -40270,7 +40894,8 @@ class PassageRefTarget extends React__namespace.Component {
|
|
|
40270
40894
|
// inline={true}
|
|
40271
40895
|
,
|
|
40272
40896
|
apiOptions: this.props.apiOptions,
|
|
40273
|
-
linterContext: this.props.linterContext
|
|
40897
|
+
linterContext: this.props.linterContext,
|
|
40898
|
+
strings: this.context.strings
|
|
40274
40899
|
});
|
|
40275
40900
|
}
|
|
40276
40901
|
}
|
|
@@ -40295,9 +40920,13 @@ const {
|
|
|
40295
40920
|
deepEq
|
|
40296
40921
|
} = Util;
|
|
40297
40922
|
class Plotter extends React__namespace.Component {
|
|
40923
|
+
static contextType = PerseusI18nContext;
|
|
40298
40924
|
// @ts-expect-error - TS2564 - Property 'shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
40299
|
-
|
|
40925
|
+
shouldSetupGraphie;
|
|
40300
40926
|
_isMounted = false;
|
|
40927
|
+
horizHairline;
|
|
40928
|
+
hairlineRange;
|
|
40929
|
+
graphie;
|
|
40301
40930
|
static defaultProps = {
|
|
40302
40931
|
type: "bar",
|
|
40303
40932
|
labels: ["", ""],
|
|
@@ -40484,11 +41113,11 @@ class Plotter extends React__namespace.Component {
|
|
|
40484
41113
|
}
|
|
40485
41114
|
}
|
|
40486
41115
|
if ((isBar || isLine) && isMobile && !this.props.static) {
|
|
40487
|
-
self.graphie.dragPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
41116
|
+
self.graphie.dragPrompt = graphie.label([c.dimX / 2, c.dimY / 2], this.context.strings.dragHandles, "center", false).css("font-weight", "bold").css("color", KhanColors.KA_GREEN).css("display", "none");
|
|
40488
41117
|
}
|
|
40489
41118
|
self.setupCategories(config);
|
|
40490
41119
|
if (isTiledPlot && isMobile) {
|
|
40491
|
-
self.graphie.dotPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
41120
|
+
self.graphie.dotPrompt = graphie.label([c.dimX / 2, c.dimY / 2], this.context.strings.tapAddPoints, "center", false).css("font-weight", "bold").css("color", KhanColors.KA_GREEN).css("display", "none");
|
|
40492
41121
|
}
|
|
40493
41122
|
if (isTiledPlot) {
|
|
40494
41123
|
self.drawPicHeights(self.state.values, prevState.values);
|
|
@@ -41163,7 +41792,7 @@ const HORIZONTAL = "horizontal";
|
|
|
41163
41792
|
const VERTICAL = "vertical";
|
|
41164
41793
|
class Sorter extends React__namespace.Component {
|
|
41165
41794
|
// @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
|
|
41166
|
-
|
|
41795
|
+
_isMounted;
|
|
41167
41796
|
static propTypes = {
|
|
41168
41797
|
apiOptions: ApiOptions.propTypes,
|
|
41169
41798
|
// eslint-disable-next-line react/forbid-prop-types
|
|
@@ -41306,6 +41935,7 @@ const getRefForPath = function (path) {
|
|
|
41306
41935
|
return "answer" + row + "," + column;
|
|
41307
41936
|
};
|
|
41308
41937
|
class Table extends React__namespace.Component {
|
|
41938
|
+
static contextType = PerseusI18nContext;
|
|
41309
41939
|
static propTypes = {
|
|
41310
41940
|
answers: PropTypes__default["default"].arrayOf(PropTypes__default["default"].arrayOf(PropTypes__default["default"].string)),
|
|
41311
41941
|
editableHeaders: PropTypes__default["default"].bool,
|
|
@@ -41375,7 +42005,8 @@ class Table extends React__namespace.Component {
|
|
|
41375
42005
|
key: i
|
|
41376
42006
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
41377
42007
|
content: header,
|
|
41378
|
-
linterContext: this.props.linterContext
|
|
42008
|
+
linterContext: this.props.linterContext,
|
|
42009
|
+
strings: this.context.strings
|
|
41379
42010
|
}));
|
|
41380
42011
|
}))), /*#__PURE__*/React__namespace.createElement("tbody", null, ___default["default"](rows).times(r => {
|
|
41381
42012
|
return /*#__PURE__*/React__namespace.createElement("tr", {
|
|
@@ -41420,7 +42051,7 @@ class Table extends React__namespace.Component {
|
|
|
41420
42051
|
};
|
|
41421
42052
|
simpleValidate = rubric => {
|
|
41422
42053
|
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Table'.
|
|
41423
|
-
return Table.validate(this.getUserInput(), rubric);
|
|
42054
|
+
return Table.validate(this.getUserInput(), rubric, this.context.strings);
|
|
41424
42055
|
};
|
|
41425
42056
|
_handleFocus = inputPath => {
|
|
41426
42057
|
this.props.onFocus(inputPath);
|
|
@@ -41489,7 +42120,7 @@ class Table extends React__namespace.Component {
|
|
|
41489
42120
|
};
|
|
41490
42121
|
}
|
|
41491
42122
|
___default["default"].extend(Table, {
|
|
41492
|
-
validate: function (state, rubric) {
|
|
42123
|
+
validate: function (state, rubric, strings) {
|
|
41493
42124
|
const filterNonEmpty = function (table) {
|
|
41494
42125
|
return ___default["default"].filter(table, function (row) {
|
|
41495
42126
|
// Check if row has a cell that is nonempty
|
|
@@ -41527,7 +42158,7 @@ ___default["default"].extend(Table, {
|
|
|
41527
42158
|
const cellSolution = rowSolution[i];
|
|
41528
42159
|
const validator = createValidator(cellSolution, {
|
|
41529
42160
|
simplify: true
|
|
41530
|
-
});
|
|
42161
|
+
}, strings);
|
|
41531
42162
|
const result = validator(cellSupplied);
|
|
41532
42163
|
if (result.message) {
|
|
41533
42164
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
@@ -41814,6 +42445,11 @@ const str = {
|
|
|
41814
42445
|
* @param s A string representation of a floating point.
|
|
41815
42446
|
*/
|
|
41816
42447
|
class SignificantFigures {
|
|
42448
|
+
order;
|
|
42449
|
+
mantissa;
|
|
42450
|
+
positive;
|
|
42451
|
+
sigFigs;
|
|
42452
|
+
sigDecs;
|
|
41817
42453
|
constructor(s) {
|
|
41818
42454
|
this.order = parseOrder(s);
|
|
41819
42455
|
this.mantissa = parseMantissa(s);
|
|
@@ -42222,17 +42858,19 @@ const countSigfigs = function (value) {
|
|
|
42222
42858
|
* rolling two second delay, but hidden immediately on further typing.
|
|
42223
42859
|
*/
|
|
42224
42860
|
class OldUnitInput extends React__namespace.Component {
|
|
42861
|
+
static contextType = PerseusI18nContext;
|
|
42862
|
+
_errorTimeout;
|
|
42225
42863
|
static defaultProps = {
|
|
42226
42864
|
apiOptions: ApiOptions.defaults,
|
|
42227
42865
|
value: ""
|
|
42228
42866
|
};
|
|
42229
|
-
static validate(userInput, rubric) {
|
|
42867
|
+
static validate(userInput, rubric, strings) {
|
|
42230
42868
|
const answer = KAS__namespace.unitParse(rubric.value).expr;
|
|
42231
42869
|
const guess = KAS__namespace.unitParse(userInput);
|
|
42232
42870
|
if (!guess.parsed) {
|
|
42233
42871
|
return {
|
|
42234
42872
|
type: "invalid",
|
|
42235
|
-
message:
|
|
42873
|
+
message: strings.dontUnderstandUnits
|
|
42236
42874
|
};
|
|
42237
42875
|
}
|
|
42238
42876
|
|
|
@@ -42247,8 +42885,7 @@ class OldUnitInput extends React__namespace.Component {
|
|
|
42247
42885
|
const sigfigs = rubric.sigfigs;
|
|
42248
42886
|
const sigfigsCorrect = countSigfigs(guess.coefficient) === sigfigs;
|
|
42249
42887
|
if (!sigfigsCorrect) {
|
|
42250
|
-
|
|
42251
|
-
message = i18n__namespace._("Check your significant figures.");
|
|
42888
|
+
message = strings.checkSigFigs;
|
|
42252
42889
|
}
|
|
42253
42890
|
|
|
42254
42891
|
// now we need to check that the answer is correct to the precision we
|
|
@@ -42267,8 +42904,7 @@ class OldUnitInput extends React__namespace.Component {
|
|
|
42267
42904
|
numericallyCorrect = false;
|
|
42268
42905
|
}
|
|
42269
42906
|
if (!numericallyCorrect) {
|
|
42270
|
-
|
|
42271
|
-
message = i18n__namespace._("That answer is numerically incorrect.");
|
|
42907
|
+
message = strings.answerNumericallyIncorrect;
|
|
42272
42908
|
}
|
|
42273
42909
|
let kasCorrect;
|
|
42274
42910
|
const guessUnit = primUnits(guess.expr.simplify());
|
|
@@ -42288,8 +42924,7 @@ class OldUnitInput extends React__namespace.Component {
|
|
|
42288
42924
|
});
|
|
42289
42925
|
}
|
|
42290
42926
|
if (!kasCorrect) {
|
|
42291
|
-
|
|
42292
|
-
message = i18n__namespace._("Check your units.");
|
|
42927
|
+
message = strings.checkUnits;
|
|
42293
42928
|
}
|
|
42294
42929
|
const correct = kasCorrect && numericallyCorrect && sigfigsCorrect;
|
|
42295
42930
|
return {
|
|
@@ -42385,7 +43020,7 @@ class OldUnitInput extends React__namespace.Component {
|
|
|
42385
43020
|
});
|
|
42386
43021
|
};
|
|
42387
43022
|
simpleValidate = (rubric, onInputError) => {
|
|
42388
|
-
return OldUnitInput.validate(this.getUserInput(), rubric);
|
|
43023
|
+
return OldUnitInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
42389
43024
|
};
|
|
42390
43025
|
getUserInput = () => {
|
|
42391
43026
|
return this.props.value;
|
|
@@ -42460,7 +43095,7 @@ class OldUnitInput extends React__namespace.Component {
|
|
|
42460
43095
|
style: {
|
|
42461
43096
|
display: "none"
|
|
42462
43097
|
}
|
|
42463
|
-
},
|
|
43098
|
+
}, this.context.strings.dontUnderstand));
|
|
42464
43099
|
}
|
|
42465
43100
|
}
|
|
42466
43101
|
|
|
@@ -42512,9 +43147,12 @@ const VideoTranscriptLink = props => {
|
|
|
42512
43147
|
// which is used by our GraphQL framework.
|
|
42513
43148
|
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'VideoKind'.
|
|
42514
43149
|
const result = useVideo(id, kind);
|
|
43150
|
+
const {
|
|
43151
|
+
strings
|
|
43152
|
+
} = usePerseusI18n();
|
|
42515
43153
|
switch (result.status) {
|
|
42516
43154
|
case "loading":
|
|
42517
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null,
|
|
43155
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.loading);
|
|
42518
43156
|
case "success":
|
|
42519
43157
|
{
|
|
42520
43158
|
const video = result.data?.video;
|
|
@@ -42526,14 +43164,14 @@ const VideoTranscriptLink = props => {
|
|
|
42526
43164
|
href: "/transcript/" + (video?.contentId || "videoNotFound"),
|
|
42527
43165
|
target: "_blank",
|
|
42528
43166
|
className: "visited-no-recolor"
|
|
42529
|
-
},
|
|
43167
|
+
}, strings.videoTranscript));
|
|
42530
43168
|
}
|
|
42531
43169
|
case "error":
|
|
42532
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null,
|
|
43170
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.somethingWrong);
|
|
42533
43171
|
case "aborted":
|
|
42534
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null,
|
|
43172
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.somethingWrong);
|
|
42535
43173
|
default:
|
|
42536
|
-
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null,
|
|
43174
|
+
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, strings.somethingWrong);
|
|
42537
43175
|
}
|
|
42538
43176
|
};
|
|
42539
43177
|
const styles$4 = aphrodite.StyleSheet.create({
|
|
@@ -42561,6 +43199,7 @@ const IS_VIMEO = /(vimeo\.com)/;
|
|
|
42561
43199
|
* Video renderer.
|
|
42562
43200
|
*/
|
|
42563
43201
|
class Video extends React__namespace.Component {
|
|
43202
|
+
static contextType = PerseusI18nContext;
|
|
42564
43203
|
/**
|
|
42565
43204
|
* This is the widget's grading function.
|
|
42566
43205
|
* Points for videos are tallied by the embedded video itself, in the case
|
|
@@ -42628,7 +43267,7 @@ class Video extends React__namespace.Component {
|
|
|
42628
43267
|
key: location + this.props.alignment
|
|
42629
43268
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
42630
43269
|
style: a11y.srOnly
|
|
42631
|
-
},
|
|
43270
|
+
}, this.context.strings.videoWrapper), /*#__PURE__*/React__namespace.createElement("iframe", {
|
|
42632
43271
|
// TODO(joshuan): Consider not using iframes when we're
|
|
42633
43272
|
// loading this from webapp. This iframe is problematic
|
|
42634
43273
|
// for screenreaders.
|
|
@@ -42692,7 +43331,7 @@ const init = function (options) {
|
|
|
42692
43331
|
|
|
42693
43332
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42694
43333
|
const libName = "@khanacademy/perseus";
|
|
42695
|
-
const libVersion = "
|
|
43334
|
+
const libVersion = "22.0.0";
|
|
42696
43335
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42697
43336
|
|
|
42698
43337
|
const apiVersion = {
|
|
@@ -42711,6 +43350,8 @@ const ItemVersion = getVersionVector();
|
|
|
42711
43350
|
ItemVersion["::renderer::"] = itemDataVersion;
|
|
42712
43351
|
|
|
42713
43352
|
class ArticleRenderer extends React__namespace.Component {
|
|
43353
|
+
static contextType = PerseusI18nContext;
|
|
43354
|
+
_currentFocus;
|
|
42714
43355
|
sectionRenderers = [];
|
|
42715
43356
|
static defaultProps = {
|
|
42716
43357
|
apiOptions: ApiOptions.defaults,
|
|
@@ -42866,8 +43507,9 @@ class ArticleRenderer extends React__namespace.Component {
|
|
|
42866
43507
|
}
|
|
42867
43508
|
},
|
|
42868
43509
|
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "article"),
|
|
42869
|
-
legacyPerseusLint: this.props.legacyPerseusLint
|
|
42870
|
-
|
|
43510
|
+
legacyPerseusLint: this.props.legacyPerseusLint,
|
|
43511
|
+
strings: this.context.strings
|
|
43512
|
+
})));
|
|
42871
43513
|
});
|
|
42872
43514
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
42873
43515
|
className: classes
|
|
@@ -42879,6 +43521,7 @@ class ArticleRenderer extends React__namespace.Component {
|
|
|
42879
43521
|
|
|
42880
43522
|
/* Renders just a hint preview */
|
|
42881
43523
|
class HintRenderer extends React__namespace.Component {
|
|
43524
|
+
static contextType = PerseusI18nContext;
|
|
42882
43525
|
static defaultProps = {
|
|
42883
43526
|
linterContext: PerseusLinter__namespace.linterContextDefault
|
|
42884
43527
|
};
|
|
@@ -42924,7 +43567,7 @@ class HintRenderer extends React__namespace.Component {
|
|
|
42924
43567
|
tabIndex: "-1"
|
|
42925
43568
|
}, !apiOptions.isMobile && /*#__PURE__*/React__namespace.createElement("span", {
|
|
42926
43569
|
className: "perseus-sr-only"
|
|
42927
|
-
},
|
|
43570
|
+
}, this.context.strings.hintPos({
|
|
42928
43571
|
pos: pos + 1
|
|
42929
43572
|
})), !apiOptions.isMobile && totalHints != null && pos != null && /*#__PURE__*/React__namespace.createElement("span", {
|
|
42930
43573
|
className: "perseus-hint-label",
|
|
@@ -42941,7 +43584,8 @@ class HintRenderer extends React__namespace.Component {
|
|
|
42941
43584
|
images: hint.images,
|
|
42942
43585
|
apiOptions: rendererApiOptions,
|
|
42943
43586
|
findExternalWidgets: this.props.findExternalWidgets,
|
|
42944
|
-
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "hint")
|
|
43587
|
+
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "hint"),
|
|
43588
|
+
strings: this.context.strings
|
|
42945
43589
|
}))
|
|
42946
43590
|
);
|
|
42947
43591
|
}
|
|
@@ -42976,6 +43620,7 @@ const styles$3 = aphrodite.StyleSheet.create({
|
|
|
42976
43620
|
// Use of UNSAFE_componentWillReceiveProps:
|
|
42977
43621
|
// eslint-disable-next-line react/no-unsafe
|
|
42978
43622
|
class HintsRenderer extends React__namespace.Component {
|
|
43623
|
+
static contextType = PerseusI18nContext;
|
|
42979
43624
|
static defaultProps = {
|
|
42980
43625
|
linterContext: PerseusLinter__namespace.linterContextDefault
|
|
42981
43626
|
};
|
|
@@ -43128,7 +43773,7 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
43128
43773
|
className: classNames
|
|
43129
43774
|
}, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React__namespace.createElement("div", {
|
|
43130
43775
|
className: aphrodite.css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
|
|
43131
|
-
},
|
|
43776
|
+
}, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React__namespace.createElement("button", {
|
|
43132
43777
|
// @ts-expect-error - TS2322 - Type '{ children: Element[]; rel: string; className: string; onClick: (evt: MouseEvent<HTMLButtonElement, MouseEvent>) => void; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
|
|
43133
43778
|
rel: "button",
|
|
43134
43779
|
className: aphrodite.css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
|
|
@@ -43143,7 +43788,7 @@ class HintsRenderer extends React__namespace.Component {
|
|
|
43143
43788
|
className: aphrodite.css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
|
|
43144
43789
|
}, "+"), /*#__PURE__*/React__namespace.createElement("span", {
|
|
43145
43790
|
className: aphrodite.css(styles$2.getAnotherHintText)
|
|
43146
|
-
},
|
|
43791
|
+
}, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
|
|
43147
43792
|
}
|
|
43148
43793
|
}
|
|
43149
43794
|
const hintIndentation = baseUnitPx + hintBorderWidth;
|
|
@@ -43246,8 +43891,13 @@ const {
|
|
|
43246
43891
|
} = objective_;
|
|
43247
43892
|
/* eslint-disable-next-line react/no-unsafe */
|
|
43248
43893
|
class ServerItemRenderer extends React__namespace.Component {
|
|
43894
|
+
static contextType = PerseusI18nContext;
|
|
43249
43895
|
// @ts-expect-error - TS2564 - Property 'questionRenderer' has no initializer and is not definitely assigned in the constructor.
|
|
43250
|
-
|
|
43896
|
+
questionRenderer;
|
|
43897
|
+
hintsRenderer;
|
|
43898
|
+
_currentFocus;
|
|
43899
|
+
_fullyRendered;
|
|
43900
|
+
blurTimeoutID;
|
|
43251
43901
|
static defaultProps = {
|
|
43252
43902
|
apiOptions: {},
|
|
43253
43903
|
// a deep default is done in `this.update()`
|
|
@@ -43539,14 +44189,16 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
43539
44189
|
content: this.props.item.question.content,
|
|
43540
44190
|
widgets: this.props.item.question.widgets,
|
|
43541
44191
|
images: this.props.item.question.images,
|
|
43542
|
-
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "question")
|
|
44192
|
+
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "question"),
|
|
44193
|
+
strings: this.context.strings
|
|
43543
44194
|
}, this.props.dependencies)));
|
|
43544
44195
|
const hintsRenderer = /*#__PURE__*/React__namespace.createElement(HintsRenderer, {
|
|
43545
44196
|
hints: this.props.item.hints,
|
|
43546
44197
|
hintsVisible: this.props.hintsVisible,
|
|
43547
44198
|
apiOptions: apiOptions,
|
|
43548
44199
|
ref: elem => this.hintsRenderer = elem,
|
|
43549
|
-
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "hints")
|
|
44200
|
+
linterContext: PerseusLinter__namespace.pushContextStack(this.props.linterContext, "hints"),
|
|
44201
|
+
strings: this.context.strings
|
|
43550
44202
|
});
|
|
43551
44203
|
return /*#__PURE__*/React__namespace.createElement(DependenciesContext.Provider, {
|
|
43552
44204
|
value: this.props.dependencies
|
|
@@ -43719,115 +44371,6 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
43719
44371
|
perseusFrameBorderWidth: perseusFrameBorderWidth
|
|
43720
44372
|
});
|
|
43721
44373
|
|
|
43722
|
-
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
43723
|
-
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
43724
|
-
|
|
43725
|
-
// Range is replaced within this file with Interval, but it is used elsewhere
|
|
43726
|
-
// and exported from the package, so we need to keep it around.
|
|
43727
|
-
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
43728
|
-
const ItemExtras = [
|
|
43729
|
-
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
43730
|
-
"calculator",
|
|
43731
|
-
// The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
|
|
43732
|
-
"chi2Table",
|
|
43733
|
-
// The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
|
|
43734
|
-
"financialCalculatorMonthlyPayment",
|
|
43735
|
-
// The user might benefit from a total amount calculator. Provided on Khan Academy when true
|
|
43736
|
-
"financialCalculatorTotalAmount",
|
|
43737
|
-
// The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
|
|
43738
|
-
"financialCalculatorTimeToPayOff",
|
|
43739
|
-
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
43740
|
-
"periodicTable",
|
|
43741
|
-
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
43742
|
-
"periodicTableWithKey",
|
|
43743
|
-
// The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
|
|
43744
|
-
"tTable",
|
|
43745
|
-
// The user might benefit from using a statistics Z Table like https://www.ztable.net/
|
|
43746
|
-
"zTable"];
|
|
43747
|
-
|
|
43748
|
-
// prettier-ignore
|
|
43749
|
-
|
|
43750
|
-
// prettier-ignore
|
|
43751
|
-
|
|
43752
|
-
// prettier-ignore
|
|
43753
|
-
|
|
43754
|
-
// prettier-ignore
|
|
43755
|
-
|
|
43756
|
-
// prettier-ignore
|
|
43757
|
-
|
|
43758
|
-
// prettier-ignore
|
|
43759
|
-
|
|
43760
|
-
// prettier-ignore
|
|
43761
|
-
|
|
43762
|
-
// prettier-ignore
|
|
43763
|
-
|
|
43764
|
-
// prettier-ignore
|
|
43765
|
-
|
|
43766
|
-
// prettier-ignore
|
|
43767
|
-
|
|
43768
|
-
// prettier-ignore
|
|
43769
|
-
|
|
43770
|
-
// prettier-ignore
|
|
43771
|
-
|
|
43772
|
-
// prettier-ignore
|
|
43773
|
-
|
|
43774
|
-
// prettier-ignore
|
|
43775
|
-
|
|
43776
|
-
// prettier-ignore
|
|
43777
|
-
|
|
43778
|
-
// prettier-ignore
|
|
43779
|
-
|
|
43780
|
-
// prettier-ignore
|
|
43781
|
-
|
|
43782
|
-
// prettier-ignore
|
|
43783
|
-
|
|
43784
|
-
// prettier-ignore
|
|
43785
|
-
|
|
43786
|
-
// prettier-ignore
|
|
43787
|
-
|
|
43788
|
-
// prettier-ignore
|
|
43789
|
-
|
|
43790
|
-
// prettier-ignore
|
|
43791
|
-
|
|
43792
|
-
// prettier-ignore
|
|
43793
|
-
|
|
43794
|
-
// prettier-ignore
|
|
43795
|
-
|
|
43796
|
-
// prettier-ignore
|
|
43797
|
-
|
|
43798
|
-
// prettier-ignore
|
|
43799
|
-
|
|
43800
|
-
// prettier-ignore
|
|
43801
|
-
|
|
43802
|
-
// prettier-ignore
|
|
43803
|
-
|
|
43804
|
-
// prettier-ignore
|
|
43805
|
-
|
|
43806
|
-
// prettier-ignore
|
|
43807
|
-
|
|
43808
|
-
// prettier-ignore
|
|
43809
|
-
|
|
43810
|
-
// prettier-ignore
|
|
43811
|
-
|
|
43812
|
-
// prettier-ignore
|
|
43813
|
-
|
|
43814
|
-
// prettier-ignore
|
|
43815
|
-
|
|
43816
|
-
// prettier-ignore
|
|
43817
|
-
|
|
43818
|
-
// prettier-ignore
|
|
43819
|
-
|
|
43820
|
-
//prettier-ignore
|
|
43821
|
-
|
|
43822
|
-
// A background image applied to various widgets.
|
|
43823
|
-
|
|
43824
|
-
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
43825
|
-
|
|
43826
|
-
// 2D range: xMin, xMax, yMin, yMax
|
|
43827
|
-
|
|
43828
|
-
const lockedFigureColors = ["purple", "blue", "teal", "green", "gold", "red", "pink"];
|
|
43829
|
-
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
43830
|
-
|
|
43831
44374
|
/**
|
|
43832
44375
|
* Traverses a {content, widgets, images} renderer props object,
|
|
43833
44376
|
* such as `itemData.question`
|
|
@@ -44068,6 +44611,10 @@ var shapes = {
|
|
|
44068
44611
|
* TreeMapperForLeavesAndCollections.
|
|
44069
44612
|
*/
|
|
44070
44613
|
class TreeMapperJustForLeaves {
|
|
44614
|
+
content;
|
|
44615
|
+
hint;
|
|
44616
|
+
tags;
|
|
44617
|
+
array;
|
|
44071
44618
|
constructor(content, hint, tags) {
|
|
44072
44619
|
this.content = content;
|
|
44073
44620
|
this.hint = hint;
|
|
@@ -44098,6 +44645,10 @@ class TreeMapperJustForLeaves {
|
|
|
44098
44645
|
* ContentMapper and HintMapper are now locked in.
|
|
44099
44646
|
*/
|
|
44100
44647
|
class TreeMapperForLeavesAndCollections {
|
|
44648
|
+
content;
|
|
44649
|
+
hint;
|
|
44650
|
+
tags;
|
|
44651
|
+
array;
|
|
44101
44652
|
constructor(content, hint, tags, array) {
|
|
44102
44653
|
this.content = content;
|
|
44103
44654
|
this.hint = hint;
|
|
@@ -44356,6 +44907,9 @@ function treeToItem(node) {
|
|
|
44356
44907
|
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
44357
44908
|
// @ts-expect-error - TS2315 - Type 'Tree' is not generic.
|
|
44358
44909
|
class MultiRenderer extends React__namespace.Component {
|
|
44910
|
+
static contextType = PerseusI18nContext;
|
|
44911
|
+
rendererDataTreeMapper;
|
|
44912
|
+
getRenderersMapper;
|
|
44359
44913
|
constructor(props) {
|
|
44360
44914
|
super(props);
|
|
44361
44915
|
this.rendererDataTreeMapper = buildMapper()
|
|
@@ -44430,7 +44984,10 @@ class MultiRenderer extends React__namespace.Component {
|
|
|
44430
44984
|
onSerializedStateUpdated: _____,
|
|
44431
44985
|
...otherProps
|
|
44432
44986
|
} = this.props;
|
|
44433
|
-
return
|
|
44987
|
+
return {
|
|
44988
|
+
...otherProps,
|
|
44989
|
+
strings: this.context.strings
|
|
44990
|
+
};
|
|
44434
44991
|
}
|
|
44435
44992
|
|
|
44436
44993
|
/**
|
|
@@ -44679,7 +45236,7 @@ class MultiRenderer extends React__namespace.Component {
|
|
|
44679
45236
|
if (this.state.renderError) {
|
|
44680
45237
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
44681
45238
|
className: aphrodite.css(styles.error)
|
|
44682
|
-
},
|
|
45239
|
+
}, this.context.strings.errorRendering({
|
|
44683
45240
|
error: String(this.state.renderError)
|
|
44684
45241
|
}));
|
|
44685
45242
|
}
|
|
@@ -45821,6 +46378,8 @@ exports.MultiItems = MultiItems;
|
|
|
45821
46378
|
exports.NumericInput = NumericInput$1;
|
|
45822
46379
|
exports.PerseusError = PerseusError;
|
|
45823
46380
|
exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
|
|
46381
|
+
exports.PerseusI18nContext = PerseusI18nContext;
|
|
46382
|
+
exports.PerseusI18nContextProvider = PerseusI18nContextProvider;
|
|
45824
46383
|
exports.PerseusMarkdown = PerseusMarkdown;
|
|
45825
46384
|
exports.PlotterWidget = Plotter$1;
|
|
45826
46385
|
exports.QUESTION_WIDGETS = QUESTION_WIDGETS;
|
|
@@ -45881,6 +46440,7 @@ exports.registerAllWidgetsForTesting = registerAllWidgetsForTesting;
|
|
|
45881
46440
|
exports.shapes = shapes;
|
|
45882
46441
|
exports.shouldHaveIndividualAnswer = shouldHaveIndividualAnswer;
|
|
45883
46442
|
exports.traverse = traverse;
|
|
46443
|
+
exports.usePerseusI18n = usePerseusI18n;
|
|
45884
46444
|
exports.violatingWidgets = violatingWidgets;
|
|
45885
46445
|
exports.widgets = allWidgets;
|
|
45886
46446
|
//# sourceMappingURL=index.js.map
|