@khanacademy/perseus 52.0.0 → 53.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/number-input.d.ts +2 -0
- package/dist/components/range-input.d.ts +1 -0
- package/dist/components/svg-image.d.ts +2 -2
- package/dist/es/index.css +0 -30
- package/dist/es/index.js +516 -1195
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +21 -13
- package/dist/es/strings.js.map +1 -1
- package/dist/index.css +0 -30
- package/dist/index.d.ts +1 -2
- package/dist/index.js +514 -1198
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +0 -1
- package/dist/renderer.d.ts +1 -1
- package/dist/strings.d.ts +1 -1
- package/dist/strings.js +21 -13
- package/dist/strings.js.map +1 -1
- package/dist/styles/constants.d.ts +0 -2
- package/dist/types.d.ts +3 -20
- package/dist/util/math-utils.d.ts +1 -0
- package/dist/util/scoring.d.ts +0 -15
- package/dist/util/test-utils.d.ts +1 -1
- package/dist/widget-ai-utils/mock-widget/prompt-utils.d.ts +1 -1
- package/dist/widget-container.d.ts +1 -1
- package/dist/widgets/categorizer/categorizer.d.ts +0 -3
- package/dist/widgets/cs-program/cs-program.d.ts +2 -3
- package/dist/widgets/definition/definition.d.ts +0 -2
- package/dist/widgets/deprecated-standin/deprecated-standin.d.ts +0 -1
- package/dist/widgets/dropdown/dropdown.d.ts +2 -4
- package/dist/widgets/explanation/explanation.d.ts +0 -2
- package/dist/widgets/expression/expression.d.ts +1 -5
- package/dist/widgets/grapher/grapher.d.ts +0 -2
- package/dist/widgets/group/group.d.ts +0 -4
- package/dist/widgets/iframe/iframe.d.ts +0 -2
- package/dist/widgets/image/image.d.ts +0 -3
- package/dist/widgets/input-number/input-number.d.ts +0 -3
- package/dist/widgets/interaction/interaction.d.ts +0 -1
- package/dist/widgets/interactive-graph.d.ts +0 -2
- package/dist/widgets/interactive-graphs/backgrounds/axis-ticks.d.ts +1 -0
- package/dist/widgets/label-image/label-image.d.ts +2 -2
- package/dist/widgets/matcher/matcher.d.ts +0 -2
- package/dist/widgets/matrix/matrix.d.ts +0 -3
- package/dist/widgets/measurer/measurer.d.ts +0 -1
- package/dist/widgets/mock-widgets/mock-widget-types.d.ts +0 -6
- package/dist/widgets/mock-widgets/mock-widget.d.ts +2 -5
- package/dist/widgets/molecule/molecule.d.ts +0 -1
- package/dist/widgets/number-line/number-line.d.ts +2 -3
- package/dist/widgets/numeric-input/numeric-input.d.ts +2 -3
- package/dist/widgets/orderer/orderer.d.ts +0 -3
- package/dist/widgets/passage/passage.d.ts +0 -1
- package/dist/widgets/passage-ref/passage-ref.d.ts +0 -2
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +0 -2
- package/dist/widgets/plotter/plotter.d.ts +0 -3
- package/dist/widgets/radio/radio.d.ts +0 -3
- package/dist/widgets/sorter/sorter.d.ts +2 -4
- package/dist/widgets/table/table.d.ts +0 -3
- package/dist/widgets/video/video.d.ts +0 -3
- package/dist/widgets.d.ts +1 -32
- package/package.json +10 -10
- package/dist/renderer-util.d.ts +0 -14
- package/dist/widgets/__shared__/score-noop.d.ts +0 -11
- package/dist/widgets/group/score-group.d.ts +0 -4
- package/dist/widgets/group/validate-group.d.ts +0 -4
- package/dist/widgets/mock-widgets/score-mock-widget.d.ts +0 -5
- package/dist/widgets/mock-widgets/validate-mock-widget.d.ts +0 -4
package/dist/es/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import * as KAS from '@khanacademy/kas';
|
|
2
2
|
import { MathInputI18nContext, CursorContext, getKeyTranslator, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
|
|
3
|
-
import { PerseusError, Errors, expressionLogic, getExpressionPublicWidgetOptions, getDecimalSeparator, approximateDeepEqual, pluck,
|
|
3
|
+
import { PerseusError, Errors, expressionLogic, getExpressionPublicWidgetOptions, getDecimalSeparator, approximateDeepEqual, pluck, CoreWidgetRegistry, getUpgradedWidgetOptions, mapObject, getNumericInputPublicWidgetOptions, passageRefLogic, radioLogic, getCategorizerPublicWidgetOptions, getCSProgramPublicWidgetOptions, getDropdownPublicWidgetOptions, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, getLabelImagePublicWidgetOptions, getMatrixSize, measurerLogic, getNumberLinePublicWidgetOptions, getOrdererPublicWidgetOptions, getSorterPublicWidgetOptions, addLibraryVersionToPerseusDebug, upgradeWidgetInfoToLatestVersion, getWidgetIdsFromContentByType } from '@khanacademy/perseus-core';
|
|
4
4
|
export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
|
|
5
5
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
6
6
|
import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
|
|
7
|
-
import { scoreExpression, validateExpression, KhanAnswerTypes, scoreInputNumber, inputNumberAnswerTypes, scoreNumericInput, scoreRadio, validateRadio, scoreCategorizer, validateCategorizer, scoreCSProgram, scoreDropdown, validateDropdown, scoreGrapher, scoreIframe, scoreInteractiveGraph, scoreLabelImage, scoreLabelImageMarker, scoreMatcher, scoreMatrix, validateMatrix, scoreNumberLine, validateNumberLine, scoreOrderer, validateOrderer, scorePlotter, validatePlotter, scoreSorter, validateSorter, scoreTable, validateTable } from '@khanacademy/perseus-score';
|
|
8
7
|
import { View, RenderStateRoot, Id, useOnMountEffect, useLatestRef, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
9
8
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
10
9
|
import { HeadingMedium, LabelSmall, LabelLarge, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
@@ -21,6 +20,7 @@ import { color, spacing, font } from '@khanacademy/wonder-blocks-tokens';
|
|
|
21
20
|
import $ from 'jquery';
|
|
22
21
|
import { v4 } from 'uuid';
|
|
23
22
|
import PropTypes from 'prop-types';
|
|
23
|
+
import { KhanAnswerTypes, emptyWidgetsFunctional, scoreWidgetsFunctional, flattenScores, inputNumberAnswerTypes, scoreRadio, scoreLabelImageMarker } from '@khanacademy/perseus-score';
|
|
24
24
|
import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-core';
|
|
25
25
|
import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
|
|
26
26
|
import { point, KhanMath, number, vector as vector$3, line, geometry, angles, coefficients } from '@khanacademy/kmath';
|
|
@@ -59,213 +59,6 @@ function _extends() {
|
|
|
59
59
|
* The translated strings that are used to render Perseus.
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
|
-
/**
|
|
63
|
-
* Untranslated strings used in Perseus. To be used by an external
|
|
64
|
-
* translator to produce translated strings, passed in as `PerseusStrings`.
|
|
65
|
-
* !! Note: Ensure that all escape sequences are double-escaped. (e.g. `\\text` -> `\\\\text`)
|
|
66
|
-
*/
|
|
67
|
-
const strings = {
|
|
68
|
-
closeKeypad: "close math keypad",
|
|
69
|
-
openKeypad: "open math keypad",
|
|
70
|
-
mathInputBox: "Math input box",
|
|
71
|
-
removeHighlight: "Remove highlight",
|
|
72
|
-
addHighlight: "Add highlight",
|
|
73
|
-
hintPos: "Hint #%(pos)s",
|
|
74
|
-
errorRendering: "Error rendering: %(error)s",
|
|
75
|
-
APPROXIMATED_PI_ERROR: "Your answer is close, but you may " + "have approximated pi. Enter your " + "answer as a multiple of pi, like " + "12 pi or " + "2/3 pi",
|
|
76
|
-
EXTRA_SYMBOLS_ERROR: "We could not understand your " + "answer. Please check your answer for extra " + "text or symbols.",
|
|
77
|
-
NEEDS_TO_BE_SIMPLFIED_ERROR: "Your answer is almost correct, " + "but it needs to be simplified.",
|
|
78
|
-
MISSING_PERCENT_ERROR: "Your answer is almost correct, " + "but it is missing a " + "<code>\\\\%</code> at the end.",
|
|
79
|
-
MULTIPLICATION_SIGN_ERROR: "I'm a computer. I only understand " + "multiplication if you use an asterisk " + "(*) as the multiplication sign.",
|
|
80
|
-
WRONG_CASE_ERROR: "Your answer includes use of a variable with the wrong case.",
|
|
81
|
-
WRONG_LETTER_ERROR: "Your answer includes a wrong variable letter.",
|
|
82
|
-
invalidSelection: "Make sure you select something for every row.",
|
|
83
|
-
ERROR_TITLE: "Oops!",
|
|
84
|
-
ERROR_MESSAGE: "Sorry, I don't understand that!",
|
|
85
|
-
hints: "Hints",
|
|
86
|
-
getAnotherHint: "Get another hint",
|
|
87
|
-
deprecatedStandin: "Sorry, this part of the question is no longer available. 😅 Don't worry, you won't be graded on this part. Keep going!",
|
|
88
|
-
keepTrying: "Keep trying",
|
|
89
|
-
tryAgain: "Try again",
|
|
90
|
-
check: "Check",
|
|
91
|
-
correctExcited: "Correct!",
|
|
92
|
-
nextQuestion: "Next question",
|
|
93
|
-
skipToTitle: "Skip to %(title)s",
|
|
94
|
-
current: "Current",
|
|
95
|
-
correct: "Correct",
|
|
96
|
-
correctSelected: "Correct (selected)",
|
|
97
|
-
correctCrossedOut: "Correct (but you crossed it out)",
|
|
98
|
-
incorrect: "Incorrect",
|
|
99
|
-
incorrectSelected: "Incorrect (selected)",
|
|
100
|
-
hideExplanation: "Hide explanation",
|
|
101
|
-
explain: "Explain",
|
|
102
|
-
INVALID_MESSAGE_PREFIX: "We couldn't grade your answer.",
|
|
103
|
-
DEFAULT_INVALID_MESSAGE_1: "It looks like you left something blank or ",
|
|
104
|
-
DEFAULT_INVALID_MESSAGE_2: "entered in an invalid answer.",
|
|
105
|
-
integerExample: "an integer, like $6$",
|
|
106
|
-
properExample: "a *proper* fraction, like $1/2$ or $6/10$",
|
|
107
|
-
simplifiedProperExample: "a *simplified proper* fraction, like $3/5$",
|
|
108
|
-
improperExample: "an *improper* fraction, like $10/7$ or $14/8$",
|
|
109
|
-
simplifiedImproperExample: "a *simplified improper* fraction, like $7/4$",
|
|
110
|
-
mixedExample: "a mixed number, like $1\\\\ 3/4$",
|
|
111
|
-
decimalExample: "an *exact* decimal, like $0.75$",
|
|
112
|
-
percentExample: "a percent, like $12.34\\\\%$",
|
|
113
|
-
piExample: "a multiple of pi, like $12$ pi or $2/3$ pi",
|
|
114
|
-
yourAnswer: "**Your answer should be** ",
|
|
115
|
-
yourAnswerLabel: "Your answer:",
|
|
116
|
-
addPoints: "Click to add points",
|
|
117
|
-
addVertices: "Click to add vertices",
|
|
118
|
-
tapMultiple: "Tap each dot on the image to select all answers that apply.",
|
|
119
|
-
tapSingle: "Tap each dot on the image to select an answer.",
|
|
120
|
-
clickMultiple: "Click each dot on the image to select all answers that apply.",
|
|
121
|
-
clickSingle: "Click each dot on the image to select an answer.",
|
|
122
|
-
choices: "Choices:",
|
|
123
|
-
answers: {
|
|
124
|
-
one: "%(num)s answer",
|
|
125
|
-
other: "%(num)s answers"
|
|
126
|
-
},
|
|
127
|
-
hideAnswersToggleLabel: "Hide answer choices",
|
|
128
|
-
moves: {
|
|
129
|
-
one: "Moves: %(num)s",
|
|
130
|
-
other: "Moves: %(num)s"
|
|
131
|
-
},
|
|
132
|
-
clickTiles: "Click on the tiles to change the lights.",
|
|
133
|
-
turnOffLights: "You must turn on all of the lights to continue.",
|
|
134
|
-
fillAllCells: "Make sure you fill in all cells in the matrix.",
|
|
135
|
-
molecularDrawing: "A molecular structure drawing. SMILES notation: %(content)s",
|
|
136
|
-
switchDirection: "Switch direction",
|
|
137
|
-
circleOpen: "Make circle open",
|
|
138
|
-
circleFilled: "Make circle filled",
|
|
139
|
-
numDivisions: "Number of divisions:",
|
|
140
|
-
divisions: "Please make sure the number of divisions is in the range %(divRangeString)s.",
|
|
141
|
-
lineRange: "lines %(lineRange)s",
|
|
142
|
-
lineNumber: "line %(lineNumber)s",
|
|
143
|
-
symbolPassage: "The symbol %(questionSymbol)s indicates that question %(questionNumber)s references this portion of the passage.",
|
|
144
|
-
symbolQuestion: " The symbol %(sentenceSymbol)s indicates that the following sentence is referenced in a question.",
|
|
145
|
-
lineLabel: {
|
|
146
|
-
context: "a label next to a reading passage to denote the line number",
|
|
147
|
-
message: "Line"
|
|
148
|
-
},
|
|
149
|
-
beginningPassage: "Beginning of reading passage.",
|
|
150
|
-
beginningFootnotes: "Beginning of reading passage footnotes.",
|
|
151
|
-
endPassage: "End of reading passage.",
|
|
152
|
-
questionMarker: "[Marker for question %(number)s]",
|
|
153
|
-
circleMarker: "[Circle marker %(number)s]",
|
|
154
|
-
sentenceMarker: "[Sentence %(number)s]",
|
|
155
|
-
dragHandles: "Drag handles to make graph",
|
|
156
|
-
tapAddPoints: "Tap to add points",
|
|
157
|
-
false: "False",
|
|
158
|
-
true: "True",
|
|
159
|
-
no: "No",
|
|
160
|
-
yes: "Yes",
|
|
161
|
-
chooseCorrectNum: "Please choose the correct number of answers.",
|
|
162
|
-
notNoneOfTheAbove: "'None of the above' may not be selected when other answers are selected.",
|
|
163
|
-
noneOfTheAbove: "None of the above",
|
|
164
|
-
chooseNumAnswers: "Choose %(numCorrect)s answers:",
|
|
165
|
-
chooseAllAnswers: "Choose all answers that apply:",
|
|
166
|
-
chooseOneAnswer: "Choose 1 answer:",
|
|
167
|
-
choiceCheckedCorrect: "(Choice %(letter)s, Checked, Correct)",
|
|
168
|
-
choiceCrossedOutCorrect: "(Choice %(letter)s, Crossed out, Correct)",
|
|
169
|
-
choiceCorrect: "(Choice %(letter)s, Correct)",
|
|
170
|
-
choiceCheckedIncorrect: "(Choice %(letter)s, Checked, Incorrect)",
|
|
171
|
-
choiceCrossedOutIncorrect: "(Choice %(letter)s, Crossed out, Incorrect)",
|
|
172
|
-
choiceIncorrect: "(Choice %(letter)s, Incorrect)",
|
|
173
|
-
choiceChecked: "(Choice %(letter)s, Checked)",
|
|
174
|
-
choiceCrossedOut: "(Choice %(letter)s, Crossed out)",
|
|
175
|
-
choice: "(Choice %(letter)s)",
|
|
176
|
-
crossOut: "Cross out",
|
|
177
|
-
crossOutOption: "Cross out option",
|
|
178
|
-
crossOutChoice: "Cross out Choice %(letter)s",
|
|
179
|
-
bringBack: "Bring back",
|
|
180
|
-
openMenuForChoice: "Open menu for Choice %(letter)s",
|
|
181
|
-
letters: {
|
|
182
|
-
context: "This is a list of single-character labels that will appear in front of multiple-choice options. For instance, a multiple-choice question with three options would display (A) first option (B) second option (C) third option. There must be spaces between each of the different characters. The characters will show up next to options in the order that they are listed here. Most multiple choice questions have 5 or fewer options.",
|
|
183
|
-
message: "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"
|
|
184
|
-
},
|
|
185
|
-
rightArrow: "Reaction arrow pointing to the right.",
|
|
186
|
-
dontUnderstandUnits: "I couldn't understand those units.",
|
|
187
|
-
checkSigFigs: "Check your significant figures.",
|
|
188
|
-
answerNumericallyIncorrect: "That answer is numerically incorrect.",
|
|
189
|
-
checkUnits: "Check your units.",
|
|
190
|
-
dontUnderstand: "I don't understand that",
|
|
191
|
-
loading: "Loading...",
|
|
192
|
-
videoTranscript: "See video transcript",
|
|
193
|
-
somethingWrong: "Something went wrong.",
|
|
194
|
-
videoWrapper: "Khan Academy video wrapper",
|
|
195
|
-
mathInputTitle: "mathematics keyboard",
|
|
196
|
-
mathInputDescription: "Use keyboard/mouse to interact with math-based input fields",
|
|
197
|
-
sin: "sin",
|
|
198
|
-
cos: "cos",
|
|
199
|
-
tan: "tan",
|
|
200
|
-
simulationLoadFail: "Sorry, this simulation cannot load.",
|
|
201
|
-
simulationLocaleWarning: "Sorry, this simulation isn't available in your language.",
|
|
202
|
-
selectAnAnswer: "Select an answer",
|
|
203
|
-
// The following strings are used for interactive graph SR descriptions.
|
|
204
|
-
addPoint: "Add Point",
|
|
205
|
-
removePoint: "Remove Point",
|
|
206
|
-
graphKeyboardPrompt: "Press Shift + Enter to interact with the graph",
|
|
207
|
-
closePolygon: "Close shape",
|
|
208
|
-
openPolygon: "Re-open shape",
|
|
209
|
-
srInteractiveElements: "Interactive elements: %(elements)s",
|
|
210
|
-
srNoInteractiveElements: "No interactive elements",
|
|
211
|
-
// TODO(LEMS-2660): The following strings are ones that will need
|
|
212
|
-
// translation tickets after all interactive graph SR strings have
|
|
213
|
-
// been finalized. Remove this comment after the tickets have been
|
|
214
|
-
// created.
|
|
215
|
-
srPointAtCoordinates: "Point %(num)s at %(x)s comma %(y)s",
|
|
216
|
-
srCircleGraph: "A circle on a coordinate plane.",
|
|
217
|
-
srCircleShape: "Circle. The center point is at %(centerX)s comma %(centerY)s.",
|
|
218
|
-
srCircleRadiusPoint: "Radius point at %(radiusPointX)s comma %(radiusPointY)s.",
|
|
219
|
-
srCircleRadius: "Circle radius is %(radius)s.",
|
|
220
|
-
srCircleOuterPoints: "Points on the circle at %(point1X)s comma %(point1Y)s, %(point2X)s comma %(point2Y)s, %(point3X)s comma %(point3Y)s, %(point4X)s comma %(point4Y)s.",
|
|
221
|
-
srLinearGraph: "A line on a coordinate plane.",
|
|
222
|
-
srLinearGraphPoints: "The line has two points, point 1 at %(point1X)s comma %(point1Y)s and point 2 at %(point2X)s comma %(point2Y)s.",
|
|
223
|
-
srLinearGraphSlopeIncreasing: "Its slope increases from left to right.",
|
|
224
|
-
srLinearGraphSlopeDecreasing: "Its slope decreases from left to right.",
|
|
225
|
-
srLinearGraphSlopeHorizontal: "Its slope is zero.",
|
|
226
|
-
srLinearGraphSlopeVertical: "Its slope is undefined.",
|
|
227
|
-
srLinearGraphXOnlyIntercept: "The line crosses the X-axis at %(xIntercept)s comma 0.",
|
|
228
|
-
srLinearGraphYOnlyIntercept: "The line crosses the Y-axis at 0 comma %(yIntercept)s.",
|
|
229
|
-
srLinearGraphBothIntercepts: "The line crosses the X-axis at %(xIntercept)s comma 0 and the Y-axis at 0 comma %(yIntercept)s.",
|
|
230
|
-
srLinearGraphOriginIntercept: "The line crosses the x and y axes at the graph's origin.",
|
|
231
|
-
srLinearGrabHandle: "Line from %(point1X)s comma %(point1Y)s to %(point2X)s comma %(point2Y)s.",
|
|
232
|
-
srAngleSideAtCoordinates: "Point %(point)s, %(side)s at %(x)s comma %(y)s",
|
|
233
|
-
srAngleVertexAtCoordinatesWithAngleMeasure: "Point 2, vertex at %(x)s comma %(y)s. Angle %(angleMeasure)s degrees",
|
|
234
|
-
srAngleGraphAriaLabel: "An angle on a coordinate plane.",
|
|
235
|
-
srAngleGraphAriaDescription: "The angle measure is %(angleMeasure)s degrees with a vertex at %(vertexX)s comma %(vertexY)s, a point on the starting side at %(startingSideX)s comma %(startingSideY)s and a point on the ending side at %(endingSideX)s comma %(endingSideY)s",
|
|
236
|
-
srSingleSegmentGraphAriaLabel: "A line segment on a coordinate plane.",
|
|
237
|
-
srMultipleSegmentGraphAriaLabel: "%(countOfSegments)s line segments on a coordinate plane.",
|
|
238
|
-
srMultipleSegmentIndividualLabel: "Segment %(indexOfSegment)s: Endpoint 1 at %(point1X)s comma %(point1Y)s. Endpoint 2 %(point2X)s comma %(point2Y)s.",
|
|
239
|
-
srSingleSegmentLabel: "Endpoint 1 at %(point1X)s comma %(point1Y)s. Endpoint 2 %(point2X)s comma %(point2Y)s.",
|
|
240
|
-
srSegmentLength: "Segment length %(length)s units.",
|
|
241
|
-
srSingleSegmentGraphEndpointAriaLabel: "Endpoint %(endpointNumber)s at %(x)s comma %(y)s.",
|
|
242
|
-
srMultipleSegmentGraphEndpointAriaLabel: "Endpoint %(endpointNumber)s on segment %(indexOfSegment)s at %(x)s comma %(y)s.",
|
|
243
|
-
srSegmentGrabHandle: "Segment from %(point1X)s comma %(point1Y)s to %(point2X)s comma %(point2Y)s.",
|
|
244
|
-
srLinearSystemGraph: "Two lines on a coordinate plane.",
|
|
245
|
-
srLinearSystemPoints: "Line %(lineNumber)s has two points, point 1 at %(point1X)s comma %(point1Y)s and point 2 at %(point2X)s comma %(point2Y)s.",
|
|
246
|
-
srLinearSystemPoint: "Point %(pointSequence)s on line %(lineNumber)s at %(x)s comma %(y)s.",
|
|
247
|
-
srRayGraph: "A ray on a coordinate plane.",
|
|
248
|
-
srRayPoints: "The endpoint is at %(point1X)s comma %(point1Y)s and the ray goes through point %(point2X)s comma %(point2Y)s.",
|
|
249
|
-
srRayGrabHandle: "Ray with endpoint %(point1X)s comma %(point1Y)s going through point %(point2X)s comma %(point2Y)s.",
|
|
250
|
-
srRayEndpoint: "Endpoint at %(x)s comma %(y)s.",
|
|
251
|
-
srRayTerminalPoint: "Through point at %(x)s comma %(y)s.",
|
|
252
|
-
srQuadraticGraph: "A parabola on a 4-quadrant coordinate plane.",
|
|
253
|
-
srQuadraticFaceUp: "The parabola opens upward.",
|
|
254
|
-
srQuadraticFaceDown: "The parabola opens downward.",
|
|
255
|
-
srQuadraticGraphVertexOrigin: "Vertex is at the origin.",
|
|
256
|
-
srQuadraticGraphVertexXAxis: "Vertex is on the X-axis.",
|
|
257
|
-
srQuadraticGraphVertexYAxis: "Vertex is on the Y-axis.",
|
|
258
|
-
srQuadraticGraphVertexQuadrant: "Vertex is in quadrant %(quadrant)s.",
|
|
259
|
-
srQuadraticTwoXIntercepts: "The X-intercepts are at %(intercept1)s comma 0 and %(intercept2)s comma 0.",
|
|
260
|
-
srQuadraticOneXIntercept: "The X-intercept is at %(intercept)s comma 0.",
|
|
261
|
-
srQuadraticYIntercept: "The Y-intercept is at 0 comma %(intercept)s.",
|
|
262
|
-
srQuadraticPointOrigin: "Point %(pointNumber)s on parabola at the origin.",
|
|
263
|
-
srQuadraticPointAxis: "Point %(pointNumber)s on parabola at %(x)s comma %(y)s.",
|
|
264
|
-
srQuadraticPointQuadrant: "Point %(pointNumber)s on parabola in quadrant %(quadrant)s at %(x)s comma %(y)s.",
|
|
265
|
-
srQuadraticInteractiveElements: "Parabola with points at %(point1X)s comma %(point1Y)s, %(point2X)s comma %(point2Y)s, and %(point3X)s comma %(point3Y)s."
|
|
266
|
-
// The above strings are used for interactive graph SR descriptions.
|
|
267
|
-
};
|
|
268
|
-
|
|
269
62
|
/**
|
|
270
63
|
* Mock strings for the Perseus package, to be used for tests and Storybook.
|
|
271
64
|
*/
|
|
@@ -650,24 +443,32 @@ const mockStrings = {
|
|
|
650
443
|
|
|
651
444
|
// This type helps us make sure all error codes are mapped to strings
|
|
652
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Map an error string to a PerseusStrings key
|
|
448
|
+
* that we can use to get the translated error message
|
|
449
|
+
*/
|
|
653
450
|
const errorToString = {
|
|
654
|
-
MISSING_PERCENT_ERROR:
|
|
655
|
-
NEEDS_TO_BE_SIMPLIFIED_ERROR:
|
|
656
|
-
APPROXIMATED_PI_ERROR:
|
|
657
|
-
EXTRA_SYMBOLS_ERROR:
|
|
658
|
-
WRONG_CASE_ERROR:
|
|
659
|
-
WRONG_LETTER_ERROR:
|
|
660
|
-
MULTIPLICATION_SIGN_ERROR:
|
|
661
|
-
INVALID_SELECTION_ERROR:
|
|
662
|
-
CHOOSE_CORRECT_NUM_ERROR:
|
|
663
|
-
NOT_NONE_ABOVE_ERROR:
|
|
664
|
-
FILL_ALL_CELLS_ERROR:
|
|
665
|
-
};
|
|
666
|
-
function mapErrorToString(
|
|
451
|
+
MISSING_PERCENT_ERROR: "MISSING_PERCENT_ERROR",
|
|
452
|
+
NEEDS_TO_BE_SIMPLIFIED_ERROR: "NEEDS_TO_BE_SIMPLFIED_ERROR",
|
|
453
|
+
APPROXIMATED_PI_ERROR: "APPROXIMATED_PI_ERROR",
|
|
454
|
+
EXTRA_SYMBOLS_ERROR: "EXTRA_SYMBOLS_ERROR",
|
|
455
|
+
WRONG_CASE_ERROR: "WRONG_CASE_ERROR",
|
|
456
|
+
WRONG_LETTER_ERROR: "WRONG_LETTER_ERROR",
|
|
457
|
+
MULTIPLICATION_SIGN_ERROR: "MULTIPLICATION_SIGN_ERROR",
|
|
458
|
+
INVALID_SELECTION_ERROR: "invalidSelection",
|
|
459
|
+
CHOOSE_CORRECT_NUM_ERROR: "chooseCorrectNum",
|
|
460
|
+
NOT_NONE_ABOVE_ERROR: "notNoneOfTheAbove",
|
|
461
|
+
FILL_ALL_CELLS_ERROR: "fillAllCells"
|
|
462
|
+
};
|
|
463
|
+
function mapErrorToString(
|
|
464
|
+
// the string representing an error code
|
|
465
|
+
err,
|
|
466
|
+
// the translated Perseus strings
|
|
467
|
+
translatedStrings) {
|
|
667
468
|
if (!err) {
|
|
668
469
|
return err;
|
|
669
470
|
}
|
|
670
|
-
return errorToString[err] || err;
|
|
471
|
+
return translatedStrings[errorToString[err]] || err;
|
|
671
472
|
}
|
|
672
473
|
|
|
673
474
|
/**
|
|
@@ -1588,7 +1389,6 @@ const ClassNames = {
|
|
|
1588
1389
|
SELECTED: "perseus-radio-selected",
|
|
1589
1390
|
OPTION_CONTENT: "perseus-radio-option-content"
|
|
1590
1391
|
},
|
|
1591
|
-
INTERACTIVE: "perseus-interactive",
|
|
1592
1392
|
CORRECT: "perseus-correct",
|
|
1593
1393
|
INCORRECT: "perseus-incorrect",
|
|
1594
1394
|
UNANSWERED: "perseus-unanswered",
|
|
@@ -1836,7 +1636,6 @@ class Expression extends React.Component {
|
|
|
1836
1636
|
// eslint-disable-next-line react/no-string-refs
|
|
1837
1637
|
, {
|
|
1838
1638
|
ref: "input",
|
|
1839
|
-
className: ClassNames.INTERACTIVE,
|
|
1840
1639
|
value: this.props.value,
|
|
1841
1640
|
onChange: this.changeAndTrack,
|
|
1842
1641
|
convertDotToTimes: this.props.times,
|
|
@@ -1949,7 +1748,6 @@ var Expression$1 = {
|
|
|
1949
1748
|
name: "expression",
|
|
1950
1749
|
displayName: "Expression / Equation",
|
|
1951
1750
|
accessible: true,
|
|
1952
|
-
defaultAlignment: "inline-block",
|
|
1953
1751
|
widget: ExpressionWithDependencies,
|
|
1954
1752
|
transform: widgetOptions => {
|
|
1955
1753
|
const {
|
|
@@ -1974,12 +1772,6 @@ var Expression$1 = {
|
|
|
1974
1772
|
propUpgrades: expressionLogic.widgetOptionsUpgrades,
|
|
1975
1773
|
// For use by the editor
|
|
1976
1774
|
isLintable: true,
|
|
1977
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
1978
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusExpressionUserInput'.
|
|
1979
|
-
scorer: scoreExpression,
|
|
1980
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
1981
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusExpressionUserInput'.
|
|
1982
|
-
validator: validateExpression,
|
|
1983
1775
|
getPublicWidgetOptions: getExpressionPublicWidgetOptions,
|
|
1984
1776
|
// TODO(LEMS-2656): remove TS suppression
|
|
1985
1777
|
// @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusExpressionRubric'.
|
|
@@ -3260,10 +3052,6 @@ const pureMdMax$1 = "1023px";
|
|
|
3260
3052
|
const pureLgMax$1 = "1279px";
|
|
3261
3053
|
// @tableBackgroundAccent: #f9f9f9; // for striping
|
|
3262
3054
|
const tableBackgroundAccent = "#F9F9F9";
|
|
3263
|
-
// @zIndexAboveScratchpad: @zIndexScratchPad + 1;
|
|
3264
|
-
const zIndexAboveScratchpad$1 = 2;
|
|
3265
|
-
// @zIndexInteractiveComponent: @zIndexAboveScratchpad + 1;
|
|
3266
|
-
const zIndexInteractiveComponent$1 = 3;
|
|
3267
3055
|
// @phoneMargin: 16px;
|
|
3268
3056
|
const phoneMargin = 16;
|
|
3269
3057
|
const negativePhoneMargin = -16;
|
|
@@ -3307,8 +3095,6 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
3307
3095
|
pureMdMax: pureMdMax$1,
|
|
3308
3096
|
pureLgMax: pureLgMax$1,
|
|
3309
3097
|
tableBackgroundAccent: tableBackgroundAccent,
|
|
3310
|
-
zIndexAboveScratchpad: zIndexAboveScratchpad$1,
|
|
3311
|
-
zIndexInteractiveComponent: zIndexInteractiveComponent$1,
|
|
3312
3098
|
phoneMargin: phoneMargin,
|
|
3313
3099
|
negativePhoneMargin: negativePhoneMargin,
|
|
3314
3100
|
hintBorderWidth: hintBorderWidth,
|
|
@@ -17533,658 +17319,6 @@ class QuestionParagraph extends React.Component {
|
|
|
17533
17319
|
}
|
|
17534
17320
|
}
|
|
17535
17321
|
|
|
17536
|
-
const noScore = {
|
|
17537
|
-
type: "points",
|
|
17538
|
-
earned: 0,
|
|
17539
|
-
total: 0,
|
|
17540
|
-
message: null
|
|
17541
|
-
};
|
|
17542
|
-
|
|
17543
|
-
/**
|
|
17544
|
-
* If a widget says that it is empty once it is graded.
|
|
17545
|
-
* Trying to encapsulate references to the score format.
|
|
17546
|
-
*/
|
|
17547
|
-
function scoreIsEmpty(score) {
|
|
17548
|
-
// HACK(benkomalo): ugh. this isn't great; the Perseus score objects
|
|
17549
|
-
// overload the type "invalid" for what should probably be three
|
|
17550
|
-
// distinct cases:
|
|
17551
|
-
// - truly empty or not fully filled out
|
|
17552
|
-
// - invalid or malformed inputs
|
|
17553
|
-
// - "almost correct" like inputs where the widget wants to give
|
|
17554
|
-
// feedback (e.g. a fraction needs to be reduced, or `pi` should
|
|
17555
|
-
// be used instead of 3.14)
|
|
17556
|
-
//
|
|
17557
|
-
// Unfortunately the coercion happens all over the place, as these
|
|
17558
|
-
// Perseus style score objects are created *everywhere* (basically
|
|
17559
|
-
// in every widget), so it's hard to change now. We assume that
|
|
17560
|
-
// anything with a "message" is not truly empty, and one of the
|
|
17561
|
-
// latter two cases for now.
|
|
17562
|
-
return score.type === "invalid" && (!score.message || score.message.length === 0);
|
|
17563
|
-
}
|
|
17564
|
-
|
|
17565
|
-
/**
|
|
17566
|
-
* Combine two score objects.
|
|
17567
|
-
*
|
|
17568
|
-
* Given two score objects for two different widgets, combine them so that
|
|
17569
|
-
* if one is wrong, the total score is wrong, etc.
|
|
17570
|
-
*/
|
|
17571
|
-
function combineScores(scoreA, scoreB) {
|
|
17572
|
-
let message;
|
|
17573
|
-
if (scoreA.type === "points" && scoreB.type === "points") {
|
|
17574
|
-
if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
|
|
17575
|
-
// TODO(alpert): Figure out how to combine messages usefully
|
|
17576
|
-
message = null;
|
|
17577
|
-
} else {
|
|
17578
|
-
message = scoreA.message || scoreB.message;
|
|
17579
|
-
}
|
|
17580
|
-
return {
|
|
17581
|
-
type: "points",
|
|
17582
|
-
earned: scoreA.earned + scoreB.earned,
|
|
17583
|
-
total: scoreA.total + scoreB.total,
|
|
17584
|
-
message: message
|
|
17585
|
-
};
|
|
17586
|
-
}
|
|
17587
|
-
if (scoreA.type === "points" && scoreB.type === "invalid") {
|
|
17588
|
-
return scoreB;
|
|
17589
|
-
}
|
|
17590
|
-
if (scoreA.type === "invalid" && scoreB.type === "points") {
|
|
17591
|
-
return scoreA;
|
|
17592
|
-
}
|
|
17593
|
-
if (scoreA.type === "invalid" && scoreB.type === "invalid") {
|
|
17594
|
-
if (scoreA.message && scoreB.message && scoreA.message !== scoreB.message) {
|
|
17595
|
-
// TODO(alpert): Figure out how to combine messages usefully
|
|
17596
|
-
message = null;
|
|
17597
|
-
} else {
|
|
17598
|
-
message = scoreA.message || scoreB.message;
|
|
17599
|
-
}
|
|
17600
|
-
return {
|
|
17601
|
-
type: "invalid",
|
|
17602
|
-
message: message
|
|
17603
|
-
};
|
|
17604
|
-
}
|
|
17605
|
-
|
|
17606
|
-
/**
|
|
17607
|
-
* The above checks cover all combinations of score type, so if we get here
|
|
17608
|
-
* then something is amiss with our inputs.
|
|
17609
|
-
*/
|
|
17610
|
-
throw new PerseusError("PerseusScore with unknown type encountered", Errors.InvalidInput, {
|
|
17611
|
-
metadata: {
|
|
17612
|
-
scoreA: JSON.stringify(scoreA),
|
|
17613
|
-
scoreB: JSON.stringify(scoreB)
|
|
17614
|
-
}
|
|
17615
|
-
});
|
|
17616
|
-
}
|
|
17617
|
-
function flattenScores(widgetScoreMap) {
|
|
17618
|
-
return Object.values(widgetScoreMap).reduce(combineScores, noScore);
|
|
17619
|
-
}
|
|
17620
|
-
function isCorrect(score) {
|
|
17621
|
-
return score.type === "points" && score.earned >= score.total;
|
|
17622
|
-
}
|
|
17623
|
-
function keScoreFromPerseusScore(score,
|
|
17624
|
-
// It's weird, but this is what we're passing it
|
|
17625
|
-
guess, state) {
|
|
17626
|
-
if (score.type === "points") {
|
|
17627
|
-
return {
|
|
17628
|
-
empty: false,
|
|
17629
|
-
correct: isCorrect(score),
|
|
17630
|
-
message: score.message,
|
|
17631
|
-
guess: guess,
|
|
17632
|
-
state: state
|
|
17633
|
-
};
|
|
17634
|
-
}
|
|
17635
|
-
if (score.type === "invalid") {
|
|
17636
|
-
return {
|
|
17637
|
-
empty: true,
|
|
17638
|
-
correct: false,
|
|
17639
|
-
message: score.message,
|
|
17640
|
-
suppressAlmostThere: score.suppressAlmostThere,
|
|
17641
|
-
guess: guess,
|
|
17642
|
-
state: state
|
|
17643
|
-
};
|
|
17644
|
-
}
|
|
17645
|
-
throw new PerseusError(
|
|
17646
|
-
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
17647
|
-
"Invalid score type: " + score.type, Errors.InvalidInput, {
|
|
17648
|
-
metadata: {
|
|
17649
|
-
score: JSON.stringify(score),
|
|
17650
|
-
guess: JSON.stringify(guess),
|
|
17651
|
-
state: JSON.stringify(state)
|
|
17652
|
-
}
|
|
17653
|
-
});
|
|
17654
|
-
}
|
|
17655
|
-
|
|
17656
|
-
const DEFAULT_ALIGNMENT$1 = "block";
|
|
17657
|
-
// NOTE(kevinb): "default" is not one in `validAlignments`.
|
|
17658
|
-
const DEFAULT_SUPPORTED_ALIGNMENTS = ["default"];
|
|
17659
|
-
const DEFAULT_STATIC = false;
|
|
17660
|
-
const DEFAULT_TRACKING = "";
|
|
17661
|
-
const DEFAULT_LINTABLE = false;
|
|
17662
|
-
const widgets = {};
|
|
17663
|
-
const editors = {};
|
|
17664
|
-
|
|
17665
|
-
// Widgets must be registered to avoid circular dependencies with the
|
|
17666
|
-
// core Editor and Renderer components.
|
|
17667
|
-
// TODO(jeremy): The widget name is already embedded in the WidgetExports type
|
|
17668
|
-
// so could we drop the `name` parameter here?
|
|
17669
|
-
const registerWidget = (name, widget) => {
|
|
17670
|
-
widgets[name] = widget;
|
|
17671
|
-
};
|
|
17672
|
-
const registerWidgets = widgets => {
|
|
17673
|
-
widgets.forEach(widget => {
|
|
17674
|
-
registerWidget(widget.name, widget);
|
|
17675
|
-
});
|
|
17676
|
-
validateAlignments();
|
|
17677
|
-
};
|
|
17678
|
-
|
|
17679
|
-
/**
|
|
17680
|
-
*
|
|
17681
|
-
* @param name - the widget that you are trying to replace
|
|
17682
|
-
* @param replacementName - the name of the widget that takes its place
|
|
17683
|
-
*
|
|
17684
|
-
* e.g. replaceWidget("transformer", "deprecated-standin") will make it so the
|
|
17685
|
-
* transformer widget is replaced by the always correct widget
|
|
17686
|
-
*/
|
|
17687
|
-
const replaceWidget = (name, replacementName) => {
|
|
17688
|
-
const substituteWidget = widgets[replacementName];
|
|
17689
|
-
|
|
17690
|
-
// If the replacement widget isn't found, we need to throw. Otherwise after
|
|
17691
|
-
// removing the deprecated widget, we'll have data asking for a widget type
|
|
17692
|
-
// that doesn't exist at all.
|
|
17693
|
-
if (!substituteWidget) {
|
|
17694
|
-
const errorMsg = `Failed to replace ${name} with ${replacementName}`;
|
|
17695
|
-
throw new PerseusError(errorMsg, Errors.Internal);
|
|
17696
|
-
}
|
|
17697
|
-
registerWidget(name, substituteWidget);
|
|
17698
|
-
};
|
|
17699
|
-
const replaceDeprecatedWidgets = () => {
|
|
17700
|
-
replaceWidget("transformer", "deprecated-standin");
|
|
17701
|
-
replaceWidget("lights-puzzle", "deprecated-standin");
|
|
17702
|
-
replaceWidget("reaction-diagram", "deprecated-standin");
|
|
17703
|
-
replaceWidget("sequence", "deprecated-standin");
|
|
17704
|
-
replaceWidget("simulator", "deprecated-standin");
|
|
17705
|
-
replaceWidget("unit-input", "deprecated-standin");
|
|
17706
|
-
};
|
|
17707
|
-
const registerEditors = editorsToRegister => {
|
|
17708
|
-
editorsToRegister.forEach(editor => {
|
|
17709
|
-
if (!editor.widgetName) {
|
|
17710
|
-
throw new PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, Errors.Internal);
|
|
17711
|
-
}
|
|
17712
|
-
editors[editor.widgetName] = editor;
|
|
17713
|
-
});
|
|
17714
|
-
};
|
|
17715
|
-
|
|
17716
|
-
/**
|
|
17717
|
-
*
|
|
17718
|
-
* @param name - the widget that you are trying to replace
|
|
17719
|
-
* @param replacementName - the name of the widget that takes its place
|
|
17720
|
-
*
|
|
17721
|
-
* e.g. replaceEditor("transformer", "deprecated-standin") will make it so the
|
|
17722
|
-
* transformer widget is replaced by the deprecated stand-in widget
|
|
17723
|
-
*/
|
|
17724
|
-
const replaceEditor = (name, replacementName) => {
|
|
17725
|
-
const substituteEditor = editors[replacementName];
|
|
17726
|
-
if (!substituteEditor && Log) {
|
|
17727
|
-
const errorMsg = `Failed to replace editor ${name} with ${replacementName}`;
|
|
17728
|
-
Log.error(errorMsg, Errors.Internal);
|
|
17729
|
-
return;
|
|
17730
|
-
}
|
|
17731
|
-
editors[name] = substituteEditor;
|
|
17732
|
-
};
|
|
17733
|
-
const replaceDeprecatedEditors = () => {
|
|
17734
|
-
replaceEditor("transformer", "deprecated-standin");
|
|
17735
|
-
replaceEditor("lights-puzzle", "deprecated-standin");
|
|
17736
|
-
replaceEditor("reaction-diagram", "deprecated-standin");
|
|
17737
|
-
replaceEditor("sequence", "deprecated-standin");
|
|
17738
|
-
replaceEditor("simulator", "deprecated-standin");
|
|
17739
|
-
replaceEditor("unit-input", "deprecated-standin");
|
|
17740
|
-
};
|
|
17741
|
-
const getWidget = name => {
|
|
17742
|
-
var _widgets$name;
|
|
17743
|
-
// TODO(alex): Consider referring to these as renderers to avoid
|
|
17744
|
-
// overloading "widget"
|
|
17745
|
-
if (!_.has(widgets, name)) {
|
|
17746
|
-
return null;
|
|
17747
|
-
}
|
|
17748
|
-
|
|
17749
|
-
// Allow widgets to specify a widget directly or via a function
|
|
17750
|
-
if ((_widgets$name = widgets[name]) != null && _widgets$name.getWidget) {
|
|
17751
|
-
var _widgets$name$getWidg, _widgets$name2;
|
|
17752
|
-
return (_widgets$name$getWidg = (_widgets$name2 = widgets[name]).getWidget) == null ? void 0 : _widgets$name$getWidg.call(_widgets$name2);
|
|
17753
|
-
}
|
|
17754
|
-
return widgets[name].widget;
|
|
17755
|
-
};
|
|
17756
|
-
const getWidgetExport = name => {
|
|
17757
|
-
var _widgets$name3;
|
|
17758
|
-
return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
|
|
17759
|
-
};
|
|
17760
|
-
const getWidgetValidator = name => {
|
|
17761
|
-
var _widgets$name$validat, _widgets$name4;
|
|
17762
|
-
return (_widgets$name$validat = (_widgets$name4 = widgets[name]) == null ? void 0 : _widgets$name4.validator) != null ? _widgets$name$validat : null;
|
|
17763
|
-
};
|
|
17764
|
-
const getWidgetScorer = name => {
|
|
17765
|
-
var _widgets$name$scorer, _widgets$name5;
|
|
17766
|
-
return (_widgets$name$scorer = (_widgets$name5 = widgets[name]) == null ? void 0 : _widgets$name5.scorer) != null ? _widgets$name$scorer : null;
|
|
17767
|
-
};
|
|
17768
|
-
const getPublicWidgetOptionsFunction = name => {
|
|
17769
|
-
var _widgets$name$getPubl, _widgets$name6;
|
|
17770
|
-
return (_widgets$name$getPubl = (_widgets$name6 = widgets[name]) == null ? void 0 : _widgets$name6.getPublicWidgetOptions) != null ? _widgets$name$getPubl : i => i;
|
|
17771
|
-
};
|
|
17772
|
-
const getEditor = name => {
|
|
17773
|
-
return _.has(editors, name) ? editors[name] : null;
|
|
17774
|
-
};
|
|
17775
|
-
const getTransform = name => {
|
|
17776
|
-
return _.has(widgets, name) ? widgets[name].transform || _.identity : null;
|
|
17777
|
-
};
|
|
17778
|
-
const getVersion = name => {
|
|
17779
|
-
const widgetInfo = widgets[name];
|
|
17780
|
-
if (widgetInfo) {
|
|
17781
|
-
return widgets[name].version || {
|
|
17782
|
-
major: 0,
|
|
17783
|
-
minor: 0
|
|
17784
|
-
};
|
|
17785
|
-
}
|
|
17786
|
-
return;
|
|
17787
|
-
};
|
|
17788
|
-
const getVersionVector = () => {
|
|
17789
|
-
const version = {};
|
|
17790
|
-
_.each(_.keys(widgets), function (name) {
|
|
17791
|
-
version[name] = getVersion(name);
|
|
17792
|
-
});
|
|
17793
|
-
return version;
|
|
17794
|
-
};
|
|
17795
|
-
const getPublicWidgets = () => {
|
|
17796
|
-
// TODO(alex): Update underscore.js so that _.pick can take a function.
|
|
17797
|
-
// @ts-expect-error - TS2740 - Type 'Pick<{ [key: string]: Readonly<{ name: string; displayName: string; getWidget?: (() => ComponentType<any>) | undefined; accessible?: boolean | ((props: any) => boolean) | undefined; hidden?: boolean | undefined; ... 10 more ...; widget: ComponentType<...>; }>; }, string>' is missing the following properties from type 'readonly Readonly<{ name: string; displayName: string; getWidget?: (() => ComponentType<any>) | undefined; accessible?: boolean | ((props: any) => boolean) | undefined; hidden?: boolean | undefined; ... 10 more ...; widget: ComponentType<...>; }>[]': length, concat, join, slice, and 18 more.
|
|
17798
|
-
return _.pick(widgets,
|
|
17799
|
-
// @ts-expect-error - TS2345 - Argument of type '(name: string) => boolean | undefined' is not assignable to parameter of type 'Iteratee<string[], boolean, string>'.
|
|
17800
|
-
_.reject(_.keys(widgets), function (name) {
|
|
17801
|
-
return widgets[name].hidden;
|
|
17802
|
-
}));
|
|
17803
|
-
};
|
|
17804
|
-
const isAccessible = widgetInfo => {
|
|
17805
|
-
const accessible = widgets[widgetInfo.type].accessible;
|
|
17806
|
-
if (typeof accessible === "function") {
|
|
17807
|
-
return accessible(widgetInfo.options);
|
|
17808
|
-
}
|
|
17809
|
-
return !!accessible;
|
|
17810
|
-
};
|
|
17811
|
-
const getAllWidgetTypes = () => {
|
|
17812
|
-
return _.keys(widgets);
|
|
17813
|
-
};
|
|
17814
|
-
const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
17815
|
-
const type = oldWidgetInfo.type;
|
|
17816
|
-
// NOTE(jeremy): This looks like it could be replaced by fixing types so
|
|
17817
|
-
// that `type` is non-optional. But we're seeing this in Sentry today so I
|
|
17818
|
-
// suspect we have legacy data (potentially unpublished) and we should
|
|
17819
|
-
// figure that out before depending solely on types.
|
|
17820
|
-
if (!_.isString(type)) {
|
|
17821
|
-
throw new PerseusError("widget type must be a string, but was: " + type, Errors.Internal);
|
|
17822
|
-
}
|
|
17823
|
-
const widgetExports = widgets[type];
|
|
17824
|
-
if (widgetExports == null) {
|
|
17825
|
-
// If we have a widget that isn't registered, we can't upgrade it
|
|
17826
|
-
// TODO(aria): Figure out what the best thing to do here would be
|
|
17827
|
-
return oldWidgetInfo;
|
|
17828
|
-
}
|
|
17829
|
-
|
|
17830
|
-
// Unversioned widgets (pre-July 2014) are all implicitly 0.0
|
|
17831
|
-
const initialVersion = oldWidgetInfo.version || {
|
|
17832
|
-
major: 0,
|
|
17833
|
-
minor: 0
|
|
17834
|
-
};
|
|
17835
|
-
const latestVersion = widgetExports.version || {
|
|
17836
|
-
major: 0,
|
|
17837
|
-
minor: 0
|
|
17838
|
-
};
|
|
17839
|
-
|
|
17840
|
-
// If the widget version is later than what we understand (major
|
|
17841
|
-
// version is higher than latest, or major versions are equal and minor
|
|
17842
|
-
// version is higher than latest), don't perform any upgrades.
|
|
17843
|
-
if (initialVersion.major > latestVersion.major || initialVersion.major === latestVersion.major && initialVersion.minor > latestVersion.minor) {
|
|
17844
|
-
return oldWidgetInfo;
|
|
17845
|
-
}
|
|
17846
|
-
|
|
17847
|
-
// We do a clone here so that it's safe to mutate the input parameter
|
|
17848
|
-
// in propUpgrades functions (which I will probably accidentally do at
|
|
17849
|
-
// some point, and we would like to not break when that happens).
|
|
17850
|
-
let newEditorProps = _.clone(oldWidgetInfo.options) || {};
|
|
17851
|
-
const upgradePropsMap = widgetExports.propUpgrades || {};
|
|
17852
|
-
|
|
17853
|
-
// Empty props usually mean a newly created widget by the editor,
|
|
17854
|
-
// and are always considerered up-to-date.
|
|
17855
|
-
// Mostly, we'd rather not run upgrade functions on props that are
|
|
17856
|
-
// not complete.
|
|
17857
|
-
if (_.keys(newEditorProps).length !== 0) {
|
|
17858
|
-
// We loop through all the versions after the current version of
|
|
17859
|
-
// the loaded widget, up to and including the latest version of the
|
|
17860
|
-
// loaded widget, and run the upgrade function to bring our loaded
|
|
17861
|
-
// widget's props up to that version.
|
|
17862
|
-
// There is a little subtlety here in that we call
|
|
17863
|
-
// upgradePropsMap[1] to upgrade *to* version 1,
|
|
17864
|
-
// (not from version 1).
|
|
17865
|
-
for (let nextVersion = initialVersion.major + 1; nextVersion <= latestVersion.major; nextVersion++) {
|
|
17866
|
-
if (upgradePropsMap[String(nextVersion)]) {
|
|
17867
|
-
newEditorProps = upgradePropsMap[String(nextVersion)](newEditorProps);
|
|
17868
|
-
} else {
|
|
17869
|
-
// This is a Log.error because it is unlikely to be hit in
|
|
17870
|
-
// local testing, and a Log.error is slightly less scary in
|
|
17871
|
-
// prod than a `throw new Error`
|
|
17872
|
-
Log.error("No upgrade found for widget. Cannot render.", Errors.Internal, {
|
|
17873
|
-
loggedMetadata: {
|
|
17874
|
-
type,
|
|
17875
|
-
fromMajorVersion: nextVersion - 1,
|
|
17876
|
-
toMajorVersion: nextVersion
|
|
17877
|
-
}
|
|
17878
|
-
});
|
|
17879
|
-
// But try to keep going anyways (yolo!)
|
|
17880
|
-
// (Throwing an error here would just break the page
|
|
17881
|
-
// silently anyways, so that doesn't seem much better
|
|
17882
|
-
// than a halfhearted attempt to continue, however
|
|
17883
|
-
// shallow...)
|
|
17884
|
-
}
|
|
17885
|
-
}
|
|
17886
|
-
}
|
|
17887
|
-
|
|
17888
|
-
// Minor version upgrades (eg. new optional props) don't have
|
|
17889
|
-
// transform functions. Instead, we fill in the new props with their
|
|
17890
|
-
// defaults.
|
|
17891
|
-
const defaultProps = type in editors ? editors[type].defaultProps : {};
|
|
17892
|
-
newEditorProps = _extends({}, defaultProps, newEditorProps);
|
|
17893
|
-
let alignment = oldWidgetInfo.alignment;
|
|
17894
|
-
|
|
17895
|
-
// Widgets that support multiple alignments will "lock in" the
|
|
17896
|
-
// alignment to the alignment that would be listed first in the
|
|
17897
|
-
// select box. If the widget only supports one alignment, the
|
|
17898
|
-
// alignment value will likely just end up as "default".
|
|
17899
|
-
if (alignment == null || alignment === "default") {
|
|
17900
|
-
alignment = getSupportedAlignments(type)[0];
|
|
17901
|
-
}
|
|
17902
|
-
let widgetStatic = oldWidgetInfo.static;
|
|
17903
|
-
if (widgetStatic == null) {
|
|
17904
|
-
widgetStatic = DEFAULT_STATIC;
|
|
17905
|
-
}
|
|
17906
|
-
return _.extend({}, oldWidgetInfo, {
|
|
17907
|
-
// maintain other info, like type
|
|
17908
|
-
// After upgrading we guarantee that the version is up-to-date
|
|
17909
|
-
version: latestVersion,
|
|
17910
|
-
// Default graded to true (so null/undefined becomes true):
|
|
17911
|
-
graded: oldWidgetInfo.graded != null ? oldWidgetInfo.graded : true,
|
|
17912
|
-
alignment: alignment,
|
|
17913
|
-
static: widgetStatic,
|
|
17914
|
-
options: newEditorProps
|
|
17915
|
-
});
|
|
17916
|
-
};
|
|
17917
|
-
const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
17918
|
-
const type = widgetInfo.type;
|
|
17919
|
-
const widgetExports = widgets[type];
|
|
17920
|
-
if (widgetExports == null) {
|
|
17921
|
-
// The widget is not a registered widget
|
|
17922
|
-
// It shouldn't matter what we return here, but for consistency
|
|
17923
|
-
// we return the untransformed options, as if the widget did
|
|
17924
|
-
// not have a transform defined.
|
|
17925
|
-
return widgetInfo;
|
|
17926
|
-
}
|
|
17927
|
-
let transform;
|
|
17928
|
-
if (widgetInfo.static) {
|
|
17929
|
-
// There aren't a lot of real places where we'll have to default to
|
|
17930
|
-
// _.identity, but it's theoretically possible if someone changes
|
|
17931
|
-
// the JSON manually / we have to back out static support for a
|
|
17932
|
-
// widget.
|
|
17933
|
-
transform = getStaticTransform(type) || _.identity;
|
|
17934
|
-
} else {
|
|
17935
|
-
transform = widgetExports.transform || _.identity;
|
|
17936
|
-
}
|
|
17937
|
-
// widgetInfo.options are the widgetEditor's props:
|
|
17938
|
-
return transform(widgetInfo.options, strings, problemNum);
|
|
17939
|
-
};
|
|
17940
|
-
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
17941
|
-
if (!traverseRenderer) {
|
|
17942
|
-
throw new PerseusError("traverseRenderer must be provided, but was not", Errors.Internal);
|
|
17943
|
-
}
|
|
17944
|
-
if (!widgetInfo || !widgetInfo.type || !widgets[widgetInfo.type]) {
|
|
17945
|
-
return widgetInfo;
|
|
17946
|
-
}
|
|
17947
|
-
const widgetExports = widgets[widgetInfo.type];
|
|
17948
|
-
const props = widgetInfo.options;
|
|
17949
|
-
if (widgetExports.traverseChildWidgets && props) {
|
|
17950
|
-
const newProps = widgetExports.traverseChildWidgets(props, traverseRenderer);
|
|
17951
|
-
return _.extend({}, widgetInfo, {
|
|
17952
|
-
options: newProps
|
|
17953
|
-
});
|
|
17954
|
-
}
|
|
17955
|
-
return widgetInfo;
|
|
17956
|
-
};
|
|
17957
|
-
|
|
17958
|
-
/**
|
|
17959
|
-
* Handling for the optional alignments for widgets
|
|
17960
|
-
* See widget-container.jsx for details on how alignments are implemented.
|
|
17961
|
-
*/
|
|
17962
|
-
|
|
17963
|
-
/**
|
|
17964
|
-
* Returns the list of supported alignments for the given (string) widget
|
|
17965
|
-
* type. This is used primarily at editing time to display the choices
|
|
17966
|
-
* for the user.
|
|
17967
|
-
*
|
|
17968
|
-
* Supported alignments are given as an array of strings in the exports of
|
|
17969
|
-
* a widget's module.
|
|
17970
|
-
*/
|
|
17971
|
-
const getSupportedAlignments = type => {
|
|
17972
|
-
const widgetExport = widgets[type];
|
|
17973
|
-
// @ts-expect-error - TS2322 - Type 'string[] | readonly Alignment[]' is not assignable to type 'readonly Alignment[]'.
|
|
17974
|
-
return widgetExport && widgetExport.supportedAlignments || DEFAULT_SUPPORTED_ALIGNMENTS;
|
|
17975
|
-
};
|
|
17976
|
-
|
|
17977
|
-
/**
|
|
17978
|
-
* For the given (string) widget type, determine the default alignment for
|
|
17979
|
-
* the widget. This is used at rendering time to go from "default" alignment
|
|
17980
|
-
* to the actual alignment displayed on the screen.
|
|
17981
|
-
*
|
|
17982
|
-
* The default alignment is given either as a string (called
|
|
17983
|
-
* `defaultAlignment`) or a function (called `getDefaultAlignment`) on
|
|
17984
|
-
* the exports of a widget's module.
|
|
17985
|
-
*/
|
|
17986
|
-
const getDefaultAlignment = type => {
|
|
17987
|
-
const widgetExports = widgets[type];
|
|
17988
|
-
let alignment;
|
|
17989
|
-
if (!widgetExports) {
|
|
17990
|
-
return DEFAULT_ALIGNMENT$1;
|
|
17991
|
-
}
|
|
17992
|
-
if (widgetExports.getDefaultAlignment) {
|
|
17993
|
-
alignment = widgetExports.getDefaultAlignment();
|
|
17994
|
-
} else {
|
|
17995
|
-
alignment = widgetExports.defaultAlignment;
|
|
17996
|
-
}
|
|
17997
|
-
return alignment || DEFAULT_ALIGNMENT$1;
|
|
17998
|
-
};
|
|
17999
|
-
const validAlignments = ["block", "inline-block", "inline", "float-left", "float-right", "full-width"];
|
|
18000
|
-
|
|
18001
|
-
/**
|
|
18002
|
-
* Used at startup to fail fast if an alignment given by a widget is
|
|
18003
|
-
* invalid.
|
|
18004
|
-
*/
|
|
18005
|
-
// TODO(alex): Change this to run as a testcase (vs. being run at runtime)
|
|
18006
|
-
// TODO(LP-10707): I think this can be completely removed because our TypeScript types
|
|
18007
|
-
// enforce this!
|
|
18008
|
-
const validateAlignments = () => {
|
|
18009
|
-
_.each(widgets, function (widgetInfo) {
|
|
18010
|
-
if (widgetInfo.defaultAlignment && !_.contains(validAlignments, widgetInfo.defaultAlignment)) {
|
|
18011
|
-
throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid defaultAlignment value: " + widgetInfo.defaultAlignment, Errors.InvalidInput);
|
|
18012
|
-
}
|
|
18013
|
-
if (widgetInfo.supportedAlignments) {
|
|
18014
|
-
const unknownAlignments = _.difference(widgetInfo.supportedAlignments, validAlignments);
|
|
18015
|
-
if (unknownAlignments.length) {
|
|
18016
|
-
throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid value for supportedAlignments: " + unknownAlignments.join(" "), Errors.InvalidInput);
|
|
18017
|
-
}
|
|
18018
|
-
}
|
|
18019
|
-
});
|
|
18020
|
-
};
|
|
18021
|
-
|
|
18022
|
-
/**
|
|
18023
|
-
* Handling for static mode for widgets that support it.
|
|
18024
|
-
*/
|
|
18025
|
-
|
|
18026
|
-
/**
|
|
18027
|
-
* Returns true iff the widget supports static mode.
|
|
18028
|
-
* A widget implicitly supports static mode if it exports a
|
|
18029
|
-
* staticTransform function.
|
|
18030
|
-
*/
|
|
18031
|
-
const supportsStaticMode = type => {
|
|
18032
|
-
const widgetInfo = widgets[type];
|
|
18033
|
-
return widgetInfo && widgetInfo.staticTransform != null;
|
|
18034
|
-
};
|
|
18035
|
-
|
|
18036
|
-
/**
|
|
18037
|
-
* Return the staticTransform function used to convert the editorProps to
|
|
18038
|
-
* the rendered widget state.
|
|
18039
|
-
*/
|
|
18040
|
-
const getStaticTransform = type => {
|
|
18041
|
-
const widgetInfo = widgets[type];
|
|
18042
|
-
return widgetInfo && widgetInfo.staticTransform;
|
|
18043
|
-
};
|
|
18044
|
-
|
|
18045
|
-
/**
|
|
18046
|
-
* Returns the tracking option for the widget. The default is "",
|
|
18047
|
-
* which means simply to track interactions once. The other available
|
|
18048
|
-
* option is "all" which means to track all interactions.
|
|
18049
|
-
*/
|
|
18050
|
-
const getTracking = type => {
|
|
18051
|
-
const widgetExport = widgets[type];
|
|
18052
|
-
return widgetExport && widgetExport.tracking || DEFAULT_TRACKING;
|
|
18053
|
-
};
|
|
18054
|
-
|
|
18055
|
-
/**
|
|
18056
|
-
* Returns true if this widget can include lintable markdown text
|
|
18057
|
-
* and supports a highlightLint prop, or false otherwise.
|
|
18058
|
-
*/
|
|
18059
|
-
const isLintable = type => {
|
|
18060
|
-
const widgetExports = widgets[type];
|
|
18061
|
-
return widgetExports && widgetExports.isLintable || DEFAULT_LINTABLE;
|
|
18062
|
-
};
|
|
18063
|
-
|
|
18064
|
-
var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
18065
|
-
__proto__: null,
|
|
18066
|
-
registerWidget: registerWidget,
|
|
18067
|
-
registerWidgets: registerWidgets,
|
|
18068
|
-
replaceWidget: replaceWidget,
|
|
18069
|
-
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
18070
|
-
registerEditors: registerEditors,
|
|
18071
|
-
replaceEditor: replaceEditor,
|
|
18072
|
-
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
18073
|
-
getWidget: getWidget,
|
|
18074
|
-
getWidgetExport: getWidgetExport,
|
|
18075
|
-
getWidgetValidator: getWidgetValidator,
|
|
18076
|
-
getWidgetScorer: getWidgetScorer,
|
|
18077
|
-
getPublicWidgetOptionsFunction: getPublicWidgetOptionsFunction,
|
|
18078
|
-
getEditor: getEditor,
|
|
18079
|
-
getTransform: getTransform,
|
|
18080
|
-
getVersion: getVersion,
|
|
18081
|
-
getVersionVector: getVersionVector,
|
|
18082
|
-
getPublicWidgets: getPublicWidgets,
|
|
18083
|
-
isAccessible: isAccessible,
|
|
18084
|
-
getAllWidgetTypes: getAllWidgetTypes,
|
|
18085
|
-
upgradeWidgetInfoToLatestVersion: upgradeWidgetInfoToLatestVersion,
|
|
18086
|
-
getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
|
|
18087
|
-
traverseChildWidgets: traverseChildWidgets$3,
|
|
18088
|
-
getSupportedAlignments: getSupportedAlignments,
|
|
18089
|
-
getDefaultAlignment: getDefaultAlignment,
|
|
18090
|
-
validateAlignments: validateAlignments,
|
|
18091
|
-
supportsStaticMode: supportsStaticMode,
|
|
18092
|
-
getStaticTransform: getStaticTransform,
|
|
18093
|
-
getTracking: getTracking,
|
|
18094
|
-
isLintable: isLintable
|
|
18095
|
-
});
|
|
18096
|
-
|
|
18097
|
-
function getUpgradedWidgetOptions(oldWidgetOptions) {
|
|
18098
|
-
return mapObject(oldWidgetOptions, (widgetInfo, widgetId) => {
|
|
18099
|
-
if (!widgetInfo.type || !widgetInfo.alignment) {
|
|
18100
|
-
const newValues = {};
|
|
18101
|
-
if (!widgetInfo.type) {
|
|
18102
|
-
// TODO: why does widget have no type?
|
|
18103
|
-
// We don't want to derive type from widget ID
|
|
18104
|
-
// see: LEMS-1845
|
|
18105
|
-
newValues.type = widgetId.split(" ")[0];
|
|
18106
|
-
}
|
|
18107
|
-
if (!widgetInfo.alignment) {
|
|
18108
|
-
newValues.alignment = "default";
|
|
18109
|
-
}
|
|
18110
|
-
widgetInfo = _extends({}, widgetInfo, newValues);
|
|
18111
|
-
}
|
|
18112
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
18113
|
-
return upgradeWidgetInfoToLatestVersion(widgetInfo);
|
|
18114
|
-
});
|
|
18115
|
-
}
|
|
18116
|
-
|
|
18117
|
-
/**
|
|
18118
|
-
* Checks the given user input to see if any answerable widgets have not been
|
|
18119
|
-
* "filled in" (ie. if they're empty). Another way to think about this
|
|
18120
|
-
* function is that its a check to see if we can score the provided input.
|
|
18121
|
-
*/
|
|
18122
|
-
function emptyWidgetsFunctional(widgets,
|
|
18123
|
-
// This is a port of old code, I'm not sure why
|
|
18124
|
-
// we need widgetIds vs the keys of the widgets object
|
|
18125
|
-
widgetIds, userInputMap, strings, locale) {
|
|
18126
|
-
return widgetIds.filter(id => {
|
|
18127
|
-
const widget = widgets[id];
|
|
18128
|
-
if (!widget || widget.static === true) {
|
|
18129
|
-
// Static widgets shouldn't count as empty
|
|
18130
|
-
return false;
|
|
18131
|
-
}
|
|
18132
|
-
const validator = getWidgetValidator(widget.type);
|
|
18133
|
-
const userInput = userInputMap[id];
|
|
18134
|
-
const validationData = widget.options;
|
|
18135
|
-
const score = validator == null ? void 0 : validator(userInput, validationData, strings, locale);
|
|
18136
|
-
if (score) {
|
|
18137
|
-
return scoreIsEmpty(score);
|
|
18138
|
-
}
|
|
18139
|
-
});
|
|
18140
|
-
}
|
|
18141
|
-
|
|
18142
|
-
// TODO: combine scorePerseusItem with scoreWidgetsFunctional
|
|
18143
|
-
// once scorePerseusItem is the only one calling scoreWidgetsFunctional
|
|
18144
|
-
function scorePerseusItem(perseusRenderData, userInputMap,
|
|
18145
|
-
// TODO(LEMS-2461,LEMS-2391): these probably
|
|
18146
|
-
// need to be removed before we move this to the server
|
|
18147
|
-
strings, locale) {
|
|
18148
|
-
// There seems to be a chance that PerseusRenderer.widgets might include
|
|
18149
|
-
// widget data for widgets that are not in PerseusRenderer.content,
|
|
18150
|
-
// so this checks that the widgets are being used before scoring them
|
|
18151
|
-
const usedWidgetIds = getWidgetIdsFromContent(perseusRenderData.content);
|
|
18152
|
-
const scores = scoreWidgetsFunctional(perseusRenderData.widgets, usedWidgetIds, userInputMap, strings, locale);
|
|
18153
|
-
return flattenScores(scores);
|
|
18154
|
-
}
|
|
18155
|
-
function scoreWidgetsFunctional(widgets,
|
|
18156
|
-
// This is a port of old code, I'm not sure why
|
|
18157
|
-
// we need widgetIds vs the keys of the widgets object
|
|
18158
|
-
widgetIds, userInputMap, strings, locale) {
|
|
18159
|
-
const upgradedWidgets = getUpgradedWidgetOptions(widgets);
|
|
18160
|
-
const gradedWidgetIds = widgetIds.filter(id => {
|
|
18161
|
-
const props = upgradedWidgets[id];
|
|
18162
|
-
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
18163
|
-
const widgetIsStatic = !!(props != null && props.static);
|
|
18164
|
-
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
18165
|
-
return widgetIsGraded && !widgetIsStatic;
|
|
18166
|
-
});
|
|
18167
|
-
const widgetScores = {};
|
|
18168
|
-
gradedWidgetIds.forEach(id => {
|
|
18169
|
-
var _validator;
|
|
18170
|
-
const widget = upgradedWidgets[id];
|
|
18171
|
-
if (!widget) {
|
|
18172
|
-
return;
|
|
18173
|
-
}
|
|
18174
|
-
const userInput = userInputMap[id];
|
|
18175
|
-
const validator = getWidgetValidator(widget.type);
|
|
18176
|
-
const scorer = getWidgetScorer(widget.type);
|
|
18177
|
-
|
|
18178
|
-
// We do validation (empty checks) first and then scoring. If
|
|
18179
|
-
// validation fails, it's result is itself a PerseusScore.
|
|
18180
|
-
const score = (_validator = validator == null ? void 0 : validator(userInput, widget.options, strings, locale)) != null ? _validator : scorer == null ? void 0 : scorer(userInput, widget.options, strings, locale);
|
|
18181
|
-
if (score != null) {
|
|
18182
|
-
widgetScores[id] = score;
|
|
18183
|
-
}
|
|
18184
|
-
});
|
|
18185
|
-
return widgetScores;
|
|
18186
|
-
}
|
|
18187
|
-
|
|
18188
17322
|
/**
|
|
18189
17323
|
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
18190
17324
|
*
|
|
@@ -18341,6 +17475,261 @@ const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
|
18341
17475
|
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
18342
17476
|
};
|
|
18343
17477
|
|
|
17478
|
+
const DEFAULT_TRACKING = "";
|
|
17479
|
+
const DEFAULT_LINTABLE = false;
|
|
17480
|
+
const widgets = {};
|
|
17481
|
+
const editors = {};
|
|
17482
|
+
|
|
17483
|
+
// Widgets must be registered to avoid circular dependencies with the
|
|
17484
|
+
// core Editor and Renderer components.
|
|
17485
|
+
// TODO(jeremy): The widget name is already embedded in the WidgetExports type
|
|
17486
|
+
// so could we drop the `name` parameter here?
|
|
17487
|
+
const registerWidget = (name, widget) => {
|
|
17488
|
+
widgets[name] = widget;
|
|
17489
|
+
};
|
|
17490
|
+
const registerWidgets = widgets => {
|
|
17491
|
+
widgets.forEach(widget => {
|
|
17492
|
+
registerWidget(widget.name, widget);
|
|
17493
|
+
});
|
|
17494
|
+
};
|
|
17495
|
+
|
|
17496
|
+
/**
|
|
17497
|
+
*
|
|
17498
|
+
* @param name - the widget that you are trying to replace
|
|
17499
|
+
* @param replacementName - the name of the widget that takes its place
|
|
17500
|
+
*
|
|
17501
|
+
* e.g. replaceWidget("transformer", "deprecated-standin") will make it so the
|
|
17502
|
+
* transformer widget is replaced by the always correct widget
|
|
17503
|
+
*/
|
|
17504
|
+
const replaceWidget = (name, replacementName) => {
|
|
17505
|
+
const substituteWidget = widgets[replacementName];
|
|
17506
|
+
|
|
17507
|
+
// If the replacement widget isn't found, we need to throw. Otherwise after
|
|
17508
|
+
// removing the deprecated widget, we'll have data asking for a widget type
|
|
17509
|
+
// that doesn't exist at all.
|
|
17510
|
+
if (!substituteWidget) {
|
|
17511
|
+
const errorMsg = `Failed to replace ${name} with ${replacementName}`;
|
|
17512
|
+
throw new PerseusError(errorMsg, Errors.Internal);
|
|
17513
|
+
}
|
|
17514
|
+
registerWidget(name, substituteWidget);
|
|
17515
|
+
};
|
|
17516
|
+
const replaceDeprecatedWidgets = () => {
|
|
17517
|
+
replaceWidget("transformer", "deprecated-standin");
|
|
17518
|
+
replaceWidget("lights-puzzle", "deprecated-standin");
|
|
17519
|
+
replaceWidget("reaction-diagram", "deprecated-standin");
|
|
17520
|
+
replaceWidget("sequence", "deprecated-standin");
|
|
17521
|
+
replaceWidget("simulator", "deprecated-standin");
|
|
17522
|
+
replaceWidget("unit-input", "deprecated-standin");
|
|
17523
|
+
};
|
|
17524
|
+
const registerEditors = editorsToRegister => {
|
|
17525
|
+
editorsToRegister.forEach(editor => {
|
|
17526
|
+
if (!editor.widgetName) {
|
|
17527
|
+
throw new PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, Errors.Internal);
|
|
17528
|
+
}
|
|
17529
|
+
editors[editor.widgetName] = editor;
|
|
17530
|
+
});
|
|
17531
|
+
};
|
|
17532
|
+
|
|
17533
|
+
/**
|
|
17534
|
+
*
|
|
17535
|
+
* @param name - the widget that you are trying to replace
|
|
17536
|
+
* @param replacementName - the name of the widget that takes its place
|
|
17537
|
+
*
|
|
17538
|
+
* e.g. replaceEditor("transformer", "deprecated-standin") will make it so the
|
|
17539
|
+
* transformer widget is replaced by the deprecated stand-in widget
|
|
17540
|
+
*/
|
|
17541
|
+
const replaceEditor = (name, replacementName) => {
|
|
17542
|
+
const substituteEditor = editors[replacementName];
|
|
17543
|
+
if (!substituteEditor && Log) {
|
|
17544
|
+
const errorMsg = `Failed to replace editor ${name} with ${replacementName}`;
|
|
17545
|
+
Log.error(errorMsg, Errors.Internal);
|
|
17546
|
+
return;
|
|
17547
|
+
}
|
|
17548
|
+
editors[name] = substituteEditor;
|
|
17549
|
+
};
|
|
17550
|
+
const replaceDeprecatedEditors = () => {
|
|
17551
|
+
replaceEditor("transformer", "deprecated-standin");
|
|
17552
|
+
replaceEditor("lights-puzzle", "deprecated-standin");
|
|
17553
|
+
replaceEditor("reaction-diagram", "deprecated-standin");
|
|
17554
|
+
replaceEditor("sequence", "deprecated-standin");
|
|
17555
|
+
replaceEditor("simulator", "deprecated-standin");
|
|
17556
|
+
replaceEditor("unit-input", "deprecated-standin");
|
|
17557
|
+
};
|
|
17558
|
+
const getWidget = name => {
|
|
17559
|
+
var _widgets$name;
|
|
17560
|
+
// TODO(alex): Consider referring to these as renderers to avoid
|
|
17561
|
+
// overloading "widget"
|
|
17562
|
+
if (!_.has(widgets, name)) {
|
|
17563
|
+
return null;
|
|
17564
|
+
}
|
|
17565
|
+
|
|
17566
|
+
// Allow widgets to specify a widget directly or via a function
|
|
17567
|
+
if ((_widgets$name = widgets[name]) != null && _widgets$name.getWidget) {
|
|
17568
|
+
var _widgets$name$getWidg, _widgets$name2;
|
|
17569
|
+
return (_widgets$name$getWidg = (_widgets$name2 = widgets[name]).getWidget) == null ? void 0 : _widgets$name$getWidg.call(_widgets$name2);
|
|
17570
|
+
}
|
|
17571
|
+
return widgets[name].widget;
|
|
17572
|
+
};
|
|
17573
|
+
const getWidgetExport = name => {
|
|
17574
|
+
var _widgets$name3;
|
|
17575
|
+
return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
|
|
17576
|
+
};
|
|
17577
|
+
const getPublicWidgetOptionsFunction = name => {
|
|
17578
|
+
var _widgets$name$getPubl, _widgets$name4;
|
|
17579
|
+
return (_widgets$name$getPubl = (_widgets$name4 = widgets[name]) == null ? void 0 : _widgets$name4.getPublicWidgetOptions) != null ? _widgets$name$getPubl : i => i;
|
|
17580
|
+
};
|
|
17581
|
+
const getEditor = name => {
|
|
17582
|
+
return _.has(editors, name) ? editors[name] : null;
|
|
17583
|
+
};
|
|
17584
|
+
const getTransform = name => {
|
|
17585
|
+
return _.has(widgets, name) ? widgets[name].transform || _.identity : null;
|
|
17586
|
+
};
|
|
17587
|
+
const getVersion = name => {
|
|
17588
|
+
const widgetInfo = widgets[name];
|
|
17589
|
+
if (widgetInfo) {
|
|
17590
|
+
return widgets[name].version || {
|
|
17591
|
+
major: 0,
|
|
17592
|
+
minor: 0
|
|
17593
|
+
};
|
|
17594
|
+
}
|
|
17595
|
+
return;
|
|
17596
|
+
};
|
|
17597
|
+
const getVersionVector = () => {
|
|
17598
|
+
const version = {};
|
|
17599
|
+
_.each(_.keys(widgets), function (name) {
|
|
17600
|
+
version[name] = getVersion(name);
|
|
17601
|
+
});
|
|
17602
|
+
return version;
|
|
17603
|
+
};
|
|
17604
|
+
const getPublicWidgets = () => {
|
|
17605
|
+
// TODO(alex): Update underscore.js so that _.pick can take a function.
|
|
17606
|
+
// @ts-expect-error - TS2740 - Type 'Pick<{ [key: string]: Readonly<{ name: string; displayName: string; getWidget?: (() => ComponentType<any>) | undefined; accessible?: boolean | ((props: any) => boolean) | undefined; hidden?: boolean | undefined; ... 10 more ...; widget: ComponentType<...>; }>; }, string>' is missing the following properties from type 'readonly Readonly<{ name: string; displayName: string; getWidget?: (() => ComponentType<any>) | undefined; accessible?: boolean | ((props: any) => boolean) | undefined; hidden?: boolean | undefined; ... 10 more ...; widget: ComponentType<...>; }>[]': length, concat, join, slice, and 18 more.
|
|
17607
|
+
return _.pick(widgets,
|
|
17608
|
+
// @ts-expect-error - TS2345 - Argument of type '(name: string) => boolean | undefined' is not assignable to parameter of type 'Iteratee<string[], boolean, string>'.
|
|
17609
|
+
_.reject(_.keys(widgets), function (name) {
|
|
17610
|
+
return widgets[name].hidden;
|
|
17611
|
+
}));
|
|
17612
|
+
};
|
|
17613
|
+
const isAccessible = widgetInfo => {
|
|
17614
|
+
const accessible = widgets[widgetInfo.type].accessible;
|
|
17615
|
+
if (typeof accessible === "function") {
|
|
17616
|
+
return accessible(widgetInfo.options);
|
|
17617
|
+
}
|
|
17618
|
+
return !!accessible;
|
|
17619
|
+
};
|
|
17620
|
+
const getAllWidgetTypes = () => {
|
|
17621
|
+
return _.keys(widgets);
|
|
17622
|
+
};
|
|
17623
|
+
const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
17624
|
+
const type = widgetInfo.type;
|
|
17625
|
+
const widgetExports = widgets[type];
|
|
17626
|
+
if (widgetExports == null) {
|
|
17627
|
+
// The widget is not a registered widget
|
|
17628
|
+
// It shouldn't matter what we return here, but for consistency
|
|
17629
|
+
// we return the untransformed options, as if the widget did
|
|
17630
|
+
// not have a transform defined.
|
|
17631
|
+
return widgetInfo;
|
|
17632
|
+
}
|
|
17633
|
+
let transform;
|
|
17634
|
+
if (widgetInfo.static) {
|
|
17635
|
+
// There aren't a lot of real places where we'll have to default to
|
|
17636
|
+
// _.identity, but it's theoretically possible if someone changes
|
|
17637
|
+
// the JSON manually / we have to back out static support for a
|
|
17638
|
+
// widget.
|
|
17639
|
+
transform = getStaticTransform(type) || _.identity;
|
|
17640
|
+
} else {
|
|
17641
|
+
transform = widgetExports.transform || _.identity;
|
|
17642
|
+
}
|
|
17643
|
+
// widgetInfo.options are the widgetEditor's props:
|
|
17644
|
+
return transform(widgetInfo.options, strings, problemNum);
|
|
17645
|
+
};
|
|
17646
|
+
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
17647
|
+
if (!traverseRenderer) {
|
|
17648
|
+
throw new PerseusError("traverseRenderer must be provided, but was not", Errors.Internal);
|
|
17649
|
+
}
|
|
17650
|
+
if (!widgetInfo || !widgetInfo.type || !widgets[widgetInfo.type]) {
|
|
17651
|
+
return widgetInfo;
|
|
17652
|
+
}
|
|
17653
|
+
const widgetExports = widgets[widgetInfo.type];
|
|
17654
|
+
const props = widgetInfo.options;
|
|
17655
|
+
if (widgetExports.traverseChildWidgets && props) {
|
|
17656
|
+
const newProps = widgetExports.traverseChildWidgets(props, traverseRenderer);
|
|
17657
|
+
return _.extend({}, widgetInfo, {
|
|
17658
|
+
options: newProps
|
|
17659
|
+
});
|
|
17660
|
+
}
|
|
17661
|
+
return widgetInfo;
|
|
17662
|
+
};
|
|
17663
|
+
|
|
17664
|
+
/**
|
|
17665
|
+
* Handling for static mode for widgets that support it.
|
|
17666
|
+
*/
|
|
17667
|
+
|
|
17668
|
+
/**
|
|
17669
|
+
* Returns true iff the widget supports static mode.
|
|
17670
|
+
* A widget implicitly supports static mode if it exports a
|
|
17671
|
+
* staticTransform function.
|
|
17672
|
+
*/
|
|
17673
|
+
const supportsStaticMode = type => {
|
|
17674
|
+
const widgetInfo = widgets[type];
|
|
17675
|
+
return widgetInfo && widgetInfo.staticTransform != null;
|
|
17676
|
+
};
|
|
17677
|
+
|
|
17678
|
+
/**
|
|
17679
|
+
* Return the staticTransform function used to convert the editorProps to
|
|
17680
|
+
* the rendered widget state.
|
|
17681
|
+
*/
|
|
17682
|
+
const getStaticTransform = type => {
|
|
17683
|
+
const widgetInfo = widgets[type];
|
|
17684
|
+
return widgetInfo && widgetInfo.staticTransform;
|
|
17685
|
+
};
|
|
17686
|
+
|
|
17687
|
+
/**
|
|
17688
|
+
* Returns the tracking option for the widget. The default is "",
|
|
17689
|
+
* which means simply to track interactions once. The other available
|
|
17690
|
+
* option is "all" which means to track all interactions.
|
|
17691
|
+
*/
|
|
17692
|
+
const getTracking = type => {
|
|
17693
|
+
const widgetExport = widgets[type];
|
|
17694
|
+
return widgetExport && widgetExport.tracking || DEFAULT_TRACKING;
|
|
17695
|
+
};
|
|
17696
|
+
|
|
17697
|
+
/**
|
|
17698
|
+
* Returns true if this widget can include lintable markdown text
|
|
17699
|
+
* and supports a highlightLint prop, or false otherwise.
|
|
17700
|
+
*/
|
|
17701
|
+
const isLintable = type => {
|
|
17702
|
+
const widgetExports = widgets[type];
|
|
17703
|
+
return widgetExports && widgetExports.isLintable || DEFAULT_LINTABLE;
|
|
17704
|
+
};
|
|
17705
|
+
|
|
17706
|
+
var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
17707
|
+
__proto__: null,
|
|
17708
|
+
registerWidget: registerWidget,
|
|
17709
|
+
registerWidgets: registerWidgets,
|
|
17710
|
+
replaceWidget: replaceWidget,
|
|
17711
|
+
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
17712
|
+
registerEditors: registerEditors,
|
|
17713
|
+
replaceEditor: replaceEditor,
|
|
17714
|
+
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
17715
|
+
getWidget: getWidget,
|
|
17716
|
+
getWidgetExport: getWidgetExport,
|
|
17717
|
+
getPublicWidgetOptionsFunction: getPublicWidgetOptionsFunction,
|
|
17718
|
+
getEditor: getEditor,
|
|
17719
|
+
getTransform: getTransform,
|
|
17720
|
+
getVersion: getVersion,
|
|
17721
|
+
getVersionVector: getVersionVector,
|
|
17722
|
+
getPublicWidgets: getPublicWidgets,
|
|
17723
|
+
isAccessible: isAccessible,
|
|
17724
|
+
getAllWidgetTypes: getAllWidgetTypes,
|
|
17725
|
+
getRendererPropsForWidgetInfo: getRendererPropsForWidgetInfo,
|
|
17726
|
+
traverseChildWidgets: traverseChildWidgets$3,
|
|
17727
|
+
supportsStaticMode: supportsStaticMode,
|
|
17728
|
+
getStaticTransform: getStaticTransform,
|
|
17729
|
+
getTracking: getTracking,
|
|
17730
|
+
isLintable: isLintable
|
|
17731
|
+
});
|
|
17732
|
+
|
|
18344
17733
|
class WidgetContainer extends React.Component {
|
|
18345
17734
|
constructor(...args) {
|
|
18346
17735
|
super(...args);
|
|
@@ -18413,7 +17802,7 @@ class WidgetContainer extends React.Component {
|
|
|
18413
17802
|
}
|
|
18414
17803
|
let alignment = this.state.widgetProps.alignment;
|
|
18415
17804
|
if (alignment === "default") {
|
|
18416
|
-
alignment = getDefaultAlignment(type);
|
|
17805
|
+
alignment = CoreWidgetRegistry.getDefaultAlignment(type);
|
|
18417
17806
|
}
|
|
18418
17807
|
className += " widget-" + alignment;
|
|
18419
17808
|
const apiOptions = this.state.widgetProps.apiOptions;
|
|
@@ -18421,6 +17810,7 @@ class WidgetContainer extends React.Component {
|
|
|
18421
17810
|
// Hack to prevent interaction with static widgets: we overlay a big
|
|
18422
17811
|
// div on top of the widget and overflow: hidden the container.
|
|
18423
17812
|
// Ideally widgets themselves should know how to prevent interaction.
|
|
17813
|
+
// UPDATE HTML5: `inert` on the underlying div would be better
|
|
18424
17814
|
const isStatic = this.state.widgetProps.static || apiOptions.readOnly;
|
|
18425
17815
|
const staticContainerStyles = {
|
|
18426
17816
|
position: "relative",
|
|
@@ -18432,7 +17822,7 @@ class WidgetContainer extends React.Component {
|
|
|
18432
17822
|
position: "absolute",
|
|
18433
17823
|
top: 0,
|
|
18434
17824
|
left: 0,
|
|
18435
|
-
zIndex:
|
|
17825
|
+
zIndex: 3
|
|
18436
17826
|
};
|
|
18437
17827
|
|
|
18438
17828
|
// Some widgets may include strings of markdown that we may
|
|
@@ -19616,7 +19006,7 @@ class Renderer extends React.Component {
|
|
|
19616
19006
|
* empty if the graph is in the starting state.
|
|
19617
19007
|
*/
|
|
19618
19008
|
emptyWidgets() {
|
|
19619
|
-
return emptyWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.
|
|
19009
|
+
return emptyWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.context.locale);
|
|
19620
19010
|
}
|
|
19621
19011
|
/**
|
|
19622
19012
|
* Returns an array of the widget `.getUserInput()` results
|
|
@@ -19676,7 +19066,7 @@ class Renderer extends React.Component {
|
|
|
19676
19066
|
* @deprecated use scorePerseusItem
|
|
19677
19067
|
*/
|
|
19678
19068
|
score() {
|
|
19679
|
-
const scores = scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.
|
|
19069
|
+
const scores = scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.context.locale);
|
|
19680
19070
|
const combinedScore = flattenScores(scores);
|
|
19681
19071
|
return combinedScore;
|
|
19682
19072
|
}
|
|
@@ -20216,7 +19606,7 @@ class InputWithExamples extends React.Component {
|
|
|
20216
19606
|
};
|
|
20217
19607
|
this._getInputClassName = () => {
|
|
20218
19608
|
// Otherwise, we need to add these INPUT and FOCUSED tags here.
|
|
20219
|
-
let className = ClassNames.INPUT
|
|
19609
|
+
let className = ClassNames.INPUT;
|
|
20220
19610
|
if (this.state.focused) {
|
|
20221
19611
|
className += " " + ClassNames.FOCUSED;
|
|
20222
19612
|
}
|
|
@@ -20628,14 +20018,10 @@ const propTransform$3 = widgetOptions => {
|
|
|
20628
20018
|
var InputNumber$1 = {
|
|
20629
20019
|
name: "input-number",
|
|
20630
20020
|
displayName: "Input number (deprecated - use numeric input instead)",
|
|
20631
|
-
defaultAlignment: "inline-block",
|
|
20632
20021
|
hidden: true,
|
|
20633
20022
|
widget: InputNumber,
|
|
20634
20023
|
transform: propTransform$3,
|
|
20635
20024
|
isLintable: true,
|
|
20636
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
20637
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusInputNumberUserInput'.
|
|
20638
|
-
scorer: scoreInputNumber,
|
|
20639
20025
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
20640
20026
|
if (rubric.value == null) {
|
|
20641
20027
|
return;
|
|
@@ -20892,14 +20278,11 @@ const propsTransform = function propsTransform(widgetOptions) {
|
|
|
20892
20278
|
var NumericInput$1 = {
|
|
20893
20279
|
name: "numeric-input",
|
|
20894
20280
|
displayName: "Numeric input",
|
|
20895
|
-
defaultAlignment: "inline-block",
|
|
20896
20281
|
accessible: true,
|
|
20897
20282
|
widget: NumericInput,
|
|
20898
20283
|
transform: propsTransform,
|
|
20899
20284
|
isLintable: true,
|
|
20900
|
-
|
|
20901
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusNumericInputUserInput'.
|
|
20902
|
-
scorer: scoreNumericInput,
|
|
20285
|
+
getPublicWidgetOptions: getNumericInputPublicWidgetOptions,
|
|
20903
20286
|
// TODO(LEMS-2656): remove TS suppression
|
|
20904
20287
|
// @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusNumericInputRubric'
|
|
20905
20288
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
@@ -20960,23 +20343,6 @@ const getPromptJSON$p = renderProps => {
|
|
|
20960
20343
|
};
|
|
20961
20344
|
};
|
|
20962
20345
|
|
|
20963
|
-
/**
|
|
20964
|
-
* Several widgets don't have "right"/"wrong" scoring logic,
|
|
20965
|
-
* so this just says to move on past those widgets
|
|
20966
|
-
*
|
|
20967
|
-
* TODO(LEMS-2543) widgets that use this probably shouldn't have any
|
|
20968
|
-
* scoring logic and the thing scoring an exercise
|
|
20969
|
-
* should just know to skip these
|
|
20970
|
-
*/
|
|
20971
|
-
function scoreNoop(points = 0) {
|
|
20972
|
-
return {
|
|
20973
|
-
type: "points",
|
|
20974
|
-
earned: points,
|
|
20975
|
-
total: points,
|
|
20976
|
-
message: null
|
|
20977
|
-
};
|
|
20978
|
-
}
|
|
20979
|
-
|
|
20980
20346
|
/**
|
|
20981
20347
|
* Utility functions for manipulating ranges of highlightable content.
|
|
20982
20348
|
*/
|
|
@@ -23152,8 +22518,7 @@ var Passage$1 = {
|
|
|
23152
22518
|
transform: editorProps => {
|
|
23153
22519
|
return _.pick(editorProps, "passageTitle", "passageText", "footnotes", "showLineNumbers");
|
|
23154
22520
|
},
|
|
23155
|
-
isLintable: true
|
|
23156
|
-
scorer: () => scoreNoop()
|
|
22521
|
+
isLintable: true
|
|
23157
22522
|
};
|
|
23158
22523
|
|
|
23159
22524
|
/**
|
|
@@ -23275,16 +22640,13 @@ var PassageRef$1 = {
|
|
|
23275
22640
|
name: "passage-ref",
|
|
23276
22641
|
displayName: "PassageRef (SAT only)",
|
|
23277
22642
|
hidden: true,
|
|
23278
|
-
defaultAlignment: "inline",
|
|
23279
22643
|
widget: PassageRef,
|
|
23280
22644
|
transform: widgetOptions => ({
|
|
23281
22645
|
passageNumber: widgetOptions.passageNumber,
|
|
23282
22646
|
referenceNumber: widgetOptions.referenceNumber,
|
|
23283
22647
|
summaryText: widgetOptions.summaryText
|
|
23284
22648
|
}),
|
|
23285
|
-
version: passageRefLogic.version
|
|
23286
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
23287
|
-
scorer: () => scoreNoop()
|
|
22649
|
+
version: passageRefLogic.version
|
|
23288
22650
|
};
|
|
23289
22651
|
|
|
23290
22652
|
/**
|
|
@@ -23326,109 +22688,6 @@ var mediaQueries = {
|
|
|
23326
22688
|
xlOrLarger: `@media screen and (min-width: ${pureXlMin})`
|
|
23327
22689
|
};
|
|
23328
22690
|
|
|
23329
|
-
const {
|
|
23330
|
-
zIndexAboveScratchpad,
|
|
23331
|
-
zIndexInteractiveComponent,
|
|
23332
|
-
radioBorderColor,
|
|
23333
|
-
checkedColor,
|
|
23334
|
-
circleSize,
|
|
23335
|
-
radioMarginWidth
|
|
23336
|
-
} = constants;
|
|
23337
|
-
var sharedStyles = StyleSheet.create({
|
|
23338
|
-
perseusInteractive: {
|
|
23339
|
-
zIndex: zIndexInteractiveComponent,
|
|
23340
|
-
position: "relative"
|
|
23341
|
-
},
|
|
23342
|
-
aboveScratchpad: {
|
|
23343
|
-
position: "relative",
|
|
23344
|
-
zIndex: zIndexAboveScratchpad
|
|
23345
|
-
},
|
|
23346
|
-
blankBackground: {
|
|
23347
|
-
// TODO(emily): Use WB colors?
|
|
23348
|
-
backgroundColor: "#FDFDFD"
|
|
23349
|
-
},
|
|
23350
|
-
perseusSrOnly: {
|
|
23351
|
-
border: 0,
|
|
23352
|
-
clip: "rect(0,0,0,0)",
|
|
23353
|
-
height: 1,
|
|
23354
|
-
margin: -1,
|
|
23355
|
-
overflow: "hidden",
|
|
23356
|
-
padding: 0,
|
|
23357
|
-
position: "absolute",
|
|
23358
|
-
width: 1
|
|
23359
|
-
},
|
|
23360
|
-
responsiveLabel: {
|
|
23361
|
-
// NOTE(charlie): The values used here should be kept in sync with the
|
|
23362
|
-
// caption text sizing in Perseus' styles.less.
|
|
23363
|
-
// TODO(charlie): Migrate the captions over to using this style.
|
|
23364
|
-
[mediaQueries.smOrSmaller]: {
|
|
23365
|
-
fontSize: 14,
|
|
23366
|
-
lineHeight: 1.3
|
|
23367
|
-
},
|
|
23368
|
-
[mediaQueries.md]: {
|
|
23369
|
-
fontSize: 17,
|
|
23370
|
-
lineHeight: 1.4
|
|
23371
|
-
},
|
|
23372
|
-
[mediaQueries.lgOrLarger]: {
|
|
23373
|
-
fontSize: 20,
|
|
23374
|
-
lineHeight: 1.4
|
|
23375
|
-
}
|
|
23376
|
-
},
|
|
23377
|
-
responsiveInput: {
|
|
23378
|
-
display: "inline-block",
|
|
23379
|
-
WebkitAppearance: "none",
|
|
23380
|
-
appearance: "none",
|
|
23381
|
-
"::-ms-check": {
|
|
23382
|
-
display: "none"
|
|
23383
|
-
},
|
|
23384
|
-
backgroundColor: "#fff",
|
|
23385
|
-
border: "2px solid #fff",
|
|
23386
|
-
boxShadow: `0 0px 0px 1px ${radioBorderColor}`,
|
|
23387
|
-
outline: "none",
|
|
23388
|
-
boxSizing: "border-box",
|
|
23389
|
-
flexShrink: 0,
|
|
23390
|
-
marginBottom: 1,
|
|
23391
|
-
marginLeft: 1,
|
|
23392
|
-
marginRight: 1,
|
|
23393
|
-
marginTop: 1,
|
|
23394
|
-
height: circleSize - 2,
|
|
23395
|
-
width: circleSize - 2
|
|
23396
|
-
},
|
|
23397
|
-
responsiveRadioInput: {
|
|
23398
|
-
borderRadius: "50%",
|
|
23399
|
-
":checked": {
|
|
23400
|
-
backgroundColor: checkedColor,
|
|
23401
|
-
border: "none",
|
|
23402
|
-
borderRadius: "50%",
|
|
23403
|
-
boxShadow: `inset 0px 0px 0px 2px white, ` + `0 0px 0px 2px ${checkedColor}`,
|
|
23404
|
-
marginTop: radioMarginWidth,
|
|
23405
|
-
marginBottom: radioMarginWidth,
|
|
23406
|
-
marginLeft: radioMarginWidth,
|
|
23407
|
-
marginRight: radioMarginWidth,
|
|
23408
|
-
height: circleSize - 2 * radioMarginWidth,
|
|
23409
|
-
width: circleSize - 2 * radioMarginWidth
|
|
23410
|
-
}
|
|
23411
|
-
},
|
|
23412
|
-
responsiveRadioInputActive: {
|
|
23413
|
-
backgroundColor: "#fff",
|
|
23414
|
-
border: "2px solid #fff",
|
|
23415
|
-
borderRadius: "50%",
|
|
23416
|
-
boxShadow: `0 0px 0px 2px ${checkedColor}`,
|
|
23417
|
-
marginTop: radioMarginWidth,
|
|
23418
|
-
marginBottom: radioMarginWidth,
|
|
23419
|
-
marginLeft: radioMarginWidth,
|
|
23420
|
-
marginRight: radioMarginWidth,
|
|
23421
|
-
height: circleSize - 2 * radioMarginWidth,
|
|
23422
|
-
width: circleSize - 2 * radioMarginWidth,
|
|
23423
|
-
":checked": {
|
|
23424
|
-
backgroundColor: "#fff"
|
|
23425
|
-
}
|
|
23426
|
-
},
|
|
23427
|
-
disableTextSelection: {
|
|
23428
|
-
userSelect: "none"
|
|
23429
|
-
}
|
|
23430
|
-
});
|
|
23431
|
-
|
|
23432
22691
|
/**
|
|
23433
22692
|
* A small collection of useful scrolling utility functions.
|
|
23434
22693
|
*/
|
|
@@ -24487,7 +23746,7 @@ const BaseRadio = function BaseRadio({
|
|
|
24487
23746
|
const aphroditeClassName = checked => {
|
|
24488
23747
|
// Whether or not to show correctness borders
|
|
24489
23748
|
// for this choice and the next choice.
|
|
24490
|
-
return css(
|
|
23749
|
+
return css(styles$o.item, styles$o.responsiveItem, checked && styles$o.selectedItem, checked && choice.highlighted && styles$o.aboveBackdrop, checked && choice.highlighted && apiOptions.isMobile && styles$o.aboveBackdropMobile, nextChoiceHighlighted && apiOptions.isMobile && styles$o.nextHighlighted);
|
|
24491
23750
|
};
|
|
24492
23751
|
|
|
24493
23752
|
// HACK(abdulrahman): Preloads the selection-state
|
|
@@ -25076,18 +24335,105 @@ var Radio = {
|
|
|
25076
24335
|
staticTransform: transform,
|
|
25077
24336
|
version: radioLogic.version,
|
|
25078
24337
|
propUpgrades: radioLogic.widgetOptionsUpgrades,
|
|
25079
|
-
isLintable: true
|
|
25080
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
25081
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusRadioUserInput
|
|
25082
|
-
scorer: scoreRadio,
|
|
25083
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
25084
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusRadioUserInput
|
|
25085
|
-
validator: validateRadio
|
|
24338
|
+
isLintable: true
|
|
25086
24339
|
};
|
|
25087
24340
|
|
|
25088
24341
|
/* eslint-disable import/no-named-as-default */
|
|
25089
24342
|
var basicWidgets = [Radio, InputNumber$1, NumericInput$1, Expression$1];
|
|
25090
24343
|
|
|
24344
|
+
const {
|
|
24345
|
+
radioBorderColor,
|
|
24346
|
+
checkedColor,
|
|
24347
|
+
circleSize,
|
|
24348
|
+
radioMarginWidth
|
|
24349
|
+
} = constants;
|
|
24350
|
+
var sharedStyles = StyleSheet.create({
|
|
24351
|
+
blankBackground: {
|
|
24352
|
+
// TODO(emily): Use WB colors?
|
|
24353
|
+
backgroundColor: "#FDFDFD"
|
|
24354
|
+
},
|
|
24355
|
+
perseusSrOnly: {
|
|
24356
|
+
border: 0,
|
|
24357
|
+
clip: "rect(0,0,0,0)",
|
|
24358
|
+
height: 1,
|
|
24359
|
+
margin: -1,
|
|
24360
|
+
overflow: "hidden",
|
|
24361
|
+
padding: 0,
|
|
24362
|
+
position: "absolute",
|
|
24363
|
+
width: 1
|
|
24364
|
+
},
|
|
24365
|
+
responsiveLabel: {
|
|
24366
|
+
// NOTE(charlie): The values used here should be kept in sync with the
|
|
24367
|
+
// caption text sizing in Perseus' styles.less.
|
|
24368
|
+
// TODO(charlie): Migrate the captions over to using this style.
|
|
24369
|
+
[mediaQueries.smOrSmaller]: {
|
|
24370
|
+
fontSize: 14,
|
|
24371
|
+
lineHeight: 1.3
|
|
24372
|
+
},
|
|
24373
|
+
[mediaQueries.md]: {
|
|
24374
|
+
fontSize: 17,
|
|
24375
|
+
lineHeight: 1.4
|
|
24376
|
+
},
|
|
24377
|
+
[mediaQueries.lgOrLarger]: {
|
|
24378
|
+
fontSize: 20,
|
|
24379
|
+
lineHeight: 1.4
|
|
24380
|
+
}
|
|
24381
|
+
},
|
|
24382
|
+
responsiveInput: {
|
|
24383
|
+
display: "inline-block",
|
|
24384
|
+
WebkitAppearance: "none",
|
|
24385
|
+
appearance: "none",
|
|
24386
|
+
"::-ms-check": {
|
|
24387
|
+
display: "none"
|
|
24388
|
+
},
|
|
24389
|
+
backgroundColor: "#fff",
|
|
24390
|
+
border: "2px solid #fff",
|
|
24391
|
+
boxShadow: `0 0px 0px 1px ${radioBorderColor}`,
|
|
24392
|
+
outline: "none",
|
|
24393
|
+
boxSizing: "border-box",
|
|
24394
|
+
flexShrink: 0,
|
|
24395
|
+
marginBottom: 1,
|
|
24396
|
+
marginLeft: 1,
|
|
24397
|
+
marginRight: 1,
|
|
24398
|
+
marginTop: 1,
|
|
24399
|
+
height: circleSize - 2,
|
|
24400
|
+
width: circleSize - 2
|
|
24401
|
+
},
|
|
24402
|
+
responsiveRadioInput: {
|
|
24403
|
+
borderRadius: "50%",
|
|
24404
|
+
":checked": {
|
|
24405
|
+
backgroundColor: checkedColor,
|
|
24406
|
+
border: "none",
|
|
24407
|
+
borderRadius: "50%",
|
|
24408
|
+
boxShadow: `inset 0px 0px 0px 2px white, ` + `0 0px 0px 2px ${checkedColor}`,
|
|
24409
|
+
marginTop: radioMarginWidth,
|
|
24410
|
+
marginBottom: radioMarginWidth,
|
|
24411
|
+
marginLeft: radioMarginWidth,
|
|
24412
|
+
marginRight: radioMarginWidth,
|
|
24413
|
+
height: circleSize - 2 * radioMarginWidth,
|
|
24414
|
+
width: circleSize - 2 * radioMarginWidth
|
|
24415
|
+
}
|
|
24416
|
+
},
|
|
24417
|
+
responsiveRadioInputActive: {
|
|
24418
|
+
backgroundColor: "#fff",
|
|
24419
|
+
border: "2px solid #fff",
|
|
24420
|
+
borderRadius: "50%",
|
|
24421
|
+
boxShadow: `0 0px 0px 2px ${checkedColor}`,
|
|
24422
|
+
marginTop: radioMarginWidth,
|
|
24423
|
+
marginBottom: radioMarginWidth,
|
|
24424
|
+
marginLeft: radioMarginWidth,
|
|
24425
|
+
marginRight: radioMarginWidth,
|
|
24426
|
+
height: circleSize - 2 * radioMarginWidth,
|
|
24427
|
+
width: circleSize - 2 * radioMarginWidth,
|
|
24428
|
+
":checked": {
|
|
24429
|
+
backgroundColor: "#fff"
|
|
24430
|
+
}
|
|
24431
|
+
},
|
|
24432
|
+
disableTextSelection: {
|
|
24433
|
+
userSelect: "none"
|
|
24434
|
+
}
|
|
24435
|
+
});
|
|
24436
|
+
|
|
25091
24437
|
const getPromptJSON$n = (renderProps, userInput) => {
|
|
25092
24438
|
return {
|
|
25093
24439
|
type: "categorizer",
|
|
@@ -25178,7 +24524,6 @@ class Categorizer extends React.Component {
|
|
|
25178
24524
|
className: "category " + css(styles$n.cell),
|
|
25179
24525
|
key: catNum
|
|
25180
24526
|
}, /*#__PURE__*/React.createElement("div", {
|
|
25181
|
-
className: ClassNames.INTERACTIVE,
|
|
25182
24527
|
role: "button",
|
|
25183
24528
|
"aria-label": catName,
|
|
25184
24529
|
onClick: () => this.onChange(itemNum, catNum)
|
|
@@ -25277,12 +24622,6 @@ var Categorizer$1 = {
|
|
|
25277
24622
|
return _.pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
25278
24623
|
},
|
|
25279
24624
|
isLintable: true,
|
|
25280
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
25281
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
|
|
25282
|
-
scorer: scoreCategorizer,
|
|
25283
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
25284
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
|
|
25285
|
-
validator: validateCategorizer,
|
|
25286
24625
|
getPublicWidgetOptions: getCategorizerPublicWidgetOptions
|
|
25287
24626
|
};
|
|
25288
24627
|
|
|
@@ -25488,12 +24827,9 @@ const styles$m = StyleSheet.create({
|
|
|
25488
24827
|
var CSProgram$1 = {
|
|
25489
24828
|
name: "cs-program",
|
|
25490
24829
|
displayName: "CS Program",
|
|
25491
|
-
supportedAlignments: ["block", "full-width"],
|
|
25492
24830
|
widget: CSProgram,
|
|
25493
24831
|
hidden: true,
|
|
25494
|
-
|
|
25495
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusCSProgramUserInput'.
|
|
25496
|
-
scorer: scoreCSProgram
|
|
24832
|
+
getPublicWidgetOptions: getCSProgramPublicWidgetOptions
|
|
25497
24833
|
};
|
|
25498
24834
|
|
|
25499
24835
|
const getPromptJSON$l = renderProps => {
|
|
@@ -25566,11 +24902,8 @@ var Definition$1 = {
|
|
|
25566
24902
|
name: "definition",
|
|
25567
24903
|
displayName: "Definition",
|
|
25568
24904
|
accessible: true,
|
|
25569
|
-
defaultAlignment: "inline",
|
|
25570
24905
|
widget: Definition,
|
|
25571
|
-
transform: x => x
|
|
25572
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
25573
|
-
scorer: () => scoreNoop()
|
|
24906
|
+
transform: x => x
|
|
25574
24907
|
};
|
|
25575
24908
|
|
|
25576
24909
|
// There are no required props, but this component can receive props from any
|
|
@@ -25600,9 +24933,7 @@ var DeprecatedStandin$1 = {
|
|
|
25600
24933
|
name: "deprecated-standin",
|
|
25601
24934
|
displayName: "Deprecated Standin",
|
|
25602
24935
|
widget: DeprecatedStandin,
|
|
25603
|
-
hidden: true
|
|
25604
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
25605
|
-
scorer: () => scoreNoop(1)
|
|
24936
|
+
hidden: true
|
|
25606
24937
|
};
|
|
25607
24938
|
|
|
25608
24939
|
const getPromptJSON$k = (renderProps, userInput) => {
|
|
@@ -25714,16 +25045,10 @@ const optionsTransform = widgetOptions => {
|
|
|
25714
25045
|
var Dropdown$1 = {
|
|
25715
25046
|
name: "dropdown",
|
|
25716
25047
|
displayName: "Drop down",
|
|
25717
|
-
defaultAlignment: "inline-block",
|
|
25718
25048
|
accessible: true,
|
|
25719
25049
|
widget: Dropdown,
|
|
25720
25050
|
transform: optionsTransform,
|
|
25721
|
-
|
|
25722
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusDropdownUserInput'.
|
|
25723
|
-
scorer: scoreDropdown,
|
|
25724
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
25725
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusDropdownUserInput'.
|
|
25726
|
-
validator: validateDropdown
|
|
25051
|
+
getPublicWidgetOptions: getDropdownPublicWidgetOptions
|
|
25727
25052
|
};
|
|
25728
25053
|
|
|
25729
25054
|
const getPromptJSON$j = renderProps => {
|
|
@@ -25878,12 +25203,9 @@ var Explanation$1 = {
|
|
|
25878
25203
|
name: "explanation",
|
|
25879
25204
|
displayName: "Explanation",
|
|
25880
25205
|
accessible: true,
|
|
25881
|
-
defaultAlignment: "inline",
|
|
25882
25206
|
widget: Explanation,
|
|
25883
25207
|
transform: _.identity,
|
|
25884
|
-
isLintable: true
|
|
25885
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
25886
|
-
scorer: () => scoreNoop()
|
|
25208
|
+
isLintable: true
|
|
25887
25209
|
};
|
|
25888
25210
|
|
|
25889
25211
|
const getPromptJSON$i = (title, rendererJSON, hintRendererJSON) => {
|
|
@@ -26072,7 +25394,7 @@ class GradedGroup extends React.Component {
|
|
|
26072
25394
|
DEFAULT_INVALID_MESSAGE_2
|
|
26073
25395
|
} = this.context.strings;
|
|
26074
25396
|
const status = score.type === "points" ? score.total === score.earned ? GRADING_STATUSES.correct : GRADING_STATUSES.incorrect : GRADING_STATUSES.invalid;
|
|
26075
|
-
const message = score.type === "points" ? score.message || "" : score.message ? `${INVALID_MESSAGE_PREFIX} ${mapErrorToString(score.message)}` : `${INVALID_MESSAGE_PREFIX} ${DEFAULT_INVALID_MESSAGE_1}${DEFAULT_INVALID_MESSAGE_2}`;
|
|
25397
|
+
const message = score.type === "points" ? score.message || "" : score.message ? `${INVALID_MESSAGE_PREFIX} ${mapErrorToString(score.message, this.context.strings)}` : `${INVALID_MESSAGE_PREFIX} ${DEFAULT_INVALID_MESSAGE_1}${DEFAULT_INVALID_MESSAGE_2}`;
|
|
26076
25398
|
this.setState({
|
|
26077
25399
|
status: status,
|
|
26078
25400
|
message: message,
|
|
@@ -26983,7 +26305,7 @@ class FunctionGrapher extends React.Component {
|
|
|
26983
26305
|
boxSizing: "initial"
|
|
26984
26306
|
}
|
|
26985
26307
|
}, /*#__PURE__*/React.createElement("div", {
|
|
26986
|
-
className: "graphie-container
|
|
26308
|
+
className: "graphie-container blank-background",
|
|
26987
26309
|
style: {
|
|
26988
26310
|
width: box[0],
|
|
26989
26311
|
height: box[1]
|
|
@@ -27122,8 +26444,7 @@ class Grapher extends React.Component {
|
|
|
27122
26444
|
const coords = this.props.plot.coords;
|
|
27123
26445
|
const asymptote = this.props.plot.asymptote;
|
|
27124
26446
|
const typeSelector = /*#__PURE__*/React.createElement("div", {
|
|
27125
|
-
style: typeSelectorStyle
|
|
27126
|
-
className: "above-scratchpad"
|
|
26447
|
+
style: typeSelectorStyle
|
|
27127
26448
|
}, /*#__PURE__*/React.createElement(ButtonGroup, {
|
|
27128
26449
|
value: type,
|
|
27129
26450
|
allowEmpty: true,
|
|
@@ -27201,10 +26522,7 @@ var Grapher$1 = {
|
|
|
27201
26522
|
hidden: true,
|
|
27202
26523
|
widget: Grapher,
|
|
27203
26524
|
transform: propTransform$2,
|
|
27204
|
-
staticTransform: staticTransform$4
|
|
27205
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
27206
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusGrapherUserInput'.
|
|
27207
|
-
scorer: scoreGrapher
|
|
26525
|
+
staticTransform: staticTransform$4
|
|
27208
26526
|
};
|
|
27209
26527
|
|
|
27210
26528
|
const getPromptJSON$f = rendererJSON => {
|
|
@@ -27220,24 +26538,6 @@ const getPromptJSON$f = rendererJSON => {
|
|
|
27220
26538
|
});
|
|
27221
26539
|
};
|
|
27222
26540
|
|
|
27223
|
-
// The `group` widget is basically a widget hosting a full Perseus system in
|
|
27224
|
-
// it. As such, scoring a group means scoring all widgets it contains.
|
|
27225
|
-
function scoreGroup(userInput, rubric, strings, locale) {
|
|
27226
|
-
const scores = scoreWidgetsFunctional(rubric.widgets, Object.keys(rubric.widgets), userInput, strings, locale);
|
|
27227
|
-
return flattenScores(scores);
|
|
27228
|
-
}
|
|
27229
|
-
|
|
27230
|
-
function validateGroup(userInput, validationData, strings, locale) {
|
|
27231
|
-
const emptyWidgets = emptyWidgetsFunctional(validationData.widgets, Object.keys(validationData.widgets), userInput, strings, locale);
|
|
27232
|
-
if (emptyWidgets.length === 0) {
|
|
27233
|
-
return null;
|
|
27234
|
-
}
|
|
27235
|
-
return {
|
|
27236
|
-
type: "invalid",
|
|
27237
|
-
message: null
|
|
27238
|
-
};
|
|
27239
|
-
}
|
|
27240
|
-
|
|
27241
26541
|
// exports has no 'transform'
|
|
27242
26542
|
|
|
27243
26543
|
class Group extends React.Component {
|
|
@@ -27392,12 +26692,6 @@ var Group$1 = {
|
|
|
27392
26692
|
displayName: "Group (SAT only)",
|
|
27393
26693
|
widget: Group,
|
|
27394
26694
|
traverseChildWidgets: traverseChildWidgets,
|
|
27395
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
27396
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusGroupUserInput'.
|
|
27397
|
-
scorer: scoreGroup,
|
|
27398
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
27399
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusGroupUserInput'.
|
|
27400
|
-
validator: validateGroup,
|
|
27401
26695
|
hidden: true,
|
|
27402
26696
|
isLintable: true
|
|
27403
26697
|
};
|
|
@@ -27533,10 +26827,7 @@ var Iframe$1 = {
|
|
|
27533
26827
|
displayName: "Iframe (deprecated)",
|
|
27534
26828
|
widget: Iframe,
|
|
27535
26829
|
// Let's not expose it to all content creators yet
|
|
27536
|
-
hidden: true
|
|
27537
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
27538
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusIframeUserInput'.
|
|
27539
|
-
scorer: scoreIframe
|
|
26830
|
+
hidden: true
|
|
27540
26831
|
};
|
|
27541
26832
|
|
|
27542
26833
|
const getPromptJSON$d = renderProps => {
|
|
@@ -27558,8 +26849,6 @@ const defaultBackgroundImage$2 = {
|
|
|
27558
26849
|
width: 0,
|
|
27559
26850
|
height: 0
|
|
27560
26851
|
};
|
|
27561
|
-
const editorAlignments = ["block", "full-width"];
|
|
27562
|
-
const DEFAULT_ALIGNMENT = "block";
|
|
27563
26852
|
|
|
27564
26853
|
// there is no transform as part of exports
|
|
27565
26854
|
|
|
@@ -27708,7 +26997,7 @@ class ImageWidget extends React.Component {
|
|
|
27708
26997
|
}
|
|
27709
26998
|
ImageWidget.contextType = PerseusI18nContext;
|
|
27710
26999
|
ImageWidget.defaultProps = {
|
|
27711
|
-
alignment:
|
|
27000
|
+
alignment: "block",
|
|
27712
27001
|
title: "",
|
|
27713
27002
|
range: [defaultRange, defaultRange],
|
|
27714
27003
|
box: [defaultBoxSize, defaultBoxSize],
|
|
@@ -27726,13 +27015,9 @@ var Image$1 = {
|
|
|
27726
27015
|
const bgImage = widgetOptions.backgroundImage;
|
|
27727
27016
|
return !(bgImage && bgImage.url && !widgetOptions.alt);
|
|
27728
27017
|
},
|
|
27729
|
-
defaultAlignment: DEFAULT_ALIGNMENT,
|
|
27730
|
-
supportedAlignments: editorAlignments,
|
|
27731
27018
|
displayName: "Image",
|
|
27732
27019
|
widget: ImageWidget,
|
|
27733
|
-
isLintable: true
|
|
27734
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
27735
|
-
scorer: () => scoreNoop()
|
|
27020
|
+
isLintable: true
|
|
27736
27021
|
};
|
|
27737
27022
|
|
|
27738
27023
|
const getPromptJSON$c = () => {
|
|
@@ -28330,9 +27615,7 @@ var Interactive = {
|
|
|
28330
27615
|
displayName: "Interaction",
|
|
28331
27616
|
widget: Interaction,
|
|
28332
27617
|
transform: _.identity,
|
|
28333
|
-
hidden: true
|
|
28334
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
28335
|
-
scorer: () => scoreNoop()
|
|
27618
|
+
hidden: true
|
|
28336
27619
|
};
|
|
28337
27620
|
|
|
28338
27621
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -28601,7 +27884,7 @@ class Graph extends React.Component {
|
|
|
28601
27884
|
image = null;
|
|
28602
27885
|
}
|
|
28603
27886
|
return /*#__PURE__*/React.createElement("div", {
|
|
28604
|
-
className: "graphie-container
|
|
27887
|
+
className: "graphie-container blank-background",
|
|
28605
27888
|
style: {
|
|
28606
27889
|
width: this.props.box[0],
|
|
28607
27890
|
height: this.props.box[1]
|
|
@@ -29236,7 +28519,8 @@ const tickLabelSize = 14;
|
|
|
29236
28519
|
const YGridTick = ({
|
|
29237
28520
|
y,
|
|
29238
28521
|
range,
|
|
29239
|
-
tickStep
|
|
28522
|
+
tickStep,
|
|
28523
|
+
showPi
|
|
29240
28524
|
}) => {
|
|
29241
28525
|
// If the graph requires out-of-bounds labels, we want to make sure to set the
|
|
29242
28526
|
// coordinates to the edge of the visible range of the graph. Otherwise,
|
|
@@ -29272,6 +28556,7 @@ const YGridTick = ({
|
|
|
29272
28556
|
// If the graph displays both the y and x axis lines within the graph, we want
|
|
29273
28557
|
// to hide the label at -1 on the y-axis to prevent overlap with the x-axis label
|
|
29274
28558
|
const showLabel = shouldShowLabel(y, range, tickStep);
|
|
28559
|
+
const yLabel = showPi ? divideByAndShowPi(y) : y.toString();
|
|
29275
28560
|
return /*#__PURE__*/React.createElement("g", {
|
|
29276
28561
|
className: "tick",
|
|
29277
28562
|
"aria-hidden": true
|
|
@@ -29289,11 +28574,12 @@ const YGridTick = ({
|
|
|
29289
28574
|
textAnchor: "end",
|
|
29290
28575
|
x: xPositionText,
|
|
29291
28576
|
y: yPositionText
|
|
29292
|
-
},
|
|
28577
|
+
}, yLabel));
|
|
29293
28578
|
};
|
|
29294
28579
|
const XGridTick = ({
|
|
29295
28580
|
x,
|
|
29296
|
-
range
|
|
28581
|
+
range,
|
|
28582
|
+
showPi
|
|
29297
28583
|
}) => {
|
|
29298
28584
|
// If the graph requires out-of-bounds labels, we want to make sure to set the
|
|
29299
28585
|
// coordinates to the edge of the visible range of the graph. Otherwise,
|
|
@@ -29332,6 +28618,7 @@ const XGridTick = ({
|
|
|
29332
28618
|
// Apply the adjustments to the x and y positions for the text
|
|
29333
28619
|
const xPositionText = xPosition + xAdjustment;
|
|
29334
28620
|
const yPositionText = yPosition + yAdjustment;
|
|
28621
|
+
const xLabel = showPi ? divideByAndShowPi(x) : x.toString();
|
|
29335
28622
|
return /*#__PURE__*/React.createElement("g", {
|
|
29336
28623
|
className: "tick",
|
|
29337
28624
|
"aria-hidden": true
|
|
@@ -29349,7 +28636,7 @@ const XGridTick = ({
|
|
|
29349
28636
|
textAnchor: "middle",
|
|
29350
28637
|
x: xPositionText,
|
|
29351
28638
|
y: yPositionText
|
|
29352
|
-
},
|
|
28639
|
+
}, xLabel));
|
|
29353
28640
|
};
|
|
29354
28641
|
|
|
29355
28642
|
// Determines whether to show the label for the given tick
|
|
@@ -29396,6 +28683,22 @@ const countSignificantDecimals = number => {
|
|
|
29396
28683
|
}
|
|
29397
28684
|
return numStr.split(".")[1].length;
|
|
29398
28685
|
};
|
|
28686
|
+
|
|
28687
|
+
// Show the given value as a multiple of pi (already assumed to be
|
|
28688
|
+
// a multiple of pi). Exported for testing
|
|
28689
|
+
function divideByAndShowPi(value) {
|
|
28690
|
+
const dividedValue = value / Math.PI;
|
|
28691
|
+
switch (dividedValue) {
|
|
28692
|
+
case 1:
|
|
28693
|
+
return "π";
|
|
28694
|
+
case -1:
|
|
28695
|
+
return "-π";
|
|
28696
|
+
case 0:
|
|
28697
|
+
return "0";
|
|
28698
|
+
default:
|
|
28699
|
+
return dividedValue + "π";
|
|
28700
|
+
}
|
|
28701
|
+
}
|
|
29399
28702
|
const AxisTicks = () => {
|
|
29400
28703
|
const {
|
|
29401
28704
|
tickStep,
|
|
@@ -29418,6 +28721,10 @@ const AxisTicks = () => {
|
|
|
29418
28721
|
key: `y-grid-tick-${y}`,
|
|
29419
28722
|
range: range,
|
|
29420
28723
|
tickStep: tickStep[Y]
|
|
28724
|
+
// Show the tick labels as multiples of pi
|
|
28725
|
+
// if the tick step is a multiple of pi.
|
|
28726
|
+
,
|
|
28727
|
+
showPi: tickStep[Y] % Math.PI === 0
|
|
29421
28728
|
});
|
|
29422
28729
|
})), /*#__PURE__*/React.createElement("g", {
|
|
29423
28730
|
className: "x-axis-ticks"
|
|
@@ -29426,6 +28733,10 @@ const AxisTicks = () => {
|
|
|
29426
28733
|
x: x,
|
|
29427
28734
|
key: `x-grid-tick-${x}`,
|
|
29428
28735
|
range: range
|
|
28736
|
+
// Show the tick labels as multiples of pi
|
|
28737
|
+
// if the tick step is a multiple of pi.
|
|
28738
|
+
,
|
|
28739
|
+
showPi: tickStep[X] % Math.PI === 0
|
|
29429
28740
|
});
|
|
29430
28741
|
})));
|
|
29431
28742
|
};
|
|
@@ -29733,6 +29044,15 @@ const styles$d = StyleSheet.create({
|
|
|
29733
29044
|
}
|
|
29734
29045
|
});
|
|
29735
29046
|
|
|
29047
|
+
function isPiMultiple(value) {
|
|
29048
|
+
// Early return for integers that clearly aren't multiples
|
|
29049
|
+
// of pi to save some computation.
|
|
29050
|
+
if (Number.isInteger(value)) {
|
|
29051
|
+
return false;
|
|
29052
|
+
}
|
|
29053
|
+
return value % Math.PI === 0 || value % (Math.PI / 2) === 0 || value % (Math.PI / 3) === 0 || value % (Math.PI / 4) === 0 || value % (Math.PI / 6) === 0;
|
|
29054
|
+
}
|
|
29055
|
+
|
|
29736
29056
|
const _excluded$1 = ["onFormatChange", "checkValidity", "useArrowKeys"];
|
|
29737
29057
|
const {
|
|
29738
29058
|
firstNumericalParse,
|
|
@@ -29870,6 +29190,19 @@ class NumberInput extends React.Component {
|
|
|
29870
29190
|
this._getInput().value = toNumericString(val, format);
|
|
29871
29191
|
};
|
|
29872
29192
|
}
|
|
29193
|
+
componentDidMount() {
|
|
29194
|
+
// If the value is a multiple of pi, but it is not in the pi format,
|
|
29195
|
+
// then convert it to the pi format and show it as a multiple of pi.
|
|
29196
|
+
const value = this.getValue();
|
|
29197
|
+
if (this.props.allowPiTruncation && value !== null && value !== 0) {
|
|
29198
|
+
if (this.state.format !== "pi" && isPiMultiple(value)) {
|
|
29199
|
+
this._setValue(value / Math.PI, "pi");
|
|
29200
|
+
this.setState({
|
|
29201
|
+
format: "pi"
|
|
29202
|
+
});
|
|
29203
|
+
}
|
|
29204
|
+
}
|
|
29205
|
+
}
|
|
29873
29206
|
componentDidUpdate(prevProps) {
|
|
29874
29207
|
if (!number.equal(this.getValue(), this.props.value)) {
|
|
29875
29208
|
this._setValue(this.props.value, this.state.format);
|
|
@@ -29912,7 +29245,8 @@ NumberInput.propTypes = {
|
|
|
29912
29245
|
onFormatChange: PropTypes.func,
|
|
29913
29246
|
checkValidity: PropTypes.func,
|
|
29914
29247
|
size: PropTypes.oneOf(["mini", "small", "normal"]),
|
|
29915
|
-
label: PropTypes.oneOf(["put your labels outside your inputs!"])
|
|
29248
|
+
label: PropTypes.oneOf(["put your labels outside your inputs!"]),
|
|
29249
|
+
allowPiTruncation: PropTypes.bool
|
|
29916
29250
|
};
|
|
29917
29251
|
NumberInput.defaultProps = {
|
|
29918
29252
|
value: null,
|
|
@@ -29951,14 +29285,16 @@ class RangeInput extends React.Component {
|
|
|
29951
29285
|
// eslint-disable-next-line react/jsx-no-bind
|
|
29952
29286
|
,
|
|
29953
29287
|
onChange: this.onChange.bind(this, 0),
|
|
29954
|
-
placeholder: this.props.placeholder[0]
|
|
29288
|
+
placeholder: this.props.placeholder[0],
|
|
29289
|
+
allowPiTruncation: this.props.allowPiTruncation
|
|
29955
29290
|
})), /*#__PURE__*/React.createElement(NumberInput, _extends({}, this.props, {
|
|
29956
29291
|
value: value[1],
|
|
29957
29292
|
checkValidity: val => checkValidity([value[0], val])
|
|
29958
29293
|
// eslint-disable-next-line react/jsx-no-bind
|
|
29959
29294
|
,
|
|
29960
29295
|
onChange: this.onChange.bind(this, 1),
|
|
29961
|
-
placeholder: this.props.placeholder[1]
|
|
29296
|
+
placeholder: this.props.placeholder[1],
|
|
29297
|
+
allowPiTruncation: this.props.allowPiTruncation
|
|
29962
29298
|
})));
|
|
29963
29299
|
}
|
|
29964
29300
|
}
|
|
@@ -29966,7 +29302,8 @@ RangeInput.propTypes = {
|
|
|
29966
29302
|
value: PropTypes.array.isRequired,
|
|
29967
29303
|
onChange: PropTypes.func.isRequired,
|
|
29968
29304
|
placeholder: PropTypes.array,
|
|
29969
|
-
checkValidity: PropTypes.func
|
|
29305
|
+
checkValidity: PropTypes.func,
|
|
29306
|
+
allowPiTruncation: PropTypes.bool
|
|
29970
29307
|
};
|
|
29971
29308
|
RangeInput.defaultProps = {
|
|
29972
29309
|
placeholder: [null, null]
|
|
@@ -36949,10 +36286,7 @@ var InteractiveGraph$1 = {
|
|
|
36949
36286
|
name: "interactive-graph",
|
|
36950
36287
|
displayName: "Interactive graph (Assessments only)",
|
|
36951
36288
|
widget: InteractiveGraph,
|
|
36952
|
-
staticTransform: staticTransform$3
|
|
36953
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
36954
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusInteractiveGraphUserInput'.
|
|
36955
|
-
scorer: scoreInteractiveGraph
|
|
36289
|
+
staticTransform: staticTransform$3
|
|
36956
36290
|
};
|
|
36957
36291
|
|
|
36958
36292
|
// TODO: can we use WB typography?
|
|
@@ -37894,9 +37228,7 @@ var LabelImage$1 = {
|
|
|
37894
37228
|
widget: LabelImageWithDependencies,
|
|
37895
37229
|
accessible: true,
|
|
37896
37230
|
isLintable: true,
|
|
37897
|
-
|
|
37898
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusLabelImageUserInput'.
|
|
37899
|
-
scorer: scoreLabelImage
|
|
37231
|
+
getPublicWidgetOptions: getLabelImagePublicWidgetOptions
|
|
37900
37232
|
};
|
|
37901
37233
|
|
|
37902
37234
|
var ItemState = /*#__PURE__*/function (ItemState) {
|
|
@@ -38129,7 +37461,7 @@ class Draggable extends React.Component {
|
|
|
38129
37461
|
// We need to keep backwards compatbility with rules specified directly
|
|
38130
37462
|
// in CSS. Hence the hacky tacking on of manual classNames.
|
|
38131
37463
|
// See sortable.less for details.
|
|
38132
|
-
let className = css(styles$8.card, styles$8.draggable, layout === "horizontal" && styles$8.horizontalCard, layout === "vertical" && styles$8.verticalCard, type === ItemState.DRAGGING && styles$8.dragging, type === ItemState.DISABLED && styles$8.disabled, !includePadding && styles$8.unpaddedCard) + " " +
|
|
37464
|
+
let className = css(styles$8.card, styles$8.draggable, layout === "horizontal" && styles$8.horizontalCard, layout === "vertical" && styles$8.verticalCard, type === ItemState.DRAGGING && styles$8.dragging, type === ItemState.DISABLED && styles$8.disabled, !includePadding && styles$8.unpaddedCard) + " " + "perseus-sortable-draggable";
|
|
38133
37465
|
if (!includePadding) {
|
|
38134
37466
|
className += " perseus-sortable-draggable-unpadded";
|
|
38135
37467
|
}
|
|
@@ -38830,10 +38162,7 @@ var Matcher$1 = {
|
|
|
38830
38162
|
name: "matcher",
|
|
38831
38163
|
displayName: "Matcher (two column)",
|
|
38832
38164
|
widget: Matcher,
|
|
38833
|
-
isLintable: true
|
|
38834
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
38835
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusMatcherUserInput'.
|
|
38836
|
-
scorer: scoreMatcher
|
|
38165
|
+
isLintable: true
|
|
38837
38166
|
};
|
|
38838
38167
|
|
|
38839
38168
|
const getPromptJSON$8 = (renderProps, userInput) => {
|
|
@@ -39237,13 +38566,7 @@ var Matrix$1 = {
|
|
|
39237
38566
|
widget: Matrix,
|
|
39238
38567
|
transform: propTransform$1,
|
|
39239
38568
|
staticTransform: staticTransform$2,
|
|
39240
|
-
isLintable: true
|
|
39241
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
39242
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusMatrixUserInput'.
|
|
39243
|
-
scorer: scoreMatrix,
|
|
39244
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
39245
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusMatrixUserInput'.
|
|
39246
|
-
validator: validateMatrix
|
|
38569
|
+
isLintable: true
|
|
39247
38570
|
};
|
|
39248
38571
|
|
|
39249
38572
|
const getPromptJSON$7 = () => {
|
|
@@ -39323,7 +38646,7 @@ class Measurer extends React.Component {
|
|
|
39323
38646
|
// TODO(scottgrant): This isn't a11y-friendly! We should insist on
|
|
39324
38647
|
// finding some valid alt text when this widget is used.
|
|
39325
38648
|
return /*#__PURE__*/React.createElement("div", {
|
|
39326
|
-
className: "perseus-widget perseus-widget-measurer " + "graphie-container
|
|
38649
|
+
className: "perseus-widget perseus-widget-measurer " + "graphie-container blank-background",
|
|
39327
38650
|
style: {
|
|
39328
38651
|
width: this.props.box[0],
|
|
39329
38652
|
height: this.props.box[1]
|
|
@@ -39360,9 +38683,7 @@ var Measurer$1 = {
|
|
|
39360
38683
|
hidden: true,
|
|
39361
38684
|
widget: Measurer,
|
|
39362
38685
|
version: measurerLogic.version,
|
|
39363
|
-
propUpgrades: measurerLogic.widgetOptionsUpgrades
|
|
39364
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
39365
|
-
scorer: () => scoreNoop(1)
|
|
38686
|
+
propUpgrades: measurerLogic.widgetOptionsUpgrades
|
|
39366
38687
|
};
|
|
39367
38688
|
|
|
39368
38689
|
/**
|
|
@@ -40250,8 +39571,7 @@ var Molecule$1 = {
|
|
|
40250
39571
|
name: "molecule-renderer",
|
|
40251
39572
|
displayName: "Molecule renderer",
|
|
40252
39573
|
hidden: true,
|
|
40253
|
-
widget: MoleculeWidget
|
|
40254
|
-
scorer: () => scoreNoop()
|
|
39574
|
+
widget: MoleculeWidget
|
|
40255
39575
|
};
|
|
40256
39576
|
|
|
40257
39577
|
const getPromptJSON$6 = (renderProps, userInput) => {
|
|
@@ -40820,12 +40140,7 @@ var NumberLine$1 = {
|
|
|
40820
40140
|
widget: NumberLine,
|
|
40821
40141
|
transform: numberLineTransform,
|
|
40822
40142
|
staticTransform: staticTransform$1,
|
|
40823
|
-
|
|
40824
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusNumberLineUserInput'.
|
|
40825
|
-
scorer: scoreNumberLine,
|
|
40826
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
40827
|
-
// @ts-expect-error: Type 'UserInput' is not assignable to type 'PerseusNumberLineUserInput'.
|
|
40828
|
-
validator: validateNumberLine
|
|
40143
|
+
getPublicWidgetOptions: getNumberLinePublicWidgetOptions
|
|
40829
40144
|
};
|
|
40830
40145
|
|
|
40831
40146
|
const getPromptJSON$5 = (renderProps, userInput) => {
|
|
@@ -40843,7 +40158,7 @@ const getPromptJSON$5 = (renderProps, userInput) => {
|
|
|
40843
40158
|
class PlaceholderCard extends React.Component {
|
|
40844
40159
|
render() {
|
|
40845
40160
|
return /*#__PURE__*/React.createElement("div", {
|
|
40846
|
-
className: "card-wrap
|
|
40161
|
+
className: "card-wrap",
|
|
40847
40162
|
style: {
|
|
40848
40163
|
width: this.props.width
|
|
40849
40164
|
}
|
|
@@ -40858,7 +40173,7 @@ class PlaceholderCard extends React.Component {
|
|
|
40858
40173
|
class DragHintCard extends React.Component {
|
|
40859
40174
|
render() {
|
|
40860
40175
|
return /*#__PURE__*/React.createElement("div", {
|
|
40861
|
-
className: "card-wrap
|
|
40176
|
+
className: "card-wrap"
|
|
40862
40177
|
}, /*#__PURE__*/React.createElement("div", {
|
|
40863
40178
|
className: "card drag-hint"
|
|
40864
40179
|
}));
|
|
@@ -40994,7 +40309,7 @@ class Card extends React.Component {
|
|
|
40994
40309
|
const rendererProps = _.pick(this.props, "content");
|
|
40995
40310
|
const onMouseDown = this.props.animating ? $.noop : this.onMouseDown;
|
|
40996
40311
|
return /*#__PURE__*/React.createElement("div", {
|
|
40997
|
-
className: "card-wrap
|
|
40312
|
+
className: "card-wrap",
|
|
40998
40313
|
style: style,
|
|
40999
40314
|
onMouseDown: onMouseDown,
|
|
41000
40315
|
onTouchStart: onMouseDown,
|
|
@@ -41365,7 +40680,7 @@ class Orderer extends React.Component {
|
|
|
41365
40680
|
});
|
|
41366
40681
|
}, this));
|
|
41367
40682
|
return /*#__PURE__*/React.createElement("div", {
|
|
41368
|
-
className: "draggy-boxy-thing orderer " + "height-" + this.props.height + " " + "layout-" + this.props.layout + " " + "
|
|
40683
|
+
className: "draggy-boxy-thing orderer " + "height-" + this.props.height + " " + "layout-" + this.props.layout + " " + "blank-background " + "perseus-clearfix "
|
|
41369
40684
|
// eslint-disable-next-line react/no-string-refs
|
|
41370
40685
|
,
|
|
41371
40686
|
ref: "orderer"
|
|
@@ -41386,12 +40701,6 @@ var Orderer$1 = {
|
|
|
41386
40701
|
hidden: true,
|
|
41387
40702
|
widget: Orderer,
|
|
41388
40703
|
isLintable: true,
|
|
41389
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
41390
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusOrdererUserInput
|
|
41391
|
-
scorer: scoreOrderer,
|
|
41392
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
41393
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusOrdererUserInput
|
|
41394
|
-
validator: validateOrderer,
|
|
41395
40704
|
getPublicWidgetOptions: getOrdererPublicWidgetOptions
|
|
41396
40705
|
};
|
|
41397
40706
|
|
|
@@ -41430,15 +40739,12 @@ PassageRefTarget.defaultProps = {
|
|
|
41430
40739
|
var PassageRefTarget$1 = {
|
|
41431
40740
|
name: "passage-ref-target",
|
|
41432
40741
|
displayName: "PassageRefTarget",
|
|
41433
|
-
defaultAlignment: "inline",
|
|
41434
40742
|
widget: PassageRefTarget,
|
|
41435
40743
|
hidden: true,
|
|
41436
40744
|
transform: editorProps => {
|
|
41437
40745
|
return _.pick(editorProps, "content");
|
|
41438
40746
|
},
|
|
41439
|
-
isLintable: true
|
|
41440
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
41441
|
-
scorer: () => scoreNoop()
|
|
40747
|
+
isLintable: true
|
|
41442
40748
|
};
|
|
41443
40749
|
|
|
41444
40750
|
const getPromptJSON$4 = () => {
|
|
@@ -42425,7 +41731,7 @@ class Plotter extends React.Component {
|
|
|
42425
41731
|
marginBottom: this.props.labels[0] ? paddingForBottomLabel : 0
|
|
42426
41732
|
};
|
|
42427
41733
|
return /*#__PURE__*/React.createElement("div", {
|
|
42428
|
-
className: "perseus-widget-plotter graphie
|
|
41734
|
+
className: "perseus-widget-plotter graphie"
|
|
42429
41735
|
// eslint-disable-next-line react/no-string-refs
|
|
42430
41736
|
,
|
|
42431
41737
|
ref: "graphieDiv",
|
|
@@ -42455,13 +41761,7 @@ var Plotter$1 = {
|
|
|
42455
41761
|
displayName: "Plotter",
|
|
42456
41762
|
hidden: true,
|
|
42457
41763
|
widget: Plotter,
|
|
42458
|
-
staticTransform: staticTransform
|
|
42459
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
42460
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusPlotterUserInput
|
|
42461
|
-
scorer: scorePlotter,
|
|
42462
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
42463
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusPlotterUserInput
|
|
42464
|
-
validator: validatePlotter
|
|
41764
|
+
staticTransform: staticTransform
|
|
42465
41765
|
};
|
|
42466
41766
|
|
|
42467
41767
|
const getPromptJSON$2 = () => {
|
|
@@ -42624,12 +41924,7 @@ var Sorter$1 = {
|
|
|
42624
41924
|
displayName: "Sorter",
|
|
42625
41925
|
widget: Sorter,
|
|
42626
41926
|
isLintable: true,
|
|
42627
|
-
|
|
42628
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusSorterUserInput
|
|
42629
|
-
scorer: scoreSorter,
|
|
42630
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
42631
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusSorterUserInput
|
|
42632
|
-
validator: validateSorter
|
|
41927
|
+
getPublicWidgetOptions: getSorterPublicWidgetOptions
|
|
42633
41928
|
};
|
|
42634
41929
|
|
|
42635
41930
|
const {
|
|
@@ -42848,13 +42143,7 @@ var Table$1 = {
|
|
|
42848
42143
|
widget: Table,
|
|
42849
42144
|
transform: propTransform,
|
|
42850
42145
|
hidden: true,
|
|
42851
|
-
isLintable: true
|
|
42852
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
42853
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusTableUserInput
|
|
42854
|
-
scorer: scoreTable,
|
|
42855
|
-
// TODO(LEMS-2656): remove TS suppression
|
|
42856
|
-
// @ts-expect-error: Type UserInput is not assignable to type PerseusTableUserInput
|
|
42857
|
-
validator: validateTable
|
|
42146
|
+
isLintable: true
|
|
42858
42147
|
};
|
|
42859
42148
|
|
|
42860
42149
|
const getPromptJSON = () => {
|
|
@@ -43014,11 +42303,7 @@ Video.contextType = PerseusI18nContext;
|
|
|
43014
42303
|
var Video$1 = {
|
|
43015
42304
|
name: "video",
|
|
43016
42305
|
displayName: "Video",
|
|
43017
|
-
|
|
43018
|
-
supportedAlignments: ["block", "float-left", "float-right", "full-width"],
|
|
43019
|
-
widget: Video,
|
|
43020
|
-
// TODO: things that aren't interactive shouldn't need scoring functions
|
|
43021
|
-
scorer: () => scoreNoop()
|
|
42306
|
+
widget: Video
|
|
43022
42307
|
};
|
|
43023
42308
|
|
|
43024
42309
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -43037,7 +42322,7 @@ const init = function init() {
|
|
|
43037
42322
|
|
|
43038
42323
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43039
42324
|
const libName = "@khanacademy/perseus";
|
|
43040
|
-
const libVersion = "
|
|
42325
|
+
const libVersion = "53.0.0";
|
|
43041
42326
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43042
42327
|
|
|
43043
42328
|
const apiVersion = {
|
|
@@ -43904,6 +43189,42 @@ const ref = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.cre
|
|
|
43904
43189
|
ref: ref
|
|
43905
43190
|
}))));
|
|
43906
43191
|
|
|
43192
|
+
function isCorrect(score) {
|
|
43193
|
+
return score.type === "points" && score.earned >= score.total;
|
|
43194
|
+
}
|
|
43195
|
+
function keScoreFromPerseusScore(score,
|
|
43196
|
+
// It's weird, but this is what we're passing it
|
|
43197
|
+
guess, state) {
|
|
43198
|
+
if (score.type === "points") {
|
|
43199
|
+
return {
|
|
43200
|
+
empty: false,
|
|
43201
|
+
correct: isCorrect(score),
|
|
43202
|
+
message: score.message,
|
|
43203
|
+
guess: guess,
|
|
43204
|
+
state: state
|
|
43205
|
+
};
|
|
43206
|
+
}
|
|
43207
|
+
if (score.type === "invalid") {
|
|
43208
|
+
return {
|
|
43209
|
+
empty: true,
|
|
43210
|
+
correct: false,
|
|
43211
|
+
message: score.message,
|
|
43212
|
+
suppressAlmostThere: score.suppressAlmostThere,
|
|
43213
|
+
guess: guess,
|
|
43214
|
+
state: state
|
|
43215
|
+
};
|
|
43216
|
+
}
|
|
43217
|
+
throw new PerseusError(
|
|
43218
|
+
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
43219
|
+
"Invalid score type: " + score.type, Errors.InvalidInput, {
|
|
43220
|
+
metadata: {
|
|
43221
|
+
score: JSON.stringify(score),
|
|
43222
|
+
guess: JSON.stringify(guess),
|
|
43223
|
+
state: JSON.stringify(state)
|
|
43224
|
+
}
|
|
43225
|
+
});
|
|
43226
|
+
}
|
|
43227
|
+
|
|
43907
43228
|
/**
|
|
43908
43229
|
* Traverses a {content, widgets, images} renderer props object,
|
|
43909
43230
|
* such as `itemData.question`
|
|
@@ -45280,5 +44601,5 @@ const ScoringUtil = {
|
|
|
45280
44601
|
* Types
|
|
45281
44602
|
*/
|
|
45282
44603
|
|
|
45283
|
-
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, mediaQueries, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting,
|
|
44604
|
+
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, mediaQueries, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
45284
44605
|
//# sourceMappingURL=index.js.map
|