@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/es/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import * as KAS from '@khanacademy/kas';
|
|
2
|
-
import {
|
|
2
|
+
import { MathInputI18nContext, CursorContext, getKeyTranslator, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
|
|
3
3
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
4
4
|
import { linterContextDefault, Rule, linterContextProps } from '@khanacademy/perseus-linter';
|
|
5
5
|
import { View, RenderStateRoot, useUniqueIdWithMock, UniqueIDProvider, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
|
-
import * as i18n from '@khanacademy/wonder-blocks-i18n';
|
|
7
6
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
8
7
|
import classNames from 'classnames';
|
|
9
8
|
import * as React from 'react';
|
|
10
|
-
import React__default, { useState, useEffect, useRef, createContext, useImperativeHandle } from 'react';
|
|
9
|
+
import React__default, { useContext, useState, useEffect, useRef, createContext, useImperativeHandle } from 'react';
|
|
11
10
|
import _, { debounce as debounce$1 } from 'underscore';
|
|
12
11
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
13
12
|
import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
|
|
@@ -69,6 +68,211 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
69
68
|
return target;
|
|
70
69
|
}
|
|
71
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The translated strings that are used to render Perseus.
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Mock strings for the Perseus package, to be used for tests and Storybook.
|
|
77
|
+
*/
|
|
78
|
+
const mockStrings = {
|
|
79
|
+
closeKeypad: "close math keypad",
|
|
80
|
+
openKeypad: "open math keypad",
|
|
81
|
+
removeHighlight: "Remove highlight",
|
|
82
|
+
addHighlight: "Add highlight",
|
|
83
|
+
hintPos: ({
|
|
84
|
+
pos
|
|
85
|
+
}) => `Hint #${pos}`,
|
|
86
|
+
errorRendering: ({
|
|
87
|
+
error
|
|
88
|
+
}) => `Error rendering: ${error}`,
|
|
89
|
+
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>",
|
|
90
|
+
EXTRA_SYMBOLS_ERROR: "We could not understand your " + "answer. Please check your answer for extra " + "text or symbols.",
|
|
91
|
+
NEEDS_TO_BE_SIMPLFIED_ERROR: "Your answer is almost correct, " + "but it needs to be simplified.",
|
|
92
|
+
MISSING_PERCENT_ERROR: "Your answer is almost correct, " + "but it is missing a " + "<code>\\%</code> at the end.",
|
|
93
|
+
MULTIPLICATION_SIGN_ERROR: "I'm a computer. I only understand " + "multiplication if you use an asterisk " + "(*) as the multiplication sign.",
|
|
94
|
+
WRONG_CASE_ERROR: "Your answer includes use of a variable with the wrong case.",
|
|
95
|
+
WRONG_LETTER_ERROR: "Your answer includes a wrong variable letter.",
|
|
96
|
+
invalidSelection: "Make sure you select something for every row.",
|
|
97
|
+
ERROR_TITLE: "Oops!",
|
|
98
|
+
ERROR_MESSAGE: "Sorry, I don't understand that!",
|
|
99
|
+
hints: "Hints",
|
|
100
|
+
getAnotherHint: "Get another hint",
|
|
101
|
+
deprecatedStandin: "Sorry, this part of the question is no longer available. 😅 Don't worry, you won't be graded on this part. Keep going!",
|
|
102
|
+
keepTrying: "Keep trying",
|
|
103
|
+
tryAgain: "Try again",
|
|
104
|
+
check: "Check",
|
|
105
|
+
correctExcited: "Correct!",
|
|
106
|
+
nextQuestion: "Next question",
|
|
107
|
+
skipToTitle: ({
|
|
108
|
+
title
|
|
109
|
+
}) => `Skip to ${title}`,
|
|
110
|
+
current: "Current",
|
|
111
|
+
correct: "Correct",
|
|
112
|
+
correctSelected: "Correct (selected)",
|
|
113
|
+
correctCrossedOut: "Correct (but you crossed it out)",
|
|
114
|
+
incorrect: "Incorrect",
|
|
115
|
+
incorrectSelected: "Incorrect (selected)",
|
|
116
|
+
hideExplanation: "Hide explanation",
|
|
117
|
+
explain: "Explain",
|
|
118
|
+
INVALID_MESSAGE_PREFIX: "We couldn't grade your answer.",
|
|
119
|
+
DEFAULT_INVALID_MESSAGE_1: "It looks like you left something blank or ",
|
|
120
|
+
DEFAULT_INVALID_MESSAGE_2: "entered in an invalid answer.",
|
|
121
|
+
integerExample: "an integer, like $6$",
|
|
122
|
+
properExample: "a *proper* fraction, like $1/2$ or $6/10$",
|
|
123
|
+
simplifiedProperExample: "a *simplified proper* fraction, like $3/5$",
|
|
124
|
+
improperExample: "an *improper* fraction, like $10/7$ or $14/8$",
|
|
125
|
+
simplifiedImproperExample: "a *simplified improper* fraction, like $7/4$",
|
|
126
|
+
mixedExample: "a mixed number, like $1\\ 3/4$",
|
|
127
|
+
decimalExample: "an *exact* decimal, like $0.75$",
|
|
128
|
+
percentExample: "a percent, like $12.34\\%$",
|
|
129
|
+
piExample: "a multiple of pi, like $12\\ \\text{pi}$ or $2/3\\ \\text{pi}$",
|
|
130
|
+
yourAnswer: "**Your answer should be** ",
|
|
131
|
+
yourAnswerLabel: "Your answer:",
|
|
132
|
+
addPoints: "Click to add points",
|
|
133
|
+
addVertices: "Click to add vertices",
|
|
134
|
+
tapMultiple: "Tap each dot on the image to select all answers that apply.",
|
|
135
|
+
tapSingle: "Tap each dot on the image to select an answer.",
|
|
136
|
+
clickMultiple: "Click each dot on the image to select all answers that apply.",
|
|
137
|
+
clickSingle: "Click each dot on the image to select an answer.",
|
|
138
|
+
choices: "Choices:",
|
|
139
|
+
answers: ({
|
|
140
|
+
num
|
|
141
|
+
}) => num === 1 ? `${num} answer` : `${num} answers`,
|
|
142
|
+
hideAnswersToggleLabel: "Hide answer choices",
|
|
143
|
+
moves: ({
|
|
144
|
+
num
|
|
145
|
+
}) => num === 1 ? `Moves: ${num}` : `Moves: ${num}`,
|
|
146
|
+
clickTiles: "Click on the tiles to change the lights.",
|
|
147
|
+
turnOffLights: "You must turn on all of the lights to continue.",
|
|
148
|
+
fillAllCells: "Make sure you fill in all cells in the matrix.",
|
|
149
|
+
molecularDrawing: ({
|
|
150
|
+
content
|
|
151
|
+
}) => `A molecular structure drawing. SMILES notation: ${content}`,
|
|
152
|
+
switchDirection: "Switch direction",
|
|
153
|
+
circleOpen: "Make circle open",
|
|
154
|
+
circleFilled: "Make circle filled",
|
|
155
|
+
numDivisions: "Number of divisions:",
|
|
156
|
+
divisions: ({
|
|
157
|
+
divRangeString
|
|
158
|
+
}) => `Please make sure the number of divisions is in the range ${divRangeString}.`,
|
|
159
|
+
lineRange: ({
|
|
160
|
+
lineRange
|
|
161
|
+
}) => `lines ${lineRange}`,
|
|
162
|
+
lineNumber: ({
|
|
163
|
+
lineNumber
|
|
164
|
+
}) => `line ${lineNumber}`,
|
|
165
|
+
symbolPassage: ({
|
|
166
|
+
questionSymbol,
|
|
167
|
+
questionNumber
|
|
168
|
+
}) => `The symbol ${questionSymbol} indicates that question ${questionNumber} references this portion of the passage.`,
|
|
169
|
+
symbolQuestion: ({
|
|
170
|
+
sentenceSymbol
|
|
171
|
+
}) => ` The symbol ${sentenceSymbol} indicates that the following sentence is referenced in a question.`,
|
|
172
|
+
lineLabel: "Line",
|
|
173
|
+
beginningPassage: "Beginning of reading passage.",
|
|
174
|
+
beginningFootnotes: "Beginning of reading passage footnotes.",
|
|
175
|
+
endPassage: "End of reading passage.",
|
|
176
|
+
questionMarker: ({
|
|
177
|
+
number
|
|
178
|
+
}) => `[Marker for question ${number}]`,
|
|
179
|
+
circleMarker: ({
|
|
180
|
+
number
|
|
181
|
+
}) => `[Circle marker ${number}]`,
|
|
182
|
+
sentenceMarker: ({
|
|
183
|
+
number
|
|
184
|
+
}) => `[Sentence ${number}]`,
|
|
185
|
+
dragHandles: "Drag handles to make graph",
|
|
186
|
+
tapAddPoints: "Tap to add points",
|
|
187
|
+
false: "False",
|
|
188
|
+
true: "True",
|
|
189
|
+
no: "No",
|
|
190
|
+
yes: "Yes",
|
|
191
|
+
chooseCorrectNum: "Please choose the correct number of answers.",
|
|
192
|
+
notNoneOfTheAbove: "'None of the above' may not be selected when other answers are selected.",
|
|
193
|
+
noneOfTheAbove: "None of the above",
|
|
194
|
+
chooseNumAnswers: ({
|
|
195
|
+
numCorrect
|
|
196
|
+
}) => `Choose ${numCorrect} answers:`,
|
|
197
|
+
chooseAllAnswers: "Choose all answers that apply:",
|
|
198
|
+
chooseOneAnswer: "Choose 1 answer:",
|
|
199
|
+
choiceCheckedCorrect: ({
|
|
200
|
+
letter
|
|
201
|
+
}) => `(Choice ${letter}, Checked, Correct)`,
|
|
202
|
+
choiceCrossedOutCorrect: ({
|
|
203
|
+
letter
|
|
204
|
+
}) => `(Choice ${letter}, Crossed out, Correct)`,
|
|
205
|
+
choiceCorrect: ({
|
|
206
|
+
letter
|
|
207
|
+
}) => `(Choice ${letter}, Correct)`,
|
|
208
|
+
choiceCheckedIncorrect: ({
|
|
209
|
+
letter
|
|
210
|
+
}) => `(Choice ${letter}, Checked, Incorrect)`,
|
|
211
|
+
choiceCrossedOutIncorrect: ({
|
|
212
|
+
letter
|
|
213
|
+
}) => `(Choice ${letter}, Crossed out, Incorrect)`,
|
|
214
|
+
choiceIncorrect: ({
|
|
215
|
+
letter
|
|
216
|
+
}) => `(Choice ${letter}, Incorrect)`,
|
|
217
|
+
choiceChecked: ({
|
|
218
|
+
letter
|
|
219
|
+
}) => `(Choice ${letter}, Checked)`,
|
|
220
|
+
choiceCrossedOut: ({
|
|
221
|
+
letter
|
|
222
|
+
}) => `(Choice ${letter}, Crossed out)`,
|
|
223
|
+
choice: ({
|
|
224
|
+
letter
|
|
225
|
+
}) => `(Choice ${letter})`,
|
|
226
|
+
crossOut: "Cross out",
|
|
227
|
+
crossOutOption: "Cross out option",
|
|
228
|
+
crossOutChoice: ({
|
|
229
|
+
letter
|
|
230
|
+
}) => `Cross out Choice ${letter}`,
|
|
231
|
+
bringBack: "Bring back",
|
|
232
|
+
openMenuForChoice: ({
|
|
233
|
+
letter
|
|
234
|
+
}) => `Open menu for Choice ${letter}`,
|
|
235
|
+
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",
|
|
236
|
+
rightArrow: "Reaction arrow pointing to the right.",
|
|
237
|
+
dontUnderstandUnits: "I couldn't understand those units.",
|
|
238
|
+
checkSigFigs: "Check your significant figures.",
|
|
239
|
+
answerNumericallyIncorrect: "That answer is numerically incorrect.",
|
|
240
|
+
checkUnits: "Check your units.",
|
|
241
|
+
dontUnderstand: "I don't understand that",
|
|
242
|
+
loading: "Loading...",
|
|
243
|
+
videoTranscript: "See video transcript",
|
|
244
|
+
somethingWrong: "Something went wrong.",
|
|
245
|
+
videoWrapper: "Khan Academy video wrapper"
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* PerseusI18nContext provides a way to set the strings and locale that are
|
|
250
|
+
* used inside the Perseus package.
|
|
251
|
+
*
|
|
252
|
+
*/
|
|
253
|
+
// @ts-expect-error - TS2322 - Type 'Context<{ strings: {}; locale: string; }>' is not assignable to type 'Context<I18nContextType>'.
|
|
254
|
+
const PerseusI18nContext = /*#__PURE__*/React.createContext(process.env.NODE_ENV === "test" || process.env.STORYBOOK ? {
|
|
255
|
+
strings: mockStrings,
|
|
256
|
+
locale: "en"
|
|
257
|
+
} :
|
|
258
|
+
// We want to return null here, not an empty object, so that we
|
|
259
|
+
// are will throw an error when attempting to access the
|
|
260
|
+
// undefined locale or strings, making it easier to debug.
|
|
261
|
+
null);
|
|
262
|
+
function PerseusI18nContextProvider({
|
|
263
|
+
children,
|
|
264
|
+
strings,
|
|
265
|
+
locale
|
|
266
|
+
}) {
|
|
267
|
+
return /*#__PURE__*/React.createElement(PerseusI18nContext.Provider, {
|
|
268
|
+
value: {
|
|
269
|
+
strings,
|
|
270
|
+
locale
|
|
271
|
+
}
|
|
272
|
+
}, children);
|
|
273
|
+
}
|
|
274
|
+
const usePerseusI18n = () => useContext(PerseusI18nContext);
|
|
275
|
+
|
|
72
276
|
const debounce = (func, delay) => {
|
|
73
277
|
let timer = null;
|
|
74
278
|
return (...args) => {
|
|
@@ -81,21 +285,8 @@ const debounce = (func, delay) => {
|
|
|
81
285
|
};
|
|
82
286
|
};
|
|
83
287
|
|
|
84
|
-
const customKeyTranslator = _extends({}, keyTranslator, {
|
|
85
|
-
// If there's something in the input that can become part of a
|
|
86
|
-
// fraction, typing "/" puts it in the numerator. If not, typing
|
|
87
|
-
// "/" does nothing. In that case, enter a \frac.
|
|
88
|
-
FRAC: mathQuill => {
|
|
89
|
-
const contents = mathQuill.latex();
|
|
90
|
-
mathQuill.typedText("/");
|
|
91
|
-
if (mathQuill.latex() === contents) {
|
|
92
|
-
mathQuill.cmd("\\frac");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
288
|
// A WYSIWYG math input that calls `onChange(LaTeX-string)`
|
|
98
|
-
class
|
|
289
|
+
class InnerMathInput extends React.Component {
|
|
99
290
|
constructor(...args) {
|
|
100
291
|
super(...args);
|
|
101
292
|
// @ts-expect-error - TS2564 - Property 'mouseDown' has no initializer and is not definitely assigned in the constructor.
|
|
@@ -109,6 +300,21 @@ class MathInput extends React.Component {
|
|
|
109
300
|
};
|
|
110
301
|
this.insert = value => {
|
|
111
302
|
const input = this.mathField();
|
|
303
|
+
const {
|
|
304
|
+
locale
|
|
305
|
+
} = this.context;
|
|
306
|
+
const customKeyTranslator = _extends({}, getKeyTranslator(locale), {
|
|
307
|
+
// If there's something in the input that can become part of a
|
|
308
|
+
// fraction, typing "/" puts it in the numerator. If not, typing
|
|
309
|
+
// "/" does nothing. In that case, enter a \frac.
|
|
310
|
+
FRAC: mathQuill => {
|
|
311
|
+
const contents = mathQuill.latex();
|
|
312
|
+
mathQuill.typedText("/");
|
|
313
|
+
if (mathQuill.latex() === contents) {
|
|
314
|
+
mathQuill.cmd("\\frac");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
112
318
|
const inputModifier = customKeyTranslator[value];
|
|
113
319
|
if (inputModifier) {
|
|
114
320
|
inputModifier(input, value);
|
|
@@ -131,8 +337,11 @@ class MathInput extends React.Component {
|
|
|
131
337
|
};
|
|
132
338
|
this.mathField = () => {
|
|
133
339
|
if (!this.__mathField && this.__mathFieldWrapperRef) {
|
|
340
|
+
const {
|
|
341
|
+
locale
|
|
342
|
+
} = this.context;
|
|
134
343
|
// Initialize MathQuill.MathField instance
|
|
135
|
-
this.__mathField = createMathField(this.__mathFieldWrapperRef, baseConfig => _extends({}, baseConfig, {
|
|
344
|
+
this.__mathField = createMathField(this.__mathFieldWrapperRef, this.props.mathInputStrings, baseConfig => _extends({}, baseConfig, {
|
|
136
345
|
handlers: {
|
|
137
346
|
edit: debounce(mathField => {
|
|
138
347
|
// This handler is guaranteed to be called on change, but
|
|
@@ -148,7 +357,7 @@ class MathInput extends React.Component {
|
|
|
148
357
|
// Use the specified symbol to represent multiplication
|
|
149
358
|
// TODO(alex): Add an option to disallow variables, in
|
|
150
359
|
// which case 'x' should get converted to '\\times'
|
|
151
|
-
if (convertDotToTimesByLocale(this.props.convertDotToTimes)) {
|
|
360
|
+
if (convertDotToTimesByLocale(locale, this.props.convertDotToTimes)) {
|
|
152
361
|
value = value.replace(/\\cdot/g, "\\times");
|
|
153
362
|
|
|
154
363
|
// Preserve cursor position in the common case:
|
|
@@ -208,7 +417,10 @@ class MathInput extends React.Component {
|
|
|
208
417
|
focused: false
|
|
209
418
|
});
|
|
210
419
|
this.handleKeypadPress = (key, e) => {
|
|
211
|
-
const
|
|
420
|
+
const {
|
|
421
|
+
locale
|
|
422
|
+
} = this.context;
|
|
423
|
+
const translator = getKeyTranslator(locale)[key];
|
|
212
424
|
const mathField = this.mathField();
|
|
213
425
|
if (mathField) {
|
|
214
426
|
if (translator) {
|
|
@@ -307,7 +519,7 @@ class MathInput extends React.Component {
|
|
|
307
519
|
focused: false,
|
|
308
520
|
active: false
|
|
309
521
|
}) : /*#__PURE__*/React.createElement(Clickable, {
|
|
310
|
-
"aria-label": this.state.keypadOpen ?
|
|
522
|
+
"aria-label": this.state.keypadOpen ? this.context.strings.closeKeypad : this.context.strings.openKeypad,
|
|
311
523
|
"aria-checked": this.state.keypadOpen,
|
|
312
524
|
role: "switch",
|
|
313
525
|
onClick: () => this.state.keypadOpen ? this.closeKeypad() : this.openKeypad()
|
|
@@ -316,10 +528,36 @@ class MathInput extends React.Component {
|
|
|
316
528
|
}, props))))));
|
|
317
529
|
}
|
|
318
530
|
}
|
|
319
|
-
|
|
531
|
+
|
|
532
|
+
// We need to have two contexts (one for Perseus and one for MathInput), so we
|
|
533
|
+
// add a wrapper around the MathInput component to provide the MathInput context
|
|
534
|
+
// to it.
|
|
535
|
+
InnerMathInput.contextType = PerseusI18nContext;
|
|
536
|
+
InnerMathInput.defaultProps = {
|
|
320
537
|
value: "",
|
|
321
538
|
convertDotToTimes: false
|
|
322
539
|
};
|
|
540
|
+
class MathInput extends React.Component {
|
|
541
|
+
constructor(...args) {
|
|
542
|
+
super(...args);
|
|
543
|
+
this.inputRef = /*#__PURE__*/React.createRef();
|
|
544
|
+
}
|
|
545
|
+
focus() {
|
|
546
|
+
var _this$inputRef$curren;
|
|
547
|
+
(_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
|
|
548
|
+
}
|
|
549
|
+
insert(value) {
|
|
550
|
+
var _this$inputRef$curren2;
|
|
551
|
+
(_this$inputRef$curren2 = this.inputRef.current) == null || _this$inputRef$curren2.insert(value);
|
|
552
|
+
}
|
|
553
|
+
render() {
|
|
554
|
+
return /*#__PURE__*/React.createElement(InnerMathInput, _extends({}, this.props, {
|
|
555
|
+
ref: this.inputRef,
|
|
556
|
+
mathInputStrings: this.context.strings
|
|
557
|
+
}));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
MathInput.contextType = MathInputI18nContext;
|
|
323
561
|
const MathInputIcon = ({
|
|
324
562
|
hovered,
|
|
325
563
|
focused,
|
|
@@ -1235,16 +1473,6 @@ const MAXERROR_EPSILON = Math.pow(2, -42);
|
|
|
1235
1473
|
// TOOD(kevinb): Figure out how this relates to KEScore in
|
|
1236
1474
|
// perseus-all-package/types.js and see if there's a way to
|
|
1237
1475
|
// unify these types.
|
|
1238
|
-
const errors = {
|
|
1239
|
-
APPROXIMATED_PI_ERROR: i18n._("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>"),
|
|
1240
|
-
EXTRA_SYMBOLS_ERROR: i18n._("We could not understand your " + "answer. Please check your answer for extra " + "text or symbols."),
|
|
1241
|
-
NEEDS_TO_BE_SIMPLFIED_ERROR: i18n._("Your answer is almost correct, " + "but it needs to be simplified."),
|
|
1242
|
-
MISSING_PERCENT_ERROR: i18n._("Your answer is almost correct, " + "but it is missing a " + "<code>\\%</code> at the end."),
|
|
1243
|
-
MULTIPLICATION_SIGN_ERROR: i18n._("I'm a computer. I only understand " + "multiplication if you use an asterisk " + "(*) as the multiplication sign."),
|
|
1244
|
-
WRONG_CASE_ERROR: i18n._("Your answer includes use of a variable with the wrong case."),
|
|
1245
|
-
WRONG_LETTER_ERROR: i18n._("Your answer includes a wrong variable letter.")
|
|
1246
|
-
};
|
|
1247
|
-
|
|
1248
1476
|
/*
|
|
1249
1477
|
* Answer types
|
|
1250
1478
|
*
|
|
@@ -1317,7 +1545,7 @@ const KhanAnswerTypes = {
|
|
|
1317
1545
|
*/
|
|
1318
1546
|
predicate: {
|
|
1319
1547
|
defaultForms: "integer, proper, improper, mixed, decimal",
|
|
1320
|
-
createValidatorFunctional: function (predicate, options) {
|
|
1548
|
+
createValidatorFunctional: function (predicate, options, strings) {
|
|
1321
1549
|
// Extract the options from the given solution object
|
|
1322
1550
|
options = _.extend({
|
|
1323
1551
|
simplify: "required",
|
|
@@ -1705,12 +1933,12 @@ const KhanAnswerTypes = {
|
|
|
1705
1933
|
} else if (form === "percent") {
|
|
1706
1934
|
// Otherwise, an error was returned
|
|
1707
1935
|
score.empty = true;
|
|
1708
|
-
score.message =
|
|
1936
|
+
score.message = strings.MISSING_PERCENT_ERROR;
|
|
1709
1937
|
} else {
|
|
1710
1938
|
if (options.simplify !== "enforced") {
|
|
1711
1939
|
score.empty = true;
|
|
1712
1940
|
}
|
|
1713
|
-
score.message =
|
|
1941
|
+
score.message = strings.NEEDS_TO_BE_SIMPLFIED_ERROR;
|
|
1714
1942
|
}
|
|
1715
1943
|
// The return false below stops the looping of the
|
|
1716
1944
|
// callback since predicate check succeeded.
|
|
@@ -1719,7 +1947,7 @@ const KhanAnswerTypes = {
|
|
|
1719
1947
|
}
|
|
1720
1948
|
if (piApprox && predicate(val, Math.abs(val * 0.001))) {
|
|
1721
1949
|
score.empty = true;
|
|
1722
|
-
score.message =
|
|
1950
|
+
score.message = strings.APPROXIMATED_PI_ERROR;
|
|
1723
1951
|
}
|
|
1724
1952
|
}
|
|
1725
1953
|
});
|
|
@@ -1735,7 +1963,7 @@ const KhanAnswerTypes = {
|
|
|
1735
1963
|
});
|
|
1736
1964
|
if (!interpretedGuess) {
|
|
1737
1965
|
score.empty = true;
|
|
1738
|
-
score.message =
|
|
1966
|
+
score.message = strings.EXTRA_SYMBOLS_ERROR;
|
|
1739
1967
|
return score;
|
|
1740
1968
|
}
|
|
1741
1969
|
}
|
|
@@ -1758,10 +1986,10 @@ const KhanAnswerTypes = {
|
|
|
1758
1986
|
type: "predicate"
|
|
1759
1987
|
})];
|
|
1760
1988
|
},
|
|
1761
|
-
createValidatorFunctional: function (correctAnswer, options) {
|
|
1989
|
+
createValidatorFunctional: function (correctAnswer, options, strings) {
|
|
1762
1990
|
return KhanAnswerTypes.predicate.createValidatorFunctional(
|
|
1763
1991
|
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
1764
|
-
...KhanAnswerTypes.number.convertToPredicate(correctAnswer, options));
|
|
1992
|
+
...KhanAnswerTypes.number.convertToPredicate(correctAnswer, options), strings);
|
|
1765
1993
|
}
|
|
1766
1994
|
},
|
|
1767
1995
|
/*
|
|
@@ -1826,7 +2054,7 @@ const KhanAnswerTypes = {
|
|
|
1826
2054
|
}
|
|
1827
2055
|
return solution;
|
|
1828
2056
|
},
|
|
1829
|
-
createValidatorFunctional: function (solution, options) {
|
|
2057
|
+
createValidatorFunctional: function (solution, options, strings) {
|
|
1830
2058
|
return function (guess) {
|
|
1831
2059
|
const score = {
|
|
1832
2060
|
empty: false,
|
|
@@ -1877,7 +2105,7 @@ const KhanAnswerTypes = {
|
|
|
1877
2105
|
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
1878
2106
|
score.ungraded = true;
|
|
1879
2107
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
1880
|
-
score.message = result.wrongVariableCase ?
|
|
2108
|
+
score.message = result.wrongVariableCase ? strings.WRONG_CASE_ERROR : strings.WRONG_LETTER_ERROR;
|
|
1881
2109
|
// Don't tell the use they're "almost there" in this case, that may not be true and isn't helpful.
|
|
1882
2110
|
// @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; }'.
|
|
1883
2111
|
score.suppressAlmostThere = true;
|
|
@@ -1903,7 +2131,7 @@ const KhanAnswerTypes = {
|
|
|
1903
2131
|
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
|
|
1904
2132
|
score.ungraded = true;
|
|
1905
2133
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
1906
|
-
score.message =
|
|
2134
|
+
score.message = strings.MULTIPLICATION_SIGN_ERROR;
|
|
1907
2135
|
} else if (resultX.message) {
|
|
1908
2136
|
// TODO(aasmund): I18nize `score.message`
|
|
1909
2137
|
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
|
|
@@ -1918,9 +2146,6 @@ const KhanAnswerTypes = {
|
|
|
1918
2146
|
};
|
|
1919
2147
|
|
|
1920
2148
|
const _excluded$5 = ["scoring"];
|
|
1921
|
-
const ERROR_TITLE = i18n._("Oops!");
|
|
1922
|
-
const ERROR_MESSAGE = i18n._("Sorry, I don't understand that!");
|
|
1923
|
-
|
|
1924
2149
|
// Map of international operator names to their English equivalents
|
|
1925
2150
|
const englishOperators = {
|
|
1926
2151
|
arctg: "arctan",
|
|
@@ -1950,6 +2175,32 @@ const deriveKeypadVersion = apiOptions => {
|
|
|
1950
2175
|
// can remove this `virtualKeypadVersion` field entirely.
|
|
1951
2176
|
return apiOptions.nativeKeypadProxy != null ? "REACT_NATIVE_KEYPAD" : "MATH_INPUT_KEYPAD_V2";
|
|
1952
2177
|
};
|
|
2178
|
+
/**
|
|
2179
|
+
* Get the character used for separating decimals.
|
|
2180
|
+
*/
|
|
2181
|
+
const getDecimalSeparator = locale => {
|
|
2182
|
+
var _match$;
|
|
2183
|
+
switch (locale) {
|
|
2184
|
+
// TODO(somewhatabstract): Remove this when Chrome supports the `ka`
|
|
2185
|
+
// locale properly.
|
|
2186
|
+
// https://github.com/formatjs/formatjs/issues/1526#issuecomment-559891201
|
|
2187
|
+
//
|
|
2188
|
+
// Supported locales in Chrome:
|
|
2189
|
+
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/icu/scripts/chrome_ui_languages.list
|
|
2190
|
+
case "ka":
|
|
2191
|
+
return ",";
|
|
2192
|
+
default:
|
|
2193
|
+
const numberWithDecimalSeparator = 1.1;
|
|
2194
|
+
// TODO(FEI-3647): Update to use .formatToParts() once we no longer have to
|
|
2195
|
+
// support Safari 12.
|
|
2196
|
+
const match = new Intl.NumberFormat(locale).format(numberWithDecimalSeparator)
|
|
2197
|
+
// 0x661 is ARABIC-INDIC DIGIT ONE
|
|
2198
|
+
// 0x6F1 is EXTENDED ARABIC-INDIC DIGIT ONE
|
|
2199
|
+
.match(/[^\d\u0661\u06F1]/);
|
|
2200
|
+
return (_match$ = match == null ? void 0 : match[0]) != null ? _match$ : ".";
|
|
2201
|
+
}
|
|
2202
|
+
};
|
|
2203
|
+
|
|
1953
2204
|
// The new, MathQuill input expression widget
|
|
1954
2205
|
class Expression extends React.Component {
|
|
1955
2206
|
constructor(..._args) {
|
|
@@ -1982,7 +2233,7 @@ class Expression extends React.Component {
|
|
|
1982
2233
|
if (!this.parse(this.props.value, this.props).parsed) {
|
|
1983
2234
|
const apiResult = this.props.apiOptions.onInputError(null,
|
|
1984
2235
|
// reserved for some widget identifier
|
|
1985
|
-
this.props.value,
|
|
2236
|
+
this.props.value, this.context.strings.ERROR_TITLE);
|
|
1986
2237
|
if (apiResult !== false) {
|
|
1987
2238
|
this.setState({
|
|
1988
2239
|
invalid: true
|
|
@@ -2006,7 +2257,7 @@ class Expression extends React.Component {
|
|
|
2006
2257
|
scoring
|
|
2007
2258
|
} = _ref,
|
|
2008
2259
|
rubric = _objectWithoutPropertiesLoose(_ref, _excluded$5);
|
|
2009
|
-
const score = Expression.validate(this.getUserInput(), rubric, onInputError || function () {});
|
|
2260
|
+
const score = Expression.validate(this.getUserInput(), rubric, onInputError || function () {}, this.context.strings, this.context.locale);
|
|
2010
2261
|
|
|
2011
2262
|
// "scoring" is a flag that indicates when we are checking answers.
|
|
2012
2263
|
// otherwise, we may just be checking validity after changes.
|
|
@@ -2033,7 +2284,7 @@ class Expression extends React.Component {
|
|
|
2033
2284
|
// make it so that solution answers with ','s or '.'s work
|
|
2034
2285
|
const options = _.pick(props || this.props, "functions");
|
|
2035
2286
|
_.extend(options, {
|
|
2036
|
-
decimal_separator:
|
|
2287
|
+
decimal_separator: getDecimalSeparator(this.context.locale)
|
|
2037
2288
|
});
|
|
2038
2289
|
return KAS.parse(normalizeTex(value), options);
|
|
2039
2290
|
};
|
|
@@ -2111,10 +2362,10 @@ class Expression extends React.Component {
|
|
|
2111
2362
|
*/
|
|
2112
2363
|
static validate(userInput, rubric,
|
|
2113
2364
|
// @ts-expect-error - TS2322 - Type '() => void' is not assignable to type 'OnInputErrorFunctionType'.
|
|
2114
|
-
onInputError = function () {}) {
|
|
2365
|
+
onInputError = function () {}, strings, locale) {
|
|
2115
2366
|
const options = _.clone(rubric);
|
|
2116
2367
|
_.extend(options, {
|
|
2117
|
-
decimal_separator:
|
|
2368
|
+
decimal_separator: getDecimalSeparator(locale)
|
|
2118
2369
|
});
|
|
2119
2370
|
const createValidator = answer => {
|
|
2120
2371
|
// We give options to KAS.parse here because it is parsing the
|
|
@@ -2137,7 +2388,7 @@ class Expression extends React.Component {
|
|
|
2137
2388
|
return KhanAnswerTypes.expression.createValidatorFunctional(expression.expr, _({}).extend(options, {
|
|
2138
2389
|
simplify: answer.simplify,
|
|
2139
2390
|
form: answer.form
|
|
2140
|
-
}));
|
|
2391
|
+
}), strings);
|
|
2141
2392
|
};
|
|
2142
2393
|
|
|
2143
2394
|
// Find the first answer form that matches the user's input and that
|
|
@@ -2280,6 +2531,10 @@ class Expression extends React.Component {
|
|
|
2280
2531
|
"perseus-widget-expression": true,
|
|
2281
2532
|
"show-error-tooltip": this.state.showErrorTooltip
|
|
2282
2533
|
});
|
|
2534
|
+
const {
|
|
2535
|
+
ERROR_MESSAGE,
|
|
2536
|
+
ERROR_TITLE
|
|
2537
|
+
} = this.context.strings;
|
|
2283
2538
|
return /*#__PURE__*/React.createElement("div", {
|
|
2284
2539
|
className: className,
|
|
2285
2540
|
onBlur: () => this.state.invalid && this.setState({
|
|
@@ -2328,6 +2583,7 @@ class Expression extends React.Component {
|
|
|
2328
2583
|
* to be included as keys on the keypad. These are scraped from the answer
|
|
2329
2584
|
* forms.
|
|
2330
2585
|
*/
|
|
2586
|
+
Expression.contextType = PerseusI18nContext;
|
|
2331
2587
|
Expression.defaultProps = {
|
|
2332
2588
|
value: "",
|
|
2333
2589
|
times: false,
|
|
@@ -2715,7 +2971,7 @@ function keScoreFromPerseusScore(score, guess, state) {
|
|
|
2715
2971
|
* Return the first valid interpretation of 'text' as a number, in the form
|
|
2716
2972
|
* {value: 2.3, exact: true}.
|
|
2717
2973
|
*/
|
|
2718
|
-
function firstNumericalParse$1(text) {
|
|
2974
|
+
function firstNumericalParse$1(text, strings) {
|
|
2719
2975
|
// TODO(alpert): This is sort of hacky...
|
|
2720
2976
|
let first;
|
|
2721
2977
|
const val = KhanAnswerTypes.predicate.createValidatorFunctional(function (ans) {
|
|
@@ -2725,7 +2981,7 @@ function firstNumericalParse$1(text) {
|
|
|
2725
2981
|
simplify: "optional",
|
|
2726
2982
|
inexact: true,
|
|
2727
2983
|
forms: "integer, proper, improper, pi, log, mixed, decimal"
|
|
2728
|
-
});
|
|
2984
|
+
}, strings);
|
|
2729
2985
|
val(text);
|
|
2730
2986
|
return first;
|
|
2731
2987
|
}
|
|
@@ -10277,8 +10533,6 @@ const getClipPoint = function getClipPoint(graph, coord, angle) {
|
|
|
10277
10533
|
class WrappedDrawing {
|
|
10278
10534
|
constructor(graphie, initialPoint) {
|
|
10279
10535
|
this.graphie = void 0;
|
|
10280
|
-
this.wrapper = void 0;
|
|
10281
|
-
this.visibleShape = void 0;
|
|
10282
10536
|
this.initialPoint = void 0;
|
|
10283
10537
|
this.graphie = graphie;
|
|
10284
10538
|
this.initialPoint = initialPoint;
|
|
@@ -18312,7 +18566,7 @@ const rules$1 = _extends({}, pureMarkdownRules, {
|
|
|
18312
18566
|
// just a stub for testing.
|
|
18313
18567
|
return /*#__PURE__*/React.createElement("em", {
|
|
18314
18568
|
key: state.key
|
|
18315
|
-
},
|
|
18569
|
+
}, `[Widget: ${node.id}]`);
|
|
18316
18570
|
}
|
|
18317
18571
|
}),
|
|
18318
18572
|
blockMath: _extends({}, pureMarkdownRules.blockMath, {
|
|
@@ -18785,6 +19039,7 @@ const replaceDeprecatedEditors = () => {
|
|
|
18785
19039
|
replaceEditor("simulator", "deprecated-standin");
|
|
18786
19040
|
};
|
|
18787
19041
|
const getWidget = name => {
|
|
19042
|
+
var _widgets$name;
|
|
18788
19043
|
// TODO(alex): Consider referring to these as renderers to avoid
|
|
18789
19044
|
// overloading "widget"
|
|
18790
19045
|
if (!_.has(widgets, name)) {
|
|
@@ -18792,9 +19047,9 @@ const getWidget = name => {
|
|
|
18792
19047
|
}
|
|
18793
19048
|
|
|
18794
19049
|
// Allow widgets to specify a widget directly or via a function
|
|
18795
|
-
if (widgets[name].getWidget) {
|
|
18796
|
-
|
|
18797
|
-
return widgets[name].getWidget();
|
|
19050
|
+
if ((_widgets$name = widgets[name]) != null && _widgets$name.getWidget) {
|
|
19051
|
+
var _widgets$name$getWidg, _widgets$name2;
|
|
19052
|
+
return (_widgets$name$getWidg = (_widgets$name2 = widgets[name]).getWidget) == null ? void 0 : _widgets$name$getWidg.call(_widgets$name2);
|
|
18798
19053
|
}
|
|
18799
19054
|
return widgets[name].widget;
|
|
18800
19055
|
};
|
|
@@ -18943,7 +19198,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
18943
19198
|
options: newEditorProps
|
|
18944
19199
|
});
|
|
18945
19200
|
};
|
|
18946
|
-
const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
19201
|
+
const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
18947
19202
|
const type = widgetInfo.type;
|
|
18948
19203
|
const widgetExports = widgets[type];
|
|
18949
19204
|
if (widgetExports == null) {
|
|
@@ -18964,7 +19219,7 @@ const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
|
18964
19219
|
transform = widgetExports.transform || _.identity;
|
|
18965
19220
|
}
|
|
18966
19221
|
// widgetInfo.options are the widgetEditor's props:
|
|
18967
|
-
return transform(widgetInfo.options, problemNum);
|
|
19222
|
+
return transform(widgetInfo.options, strings, problemNum);
|
|
18968
19223
|
};
|
|
18969
19224
|
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
18970
19225
|
if (!traverseRenderer) {
|
|
@@ -19363,8 +19618,11 @@ class Renderer extends React.Component {
|
|
|
19363
19618
|
problemNum
|
|
19364
19619
|
} = props;
|
|
19365
19620
|
const widgetsStartProps = {};
|
|
19621
|
+
const {
|
|
19622
|
+
strings
|
|
19623
|
+
} = this.props;
|
|
19366
19624
|
entries(allWidgetInfo).forEach(([key, widgetInfo]) => {
|
|
19367
|
-
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, problemNum);
|
|
19625
|
+
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, strings, problemNum);
|
|
19368
19626
|
});
|
|
19369
19627
|
|
|
19370
19628
|
// Call the onWidgetStartProps callback if it exists
|
|
@@ -21424,10 +21682,12 @@ class InputWithExamples extends React.Component {
|
|
|
21424
21682
|
id: this._getUniqueId()
|
|
21425
21683
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
21426
21684
|
content: examplesContent,
|
|
21427
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "input-with-examples")
|
|
21685
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "input-with-examples"),
|
|
21686
|
+
strings: this.context.strings
|
|
21428
21687
|
})));
|
|
21429
21688
|
}
|
|
21430
21689
|
}
|
|
21690
|
+
InputWithExamples.contextType = PerseusI18nContext;
|
|
21431
21691
|
InputWithExamples.defaultProps = {
|
|
21432
21692
|
type: "text",
|
|
21433
21693
|
shouldShowExamples: true,
|
|
@@ -21549,32 +21809,32 @@ const answerTypes = {
|
|
|
21549
21809
|
}
|
|
21550
21810
|
};
|
|
21551
21811
|
const formExamples$1 = {
|
|
21552
|
-
integer: function (options) {
|
|
21553
|
-
return
|
|
21812
|
+
integer: function (options, strings) {
|
|
21813
|
+
return strings.integerExample;
|
|
21554
21814
|
},
|
|
21555
|
-
proper: function (options) {
|
|
21815
|
+
proper: function (options, strings) {
|
|
21556
21816
|
if (options.simplify === "optional") {
|
|
21557
|
-
return
|
|
21817
|
+
return strings.properExample;
|
|
21558
21818
|
}
|
|
21559
|
-
return
|
|
21819
|
+
return strings.simplifiedProperExample;
|
|
21560
21820
|
},
|
|
21561
|
-
improper: function (options) {
|
|
21821
|
+
improper: function (options, strings) {
|
|
21562
21822
|
if (options.simplify === "optional") {
|
|
21563
|
-
return
|
|
21823
|
+
return strings.improperExample;
|
|
21564
21824
|
}
|
|
21565
|
-
return
|
|
21825
|
+
return strings.simplifiedImproperExample;
|
|
21566
21826
|
},
|
|
21567
|
-
mixed: function (options) {
|
|
21568
|
-
return
|
|
21827
|
+
mixed: function (options, strings) {
|
|
21828
|
+
return strings.mixedExample;
|
|
21569
21829
|
},
|
|
21570
|
-
decimal: function (options) {
|
|
21571
|
-
return
|
|
21830
|
+
decimal: function (options, strings) {
|
|
21831
|
+
return strings.decimalExample;
|
|
21572
21832
|
},
|
|
21573
|
-
percent: function (options) {
|
|
21574
|
-
return
|
|
21833
|
+
percent: function (options, strings) {
|
|
21834
|
+
return strings.percentExample;
|
|
21575
21835
|
},
|
|
21576
|
-
pi: function (options) {
|
|
21577
|
-
return
|
|
21836
|
+
pi: function (options, strings) {
|
|
21837
|
+
return strings.piExample;
|
|
21578
21838
|
}
|
|
21579
21839
|
};
|
|
21580
21840
|
class InputNumber extends React.Component {
|
|
@@ -21632,18 +21892,16 @@ class InputNumber extends React.Component {
|
|
|
21632
21892
|
};
|
|
21633
21893
|
this.simpleValidate = (rubric, onInputError) => {
|
|
21634
21894
|
onInputError = onInputError || function () {};
|
|
21635
|
-
return InputNumber.validate(this.getUserInput(), rubric, onInputError);
|
|
21895
|
+
return InputNumber.validate(this.getUserInput(), rubric, this.context.strings, onInputError);
|
|
21636
21896
|
};
|
|
21637
21897
|
this.examples = () => {
|
|
21898
|
+
const {
|
|
21899
|
+
strings
|
|
21900
|
+
} = this.context;
|
|
21638
21901
|
const type = this.props.answerType;
|
|
21639
21902
|
const forms = answerTypes[type].forms.split(/\s*,\s*/);
|
|
21640
|
-
const examples = _.map(forms,
|
|
21641
|
-
|
|
21642
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
21643
|
-
// eslint-disable-next-line @babel/no-invalid-this
|
|
21644
|
-
return formExamples$1[form](this.props);
|
|
21645
|
-
}, this);
|
|
21646
|
-
return [i18n._("**Your answer should be** ")].concat(examples);
|
|
21903
|
+
const examples = _.map(forms, form => formExamples$1[form](this.props, strings));
|
|
21904
|
+
return [strings.yourAnswer].concat(examples);
|
|
21647
21905
|
};
|
|
21648
21906
|
}
|
|
21649
21907
|
render() {
|
|
@@ -21696,7 +21954,7 @@ class InputNumber extends React.Component {
|
|
|
21696
21954
|
linterContext: this.props.linterContext
|
|
21697
21955
|
});
|
|
21698
21956
|
}
|
|
21699
|
-
static validate(state, rubric, onInputError = () => {}) {
|
|
21957
|
+
static validate(state, rubric, strings, onInputError = () => {}) {
|
|
21700
21958
|
if (rubric.answerType == null) {
|
|
21701
21959
|
rubric.answerType = "number";
|
|
21702
21960
|
}
|
|
@@ -21710,7 +21968,7 @@ class InputNumber extends React.Component {
|
|
|
21710
21968
|
inexact: rubric.inexact || undefined,
|
|
21711
21969
|
maxError: rubric.maxError,
|
|
21712
21970
|
forms: answerTypes[rubric.answerType].forms
|
|
21713
|
-
});
|
|
21971
|
+
}, strings);
|
|
21714
21972
|
|
|
21715
21973
|
// We may have received TeX; try to parse it before grading.
|
|
21716
21974
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
@@ -21752,6 +22010,7 @@ class InputNumber extends React.Component {
|
|
|
21752
22010
|
return answerString;
|
|
21753
22011
|
}
|
|
21754
22012
|
}
|
|
22013
|
+
InputNumber.contextType = PerseusI18nContext;
|
|
21755
22014
|
InputNumber.defaultProps = {
|
|
21756
22015
|
currentValue: "",
|
|
21757
22016
|
size: "normal",
|
|
@@ -21835,12 +22094,12 @@ const answerFormButtons = [{
|
|
|
21835
22094
|
content: "\u03C0"
|
|
21836
22095
|
}];
|
|
21837
22096
|
const formExamples = {
|
|
21838
|
-
integer: () =>
|
|
21839
|
-
proper: form => form.simplify === "optional" ?
|
|
21840
|
-
improper: form => form.simplify === "optional" ?
|
|
21841
|
-
mixed: () =>
|
|
21842
|
-
decimal: () =>
|
|
21843
|
-
pi: () =>
|
|
22097
|
+
integer: (form, strings) => strings.integerExample,
|
|
22098
|
+
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
22099
|
+
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
22100
|
+
mixed: (form, strings) => strings.mixedExample,
|
|
22101
|
+
decimal: (form, strings) => strings.decimalExample,
|
|
22102
|
+
pi: (form, strings) => strings.piExample
|
|
21844
22103
|
};
|
|
21845
22104
|
class NumericInput extends React.Component {
|
|
21846
22105
|
constructor(...args) {
|
|
@@ -21862,13 +22121,12 @@ class NumericInput extends React.Component {
|
|
|
21862
22121
|
};
|
|
21863
22122
|
});
|
|
21864
22123
|
let examples = _.map(forms, form => {
|
|
21865
|
-
|
|
21866
|
-
return formExamples[form.name](form);
|
|
22124
|
+
return formExamples[form.name](form, this.context.strings);
|
|
21867
22125
|
});
|
|
21868
22126
|
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
21869
22127
|
// versions of the same format
|
|
21870
22128
|
examples = _.uniq(examples);
|
|
21871
|
-
return [
|
|
22129
|
+
return [this.context.strings.yourAnswer].concat(examples);
|
|
21872
22130
|
};
|
|
21873
22131
|
this.shouldShowExamples = () => {
|
|
21874
22132
|
var _this$props$answerFor2, _this$props$answerFor3;
|
|
@@ -21881,7 +22139,7 @@ class NumericInput extends React.Component {
|
|
|
21881
22139
|
return !noFormsAccepted && !allFormsAccepted;
|
|
21882
22140
|
};
|
|
21883
22141
|
this.simpleValidate = rubric => {
|
|
21884
|
-
return NumericInput.validate(this.getUserInput(), rubric);
|
|
22142
|
+
return NumericInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
21885
22143
|
};
|
|
21886
22144
|
this.focus = () => {
|
|
21887
22145
|
var _this$inputRef;
|
|
@@ -21961,7 +22219,7 @@ class NumericInput extends React.Component {
|
|
|
21961
22219
|
}
|
|
21962
22220
|
return answerStrings[0];
|
|
21963
22221
|
}
|
|
21964
|
-
static validate(userInput, rubric) {
|
|
22222
|
+
static validate(userInput, rubric, strings) {
|
|
21965
22223
|
const defaultAnswerForms = answerFormButtons.map(e => e["value"])
|
|
21966
22224
|
// Don't default to validating the answer as a pi answer
|
|
21967
22225
|
// if answerForm isn't set on the answer
|
|
@@ -21988,7 +22246,7 @@ class NumericInput extends React.Component {
|
|
|
21988
22246
|
// TODO(merlob) backfill / delete
|
|
21989
22247
|
maxError: answer.maxError,
|
|
21990
22248
|
forms: validatorForms
|
|
21991
|
-
});
|
|
22249
|
+
}, strings);
|
|
21992
22250
|
};
|
|
21993
22251
|
|
|
21994
22252
|
// We may have received TeX; try to parse it before grading.
|
|
@@ -22058,7 +22316,7 @@ class NumericInput extends React.Component {
|
|
|
22058
22316
|
render() {
|
|
22059
22317
|
let labelText = this.props.labelText;
|
|
22060
22318
|
if (labelText == null || labelText === "") {
|
|
22061
|
-
labelText =
|
|
22319
|
+
labelText = this.context.strings.yourAnswerLabel;
|
|
22062
22320
|
}
|
|
22063
22321
|
|
|
22064
22322
|
// To right align a custom keypad we need to wrap it.
|
|
@@ -22113,6 +22371,7 @@ class NumericInput extends React.Component {
|
|
|
22113
22371
|
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
22114
22372
|
// When should two answers to a problem take different answer types?
|
|
22115
22373
|
// See D27790 for more discussion.
|
|
22374
|
+
NumericInput.contextType = PerseusI18nContext;
|
|
22116
22375
|
NumericInput.defaultProps = {
|
|
22117
22376
|
currentValue: "",
|
|
22118
22377
|
size: "normal",
|
|
@@ -22268,18 +22527,21 @@ class PassageRef extends React.Component {
|
|
|
22268
22527
|
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
|
|
22269
22528
|
}
|
|
22270
22529
|
render() {
|
|
22530
|
+
const {
|
|
22531
|
+
strings
|
|
22532
|
+
} = this.context;
|
|
22271
22533
|
const lineRange = this.state.lineRange;
|
|
22272
22534
|
let lineRangeOutput;
|
|
22273
22535
|
if (!lineRange) {
|
|
22274
|
-
lineRangeOutput =
|
|
22536
|
+
lineRangeOutput = strings.lineRange({
|
|
22275
22537
|
lineRange: `?${EN_DASH$1}?`
|
|
22276
22538
|
});
|
|
22277
22539
|
} else if (lineRange[0] === lineRange[1]) {
|
|
22278
|
-
lineRangeOutput =
|
|
22279
|
-
lineNumber: lineRange[0]
|
|
22540
|
+
lineRangeOutput = strings.lineNumber({
|
|
22541
|
+
lineNumber: String(lineRange[0])
|
|
22280
22542
|
});
|
|
22281
22543
|
} else {
|
|
22282
|
-
lineRangeOutput =
|
|
22544
|
+
lineRangeOutput = strings.lineRange({
|
|
22283
22545
|
lineRange: lineRange[0] + EN_DASH$1 + lineRange[1]
|
|
22284
22546
|
});
|
|
22285
22547
|
}
|
|
@@ -22321,6 +22583,7 @@ class PassageRef extends React.Component {
|
|
|
22321
22583
|
};
|
|
22322
22584
|
}
|
|
22323
22585
|
}
|
|
22586
|
+
PassageRef.contextType = PerseusI18nContext;
|
|
22324
22587
|
PassageRef.defaultProps = {
|
|
22325
22588
|
passageNumber: 1,
|
|
22326
22589
|
referenceNumber: 1,
|
|
@@ -22684,7 +22947,7 @@ Icon.defaultProps = {
|
|
|
22684
22947
|
color: "currentColor"
|
|
22685
22948
|
};
|
|
22686
22949
|
|
|
22687
|
-
function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
22950
|
+
function getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings) {
|
|
22688
22951
|
// There are two pieces of metadata we want to add to each a11yText:
|
|
22689
22952
|
// whether the answer was checked/crossed-out/neither, and whether the
|
|
22690
22953
|
// answer is correct/incorrect/not-yet-revealed.
|
|
@@ -22693,45 +22956,45 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
|
22693
22956
|
// we've just enumerated all 9 possibilities as separate strings.
|
|
22694
22957
|
if (showCorrectness && correct) {
|
|
22695
22958
|
if (checked) {
|
|
22696
|
-
return
|
|
22959
|
+
return strings.choiceCheckedCorrect({
|
|
22697
22960
|
letter
|
|
22698
22961
|
});
|
|
22699
22962
|
}
|
|
22700
22963
|
if (crossedOut) {
|
|
22701
|
-
return
|
|
22964
|
+
return strings.choiceCrossedOutCorrect({
|
|
22702
22965
|
letter
|
|
22703
22966
|
});
|
|
22704
22967
|
}
|
|
22705
|
-
return
|
|
22968
|
+
return strings.choiceCorrect({
|
|
22706
22969
|
letter
|
|
22707
22970
|
});
|
|
22708
22971
|
}
|
|
22709
22972
|
if (showCorrectness && !correct) {
|
|
22710
22973
|
if (checked) {
|
|
22711
|
-
return
|
|
22974
|
+
return strings.choiceCheckedIncorrect({
|
|
22712
22975
|
letter
|
|
22713
22976
|
});
|
|
22714
22977
|
}
|
|
22715
22978
|
if (crossedOut) {
|
|
22716
|
-
return
|
|
22979
|
+
return strings.choiceCrossedOutIncorrect({
|
|
22717
22980
|
letter
|
|
22718
22981
|
});
|
|
22719
22982
|
}
|
|
22720
|
-
return
|
|
22983
|
+
return strings.choiceIncorrect({
|
|
22721
22984
|
letter
|
|
22722
22985
|
});
|
|
22723
22986
|
}
|
|
22724
22987
|
if (checked) {
|
|
22725
|
-
return
|
|
22988
|
+
return strings.choiceChecked({
|
|
22726
22989
|
letter
|
|
22727
22990
|
});
|
|
22728
22991
|
}
|
|
22729
22992
|
if (crossedOut) {
|
|
22730
|
-
return
|
|
22993
|
+
return strings.choiceCrossedOut({
|
|
22731
22994
|
letter
|
|
22732
22995
|
});
|
|
22733
22996
|
}
|
|
22734
|
-
return
|
|
22997
|
+
return strings.choice({
|
|
22735
22998
|
letter
|
|
22736
22999
|
});
|
|
22737
23000
|
}
|
|
@@ -22778,18 +23041,8 @@ const styles$z = StyleSheet.create({
|
|
|
22778
23041
|
* "choice letter". (For example, in English, `getChoiceLetter(0)` is "A",
|
|
22779
23042
|
* `getChoiceLetter(1)` is "B", etc.)
|
|
22780
23043
|
*/
|
|
22781
|
-
function getChoiceLetter(pos) {
|
|
22782
|
-
|
|
22783
|
-
* front of multiple-choice options. For instance, a multiple-choice
|
|
22784
|
-
* question with three options would display
|
|
22785
|
-
* (A) first option
|
|
22786
|
-
* (B) second option
|
|
22787
|
-
* (C) third option
|
|
22788
|
-
* There must be spaces between each of the different characters. The
|
|
22789
|
-
* characters will show up next to options in the order that they are
|
|
22790
|
-
* listed here. Most multiple choice questions have 5 or fewer options.
|
|
22791
|
-
*/
|
|
22792
|
-
const lettersString = i18n._("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");
|
|
23044
|
+
function getChoiceLetter(pos, strings) {
|
|
23045
|
+
const lettersString = strings.letters;
|
|
22793
23046
|
const letters = lettersString.split(" ");
|
|
22794
23047
|
if (pos < letters.length) {
|
|
22795
23048
|
// If the position we need is listed in the localized string, use that.
|
|
@@ -22853,7 +23106,10 @@ function ChoiceInner(props) {
|
|
|
22853
23106
|
showCorrectness,
|
|
22854
23107
|
correct
|
|
22855
23108
|
} = props;
|
|
22856
|
-
const
|
|
23109
|
+
const {
|
|
23110
|
+
strings
|
|
23111
|
+
} = usePerseusI18n();
|
|
23112
|
+
const letter = getChoiceLetter(pos, strings);
|
|
22857
23113
|
if (!showCorrectness) {
|
|
22858
23114
|
return letter;
|
|
22859
23115
|
}
|
|
@@ -22999,24 +23255,24 @@ const styles$w = StyleSheet.create({
|
|
|
22999
23255
|
* ChoiceIcon visualizations but is meant to make the distinctions
|
|
23000
23256
|
* between the states more immediately clear to users.
|
|
23001
23257
|
*/
|
|
23002
|
-
function renderText(checked, correct, crossedOut) {
|
|
23258
|
+
function renderText(checked, correct, crossedOut, strings) {
|
|
23003
23259
|
if (correct) {
|
|
23004
23260
|
// For correct answers, we surface checked _or_ crossedOut state,
|
|
23005
23261
|
// because any interaction with the correct answer is noteworthy!
|
|
23006
23262
|
if (checked) {
|
|
23007
|
-
return
|
|
23263
|
+
return strings.correctSelected;
|
|
23008
23264
|
}
|
|
23009
23265
|
if (crossedOut) {
|
|
23010
|
-
return
|
|
23266
|
+
return strings.correctCrossedOut;
|
|
23011
23267
|
}
|
|
23012
|
-
return
|
|
23268
|
+
return strings.correct;
|
|
23013
23269
|
}
|
|
23014
23270
|
// But, for incorrect answers, we only surface checked state,
|
|
23015
23271
|
// because crossing out an incorrect answer is not noteworthy.
|
|
23016
23272
|
if (checked) {
|
|
23017
|
-
return
|
|
23273
|
+
return strings.incorrectSelected;
|
|
23018
23274
|
}
|
|
23019
|
-
return
|
|
23275
|
+
return strings.incorrect;
|
|
23020
23276
|
}
|
|
23021
23277
|
const OptionStatus = function OptionStatus(props) {
|
|
23022
23278
|
const {
|
|
@@ -23026,6 +23282,9 @@ const OptionStatus = function OptionStatus(props) {
|
|
|
23026
23282
|
previouslyAnswered,
|
|
23027
23283
|
reviewMode
|
|
23028
23284
|
} = props;
|
|
23285
|
+
const {
|
|
23286
|
+
strings
|
|
23287
|
+
} = usePerseusI18n();
|
|
23029
23288
|
|
|
23030
23289
|
// Option status is shown only in review mode, or for incorrectly
|
|
23031
23290
|
// answered items.
|
|
@@ -23045,7 +23304,7 @@ const OptionStatus = function OptionStatus(props) {
|
|
|
23045
23304
|
}
|
|
23046
23305
|
return /*#__PURE__*/React.createElement("div", {
|
|
23047
23306
|
className: css(styles$v.text, textStyle)
|
|
23048
|
-
}, renderText(checked, correct, crossedOut));
|
|
23307
|
+
}, renderText(checked, correct, crossedOut, strings));
|
|
23049
23308
|
};
|
|
23050
23309
|
const styles$v = StyleSheet.create({
|
|
23051
23310
|
text: {
|
|
@@ -23092,6 +23351,9 @@ const Choice = function Choice(props) {
|
|
|
23092
23351
|
forwardedRef
|
|
23093
23352
|
} = props;
|
|
23094
23353
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
23354
|
+
const {
|
|
23355
|
+
strings
|
|
23356
|
+
} = usePerseusI18n();
|
|
23095
23357
|
useEffect(() => {
|
|
23096
23358
|
if (isInputFocused && disabled) {
|
|
23097
23359
|
setIsInputFocused(false);
|
|
@@ -23121,8 +23383,8 @@ const Choice = function Choice(props) {
|
|
|
23121
23383
|
// However, we don't want to do this when we're in review mode in the
|
|
23122
23384
|
// content library.
|
|
23123
23385
|
const showDimmed = !reviewMode && apiOptions.readOnly || crossedOut;
|
|
23124
|
-
const letter = getChoiceLetter(pos);
|
|
23125
|
-
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness);
|
|
23386
|
+
const letter = getChoiceLetter(pos, strings);
|
|
23387
|
+
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings);
|
|
23126
23388
|
const idFactory = useUniqueIdWithMock(`choice`);
|
|
23127
23389
|
const choiceId = idFactory.get(letter);
|
|
23128
23390
|
return /*#__PURE__*/React.createElement("div", {
|
|
@@ -23222,15 +23484,15 @@ const Choice = function Choice(props) {
|
|
|
23222
23484
|
content: ({
|
|
23223
23485
|
close
|
|
23224
23486
|
}) => /*#__PURE__*/React.createElement(PopoverContent, {
|
|
23225
|
-
title:
|
|
23226
|
-
content:
|
|
23487
|
+
title: strings.crossOut,
|
|
23488
|
+
content: strings.crossOutOption,
|
|
23227
23489
|
closeButtonVisible: true,
|
|
23228
23490
|
actions: /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
|
|
23229
23491
|
size: spacing.medium_16
|
|
23230
23492
|
}), /*#__PURE__*/React.createElement(Button, {
|
|
23231
23493
|
kind: "primary",
|
|
23232
|
-
"aria-label":
|
|
23233
|
-
letter: getChoiceLetter(pos)
|
|
23494
|
+
"aria-label": strings.crossOutChoice({
|
|
23495
|
+
letter: getChoiceLetter(pos, strings)
|
|
23234
23496
|
}),
|
|
23235
23497
|
disabled: apiOptions.readOnly || reviewMode,
|
|
23236
23498
|
onClick: () => {
|
|
@@ -23250,14 +23512,14 @@ const Choice = function Choice(props) {
|
|
|
23250
23512
|
}
|
|
23251
23513
|
close();
|
|
23252
23514
|
}
|
|
23253
|
-
}, crossedOut ?
|
|
23515
|
+
}, crossedOut ? strings.bringBack : strings.crossOut))
|
|
23254
23516
|
})
|
|
23255
23517
|
}, ({
|
|
23256
23518
|
open
|
|
23257
23519
|
}) => /*#__PURE__*/React.createElement(Clickable, {
|
|
23258
23520
|
onClick: open,
|
|
23259
|
-
"aria-label":
|
|
23260
|
-
letter: getChoiceLetter(pos)
|
|
23521
|
+
"aria-label": strings.openMenuForChoice({
|
|
23522
|
+
letter: getChoiceLetter(pos, strings)
|
|
23261
23523
|
}),
|
|
23262
23524
|
style: {
|
|
23263
23525
|
alignSelf: "center",
|
|
@@ -23309,6 +23571,9 @@ const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
|
|
|
23309
23571
|
forwardedRef
|
|
23310
23572
|
} = props,
|
|
23311
23573
|
rest = _objectWithoutPropertiesLoose(props, _excluded$3);
|
|
23574
|
+
const {
|
|
23575
|
+
strings
|
|
23576
|
+
} = usePerseusI18n();
|
|
23312
23577
|
const choiceProps = _extends({}, rest, {
|
|
23313
23578
|
content: showContent ? content :
|
|
23314
23579
|
/*#__PURE__*/
|
|
@@ -23324,7 +23589,8 @@ const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
|
|
|
23324
23589
|
// just to render a string
|
|
23325
23590
|
React.createElement(Renderer, {
|
|
23326
23591
|
key: "noneOfTheAboveRenderer",
|
|
23327
|
-
content:
|
|
23592
|
+
content: strings.noneOfTheAbove,
|
|
23593
|
+
strings: strings
|
|
23328
23594
|
})
|
|
23329
23595
|
});
|
|
23330
23596
|
return /*#__PURE__*/React.createElement(Choice$1, _extends({}, choiceProps, {
|
|
@@ -23344,16 +23610,16 @@ const {
|
|
|
23344
23610
|
|
|
23345
23611
|
// exported for tests
|
|
23346
23612
|
|
|
23347
|
-
function getInstructionsText(multipleSelect, countChoices, numCorrect) {
|
|
23613
|
+
function getInstructionsText(multipleSelect, countChoices, numCorrect, strings) {
|
|
23348
23614
|
if (multipleSelect) {
|
|
23349
23615
|
if (countChoices) {
|
|
23350
|
-
return
|
|
23351
|
-
numCorrect: numCorrect
|
|
23616
|
+
return strings.chooseNumAnswers({
|
|
23617
|
+
numCorrect: String(numCorrect)
|
|
23352
23618
|
});
|
|
23353
23619
|
}
|
|
23354
|
-
return
|
|
23620
|
+
return strings.chooseAllAnswers;
|
|
23355
23621
|
}
|
|
23356
|
-
return
|
|
23622
|
+
return strings.chooseOneAnswer;
|
|
23357
23623
|
}
|
|
23358
23624
|
const BaseRadio = function BaseRadio(props) {
|
|
23359
23625
|
const {
|
|
@@ -23368,6 +23634,9 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23368
23634
|
isLastUsedWidget,
|
|
23369
23635
|
registerFocusFunction
|
|
23370
23636
|
} = props;
|
|
23637
|
+
const {
|
|
23638
|
+
strings
|
|
23639
|
+
} = usePerseusI18n();
|
|
23371
23640
|
|
|
23372
23641
|
// useEffect doesn't have previous props
|
|
23373
23642
|
const prevReviewModeRubric = useRef();
|
|
@@ -23474,7 +23743,7 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23474
23743
|
const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
23475
23744
|
const className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$t.radio, styles$t.responsiveRadioContainer, firstChoiceHighlighted && isMobile && styles$t.radioContainerFirstHighlighted, lastChoiceHighlighted && isMobile && styles$t.radioContainerLastHighlighted));
|
|
23476
23745
|
const instructionsClassName = classNames("instructions", css(styles$t.instructions, isMobile && styles$t.instructionsMobile));
|
|
23477
|
-
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
|
|
23746
|
+
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
|
|
23478
23747
|
const responsiveClassName = css(styles$t.responsiveFieldset);
|
|
23479
23748
|
const fieldset = /*#__PURE__*/React.createElement("fieldset", {
|
|
23480
23749
|
className: `perseus-widget-radio-fieldset ${responsiveClassName}`
|
|
@@ -23739,7 +24008,8 @@ class Radio$1 extends React.Component {
|
|
|
23739
24008
|
linterContext: _extends({}, this.props.linterContext, {
|
|
23740
24009
|
// @ts-expect-error - TS2322 - Type '{ blockHighlight: true; contentType: string; highlightLint: boolean; paths: readonly string[]; stack: readonly string[]; }' is not assignable to type 'LinterContextProps'.
|
|
23741
24010
|
blockHighlight: true
|
|
23742
|
-
})
|
|
24011
|
+
}),
|
|
24012
|
+
strings: this.context.strings
|
|
23743
24013
|
});
|
|
23744
24014
|
};
|
|
23745
24015
|
// When `BaseRadio`'s `onChange` handler is called, indicating a change in
|
|
@@ -23791,7 +24061,7 @@ class Radio$1 extends React.Component {
|
|
|
23791
24061
|
return Radio$1.getUserInputFromProps(this.props);
|
|
23792
24062
|
};
|
|
23793
24063
|
this.simpleValidate = rubric => {
|
|
23794
|
-
return Radio$1.validate(this.getUserInput(), rubric);
|
|
24064
|
+
return Radio$1.validate(this.getUserInput(), rubric, this.context.strings);
|
|
23795
24065
|
};
|
|
23796
24066
|
/**
|
|
23797
24067
|
* Turn on rationale display for the currently selected choices. Note that
|
|
@@ -23852,7 +24122,7 @@ class Radio$1 extends React.Component {
|
|
|
23852
24122
|
}
|
|
23853
24123
|
};
|
|
23854
24124
|
}
|
|
23855
|
-
static validate(userInput, rubric) {
|
|
24125
|
+
static validate(userInput, rubric, strings) {
|
|
23856
24126
|
const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
23857
24127
|
return sum + (selected ? 1 : 0);
|
|
23858
24128
|
}, 0);
|
|
@@ -23865,7 +24135,7 @@ class Radio$1 extends React.Component {
|
|
|
23865
24135
|
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
23866
24136
|
return {
|
|
23867
24137
|
type: "invalid",
|
|
23868
|
-
message:
|
|
24138
|
+
message: strings.chooseCorrectNum
|
|
23869
24139
|
};
|
|
23870
24140
|
// If NOTA and some other answer are checked, ...
|
|
23871
24141
|
}
|
|
@@ -23873,7 +24143,7 @@ class Radio$1 extends React.Component {
|
|
|
23873
24143
|
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
23874
24144
|
return {
|
|
23875
24145
|
type: "invalid",
|
|
23876
|
-
message:
|
|
24146
|
+
message: strings.notNoneOfTheAbove
|
|
23877
24147
|
};
|
|
23878
24148
|
}
|
|
23879
24149
|
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
@@ -23985,6 +24255,9 @@ class Radio$1 extends React.Component {
|
|
|
23985
24255
|
const {
|
|
23986
24256
|
choices
|
|
23987
24257
|
} = this.props;
|
|
24258
|
+
const {
|
|
24259
|
+
strings
|
|
24260
|
+
} = this.context;
|
|
23988
24261
|
let choiceStates;
|
|
23989
24262
|
if (this.props.static) {
|
|
23990
24263
|
choiceStates = choices.map(choice => ({
|
|
@@ -24036,11 +24309,7 @@ class Radio$1 extends React.Component {
|
|
|
24036
24309
|
}));
|
|
24037
24310
|
}
|
|
24038
24311
|
const choicesProp = choices.map((choice, i) => {
|
|
24039
|
-
const content = choice.isNoneOfTheAbove && !choice.content ?
|
|
24040
|
-
// we use i18n._ instead of $_ here because the content
|
|
24041
|
-
// sent to a renderer needs to be a string, not a react
|
|
24042
|
-
// node (/renderable/fragment).
|
|
24043
|
-
i18n._("None of the above") : choice.content;
|
|
24312
|
+
const content = choice.isNoneOfTheAbove && !choice.content ? strings.noneOfTheAbove : choice.content;
|
|
24044
24313
|
const {
|
|
24045
24314
|
selected,
|
|
24046
24315
|
crossedOut,
|
|
@@ -24092,6 +24361,7 @@ class Radio$1 extends React.Component {
|
|
|
24092
24361
|
});
|
|
24093
24362
|
}
|
|
24094
24363
|
}
|
|
24364
|
+
Radio$1.contextType = PerseusI18nContext;
|
|
24095
24365
|
Radio$1.defaultProps = {
|
|
24096
24366
|
choices: [],
|
|
24097
24367
|
multipleSelect: false,
|
|
@@ -24106,14 +24376,8 @@ const {
|
|
|
24106
24376
|
random
|
|
24107
24377
|
} = Util;
|
|
24108
24378
|
|
|
24109
|
-
// Represents choices that we automatically re-order if encountered.
|
|
24110
|
-
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
24111
|
-
// found.
|
|
24112
|
-
// Note 2: these are internationalized when compared later on.
|
|
24113
|
-
const ReversedChoices = [[i18n._("False"), i18n._("True")], [i18n._("No"), i18n._("Yes")]];
|
|
24114
|
-
|
|
24115
24379
|
// Transforms the choices for display.
|
|
24116
|
-
const _choiceTransform = (widgetOptions, problemNum) => {
|
|
24380
|
+
const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
24117
24381
|
const _maybeRandomize = function _maybeRandomize(array) {
|
|
24118
24382
|
const randomSeed = problemNum === undefined ? random : problemNum;
|
|
24119
24383
|
// NOTE: `problemNum` will only be set when the radio widget is
|
|
@@ -24142,6 +24406,11 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24142
24406
|
return newChoices;
|
|
24143
24407
|
};
|
|
24144
24408
|
const enforceOrdering = choices => {
|
|
24409
|
+
// Represents choices that we automatically re-order if encountered.
|
|
24410
|
+
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
24411
|
+
// found.
|
|
24412
|
+
// Note 2: these are internationalized when compared later on.
|
|
24413
|
+
const ReversedChoices = [[strings.false, strings.true], [strings.no, strings.yes]];
|
|
24145
24414
|
const content = choices.map(c => c.content);
|
|
24146
24415
|
if (ReversedChoices.some(reversed => _.isEqual(content, reversed))) {
|
|
24147
24416
|
return [choices[1], choices[0]];
|
|
@@ -24167,8 +24436,8 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24167
24436
|
// 1) we randomize the order first
|
|
24168
24437
|
_maybeRandomize(choices)));
|
|
24169
24438
|
};
|
|
24170
|
-
const transform = (widgetOptions, problemNum) => {
|
|
24171
|
-
const choices = _choiceTransform(widgetOptions, problemNum);
|
|
24439
|
+
const transform = (widgetOptions, strings, problemNum) => {
|
|
24440
|
+
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24172
24441
|
const numCorrect = _.reduce(widgetOptions.choices, function (memo, choice) {
|
|
24173
24442
|
return choice.correct ? memo + 1 : memo;
|
|
24174
24443
|
}, 0);
|
|
@@ -24254,7 +24523,7 @@ class Categorizer extends React.Component {
|
|
|
24254
24523
|
return Categorizer.getUserInputFromProps(this.props);
|
|
24255
24524
|
};
|
|
24256
24525
|
this.simpleValidate = rubric => {
|
|
24257
|
-
return Categorizer.validate(this.getUserInput(), rubric);
|
|
24526
|
+
return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
|
|
24258
24527
|
};
|
|
24259
24528
|
}
|
|
24260
24529
|
render() {
|
|
@@ -24283,7 +24552,8 @@ class Categorizer extends React.Component {
|
|
|
24283
24552
|
key: i
|
|
24284
24553
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24285
24554
|
content: category,
|
|
24286
|
-
linterContext: this.props.linterContext
|
|
24555
|
+
linterContext: this.props.linterContext,
|
|
24556
|
+
strings: this.context.strings
|
|
24287
24557
|
}));
|
|
24288
24558
|
}))), /*#__PURE__*/React.createElement("tbody", null, indexedItems.map(indexedItem => {
|
|
24289
24559
|
const item = indexedItem[0];
|
|
@@ -24295,7 +24565,8 @@ class Categorizer extends React.Component {
|
|
|
24295
24565
|
// @ts-expect-error - TS2322 - Type 'string | number' is not assignable to type 'string | undefined'.
|
|
24296
24566
|
, {
|
|
24297
24567
|
content: item,
|
|
24298
|
-
linterContext: this.props.linterContext
|
|
24568
|
+
linterContext: this.props.linterContext,
|
|
24569
|
+
strings: this.context.strings
|
|
24299
24570
|
})), self.props.categories.map((catName, catNum) => {
|
|
24300
24571
|
const selected = self.props.values[itemNum] === catNum;
|
|
24301
24572
|
return /*#__PURE__*/React.createElement("td", {
|
|
@@ -24338,7 +24609,7 @@ class Categorizer extends React.Component {
|
|
|
24338
24609
|
this.change("values", values);
|
|
24339
24610
|
this.props.trackInteraction();
|
|
24340
24611
|
}
|
|
24341
|
-
static validate(userInput, rubric) {
|
|
24612
|
+
static validate(userInput, rubric, strings) {
|
|
24342
24613
|
let completed = true;
|
|
24343
24614
|
let allCorrect = true;
|
|
24344
24615
|
rubric.values.forEach((value, i) => {
|
|
@@ -24352,7 +24623,7 @@ class Categorizer extends React.Component {
|
|
|
24352
24623
|
if (!completed) {
|
|
24353
24624
|
return {
|
|
24354
24625
|
type: "invalid",
|
|
24355
|
-
message:
|
|
24626
|
+
message: strings.invalidSelection
|
|
24356
24627
|
};
|
|
24357
24628
|
}
|
|
24358
24629
|
return {
|
|
@@ -24368,6 +24639,7 @@ class Categorizer extends React.Component {
|
|
|
24368
24639
|
}
|
|
24369
24640
|
|
|
24370
24641
|
// TODO(benkomalo): inject page-margin into Perseus instead of hardcoding.
|
|
24642
|
+
Categorizer.contextType = PerseusI18nContext;
|
|
24371
24643
|
Categorizer.defaultProps = {
|
|
24372
24644
|
items: [],
|
|
24373
24645
|
categories: [],
|
|
@@ -24693,7 +24965,8 @@ class Definition extends React.Component {
|
|
|
24693
24965
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24694
24966
|
apiOptions: this.props.apiOptions,
|
|
24695
24967
|
content: this.props.definition,
|
|
24696
|
-
widgets: this.props.widgets
|
|
24968
|
+
widgets: this.props.widgets,
|
|
24969
|
+
strings: this.context.strings
|
|
24697
24970
|
})),
|
|
24698
24971
|
opened: activeDefinitionId === this.props.widgetId,
|
|
24699
24972
|
onClose: () => setActiveDefinitionId(null),
|
|
@@ -24715,6 +24988,7 @@ class Definition extends React.Component {
|
|
|
24715
24988
|
}, this.props.togglePrompt))));
|
|
24716
24989
|
}
|
|
24717
24990
|
}
|
|
24991
|
+
Definition.contextType = PerseusI18nContext;
|
|
24718
24992
|
Definition.defaultProps = {
|
|
24719
24993
|
togglePrompt: "define me",
|
|
24720
24994
|
definition: "definition goes here"
|
|
@@ -24765,12 +25039,13 @@ class DeprecatedStandin extends React__default.Component {
|
|
|
24765
25039
|
paddingBottom: 8
|
|
24766
25040
|
}
|
|
24767
25041
|
}, /*#__PURE__*/React__default.createElement(Banner, {
|
|
24768
|
-
text:
|
|
25042
|
+
text: this.context.strings.deprecatedStandin,
|
|
24769
25043
|
kind: "info",
|
|
24770
25044
|
layout: "full-width"
|
|
24771
25045
|
}));
|
|
24772
25046
|
}
|
|
24773
25047
|
}
|
|
25048
|
+
DeprecatedStandin.contextType = PerseusI18nContext;
|
|
24774
25049
|
var DeprecatedStandin$1 = {
|
|
24775
25050
|
name: "deprecated-standin",
|
|
24776
25051
|
displayName: "Deprecated Standin",
|
|
@@ -24965,10 +25240,12 @@ class Explanation extends React.Component {
|
|
|
24965
25240
|
apiOptions: this.props.apiOptions,
|
|
24966
25241
|
content: this.props.explanation,
|
|
24967
25242
|
widgets: this.props.widgets,
|
|
24968
|
-
linterContext: this.props.linterContext
|
|
25243
|
+
linterContext: this.props.linterContext,
|
|
25244
|
+
strings: this.context.strings
|
|
24969
25245
|
})))));
|
|
24970
25246
|
}
|
|
24971
25247
|
}
|
|
25248
|
+
Explanation.contextType = PerseusI18nContext;
|
|
24972
25249
|
Explanation.defaultProps = {
|
|
24973
25250
|
showPrompt: "Explain",
|
|
24974
25251
|
hidePrompt: "Hide explanation",
|
|
@@ -25036,6 +25313,13 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25036
25313
|
onCheckAnswer,
|
|
25037
25314
|
onNextQuestion
|
|
25038
25315
|
} = this.props;
|
|
25316
|
+
const {
|
|
25317
|
+
keepTrying,
|
|
25318
|
+
tryAgain,
|
|
25319
|
+
check,
|
|
25320
|
+
correctExcited,
|
|
25321
|
+
nextQuestion
|
|
25322
|
+
} = this.context.strings;
|
|
25039
25323
|
const answerBarStyle = _extends({}, styles$o.answerBar, {
|
|
25040
25324
|
backgroundColor: answerBarState === "CORRECT" ? color.offWhite : "white",
|
|
25041
25325
|
// Center the "Correct!" message only when there's no next question
|
|
@@ -25049,10 +25333,10 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25049
25333
|
style: {
|
|
25050
25334
|
marginLeft: 8
|
|
25051
25335
|
}
|
|
25052
|
-
},
|
|
25336
|
+
}, keepTrying)) : /*#__PURE__*/React.createElement("span", null); // empty span keeps the button on the right side
|
|
25053
25337
|
|
|
25054
25338
|
if (answerBarState !== "CORRECT") {
|
|
25055
|
-
const buttonLabel = answerBarState === "INCORRECT" ?
|
|
25339
|
+
const buttonLabel = answerBarState === "INCORRECT" ? tryAgain : check;
|
|
25056
25340
|
return /*#__PURE__*/React.createElement("div", {
|
|
25057
25341
|
style: answerBarStyle
|
|
25058
25342
|
}, message, /*#__PURE__*/React.createElement(Button, {
|
|
@@ -25075,15 +25359,16 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25075
25359
|
}
|
|
25076
25360
|
}))), /*#__PURE__*/React.createElement("span", {
|
|
25077
25361
|
role: "alert",
|
|
25078
|
-
"aria-label":
|
|
25362
|
+
"aria-label": correctExcited,
|
|
25079
25363
|
style: {
|
|
25080
25364
|
marginLeft: 8
|
|
25081
25365
|
}
|
|
25082
|
-
},
|
|
25366
|
+
}, correctExcited)), onNextQuestion && /*#__PURE__*/React.createElement(Button, {
|
|
25083
25367
|
onClick: onNextQuestion
|
|
25084
|
-
},
|
|
25368
|
+
}, nextQuestion));
|
|
25085
25369
|
}
|
|
25086
25370
|
}
|
|
25371
|
+
GradedGroupAnswerBar.contextType = PerseusI18nContext;
|
|
25087
25372
|
const fontSize = 17;
|
|
25088
25373
|
const styles$o = {
|
|
25089
25374
|
answerBar: {
|
|
@@ -25137,10 +25422,6 @@ const getNextState = (currentState, answerable) => {
|
|
|
25137
25422
|
}
|
|
25138
25423
|
};
|
|
25139
25424
|
|
|
25140
|
-
// Prepended to all invalid messages to make the widget messages a bit clearer
|
|
25141
|
-
const INVALID_MESSAGE_PREFIX = i18n._("We couldn't grade your answer.");
|
|
25142
|
-
const DEFAULT_INVALID_MESSAGE = i18n._("It looks like you left something blank or ") + i18n._("entered in an invalid answer.");
|
|
25143
|
-
|
|
25144
25425
|
// exports has no 'transform'
|
|
25145
25426
|
|
|
25146
25427
|
// A Graded Group is more or less a Group widget that displays a check
|
|
@@ -25192,8 +25473,13 @@ class GradedGroup extends React.Component {
|
|
|
25192
25473
|
// eslint-disable-next-line react/no-string-refs
|
|
25193
25474
|
// @ts-expect-error - TS2339 - Property 'score' does not exist on type 'ReactInstance'.
|
|
25194
25475
|
const score = this.refs.renderer.score();
|
|
25476
|
+
const {
|
|
25477
|
+
INVALID_MESSAGE_PREFIX,
|
|
25478
|
+
DEFAULT_INVALID_MESSAGE_1,
|
|
25479
|
+
DEFAULT_INVALID_MESSAGE_2
|
|
25480
|
+
} = this.context.strings;
|
|
25195
25481
|
const status = score.type === "points" ? score.total === score.earned ? GRADING_STATUSES.correct : GRADING_STATUSES.incorrect : GRADING_STATUSES.invalid;
|
|
25196
|
-
const message = score.type === "points" ? score.message || "" : score.message ? `${INVALID_MESSAGE_PREFIX} ${score.message}` : `${INVALID_MESSAGE_PREFIX} ${
|
|
25482
|
+
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}`;
|
|
25197
25483
|
this.setState({
|
|
25198
25484
|
status: status,
|
|
25199
25485
|
message: message,
|
|
@@ -25258,8 +25544,7 @@ class GradedGroup extends React.Component {
|
|
|
25258
25544
|
color: "#526f03"
|
|
25259
25545
|
}
|
|
25260
25546
|
}));
|
|
25261
|
-
|
|
25262
|
-
gradeStatus = i18n._("Correct");
|
|
25547
|
+
gradeStatus = this.context.strings.correct;
|
|
25263
25548
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25264
25549
|
// TODO(jeremy): update to a WB colour
|
|
25265
25550
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
@@ -25268,8 +25553,7 @@ class GradedGroup extends React.Component {
|
|
|
25268
25553
|
color: "#ff5454"
|
|
25269
25554
|
}
|
|
25270
25555
|
}));
|
|
25271
|
-
|
|
25272
|
-
gradeStatus = i18n._("Incorrect");
|
|
25556
|
+
gradeStatus = this.context.strings.incorrect;
|
|
25273
25557
|
}
|
|
25274
25558
|
const mobileClass = this.props.inGradedGroupSet ? css(styles$n.gradedGroupInSet) : css(styles$n.gradedGroup);
|
|
25275
25559
|
const classes = classNames({
|
|
@@ -25298,7 +25582,8 @@ class GradedGroup extends React.Component {
|
|
|
25298
25582
|
readOnly
|
|
25299
25583
|
}),
|
|
25300
25584
|
onInteractWithWidget: this._onInteractWithWidget,
|
|
25301
|
-
linterContext: this.props.linterContext
|
|
25585
|
+
linterContext: this.props.linterContext,
|
|
25586
|
+
strings: this.context.strings
|
|
25302
25587
|
})), !apiOptions.isMobile && icon && /*#__PURE__*/React.createElement("div", {
|
|
25303
25588
|
className: "group-icon"
|
|
25304
25589
|
}, icon), !apiOptions.isMobile && gradeStatus && /*#__PURE__*/React.createElement("div", {
|
|
@@ -25312,14 +25597,14 @@ class GradedGroup extends React.Component {
|
|
|
25312
25597
|
kind: "secondary",
|
|
25313
25598
|
disabled: this.props.apiOptions.readOnly,
|
|
25314
25599
|
onClick: this._checkAnswer
|
|
25315
|
-
},
|
|
25600
|
+
}, this.context.strings.check), !apiOptions.isMobile && isCorrect && this.props.onNextQuestion && /*#__PURE__*/React.createElement(Button, {
|
|
25316
25601
|
kind: "secondary",
|
|
25317
25602
|
disabled: this.props.apiOptions.readOnly,
|
|
25318
25603
|
onClick: this.props.onNextQuestion,
|
|
25319
25604
|
style: {
|
|
25320
25605
|
marginLeft: 5
|
|
25321
25606
|
}
|
|
25322
|
-
},
|
|
25607
|
+
}, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
|
|
25323
25608
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
25324
25609
|
tabIndex: "0",
|
|
25325
25610
|
className: css(styles$n.explanationTitle),
|
|
@@ -25333,11 +25618,12 @@ class GradedGroup extends React.Component {
|
|
|
25333
25618
|
showHint: false
|
|
25334
25619
|
});
|
|
25335
25620
|
}
|
|
25336
|
-
},
|
|
25621
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props.hint, {
|
|
25337
25622
|
// eslint-disable-next-line react/no-string-refs
|
|
25338
25623
|
ref: "hints-renderer",
|
|
25339
25624
|
apiOptions: apiOptions,
|
|
25340
|
-
linterContext: this.props.linterContext
|
|
25625
|
+
linterContext: this.props.linterContext,
|
|
25626
|
+
strings: this.context.strings
|
|
25341
25627
|
}))) :
|
|
25342
25628
|
/*#__PURE__*/
|
|
25343
25629
|
// Not using Button here bc the styles won't work.
|
|
@@ -25355,7 +25641,7 @@ class GradedGroup extends React.Component {
|
|
|
25355
25641
|
});
|
|
25356
25642
|
},
|
|
25357
25643
|
className: css(styles$n.showHintLink)
|
|
25358
|
-
},
|
|
25644
|
+
}, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
|
|
25359
25645
|
apiOptions: apiOptions,
|
|
25360
25646
|
answerBarState: answerBarState,
|
|
25361
25647
|
onCheckAnswer: this._checkAnswer,
|
|
@@ -25363,6 +25649,7 @@ class GradedGroup extends React.Component {
|
|
|
25363
25649
|
}));
|
|
25364
25650
|
}
|
|
25365
25651
|
}
|
|
25652
|
+
GradedGroup.contextType = PerseusI18nContext;
|
|
25366
25653
|
GradedGroup.defaultProps = {
|
|
25367
25654
|
title: "",
|
|
25368
25655
|
content: "",
|
|
@@ -25456,7 +25743,7 @@ class Indicators extends React.Component {
|
|
|
25456
25743
|
key: title
|
|
25457
25744
|
}, /*#__PURE__*/React.createElement(Clickable, {
|
|
25458
25745
|
role: "button",
|
|
25459
|
-
"aria-label":
|
|
25746
|
+
"aria-label": this.context.strings.skipToTitle({
|
|
25460
25747
|
title
|
|
25461
25748
|
}),
|
|
25462
25749
|
style: styles$m.indicatorButton,
|
|
@@ -25472,12 +25759,10 @@ class Indicators extends React.Component {
|
|
|
25472
25759
|
style: styles$m.indicatorDotActive
|
|
25473
25760
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25474
25761
|
className: css(a11y.srOnly)
|
|
25475
|
-
},
|
|
25762
|
+
}, this.context.strings.current)))))));
|
|
25476
25763
|
}
|
|
25477
25764
|
}
|
|
25478
|
-
|
|
25479
|
-
// no transform
|
|
25480
|
-
|
|
25765
|
+
Indicators.contextType = PerseusI18nContext; // no transform
|
|
25481
25766
|
// TODO(jared): find a better name for this :) and for GradedGroup; the names
|
|
25482
25767
|
// are currently a little confusing.
|
|
25483
25768
|
class GradedGroupSet extends React.Component {
|
|
@@ -25553,7 +25838,7 @@ class GradedGroupSet extends React.Component {
|
|
|
25553
25838
|
}
|
|
25554
25839
|
const currentGroup = this.props.gradedGroups[this.state.currentGroup];
|
|
25555
25840
|
if (!currentGroup) {
|
|
25556
|
-
return /*#__PURE__*/React.createElement("span", null,
|
|
25841
|
+
return /*#__PURE__*/React.createElement("span", null, "No current group...");
|
|
25557
25842
|
}
|
|
25558
25843
|
const numGroups = this.props.gradedGroups.length;
|
|
25559
25844
|
const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
|
|
@@ -26848,7 +27133,8 @@ class Group extends React.Component {
|
|
|
26848
27133
|
findExternalWidgets: this.props.findWidgets,
|
|
26849
27134
|
reviewMode: !!this.props.reviewModeRubric,
|
|
26850
27135
|
onInteractWithWidget: onInteractWithWidget,
|
|
26851
|
-
linterContext: this.props.linterContext
|
|
27136
|
+
linterContext: this.props.linterContext,
|
|
27137
|
+
strings: this.context.strings
|
|
26852
27138
|
}), this.props.icon &&
|
|
26853
27139
|
/*#__PURE__*/
|
|
26854
27140
|
// @ts-expect-error - TS2339 - Property 'icon' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
|
|
@@ -26857,6 +27143,7 @@ class Group extends React.Component {
|
|
|
26857
27143
|
}, this.props.icon));
|
|
26858
27144
|
}
|
|
26859
27145
|
}
|
|
27146
|
+
Group.contextType = PerseusI18nContext;
|
|
26860
27147
|
Group.defaultProps = {
|
|
26861
27148
|
content: "",
|
|
26862
27149
|
widgets: {},
|
|
@@ -27122,7 +27409,8 @@ class ImageWidget extends React.Component {
|
|
|
27122
27409
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27123
27410
|
content: this.props.alt,
|
|
27124
27411
|
apiOptions: apiOptions,
|
|
27125
|
-
linterContext: this.props.linterContext
|
|
27412
|
+
linterContext: this.props.linterContext,
|
|
27413
|
+
strings: this.context.strings
|
|
27126
27414
|
}));
|
|
27127
27415
|
}
|
|
27128
27416
|
|
|
@@ -27182,7 +27470,8 @@ class ImageWidget extends React.Component {
|
|
|
27182
27470
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27183
27471
|
content: _title + this.props.caption,
|
|
27184
27472
|
apiOptions: apiOptions,
|
|
27185
|
-
linterContext: this.props.linterContext
|
|
27473
|
+
linterContext: this.props.linterContext,
|
|
27474
|
+
strings: this.context.strings
|
|
27186
27475
|
})));
|
|
27187
27476
|
}
|
|
27188
27477
|
return /*#__PURE__*/React.createElement("figure", {
|
|
@@ -27200,7 +27489,8 @@ class ImageWidget extends React.Component {
|
|
|
27200
27489
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27201
27490
|
content: this.props.title,
|
|
27202
27491
|
apiOptions: apiOptions,
|
|
27203
|
-
linterContext: this.props.linterContext
|
|
27492
|
+
linterContext: this.props.linterContext,
|
|
27493
|
+
strings: this.context.strings
|
|
27204
27494
|
}));
|
|
27205
27495
|
}
|
|
27206
27496
|
if (this.props.caption) {
|
|
@@ -27212,7 +27502,8 @@ class ImageWidget extends React.Component {
|
|
|
27212
27502
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27213
27503
|
content: this.props.caption,
|
|
27214
27504
|
apiOptions: apiOptions,
|
|
27215
|
-
linterContext: this.props.linterContext
|
|
27505
|
+
linterContext: this.props.linterContext,
|
|
27506
|
+
strings: this.context.strings
|
|
27216
27507
|
}));
|
|
27217
27508
|
}
|
|
27218
27509
|
return /*#__PURE__*/React.createElement("figure", {
|
|
@@ -27231,6 +27522,7 @@ class ImageWidget extends React.Component {
|
|
|
27231
27522
|
};
|
|
27232
27523
|
}
|
|
27233
27524
|
}
|
|
27525
|
+
ImageWidget.contextType = PerseusI18nContext;
|
|
27234
27526
|
ImageWidget.defaultProps = {
|
|
27235
27527
|
alignment: DEFAULT_ALIGNMENT,
|
|
27236
27528
|
title: "",
|
|
@@ -28163,6 +28455,123 @@ Graph.defaultProps = {
|
|
|
28163
28455
|
isMobile: false
|
|
28164
28456
|
};
|
|
28165
28457
|
|
|
28458
|
+
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
28459
|
+
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
28460
|
+
|
|
28461
|
+
// Range is replaced within this file with Interval, but it is used elsewhere
|
|
28462
|
+
// and exported from the package, so we need to keep it around.
|
|
28463
|
+
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
28464
|
+
const ItemExtras = [
|
|
28465
|
+
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
28466
|
+
"calculator",
|
|
28467
|
+
// The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
|
|
28468
|
+
"chi2Table",
|
|
28469
|
+
// The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
|
|
28470
|
+
"financialCalculatorMonthlyPayment",
|
|
28471
|
+
// The user might benefit from a total amount calculator. Provided on Khan Academy when true
|
|
28472
|
+
"financialCalculatorTotalAmount",
|
|
28473
|
+
// The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
|
|
28474
|
+
"financialCalculatorTimeToPayOff",
|
|
28475
|
+
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
28476
|
+
"periodicTable",
|
|
28477
|
+
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
28478
|
+
"periodicTableWithKey",
|
|
28479
|
+
// The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
|
|
28480
|
+
"tTable",
|
|
28481
|
+
// The user might benefit from using a statistics Z Table like https://www.ztable.net/
|
|
28482
|
+
"zTable"];
|
|
28483
|
+
|
|
28484
|
+
// prettier-ignore
|
|
28485
|
+
|
|
28486
|
+
// prettier-ignore
|
|
28487
|
+
|
|
28488
|
+
// prettier-ignore
|
|
28489
|
+
|
|
28490
|
+
// prettier-ignore
|
|
28491
|
+
|
|
28492
|
+
// prettier-ignore
|
|
28493
|
+
|
|
28494
|
+
// prettier-ignore
|
|
28495
|
+
|
|
28496
|
+
// prettier-ignore
|
|
28497
|
+
|
|
28498
|
+
// prettier-ignore
|
|
28499
|
+
|
|
28500
|
+
// prettier-ignore
|
|
28501
|
+
|
|
28502
|
+
// prettier-ignore
|
|
28503
|
+
|
|
28504
|
+
// prettier-ignore
|
|
28505
|
+
|
|
28506
|
+
// prettier-ignore
|
|
28507
|
+
|
|
28508
|
+
// prettier-ignore
|
|
28509
|
+
|
|
28510
|
+
// prettier-ignore
|
|
28511
|
+
|
|
28512
|
+
// prettier-ignore
|
|
28513
|
+
|
|
28514
|
+
// prettier-ignore
|
|
28515
|
+
|
|
28516
|
+
// prettier-ignore
|
|
28517
|
+
|
|
28518
|
+
// prettier-ignore
|
|
28519
|
+
|
|
28520
|
+
// prettier-ignore
|
|
28521
|
+
|
|
28522
|
+
// prettier-ignore
|
|
28523
|
+
|
|
28524
|
+
// prettier-ignore
|
|
28525
|
+
|
|
28526
|
+
// prettier-ignore
|
|
28527
|
+
|
|
28528
|
+
// prettier-ignore
|
|
28529
|
+
|
|
28530
|
+
// prettier-ignore
|
|
28531
|
+
|
|
28532
|
+
// prettier-ignore
|
|
28533
|
+
|
|
28534
|
+
// prettier-ignore
|
|
28535
|
+
|
|
28536
|
+
// prettier-ignore
|
|
28537
|
+
|
|
28538
|
+
// prettier-ignore
|
|
28539
|
+
|
|
28540
|
+
// prettier-ignore
|
|
28541
|
+
|
|
28542
|
+
// prettier-ignore
|
|
28543
|
+
|
|
28544
|
+
// prettier-ignore
|
|
28545
|
+
|
|
28546
|
+
// prettier-ignore
|
|
28547
|
+
|
|
28548
|
+
// prettier-ignore
|
|
28549
|
+
|
|
28550
|
+
// prettier-ignore
|
|
28551
|
+
|
|
28552
|
+
// prettier-ignore
|
|
28553
|
+
|
|
28554
|
+
// prettier-ignore
|
|
28555
|
+
|
|
28556
|
+
//prettier-ignore
|
|
28557
|
+
|
|
28558
|
+
// A background image applied to various widgets.
|
|
28559
|
+
|
|
28560
|
+
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28561
|
+
const lockedFigureColors = {
|
|
28562
|
+
blue: "#3D7586",
|
|
28563
|
+
green: "#447A53",
|
|
28564
|
+
gray: "#5D5F66",
|
|
28565
|
+
grayH: "#3B3D45",
|
|
28566
|
+
grayI: "#21242C",
|
|
28567
|
+
purple: "#594094",
|
|
28568
|
+
purpleD: "#8351E8",
|
|
28569
|
+
pink: "#B25071",
|
|
28570
|
+
orange: "#946700",
|
|
28571
|
+
red: "#D92916"
|
|
28572
|
+
};
|
|
28573
|
+
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28574
|
+
|
|
28166
28575
|
const LockedLine = props => {
|
|
28167
28576
|
const {
|
|
28168
28577
|
color: color$1,
|
|
@@ -28179,7 +28588,7 @@ const LockedLine = props => {
|
|
|
28179
28588
|
line = /*#__PURE__*/React.createElement(LineType, {
|
|
28180
28589
|
point1: point1.coord,
|
|
28181
28590
|
point2: point2.coord,
|
|
28182
|
-
color:
|
|
28591
|
+
color: lockedFigureColors[color$1],
|
|
28183
28592
|
style: lineStyle
|
|
28184
28593
|
});
|
|
28185
28594
|
} else {
|
|
@@ -28193,8 +28602,8 @@ const LockedLine = props => {
|
|
|
28193
28602
|
y: point1.coord[1],
|
|
28194
28603
|
svgCircleProps: {
|
|
28195
28604
|
style: {
|
|
28196
|
-
fill: point1.filled ?
|
|
28197
|
-
stroke:
|
|
28605
|
+
fill: point1.filled ? lockedFigureColors[point1.color] : color.white,
|
|
28606
|
+
stroke: lockedFigureColors[point1.color],
|
|
28198
28607
|
strokeWidth: spacing.xxxxSmall_2
|
|
28199
28608
|
}
|
|
28200
28609
|
}
|
|
@@ -28203,8 +28612,8 @@ const LockedLine = props => {
|
|
|
28203
28612
|
y: point2.coord[1],
|
|
28204
28613
|
svgCircleProps: {
|
|
28205
28614
|
style: {
|
|
28206
|
-
fill: point2.filled ?
|
|
28207
|
-
stroke:
|
|
28615
|
+
fill: point2.filled ? lockedFigureColors[point2.color] : color.white,
|
|
28616
|
+
stroke: lockedFigureColors[point2.color],
|
|
28208
28617
|
strokeWidth: spacing.xxxxSmall_2
|
|
28209
28618
|
}
|
|
28210
28619
|
}
|
|
@@ -28223,8 +28632,8 @@ const LockedPoint = props => {
|
|
|
28223
28632
|
y: y,
|
|
28224
28633
|
svgCircleProps: {
|
|
28225
28634
|
style: {
|
|
28226
|
-
fill: filled ?
|
|
28227
|
-
stroke:
|
|
28635
|
+
fill: filled ? lockedFigureColors[color$1] : color.white,
|
|
28636
|
+
stroke: lockedFigureColors[color$1],
|
|
28228
28637
|
strokeWidth: spacing.xxxxSmall_2
|
|
28229
28638
|
}
|
|
28230
28639
|
}
|
|
@@ -28577,7 +28986,8 @@ const MovableLine = props => {
|
|
|
28577
28986
|
const defaultGraphConfig = {
|
|
28578
28987
|
range: [[0, 1], [0, 1]],
|
|
28579
28988
|
snapStep: [1, 1],
|
|
28580
|
-
markings: "none"
|
|
28989
|
+
markings: "none",
|
|
28990
|
+
showTooltips: false
|
|
28581
28991
|
};
|
|
28582
28992
|
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28583
28993
|
function useGraphConfig() {
|
|
@@ -28588,10 +28998,12 @@ function useGraphConfig() {
|
|
|
28588
28998
|
// graph.
|
|
28589
28999
|
const hitboxSizePx = 48;
|
|
28590
29000
|
const StyledMovablePoint = props => {
|
|
29001
|
+
var _Object$entries$find$, _Object$entries$find;
|
|
28591
29002
|
const {
|
|
28592
29003
|
range,
|
|
28593
29004
|
snapStep,
|
|
28594
|
-
markings
|
|
29005
|
+
markings,
|
|
29006
|
+
showTooltips
|
|
28595
29007
|
} = useGraphConfig();
|
|
28596
29008
|
const hitboxRef = useRef(null);
|
|
28597
29009
|
const {
|
|
@@ -28599,6 +29011,10 @@ const StyledMovablePoint = props => {
|
|
|
28599
29011
|
onMove,
|
|
28600
29012
|
color: color$1 = color.blue
|
|
28601
29013
|
} = props;
|
|
29014
|
+
|
|
29015
|
+
// WB Tooltip requires a color name for the background color.
|
|
29016
|
+
// Since the color in props is a hex value, a reverse lookup is needed.
|
|
29017
|
+
const wbColorName = (_Object$entries$find$ = (_Object$entries$find = Object.entries(color).find(([_, value]) => value === color$1)) == null ? void 0 : _Object$entries$find[0]) != null ? _Object$entries$find$ : "blue";
|
|
28602
29018
|
const {
|
|
28603
29019
|
dragging
|
|
28604
29020
|
} = useMovable({
|
|
@@ -28616,19 +29032,20 @@ const StyledMovablePoint = props => {
|
|
|
28616
29032
|
const [[_, horizontalStartY]] = useTransform([0, yMin]);
|
|
28617
29033
|
const [[__, horizontalEndY]] = useTransform([0, yMax]);
|
|
28618
29034
|
const showHairlines = dragging && markings !== "none";
|
|
28619
|
-
|
|
29035
|
+
const hairlines = /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
28620
29036
|
x1: verticalStartX,
|
|
28621
29037
|
y1: y,
|
|
28622
29038
|
x2: verticalEndX,
|
|
28623
29039
|
y2: y,
|
|
28624
|
-
stroke: color
|
|
29040
|
+
stroke: color$1
|
|
28625
29041
|
}), /*#__PURE__*/React.createElement("line", {
|
|
28626
29042
|
x1: x,
|
|
28627
29043
|
y1: horizontalStartY,
|
|
28628
29044
|
x2: x,
|
|
28629
29045
|
y2: horizontalEndY,
|
|
28630
|
-
stroke: color
|
|
28631
|
-
}))
|
|
29046
|
+
stroke: color$1
|
|
29047
|
+
}));
|
|
29048
|
+
const svgForPoint = /*#__PURE__*/React.createElement("g", {
|
|
28632
29049
|
ref: hitboxRef,
|
|
28633
29050
|
className: pointClasses,
|
|
28634
29051
|
tabIndex: 0,
|
|
@@ -28661,7 +29078,15 @@ const StyledMovablePoint = props => {
|
|
|
28661
29078
|
fill: color$1
|
|
28662
29079
|
},
|
|
28663
29080
|
"data-testid": "movable-point__center"
|
|
28664
|
-
}))
|
|
29081
|
+
}));
|
|
29082
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
29083
|
+
autoUpdate: true,
|
|
29084
|
+
backgroundColor: wbColorName,
|
|
29085
|
+
content: `(${point[0]}, ${point[1]})`,
|
|
29086
|
+
contentStyle: {
|
|
29087
|
+
color: "white"
|
|
29088
|
+
}
|
|
29089
|
+
}, svgForPoint) : svgForPoint);
|
|
28665
29090
|
};
|
|
28666
29091
|
|
|
28667
29092
|
const SegmentGraph = props => {
|
|
@@ -29587,7 +30012,7 @@ class NumberInput extends React.Component {
|
|
|
29587
30012
|
const placeholder = this.props.placeholder;
|
|
29588
30013
|
return _.isFinite(placeholder) ? +placeholder : null;
|
|
29589
30014
|
}
|
|
29590
|
-
const result = firstNumericalParse(value);
|
|
30015
|
+
const result = firstNumericalParse(value, this.context.strings);
|
|
29591
30016
|
return _.isFinite(result) ? result : this.props.value;
|
|
29592
30017
|
};
|
|
29593
30018
|
/* Set text input focus to this input */
|
|
@@ -29617,7 +30042,7 @@ class NumberInput extends React.Component {
|
|
|
29617
30042
|
if (value == null) {
|
|
29618
30043
|
return true;
|
|
29619
30044
|
}
|
|
29620
|
-
const val = firstNumericalParse(value);
|
|
30045
|
+
const val = firstNumericalParse(value, this.context.strings);
|
|
29621
30046
|
const checkValidity = this.props.checkValidity;
|
|
29622
30047
|
return _.isFinite(val) && checkValidity(val);
|
|
29623
30048
|
};
|
|
@@ -29713,6 +30138,7 @@ class NumberInput extends React.Component {
|
|
|
29713
30138
|
}
|
|
29714
30139
|
}
|
|
29715
30140
|
}
|
|
30141
|
+
NumberInput.contextType = PerseusI18nContext;
|
|
29716
30142
|
NumberInput.propTypes = {
|
|
29717
30143
|
value: PropTypes.number,
|
|
29718
30144
|
format: PropTypes.string,
|
|
@@ -30448,7 +30874,8 @@ const MafsGraph = props => {
|
|
|
30448
30874
|
value: {
|
|
30449
30875
|
range: state.range,
|
|
30450
30876
|
snapStep: state.snapStep,
|
|
30451
|
-
markings: props.markings
|
|
30877
|
+
markings: props.markings,
|
|
30878
|
+
showTooltips: !!props.showTooltips
|
|
30452
30879
|
}
|
|
30453
30880
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30454
30881
|
style: {
|
|
@@ -31710,9 +32137,9 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
31710
32137
|
// isClickToAddPoints() only applies to points and polygons
|
|
31711
32138
|
if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
|
|
31712
32139
|
if (this.props.graph.type === "point") {
|
|
31713
|
-
instructions =
|
|
32140
|
+
instructions = this.context.strings.addPoints;
|
|
31714
32141
|
} else if (this.props.graph.type === "polygon") {
|
|
31715
|
-
instructions =
|
|
32142
|
+
instructions = this.context.strings.addVertices;
|
|
31716
32143
|
}
|
|
31717
32144
|
} else {
|
|
31718
32145
|
instructions = undefined;
|
|
@@ -31752,6 +32179,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
31752
32179
|
}));
|
|
31753
32180
|
}
|
|
31754
32181
|
}
|
|
32182
|
+
LegacyInteractiveGraph.contextType = PerseusI18nContext;
|
|
31755
32183
|
LegacyInteractiveGraph.defaultProps = {
|
|
31756
32184
|
labels: ["x", "y"],
|
|
31757
32185
|
range: [[-10, 10], [-10, 10]],
|
|
@@ -31798,7 +32226,8 @@ class InteractiveGraph extends React.Component {
|
|
|
31798
32226
|
ref: this.mafsRef,
|
|
31799
32227
|
gridStep: gridStep,
|
|
31800
32228
|
snapStep: snapStep,
|
|
31801
|
-
box: box
|
|
32229
|
+
box: box,
|
|
32230
|
+
showTooltips: !!this.props.showTooltips
|
|
31802
32231
|
}));
|
|
31803
32232
|
}
|
|
31804
32233
|
return /*#__PURE__*/React.createElement(LegacyInteractiveGraph, _extends({
|
|
@@ -33340,6 +33769,9 @@ var globalStyles = /*#__PURE__*/Object.freeze({
|
|
|
33340
33769
|
});
|
|
33341
33770
|
|
|
33342
33771
|
const AnswerChoices = props => {
|
|
33772
|
+
const {
|
|
33773
|
+
strings
|
|
33774
|
+
} = usePerseusI18n();
|
|
33343
33775
|
const onAnswerChange = selected => {
|
|
33344
33776
|
const {
|
|
33345
33777
|
choices,
|
|
@@ -33357,6 +33789,7 @@ const AnswerChoices = props => {
|
|
|
33357
33789
|
value: content,
|
|
33358
33790
|
label: /*#__PURE__*/React.createElement(Renderer, {
|
|
33359
33791
|
content: content,
|
|
33792
|
+
strings: strings,
|
|
33360
33793
|
inline: true
|
|
33361
33794
|
})
|
|
33362
33795
|
}));
|
|
@@ -33386,14 +33819,13 @@ const AnswerChoices = props => {
|
|
|
33386
33819
|
}));
|
|
33387
33820
|
};
|
|
33388
33821
|
|
|
33389
|
-
const strings = {
|
|
33390
|
-
hideAnswersToggleLabel: i18n._("Hide answer choices")
|
|
33391
|
-
};
|
|
33392
|
-
|
|
33393
33822
|
const HideAnswersToggle = props => {
|
|
33394
33823
|
const idFactory = useUniqueIdWithMock();
|
|
33395
33824
|
const switchId = idFactory.get("hide-answers-toggle");
|
|
33396
33825
|
const labelId = idFactory.get("hide-answers-label");
|
|
33826
|
+
const {
|
|
33827
|
+
strings
|
|
33828
|
+
} = usePerseusI18n();
|
|
33397
33829
|
return /*#__PURE__*/React.createElement(View, {
|
|
33398
33830
|
style: styles$g.switchWrapper
|
|
33399
33831
|
}, /*#__PURE__*/React.createElement(Switch, {
|
|
@@ -33434,9 +33866,12 @@ const AnswerPill = props => {
|
|
|
33434
33866
|
hovered
|
|
33435
33867
|
} = props;
|
|
33436
33868
|
const idFactory = useUniqueIdWithMock();
|
|
33437
|
-
const
|
|
33438
|
-
|
|
33439
|
-
|
|
33869
|
+
const {
|
|
33870
|
+
strings
|
|
33871
|
+
} = usePerseusI18n();
|
|
33872
|
+
const answerString = selectedAnswers.length > 1 ? strings.answers({
|
|
33873
|
+
num: selectedAnswers.length
|
|
33874
|
+
}) : selectedAnswers[0];
|
|
33440
33875
|
|
|
33441
33876
|
// It should no longer be possible to interact with an answer after it
|
|
33442
33877
|
// has been labeled (answered) correctly.
|
|
@@ -33463,6 +33898,7 @@ const AnswerPill = props => {
|
|
|
33463
33898
|
style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
|
|
33464
33899
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
33465
33900
|
content: answerString,
|
|
33901
|
+
strings: strings,
|
|
33466
33902
|
inline: true
|
|
33467
33903
|
})));
|
|
33468
33904
|
};
|
|
@@ -33557,10 +33993,8 @@ class Marker extends React.Component {
|
|
|
33557
33993
|
const markerDisabled = showCorrectness === "correct";
|
|
33558
33994
|
const active = hovered || focused;
|
|
33559
33995
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
|
|
33560
|
-
style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive]
|
|
33561
|
-
|
|
33562
|
-
,
|
|
33563
|
-
"aria-label": markerDisabled ? i18n._("Correct!") : label
|
|
33996
|
+
style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive],
|
|
33997
|
+
"aria-label": markerDisabled ? this.context.strings.correctExcited : label
|
|
33564
33998
|
}, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React.createElement(AnswerPill, {
|
|
33565
33999
|
selectedAnswers: selected,
|
|
33566
34000
|
showCorrectness: showCorrectness,
|
|
@@ -33572,6 +34006,7 @@ class Marker extends React.Component {
|
|
|
33572
34006
|
}));
|
|
33573
34007
|
}
|
|
33574
34008
|
}
|
|
34009
|
+
Marker.contextType = PerseusI18nContext;
|
|
33575
34010
|
Marker.defaultProps = {
|
|
33576
34011
|
selected: []
|
|
33577
34012
|
};
|
|
@@ -34143,8 +34578,11 @@ class LabelImage extends React.Component {
|
|
|
34143
34578
|
multipleAnswers,
|
|
34144
34579
|
hideChoicesFromInstructions: hideChoices
|
|
34145
34580
|
} = this.props;
|
|
34146
|
-
const
|
|
34147
|
-
|
|
34581
|
+
const {
|
|
34582
|
+
strings
|
|
34583
|
+
} = this.context;
|
|
34584
|
+
const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
|
|
34585
|
+
const choicesString = strings.choices;
|
|
34148
34586
|
return /*#__PURE__*/React.createElement("div", {
|
|
34149
34587
|
className: classNames("perseus-label-image-widget-instructions", css(styles$d.instructions))
|
|
34150
34588
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -34155,7 +34593,8 @@ class LabelImage extends React.Component {
|
|
|
34155
34593
|
className: css(styles$d.instructionsChoice),
|
|
34156
34594
|
key: index
|
|
34157
34595
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
34158
|
-
content: choice
|
|
34596
|
+
content: choice,
|
|
34597
|
+
strings: strings
|
|
34159
34598
|
})))));
|
|
34160
34599
|
}
|
|
34161
34600
|
render() {
|
|
@@ -34206,6 +34645,7 @@ class LabelImage extends React.Component {
|
|
|
34206
34645
|
}));
|
|
34207
34646
|
}
|
|
34208
34647
|
}
|
|
34648
|
+
LabelImage.contextType = PerseusI18nContext;
|
|
34209
34649
|
const styles$d = StyleSheet.create({
|
|
34210
34650
|
instructions: {
|
|
34211
34651
|
paddingBottom: 16
|
|
@@ -34519,7 +34959,8 @@ class Draggable extends React.Component {
|
|
|
34519
34959
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
34520
34960
|
content: this.props.content,
|
|
34521
34961
|
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "draggable"),
|
|
34522
|
-
onRender: this.props.onRender
|
|
34962
|
+
onRender: this.props.onRender,
|
|
34963
|
+
strings: this.context.strings
|
|
34523
34964
|
}));
|
|
34524
34965
|
}
|
|
34525
34966
|
componentDidUpdate(prevProps) {
|
|
@@ -34544,6 +34985,7 @@ class Draggable extends React.Component {
|
|
|
34544
34985
|
}
|
|
34545
34986
|
}
|
|
34546
34987
|
}
|
|
34988
|
+
Draggable.contextType = PerseusI18nContext;
|
|
34547
34989
|
Draggable.defaultProps = {
|
|
34548
34990
|
includePadding: true,
|
|
34549
34991
|
type: ItemState.STATIC,
|
|
@@ -35104,12 +35546,14 @@ class Matcher extends React.Component {
|
|
|
35104
35546
|
className: css(styles$b.column, styles$b.columnLabel)
|
|
35105
35547
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35106
35548
|
content: this.props.labels[0] || "...",
|
|
35107
|
-
linterContext: this.props.linterContext
|
|
35549
|
+
linterContext: this.props.linterContext,
|
|
35550
|
+
strings: this.context.strings
|
|
35108
35551
|
})), /*#__PURE__*/React.createElement("th", {
|
|
35109
35552
|
className: css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
|
|
35110
35553
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35111
35554
|
content: this.props.labels[1] || "...",
|
|
35112
|
-
linterContext: this.props.linterContext
|
|
35555
|
+
linterContext: this.props.linterContext,
|
|
35556
|
+
strings: this.context.strings
|
|
35113
35557
|
}))), /*#__PURE__*/React.createElement("tr", {
|
|
35114
35558
|
className: css(styles$b.row)
|
|
35115
35559
|
}, /*#__PURE__*/React.createElement("td", {
|
|
@@ -35146,6 +35590,7 @@ class Matcher extends React.Component {
|
|
|
35146
35590
|
})))));
|
|
35147
35591
|
}
|
|
35148
35592
|
}
|
|
35593
|
+
Matcher.contextType = PerseusI18nContext;
|
|
35149
35594
|
Matcher.propTypes = {
|
|
35150
35595
|
apiOptions: ApiOptions.propTypes,
|
|
35151
35596
|
labels: PropTypes.array,
|
|
@@ -35431,8 +35876,58 @@ class Matrix extends React.Component {
|
|
|
35431
35876
|
};
|
|
35432
35877
|
};
|
|
35433
35878
|
this.simpleValidate = rubric => {
|
|
35434
|
-
|
|
35435
|
-
|
|
35879
|
+
return Matrix.validate(this.getUserInput(), rubric, this.context.strings);
|
|
35880
|
+
};
|
|
35881
|
+
}
|
|
35882
|
+
static validate(state, rubric, strings) {
|
|
35883
|
+
const solution = rubric.answers;
|
|
35884
|
+
const supplied = state.answers;
|
|
35885
|
+
const solutionSize = getMatrixSize(solution);
|
|
35886
|
+
const suppliedSize = getMatrixSize(supplied);
|
|
35887
|
+
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
35888
|
+
const createValidator = KhanAnswerTypes.number.createValidatorFunctional;
|
|
35889
|
+
let message = null;
|
|
35890
|
+
let hasEmptyCell = false;
|
|
35891
|
+
let incorrect = false;
|
|
35892
|
+
_(suppliedSize[0]).times(row => {
|
|
35893
|
+
_(suppliedSize[1]).times(col => {
|
|
35894
|
+
if (supplied[row][col] == null || supplied[row][col].toString().length === 0) {
|
|
35895
|
+
hasEmptyCell = true;
|
|
35896
|
+
}
|
|
35897
|
+
if (!incorrectSize) {
|
|
35898
|
+
const validator = createValidator(solution[row][col], {
|
|
35899
|
+
simplify: true
|
|
35900
|
+
}, strings);
|
|
35901
|
+
const result = validator(supplied[row][col]);
|
|
35902
|
+
if (result.message) {
|
|
35903
|
+
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
35904
|
+
message = result.message;
|
|
35905
|
+
}
|
|
35906
|
+
if (!result.correct) {
|
|
35907
|
+
incorrect = true;
|
|
35908
|
+
}
|
|
35909
|
+
}
|
|
35910
|
+
});
|
|
35911
|
+
});
|
|
35912
|
+
if (hasEmptyCell) {
|
|
35913
|
+
return {
|
|
35914
|
+
type: "invalid",
|
|
35915
|
+
message: strings.fillAllCells
|
|
35916
|
+
};
|
|
35917
|
+
}
|
|
35918
|
+
if (incorrectSize) {
|
|
35919
|
+
return {
|
|
35920
|
+
type: "points",
|
|
35921
|
+
earned: 0,
|
|
35922
|
+
total: 1,
|
|
35923
|
+
message: null
|
|
35924
|
+
};
|
|
35925
|
+
}
|
|
35926
|
+
return {
|
|
35927
|
+
type: "points",
|
|
35928
|
+
earned: incorrect ? 0 : 1,
|
|
35929
|
+
total: 1,
|
|
35930
|
+
message: message
|
|
35436
35931
|
};
|
|
35437
35932
|
}
|
|
35438
35933
|
componentDidMount() {
|
|
@@ -35474,7 +35969,8 @@ class Matrix extends React.Component {
|
|
|
35474
35969
|
className: "matrix-prefix"
|
|
35475
35970
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35476
35971
|
content: this.props.prefix,
|
|
35477
|
-
linterContext: this.props.linterContext
|
|
35972
|
+
linterContext: this.props.linterContext,
|
|
35973
|
+
strings: this.context.strings
|
|
35478
35974
|
})), /*#__PURE__*/React.createElement("div", {
|
|
35479
35975
|
className: "matrix-input"
|
|
35480
35976
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -35587,10 +36083,12 @@ class Matrix extends React.Component {
|
|
|
35587
36083
|
className: "matrix-suffix"
|
|
35588
36084
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35589
36085
|
content: this.props.suffix,
|
|
35590
|
-
linterContext: this.props.linterContext
|
|
36086
|
+
linterContext: this.props.linterContext,
|
|
36087
|
+
strings: this.context.strings
|
|
35591
36088
|
})));
|
|
35592
36089
|
}
|
|
35593
36090
|
}
|
|
36091
|
+
Matrix.contextType = PerseusI18nContext;
|
|
35594
36092
|
Matrix.defaultProps = {
|
|
35595
36093
|
matrixBoardSize: [3, 3],
|
|
35596
36094
|
answers: [[]],
|
|
@@ -35600,59 +36098,6 @@ Matrix.defaultProps = {
|
|
|
35600
36098
|
apiOptions: ApiOptions.defaults,
|
|
35601
36099
|
linterContext: linterContextDefault
|
|
35602
36100
|
};
|
|
35603
|
-
_.extend(Matrix, {
|
|
35604
|
-
validate: function (state, rubric) {
|
|
35605
|
-
const solution = rubric.answers;
|
|
35606
|
-
const supplied = state.answers;
|
|
35607
|
-
const solutionSize = getMatrixSize(solution);
|
|
35608
|
-
const suppliedSize = getMatrixSize(supplied);
|
|
35609
|
-
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
35610
|
-
const createValidator = KhanAnswerTypes.number.createValidatorFunctional;
|
|
35611
|
-
let message = null;
|
|
35612
|
-
let hasEmptyCell = false;
|
|
35613
|
-
let incorrect = false;
|
|
35614
|
-
_(suppliedSize[0]).times(row => {
|
|
35615
|
-
_(suppliedSize[1]).times(col => {
|
|
35616
|
-
if (supplied[row][col] == null || supplied[row][col].toString().length === 0) {
|
|
35617
|
-
hasEmptyCell = true;
|
|
35618
|
-
}
|
|
35619
|
-
if (!incorrectSize) {
|
|
35620
|
-
const validator = createValidator(solution[row][col], {
|
|
35621
|
-
simplify: true
|
|
35622
|
-
});
|
|
35623
|
-
const result = validator(supplied[row][col]);
|
|
35624
|
-
if (result.message) {
|
|
35625
|
-
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
35626
|
-
message = result.message;
|
|
35627
|
-
}
|
|
35628
|
-
if (!result.correct) {
|
|
35629
|
-
incorrect = true;
|
|
35630
|
-
}
|
|
35631
|
-
}
|
|
35632
|
-
});
|
|
35633
|
-
});
|
|
35634
|
-
if (hasEmptyCell) {
|
|
35635
|
-
return {
|
|
35636
|
-
type: "invalid",
|
|
35637
|
-
message: i18n._("Make sure you fill in all cells in the matrix.")
|
|
35638
|
-
};
|
|
35639
|
-
}
|
|
35640
|
-
if (incorrectSize) {
|
|
35641
|
-
return {
|
|
35642
|
-
type: "points",
|
|
35643
|
-
earned: 0,
|
|
35644
|
-
total: 1,
|
|
35645
|
-
message: null
|
|
35646
|
-
};
|
|
35647
|
-
}
|
|
35648
|
-
return {
|
|
35649
|
-
type: "points",
|
|
35650
|
-
earned: incorrect ? 0 : 1,
|
|
35651
|
-
total: 1,
|
|
35652
|
-
message: message
|
|
35653
|
-
};
|
|
35654
|
-
}
|
|
35655
|
-
});
|
|
35656
36101
|
const propTransform$1 = editorProps => {
|
|
35657
36102
|
// Remove answers before passing to widget
|
|
35658
36103
|
const blankAnswers = _(editorProps.matrixBoardSize[0]).times(function () {
|
|
@@ -36690,8 +37135,8 @@ class Molecule extends React.Component {
|
|
|
36690
37135
|
// eslint-disable-next-line react/no-string-refs
|
|
36691
37136
|
,
|
|
36692
37137
|
ref: "canvas"
|
|
36693
|
-
},
|
|
36694
|
-
content: this.props.smiles
|
|
37138
|
+
}, this.context.strings.molecularDrawing({
|
|
37139
|
+
content: this.props.smiles || ""
|
|
36695
37140
|
}));
|
|
36696
37141
|
if (this.state.error) {
|
|
36697
37142
|
content = /*#__PURE__*/React.createElement("div", {
|
|
@@ -36703,6 +37148,7 @@ class Molecule extends React.Component {
|
|
|
36703
37148
|
}, content);
|
|
36704
37149
|
}
|
|
36705
37150
|
}
|
|
37151
|
+
Molecule.contextType = PerseusI18nContext;
|
|
36706
37152
|
class MoleculeWidget extends React.Component {
|
|
36707
37153
|
constructor(...args) {
|
|
36708
37154
|
super(...args);
|
|
@@ -37165,18 +37611,21 @@ class NumberLine extends React.Component {
|
|
|
37165
37611
|
};
|
|
37166
37612
|
}
|
|
37167
37613
|
render() {
|
|
37614
|
+
const {
|
|
37615
|
+
strings
|
|
37616
|
+
} = this.context;
|
|
37168
37617
|
const divisionRange = this.props.divisionRange;
|
|
37169
37618
|
const divRangeString = divisionRange[0] + EN_DASH + divisionRange[1];
|
|
37170
37619
|
const invalidNumDivisions = this.props.numDivisions < divisionRange[0] || this.props.numDivisions > divisionRange[1];
|
|
37171
37620
|
const inequalityControls = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("input", {
|
|
37172
37621
|
type: "button",
|
|
37173
37622
|
className: "simple-button",
|
|
37174
|
-
value:
|
|
37623
|
+
value: strings.switchDirection,
|
|
37175
37624
|
onClick: this.handleReverse
|
|
37176
37625
|
}), /*#__PURE__*/React.createElement("input", {
|
|
37177
37626
|
type: "button",
|
|
37178
37627
|
className: "simple-button",
|
|
37179
|
-
value: _(["le", "ge"]).contains(this.props.rel) ?
|
|
37628
|
+
value: _(["le", "ge"]).contains(this.props.rel) ? strings.circleOpen : strings.circleFilled,
|
|
37180
37629
|
onClick: this.handleToggleStrict
|
|
37181
37630
|
}));
|
|
37182
37631
|
let tickCtrl;
|
|
@@ -37187,7 +37636,7 @@ class NumberLine extends React.Component {
|
|
|
37187
37636
|
} else {
|
|
37188
37637
|
Input = NumberInput;
|
|
37189
37638
|
}
|
|
37190
|
-
tickCtrl = /*#__PURE__*/React.createElement("label", null,
|
|
37639
|
+
tickCtrl = /*#__PURE__*/React.createElement("label", null, strings.numDivisions, " ", /*#__PURE__*/React.createElement(Input
|
|
37191
37640
|
// eslint-disable-next-line react/no-string-refs
|
|
37192
37641
|
, {
|
|
37193
37642
|
ref: "tick-ctrl",
|
|
@@ -37204,13 +37653,14 @@ class NumberLine extends React.Component {
|
|
|
37204
37653
|
className: "perseus-widget " + "perseus-widget-interactive-number-line"
|
|
37205
37654
|
}, tickCtrl, !this.isValid() ? /*#__PURE__*/React.createElement("div", {
|
|
37206
37655
|
className: "perseus-error"
|
|
37207
|
-
},
|
|
37656
|
+
}, "Invalid number line configuration.") : this.props.isTickCtrl && invalidNumDivisions ? /*#__PURE__*/React.createElement("div", {
|
|
37208
37657
|
className: "perseus-error"
|
|
37209
|
-
},
|
|
37658
|
+
}, strings.divisions({
|
|
37210
37659
|
divRangeString: divRangeString
|
|
37211
37660
|
})) : this._renderGraphie(), !this.props.static && this.props.isInequality && inequalityControls);
|
|
37212
37661
|
}
|
|
37213
37662
|
}
|
|
37663
|
+
NumberLine.contextType = PerseusI18nContext;
|
|
37214
37664
|
NumberLine.defaultProps = {
|
|
37215
37665
|
range: [0, 10],
|
|
37216
37666
|
labelStyle: "decimal",
|
|
@@ -37437,7 +37887,8 @@ class Card extends React.Component {
|
|
|
37437
37887
|
}, /*#__PURE__*/React.createElement("div", {
|
|
37438
37888
|
className: className.join(" ")
|
|
37439
37889
|
}, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
|
|
37440
|
-
linterContext: this.props.linterContext
|
|
37890
|
+
linterContext: this.props.linterContext,
|
|
37891
|
+
strings: this.context.strings
|
|
37441
37892
|
}))));
|
|
37442
37893
|
}
|
|
37443
37894
|
shouldComponentUpdate(nextProps, nextState) {
|
|
@@ -37490,6 +37941,7 @@ class Card extends React.Component {
|
|
|
37490
37941
|
document.removeEventListener("touchmove", this.onMouseMove);
|
|
37491
37942
|
}
|
|
37492
37943
|
}
|
|
37944
|
+
Card.contextType = PerseusI18nContext;
|
|
37493
37945
|
Card.propTypes = {
|
|
37494
37946
|
floating: PropTypes.bool.isRequired,
|
|
37495
37947
|
animating: PropTypes.bool,
|
|
@@ -38779,7 +39231,7 @@ class HighlightSetRenderer extends React.PureComponent {
|
|
|
38779
39231
|
}
|
|
38780
39232
|
const hoveredHighlight = this.props.highlights[hoveredHighlightKey];
|
|
38781
39233
|
return /*#__PURE__*/React.createElement(HighlightTooltip, {
|
|
38782
|
-
label:
|
|
39234
|
+
label: this.context.strings.removeHighlight,
|
|
38783
39235
|
focusNode: hoveredHighlight.domRange.endContainer,
|
|
38784
39236
|
focusOffset: hoveredHighlight.domRange.endOffset,
|
|
38785
39237
|
offsetParent: this.props.offsetParent,
|
|
@@ -38809,6 +39261,7 @@ class HighlightSetRenderer extends React.PureComponent {
|
|
|
38809
39261
|
})), this.props.editable && this._renderTooltip());
|
|
38810
39262
|
}
|
|
38811
39263
|
}
|
|
39264
|
+
HighlightSetRenderer.contextType = PerseusI18nContext;
|
|
38812
39265
|
|
|
38813
39266
|
/* eslint-disable react/no-unsafe */
|
|
38814
39267
|
class SelectionTracker extends React.PureComponent {
|
|
@@ -39009,7 +39462,7 @@ class HighlightingUI extends React.PureComponent {
|
|
|
39009
39462
|
onRemoveHighlight: this.props.onRemoveHighlight,
|
|
39010
39463
|
zIndexes: this.props.zIndexes
|
|
39011
39464
|
}), this._selectionIsValid(trackedSelection) && !userIsMouseSelecting && /*#__PURE__*/React.createElement(HighlightTooltip, {
|
|
39012
|
-
label:
|
|
39465
|
+
label: this.context.strings.addHighlight,
|
|
39013
39466
|
onClick: () => this._handleAddHighlight(trackedSelection.proposedHighlight),
|
|
39014
39467
|
focusNode: trackedSelection.focusNode,
|
|
39015
39468
|
focusOffset: trackedSelection.focusOffset,
|
|
@@ -39017,6 +39470,7 @@ class HighlightingUI extends React.PureComponent {
|
|
|
39017
39470
|
})));
|
|
39018
39471
|
}
|
|
39019
39472
|
}
|
|
39473
|
+
HighlightingUI.contextType = PerseusI18nContext;
|
|
39020
39474
|
|
|
39021
39475
|
/**
|
|
39022
39476
|
* This component, whenever its content updates, traverses the DOM to find
|
|
@@ -39307,16 +39761,30 @@ class RefStart extends React.Component {
|
|
|
39307
39761
|
render() {
|
|
39308
39762
|
return /*#__PURE__*/React.createElement("span", {
|
|
39309
39763
|
style: REF_STYLE
|
|
39310
|
-
},
|
|
39764
|
+
}, "_");
|
|
39311
39765
|
}
|
|
39312
39766
|
}
|
|
39313
39767
|
class RefEnd extends React.Component {
|
|
39314
39768
|
render() {
|
|
39315
39769
|
return /*#__PURE__*/React.createElement("span", {
|
|
39316
39770
|
style: REF_STYLE
|
|
39317
|
-
},
|
|
39771
|
+
}, "_");
|
|
39318
39772
|
}
|
|
39319
39773
|
}
|
|
39774
|
+
const AltText = ({
|
|
39775
|
+
id,
|
|
39776
|
+
number
|
|
39777
|
+
}) => {
|
|
39778
|
+
const {
|
|
39779
|
+
strings
|
|
39780
|
+
} = usePerseusI18n();
|
|
39781
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
39782
|
+
key: "alt-text",
|
|
39783
|
+
className: "perseus-sr-only"
|
|
39784
|
+
}, strings[id]({
|
|
39785
|
+
number
|
|
39786
|
+
}));
|
|
39787
|
+
};
|
|
39320
39788
|
const rules = {
|
|
39321
39789
|
newline: SimpleMarkdown.defaultRules.newline,
|
|
39322
39790
|
paragraph: SimpleMarkdown.defaultRules.paragraph,
|
|
@@ -39485,12 +39953,10 @@ const rules = {
|
|
|
39485
39953
|
"aria-hidden": "true"
|
|
39486
39954
|
}, /*#__PURE__*/React.createElement("span", {
|
|
39487
39955
|
style: SQUARE_LABEL_STYLE
|
|
39488
|
-
}, node.content)), /*#__PURE__*/React.createElement(
|
|
39489
|
-
|
|
39490
|
-
className: "perseus-sr-only"
|
|
39491
|
-
}, i18n.$_("[Marker for question %(number)s]", {
|
|
39956
|
+
}, node.content)), /*#__PURE__*/React.createElement(AltText, {
|
|
39957
|
+
id: "questionMarker",
|
|
39492
39958
|
number: node.content
|
|
39493
|
-
})
|
|
39959
|
+
}), node.space ? "\u00A0" : null];
|
|
39494
39960
|
}
|
|
39495
39961
|
},
|
|
39496
39962
|
circleLabel: {
|
|
@@ -39511,12 +39977,10 @@ const rules = {
|
|
|
39511
39977
|
"aria-hidden": true
|
|
39512
39978
|
}, /*#__PURE__*/React.createElement("span", {
|
|
39513
39979
|
style: CIRCLE_LABEL_STYLE
|
|
39514
|
-
}, node.content)), /*#__PURE__*/React.createElement(
|
|
39515
|
-
|
|
39516
|
-
className: "perseus-sr-only"
|
|
39517
|
-
}, i18n.$_("[Circle marker %(number)s]", {
|
|
39980
|
+
}, node.content)), /*#__PURE__*/React.createElement(AltText, {
|
|
39981
|
+
id: "circleMarker",
|
|
39518
39982
|
number: node.content
|
|
39519
|
-
})
|
|
39983
|
+
}), node.space ? "\u00A0" : null];
|
|
39520
39984
|
}
|
|
39521
39985
|
},
|
|
39522
39986
|
squareBracketRef: {
|
|
@@ -39536,12 +40000,10 @@ const rules = {
|
|
|
39536
40000
|
key: "visual-brackets",
|
|
39537
40001
|
className: "perseus-passage-bracket-label",
|
|
39538
40002
|
"aria-hidden": "true"
|
|
39539
|
-
}, "[", node.content, "]"), /*#__PURE__*/React.createElement(
|
|
39540
|
-
|
|
39541
|
-
className: "perseus-sr-only"
|
|
39542
|
-
}, i18n.$_("[Sentence %(number)s]", {
|
|
40003
|
+
}, "[", node.content, "]"), /*#__PURE__*/React.createElement(AltText, {
|
|
40004
|
+
id: "sentenceMarker",
|
|
39543
40005
|
number: node.content
|
|
39544
|
-
})
|
|
40006
|
+
}), node.space ? "\u00A0" : null];
|
|
39545
40007
|
}
|
|
39546
40008
|
},
|
|
39547
40009
|
highlight: {
|
|
@@ -39932,15 +40394,18 @@ class Passage extends React.Component {
|
|
|
39932
40394
|
_renderInstructions(parseState) {
|
|
39933
40395
|
const firstQuestionNumber = parseState.firstQuestionRef;
|
|
39934
40396
|
const firstSentenceRef = parseState.firstSentenceRef;
|
|
40397
|
+
const {
|
|
40398
|
+
strings
|
|
40399
|
+
} = this.context;
|
|
39935
40400
|
let instructions = "";
|
|
39936
40401
|
if (firstQuestionNumber) {
|
|
39937
|
-
instructions +=
|
|
40402
|
+
instructions += strings.symbolPassage({
|
|
39938
40403
|
questionSymbol: "[[" + firstQuestionNumber + "]]",
|
|
39939
40404
|
questionNumber: firstQuestionNumber
|
|
39940
40405
|
});
|
|
39941
40406
|
}
|
|
39942
40407
|
if (firstSentenceRef) {
|
|
39943
|
-
instructions +=
|
|
40408
|
+
instructions += strings.symbolQuestion({
|
|
39944
40409
|
sentenceSymbol: "[" + firstSentenceRef + "]"
|
|
39945
40410
|
});
|
|
39946
40411
|
}
|
|
@@ -39986,6 +40451,9 @@ class Passage extends React.Component {
|
|
|
39986
40451
|
return PassageMarkdown.output(parsed);
|
|
39987
40452
|
}
|
|
39988
40453
|
render() {
|
|
40454
|
+
const {
|
|
40455
|
+
strings
|
|
40456
|
+
} = this.context;
|
|
39989
40457
|
let lineNumbers;
|
|
39990
40458
|
const nLines = this.state.nLines;
|
|
39991
40459
|
if (this.props.showLineNumbers && nLines) {
|
|
@@ -39994,9 +40462,7 @@ class Passage extends React.Component {
|
|
|
39994
40462
|
lineNumbers = _.range(1, nLines + 1).map(lineN => {
|
|
39995
40463
|
const lineAt = lineN + this.state.startLineNumbersAfter;
|
|
39996
40464
|
if (lineAt === 4) {
|
|
39997
|
-
|
|
39998
|
-
// I18N: a label next to a reading passage to denote the line number
|
|
39999
|
-
const translatedLine = i18n._("Line ");
|
|
40465
|
+
const translatedLine = strings.lineLabel;
|
|
40000
40466
|
return /*#__PURE__*/React.createElement("span", {
|
|
40001
40467
|
key: "line-marker",
|
|
40002
40468
|
className: "line-marker"
|
|
@@ -40026,13 +40492,14 @@ class Passage extends React.Component {
|
|
|
40026
40492
|
className: "passage-title"
|
|
40027
40493
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
40028
40494
|
content: this.props.passageTitle,
|
|
40029
|
-
linterContext: this.props.linterContext
|
|
40495
|
+
linterContext: this.props.linterContext,
|
|
40496
|
+
strings: strings
|
|
40030
40497
|
})), lineNumbers && /*#__PURE__*/React.createElement("div", {
|
|
40031
40498
|
className: "line-numbers",
|
|
40032
40499
|
"aria-hidden": true
|
|
40033
40500
|
}, lineNumbers), !hasTitle && /*#__PURE__*/React.createElement("h3", {
|
|
40034
40501
|
className: "perseus-sr-only"
|
|
40035
|
-
},
|
|
40502
|
+
}, strings.beginningPassage), /*#__PURE__*/React.createElement("div", {
|
|
40036
40503
|
className: "passage-text"
|
|
40037
40504
|
}, this.shouldRenderJipt() ?
|
|
40038
40505
|
/*#__PURE__*/
|
|
@@ -40040,18 +40507,20 @@ class Passage extends React.Component {
|
|
|
40040
40507
|
// content to a <Renderer /> which knows how
|
|
40041
40508
|
// to handle rendering JIPT text.
|
|
40042
40509
|
React.createElement(Renderer, {
|
|
40043
|
-
content: this.props.passageText
|
|
40510
|
+
content: this.props.passageText,
|
|
40511
|
+
strings: strings
|
|
40044
40512
|
}) : this._renderContent(parsedContent)), this._hasFootnotes() && [/*#__PURE__*/React.createElement("h4", {
|
|
40045
40513
|
key: "footnote-start",
|
|
40046
40514
|
className: "perseus-sr-only"
|
|
40047
|
-
},
|
|
40515
|
+
}, strings.beginningFootnotes), /*#__PURE__*/React.createElement("div", {
|
|
40048
40516
|
key: "footnotes",
|
|
40049
40517
|
className: "footnotes"
|
|
40050
40518
|
}, this._renderFootnotes())], /*#__PURE__*/React.createElement("div", {
|
|
40051
40519
|
className: "perseus-sr-only"
|
|
40052
|
-
},
|
|
40520
|
+
}, strings.endPassage))));
|
|
40053
40521
|
}
|
|
40054
40522
|
}
|
|
40523
|
+
Passage.contextType = PerseusI18nContext;
|
|
40055
40524
|
Passage.defaultProps = {
|
|
40056
40525
|
passageTitle: "",
|
|
40057
40526
|
passageText: "",
|
|
@@ -40102,10 +40571,12 @@ class PassageRefTarget extends React.Component {
|
|
|
40102
40571
|
// inline={true}
|
|
40103
40572
|
,
|
|
40104
40573
|
apiOptions: this.props.apiOptions,
|
|
40105
|
-
linterContext: this.props.linterContext
|
|
40574
|
+
linterContext: this.props.linterContext,
|
|
40575
|
+
strings: this.context.strings
|
|
40106
40576
|
});
|
|
40107
40577
|
}
|
|
40108
40578
|
}
|
|
40579
|
+
PassageRefTarget.contextType = PerseusI18nContext;
|
|
40109
40580
|
PassageRefTarget.defaultProps = {
|
|
40110
40581
|
content: "",
|
|
40111
40582
|
linterContext: linterContextDefault
|
|
@@ -40289,11 +40760,11 @@ class Plotter extends React.Component {
|
|
|
40289
40760
|
}
|
|
40290
40761
|
}
|
|
40291
40762
|
if ((isBar || isLine) && isMobile && !this.props.static) {
|
|
40292
|
-
self.graphie.dragPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
40763
|
+
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");
|
|
40293
40764
|
}
|
|
40294
40765
|
self.setupCategories(config);
|
|
40295
40766
|
if (isTiledPlot && isMobile) {
|
|
40296
|
-
self.graphie.dotPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
40767
|
+
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");
|
|
40297
40768
|
}
|
|
40298
40769
|
if (isTiledPlot) {
|
|
40299
40770
|
self.drawPicHeights(self.state.values, prevState.values);
|
|
@@ -40908,6 +41379,7 @@ class Plotter extends React.Component {
|
|
|
40908
41379
|
});
|
|
40909
41380
|
}
|
|
40910
41381
|
}
|
|
41382
|
+
Plotter.contextType = PerseusI18nContext;
|
|
40911
41383
|
Plotter.defaultProps = {
|
|
40912
41384
|
type: "bar",
|
|
40913
41385
|
labels: ["", ""],
|
|
@@ -41179,7 +41651,7 @@ class Table extends React.Component {
|
|
|
41179
41651
|
};
|
|
41180
41652
|
this.simpleValidate = rubric => {
|
|
41181
41653
|
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Table'.
|
|
41182
|
-
return Table.validate(this.getUserInput(), rubric);
|
|
41654
|
+
return Table.validate(this.getUserInput(), rubric, this.context.strings);
|
|
41183
41655
|
};
|
|
41184
41656
|
this._handleFocus = inputPath => {
|
|
41185
41657
|
this.props.onFocus(inputPath);
|
|
@@ -41284,7 +41756,8 @@ class Table extends React.Component {
|
|
|
41284
41756
|
key: i
|
|
41285
41757
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
41286
41758
|
content: header,
|
|
41287
|
-
linterContext: this.props.linterContext
|
|
41759
|
+
linterContext: this.props.linterContext,
|
|
41760
|
+
strings: this.context.strings
|
|
41288
41761
|
}));
|
|
41289
41762
|
}))), /*#__PURE__*/React.createElement("tbody", null, _(rows).times(r => {
|
|
41290
41763
|
return /*#__PURE__*/React.createElement("tr", {
|
|
@@ -41306,6 +41779,7 @@ class Table extends React.Component {
|
|
|
41306
41779
|
})));
|
|
41307
41780
|
}
|
|
41308
41781
|
}
|
|
41782
|
+
Table.contextType = PerseusI18nContext;
|
|
41309
41783
|
Table.propTypes = {
|
|
41310
41784
|
answers: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)),
|
|
41311
41785
|
editableHeaders: PropTypes.bool,
|
|
@@ -41333,7 +41807,7 @@ Table.defaultProps = function () {
|
|
|
41333
41807
|
};
|
|
41334
41808
|
}();
|
|
41335
41809
|
_.extend(Table, {
|
|
41336
|
-
validate: function (state, rubric) {
|
|
41810
|
+
validate: function (state, rubric, strings) {
|
|
41337
41811
|
const filterNonEmpty = function filterNonEmpty(table) {
|
|
41338
41812
|
return _.filter(table, function (row) {
|
|
41339
41813
|
// Check if row has a cell that is nonempty
|
|
@@ -41371,7 +41845,7 @@ _.extend(Table, {
|
|
|
41371
41845
|
const cellSolution = rowSolution[i];
|
|
41372
41846
|
const validator = createValidator(cellSolution, {
|
|
41373
41847
|
simplify: true
|
|
41374
|
-
});
|
|
41848
|
+
}, strings);
|
|
41375
41849
|
const result = validator(cellSupplied);
|
|
41376
41850
|
if (result.message) {
|
|
41377
41851
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
@@ -42134,7 +42608,7 @@ class OldUnitInput extends React.Component {
|
|
|
42134
42608
|
});
|
|
42135
42609
|
};
|
|
42136
42610
|
this.simpleValidate = (rubric, onInputError) => {
|
|
42137
|
-
return OldUnitInput.validate(this.getUserInput(), rubric);
|
|
42611
|
+
return OldUnitInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
42138
42612
|
};
|
|
42139
42613
|
this.getUserInput = () => {
|
|
42140
42614
|
return this.props.value;
|
|
@@ -42187,13 +42661,13 @@ class OldUnitInput extends React.Component {
|
|
|
42187
42661
|
return "unit";
|
|
42188
42662
|
};
|
|
42189
42663
|
}
|
|
42190
|
-
static validate(userInput, rubric) {
|
|
42664
|
+
static validate(userInput, rubric, strings) {
|
|
42191
42665
|
const answer = KAS.unitParse(rubric.value).expr;
|
|
42192
42666
|
const guess = KAS.unitParse(userInput);
|
|
42193
42667
|
if (!guess.parsed) {
|
|
42194
42668
|
return {
|
|
42195
42669
|
type: "invalid",
|
|
42196
|
-
message:
|
|
42670
|
+
message: strings.dontUnderstandUnits
|
|
42197
42671
|
};
|
|
42198
42672
|
}
|
|
42199
42673
|
|
|
@@ -42208,8 +42682,7 @@ class OldUnitInput extends React.Component {
|
|
|
42208
42682
|
const sigfigs = rubric.sigfigs;
|
|
42209
42683
|
const sigfigsCorrect = countSigfigs(guess.coefficient) === sigfigs;
|
|
42210
42684
|
if (!sigfigsCorrect) {
|
|
42211
|
-
|
|
42212
|
-
message = i18n._("Check your significant figures.");
|
|
42685
|
+
message = strings.checkSigFigs;
|
|
42213
42686
|
}
|
|
42214
42687
|
|
|
42215
42688
|
// now we need to check that the answer is correct to the precision we
|
|
@@ -42228,8 +42701,7 @@ class OldUnitInput extends React.Component {
|
|
|
42228
42701
|
numericallyCorrect = false;
|
|
42229
42702
|
}
|
|
42230
42703
|
if (!numericallyCorrect) {
|
|
42231
|
-
|
|
42232
|
-
message = i18n._("That answer is numerically incorrect.");
|
|
42704
|
+
message = strings.answerNumericallyIncorrect;
|
|
42233
42705
|
}
|
|
42234
42706
|
let kasCorrect;
|
|
42235
42707
|
const guessUnit = primUnits(guess.expr.simplify());
|
|
@@ -42249,8 +42721,7 @@ class OldUnitInput extends React.Component {
|
|
|
42249
42721
|
});
|
|
42250
42722
|
}
|
|
42251
42723
|
if (!kasCorrect) {
|
|
42252
|
-
|
|
42253
|
-
message = i18n._("Check your units.");
|
|
42724
|
+
message = strings.checkUnits;
|
|
42254
42725
|
}
|
|
42255
42726
|
const correct = kasCorrect && numericallyCorrect && sigfigsCorrect;
|
|
42256
42727
|
return {
|
|
@@ -42299,12 +42770,13 @@ class OldUnitInput extends React.Component {
|
|
|
42299
42770
|
style: {
|
|
42300
42771
|
display: "none"
|
|
42301
42772
|
}
|
|
42302
|
-
},
|
|
42773
|
+
}, this.context.strings.dontUnderstand));
|
|
42303
42774
|
}
|
|
42304
42775
|
}
|
|
42305
42776
|
|
|
42306
42777
|
// Extract the primitive units from a unit expression. This first simplifies
|
|
42307
42778
|
// `expr` to a `Mul` like "5 kg m / s^2" then removes the first term.
|
|
42779
|
+
OldUnitInput.contextType = PerseusI18nContext;
|
|
42308
42780
|
OldUnitInput.defaultProps = {
|
|
42309
42781
|
apiOptions: ApiOptions.defaults,
|
|
42310
42782
|
value: ""
|
|
@@ -42355,9 +42827,12 @@ const VideoTranscriptLink = props => {
|
|
|
42355
42827
|
// which is used by our GraphQL framework.
|
|
42356
42828
|
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'VideoKind'.
|
|
42357
42829
|
const result = useVideo(id, kind);
|
|
42830
|
+
const {
|
|
42831
|
+
strings
|
|
42832
|
+
} = usePerseusI18n();
|
|
42358
42833
|
switch (result.status) {
|
|
42359
42834
|
case "loading":
|
|
42360
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42835
|
+
return /*#__PURE__*/React.createElement(View, null, strings.loading);
|
|
42361
42836
|
case "success":
|
|
42362
42837
|
{
|
|
42363
42838
|
var _result$data;
|
|
@@ -42370,14 +42845,14 @@ const VideoTranscriptLink = props => {
|
|
|
42370
42845
|
href: "/transcript/" + ((video == null ? void 0 : video.contentId) || "videoNotFound"),
|
|
42371
42846
|
target: "_blank",
|
|
42372
42847
|
className: "visited-no-recolor"
|
|
42373
|
-
},
|
|
42848
|
+
}, strings.videoTranscript));
|
|
42374
42849
|
}
|
|
42375
42850
|
case "error":
|
|
42376
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42851
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42377
42852
|
case "aborted":
|
|
42378
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42853
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42379
42854
|
default:
|
|
42380
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42855
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42381
42856
|
}
|
|
42382
42857
|
};
|
|
42383
42858
|
const styles$4 = StyleSheet.create({
|
|
@@ -42469,7 +42944,7 @@ class Video extends React.Component {
|
|
|
42469
42944
|
key: location + this.props.alignment
|
|
42470
42945
|
}, /*#__PURE__*/React.createElement(View, {
|
|
42471
42946
|
style: a11y.srOnly
|
|
42472
|
-
},
|
|
42947
|
+
}, this.context.strings.videoWrapper), /*#__PURE__*/React.createElement("iframe", {
|
|
42473
42948
|
// TODO(joshuan): Consider not using iframes when we're
|
|
42474
42949
|
// loading this from webapp. This iframe is problematic
|
|
42475
42950
|
// for screenreaders.
|
|
@@ -42484,6 +42959,7 @@ class Video extends React.Component {
|
|
|
42484
42959
|
}));
|
|
42485
42960
|
}
|
|
42486
42961
|
}
|
|
42962
|
+
Video.contextType = PerseusI18nContext;
|
|
42487
42963
|
var Video$1 = {
|
|
42488
42964
|
name: "video",
|
|
42489
42965
|
displayName: "Video",
|
|
@@ -42533,7 +43009,7 @@ const init = function init(options) {
|
|
|
42533
43009
|
|
|
42534
43010
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42535
43011
|
const libName = "@khanacademy/perseus";
|
|
42536
|
-
const libVersion = "
|
|
43012
|
+
const libVersion = "22.0.0";
|
|
42537
43013
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42538
43014
|
|
|
42539
43015
|
const apiVersion = {
|
|
@@ -42699,8 +43175,9 @@ class ArticleRenderer extends React.Component {
|
|
|
42699
43175
|
}
|
|
42700
43176
|
}),
|
|
42701
43177
|
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "article"),
|
|
42702
|
-
legacyPerseusLint: this.props.legacyPerseusLint
|
|
42703
|
-
|
|
43178
|
+
legacyPerseusLint: this.props.legacyPerseusLint,
|
|
43179
|
+
strings: this.context.strings
|
|
43180
|
+
})));
|
|
42704
43181
|
});
|
|
42705
43182
|
return /*#__PURE__*/React.createElement("div", {
|
|
42706
43183
|
className: classes
|
|
@@ -42709,6 +43186,7 @@ class ArticleRenderer extends React.Component {
|
|
|
42709
43186
|
}, sections));
|
|
42710
43187
|
}
|
|
42711
43188
|
}
|
|
43189
|
+
ArticleRenderer.contextType = PerseusI18nContext;
|
|
42712
43190
|
ArticleRenderer.defaultProps = {
|
|
42713
43191
|
apiOptions: ApiOptions.defaults,
|
|
42714
43192
|
useNewStyles: false,
|
|
@@ -42761,7 +43239,7 @@ class HintRenderer extends React.Component {
|
|
|
42761
43239
|
tabIndex: "-1"
|
|
42762
43240
|
}, !apiOptions.isMobile && /*#__PURE__*/React.createElement("span", {
|
|
42763
43241
|
className: "perseus-sr-only"
|
|
42764
|
-
},
|
|
43242
|
+
}, this.context.strings.hintPos({
|
|
42765
43243
|
pos: pos + 1
|
|
42766
43244
|
})), !apiOptions.isMobile && totalHints != null && pos != null && /*#__PURE__*/React.createElement("span", {
|
|
42767
43245
|
className: "perseus-hint-label",
|
|
@@ -42778,11 +43256,13 @@ class HintRenderer extends React.Component {
|
|
|
42778
43256
|
images: hint.images,
|
|
42779
43257
|
apiOptions: rendererApiOptions,
|
|
42780
43258
|
findExternalWidgets: this.props.findExternalWidgets,
|
|
42781
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hint")
|
|
43259
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hint"),
|
|
43260
|
+
strings: this.context.strings
|
|
42782
43261
|
}))
|
|
42783
43262
|
);
|
|
42784
43263
|
}
|
|
42785
43264
|
}
|
|
43265
|
+
HintRenderer.contextType = PerseusI18nContext;
|
|
42786
43266
|
HintRenderer.defaultProps = {
|
|
42787
43267
|
linterContext: PerseusLinter.linterContextDefault
|
|
42788
43268
|
};
|
|
@@ -42964,7 +43444,7 @@ class HintsRenderer extends React.Component {
|
|
|
42964
43444
|
className: classNames$1
|
|
42965
43445
|
}, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React.createElement("div", {
|
|
42966
43446
|
className: css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
|
|
42967
|
-
},
|
|
43447
|
+
}, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React.createElement("button", {
|
|
42968
43448
|
// @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>'.
|
|
42969
43449
|
rel: "button",
|
|
42970
43450
|
className: css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
|
|
@@ -42979,9 +43459,10 @@ class HintsRenderer extends React.Component {
|
|
|
42979
43459
|
className: css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
|
|
42980
43460
|
}, "+"), /*#__PURE__*/React.createElement("span", {
|
|
42981
43461
|
className: css(styles$2.getAnotherHintText)
|
|
42982
|
-
},
|
|
43462
|
+
}, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
|
|
42983
43463
|
}
|
|
42984
43464
|
}
|
|
43465
|
+
HintsRenderer.contextType = PerseusI18nContext;
|
|
42985
43466
|
HintsRenderer.defaultProps = {
|
|
42986
43467
|
linterContext: PerseusLinter.linterContextDefault
|
|
42987
43468
|
};
|
|
@@ -43372,14 +43853,16 @@ class ServerItemRenderer extends React.Component {
|
|
|
43372
43853
|
content: this.props.item.question.content,
|
|
43373
43854
|
widgets: this.props.item.question.widgets,
|
|
43374
43855
|
images: this.props.item.question.images,
|
|
43375
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "question")
|
|
43856
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "question"),
|
|
43857
|
+
strings: this.context.strings
|
|
43376
43858
|
}, this.props.dependencies)));
|
|
43377
43859
|
const hintsRenderer = /*#__PURE__*/React.createElement(HintsRenderer, {
|
|
43378
43860
|
hints: this.props.item.hints,
|
|
43379
43861
|
hintsVisible: this.props.hintsVisible,
|
|
43380
43862
|
apiOptions: apiOptions,
|
|
43381
43863
|
ref: elem => this.hintsRenderer = elem,
|
|
43382
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hints")
|
|
43864
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hints"),
|
|
43865
|
+
strings: this.context.strings
|
|
43383
43866
|
});
|
|
43384
43867
|
return /*#__PURE__*/React.createElement(DependenciesContext.Provider, {
|
|
43385
43868
|
value: this.props.dependencies
|
|
@@ -43393,6 +43876,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
43393
43876
|
}, hintsRenderer)));
|
|
43394
43877
|
}
|
|
43395
43878
|
}
|
|
43879
|
+
ServerItemRenderer.contextType = PerseusI18nContext;
|
|
43396
43880
|
ServerItemRenderer.defaultProps = {
|
|
43397
43881
|
apiOptions: {},
|
|
43398
43882
|
// a deep default is done in `this.update()`
|
|
@@ -43555,115 +44039,6 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
43555
44039
|
perseusFrameBorderWidth: perseusFrameBorderWidth
|
|
43556
44040
|
});
|
|
43557
44041
|
|
|
43558
|
-
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
43559
|
-
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
43560
|
-
|
|
43561
|
-
// Range is replaced within this file with Interval, but it is used elsewhere
|
|
43562
|
-
// and exported from the package, so we need to keep it around.
|
|
43563
|
-
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
43564
|
-
const ItemExtras = [
|
|
43565
|
-
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
43566
|
-
"calculator",
|
|
43567
|
-
// The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
|
|
43568
|
-
"chi2Table",
|
|
43569
|
-
// The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
|
|
43570
|
-
"financialCalculatorMonthlyPayment",
|
|
43571
|
-
// The user might benefit from a total amount calculator. Provided on Khan Academy when true
|
|
43572
|
-
"financialCalculatorTotalAmount",
|
|
43573
|
-
// The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
|
|
43574
|
-
"financialCalculatorTimeToPayOff",
|
|
43575
|
-
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
43576
|
-
"periodicTable",
|
|
43577
|
-
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
43578
|
-
"periodicTableWithKey",
|
|
43579
|
-
// The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
|
|
43580
|
-
"tTable",
|
|
43581
|
-
// The user might benefit from using a statistics Z Table like https://www.ztable.net/
|
|
43582
|
-
"zTable"];
|
|
43583
|
-
|
|
43584
|
-
// prettier-ignore
|
|
43585
|
-
|
|
43586
|
-
// prettier-ignore
|
|
43587
|
-
|
|
43588
|
-
// prettier-ignore
|
|
43589
|
-
|
|
43590
|
-
// prettier-ignore
|
|
43591
|
-
|
|
43592
|
-
// prettier-ignore
|
|
43593
|
-
|
|
43594
|
-
// prettier-ignore
|
|
43595
|
-
|
|
43596
|
-
// prettier-ignore
|
|
43597
|
-
|
|
43598
|
-
// prettier-ignore
|
|
43599
|
-
|
|
43600
|
-
// prettier-ignore
|
|
43601
|
-
|
|
43602
|
-
// prettier-ignore
|
|
43603
|
-
|
|
43604
|
-
// prettier-ignore
|
|
43605
|
-
|
|
43606
|
-
// prettier-ignore
|
|
43607
|
-
|
|
43608
|
-
// prettier-ignore
|
|
43609
|
-
|
|
43610
|
-
// prettier-ignore
|
|
43611
|
-
|
|
43612
|
-
// prettier-ignore
|
|
43613
|
-
|
|
43614
|
-
// prettier-ignore
|
|
43615
|
-
|
|
43616
|
-
// prettier-ignore
|
|
43617
|
-
|
|
43618
|
-
// prettier-ignore
|
|
43619
|
-
|
|
43620
|
-
// prettier-ignore
|
|
43621
|
-
|
|
43622
|
-
// prettier-ignore
|
|
43623
|
-
|
|
43624
|
-
// prettier-ignore
|
|
43625
|
-
|
|
43626
|
-
// prettier-ignore
|
|
43627
|
-
|
|
43628
|
-
// prettier-ignore
|
|
43629
|
-
|
|
43630
|
-
// prettier-ignore
|
|
43631
|
-
|
|
43632
|
-
// prettier-ignore
|
|
43633
|
-
|
|
43634
|
-
// prettier-ignore
|
|
43635
|
-
|
|
43636
|
-
// prettier-ignore
|
|
43637
|
-
|
|
43638
|
-
// prettier-ignore
|
|
43639
|
-
|
|
43640
|
-
// prettier-ignore
|
|
43641
|
-
|
|
43642
|
-
// prettier-ignore
|
|
43643
|
-
|
|
43644
|
-
// prettier-ignore
|
|
43645
|
-
|
|
43646
|
-
// prettier-ignore
|
|
43647
|
-
|
|
43648
|
-
// prettier-ignore
|
|
43649
|
-
|
|
43650
|
-
// prettier-ignore
|
|
43651
|
-
|
|
43652
|
-
// prettier-ignore
|
|
43653
|
-
|
|
43654
|
-
// prettier-ignore
|
|
43655
|
-
|
|
43656
|
-
//prettier-ignore
|
|
43657
|
-
|
|
43658
|
-
// A background image applied to various widgets.
|
|
43659
|
-
|
|
43660
|
-
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
43661
|
-
|
|
43662
|
-
// 2D range: xMin, xMax, yMin, yMax
|
|
43663
|
-
|
|
43664
|
-
const lockedFigureColors = ["purple", "blue", "teal", "green", "gold", "red", "pink"];
|
|
43665
|
-
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
43666
|
-
|
|
43667
44042
|
/**
|
|
43668
44043
|
* Traverses a {content, widgets, images} renderer props object,
|
|
43669
44044
|
* such as `itemData.question`
|
|
@@ -44272,7 +44647,9 @@ class MultiRenderer extends React.Component {
|
|
|
44272
44647
|
// `<Renderer>`. I'm not sure how else to do this.
|
|
44273
44648
|
const _this$props = this.props,
|
|
44274
44649
|
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
44275
|
-
return otherProps
|
|
44650
|
+
return _extends({}, otherProps, {
|
|
44651
|
+
strings: this.context.strings
|
|
44652
|
+
});
|
|
44276
44653
|
}
|
|
44277
44654
|
|
|
44278
44655
|
/**
|
|
@@ -44523,7 +44900,7 @@ class MultiRenderer extends React.Component {
|
|
|
44523
44900
|
if (this.state.renderError) {
|
|
44524
44901
|
return /*#__PURE__*/React.createElement("div", {
|
|
44525
44902
|
className: css(styles.error)
|
|
44526
|
-
},
|
|
44903
|
+
}, this.context.strings.errorRendering({
|
|
44527
44904
|
error: String(this.state.renderError)
|
|
44528
44905
|
}));
|
|
44529
44906
|
}
|
|
@@ -44537,6 +44914,7 @@ class MultiRenderer extends React.Component {
|
|
|
44537
44914
|
}));
|
|
44538
44915
|
}
|
|
44539
44916
|
}
|
|
44917
|
+
MultiRenderer.contextType = PerseusI18nContext;
|
|
44540
44918
|
const styles = StyleSheet.create({
|
|
44541
44919
|
error: {
|
|
44542
44920
|
color: "red"
|
|
@@ -45632,5 +46010,5 @@ const EditorJsonify = {
|
|
|
45632
46010
|
}
|
|
45633
46011
|
};
|
|
45634
46012
|
|
|
45635
|
-
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, violatingWidgets, allWidgets as widgets };
|
|
46013
|
+
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
45636
46014
|
//# sourceMappingURL=index.js.map
|