@khanacademy/perseus 21.6.0 → 22.0.1
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 +883 -496
- 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 +1099 -534
- 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/graphs/components/arrowhead.d.ts +1 -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
|
};
|
|
@@ -2069,9 +2320,10 @@ class Expression extends React.Component {
|
|
|
2069
2320
|
this.refs.input.focus();
|
|
2070
2321
|
};
|
|
2071
2322
|
this.blurInputPath = inputPath => {
|
|
2323
|
+
var _this$refs$input;
|
|
2072
2324
|
// eslint-disable-next-line react/no-string-refs
|
|
2073
2325
|
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
2074
|
-
this.refs.input.blur();
|
|
2326
|
+
(_this$refs$input = this.refs.input) == null || _this$refs$input.blur();
|
|
2075
2327
|
};
|
|
2076
2328
|
this.getInputPaths = () => {
|
|
2077
2329
|
// The widget itself is an input, so we return a single empty list to
|
|
@@ -2111,10 +2363,10 @@ class Expression extends React.Component {
|
|
|
2111
2363
|
*/
|
|
2112
2364
|
static validate(userInput, rubric,
|
|
2113
2365
|
// @ts-expect-error - TS2322 - Type '() => void' is not assignable to type 'OnInputErrorFunctionType'.
|
|
2114
|
-
onInputError = function () {}) {
|
|
2366
|
+
onInputError = function () {}, strings, locale) {
|
|
2115
2367
|
const options = _.clone(rubric);
|
|
2116
2368
|
_.extend(options, {
|
|
2117
|
-
decimal_separator:
|
|
2369
|
+
decimal_separator: getDecimalSeparator(locale)
|
|
2118
2370
|
});
|
|
2119
2371
|
const createValidator = answer => {
|
|
2120
2372
|
// We give options to KAS.parse here because it is parsing the
|
|
@@ -2137,7 +2389,7 @@ class Expression extends React.Component {
|
|
|
2137
2389
|
return KhanAnswerTypes.expression.createValidatorFunctional(expression.expr, _({}).extend(options, {
|
|
2138
2390
|
simplify: answer.simplify,
|
|
2139
2391
|
form: answer.form
|
|
2140
|
-
}));
|
|
2392
|
+
}), strings);
|
|
2141
2393
|
};
|
|
2142
2394
|
|
|
2143
2395
|
// Find the first answer form that matches the user's input and that
|
|
@@ -2280,6 +2532,10 @@ class Expression extends React.Component {
|
|
|
2280
2532
|
"perseus-widget-expression": true,
|
|
2281
2533
|
"show-error-tooltip": this.state.showErrorTooltip
|
|
2282
2534
|
});
|
|
2535
|
+
const {
|
|
2536
|
+
ERROR_MESSAGE,
|
|
2537
|
+
ERROR_TITLE
|
|
2538
|
+
} = this.context.strings;
|
|
2283
2539
|
return /*#__PURE__*/React.createElement("div", {
|
|
2284
2540
|
className: className,
|
|
2285
2541
|
onBlur: () => this.state.invalid && this.setState({
|
|
@@ -2328,6 +2584,7 @@ class Expression extends React.Component {
|
|
|
2328
2584
|
* to be included as keys on the keypad. These are scraped from the answer
|
|
2329
2585
|
* forms.
|
|
2330
2586
|
*/
|
|
2587
|
+
Expression.contextType = PerseusI18nContext;
|
|
2331
2588
|
Expression.defaultProps = {
|
|
2332
2589
|
value: "",
|
|
2333
2590
|
times: false,
|
|
@@ -2715,7 +2972,7 @@ function keScoreFromPerseusScore(score, guess, state) {
|
|
|
2715
2972
|
* Return the first valid interpretation of 'text' as a number, in the form
|
|
2716
2973
|
* {value: 2.3, exact: true}.
|
|
2717
2974
|
*/
|
|
2718
|
-
function firstNumericalParse$1(text) {
|
|
2975
|
+
function firstNumericalParse$1(text, strings) {
|
|
2719
2976
|
// TODO(alpert): This is sort of hacky...
|
|
2720
2977
|
let first;
|
|
2721
2978
|
const val = KhanAnswerTypes.predicate.createValidatorFunctional(function (ans) {
|
|
@@ -2725,7 +2982,7 @@ function firstNumericalParse$1(text) {
|
|
|
2725
2982
|
simplify: "optional",
|
|
2726
2983
|
inexact: true,
|
|
2727
2984
|
forms: "integer, proper, improper, pi, log, mixed, decimal"
|
|
2728
|
-
});
|
|
2985
|
+
}, strings);
|
|
2729
2986
|
val(text);
|
|
2730
2987
|
return first;
|
|
2731
2988
|
}
|
|
@@ -10277,8 +10534,6 @@ const getClipPoint = function getClipPoint(graph, coord, angle) {
|
|
|
10277
10534
|
class WrappedDrawing {
|
|
10278
10535
|
constructor(graphie, initialPoint) {
|
|
10279
10536
|
this.graphie = void 0;
|
|
10280
|
-
this.wrapper = void 0;
|
|
10281
|
-
this.visibleShape = void 0;
|
|
10282
10537
|
this.initialPoint = void 0;
|
|
10283
10538
|
this.graphie = graphie;
|
|
10284
10539
|
this.initialPoint = initialPoint;
|
|
@@ -18312,7 +18567,7 @@ const rules$1 = _extends({}, pureMarkdownRules, {
|
|
|
18312
18567
|
// just a stub for testing.
|
|
18313
18568
|
return /*#__PURE__*/React.createElement("em", {
|
|
18314
18569
|
key: state.key
|
|
18315
|
-
},
|
|
18570
|
+
}, `[Widget: ${node.id}]`);
|
|
18316
18571
|
}
|
|
18317
18572
|
}),
|
|
18318
18573
|
blockMath: _extends({}, pureMarkdownRules.blockMath, {
|
|
@@ -18785,6 +19040,7 @@ const replaceDeprecatedEditors = () => {
|
|
|
18785
19040
|
replaceEditor("simulator", "deprecated-standin");
|
|
18786
19041
|
};
|
|
18787
19042
|
const getWidget = name => {
|
|
19043
|
+
var _widgets$name;
|
|
18788
19044
|
// TODO(alex): Consider referring to these as renderers to avoid
|
|
18789
19045
|
// overloading "widget"
|
|
18790
19046
|
if (!_.has(widgets, name)) {
|
|
@@ -18792,9 +19048,9 @@ const getWidget = name => {
|
|
|
18792
19048
|
}
|
|
18793
19049
|
|
|
18794
19050
|
// Allow widgets to specify a widget directly or via a function
|
|
18795
|
-
if (widgets[name].getWidget) {
|
|
18796
|
-
|
|
18797
|
-
return widgets[name].getWidget();
|
|
19051
|
+
if ((_widgets$name = widgets[name]) != null && _widgets$name.getWidget) {
|
|
19052
|
+
var _widgets$name$getWidg, _widgets$name2;
|
|
19053
|
+
return (_widgets$name$getWidg = (_widgets$name2 = widgets[name]).getWidget) == null ? void 0 : _widgets$name$getWidg.call(_widgets$name2);
|
|
18798
19054
|
}
|
|
18799
19055
|
return widgets[name].widget;
|
|
18800
19056
|
};
|
|
@@ -18943,7 +19199,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
18943
19199
|
options: newEditorProps
|
|
18944
19200
|
});
|
|
18945
19201
|
};
|
|
18946
|
-
const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
19202
|
+
const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
18947
19203
|
const type = widgetInfo.type;
|
|
18948
19204
|
const widgetExports = widgets[type];
|
|
18949
19205
|
if (widgetExports == null) {
|
|
@@ -18964,7 +19220,7 @@ const getRendererPropsForWidgetInfo = (widgetInfo, problemNum) => {
|
|
|
18964
19220
|
transform = widgetExports.transform || _.identity;
|
|
18965
19221
|
}
|
|
18966
19222
|
// widgetInfo.options are the widgetEditor's props:
|
|
18967
|
-
return transform(widgetInfo.options, problemNum);
|
|
19223
|
+
return transform(widgetInfo.options, strings, problemNum);
|
|
18968
19224
|
};
|
|
18969
19225
|
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
18970
19226
|
if (!traverseRenderer) {
|
|
@@ -19363,8 +19619,11 @@ class Renderer extends React.Component {
|
|
|
19363
19619
|
problemNum
|
|
19364
19620
|
} = props;
|
|
19365
19621
|
const widgetsStartProps = {};
|
|
19622
|
+
const {
|
|
19623
|
+
strings
|
|
19624
|
+
} = this.props;
|
|
19366
19625
|
entries(allWidgetInfo).forEach(([key, widgetInfo]) => {
|
|
19367
|
-
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, problemNum);
|
|
19626
|
+
widgetsStartProps[key] = getRendererPropsForWidgetInfo(widgetInfo, strings, problemNum);
|
|
19368
19627
|
});
|
|
19369
19628
|
|
|
19370
19629
|
// Call the onWidgetStartProps callback if it exists
|
|
@@ -21424,10 +21683,12 @@ class InputWithExamples extends React.Component {
|
|
|
21424
21683
|
id: this._getUniqueId()
|
|
21425
21684
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
21426
21685
|
content: examplesContent,
|
|
21427
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "input-with-examples")
|
|
21686
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "input-with-examples"),
|
|
21687
|
+
strings: this.context.strings
|
|
21428
21688
|
})));
|
|
21429
21689
|
}
|
|
21430
21690
|
}
|
|
21691
|
+
InputWithExamples.contextType = PerseusI18nContext;
|
|
21431
21692
|
InputWithExamples.defaultProps = {
|
|
21432
21693
|
type: "text",
|
|
21433
21694
|
shouldShowExamples: true,
|
|
@@ -21458,8 +21719,9 @@ class SimpleKeypadInput extends React.Component {
|
|
|
21458
21719
|
}
|
|
21459
21720
|
|
|
21460
21721
|
blur() {
|
|
21722
|
+
var _this$refs$input;
|
|
21461
21723
|
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
21462
|
-
this.refs.input.blur(); // eslint-disable-line react/no-string-refs
|
|
21724
|
+
(_this$refs$input = this.refs.input) == null || _this$refs$input.blur(); // eslint-disable-line react/no-string-refs
|
|
21463
21725
|
}
|
|
21464
21726
|
|
|
21465
21727
|
getValue() {
|
|
@@ -21549,32 +21811,32 @@ const answerTypes = {
|
|
|
21549
21811
|
}
|
|
21550
21812
|
};
|
|
21551
21813
|
const formExamples$1 = {
|
|
21552
|
-
integer: function (options) {
|
|
21553
|
-
return
|
|
21814
|
+
integer: function (options, strings) {
|
|
21815
|
+
return strings.integerExample;
|
|
21554
21816
|
},
|
|
21555
|
-
proper: function (options) {
|
|
21817
|
+
proper: function (options, strings) {
|
|
21556
21818
|
if (options.simplify === "optional") {
|
|
21557
|
-
return
|
|
21819
|
+
return strings.properExample;
|
|
21558
21820
|
}
|
|
21559
|
-
return
|
|
21821
|
+
return strings.simplifiedProperExample;
|
|
21560
21822
|
},
|
|
21561
|
-
improper: function (options) {
|
|
21823
|
+
improper: function (options, strings) {
|
|
21562
21824
|
if (options.simplify === "optional") {
|
|
21563
|
-
return
|
|
21825
|
+
return strings.improperExample;
|
|
21564
21826
|
}
|
|
21565
|
-
return
|
|
21827
|
+
return strings.simplifiedImproperExample;
|
|
21566
21828
|
},
|
|
21567
|
-
mixed: function (options) {
|
|
21568
|
-
return
|
|
21829
|
+
mixed: function (options, strings) {
|
|
21830
|
+
return strings.mixedExample;
|
|
21569
21831
|
},
|
|
21570
|
-
decimal: function (options) {
|
|
21571
|
-
return
|
|
21832
|
+
decimal: function (options, strings) {
|
|
21833
|
+
return strings.decimalExample;
|
|
21572
21834
|
},
|
|
21573
|
-
percent: function (options) {
|
|
21574
|
-
return
|
|
21835
|
+
percent: function (options, strings) {
|
|
21836
|
+
return strings.percentExample;
|
|
21575
21837
|
},
|
|
21576
|
-
pi: function (options) {
|
|
21577
|
-
return
|
|
21838
|
+
pi: function (options, strings) {
|
|
21839
|
+
return strings.piExample;
|
|
21578
21840
|
}
|
|
21579
21841
|
};
|
|
21580
21842
|
class InputNumber extends React.Component {
|
|
@@ -21606,9 +21868,10 @@ class InputNumber extends React.Component {
|
|
|
21606
21868
|
this.refs.input.focus();
|
|
21607
21869
|
};
|
|
21608
21870
|
this.blurInputPath = inputPath => {
|
|
21871
|
+
var _this$refs$input;
|
|
21609
21872
|
// eslint-disable-next-line react/no-string-refs
|
|
21610
21873
|
// @ts-expect-error - TS2339 - Property 'blur' does not exist on type 'ReactInstance'.
|
|
21611
|
-
this.refs.input.blur();
|
|
21874
|
+
(_this$refs$input = this.refs.input) == null || _this$refs$input.blur();
|
|
21612
21875
|
};
|
|
21613
21876
|
this.getInputPaths = () => {
|
|
21614
21877
|
// The widget itself is an input, so we return a single empty list to
|
|
@@ -21632,18 +21895,16 @@ class InputNumber extends React.Component {
|
|
|
21632
21895
|
};
|
|
21633
21896
|
this.simpleValidate = (rubric, onInputError) => {
|
|
21634
21897
|
onInputError = onInputError || function () {};
|
|
21635
|
-
return InputNumber.validate(this.getUserInput(), rubric, onInputError);
|
|
21898
|
+
return InputNumber.validate(this.getUserInput(), rubric, this.context.strings, onInputError);
|
|
21636
21899
|
};
|
|
21637
21900
|
this.examples = () => {
|
|
21901
|
+
const {
|
|
21902
|
+
strings
|
|
21903
|
+
} = this.context;
|
|
21638
21904
|
const type = this.props.answerType;
|
|
21639
21905
|
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);
|
|
21906
|
+
const examples = _.map(forms, form => formExamples$1[form](this.props, strings));
|
|
21907
|
+
return [strings.yourAnswer].concat(examples);
|
|
21647
21908
|
};
|
|
21648
21909
|
}
|
|
21649
21910
|
render() {
|
|
@@ -21696,7 +21957,7 @@ class InputNumber extends React.Component {
|
|
|
21696
21957
|
linterContext: this.props.linterContext
|
|
21697
21958
|
});
|
|
21698
21959
|
}
|
|
21699
|
-
static validate(state, rubric, onInputError = () => {}) {
|
|
21960
|
+
static validate(state, rubric, strings, onInputError = () => {}) {
|
|
21700
21961
|
if (rubric.answerType == null) {
|
|
21701
21962
|
rubric.answerType = "number";
|
|
21702
21963
|
}
|
|
@@ -21710,7 +21971,7 @@ class InputNumber extends React.Component {
|
|
|
21710
21971
|
inexact: rubric.inexact || undefined,
|
|
21711
21972
|
maxError: rubric.maxError,
|
|
21712
21973
|
forms: answerTypes[rubric.answerType].forms
|
|
21713
|
-
});
|
|
21974
|
+
}, strings);
|
|
21714
21975
|
|
|
21715
21976
|
// We may have received TeX; try to parse it before grading.
|
|
21716
21977
|
// If `currentValue` is not TeX, this should be a no-op.
|
|
@@ -21752,6 +22013,7 @@ class InputNumber extends React.Component {
|
|
|
21752
22013
|
return answerString;
|
|
21753
22014
|
}
|
|
21754
22015
|
}
|
|
22016
|
+
InputNumber.contextType = PerseusI18nContext;
|
|
21755
22017
|
InputNumber.defaultProps = {
|
|
21756
22018
|
currentValue: "",
|
|
21757
22019
|
size: "normal",
|
|
@@ -21835,12 +22097,12 @@ const answerFormButtons = [{
|
|
|
21835
22097
|
content: "\u03C0"
|
|
21836
22098
|
}];
|
|
21837
22099
|
const formExamples = {
|
|
21838
|
-
integer: () =>
|
|
21839
|
-
proper: form => form.simplify === "optional" ?
|
|
21840
|
-
improper: form => form.simplify === "optional" ?
|
|
21841
|
-
mixed: () =>
|
|
21842
|
-
decimal: () =>
|
|
21843
|
-
pi: () =>
|
|
22100
|
+
integer: (form, strings) => strings.integerExample,
|
|
22101
|
+
proper: (form, strings) => form.simplify === "optional" ? strings.properExample : strings.simplifiedProperExample,
|
|
22102
|
+
improper: (form, strings) => form.simplify === "optional" ? strings.improperExample : strings.simplifiedImproperExample,
|
|
22103
|
+
mixed: (form, strings) => strings.mixedExample,
|
|
22104
|
+
decimal: (form, strings) => strings.decimalExample,
|
|
22105
|
+
pi: (form, strings) => strings.piExample
|
|
21844
22106
|
};
|
|
21845
22107
|
class NumericInput extends React.Component {
|
|
21846
22108
|
constructor(...args) {
|
|
@@ -21862,13 +22124,12 @@ class NumericInput extends React.Component {
|
|
|
21862
22124
|
};
|
|
21863
22125
|
});
|
|
21864
22126
|
let examples = _.map(forms, form => {
|
|
21865
|
-
|
|
21866
|
-
return formExamples[form.name](form);
|
|
22127
|
+
return formExamples[form.name](form, this.context.strings);
|
|
21867
22128
|
});
|
|
21868
22129
|
// Ensure no duplicate tooltip text from simplified and unsimplified
|
|
21869
22130
|
// versions of the same format
|
|
21870
22131
|
examples = _.uniq(examples);
|
|
21871
|
-
return [
|
|
22132
|
+
return [this.context.strings.yourAnswer].concat(examples);
|
|
21872
22133
|
};
|
|
21873
22134
|
this.shouldShowExamples = () => {
|
|
21874
22135
|
var _this$props$answerFor2, _this$props$answerFor3;
|
|
@@ -21881,7 +22142,7 @@ class NumericInput extends React.Component {
|
|
|
21881
22142
|
return !noFormsAccepted && !allFormsAccepted;
|
|
21882
22143
|
};
|
|
21883
22144
|
this.simpleValidate = rubric => {
|
|
21884
|
-
return NumericInput.validate(this.getUserInput(), rubric);
|
|
22145
|
+
return NumericInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
21885
22146
|
};
|
|
21886
22147
|
this.focus = () => {
|
|
21887
22148
|
var _this$inputRef;
|
|
@@ -21961,7 +22222,7 @@ class NumericInput extends React.Component {
|
|
|
21961
22222
|
}
|
|
21962
22223
|
return answerStrings[0];
|
|
21963
22224
|
}
|
|
21964
|
-
static validate(userInput, rubric) {
|
|
22225
|
+
static validate(userInput, rubric, strings) {
|
|
21965
22226
|
const defaultAnswerForms = answerFormButtons.map(e => e["value"])
|
|
21966
22227
|
// Don't default to validating the answer as a pi answer
|
|
21967
22228
|
// if answerForm isn't set on the answer
|
|
@@ -21988,7 +22249,7 @@ class NumericInput extends React.Component {
|
|
|
21988
22249
|
// TODO(merlob) backfill / delete
|
|
21989
22250
|
maxError: answer.maxError,
|
|
21990
22251
|
forms: validatorForms
|
|
21991
|
-
});
|
|
22252
|
+
}, strings);
|
|
21992
22253
|
};
|
|
21993
22254
|
|
|
21994
22255
|
// We may have received TeX; try to parse it before grading.
|
|
@@ -22058,7 +22319,7 @@ class NumericInput extends React.Component {
|
|
|
22058
22319
|
render() {
|
|
22059
22320
|
let labelText = this.props.labelText;
|
|
22060
22321
|
if (labelText == null || labelText === "") {
|
|
22061
|
-
labelText =
|
|
22322
|
+
labelText = this.context.strings.yourAnswerLabel;
|
|
22062
22323
|
}
|
|
22063
22324
|
|
|
22064
22325
|
// To right align a custom keypad we need to wrap it.
|
|
@@ -22113,6 +22374,7 @@ class NumericInput extends React.Component {
|
|
|
22113
22374
|
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
22114
22375
|
// When should two answers to a problem take different answer types?
|
|
22115
22376
|
// See D27790 for more discussion.
|
|
22377
|
+
NumericInput.contextType = PerseusI18nContext;
|
|
22116
22378
|
NumericInput.defaultProps = {
|
|
22117
22379
|
currentValue: "",
|
|
22118
22380
|
size: "normal",
|
|
@@ -22268,18 +22530,21 @@ class PassageRef extends React.Component {
|
|
|
22268
22530
|
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
|
|
22269
22531
|
}
|
|
22270
22532
|
render() {
|
|
22533
|
+
const {
|
|
22534
|
+
strings
|
|
22535
|
+
} = this.context;
|
|
22271
22536
|
const lineRange = this.state.lineRange;
|
|
22272
22537
|
let lineRangeOutput;
|
|
22273
22538
|
if (!lineRange) {
|
|
22274
|
-
lineRangeOutput =
|
|
22539
|
+
lineRangeOutput = strings.lineRange({
|
|
22275
22540
|
lineRange: `?${EN_DASH$1}?`
|
|
22276
22541
|
});
|
|
22277
22542
|
} else if (lineRange[0] === lineRange[1]) {
|
|
22278
|
-
lineRangeOutput =
|
|
22279
|
-
lineNumber: lineRange[0]
|
|
22543
|
+
lineRangeOutput = strings.lineNumber({
|
|
22544
|
+
lineNumber: String(lineRange[0])
|
|
22280
22545
|
});
|
|
22281
22546
|
} else {
|
|
22282
|
-
lineRangeOutput =
|
|
22547
|
+
lineRangeOutput = strings.lineRange({
|
|
22283
22548
|
lineRange: lineRange[0] + EN_DASH$1 + lineRange[1]
|
|
22284
22549
|
});
|
|
22285
22550
|
}
|
|
@@ -22321,6 +22586,7 @@ class PassageRef extends React.Component {
|
|
|
22321
22586
|
};
|
|
22322
22587
|
}
|
|
22323
22588
|
}
|
|
22589
|
+
PassageRef.contextType = PerseusI18nContext;
|
|
22324
22590
|
PassageRef.defaultProps = {
|
|
22325
22591
|
passageNumber: 1,
|
|
22326
22592
|
referenceNumber: 1,
|
|
@@ -22684,7 +22950,7 @@ Icon.defaultProps = {
|
|
|
22684
22950
|
color: "currentColor"
|
|
22685
22951
|
};
|
|
22686
22952
|
|
|
22687
|
-
function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
22953
|
+
function getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings) {
|
|
22688
22954
|
// There are two pieces of metadata we want to add to each a11yText:
|
|
22689
22955
|
// whether the answer was checked/crossed-out/neither, and whether the
|
|
22690
22956
|
// answer is correct/incorrect/not-yet-revealed.
|
|
@@ -22693,45 +22959,45 @@ function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
|
22693
22959
|
// we've just enumerated all 9 possibilities as separate strings.
|
|
22694
22960
|
if (showCorrectness && correct) {
|
|
22695
22961
|
if (checked) {
|
|
22696
|
-
return
|
|
22962
|
+
return strings.choiceCheckedCorrect({
|
|
22697
22963
|
letter
|
|
22698
22964
|
});
|
|
22699
22965
|
}
|
|
22700
22966
|
if (crossedOut) {
|
|
22701
|
-
return
|
|
22967
|
+
return strings.choiceCrossedOutCorrect({
|
|
22702
22968
|
letter
|
|
22703
22969
|
});
|
|
22704
22970
|
}
|
|
22705
|
-
return
|
|
22971
|
+
return strings.choiceCorrect({
|
|
22706
22972
|
letter
|
|
22707
22973
|
});
|
|
22708
22974
|
}
|
|
22709
22975
|
if (showCorrectness && !correct) {
|
|
22710
22976
|
if (checked) {
|
|
22711
|
-
return
|
|
22977
|
+
return strings.choiceCheckedIncorrect({
|
|
22712
22978
|
letter
|
|
22713
22979
|
});
|
|
22714
22980
|
}
|
|
22715
22981
|
if (crossedOut) {
|
|
22716
|
-
return
|
|
22982
|
+
return strings.choiceCrossedOutIncorrect({
|
|
22717
22983
|
letter
|
|
22718
22984
|
});
|
|
22719
22985
|
}
|
|
22720
|
-
return
|
|
22986
|
+
return strings.choiceIncorrect({
|
|
22721
22987
|
letter
|
|
22722
22988
|
});
|
|
22723
22989
|
}
|
|
22724
22990
|
if (checked) {
|
|
22725
|
-
return
|
|
22991
|
+
return strings.choiceChecked({
|
|
22726
22992
|
letter
|
|
22727
22993
|
});
|
|
22728
22994
|
}
|
|
22729
22995
|
if (crossedOut) {
|
|
22730
|
-
return
|
|
22996
|
+
return strings.choiceCrossedOut({
|
|
22731
22997
|
letter
|
|
22732
22998
|
});
|
|
22733
22999
|
}
|
|
22734
|
-
return
|
|
23000
|
+
return strings.choice({
|
|
22735
23001
|
letter
|
|
22736
23002
|
});
|
|
22737
23003
|
}
|
|
@@ -22778,18 +23044,8 @@ const styles$z = StyleSheet.create({
|
|
|
22778
23044
|
* "choice letter". (For example, in English, `getChoiceLetter(0)` is "A",
|
|
22779
23045
|
* `getChoiceLetter(1)` is "B", etc.)
|
|
22780
23046
|
*/
|
|
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");
|
|
23047
|
+
function getChoiceLetter(pos, strings) {
|
|
23048
|
+
const lettersString = strings.letters;
|
|
22793
23049
|
const letters = lettersString.split(" ");
|
|
22794
23050
|
if (pos < letters.length) {
|
|
22795
23051
|
// If the position we need is listed in the localized string, use that.
|
|
@@ -22853,7 +23109,10 @@ function ChoiceInner(props) {
|
|
|
22853
23109
|
showCorrectness,
|
|
22854
23110
|
correct
|
|
22855
23111
|
} = props;
|
|
22856
|
-
const
|
|
23112
|
+
const {
|
|
23113
|
+
strings
|
|
23114
|
+
} = usePerseusI18n();
|
|
23115
|
+
const letter = getChoiceLetter(pos, strings);
|
|
22857
23116
|
if (!showCorrectness) {
|
|
22858
23117
|
return letter;
|
|
22859
23118
|
}
|
|
@@ -22999,24 +23258,24 @@ const styles$w = StyleSheet.create({
|
|
|
22999
23258
|
* ChoiceIcon visualizations but is meant to make the distinctions
|
|
23000
23259
|
* between the states more immediately clear to users.
|
|
23001
23260
|
*/
|
|
23002
|
-
function renderText(checked, correct, crossedOut) {
|
|
23261
|
+
function renderText(checked, correct, crossedOut, strings) {
|
|
23003
23262
|
if (correct) {
|
|
23004
23263
|
// For correct answers, we surface checked _or_ crossedOut state,
|
|
23005
23264
|
// because any interaction with the correct answer is noteworthy!
|
|
23006
23265
|
if (checked) {
|
|
23007
|
-
return
|
|
23266
|
+
return strings.correctSelected;
|
|
23008
23267
|
}
|
|
23009
23268
|
if (crossedOut) {
|
|
23010
|
-
return
|
|
23269
|
+
return strings.correctCrossedOut;
|
|
23011
23270
|
}
|
|
23012
|
-
return
|
|
23271
|
+
return strings.correct;
|
|
23013
23272
|
}
|
|
23014
23273
|
// But, for incorrect answers, we only surface checked state,
|
|
23015
23274
|
// because crossing out an incorrect answer is not noteworthy.
|
|
23016
23275
|
if (checked) {
|
|
23017
|
-
return
|
|
23276
|
+
return strings.incorrectSelected;
|
|
23018
23277
|
}
|
|
23019
|
-
return
|
|
23278
|
+
return strings.incorrect;
|
|
23020
23279
|
}
|
|
23021
23280
|
const OptionStatus = function OptionStatus(props) {
|
|
23022
23281
|
const {
|
|
@@ -23026,6 +23285,9 @@ const OptionStatus = function OptionStatus(props) {
|
|
|
23026
23285
|
previouslyAnswered,
|
|
23027
23286
|
reviewMode
|
|
23028
23287
|
} = props;
|
|
23288
|
+
const {
|
|
23289
|
+
strings
|
|
23290
|
+
} = usePerseusI18n();
|
|
23029
23291
|
|
|
23030
23292
|
// Option status is shown only in review mode, or for incorrectly
|
|
23031
23293
|
// answered items.
|
|
@@ -23045,7 +23307,7 @@ const OptionStatus = function OptionStatus(props) {
|
|
|
23045
23307
|
}
|
|
23046
23308
|
return /*#__PURE__*/React.createElement("div", {
|
|
23047
23309
|
className: css(styles$v.text, textStyle)
|
|
23048
|
-
}, renderText(checked, correct, crossedOut));
|
|
23310
|
+
}, renderText(checked, correct, crossedOut, strings));
|
|
23049
23311
|
};
|
|
23050
23312
|
const styles$v = StyleSheet.create({
|
|
23051
23313
|
text: {
|
|
@@ -23092,6 +23354,9 @@ const Choice = function Choice(props) {
|
|
|
23092
23354
|
forwardedRef
|
|
23093
23355
|
} = props;
|
|
23094
23356
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
23357
|
+
const {
|
|
23358
|
+
strings
|
|
23359
|
+
} = usePerseusI18n();
|
|
23095
23360
|
useEffect(() => {
|
|
23096
23361
|
if (isInputFocused && disabled) {
|
|
23097
23362
|
setIsInputFocused(false);
|
|
@@ -23121,8 +23386,8 @@ const Choice = function Choice(props) {
|
|
|
23121
23386
|
// However, we don't want to do this when we're in review mode in the
|
|
23122
23387
|
// content library.
|
|
23123
23388
|
const showDimmed = !reviewMode && apiOptions.readOnly || crossedOut;
|
|
23124
|
-
const letter = getChoiceLetter(pos);
|
|
23125
|
-
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness);
|
|
23389
|
+
const letter = getChoiceLetter(pos, strings);
|
|
23390
|
+
const a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness, strings);
|
|
23126
23391
|
const idFactory = useUniqueIdWithMock(`choice`);
|
|
23127
23392
|
const choiceId = idFactory.get(letter);
|
|
23128
23393
|
return /*#__PURE__*/React.createElement("div", {
|
|
@@ -23222,15 +23487,15 @@ const Choice = function Choice(props) {
|
|
|
23222
23487
|
content: ({
|
|
23223
23488
|
close
|
|
23224
23489
|
}) => /*#__PURE__*/React.createElement(PopoverContent, {
|
|
23225
|
-
title:
|
|
23226
|
-
content:
|
|
23490
|
+
title: strings.crossOut,
|
|
23491
|
+
content: strings.crossOutOption,
|
|
23227
23492
|
closeButtonVisible: true,
|
|
23228
23493
|
actions: /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
|
|
23229
23494
|
size: spacing.medium_16
|
|
23230
23495
|
}), /*#__PURE__*/React.createElement(Button, {
|
|
23231
23496
|
kind: "primary",
|
|
23232
|
-
"aria-label":
|
|
23233
|
-
letter: getChoiceLetter(pos)
|
|
23497
|
+
"aria-label": strings.crossOutChoice({
|
|
23498
|
+
letter: getChoiceLetter(pos, strings)
|
|
23234
23499
|
}),
|
|
23235
23500
|
disabled: apiOptions.readOnly || reviewMode,
|
|
23236
23501
|
onClick: () => {
|
|
@@ -23250,14 +23515,14 @@ const Choice = function Choice(props) {
|
|
|
23250
23515
|
}
|
|
23251
23516
|
close();
|
|
23252
23517
|
}
|
|
23253
|
-
}, crossedOut ?
|
|
23518
|
+
}, crossedOut ? strings.bringBack : strings.crossOut))
|
|
23254
23519
|
})
|
|
23255
23520
|
}, ({
|
|
23256
23521
|
open
|
|
23257
23522
|
}) => /*#__PURE__*/React.createElement(Clickable, {
|
|
23258
23523
|
onClick: open,
|
|
23259
|
-
"aria-label":
|
|
23260
|
-
letter: getChoiceLetter(pos)
|
|
23524
|
+
"aria-label": strings.openMenuForChoice({
|
|
23525
|
+
letter: getChoiceLetter(pos, strings)
|
|
23261
23526
|
}),
|
|
23262
23527
|
style: {
|
|
23263
23528
|
alignSelf: "center",
|
|
@@ -23309,6 +23574,9 @@ const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
|
|
|
23309
23574
|
forwardedRef
|
|
23310
23575
|
} = props,
|
|
23311
23576
|
rest = _objectWithoutPropertiesLoose(props, _excluded$3);
|
|
23577
|
+
const {
|
|
23578
|
+
strings
|
|
23579
|
+
} = usePerseusI18n();
|
|
23312
23580
|
const choiceProps = _extends({}, rest, {
|
|
23313
23581
|
content: showContent ? content :
|
|
23314
23582
|
/*#__PURE__*/
|
|
@@ -23324,7 +23592,8 @@ const ChoiceNoneAbove = function ChoiceNoneAbove(props) {
|
|
|
23324
23592
|
// just to render a string
|
|
23325
23593
|
React.createElement(Renderer, {
|
|
23326
23594
|
key: "noneOfTheAboveRenderer",
|
|
23327
|
-
content:
|
|
23595
|
+
content: strings.noneOfTheAbove,
|
|
23596
|
+
strings: strings
|
|
23328
23597
|
})
|
|
23329
23598
|
});
|
|
23330
23599
|
return /*#__PURE__*/React.createElement(Choice$1, _extends({}, choiceProps, {
|
|
@@ -23344,16 +23613,16 @@ const {
|
|
|
23344
23613
|
|
|
23345
23614
|
// exported for tests
|
|
23346
23615
|
|
|
23347
|
-
function getInstructionsText(multipleSelect, countChoices, numCorrect) {
|
|
23616
|
+
function getInstructionsText(multipleSelect, countChoices, numCorrect, strings) {
|
|
23348
23617
|
if (multipleSelect) {
|
|
23349
23618
|
if (countChoices) {
|
|
23350
|
-
return
|
|
23351
|
-
numCorrect: numCorrect
|
|
23619
|
+
return strings.chooseNumAnswers({
|
|
23620
|
+
numCorrect: String(numCorrect)
|
|
23352
23621
|
});
|
|
23353
23622
|
}
|
|
23354
|
-
return
|
|
23623
|
+
return strings.chooseAllAnswers;
|
|
23355
23624
|
}
|
|
23356
|
-
return
|
|
23625
|
+
return strings.chooseOneAnswer;
|
|
23357
23626
|
}
|
|
23358
23627
|
const BaseRadio = function BaseRadio(props) {
|
|
23359
23628
|
const {
|
|
@@ -23368,6 +23637,9 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23368
23637
|
isLastUsedWidget,
|
|
23369
23638
|
registerFocusFunction
|
|
23370
23639
|
} = props;
|
|
23640
|
+
const {
|
|
23641
|
+
strings
|
|
23642
|
+
} = usePerseusI18n();
|
|
23371
23643
|
|
|
23372
23644
|
// useEffect doesn't have previous props
|
|
23373
23645
|
const prevReviewModeRubric = useRef();
|
|
@@ -23474,7 +23746,7 @@ const BaseRadio = function BaseRadio(props) {
|
|
|
23474
23746
|
const lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
23475
23747
|
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
23748
|
const instructionsClassName = classNames("instructions", css(styles$t.instructions, isMobile && styles$t.instructionsMobile));
|
|
23477
|
-
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
|
|
23749
|
+
const instructions = getInstructionsText(multipleSelect, countChoices, numCorrect, strings);
|
|
23478
23750
|
const responsiveClassName = css(styles$t.responsiveFieldset);
|
|
23479
23751
|
const fieldset = /*#__PURE__*/React.createElement("fieldset", {
|
|
23480
23752
|
className: `perseus-widget-radio-fieldset ${responsiveClassName}`
|
|
@@ -23739,7 +24011,8 @@ class Radio$1 extends React.Component {
|
|
|
23739
24011
|
linterContext: _extends({}, this.props.linterContext, {
|
|
23740
24012
|
// @ts-expect-error - TS2322 - Type '{ blockHighlight: true; contentType: string; highlightLint: boolean; paths: readonly string[]; stack: readonly string[]; }' is not assignable to type 'LinterContextProps'.
|
|
23741
24013
|
blockHighlight: true
|
|
23742
|
-
})
|
|
24014
|
+
}),
|
|
24015
|
+
strings: this.context.strings
|
|
23743
24016
|
});
|
|
23744
24017
|
};
|
|
23745
24018
|
// When `BaseRadio`'s `onChange` handler is called, indicating a change in
|
|
@@ -23791,7 +24064,7 @@ class Radio$1 extends React.Component {
|
|
|
23791
24064
|
return Radio$1.getUserInputFromProps(this.props);
|
|
23792
24065
|
};
|
|
23793
24066
|
this.simpleValidate = rubric => {
|
|
23794
|
-
return Radio$1.validate(this.getUserInput(), rubric);
|
|
24067
|
+
return Radio$1.validate(this.getUserInput(), rubric, this.context.strings);
|
|
23795
24068
|
};
|
|
23796
24069
|
/**
|
|
23797
24070
|
* Turn on rationale display for the currently selected choices. Note that
|
|
@@ -23852,7 +24125,7 @@ class Radio$1 extends React.Component {
|
|
|
23852
24125
|
}
|
|
23853
24126
|
};
|
|
23854
24127
|
}
|
|
23855
|
-
static validate(userInput, rubric) {
|
|
24128
|
+
static validate(userInput, rubric, strings) {
|
|
23856
24129
|
const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
23857
24130
|
return sum + (selected ? 1 : 0);
|
|
23858
24131
|
}, 0);
|
|
@@ -23865,7 +24138,7 @@ class Radio$1 extends React.Component {
|
|
|
23865
24138
|
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
23866
24139
|
return {
|
|
23867
24140
|
type: "invalid",
|
|
23868
|
-
message:
|
|
24141
|
+
message: strings.chooseCorrectNum
|
|
23869
24142
|
};
|
|
23870
24143
|
// If NOTA and some other answer are checked, ...
|
|
23871
24144
|
}
|
|
@@ -23873,7 +24146,7 @@ class Radio$1 extends React.Component {
|
|
|
23873
24146
|
if (userInput.noneOfTheAboveSelected && numSelected > 1) {
|
|
23874
24147
|
return {
|
|
23875
24148
|
type: "invalid",
|
|
23876
|
-
message:
|
|
24149
|
+
message: strings.notNoneOfTheAbove
|
|
23877
24150
|
};
|
|
23878
24151
|
}
|
|
23879
24152
|
const correct = userInput.choicesSelected.every((selected, i) => {
|
|
@@ -23985,6 +24258,9 @@ class Radio$1 extends React.Component {
|
|
|
23985
24258
|
const {
|
|
23986
24259
|
choices
|
|
23987
24260
|
} = this.props;
|
|
24261
|
+
const {
|
|
24262
|
+
strings
|
|
24263
|
+
} = this.context;
|
|
23988
24264
|
let choiceStates;
|
|
23989
24265
|
if (this.props.static) {
|
|
23990
24266
|
choiceStates = choices.map(choice => ({
|
|
@@ -24036,11 +24312,7 @@ class Radio$1 extends React.Component {
|
|
|
24036
24312
|
}));
|
|
24037
24313
|
}
|
|
24038
24314
|
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;
|
|
24315
|
+
const content = choice.isNoneOfTheAbove && !choice.content ? strings.noneOfTheAbove : choice.content;
|
|
24044
24316
|
const {
|
|
24045
24317
|
selected,
|
|
24046
24318
|
crossedOut,
|
|
@@ -24092,6 +24364,7 @@ class Radio$1 extends React.Component {
|
|
|
24092
24364
|
});
|
|
24093
24365
|
}
|
|
24094
24366
|
}
|
|
24367
|
+
Radio$1.contextType = PerseusI18nContext;
|
|
24095
24368
|
Radio$1.defaultProps = {
|
|
24096
24369
|
choices: [],
|
|
24097
24370
|
multipleSelect: false,
|
|
@@ -24106,14 +24379,8 @@ const {
|
|
|
24106
24379
|
random
|
|
24107
24380
|
} = Util;
|
|
24108
24381
|
|
|
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
24382
|
// Transforms the choices for display.
|
|
24116
|
-
const _choiceTransform = (widgetOptions, problemNum) => {
|
|
24383
|
+
const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
24117
24384
|
const _maybeRandomize = function _maybeRandomize(array) {
|
|
24118
24385
|
const randomSeed = problemNum === undefined ? random : problemNum;
|
|
24119
24386
|
// NOTE: `problemNum` will only be set when the radio widget is
|
|
@@ -24142,6 +24409,11 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24142
24409
|
return newChoices;
|
|
24143
24410
|
};
|
|
24144
24411
|
const enforceOrdering = choices => {
|
|
24412
|
+
// Represents choices that we automatically re-order if encountered.
|
|
24413
|
+
// Note: these are in the reversed (incorrect) order that we will swap, if
|
|
24414
|
+
// found.
|
|
24415
|
+
// Note 2: these are internationalized when compared later on.
|
|
24416
|
+
const ReversedChoices = [[strings.false, strings.true], [strings.no, strings.yes]];
|
|
24145
24417
|
const content = choices.map(c => c.content);
|
|
24146
24418
|
if (ReversedChoices.some(reversed => _.isEqual(content, reversed))) {
|
|
24147
24419
|
return [choices[1], choices[0]];
|
|
@@ -24167,8 +24439,8 @@ const _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
24167
24439
|
// 1) we randomize the order first
|
|
24168
24440
|
_maybeRandomize(choices)));
|
|
24169
24441
|
};
|
|
24170
|
-
const transform = (widgetOptions, problemNum) => {
|
|
24171
|
-
const choices = _choiceTransform(widgetOptions, problemNum);
|
|
24442
|
+
const transform = (widgetOptions, strings, problemNum) => {
|
|
24443
|
+
const choices = _choiceTransform(widgetOptions, strings, problemNum);
|
|
24172
24444
|
const numCorrect = _.reduce(widgetOptions.choices, function (memo, choice) {
|
|
24173
24445
|
return choice.correct ? memo + 1 : memo;
|
|
24174
24446
|
}, 0);
|
|
@@ -24254,7 +24526,7 @@ class Categorizer extends React.Component {
|
|
|
24254
24526
|
return Categorizer.getUserInputFromProps(this.props);
|
|
24255
24527
|
};
|
|
24256
24528
|
this.simpleValidate = rubric => {
|
|
24257
|
-
return Categorizer.validate(this.getUserInput(), rubric);
|
|
24529
|
+
return Categorizer.validate(this.getUserInput(), rubric, this.context.strings);
|
|
24258
24530
|
};
|
|
24259
24531
|
}
|
|
24260
24532
|
render() {
|
|
@@ -24283,7 +24555,8 @@ class Categorizer extends React.Component {
|
|
|
24283
24555
|
key: i
|
|
24284
24556
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24285
24557
|
content: category,
|
|
24286
|
-
linterContext: this.props.linterContext
|
|
24558
|
+
linterContext: this.props.linterContext,
|
|
24559
|
+
strings: this.context.strings
|
|
24287
24560
|
}));
|
|
24288
24561
|
}))), /*#__PURE__*/React.createElement("tbody", null, indexedItems.map(indexedItem => {
|
|
24289
24562
|
const item = indexedItem[0];
|
|
@@ -24295,7 +24568,8 @@ class Categorizer extends React.Component {
|
|
|
24295
24568
|
// @ts-expect-error - TS2322 - Type 'string | number' is not assignable to type 'string | undefined'.
|
|
24296
24569
|
, {
|
|
24297
24570
|
content: item,
|
|
24298
|
-
linterContext: this.props.linterContext
|
|
24571
|
+
linterContext: this.props.linterContext,
|
|
24572
|
+
strings: this.context.strings
|
|
24299
24573
|
})), self.props.categories.map((catName, catNum) => {
|
|
24300
24574
|
const selected = self.props.values[itemNum] === catNum;
|
|
24301
24575
|
return /*#__PURE__*/React.createElement("td", {
|
|
@@ -24338,7 +24612,7 @@ class Categorizer extends React.Component {
|
|
|
24338
24612
|
this.change("values", values);
|
|
24339
24613
|
this.props.trackInteraction();
|
|
24340
24614
|
}
|
|
24341
|
-
static validate(userInput, rubric) {
|
|
24615
|
+
static validate(userInput, rubric, strings) {
|
|
24342
24616
|
let completed = true;
|
|
24343
24617
|
let allCorrect = true;
|
|
24344
24618
|
rubric.values.forEach((value, i) => {
|
|
@@ -24352,7 +24626,7 @@ class Categorizer extends React.Component {
|
|
|
24352
24626
|
if (!completed) {
|
|
24353
24627
|
return {
|
|
24354
24628
|
type: "invalid",
|
|
24355
|
-
message:
|
|
24629
|
+
message: strings.invalidSelection
|
|
24356
24630
|
};
|
|
24357
24631
|
}
|
|
24358
24632
|
return {
|
|
@@ -24368,6 +24642,7 @@ class Categorizer extends React.Component {
|
|
|
24368
24642
|
}
|
|
24369
24643
|
|
|
24370
24644
|
// TODO(benkomalo): inject page-margin into Perseus instead of hardcoding.
|
|
24645
|
+
Categorizer.contextType = PerseusI18nContext;
|
|
24371
24646
|
Categorizer.defaultProps = {
|
|
24372
24647
|
items: [],
|
|
24373
24648
|
categories: [],
|
|
@@ -24693,7 +24968,8 @@ class Definition extends React.Component {
|
|
|
24693
24968
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
24694
24969
|
apiOptions: this.props.apiOptions,
|
|
24695
24970
|
content: this.props.definition,
|
|
24696
|
-
widgets: this.props.widgets
|
|
24971
|
+
widgets: this.props.widgets,
|
|
24972
|
+
strings: this.context.strings
|
|
24697
24973
|
})),
|
|
24698
24974
|
opened: activeDefinitionId === this.props.widgetId,
|
|
24699
24975
|
onClose: () => setActiveDefinitionId(null),
|
|
@@ -24715,6 +24991,7 @@ class Definition extends React.Component {
|
|
|
24715
24991
|
}, this.props.togglePrompt))));
|
|
24716
24992
|
}
|
|
24717
24993
|
}
|
|
24994
|
+
Definition.contextType = PerseusI18nContext;
|
|
24718
24995
|
Definition.defaultProps = {
|
|
24719
24996
|
togglePrompt: "define me",
|
|
24720
24997
|
definition: "definition goes here"
|
|
@@ -24765,12 +25042,13 @@ class DeprecatedStandin extends React__default.Component {
|
|
|
24765
25042
|
paddingBottom: 8
|
|
24766
25043
|
}
|
|
24767
25044
|
}, /*#__PURE__*/React__default.createElement(Banner, {
|
|
24768
|
-
text:
|
|
25045
|
+
text: this.context.strings.deprecatedStandin,
|
|
24769
25046
|
kind: "info",
|
|
24770
25047
|
layout: "full-width"
|
|
24771
25048
|
}));
|
|
24772
25049
|
}
|
|
24773
25050
|
}
|
|
25051
|
+
DeprecatedStandin.contextType = PerseusI18nContext;
|
|
24774
25052
|
var DeprecatedStandin$1 = {
|
|
24775
25053
|
name: "deprecated-standin",
|
|
24776
25054
|
displayName: "Deprecated Standin",
|
|
@@ -24965,10 +25243,12 @@ class Explanation extends React.Component {
|
|
|
24965
25243
|
apiOptions: this.props.apiOptions,
|
|
24966
25244
|
content: this.props.explanation,
|
|
24967
25245
|
widgets: this.props.widgets,
|
|
24968
|
-
linterContext: this.props.linterContext
|
|
25246
|
+
linterContext: this.props.linterContext,
|
|
25247
|
+
strings: this.context.strings
|
|
24969
25248
|
})))));
|
|
24970
25249
|
}
|
|
24971
25250
|
}
|
|
25251
|
+
Explanation.contextType = PerseusI18nContext;
|
|
24972
25252
|
Explanation.defaultProps = {
|
|
24973
25253
|
showPrompt: "Explain",
|
|
24974
25254
|
hidePrompt: "Hide explanation",
|
|
@@ -25036,6 +25316,13 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25036
25316
|
onCheckAnswer,
|
|
25037
25317
|
onNextQuestion
|
|
25038
25318
|
} = this.props;
|
|
25319
|
+
const {
|
|
25320
|
+
keepTrying,
|
|
25321
|
+
tryAgain,
|
|
25322
|
+
check,
|
|
25323
|
+
correctExcited,
|
|
25324
|
+
nextQuestion
|
|
25325
|
+
} = this.context.strings;
|
|
25039
25326
|
const answerBarStyle = _extends({}, styles$o.answerBar, {
|
|
25040
25327
|
backgroundColor: answerBarState === "CORRECT" ? color.offWhite : "white",
|
|
25041
25328
|
// Center the "Correct!" message only when there's no next question
|
|
@@ -25049,10 +25336,10 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25049
25336
|
style: {
|
|
25050
25337
|
marginLeft: 8
|
|
25051
25338
|
}
|
|
25052
|
-
},
|
|
25339
|
+
}, keepTrying)) : /*#__PURE__*/React.createElement("span", null); // empty span keeps the button on the right side
|
|
25053
25340
|
|
|
25054
25341
|
if (answerBarState !== "CORRECT") {
|
|
25055
|
-
const buttonLabel = answerBarState === "INCORRECT" ?
|
|
25342
|
+
const buttonLabel = answerBarState === "INCORRECT" ? tryAgain : check;
|
|
25056
25343
|
return /*#__PURE__*/React.createElement("div", {
|
|
25057
25344
|
style: answerBarStyle
|
|
25058
25345
|
}, message, /*#__PURE__*/React.createElement(Button, {
|
|
@@ -25075,15 +25362,16 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
25075
25362
|
}
|
|
25076
25363
|
}))), /*#__PURE__*/React.createElement("span", {
|
|
25077
25364
|
role: "alert",
|
|
25078
|
-
"aria-label":
|
|
25365
|
+
"aria-label": correctExcited,
|
|
25079
25366
|
style: {
|
|
25080
25367
|
marginLeft: 8
|
|
25081
25368
|
}
|
|
25082
|
-
},
|
|
25369
|
+
}, correctExcited)), onNextQuestion && /*#__PURE__*/React.createElement(Button, {
|
|
25083
25370
|
onClick: onNextQuestion
|
|
25084
|
-
},
|
|
25371
|
+
}, nextQuestion));
|
|
25085
25372
|
}
|
|
25086
25373
|
}
|
|
25374
|
+
GradedGroupAnswerBar.contextType = PerseusI18nContext;
|
|
25087
25375
|
const fontSize = 17;
|
|
25088
25376
|
const styles$o = {
|
|
25089
25377
|
answerBar: {
|
|
@@ -25137,10 +25425,6 @@ const getNextState = (currentState, answerable) => {
|
|
|
25137
25425
|
}
|
|
25138
25426
|
};
|
|
25139
25427
|
|
|
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
25428
|
// exports has no 'transform'
|
|
25145
25429
|
|
|
25146
25430
|
// A Graded Group is more or less a Group widget that displays a check
|
|
@@ -25192,8 +25476,13 @@ class GradedGroup extends React.Component {
|
|
|
25192
25476
|
// eslint-disable-next-line react/no-string-refs
|
|
25193
25477
|
// @ts-expect-error - TS2339 - Property 'score' does not exist on type 'ReactInstance'.
|
|
25194
25478
|
const score = this.refs.renderer.score();
|
|
25479
|
+
const {
|
|
25480
|
+
INVALID_MESSAGE_PREFIX,
|
|
25481
|
+
DEFAULT_INVALID_MESSAGE_1,
|
|
25482
|
+
DEFAULT_INVALID_MESSAGE_2
|
|
25483
|
+
} = this.context.strings;
|
|
25195
25484
|
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} ${
|
|
25485
|
+
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
25486
|
this.setState({
|
|
25198
25487
|
status: status,
|
|
25199
25488
|
message: message,
|
|
@@ -25258,8 +25547,7 @@ class GradedGroup extends React.Component {
|
|
|
25258
25547
|
color: "#526f03"
|
|
25259
25548
|
}
|
|
25260
25549
|
}));
|
|
25261
|
-
|
|
25262
|
-
gradeStatus = i18n._("Correct");
|
|
25550
|
+
gradeStatus = this.context.strings.correct;
|
|
25263
25551
|
} else if (this.state.status === GRADING_STATUSES.incorrect) {
|
|
25264
25552
|
// TODO(jeremy): update to a WB colour
|
|
25265
25553
|
// @ts-expect-error - TS2322 - Type 'Element' is not assignable to type 'null'.
|
|
@@ -25268,8 +25556,7 @@ class GradedGroup extends React.Component {
|
|
|
25268
25556
|
color: "#ff5454"
|
|
25269
25557
|
}
|
|
25270
25558
|
}));
|
|
25271
|
-
|
|
25272
|
-
gradeStatus = i18n._("Incorrect");
|
|
25559
|
+
gradeStatus = this.context.strings.incorrect;
|
|
25273
25560
|
}
|
|
25274
25561
|
const mobileClass = this.props.inGradedGroupSet ? css(styles$n.gradedGroupInSet) : css(styles$n.gradedGroup);
|
|
25275
25562
|
const classes = classNames({
|
|
@@ -25298,7 +25585,8 @@ class GradedGroup extends React.Component {
|
|
|
25298
25585
|
readOnly
|
|
25299
25586
|
}),
|
|
25300
25587
|
onInteractWithWidget: this._onInteractWithWidget,
|
|
25301
|
-
linterContext: this.props.linterContext
|
|
25588
|
+
linterContext: this.props.linterContext,
|
|
25589
|
+
strings: this.context.strings
|
|
25302
25590
|
})), !apiOptions.isMobile && icon && /*#__PURE__*/React.createElement("div", {
|
|
25303
25591
|
className: "group-icon"
|
|
25304
25592
|
}, icon), !apiOptions.isMobile && gradeStatus && /*#__PURE__*/React.createElement("div", {
|
|
@@ -25312,14 +25600,14 @@ class GradedGroup extends React.Component {
|
|
|
25312
25600
|
kind: "secondary",
|
|
25313
25601
|
disabled: this.props.apiOptions.readOnly,
|
|
25314
25602
|
onClick: this._checkAnswer
|
|
25315
|
-
},
|
|
25603
|
+
}, this.context.strings.check), !apiOptions.isMobile && isCorrect && this.props.onNextQuestion && /*#__PURE__*/React.createElement(Button, {
|
|
25316
25604
|
kind: "secondary",
|
|
25317
25605
|
disabled: this.props.apiOptions.readOnly,
|
|
25318
25606
|
onClick: this.props.onNextQuestion,
|
|
25319
25607
|
style: {
|
|
25320
25608
|
marginLeft: 5
|
|
25321
25609
|
}
|
|
25322
|
-
},
|
|
25610
|
+
}, this.context.strings.nextQuestion), this.props.hint && this.props.hint.content && (this.state.showHint ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
|
|
25323
25611
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
|
|
25324
25612
|
tabIndex: "0",
|
|
25325
25613
|
className: css(styles$n.explanationTitle),
|
|
@@ -25333,11 +25621,12 @@ class GradedGroup extends React.Component {
|
|
|
25333
25621
|
showHint: false
|
|
25334
25622
|
});
|
|
25335
25623
|
}
|
|
25336
|
-
},
|
|
25624
|
+
}, this.context.strings.hideExplanation), /*#__PURE__*/React.createElement(Renderer, _extends({}, this.props.hint, {
|
|
25337
25625
|
// eslint-disable-next-line react/no-string-refs
|
|
25338
25626
|
ref: "hints-renderer",
|
|
25339
25627
|
apiOptions: apiOptions,
|
|
25340
|
-
linterContext: this.props.linterContext
|
|
25628
|
+
linterContext: this.props.linterContext,
|
|
25629
|
+
strings: this.context.strings
|
|
25341
25630
|
}))) :
|
|
25342
25631
|
/*#__PURE__*/
|
|
25343
25632
|
// Not using Button here bc the styles won't work.
|
|
@@ -25355,7 +25644,7 @@ class GradedGroup extends React.Component {
|
|
|
25355
25644
|
});
|
|
25356
25645
|
},
|
|
25357
25646
|
className: css(styles$n.showHintLink)
|
|
25358
|
-
},
|
|
25647
|
+
}, this.context.strings.explain)), apiOptions.isMobile && answerBarState !== "HIDDEN" && /*#__PURE__*/React.createElement(GradedGroupAnswerBar, {
|
|
25359
25648
|
apiOptions: apiOptions,
|
|
25360
25649
|
answerBarState: answerBarState,
|
|
25361
25650
|
onCheckAnswer: this._checkAnswer,
|
|
@@ -25363,6 +25652,7 @@ class GradedGroup extends React.Component {
|
|
|
25363
25652
|
}));
|
|
25364
25653
|
}
|
|
25365
25654
|
}
|
|
25655
|
+
GradedGroup.contextType = PerseusI18nContext;
|
|
25366
25656
|
GradedGroup.defaultProps = {
|
|
25367
25657
|
title: "",
|
|
25368
25658
|
content: "",
|
|
@@ -25456,7 +25746,7 @@ class Indicators extends React.Component {
|
|
|
25456
25746
|
key: title
|
|
25457
25747
|
}, /*#__PURE__*/React.createElement(Clickable, {
|
|
25458
25748
|
role: "button",
|
|
25459
|
-
"aria-label":
|
|
25749
|
+
"aria-label": this.context.strings.skipToTitle({
|
|
25460
25750
|
title
|
|
25461
25751
|
}),
|
|
25462
25752
|
style: styles$m.indicatorButton,
|
|
@@ -25472,12 +25762,10 @@ class Indicators extends React.Component {
|
|
|
25472
25762
|
style: styles$m.indicatorDotActive
|
|
25473
25763
|
}, /*#__PURE__*/React.createElement("span", {
|
|
25474
25764
|
className: css(a11y.srOnly)
|
|
25475
|
-
},
|
|
25765
|
+
}, this.context.strings.current)))))));
|
|
25476
25766
|
}
|
|
25477
25767
|
}
|
|
25478
|
-
|
|
25479
|
-
// no transform
|
|
25480
|
-
|
|
25768
|
+
Indicators.contextType = PerseusI18nContext; // no transform
|
|
25481
25769
|
// TODO(jared): find a better name for this :) and for GradedGroup; the names
|
|
25482
25770
|
// are currently a little confusing.
|
|
25483
25771
|
class GradedGroupSet extends React.Component {
|
|
@@ -25553,7 +25841,7 @@ class GradedGroupSet extends React.Component {
|
|
|
25553
25841
|
}
|
|
25554
25842
|
const currentGroup = this.props.gradedGroups[this.state.currentGroup];
|
|
25555
25843
|
if (!currentGroup) {
|
|
25556
|
-
return /*#__PURE__*/React.createElement("span", null,
|
|
25844
|
+
return /*#__PURE__*/React.createElement("span", null, "No current group...");
|
|
25557
25845
|
}
|
|
25558
25846
|
const numGroups = this.props.gradedGroups.length;
|
|
25559
25847
|
const handleNextQuestion = this.state.currentGroup < numGroups - 1 ? this.handleNextQuestion : null;
|
|
@@ -26848,7 +27136,8 @@ class Group extends React.Component {
|
|
|
26848
27136
|
findExternalWidgets: this.props.findWidgets,
|
|
26849
27137
|
reviewMode: !!this.props.reviewModeRubric,
|
|
26850
27138
|
onInteractWithWidget: onInteractWithWidget,
|
|
26851
|
-
linterContext: this.props.linterContext
|
|
27139
|
+
linterContext: this.props.linterContext,
|
|
27140
|
+
strings: this.context.strings
|
|
26852
27141
|
}), this.props.icon &&
|
|
26853
27142
|
/*#__PURE__*/
|
|
26854
27143
|
// @ts-expect-error - TS2339 - Property 'icon' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
|
|
@@ -26857,6 +27146,7 @@ class Group extends React.Component {
|
|
|
26857
27146
|
}, this.props.icon));
|
|
26858
27147
|
}
|
|
26859
27148
|
}
|
|
27149
|
+
Group.contextType = PerseusI18nContext;
|
|
26860
27150
|
Group.defaultProps = {
|
|
26861
27151
|
content: "",
|
|
26862
27152
|
widgets: {},
|
|
@@ -27122,7 +27412,8 @@ class ImageWidget extends React.Component {
|
|
|
27122
27412
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27123
27413
|
content: this.props.alt,
|
|
27124
27414
|
apiOptions: apiOptions,
|
|
27125
|
-
linterContext: this.props.linterContext
|
|
27415
|
+
linterContext: this.props.linterContext,
|
|
27416
|
+
strings: this.context.strings
|
|
27126
27417
|
}));
|
|
27127
27418
|
}
|
|
27128
27419
|
|
|
@@ -27182,7 +27473,8 @@ class ImageWidget extends React.Component {
|
|
|
27182
27473
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27183
27474
|
content: _title + this.props.caption,
|
|
27184
27475
|
apiOptions: apiOptions,
|
|
27185
|
-
linterContext: this.props.linterContext
|
|
27476
|
+
linterContext: this.props.linterContext,
|
|
27477
|
+
strings: this.context.strings
|
|
27186
27478
|
})));
|
|
27187
27479
|
}
|
|
27188
27480
|
return /*#__PURE__*/React.createElement("figure", {
|
|
@@ -27200,7 +27492,8 @@ class ImageWidget extends React.Component {
|
|
|
27200
27492
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27201
27493
|
content: this.props.title,
|
|
27202
27494
|
apiOptions: apiOptions,
|
|
27203
|
-
linterContext: this.props.linterContext
|
|
27495
|
+
linterContext: this.props.linterContext,
|
|
27496
|
+
strings: this.context.strings
|
|
27204
27497
|
}));
|
|
27205
27498
|
}
|
|
27206
27499
|
if (this.props.caption) {
|
|
@@ -27212,7 +27505,8 @@ class ImageWidget extends React.Component {
|
|
|
27212
27505
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27213
27506
|
content: this.props.caption,
|
|
27214
27507
|
apiOptions: apiOptions,
|
|
27215
|
-
linterContext: this.props.linterContext
|
|
27508
|
+
linterContext: this.props.linterContext,
|
|
27509
|
+
strings: this.context.strings
|
|
27216
27510
|
}));
|
|
27217
27511
|
}
|
|
27218
27512
|
return /*#__PURE__*/React.createElement("figure", {
|
|
@@ -27231,6 +27525,7 @@ class ImageWidget extends React.Component {
|
|
|
27231
27525
|
};
|
|
27232
27526
|
}
|
|
27233
27527
|
}
|
|
27528
|
+
ImageWidget.contextType = PerseusI18nContext;
|
|
27234
27529
|
ImageWidget.defaultProps = {
|
|
27235
27530
|
alignment: DEFAULT_ALIGNMENT,
|
|
27236
27531
|
title: "",
|
|
@@ -28163,6 +28458,123 @@ Graph.defaultProps = {
|
|
|
28163
28458
|
isMobile: false
|
|
28164
28459
|
};
|
|
28165
28460
|
|
|
28461
|
+
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
28462
|
+
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
28463
|
+
|
|
28464
|
+
// Range is replaced within this file with Interval, but it is used elsewhere
|
|
28465
|
+
// and exported from the package, so we need to keep it around.
|
|
28466
|
+
// TODO(FEI-5054): Figure out how to get global .d.ts files working with monorepos
|
|
28467
|
+
const ItemExtras = [
|
|
28468
|
+
// The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
|
|
28469
|
+
"calculator",
|
|
28470
|
+
// The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
|
|
28471
|
+
"chi2Table",
|
|
28472
|
+
// The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
|
|
28473
|
+
"financialCalculatorMonthlyPayment",
|
|
28474
|
+
// The user might benefit from a total amount calculator. Provided on Khan Academy when true
|
|
28475
|
+
"financialCalculatorTotalAmount",
|
|
28476
|
+
// The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
|
|
28477
|
+
"financialCalculatorTimeToPayOff",
|
|
28478
|
+
// The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
|
|
28479
|
+
"periodicTable",
|
|
28480
|
+
// The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
|
|
28481
|
+
"periodicTableWithKey",
|
|
28482
|
+
// The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
|
|
28483
|
+
"tTable",
|
|
28484
|
+
// The user might benefit from using a statistics Z Table like https://www.ztable.net/
|
|
28485
|
+
"zTable"];
|
|
28486
|
+
|
|
28487
|
+
// prettier-ignore
|
|
28488
|
+
|
|
28489
|
+
// prettier-ignore
|
|
28490
|
+
|
|
28491
|
+
// prettier-ignore
|
|
28492
|
+
|
|
28493
|
+
// prettier-ignore
|
|
28494
|
+
|
|
28495
|
+
// prettier-ignore
|
|
28496
|
+
|
|
28497
|
+
// prettier-ignore
|
|
28498
|
+
|
|
28499
|
+
// prettier-ignore
|
|
28500
|
+
|
|
28501
|
+
// prettier-ignore
|
|
28502
|
+
|
|
28503
|
+
// prettier-ignore
|
|
28504
|
+
|
|
28505
|
+
// prettier-ignore
|
|
28506
|
+
|
|
28507
|
+
// prettier-ignore
|
|
28508
|
+
|
|
28509
|
+
// prettier-ignore
|
|
28510
|
+
|
|
28511
|
+
// prettier-ignore
|
|
28512
|
+
|
|
28513
|
+
// prettier-ignore
|
|
28514
|
+
|
|
28515
|
+
// prettier-ignore
|
|
28516
|
+
|
|
28517
|
+
// prettier-ignore
|
|
28518
|
+
|
|
28519
|
+
// prettier-ignore
|
|
28520
|
+
|
|
28521
|
+
// prettier-ignore
|
|
28522
|
+
|
|
28523
|
+
// prettier-ignore
|
|
28524
|
+
|
|
28525
|
+
// prettier-ignore
|
|
28526
|
+
|
|
28527
|
+
// prettier-ignore
|
|
28528
|
+
|
|
28529
|
+
// prettier-ignore
|
|
28530
|
+
|
|
28531
|
+
// prettier-ignore
|
|
28532
|
+
|
|
28533
|
+
// prettier-ignore
|
|
28534
|
+
|
|
28535
|
+
// prettier-ignore
|
|
28536
|
+
|
|
28537
|
+
// prettier-ignore
|
|
28538
|
+
|
|
28539
|
+
// prettier-ignore
|
|
28540
|
+
|
|
28541
|
+
// prettier-ignore
|
|
28542
|
+
|
|
28543
|
+
// prettier-ignore
|
|
28544
|
+
|
|
28545
|
+
// prettier-ignore
|
|
28546
|
+
|
|
28547
|
+
// prettier-ignore
|
|
28548
|
+
|
|
28549
|
+
// prettier-ignore
|
|
28550
|
+
|
|
28551
|
+
// prettier-ignore
|
|
28552
|
+
|
|
28553
|
+
// prettier-ignore
|
|
28554
|
+
|
|
28555
|
+
// prettier-ignore
|
|
28556
|
+
|
|
28557
|
+
// prettier-ignore
|
|
28558
|
+
|
|
28559
|
+
//prettier-ignore
|
|
28560
|
+
|
|
28561
|
+
// A background image applied to various widgets.
|
|
28562
|
+
|
|
28563
|
+
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28564
|
+
const lockedFigureColors = {
|
|
28565
|
+
blue: "#3D7586",
|
|
28566
|
+
green: "#447A53",
|
|
28567
|
+
gray: "#5D5F66",
|
|
28568
|
+
grayH: "#3B3D45",
|
|
28569
|
+
grayI: "#21242C",
|
|
28570
|
+
purple: "#594094",
|
|
28571
|
+
purpleD: "#8351E8",
|
|
28572
|
+
pink: "#B25071",
|
|
28573
|
+
orange: "#946700",
|
|
28574
|
+
red: "#D92916"
|
|
28575
|
+
};
|
|
28576
|
+
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28577
|
+
|
|
28166
28578
|
const LockedLine = props => {
|
|
28167
28579
|
const {
|
|
28168
28580
|
color: color$1,
|
|
@@ -28179,7 +28591,7 @@ const LockedLine = props => {
|
|
|
28179
28591
|
line = /*#__PURE__*/React.createElement(LineType, {
|
|
28180
28592
|
point1: point1.coord,
|
|
28181
28593
|
point2: point2.coord,
|
|
28182
|
-
color:
|
|
28594
|
+
color: lockedFigureColors[color$1],
|
|
28183
28595
|
style: lineStyle
|
|
28184
28596
|
});
|
|
28185
28597
|
} else {
|
|
@@ -28193,8 +28605,8 @@ const LockedLine = props => {
|
|
|
28193
28605
|
y: point1.coord[1],
|
|
28194
28606
|
svgCircleProps: {
|
|
28195
28607
|
style: {
|
|
28196
|
-
fill: point1.filled ?
|
|
28197
|
-
stroke:
|
|
28608
|
+
fill: point1.filled ? lockedFigureColors[point1.color] : color.white,
|
|
28609
|
+
stroke: lockedFigureColors[point1.color],
|
|
28198
28610
|
strokeWidth: spacing.xxxxSmall_2
|
|
28199
28611
|
}
|
|
28200
28612
|
}
|
|
@@ -28203,8 +28615,8 @@ const LockedLine = props => {
|
|
|
28203
28615
|
y: point2.coord[1],
|
|
28204
28616
|
svgCircleProps: {
|
|
28205
28617
|
style: {
|
|
28206
|
-
fill: point2.filled ?
|
|
28207
|
-
stroke:
|
|
28618
|
+
fill: point2.filled ? lockedFigureColors[point2.color] : color.white,
|
|
28619
|
+
stroke: lockedFigureColors[point2.color],
|
|
28208
28620
|
strokeWidth: spacing.xxxxSmall_2
|
|
28209
28621
|
}
|
|
28210
28622
|
}
|
|
@@ -28223,8 +28635,8 @@ const LockedPoint = props => {
|
|
|
28223
28635
|
y: y,
|
|
28224
28636
|
svgCircleProps: {
|
|
28225
28637
|
style: {
|
|
28226
|
-
fill: filled ?
|
|
28227
|
-
stroke:
|
|
28638
|
+
fill: filled ? lockedFigureColors[color$1] : color.white,
|
|
28639
|
+
stroke: lockedFigureColors[color$1],
|
|
28228
28640
|
strokeWidth: spacing.xxxxSmall_2
|
|
28229
28641
|
}
|
|
28230
28642
|
}
|
|
@@ -28459,6 +28871,7 @@ function scaleCommandBy(scaleFactor) {
|
|
|
28459
28871
|
// don't want that.
|
|
28460
28872
|
const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).curve(0, -0.25, -2.75, -2.5, -3, -4).scale(1.4).build();
|
|
28461
28873
|
function Arrowhead(props) {
|
|
28874
|
+
var _props$color;
|
|
28462
28875
|
const [point] = useTransform([props.x, props.y]);
|
|
28463
28876
|
return /*#__PURE__*/React.createElement("g", {
|
|
28464
28877
|
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
@@ -28468,7 +28881,7 @@ function Arrowhead(props) {
|
|
|
28468
28881
|
d: arrowPath,
|
|
28469
28882
|
fill: "none",
|
|
28470
28883
|
style: {
|
|
28471
|
-
stroke: "inherit"
|
|
28884
|
+
stroke: (_props$color = props.color) != null ? _props$color : "inherit"
|
|
28472
28885
|
},
|
|
28473
28886
|
strokeLinejoin: "round",
|
|
28474
28887
|
strokeLinecap: "round"
|
|
@@ -28577,7 +28990,8 @@ const MovableLine = props => {
|
|
|
28577
28990
|
const defaultGraphConfig = {
|
|
28578
28991
|
range: [[0, 1], [0, 1]],
|
|
28579
28992
|
snapStep: [1, 1],
|
|
28580
|
-
markings: "none"
|
|
28993
|
+
markings: "none",
|
|
28994
|
+
showTooltips: false
|
|
28581
28995
|
};
|
|
28582
28996
|
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28583
28997
|
function useGraphConfig() {
|
|
@@ -28588,10 +29002,12 @@ function useGraphConfig() {
|
|
|
28588
29002
|
// graph.
|
|
28589
29003
|
const hitboxSizePx = 48;
|
|
28590
29004
|
const StyledMovablePoint = props => {
|
|
29005
|
+
var _Object$entries$find$, _Object$entries$find;
|
|
28591
29006
|
const {
|
|
28592
29007
|
range,
|
|
28593
29008
|
snapStep,
|
|
28594
|
-
markings
|
|
29009
|
+
markings,
|
|
29010
|
+
showTooltips
|
|
28595
29011
|
} = useGraphConfig();
|
|
28596
29012
|
const hitboxRef = useRef(null);
|
|
28597
29013
|
const {
|
|
@@ -28599,6 +29015,10 @@ const StyledMovablePoint = props => {
|
|
|
28599
29015
|
onMove,
|
|
28600
29016
|
color: color$1 = color.blue
|
|
28601
29017
|
} = props;
|
|
29018
|
+
|
|
29019
|
+
// WB Tooltip requires a color name for the background color.
|
|
29020
|
+
// Since the color in props is a hex value, a reverse lookup is needed.
|
|
29021
|
+
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
29022
|
const {
|
|
28603
29023
|
dragging
|
|
28604
29024
|
} = useMovable({
|
|
@@ -28616,19 +29036,20 @@ const StyledMovablePoint = props => {
|
|
|
28616
29036
|
const [[_, horizontalStartY]] = useTransform([0, yMin]);
|
|
28617
29037
|
const [[__, horizontalEndY]] = useTransform([0, yMax]);
|
|
28618
29038
|
const showHairlines = dragging && markings !== "none";
|
|
28619
|
-
|
|
29039
|
+
const hairlines = /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
28620
29040
|
x1: verticalStartX,
|
|
28621
29041
|
y1: y,
|
|
28622
29042
|
x2: verticalEndX,
|
|
28623
29043
|
y2: y,
|
|
28624
|
-
stroke: color
|
|
29044
|
+
stroke: color$1
|
|
28625
29045
|
}), /*#__PURE__*/React.createElement("line", {
|
|
28626
29046
|
x1: x,
|
|
28627
29047
|
y1: horizontalStartY,
|
|
28628
29048
|
x2: x,
|
|
28629
29049
|
y2: horizontalEndY,
|
|
28630
|
-
stroke: color
|
|
28631
|
-
}))
|
|
29050
|
+
stroke: color$1
|
|
29051
|
+
}));
|
|
29052
|
+
const svgForPoint = /*#__PURE__*/React.createElement("g", {
|
|
28632
29053
|
ref: hitboxRef,
|
|
28633
29054
|
className: pointClasses,
|
|
28634
29055
|
tabIndex: 0,
|
|
@@ -28661,7 +29082,15 @@ const StyledMovablePoint = props => {
|
|
|
28661
29082
|
fill: color$1
|
|
28662
29083
|
},
|
|
28663
29084
|
"data-testid": "movable-point__center"
|
|
28664
|
-
}))
|
|
29085
|
+
}));
|
|
29086
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
29087
|
+
autoUpdate: true,
|
|
29088
|
+
backgroundColor: wbColorName,
|
|
29089
|
+
content: `(${point[0]}, ${point[1]})`,
|
|
29090
|
+
contentStyle: {
|
|
29091
|
+
color: "white"
|
|
29092
|
+
}
|
|
29093
|
+
}, svgForPoint) : svgForPoint);
|
|
28665
29094
|
};
|
|
28666
29095
|
|
|
28667
29096
|
const SegmentGraph = props => {
|
|
@@ -29047,22 +29476,27 @@ function AxisArrows() {
|
|
|
29047
29476
|
const {
|
|
29048
29477
|
range: [[xMin, xMax], [yMin, yMax]]
|
|
29049
29478
|
} = useGraphConfig();
|
|
29479
|
+
const axisColor = "var(--mafs-fg)";
|
|
29050
29480
|
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29481
|
+
color: axisColor,
|
|
29482
|
+
x: xMin,
|
|
29483
|
+
y: 0,
|
|
29484
|
+
angle: 180
|
|
29485
|
+
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29486
|
+
color: axisColor,
|
|
29051
29487
|
x: xMax,
|
|
29052
29488
|
y: 0,
|
|
29053
29489
|
angle: 0
|
|
29054
29490
|
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29491
|
+
color: axisColor,
|
|
29055
29492
|
x: 0,
|
|
29056
29493
|
y: yMin,
|
|
29057
|
-
angle:
|
|
29058
|
-
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29059
|
-
x: xMin,
|
|
29060
|
-
y: 0,
|
|
29061
|
-
angle: 180
|
|
29494
|
+
angle: 270
|
|
29062
29495
|
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29496
|
+
color: axisColor,
|
|
29063
29497
|
x: 0,
|
|
29064
29498
|
y: yMax,
|
|
29065
|
-
angle:
|
|
29499
|
+
angle: 90
|
|
29066
29500
|
}));
|
|
29067
29501
|
}
|
|
29068
29502
|
|
|
@@ -29188,7 +29622,7 @@ const Grid = props => {
|
|
|
29188
29622
|
return props.markings === "none" ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
|
|
29189
29623
|
xAxis: axisOptions(props, 0),
|
|
29190
29624
|
yAxis: axisOptions(props, 1)
|
|
29191
|
-
}),
|
|
29625
|
+
}),
|
|
29192
29626
|
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
29193
29627
|
props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisTicks, {
|
|
29194
29628
|
range: props.range,
|
|
@@ -29587,7 +30021,7 @@ class NumberInput extends React.Component {
|
|
|
29587
30021
|
const placeholder = this.props.placeholder;
|
|
29588
30022
|
return _.isFinite(placeholder) ? +placeholder : null;
|
|
29589
30023
|
}
|
|
29590
|
-
const result = firstNumericalParse(value);
|
|
30024
|
+
const result = firstNumericalParse(value, this.context.strings);
|
|
29591
30025
|
return _.isFinite(result) ? result : this.props.value;
|
|
29592
30026
|
};
|
|
29593
30027
|
/* Set text input focus to this input */
|
|
@@ -29617,7 +30051,7 @@ class NumberInput extends React.Component {
|
|
|
29617
30051
|
if (value == null) {
|
|
29618
30052
|
return true;
|
|
29619
30053
|
}
|
|
29620
|
-
const val = firstNumericalParse(value);
|
|
30054
|
+
const val = firstNumericalParse(value, this.context.strings);
|
|
29621
30055
|
const checkValidity = this.props.checkValidity;
|
|
29622
30056
|
return _.isFinite(val) && checkValidity(val);
|
|
29623
30057
|
};
|
|
@@ -29713,6 +30147,7 @@ class NumberInput extends React.Component {
|
|
|
29713
30147
|
}
|
|
29714
30148
|
}
|
|
29715
30149
|
}
|
|
30150
|
+
NumberInput.contextType = PerseusI18nContext;
|
|
29716
30151
|
NumberInput.propTypes = {
|
|
29717
30152
|
value: PropTypes.number,
|
|
29718
30153
|
format: PropTypes.string,
|
|
@@ -30448,7 +30883,8 @@ const MafsGraph = props => {
|
|
|
30448
30883
|
value: {
|
|
30449
30884
|
range: state.range,
|
|
30450
30885
|
snapStep: state.snapStep,
|
|
30451
|
-
markings: props.markings
|
|
30886
|
+
markings: props.markings,
|
|
30887
|
+
showTooltips: !!props.showTooltips
|
|
30452
30888
|
}
|
|
30453
30889
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30454
30890
|
style: {
|
|
@@ -31710,9 +32146,9 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
31710
32146
|
// isClickToAddPoints() only applies to points and polygons
|
|
31711
32147
|
if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
|
|
31712
32148
|
if (this.props.graph.type === "point") {
|
|
31713
|
-
instructions =
|
|
32149
|
+
instructions = this.context.strings.addPoints;
|
|
31714
32150
|
} else if (this.props.graph.type === "polygon") {
|
|
31715
|
-
instructions =
|
|
32151
|
+
instructions = this.context.strings.addVertices;
|
|
31716
32152
|
}
|
|
31717
32153
|
} else {
|
|
31718
32154
|
instructions = undefined;
|
|
@@ -31752,6 +32188,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
31752
32188
|
}));
|
|
31753
32189
|
}
|
|
31754
32190
|
}
|
|
32191
|
+
LegacyInteractiveGraph.contextType = PerseusI18nContext;
|
|
31755
32192
|
LegacyInteractiveGraph.defaultProps = {
|
|
31756
32193
|
labels: ["x", "y"],
|
|
31757
32194
|
range: [[-10, 10], [-10, 10]],
|
|
@@ -31798,7 +32235,8 @@ class InteractiveGraph extends React.Component {
|
|
|
31798
32235
|
ref: this.mafsRef,
|
|
31799
32236
|
gridStep: gridStep,
|
|
31800
32237
|
snapStep: snapStep,
|
|
31801
|
-
box: box
|
|
32238
|
+
box: box,
|
|
32239
|
+
showTooltips: !!this.props.showTooltips
|
|
31802
32240
|
}));
|
|
31803
32241
|
}
|
|
31804
32242
|
return /*#__PURE__*/React.createElement(LegacyInteractiveGraph, _extends({
|
|
@@ -33340,6 +33778,9 @@ var globalStyles = /*#__PURE__*/Object.freeze({
|
|
|
33340
33778
|
});
|
|
33341
33779
|
|
|
33342
33780
|
const AnswerChoices = props => {
|
|
33781
|
+
const {
|
|
33782
|
+
strings
|
|
33783
|
+
} = usePerseusI18n();
|
|
33343
33784
|
const onAnswerChange = selected => {
|
|
33344
33785
|
const {
|
|
33345
33786
|
choices,
|
|
@@ -33357,6 +33798,7 @@ const AnswerChoices = props => {
|
|
|
33357
33798
|
value: content,
|
|
33358
33799
|
label: /*#__PURE__*/React.createElement(Renderer, {
|
|
33359
33800
|
content: content,
|
|
33801
|
+
strings: strings,
|
|
33360
33802
|
inline: true
|
|
33361
33803
|
})
|
|
33362
33804
|
}));
|
|
@@ -33386,14 +33828,13 @@ const AnswerChoices = props => {
|
|
|
33386
33828
|
}));
|
|
33387
33829
|
};
|
|
33388
33830
|
|
|
33389
|
-
const strings = {
|
|
33390
|
-
hideAnswersToggleLabel: i18n._("Hide answer choices")
|
|
33391
|
-
};
|
|
33392
|
-
|
|
33393
33831
|
const HideAnswersToggle = props => {
|
|
33394
33832
|
const idFactory = useUniqueIdWithMock();
|
|
33395
33833
|
const switchId = idFactory.get("hide-answers-toggle");
|
|
33396
33834
|
const labelId = idFactory.get("hide-answers-label");
|
|
33835
|
+
const {
|
|
33836
|
+
strings
|
|
33837
|
+
} = usePerseusI18n();
|
|
33397
33838
|
return /*#__PURE__*/React.createElement(View, {
|
|
33398
33839
|
style: styles$g.switchWrapper
|
|
33399
33840
|
}, /*#__PURE__*/React.createElement(Switch, {
|
|
@@ -33434,9 +33875,12 @@ const AnswerPill = props => {
|
|
|
33434
33875
|
hovered
|
|
33435
33876
|
} = props;
|
|
33436
33877
|
const idFactory = useUniqueIdWithMock();
|
|
33437
|
-
const
|
|
33438
|
-
|
|
33439
|
-
|
|
33878
|
+
const {
|
|
33879
|
+
strings
|
|
33880
|
+
} = usePerseusI18n();
|
|
33881
|
+
const answerString = selectedAnswers.length > 1 ? strings.answers({
|
|
33882
|
+
num: selectedAnswers.length
|
|
33883
|
+
}) : selectedAnswers[0];
|
|
33440
33884
|
|
|
33441
33885
|
// It should no longer be possible to interact with an answer after it
|
|
33442
33886
|
// has been labeled (answered) correctly.
|
|
@@ -33463,6 +33907,7 @@ const AnswerPill = props => {
|
|
|
33463
33907
|
style: [style, popperStyle, styles$f.pill, correct && styles$f.correct, incorrect && styles$f.incorrect, (focused || hovered) && BringToFront]
|
|
33464
33908
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
33465
33909
|
content: answerString,
|
|
33910
|
+
strings: strings,
|
|
33466
33911
|
inline: true
|
|
33467
33912
|
})));
|
|
33468
33913
|
};
|
|
@@ -33557,10 +34002,8 @@ class Marker extends React.Component {
|
|
|
33557
34002
|
const markerDisabled = showCorrectness === "correct";
|
|
33558
34003
|
const active = hovered || focused;
|
|
33559
34004
|
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
|
|
34005
|
+
style: [styles$e.marker, active && !markerDisabled && styles$e.markerActive],
|
|
34006
|
+
"aria-label": markerDisabled ? this.context.strings.correctExcited : label
|
|
33564
34007
|
}, this.renderIcon()), !!selected && showAnswer && /*#__PURE__*/React.createElement(AnswerPill, {
|
|
33565
34008
|
selectedAnswers: selected,
|
|
33566
34009
|
showCorrectness: showCorrectness,
|
|
@@ -33572,6 +34015,7 @@ class Marker extends React.Component {
|
|
|
33572
34015
|
}));
|
|
33573
34016
|
}
|
|
33574
34017
|
}
|
|
34018
|
+
Marker.contextType = PerseusI18nContext;
|
|
33575
34019
|
Marker.defaultProps = {
|
|
33576
34020
|
selected: []
|
|
33577
34021
|
};
|
|
@@ -34143,8 +34587,11 @@ class LabelImage extends React.Component {
|
|
|
34143
34587
|
multipleAnswers,
|
|
34144
34588
|
hideChoicesFromInstructions: hideChoices
|
|
34145
34589
|
} = this.props;
|
|
34146
|
-
const
|
|
34147
|
-
|
|
34590
|
+
const {
|
|
34591
|
+
strings
|
|
34592
|
+
} = this.context;
|
|
34593
|
+
const promptString = isMobile ? multipleAnswers ? strings.tapMultiple : strings.tapSingle : multipleAnswers ? strings.clickMultiple : strings.clickSingle;
|
|
34594
|
+
const choicesString = strings.choices;
|
|
34148
34595
|
return /*#__PURE__*/React.createElement("div", {
|
|
34149
34596
|
className: classNames("perseus-label-image-widget-instructions", css(styles$d.instructions))
|
|
34150
34597
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -34155,7 +34602,8 @@ class LabelImage extends React.Component {
|
|
|
34155
34602
|
className: css(styles$d.instructionsChoice),
|
|
34156
34603
|
key: index
|
|
34157
34604
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
34158
|
-
content: choice
|
|
34605
|
+
content: choice,
|
|
34606
|
+
strings: strings
|
|
34159
34607
|
})))));
|
|
34160
34608
|
}
|
|
34161
34609
|
render() {
|
|
@@ -34206,6 +34654,7 @@ class LabelImage extends React.Component {
|
|
|
34206
34654
|
}));
|
|
34207
34655
|
}
|
|
34208
34656
|
}
|
|
34657
|
+
LabelImage.contextType = PerseusI18nContext;
|
|
34209
34658
|
const styles$d = StyleSheet.create({
|
|
34210
34659
|
instructions: {
|
|
34211
34660
|
paddingBottom: 16
|
|
@@ -34519,7 +34968,8 @@ class Draggable extends React.Component {
|
|
|
34519
34968
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
34520
34969
|
content: this.props.content,
|
|
34521
34970
|
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "draggable"),
|
|
34522
|
-
onRender: this.props.onRender
|
|
34971
|
+
onRender: this.props.onRender,
|
|
34972
|
+
strings: this.context.strings
|
|
34523
34973
|
}));
|
|
34524
34974
|
}
|
|
34525
34975
|
componentDidUpdate(prevProps) {
|
|
@@ -34544,6 +34994,7 @@ class Draggable extends React.Component {
|
|
|
34544
34994
|
}
|
|
34545
34995
|
}
|
|
34546
34996
|
}
|
|
34997
|
+
Draggable.contextType = PerseusI18nContext;
|
|
34547
34998
|
Draggable.defaultProps = {
|
|
34548
34999
|
includePadding: true,
|
|
34549
35000
|
type: ItemState.STATIC,
|
|
@@ -35104,12 +35555,14 @@ class Matcher extends React.Component {
|
|
|
35104
35555
|
className: css(styles$b.column, styles$b.columnLabel)
|
|
35105
35556
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35106
35557
|
content: this.props.labels[0] || "...",
|
|
35107
|
-
linterContext: this.props.linterContext
|
|
35558
|
+
linterContext: this.props.linterContext,
|
|
35559
|
+
strings: this.context.strings
|
|
35108
35560
|
})), /*#__PURE__*/React.createElement("th", {
|
|
35109
35561
|
className: css(styles$b.column, styles$b.columnRight, styles$b.columnLabel)
|
|
35110
35562
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35111
35563
|
content: this.props.labels[1] || "...",
|
|
35112
|
-
linterContext: this.props.linterContext
|
|
35564
|
+
linterContext: this.props.linterContext,
|
|
35565
|
+
strings: this.context.strings
|
|
35113
35566
|
}))), /*#__PURE__*/React.createElement("tr", {
|
|
35114
35567
|
className: css(styles$b.row)
|
|
35115
35568
|
}, /*#__PURE__*/React.createElement("td", {
|
|
@@ -35146,6 +35599,7 @@ class Matcher extends React.Component {
|
|
|
35146
35599
|
})))));
|
|
35147
35600
|
}
|
|
35148
35601
|
}
|
|
35602
|
+
Matcher.contextType = PerseusI18nContext;
|
|
35149
35603
|
Matcher.propTypes = {
|
|
35150
35604
|
apiOptions: ApiOptions.propTypes,
|
|
35151
35605
|
labels: PropTypes.array,
|
|
@@ -35431,8 +35885,58 @@ class Matrix extends React.Component {
|
|
|
35431
35885
|
};
|
|
35432
35886
|
};
|
|
35433
35887
|
this.simpleValidate = rubric => {
|
|
35434
|
-
|
|
35435
|
-
|
|
35888
|
+
return Matrix.validate(this.getUserInput(), rubric, this.context.strings);
|
|
35889
|
+
};
|
|
35890
|
+
}
|
|
35891
|
+
static validate(state, rubric, strings) {
|
|
35892
|
+
const solution = rubric.answers;
|
|
35893
|
+
const supplied = state.answers;
|
|
35894
|
+
const solutionSize = getMatrixSize(solution);
|
|
35895
|
+
const suppliedSize = getMatrixSize(supplied);
|
|
35896
|
+
const incorrectSize = solutionSize[0] !== suppliedSize[0] || solutionSize[1] !== suppliedSize[1];
|
|
35897
|
+
const createValidator = KhanAnswerTypes.number.createValidatorFunctional;
|
|
35898
|
+
let message = null;
|
|
35899
|
+
let hasEmptyCell = false;
|
|
35900
|
+
let incorrect = false;
|
|
35901
|
+
_(suppliedSize[0]).times(row => {
|
|
35902
|
+
_(suppliedSize[1]).times(col => {
|
|
35903
|
+
if (supplied[row][col] == null || supplied[row][col].toString().length === 0) {
|
|
35904
|
+
hasEmptyCell = true;
|
|
35905
|
+
}
|
|
35906
|
+
if (!incorrectSize) {
|
|
35907
|
+
const validator = createValidator(solution[row][col], {
|
|
35908
|
+
simplify: true
|
|
35909
|
+
}, strings);
|
|
35910
|
+
const result = validator(supplied[row][col]);
|
|
35911
|
+
if (result.message) {
|
|
35912
|
+
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
35913
|
+
message = result.message;
|
|
35914
|
+
}
|
|
35915
|
+
if (!result.correct) {
|
|
35916
|
+
incorrect = true;
|
|
35917
|
+
}
|
|
35918
|
+
}
|
|
35919
|
+
});
|
|
35920
|
+
});
|
|
35921
|
+
if (hasEmptyCell) {
|
|
35922
|
+
return {
|
|
35923
|
+
type: "invalid",
|
|
35924
|
+
message: strings.fillAllCells
|
|
35925
|
+
};
|
|
35926
|
+
}
|
|
35927
|
+
if (incorrectSize) {
|
|
35928
|
+
return {
|
|
35929
|
+
type: "points",
|
|
35930
|
+
earned: 0,
|
|
35931
|
+
total: 1,
|
|
35932
|
+
message: null
|
|
35933
|
+
};
|
|
35934
|
+
}
|
|
35935
|
+
return {
|
|
35936
|
+
type: "points",
|
|
35937
|
+
earned: incorrect ? 0 : 1,
|
|
35938
|
+
total: 1,
|
|
35939
|
+
message: message
|
|
35436
35940
|
};
|
|
35437
35941
|
}
|
|
35438
35942
|
componentDidMount() {
|
|
@@ -35474,7 +35978,8 @@ class Matrix extends React.Component {
|
|
|
35474
35978
|
className: "matrix-prefix"
|
|
35475
35979
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35476
35980
|
content: this.props.prefix,
|
|
35477
|
-
linterContext: this.props.linterContext
|
|
35981
|
+
linterContext: this.props.linterContext,
|
|
35982
|
+
strings: this.context.strings
|
|
35478
35983
|
})), /*#__PURE__*/React.createElement("div", {
|
|
35479
35984
|
className: "matrix-input"
|
|
35480
35985
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -35587,10 +36092,12 @@ class Matrix extends React.Component {
|
|
|
35587
36092
|
className: "matrix-suffix"
|
|
35588
36093
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
35589
36094
|
content: this.props.suffix,
|
|
35590
|
-
linterContext: this.props.linterContext
|
|
36095
|
+
linterContext: this.props.linterContext,
|
|
36096
|
+
strings: this.context.strings
|
|
35591
36097
|
})));
|
|
35592
36098
|
}
|
|
35593
36099
|
}
|
|
36100
|
+
Matrix.contextType = PerseusI18nContext;
|
|
35594
36101
|
Matrix.defaultProps = {
|
|
35595
36102
|
matrixBoardSize: [3, 3],
|
|
35596
36103
|
answers: [[]],
|
|
@@ -35600,59 +36107,6 @@ Matrix.defaultProps = {
|
|
|
35600
36107
|
apiOptions: ApiOptions.defaults,
|
|
35601
36108
|
linterContext: linterContextDefault
|
|
35602
36109
|
};
|
|
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
36110
|
const propTransform$1 = editorProps => {
|
|
35657
36111
|
// Remove answers before passing to widget
|
|
35658
36112
|
const blankAnswers = _(editorProps.matrixBoardSize[0]).times(function () {
|
|
@@ -36690,8 +37144,8 @@ class Molecule extends React.Component {
|
|
|
36690
37144
|
// eslint-disable-next-line react/no-string-refs
|
|
36691
37145
|
,
|
|
36692
37146
|
ref: "canvas"
|
|
36693
|
-
},
|
|
36694
|
-
content: this.props.smiles
|
|
37147
|
+
}, this.context.strings.molecularDrawing({
|
|
37148
|
+
content: this.props.smiles || ""
|
|
36695
37149
|
}));
|
|
36696
37150
|
if (this.state.error) {
|
|
36697
37151
|
content = /*#__PURE__*/React.createElement("div", {
|
|
@@ -36703,6 +37157,7 @@ class Molecule extends React.Component {
|
|
|
36703
37157
|
}, content);
|
|
36704
37158
|
}
|
|
36705
37159
|
}
|
|
37160
|
+
Molecule.contextType = PerseusI18nContext;
|
|
36706
37161
|
class MoleculeWidget extends React.Component {
|
|
36707
37162
|
constructor(...args) {
|
|
36708
37163
|
super(...args);
|
|
@@ -37165,18 +37620,21 @@ class NumberLine extends React.Component {
|
|
|
37165
37620
|
};
|
|
37166
37621
|
}
|
|
37167
37622
|
render() {
|
|
37623
|
+
const {
|
|
37624
|
+
strings
|
|
37625
|
+
} = this.context;
|
|
37168
37626
|
const divisionRange = this.props.divisionRange;
|
|
37169
37627
|
const divRangeString = divisionRange[0] + EN_DASH + divisionRange[1];
|
|
37170
37628
|
const invalidNumDivisions = this.props.numDivisions < divisionRange[0] || this.props.numDivisions > divisionRange[1];
|
|
37171
37629
|
const inequalityControls = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("input", {
|
|
37172
37630
|
type: "button",
|
|
37173
37631
|
className: "simple-button",
|
|
37174
|
-
value:
|
|
37632
|
+
value: strings.switchDirection,
|
|
37175
37633
|
onClick: this.handleReverse
|
|
37176
37634
|
}), /*#__PURE__*/React.createElement("input", {
|
|
37177
37635
|
type: "button",
|
|
37178
37636
|
className: "simple-button",
|
|
37179
|
-
value: _(["le", "ge"]).contains(this.props.rel) ?
|
|
37637
|
+
value: _(["le", "ge"]).contains(this.props.rel) ? strings.circleOpen : strings.circleFilled,
|
|
37180
37638
|
onClick: this.handleToggleStrict
|
|
37181
37639
|
}));
|
|
37182
37640
|
let tickCtrl;
|
|
@@ -37187,7 +37645,7 @@ class NumberLine extends React.Component {
|
|
|
37187
37645
|
} else {
|
|
37188
37646
|
Input = NumberInput;
|
|
37189
37647
|
}
|
|
37190
|
-
tickCtrl = /*#__PURE__*/React.createElement("label", null,
|
|
37648
|
+
tickCtrl = /*#__PURE__*/React.createElement("label", null, strings.numDivisions, " ", /*#__PURE__*/React.createElement(Input
|
|
37191
37649
|
// eslint-disable-next-line react/no-string-refs
|
|
37192
37650
|
, {
|
|
37193
37651
|
ref: "tick-ctrl",
|
|
@@ -37204,13 +37662,14 @@ class NumberLine extends React.Component {
|
|
|
37204
37662
|
className: "perseus-widget " + "perseus-widget-interactive-number-line"
|
|
37205
37663
|
}, tickCtrl, !this.isValid() ? /*#__PURE__*/React.createElement("div", {
|
|
37206
37664
|
className: "perseus-error"
|
|
37207
|
-
},
|
|
37665
|
+
}, "Invalid number line configuration.") : this.props.isTickCtrl && invalidNumDivisions ? /*#__PURE__*/React.createElement("div", {
|
|
37208
37666
|
className: "perseus-error"
|
|
37209
|
-
},
|
|
37667
|
+
}, strings.divisions({
|
|
37210
37668
|
divRangeString: divRangeString
|
|
37211
37669
|
})) : this._renderGraphie(), !this.props.static && this.props.isInequality && inequalityControls);
|
|
37212
37670
|
}
|
|
37213
37671
|
}
|
|
37672
|
+
NumberLine.contextType = PerseusI18nContext;
|
|
37214
37673
|
NumberLine.defaultProps = {
|
|
37215
37674
|
range: [0, 10],
|
|
37216
37675
|
labelStyle: "decimal",
|
|
@@ -37437,7 +37896,8 @@ class Card extends React.Component {
|
|
|
37437
37896
|
}, /*#__PURE__*/React.createElement("div", {
|
|
37438
37897
|
className: className.join(" ")
|
|
37439
37898
|
}, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
|
|
37440
|
-
linterContext: this.props.linterContext
|
|
37899
|
+
linterContext: this.props.linterContext,
|
|
37900
|
+
strings: this.context.strings
|
|
37441
37901
|
}))));
|
|
37442
37902
|
}
|
|
37443
37903
|
shouldComponentUpdate(nextProps, nextState) {
|
|
@@ -37490,6 +37950,7 @@ class Card extends React.Component {
|
|
|
37490
37950
|
document.removeEventListener("touchmove", this.onMouseMove);
|
|
37491
37951
|
}
|
|
37492
37952
|
}
|
|
37953
|
+
Card.contextType = PerseusI18nContext;
|
|
37493
37954
|
Card.propTypes = {
|
|
37494
37955
|
floating: PropTypes.bool.isRequired,
|
|
37495
37956
|
animating: PropTypes.bool,
|
|
@@ -38779,7 +39240,7 @@ class HighlightSetRenderer extends React.PureComponent {
|
|
|
38779
39240
|
}
|
|
38780
39241
|
const hoveredHighlight = this.props.highlights[hoveredHighlightKey];
|
|
38781
39242
|
return /*#__PURE__*/React.createElement(HighlightTooltip, {
|
|
38782
|
-
label:
|
|
39243
|
+
label: this.context.strings.removeHighlight,
|
|
38783
39244
|
focusNode: hoveredHighlight.domRange.endContainer,
|
|
38784
39245
|
focusOffset: hoveredHighlight.domRange.endOffset,
|
|
38785
39246
|
offsetParent: this.props.offsetParent,
|
|
@@ -38809,6 +39270,7 @@ class HighlightSetRenderer extends React.PureComponent {
|
|
|
38809
39270
|
})), this.props.editable && this._renderTooltip());
|
|
38810
39271
|
}
|
|
38811
39272
|
}
|
|
39273
|
+
HighlightSetRenderer.contextType = PerseusI18nContext;
|
|
38812
39274
|
|
|
38813
39275
|
/* eslint-disable react/no-unsafe */
|
|
38814
39276
|
class SelectionTracker extends React.PureComponent {
|
|
@@ -39009,7 +39471,7 @@ class HighlightingUI extends React.PureComponent {
|
|
|
39009
39471
|
onRemoveHighlight: this.props.onRemoveHighlight,
|
|
39010
39472
|
zIndexes: this.props.zIndexes
|
|
39011
39473
|
}), this._selectionIsValid(trackedSelection) && !userIsMouseSelecting && /*#__PURE__*/React.createElement(HighlightTooltip, {
|
|
39012
|
-
label:
|
|
39474
|
+
label: this.context.strings.addHighlight,
|
|
39013
39475
|
onClick: () => this._handleAddHighlight(trackedSelection.proposedHighlight),
|
|
39014
39476
|
focusNode: trackedSelection.focusNode,
|
|
39015
39477
|
focusOffset: trackedSelection.focusOffset,
|
|
@@ -39017,6 +39479,7 @@ class HighlightingUI extends React.PureComponent {
|
|
|
39017
39479
|
})));
|
|
39018
39480
|
}
|
|
39019
39481
|
}
|
|
39482
|
+
HighlightingUI.contextType = PerseusI18nContext;
|
|
39020
39483
|
|
|
39021
39484
|
/**
|
|
39022
39485
|
* This component, whenever its content updates, traverses the DOM to find
|
|
@@ -39307,16 +39770,30 @@ class RefStart extends React.Component {
|
|
|
39307
39770
|
render() {
|
|
39308
39771
|
return /*#__PURE__*/React.createElement("span", {
|
|
39309
39772
|
style: REF_STYLE
|
|
39310
|
-
},
|
|
39773
|
+
}, "_");
|
|
39311
39774
|
}
|
|
39312
39775
|
}
|
|
39313
39776
|
class RefEnd extends React.Component {
|
|
39314
39777
|
render() {
|
|
39315
39778
|
return /*#__PURE__*/React.createElement("span", {
|
|
39316
39779
|
style: REF_STYLE
|
|
39317
|
-
},
|
|
39780
|
+
}, "_");
|
|
39318
39781
|
}
|
|
39319
39782
|
}
|
|
39783
|
+
const AltText = ({
|
|
39784
|
+
id,
|
|
39785
|
+
number
|
|
39786
|
+
}) => {
|
|
39787
|
+
const {
|
|
39788
|
+
strings
|
|
39789
|
+
} = usePerseusI18n();
|
|
39790
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
39791
|
+
key: "alt-text",
|
|
39792
|
+
className: "perseus-sr-only"
|
|
39793
|
+
}, strings[id]({
|
|
39794
|
+
number
|
|
39795
|
+
}));
|
|
39796
|
+
};
|
|
39320
39797
|
const rules = {
|
|
39321
39798
|
newline: SimpleMarkdown.defaultRules.newline,
|
|
39322
39799
|
paragraph: SimpleMarkdown.defaultRules.paragraph,
|
|
@@ -39485,12 +39962,10 @@ const rules = {
|
|
|
39485
39962
|
"aria-hidden": "true"
|
|
39486
39963
|
}, /*#__PURE__*/React.createElement("span", {
|
|
39487
39964
|
style: SQUARE_LABEL_STYLE
|
|
39488
|
-
}, node.content)), /*#__PURE__*/React.createElement(
|
|
39489
|
-
|
|
39490
|
-
className: "perseus-sr-only"
|
|
39491
|
-
}, i18n.$_("[Marker for question %(number)s]", {
|
|
39965
|
+
}, node.content)), /*#__PURE__*/React.createElement(AltText, {
|
|
39966
|
+
id: "questionMarker",
|
|
39492
39967
|
number: node.content
|
|
39493
|
-
})
|
|
39968
|
+
}), node.space ? "\u00A0" : null];
|
|
39494
39969
|
}
|
|
39495
39970
|
},
|
|
39496
39971
|
circleLabel: {
|
|
@@ -39511,12 +39986,10 @@ const rules = {
|
|
|
39511
39986
|
"aria-hidden": true
|
|
39512
39987
|
}, /*#__PURE__*/React.createElement("span", {
|
|
39513
39988
|
style: CIRCLE_LABEL_STYLE
|
|
39514
|
-
}, node.content)), /*#__PURE__*/React.createElement(
|
|
39515
|
-
|
|
39516
|
-
className: "perseus-sr-only"
|
|
39517
|
-
}, i18n.$_("[Circle marker %(number)s]", {
|
|
39989
|
+
}, node.content)), /*#__PURE__*/React.createElement(AltText, {
|
|
39990
|
+
id: "circleMarker",
|
|
39518
39991
|
number: node.content
|
|
39519
|
-
})
|
|
39992
|
+
}), node.space ? "\u00A0" : null];
|
|
39520
39993
|
}
|
|
39521
39994
|
},
|
|
39522
39995
|
squareBracketRef: {
|
|
@@ -39536,12 +40009,10 @@ const rules = {
|
|
|
39536
40009
|
key: "visual-brackets",
|
|
39537
40010
|
className: "perseus-passage-bracket-label",
|
|
39538
40011
|
"aria-hidden": "true"
|
|
39539
|
-
}, "[", node.content, "]"), /*#__PURE__*/React.createElement(
|
|
39540
|
-
|
|
39541
|
-
className: "perseus-sr-only"
|
|
39542
|
-
}, i18n.$_("[Sentence %(number)s]", {
|
|
40012
|
+
}, "[", node.content, "]"), /*#__PURE__*/React.createElement(AltText, {
|
|
40013
|
+
id: "sentenceMarker",
|
|
39543
40014
|
number: node.content
|
|
39544
|
-
})
|
|
40015
|
+
}), node.space ? "\u00A0" : null];
|
|
39545
40016
|
}
|
|
39546
40017
|
},
|
|
39547
40018
|
highlight: {
|
|
@@ -39932,15 +40403,18 @@ class Passage extends React.Component {
|
|
|
39932
40403
|
_renderInstructions(parseState) {
|
|
39933
40404
|
const firstQuestionNumber = parseState.firstQuestionRef;
|
|
39934
40405
|
const firstSentenceRef = parseState.firstSentenceRef;
|
|
40406
|
+
const {
|
|
40407
|
+
strings
|
|
40408
|
+
} = this.context;
|
|
39935
40409
|
let instructions = "";
|
|
39936
40410
|
if (firstQuestionNumber) {
|
|
39937
|
-
instructions +=
|
|
40411
|
+
instructions += strings.symbolPassage({
|
|
39938
40412
|
questionSymbol: "[[" + firstQuestionNumber + "]]",
|
|
39939
40413
|
questionNumber: firstQuestionNumber
|
|
39940
40414
|
});
|
|
39941
40415
|
}
|
|
39942
40416
|
if (firstSentenceRef) {
|
|
39943
|
-
instructions +=
|
|
40417
|
+
instructions += strings.symbolQuestion({
|
|
39944
40418
|
sentenceSymbol: "[" + firstSentenceRef + "]"
|
|
39945
40419
|
});
|
|
39946
40420
|
}
|
|
@@ -39986,6 +40460,9 @@ class Passage extends React.Component {
|
|
|
39986
40460
|
return PassageMarkdown.output(parsed);
|
|
39987
40461
|
}
|
|
39988
40462
|
render() {
|
|
40463
|
+
const {
|
|
40464
|
+
strings
|
|
40465
|
+
} = this.context;
|
|
39989
40466
|
let lineNumbers;
|
|
39990
40467
|
const nLines = this.state.nLines;
|
|
39991
40468
|
if (this.props.showLineNumbers && nLines) {
|
|
@@ -39994,9 +40471,7 @@ class Passage extends React.Component {
|
|
|
39994
40471
|
lineNumbers = _.range(1, nLines + 1).map(lineN => {
|
|
39995
40472
|
const lineAt = lineN + this.state.startLineNumbersAfter;
|
|
39996
40473
|
if (lineAt === 4) {
|
|
39997
|
-
|
|
39998
|
-
// I18N: a label next to a reading passage to denote the line number
|
|
39999
|
-
const translatedLine = i18n._("Line ");
|
|
40474
|
+
const translatedLine = strings.lineLabel;
|
|
40000
40475
|
return /*#__PURE__*/React.createElement("span", {
|
|
40001
40476
|
key: "line-marker",
|
|
40002
40477
|
className: "line-marker"
|
|
@@ -40026,13 +40501,14 @@ class Passage extends React.Component {
|
|
|
40026
40501
|
className: "passage-title"
|
|
40027
40502
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
40028
40503
|
content: this.props.passageTitle,
|
|
40029
|
-
linterContext: this.props.linterContext
|
|
40504
|
+
linterContext: this.props.linterContext,
|
|
40505
|
+
strings: strings
|
|
40030
40506
|
})), lineNumbers && /*#__PURE__*/React.createElement("div", {
|
|
40031
40507
|
className: "line-numbers",
|
|
40032
40508
|
"aria-hidden": true
|
|
40033
40509
|
}, lineNumbers), !hasTitle && /*#__PURE__*/React.createElement("h3", {
|
|
40034
40510
|
className: "perseus-sr-only"
|
|
40035
|
-
},
|
|
40511
|
+
}, strings.beginningPassage), /*#__PURE__*/React.createElement("div", {
|
|
40036
40512
|
className: "passage-text"
|
|
40037
40513
|
}, this.shouldRenderJipt() ?
|
|
40038
40514
|
/*#__PURE__*/
|
|
@@ -40040,18 +40516,20 @@ class Passage extends React.Component {
|
|
|
40040
40516
|
// content to a <Renderer /> which knows how
|
|
40041
40517
|
// to handle rendering JIPT text.
|
|
40042
40518
|
React.createElement(Renderer, {
|
|
40043
|
-
content: this.props.passageText
|
|
40519
|
+
content: this.props.passageText,
|
|
40520
|
+
strings: strings
|
|
40044
40521
|
}) : this._renderContent(parsedContent)), this._hasFootnotes() && [/*#__PURE__*/React.createElement("h4", {
|
|
40045
40522
|
key: "footnote-start",
|
|
40046
40523
|
className: "perseus-sr-only"
|
|
40047
|
-
},
|
|
40524
|
+
}, strings.beginningFootnotes), /*#__PURE__*/React.createElement("div", {
|
|
40048
40525
|
key: "footnotes",
|
|
40049
40526
|
className: "footnotes"
|
|
40050
40527
|
}, this._renderFootnotes())], /*#__PURE__*/React.createElement("div", {
|
|
40051
40528
|
className: "perseus-sr-only"
|
|
40052
|
-
},
|
|
40529
|
+
}, strings.endPassage))));
|
|
40053
40530
|
}
|
|
40054
40531
|
}
|
|
40532
|
+
Passage.contextType = PerseusI18nContext;
|
|
40055
40533
|
Passage.defaultProps = {
|
|
40056
40534
|
passageTitle: "",
|
|
40057
40535
|
passageText: "",
|
|
@@ -40102,10 +40580,12 @@ class PassageRefTarget extends React.Component {
|
|
|
40102
40580
|
// inline={true}
|
|
40103
40581
|
,
|
|
40104
40582
|
apiOptions: this.props.apiOptions,
|
|
40105
|
-
linterContext: this.props.linterContext
|
|
40583
|
+
linterContext: this.props.linterContext,
|
|
40584
|
+
strings: this.context.strings
|
|
40106
40585
|
});
|
|
40107
40586
|
}
|
|
40108
40587
|
}
|
|
40588
|
+
PassageRefTarget.contextType = PerseusI18nContext;
|
|
40109
40589
|
PassageRefTarget.defaultProps = {
|
|
40110
40590
|
content: "",
|
|
40111
40591
|
linterContext: linterContextDefault
|
|
@@ -40289,11 +40769,11 @@ class Plotter extends React.Component {
|
|
|
40289
40769
|
}
|
|
40290
40770
|
}
|
|
40291
40771
|
if ((isBar || isLine) && isMobile && !this.props.static) {
|
|
40292
|
-
self.graphie.dragPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
40772
|
+
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
40773
|
}
|
|
40294
40774
|
self.setupCategories(config);
|
|
40295
40775
|
if (isTiledPlot && isMobile) {
|
|
40296
|
-
self.graphie.dotPrompt = graphie.label([c.dimX / 2, c.dimY / 2],
|
|
40776
|
+
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
40777
|
}
|
|
40298
40778
|
if (isTiledPlot) {
|
|
40299
40779
|
self.drawPicHeights(self.state.values, prevState.values);
|
|
@@ -40908,6 +41388,7 @@ class Plotter extends React.Component {
|
|
|
40908
41388
|
});
|
|
40909
41389
|
}
|
|
40910
41390
|
}
|
|
41391
|
+
Plotter.contextType = PerseusI18nContext;
|
|
40911
41392
|
Plotter.defaultProps = {
|
|
40912
41393
|
type: "bar",
|
|
40913
41394
|
labels: ["", ""],
|
|
@@ -41179,7 +41660,7 @@ class Table extends React.Component {
|
|
|
41179
41660
|
};
|
|
41180
41661
|
this.simpleValidate = rubric => {
|
|
41181
41662
|
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type 'typeof Table'.
|
|
41182
|
-
return Table.validate(this.getUserInput(), rubric);
|
|
41663
|
+
return Table.validate(this.getUserInput(), rubric, this.context.strings);
|
|
41183
41664
|
};
|
|
41184
41665
|
this._handleFocus = inputPath => {
|
|
41185
41666
|
this.props.onFocus(inputPath);
|
|
@@ -41284,7 +41765,8 @@ class Table extends React.Component {
|
|
|
41284
41765
|
key: i
|
|
41285
41766
|
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
41286
41767
|
content: header,
|
|
41287
|
-
linterContext: this.props.linterContext
|
|
41768
|
+
linterContext: this.props.linterContext,
|
|
41769
|
+
strings: this.context.strings
|
|
41288
41770
|
}));
|
|
41289
41771
|
}))), /*#__PURE__*/React.createElement("tbody", null, _(rows).times(r => {
|
|
41290
41772
|
return /*#__PURE__*/React.createElement("tr", {
|
|
@@ -41306,6 +41788,7 @@ class Table extends React.Component {
|
|
|
41306
41788
|
})));
|
|
41307
41789
|
}
|
|
41308
41790
|
}
|
|
41791
|
+
Table.contextType = PerseusI18nContext;
|
|
41309
41792
|
Table.propTypes = {
|
|
41310
41793
|
answers: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)),
|
|
41311
41794
|
editableHeaders: PropTypes.bool,
|
|
@@ -41333,7 +41816,7 @@ Table.defaultProps = function () {
|
|
|
41333
41816
|
};
|
|
41334
41817
|
}();
|
|
41335
41818
|
_.extend(Table, {
|
|
41336
|
-
validate: function (state, rubric) {
|
|
41819
|
+
validate: function (state, rubric, strings) {
|
|
41337
41820
|
const filterNonEmpty = function filterNonEmpty(table) {
|
|
41338
41821
|
return _.filter(table, function (row) {
|
|
41339
41822
|
// Check if row has a cell that is nonempty
|
|
@@ -41371,7 +41854,7 @@ _.extend(Table, {
|
|
|
41371
41854
|
const cellSolution = rowSolution[i];
|
|
41372
41855
|
const validator = createValidator(cellSolution, {
|
|
41373
41856
|
simplify: true
|
|
41374
|
-
});
|
|
41857
|
+
}, strings);
|
|
41375
41858
|
const result = validator(cellSupplied);
|
|
41376
41859
|
if (result.message) {
|
|
41377
41860
|
// @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'null'.
|
|
@@ -42134,7 +42617,7 @@ class OldUnitInput extends React.Component {
|
|
|
42134
42617
|
});
|
|
42135
42618
|
};
|
|
42136
42619
|
this.simpleValidate = (rubric, onInputError) => {
|
|
42137
|
-
return OldUnitInput.validate(this.getUserInput(), rubric);
|
|
42620
|
+
return OldUnitInput.validate(this.getUserInput(), rubric, this.context.strings);
|
|
42138
42621
|
};
|
|
42139
42622
|
this.getUserInput = () => {
|
|
42140
42623
|
return this.props.value;
|
|
@@ -42187,13 +42670,13 @@ class OldUnitInput extends React.Component {
|
|
|
42187
42670
|
return "unit";
|
|
42188
42671
|
};
|
|
42189
42672
|
}
|
|
42190
|
-
static validate(userInput, rubric) {
|
|
42673
|
+
static validate(userInput, rubric, strings) {
|
|
42191
42674
|
const answer = KAS.unitParse(rubric.value).expr;
|
|
42192
42675
|
const guess = KAS.unitParse(userInput);
|
|
42193
42676
|
if (!guess.parsed) {
|
|
42194
42677
|
return {
|
|
42195
42678
|
type: "invalid",
|
|
42196
|
-
message:
|
|
42679
|
+
message: strings.dontUnderstandUnits
|
|
42197
42680
|
};
|
|
42198
42681
|
}
|
|
42199
42682
|
|
|
@@ -42208,8 +42691,7 @@ class OldUnitInput extends React.Component {
|
|
|
42208
42691
|
const sigfigs = rubric.sigfigs;
|
|
42209
42692
|
const sigfigsCorrect = countSigfigs(guess.coefficient) === sigfigs;
|
|
42210
42693
|
if (!sigfigsCorrect) {
|
|
42211
|
-
|
|
42212
|
-
message = i18n._("Check your significant figures.");
|
|
42694
|
+
message = strings.checkSigFigs;
|
|
42213
42695
|
}
|
|
42214
42696
|
|
|
42215
42697
|
// now we need to check that the answer is correct to the precision we
|
|
@@ -42228,8 +42710,7 @@ class OldUnitInput extends React.Component {
|
|
|
42228
42710
|
numericallyCorrect = false;
|
|
42229
42711
|
}
|
|
42230
42712
|
if (!numericallyCorrect) {
|
|
42231
|
-
|
|
42232
|
-
message = i18n._("That answer is numerically incorrect.");
|
|
42713
|
+
message = strings.answerNumericallyIncorrect;
|
|
42233
42714
|
}
|
|
42234
42715
|
let kasCorrect;
|
|
42235
42716
|
const guessUnit = primUnits(guess.expr.simplify());
|
|
@@ -42249,8 +42730,7 @@ class OldUnitInput extends React.Component {
|
|
|
42249
42730
|
});
|
|
42250
42731
|
}
|
|
42251
42732
|
if (!kasCorrect) {
|
|
42252
|
-
|
|
42253
|
-
message = i18n._("Check your units.");
|
|
42733
|
+
message = strings.checkUnits;
|
|
42254
42734
|
}
|
|
42255
42735
|
const correct = kasCorrect && numericallyCorrect && sigfigsCorrect;
|
|
42256
42736
|
return {
|
|
@@ -42299,12 +42779,13 @@ class OldUnitInput extends React.Component {
|
|
|
42299
42779
|
style: {
|
|
42300
42780
|
display: "none"
|
|
42301
42781
|
}
|
|
42302
|
-
},
|
|
42782
|
+
}, this.context.strings.dontUnderstand));
|
|
42303
42783
|
}
|
|
42304
42784
|
}
|
|
42305
42785
|
|
|
42306
42786
|
// Extract the primitive units from a unit expression. This first simplifies
|
|
42307
42787
|
// `expr` to a `Mul` like "5 kg m / s^2" then removes the first term.
|
|
42788
|
+
OldUnitInput.contextType = PerseusI18nContext;
|
|
42308
42789
|
OldUnitInput.defaultProps = {
|
|
42309
42790
|
apiOptions: ApiOptions.defaults,
|
|
42310
42791
|
value: ""
|
|
@@ -42355,9 +42836,12 @@ const VideoTranscriptLink = props => {
|
|
|
42355
42836
|
// which is used by our GraphQL framework.
|
|
42356
42837
|
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'VideoKind'.
|
|
42357
42838
|
const result = useVideo(id, kind);
|
|
42839
|
+
const {
|
|
42840
|
+
strings
|
|
42841
|
+
} = usePerseusI18n();
|
|
42358
42842
|
switch (result.status) {
|
|
42359
42843
|
case "loading":
|
|
42360
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42844
|
+
return /*#__PURE__*/React.createElement(View, null, strings.loading);
|
|
42361
42845
|
case "success":
|
|
42362
42846
|
{
|
|
42363
42847
|
var _result$data;
|
|
@@ -42370,14 +42854,14 @@ const VideoTranscriptLink = props => {
|
|
|
42370
42854
|
href: "/transcript/" + ((video == null ? void 0 : video.contentId) || "videoNotFound"),
|
|
42371
42855
|
target: "_blank",
|
|
42372
42856
|
className: "visited-no-recolor"
|
|
42373
|
-
},
|
|
42857
|
+
}, strings.videoTranscript));
|
|
42374
42858
|
}
|
|
42375
42859
|
case "error":
|
|
42376
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42860
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42377
42861
|
case "aborted":
|
|
42378
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42862
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42379
42863
|
default:
|
|
42380
|
-
return /*#__PURE__*/React.createElement(View, null,
|
|
42864
|
+
return /*#__PURE__*/React.createElement(View, null, strings.somethingWrong);
|
|
42381
42865
|
}
|
|
42382
42866
|
};
|
|
42383
42867
|
const styles$4 = StyleSheet.create({
|
|
@@ -42469,7 +42953,7 @@ class Video extends React.Component {
|
|
|
42469
42953
|
key: location + this.props.alignment
|
|
42470
42954
|
}, /*#__PURE__*/React.createElement(View, {
|
|
42471
42955
|
style: a11y.srOnly
|
|
42472
|
-
},
|
|
42956
|
+
}, this.context.strings.videoWrapper), /*#__PURE__*/React.createElement("iframe", {
|
|
42473
42957
|
// TODO(joshuan): Consider not using iframes when we're
|
|
42474
42958
|
// loading this from webapp. This iframe is problematic
|
|
42475
42959
|
// for screenreaders.
|
|
@@ -42484,6 +42968,7 @@ class Video extends React.Component {
|
|
|
42484
42968
|
}));
|
|
42485
42969
|
}
|
|
42486
42970
|
}
|
|
42971
|
+
Video.contextType = PerseusI18nContext;
|
|
42487
42972
|
var Video$1 = {
|
|
42488
42973
|
name: "video",
|
|
42489
42974
|
displayName: "Video",
|
|
@@ -42533,7 +43018,7 @@ const init = function init(options) {
|
|
|
42533
43018
|
|
|
42534
43019
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42535
43020
|
const libName = "@khanacademy/perseus";
|
|
42536
|
-
const libVersion = "
|
|
43021
|
+
const libVersion = "22.0.1";
|
|
42537
43022
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42538
43023
|
|
|
42539
43024
|
const apiVersion = {
|
|
@@ -42699,8 +43184,9 @@ class ArticleRenderer extends React.Component {
|
|
|
42699
43184
|
}
|
|
42700
43185
|
}),
|
|
42701
43186
|
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "article"),
|
|
42702
|
-
legacyPerseusLint: this.props.legacyPerseusLint
|
|
42703
|
-
|
|
43187
|
+
legacyPerseusLint: this.props.legacyPerseusLint,
|
|
43188
|
+
strings: this.context.strings
|
|
43189
|
+
})));
|
|
42704
43190
|
});
|
|
42705
43191
|
return /*#__PURE__*/React.createElement("div", {
|
|
42706
43192
|
className: classes
|
|
@@ -42709,6 +43195,7 @@ class ArticleRenderer extends React.Component {
|
|
|
42709
43195
|
}, sections));
|
|
42710
43196
|
}
|
|
42711
43197
|
}
|
|
43198
|
+
ArticleRenderer.contextType = PerseusI18nContext;
|
|
42712
43199
|
ArticleRenderer.defaultProps = {
|
|
42713
43200
|
apiOptions: ApiOptions.defaults,
|
|
42714
43201
|
useNewStyles: false,
|
|
@@ -42761,7 +43248,7 @@ class HintRenderer extends React.Component {
|
|
|
42761
43248
|
tabIndex: "-1"
|
|
42762
43249
|
}, !apiOptions.isMobile && /*#__PURE__*/React.createElement("span", {
|
|
42763
43250
|
className: "perseus-sr-only"
|
|
42764
|
-
},
|
|
43251
|
+
}, this.context.strings.hintPos({
|
|
42765
43252
|
pos: pos + 1
|
|
42766
43253
|
})), !apiOptions.isMobile && totalHints != null && pos != null && /*#__PURE__*/React.createElement("span", {
|
|
42767
43254
|
className: "perseus-hint-label",
|
|
@@ -42778,11 +43265,13 @@ class HintRenderer extends React.Component {
|
|
|
42778
43265
|
images: hint.images,
|
|
42779
43266
|
apiOptions: rendererApiOptions,
|
|
42780
43267
|
findExternalWidgets: this.props.findExternalWidgets,
|
|
42781
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hint")
|
|
43268
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hint"),
|
|
43269
|
+
strings: this.context.strings
|
|
42782
43270
|
}))
|
|
42783
43271
|
);
|
|
42784
43272
|
}
|
|
42785
43273
|
}
|
|
43274
|
+
HintRenderer.contextType = PerseusI18nContext;
|
|
42786
43275
|
HintRenderer.defaultProps = {
|
|
42787
43276
|
linterContext: PerseusLinter.linterContextDefault
|
|
42788
43277
|
};
|
|
@@ -42964,7 +43453,7 @@ class HintsRenderer extends React.Component {
|
|
|
42964
43453
|
className: classNames$1
|
|
42965
43454
|
}, apiOptions.isMobile && hintsVisible > 0 && /*#__PURE__*/React.createElement("div", {
|
|
42966
43455
|
className: css(styles$2.mobileHintStylesHintTitle, sharedStyles.responsiveLabel)
|
|
42967
|
-
},
|
|
43456
|
+
}, this.context.strings.hints), hints, showGetAnotherHint && /*#__PURE__*/React.createElement("button", {
|
|
42968
43457
|
// @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
43458
|
rel: "button",
|
|
42970
43459
|
className: css(styles$2.linkButton, styles$2.getAnotherHintButton, apiOptions.isMobile && styles$2.mobileHintStylesGetAnotherHintButton),
|
|
@@ -42979,9 +43468,10 @@ class HintsRenderer extends React.Component {
|
|
|
42979
43468
|
className: css(styles$2.plusText, apiOptions.isMobile && styles$2.mobileHintStylesPlusText)
|
|
42980
43469
|
}, "+"), /*#__PURE__*/React.createElement("span", {
|
|
42981
43470
|
className: css(styles$2.getAnotherHintText)
|
|
42982
|
-
},
|
|
43471
|
+
}, this.context.strings.getAnotherHint, " ", hintRatioCopy)));
|
|
42983
43472
|
}
|
|
42984
43473
|
}
|
|
43474
|
+
HintsRenderer.contextType = PerseusI18nContext;
|
|
42985
43475
|
HintsRenderer.defaultProps = {
|
|
42986
43476
|
linterContext: PerseusLinter.linterContextDefault
|
|
42987
43477
|
};
|
|
@@ -43372,14 +43862,16 @@ class ServerItemRenderer extends React.Component {
|
|
|
43372
43862
|
content: this.props.item.question.content,
|
|
43373
43863
|
widgets: this.props.item.question.widgets,
|
|
43374
43864
|
images: this.props.item.question.images,
|
|
43375
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "question")
|
|
43865
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "question"),
|
|
43866
|
+
strings: this.context.strings
|
|
43376
43867
|
}, this.props.dependencies)));
|
|
43377
43868
|
const hintsRenderer = /*#__PURE__*/React.createElement(HintsRenderer, {
|
|
43378
43869
|
hints: this.props.item.hints,
|
|
43379
43870
|
hintsVisible: this.props.hintsVisible,
|
|
43380
43871
|
apiOptions: apiOptions,
|
|
43381
43872
|
ref: elem => this.hintsRenderer = elem,
|
|
43382
|
-
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hints")
|
|
43873
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "hints"),
|
|
43874
|
+
strings: this.context.strings
|
|
43383
43875
|
});
|
|
43384
43876
|
return /*#__PURE__*/React.createElement(DependenciesContext.Provider, {
|
|
43385
43877
|
value: this.props.dependencies
|
|
@@ -43393,6 +43885,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
43393
43885
|
}, hintsRenderer)));
|
|
43394
43886
|
}
|
|
43395
43887
|
}
|
|
43888
|
+
ServerItemRenderer.contextType = PerseusI18nContext;
|
|
43396
43889
|
ServerItemRenderer.defaultProps = {
|
|
43397
43890
|
apiOptions: {},
|
|
43398
43891
|
// a deep default is done in `this.update()`
|
|
@@ -43555,115 +44048,6 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
43555
44048
|
perseusFrameBorderWidth: perseusFrameBorderWidth
|
|
43556
44049
|
});
|
|
43557
44050
|
|
|
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
44051
|
/**
|
|
43668
44052
|
* Traverses a {content, widgets, images} renderer props object,
|
|
43669
44053
|
* such as `itemData.question`
|
|
@@ -44272,7 +44656,9 @@ class MultiRenderer extends React.Component {
|
|
|
44272
44656
|
// `<Renderer>`. I'm not sure how else to do this.
|
|
44273
44657
|
const _this$props = this.props,
|
|
44274
44658
|
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
44275
|
-
return otherProps
|
|
44659
|
+
return _extends({}, otherProps, {
|
|
44660
|
+
strings: this.context.strings
|
|
44661
|
+
});
|
|
44276
44662
|
}
|
|
44277
44663
|
|
|
44278
44664
|
/**
|
|
@@ -44523,7 +44909,7 @@ class MultiRenderer extends React.Component {
|
|
|
44523
44909
|
if (this.state.renderError) {
|
|
44524
44910
|
return /*#__PURE__*/React.createElement("div", {
|
|
44525
44911
|
className: css(styles.error)
|
|
44526
|
-
},
|
|
44912
|
+
}, this.context.strings.errorRendering({
|
|
44527
44913
|
error: String(this.state.renderError)
|
|
44528
44914
|
}));
|
|
44529
44915
|
}
|
|
@@ -44537,6 +44923,7 @@ class MultiRenderer extends React.Component {
|
|
|
44537
44923
|
}));
|
|
44538
44924
|
}
|
|
44539
44925
|
}
|
|
44926
|
+
MultiRenderer.contextType = PerseusI18nContext;
|
|
44540
44927
|
const styles = StyleSheet.create({
|
|
44541
44928
|
error: {
|
|
44542
44929
|
color: "red"
|
|
@@ -45632,5 +46019,5 @@ const EditorJsonify = {
|
|
|
45632
46019
|
}
|
|
45633
46020
|
};
|
|
45634
46021
|
|
|
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 };
|
|
46022
|
+
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
46023
|
//# sourceMappingURL=index.js.map
|