@khanacademy/perseus 41.4.0 → 41.5.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/es/index.css +3 -0
- package/dist/es/index.js +556 -77
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +3 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +556 -77
- package/dist/index.js.map +1 -1
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/util/parse-perseus-json/perseus-parsers/graded-group-set-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/graded-group-widget.d.ts +16 -0
- package/dist/util/parse-perseus-json/perseus-parsers/grapher-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/group-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/iframe-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/image-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/input-number-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/interaction-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/label-image-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/matcher-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/matrix-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/measurer-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/molecule-renderer-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/number-line-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/numeric-input-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/orderer-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/passage-ref-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/passage-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/phet-simulation-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/plotter-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/python-program-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/radio-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/sorter-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/table-widget.d.ts +3 -0
- package/dist/util/parse-perseus-json/perseus-parsers/video-widget.d.ts +3 -0
- package/dist/widgets/numeric-input/numeric-input.d.ts +7 -0
- package/package.json +1 -1
package/dist/es/index.js
CHANGED
|
@@ -2591,7 +2591,7 @@ const keypadConfigurationForProps = widgetOptions => {
|
|
|
2591
2591
|
times: widgetOptions.times
|
|
2592
2592
|
};
|
|
2593
2593
|
};
|
|
2594
|
-
const propUpgrades$
|
|
2594
|
+
const propUpgrades$3 = {
|
|
2595
2595
|
/* c8 ignore next */
|
|
2596
2596
|
"1": v0props => ({
|
|
2597
2597
|
times: v0props.times,
|
|
@@ -2651,7 +2651,7 @@ var Expression$1 = {
|
|
|
2651
2651
|
major: 1,
|
|
2652
2652
|
minor: 0
|
|
2653
2653
|
},
|
|
2654
|
-
propUpgrades: propUpgrades$
|
|
2654
|
+
propUpgrades: propUpgrades$3,
|
|
2655
2655
|
// For use by the editor
|
|
2656
2656
|
isLintable: true,
|
|
2657
2657
|
scorer: scoreExpression,
|
|
@@ -18723,6 +18723,9 @@ const replaceDeprecatedWidgets = () => {
|
|
|
18723
18723
|
replaceWidget("sequence", "deprecated-standin");
|
|
18724
18724
|
replaceWidget("simulator", "deprecated-standin");
|
|
18725
18725
|
replaceWidget("unit-input", "deprecated-standin");
|
|
18726
|
+
|
|
18727
|
+
// Input-Number is a special case as it is being replaced by Numeric-Input
|
|
18728
|
+
replaceWidget("input-number", "numeric-input");
|
|
18726
18729
|
};
|
|
18727
18730
|
const registerEditors = editorsToRegister => {
|
|
18728
18731
|
editorsToRegister.forEach(editor => {
|
|
@@ -18757,6 +18760,11 @@ const replaceDeprecatedEditors = () => {
|
|
|
18757
18760
|
replaceEditor("sequence", "deprecated-standin");
|
|
18758
18761
|
replaceEditor("simulator", "deprecated-standin");
|
|
18759
18762
|
replaceEditor("unit-input", "deprecated-standin");
|
|
18763
|
+
|
|
18764
|
+
// We're replacing the input-number editor with the numeric-input editor here,
|
|
18765
|
+
// but we're also modifying the JSON content to convert input-number into the
|
|
18766
|
+
// numeric-input format over in editor-page.tsx on line 92.
|
|
18767
|
+
replaceEditor("input-number", "numeric-input");
|
|
18760
18768
|
};
|
|
18761
18769
|
const getWidget = name => {
|
|
18762
18770
|
var _widgets$name;
|
|
@@ -18807,10 +18815,8 @@ const getVersionVector = () => {
|
|
|
18807
18815
|
const getPublicWidgets = () => {
|
|
18808
18816
|
// TODO(alex): Update underscore.js so that _.pick can take a function.
|
|
18809
18817
|
// @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.
|
|
18810
|
-
return _.pick(widgets,
|
|
18811
|
-
|
|
18812
|
-
_.reject(_.keys(widgets), function (name) {
|
|
18813
|
-
return widgets[name].hidden;
|
|
18818
|
+
return _.pick(widgets, _.reject(_.keys(widgets), function (name) {
|
|
18819
|
+
return widgets[name].hidden || name === "input-number";
|
|
18814
18820
|
}));
|
|
18815
18821
|
};
|
|
18816
18822
|
const isAccessible = widgetInfo => {
|
|
@@ -22150,7 +22156,7 @@ class NumericInput extends React.Component {
|
|
|
22150
22156
|
height: "auto"
|
|
22151
22157
|
}
|
|
22152
22158
|
});
|
|
22153
|
-
return /*#__PURE__*/React.createElement(
|
|
22159
|
+
return /*#__PURE__*/React.createElement(InputWithExamples, {
|
|
22154
22160
|
ref: ref => this.inputRef = ref,
|
|
22155
22161
|
value: this.props.currentValue,
|
|
22156
22162
|
onChange: this.handleChange,
|
|
@@ -22162,7 +22168,7 @@ class NumericInput extends React.Component {
|
|
|
22162
22168
|
id: this.props.widgetId,
|
|
22163
22169
|
disabled: this.props.apiOptions.readOnly,
|
|
22164
22170
|
style: styles.input
|
|
22165
|
-
})
|
|
22171
|
+
});
|
|
22166
22172
|
}
|
|
22167
22173
|
}
|
|
22168
22174
|
|
|
@@ -22231,13 +22237,65 @@ const propsTransform = function propsTransform(widgetOptions) {
|
|
|
22231
22237
|
});
|
|
22232
22238
|
return rendererProps;
|
|
22233
22239
|
};
|
|
22240
|
+
|
|
22241
|
+
// This function is being used to replace the input-number widget
|
|
22242
|
+
// with the numeric-input widget
|
|
22243
|
+
const propUpgrades$2 = {
|
|
22244
|
+
/* c8 ignore next */
|
|
22245
|
+
"1": initialProps => {
|
|
22246
|
+
// If the initialProps has a value, it means we're upgrading from
|
|
22247
|
+
// input-number to numeric-input. In this case, we need to upgrade
|
|
22248
|
+
// the widget options accordingly.
|
|
22249
|
+
if (initialProps.value) {
|
|
22250
|
+
const provideAnswerForm = initialProps.answerType !== "number";
|
|
22251
|
+
|
|
22252
|
+
// We need to determine the mathFormat for the numeric-input widget
|
|
22253
|
+
const mathFormat = initialProps.answerType === "rational" ? "proper" // input-number uses "rational" for proper fractions
|
|
22254
|
+
: initialProps.answerType; // Otherwise, we can use the answerType directly
|
|
22255
|
+
|
|
22256
|
+
// If adjusting this logic, also adjust the logic in the convertInputNumberWidgetOptions
|
|
22257
|
+
// function in input-number.ts in the Perseus Editor package's util folder
|
|
22258
|
+
const answers = [{
|
|
22259
|
+
value: initialProps.value,
|
|
22260
|
+
simplify: initialProps.simplify,
|
|
22261
|
+
answerForms: provideAnswerForm ? [mathFormat] : undefined,
|
|
22262
|
+
strict: initialProps.inexact,
|
|
22263
|
+
// We only want to set maxError if the inexact prop is true
|
|
22264
|
+
maxError: initialProps.inexact ? initialProps.maxError : 0,
|
|
22265
|
+
status: "correct",
|
|
22266
|
+
// Input-number only allows correct answers
|
|
22267
|
+
message: ""
|
|
22268
|
+
}];
|
|
22269
|
+
return {
|
|
22270
|
+
answers,
|
|
22271
|
+
size: initialProps.size,
|
|
22272
|
+
coefficient: false,
|
|
22273
|
+
// input-number doesn't have a coefficient prop
|
|
22274
|
+
labelText: "",
|
|
22275
|
+
// input-number doesn't have a labelText prop
|
|
22276
|
+
static: false,
|
|
22277
|
+
// static is always false for numeric-input
|
|
22278
|
+
rightAlign: initialProps.rightAlign || false
|
|
22279
|
+
};
|
|
22280
|
+
} else {
|
|
22281
|
+
// Otherwise simply return the initialProps as there's no differences
|
|
22282
|
+
// between v0 and v1 for numeric-input
|
|
22283
|
+
return initialProps;
|
|
22284
|
+
}
|
|
22285
|
+
}
|
|
22286
|
+
};
|
|
22234
22287
|
var NumericInput$1 = {
|
|
22235
22288
|
name: "numeric-input",
|
|
22236
22289
|
displayName: "Numeric input",
|
|
22237
22290
|
defaultAlignment: "inline-block",
|
|
22238
22291
|
accessible: true,
|
|
22239
22292
|
widget: NumericInput,
|
|
22293
|
+
version: {
|
|
22294
|
+
major: 1,
|
|
22295
|
+
minor: 0
|
|
22296
|
+
},
|
|
22240
22297
|
transform: propsTransform,
|
|
22298
|
+
propUpgrades: propUpgrades$2,
|
|
22241
22299
|
isLintable: true,
|
|
22242
22300
|
scorer: scoreNumericInput,
|
|
22243
22301
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
@@ -31957,17 +32015,12 @@ const ItemExtras = [
|
|
|
31957
32015
|
// prettier-ignore
|
|
31958
32016
|
|
|
31959
32017
|
// prettier-ignore
|
|
31960
|
-
|
|
32018
|
+
// While this widget is deprecated, we still need the type for conversion purposes
|
|
31961
32019
|
// prettier-ignore
|
|
31962
|
-
|
|
31963
32020
|
// prettier-ignore
|
|
31964
|
-
|
|
31965
32021
|
// prettier-ignore
|
|
31966
|
-
|
|
31967
32022
|
//prettier-ignore
|
|
31968
|
-
|
|
31969
32023
|
// A background image applied to various widgets.
|
|
31970
|
-
|
|
31971
32024
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
31972
32025
|
|
|
31973
32026
|
// 2D range: xMin, xMax, yMin, yMax
|
|
@@ -44624,7 +44677,7 @@ const init = function init() {
|
|
|
44624
44677
|
|
|
44625
44678
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44626
44679
|
const libName = "@khanacademy/perseus";
|
|
44627
|
-
const libVersion = "41.
|
|
44680
|
+
const libVersion = "41.5.0";
|
|
44628
44681
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44629
44682
|
|
|
44630
44683
|
const apiVersion = {
|
|
@@ -45328,7 +45381,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
45328
45381
|
|
|
45329
45382
|
/**
|
|
45330
45383
|
* Accepts a question area widgetId, or an answer area widgetId of
|
|
45331
|
-
* the form "answer-input
|
|
45384
|
+
* the form "answer-numeric-input 1", or the string "answer-area"
|
|
45332
45385
|
* for the whole answer area (if the answer area is a single widget).
|
|
45333
45386
|
*/
|
|
45334
45387
|
_setWidgetProps(widgetId, newProps, callback) {
|
|
@@ -48283,6 +48336,118 @@ const parseExpressionWidget = parseWidget(constant("expression"), object({
|
|
|
48283
48336
|
buttonsVisible: optional(enumeration("always", "never", "focused"))
|
|
48284
48337
|
}));
|
|
48285
48338
|
|
|
48339
|
+
const parsePerseusRenderer = object({
|
|
48340
|
+
content: string,
|
|
48341
|
+
// This module has an import cycle with parseWidgetsMap, because the
|
|
48342
|
+
// `group` widget can contain another renderer.
|
|
48343
|
+
// The anonymous function below ensures that we don't try to access
|
|
48344
|
+
// parseWidgetsMap before it's defined.
|
|
48345
|
+
widgets: (rawVal, ctx) => parseWidgetsMap(rawVal, ctx),
|
|
48346
|
+
metadata: optional(array(string)),
|
|
48347
|
+
images: record(string, object({
|
|
48348
|
+
width: number,
|
|
48349
|
+
height: number
|
|
48350
|
+
}))
|
|
48351
|
+
});
|
|
48352
|
+
|
|
48353
|
+
const parseGradedGroupWidgetOptions = object({
|
|
48354
|
+
title: string,
|
|
48355
|
+
hasHint: optional(nullable(boolean)),
|
|
48356
|
+
// This module has an import cycle with parsePerseusRenderer.
|
|
48357
|
+
// The anonymous function below ensures that we don't try to access
|
|
48358
|
+
// parsePerseusRenderer before it's defined.
|
|
48359
|
+
hint: optional(nullable((rawVal, ctx) => parsePerseusRenderer(rawVal, ctx))),
|
|
48360
|
+
content: string,
|
|
48361
|
+
// This module has an import cycle with parseWidgetsMap.
|
|
48362
|
+
// The anonymous function below ensures that we don't try to access
|
|
48363
|
+
// parseWidgetsMap before it's defined.
|
|
48364
|
+
widgets: (rawVal, ctx) => parseWidgetsMap(rawVal, ctx),
|
|
48365
|
+
widgetEnabled: optional(nullable(boolean)),
|
|
48366
|
+
immutableWidgets: optional(nullable(boolean)),
|
|
48367
|
+
images: record(string, object({
|
|
48368
|
+
width: number,
|
|
48369
|
+
height: number
|
|
48370
|
+
}))
|
|
48371
|
+
});
|
|
48372
|
+
const parseGradedGroupWidget = parseWidget(constant("graded-group"), parseGradedGroupWidgetOptions);
|
|
48373
|
+
|
|
48374
|
+
const parseGradedGroupSetWidget = parseWidget(constant("graded-group-set"), object({
|
|
48375
|
+
gradedGroups: array(parseGradedGroupWidgetOptions)
|
|
48376
|
+
}));
|
|
48377
|
+
|
|
48378
|
+
const pairOfNumbers$3 = pair(number, number);
|
|
48379
|
+
const pairOfPoints = pair(pairOfNumbers$3, pairOfNumbers$3);
|
|
48380
|
+
const parseGrapherWidget = parseWidget(constant("grapher"), object({
|
|
48381
|
+
availableTypes: array(enumeration("absolute_value", "exponential", "linear", "logarithm", "quadratic", "sinusoid", "tangent")),
|
|
48382
|
+
correct: union(object({
|
|
48383
|
+
type: constant("absolute_value"),
|
|
48384
|
+
coords: pairOfPoints
|
|
48385
|
+
})).or(object({
|
|
48386
|
+
type: constant("exponential"),
|
|
48387
|
+
asymptote: pairOfPoints,
|
|
48388
|
+
coords: pairOfPoints
|
|
48389
|
+
})).or(object({
|
|
48390
|
+
type: constant("linear"),
|
|
48391
|
+
coords: pairOfPoints
|
|
48392
|
+
})).or(object({
|
|
48393
|
+
type: constant("logarithm"),
|
|
48394
|
+
asymptote: pairOfPoints,
|
|
48395
|
+
coords: pairOfPoints
|
|
48396
|
+
})).or(object({
|
|
48397
|
+
type: constant("quadratic"),
|
|
48398
|
+
coords: pairOfPoints
|
|
48399
|
+
})).or(object({
|
|
48400
|
+
type: constant("sinusoid"),
|
|
48401
|
+
coords: pairOfPoints
|
|
48402
|
+
})).or(object({
|
|
48403
|
+
type: constant("tangent"),
|
|
48404
|
+
coords: pairOfPoints
|
|
48405
|
+
})).parser,
|
|
48406
|
+
graph: object({
|
|
48407
|
+
backgroundImage: object({
|
|
48408
|
+
bottom: optional(number),
|
|
48409
|
+
height: optional(number),
|
|
48410
|
+
left: optional(number),
|
|
48411
|
+
scale: optional(number),
|
|
48412
|
+
url: optional(nullable(string)),
|
|
48413
|
+
width: optional(number)
|
|
48414
|
+
}),
|
|
48415
|
+
box: optional(pairOfNumbers$3),
|
|
48416
|
+
editableSettings: optional(array(enumeration("graph", "snap", "image", "measure"))),
|
|
48417
|
+
gridStep: optional(pairOfNumbers$3),
|
|
48418
|
+
labels: pair(string, string),
|
|
48419
|
+
markings: enumeration("graph", "none", "grid"),
|
|
48420
|
+
range: pair(pairOfNumbers$3, pairOfNumbers$3),
|
|
48421
|
+
rulerLabel: constant(""),
|
|
48422
|
+
rulerTicks: number,
|
|
48423
|
+
showProtractor: optional(boolean),
|
|
48424
|
+
showRuler: optional(boolean),
|
|
48425
|
+
showTooltips: optional(boolean),
|
|
48426
|
+
snapStep: optional(pairOfNumbers$3),
|
|
48427
|
+
step: pairOfNumbers$3,
|
|
48428
|
+
valid: optional(union(boolean).or(string).parser)
|
|
48429
|
+
})
|
|
48430
|
+
}));
|
|
48431
|
+
|
|
48432
|
+
const parseGroupWidget = parseWidget(constant("group"),
|
|
48433
|
+
// This module has an import cycle with parsePerseusRenderer.
|
|
48434
|
+
// The anonymous function below ensures that we don't try to access
|
|
48435
|
+
// parsePerseusRenderer before it's defined.
|
|
48436
|
+
(rawVal, ctx) => parsePerseusRenderer(rawVal, ctx));
|
|
48437
|
+
|
|
48438
|
+
const parseIframeWidget = parseWidget(constant("iframe"), object({
|
|
48439
|
+
url: string,
|
|
48440
|
+
settings: array(object({
|
|
48441
|
+
name: string,
|
|
48442
|
+
value: string
|
|
48443
|
+
})),
|
|
48444
|
+
width: union(number).or(string).parser,
|
|
48445
|
+
height: union(number).or(string).parser,
|
|
48446
|
+
allowFullScreen: boolean,
|
|
48447
|
+
allowTopNavigation: optional(boolean),
|
|
48448
|
+
static: boolean
|
|
48449
|
+
}));
|
|
48450
|
+
|
|
48286
48451
|
const parsePerseusImageBackground = object({
|
|
48287
48452
|
url: optional(nullable(string)),
|
|
48288
48453
|
width: optional(number),
|
|
@@ -48294,6 +48459,160 @@ const parsePerseusImageBackground = object({
|
|
|
48294
48459
|
scale: optional(union(number).or(string).parser)
|
|
48295
48460
|
});
|
|
48296
48461
|
|
|
48462
|
+
const pairOfNumbers$2 = pair(number, number);
|
|
48463
|
+
const parseImageWidget = parseWidget(constant("image"), object({
|
|
48464
|
+
title: optional(string),
|
|
48465
|
+
caption: optional(string),
|
|
48466
|
+
alt: optional(string),
|
|
48467
|
+
backgroundImage: parsePerseusImageBackground,
|
|
48468
|
+
static: optional(boolean),
|
|
48469
|
+
labels: optional(array(object({
|
|
48470
|
+
content: string,
|
|
48471
|
+
alignment: string,
|
|
48472
|
+
coordinates: array(number)
|
|
48473
|
+
}))),
|
|
48474
|
+
range: optional(pair(pairOfNumbers$2, pairOfNumbers$2)),
|
|
48475
|
+
box: optional(pairOfNumbers$2)
|
|
48476
|
+
}));
|
|
48477
|
+
|
|
48478
|
+
const parseInputNumberWidget = parseWidget(constant("input-number"), object({
|
|
48479
|
+
answerType: optional(enumeration("number", "decimal", "integer", "rational", "improper", "mixed", "percent", "pi")),
|
|
48480
|
+
inexact: optional(boolean),
|
|
48481
|
+
maxError: optional(union(number).or(string).parser),
|
|
48482
|
+
rightAlign: optional(boolean),
|
|
48483
|
+
simplify: enumeration("required", "optional", "enforced"),
|
|
48484
|
+
size: enumeration("normal", "small"),
|
|
48485
|
+
value: union(number).or(string).parser,
|
|
48486
|
+
customKeypad: optional(boolean)
|
|
48487
|
+
}));
|
|
48488
|
+
|
|
48489
|
+
const pairOfNumbers$1 = pair(number, number);
|
|
48490
|
+
const parseFunctionElement = object({
|
|
48491
|
+
type: constant("function"),
|
|
48492
|
+
key: string,
|
|
48493
|
+
options: object({
|
|
48494
|
+
value: string,
|
|
48495
|
+
funcName: string,
|
|
48496
|
+
rangeMin: string,
|
|
48497
|
+
rangeMax: string,
|
|
48498
|
+
color: string,
|
|
48499
|
+
strokeDasharray: string,
|
|
48500
|
+
strokeWidth: number
|
|
48501
|
+
})
|
|
48502
|
+
});
|
|
48503
|
+
const parseLabelElement = object({
|
|
48504
|
+
type: constant("label"),
|
|
48505
|
+
key: string,
|
|
48506
|
+
options: object({
|
|
48507
|
+
label: string,
|
|
48508
|
+
color: string,
|
|
48509
|
+
coordX: string,
|
|
48510
|
+
coordY: string
|
|
48511
|
+
})
|
|
48512
|
+
});
|
|
48513
|
+
const parseLineElement = object({
|
|
48514
|
+
type: constant("line"),
|
|
48515
|
+
key: string,
|
|
48516
|
+
options: object({
|
|
48517
|
+
color: string,
|
|
48518
|
+
startX: string,
|
|
48519
|
+
startY: string,
|
|
48520
|
+
endX: string,
|
|
48521
|
+
endY: string,
|
|
48522
|
+
strokeDasharray: string,
|
|
48523
|
+
strokeWidth: number,
|
|
48524
|
+
arrows: string
|
|
48525
|
+
})
|
|
48526
|
+
});
|
|
48527
|
+
const parseMovableLineElement = object({
|
|
48528
|
+
type: constant("movable-line"),
|
|
48529
|
+
key: string,
|
|
48530
|
+
options: object({
|
|
48531
|
+
startX: string,
|
|
48532
|
+
startY: string,
|
|
48533
|
+
startSubscript: number,
|
|
48534
|
+
endX: string,
|
|
48535
|
+
endY: string,
|
|
48536
|
+
endSubscript: number,
|
|
48537
|
+
constraint: string,
|
|
48538
|
+
snap: number,
|
|
48539
|
+
constraintFn: string,
|
|
48540
|
+
constraintXMin: string,
|
|
48541
|
+
constraintXMax: string,
|
|
48542
|
+
constraintYMin: string,
|
|
48543
|
+
constraintYMax: string
|
|
48544
|
+
})
|
|
48545
|
+
});
|
|
48546
|
+
const parseMovablePointElement = object({
|
|
48547
|
+
type: constant("movable-point"),
|
|
48548
|
+
key: string,
|
|
48549
|
+
options: object({
|
|
48550
|
+
startX: string,
|
|
48551
|
+
startY: string,
|
|
48552
|
+
varSubscript: number,
|
|
48553
|
+
constraint: string,
|
|
48554
|
+
snap: number,
|
|
48555
|
+
constraintFn: string,
|
|
48556
|
+
constraintXMin: string,
|
|
48557
|
+
constraintXMax: string,
|
|
48558
|
+
constraintYMin: string,
|
|
48559
|
+
constraintYMax: string
|
|
48560
|
+
})
|
|
48561
|
+
});
|
|
48562
|
+
const parseParametricElement = object({
|
|
48563
|
+
type: constant("parametric"),
|
|
48564
|
+
key: string,
|
|
48565
|
+
options: object({
|
|
48566
|
+
x: string,
|
|
48567
|
+
y: string,
|
|
48568
|
+
rangeMin: string,
|
|
48569
|
+
rangeMax: string,
|
|
48570
|
+
color: string,
|
|
48571
|
+
strokeDasharray: string,
|
|
48572
|
+
strokeWidth: number
|
|
48573
|
+
})
|
|
48574
|
+
});
|
|
48575
|
+
const parsePointElement = object({
|
|
48576
|
+
type: constant("point"),
|
|
48577
|
+
key: string,
|
|
48578
|
+
options: object({
|
|
48579
|
+
color: string,
|
|
48580
|
+
coordX: string,
|
|
48581
|
+
coordY: string
|
|
48582
|
+
})
|
|
48583
|
+
});
|
|
48584
|
+
const parseRectangleElement = object({
|
|
48585
|
+
type: constant("rectangle"),
|
|
48586
|
+
key: string,
|
|
48587
|
+
options: object({
|
|
48588
|
+
color: string,
|
|
48589
|
+
coordX: string,
|
|
48590
|
+
coordY: string,
|
|
48591
|
+
width: string,
|
|
48592
|
+
height: string
|
|
48593
|
+
})
|
|
48594
|
+
});
|
|
48595
|
+
const parseInteractionWidget = parseWidget(constant("interaction"), object({
|
|
48596
|
+
static: boolean,
|
|
48597
|
+
graph: object({
|
|
48598
|
+
editableSettings: optional(array(enumeration("canvas", "graph"))),
|
|
48599
|
+
box: pairOfNumbers$1,
|
|
48600
|
+
labels: array(string),
|
|
48601
|
+
range: pair(pairOfNumbers$1, pairOfNumbers$1),
|
|
48602
|
+
gridStep: pairOfNumbers$1,
|
|
48603
|
+
markings: enumeration("graph", "grid", "none"),
|
|
48604
|
+
snapStep: optional(pairOfNumbers$1),
|
|
48605
|
+
valid: optional(union(boolean).or(string).parser),
|
|
48606
|
+
backgroundImage: optional(parsePerseusImageBackground),
|
|
48607
|
+
showProtractor: optional(boolean),
|
|
48608
|
+
showRuler: optional(boolean),
|
|
48609
|
+
rulerLabel: optional(string),
|
|
48610
|
+
rulerTicks: optional(number),
|
|
48611
|
+
tickStep: pairOfNumbers$1
|
|
48612
|
+
}),
|
|
48613
|
+
elements: array(union(parseFunctionElement).or(parseLabelElement).or(parseLineElement).or(parseMovableLineElement).or(parseMovablePointElement).or(parseParametricElement).or(parsePointElement).or(parseRectangleElement).parser)
|
|
48614
|
+
}));
|
|
48615
|
+
|
|
48297
48616
|
// Used to represent 2-D points and ranges
|
|
48298
48617
|
const pairOfNumbers = pair(number, number);
|
|
48299
48618
|
const parsePerseusGraphTypeAngle = object({
|
|
@@ -48480,6 +48799,195 @@ const parseInteractiveGraphWidget = parseWidget(constant("interactive-graph"), o
|
|
|
48480
48799
|
fullGraphAriaDescription: optional(string)
|
|
48481
48800
|
}));
|
|
48482
48801
|
|
|
48802
|
+
const parseLabelImageWidget = parseWidget(constant("label-image"), object({
|
|
48803
|
+
choices: array(string),
|
|
48804
|
+
imageUrl: string,
|
|
48805
|
+
imageAlt: string,
|
|
48806
|
+
imageHeight: number,
|
|
48807
|
+
imageWidth: number,
|
|
48808
|
+
markers: array(object({
|
|
48809
|
+
answers: array(string),
|
|
48810
|
+
label: string,
|
|
48811
|
+
x: number,
|
|
48812
|
+
y: number
|
|
48813
|
+
})),
|
|
48814
|
+
hideChoicesFromInstructions: boolean,
|
|
48815
|
+
multipleAnswers: boolean,
|
|
48816
|
+
static: boolean
|
|
48817
|
+
}));
|
|
48818
|
+
|
|
48819
|
+
const parseMatcherWidget = parseWidget(constant("matcher"), object({
|
|
48820
|
+
labels: array(string),
|
|
48821
|
+
left: array(string),
|
|
48822
|
+
right: array(string),
|
|
48823
|
+
orderMatters: boolean,
|
|
48824
|
+
padding: boolean
|
|
48825
|
+
}));
|
|
48826
|
+
|
|
48827
|
+
const parseMatrixWidget = parseWidget(constant("matrix"), object({
|
|
48828
|
+
prefix: string,
|
|
48829
|
+
suffix: string,
|
|
48830
|
+
answers: array(array(number)),
|
|
48831
|
+
cursorPosition: array(number),
|
|
48832
|
+
matrixBoardSize: array(number),
|
|
48833
|
+
static: boolean
|
|
48834
|
+
}));
|
|
48835
|
+
|
|
48836
|
+
const parseMeasurerWidget = parseWidget(constant("measurer"), object({
|
|
48837
|
+
image: parsePerseusImageBackground,
|
|
48838
|
+
showProtractor: boolean,
|
|
48839
|
+
showRuler: boolean,
|
|
48840
|
+
rulerLabel: string,
|
|
48841
|
+
rulerTicks: number,
|
|
48842
|
+
rulerPixels: number,
|
|
48843
|
+
rulerLength: number,
|
|
48844
|
+
box: pair(number, number),
|
|
48845
|
+
static: boolean
|
|
48846
|
+
}));
|
|
48847
|
+
|
|
48848
|
+
const parseMoleculeRendererWidget = parseWidget(constant("molecule-renderer"), object({
|
|
48849
|
+
widgetId: string,
|
|
48850
|
+
rotationAngle: optional(number),
|
|
48851
|
+
smiles: optional(string)
|
|
48852
|
+
}));
|
|
48853
|
+
|
|
48854
|
+
const parseNumberLineWidget = parseWidget(constant("number-line"), object({
|
|
48855
|
+
range: array(number),
|
|
48856
|
+
labelRange: array(nullable(number)),
|
|
48857
|
+
labelStyle: string,
|
|
48858
|
+
labelTicks: boolean,
|
|
48859
|
+
isTickCtrl: optional(nullable(boolean)),
|
|
48860
|
+
divisionRange: array(number),
|
|
48861
|
+
numDivisions: optional(nullable(number)),
|
|
48862
|
+
snapDivisions: number,
|
|
48863
|
+
tickStep: optional(nullable(number)),
|
|
48864
|
+
correctRel: optional(nullable(string)),
|
|
48865
|
+
correctX: number,
|
|
48866
|
+
initialX: optional(nullable(number)),
|
|
48867
|
+
showTooltip: optional(boolean),
|
|
48868
|
+
static: boolean
|
|
48869
|
+
}));
|
|
48870
|
+
|
|
48871
|
+
const parseMathFormat = enumeration("integer", "mixed", "improper", "proper", "decimal", "percent", "pi");
|
|
48872
|
+
const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
|
|
48873
|
+
answers: array(object({
|
|
48874
|
+
message: string,
|
|
48875
|
+
value: number,
|
|
48876
|
+
status: string,
|
|
48877
|
+
answerForms: optional(array(parseMathFormat)),
|
|
48878
|
+
strict: boolean,
|
|
48879
|
+
maxError: optional(nullable(number)),
|
|
48880
|
+
simplify: optional(nullable(string))
|
|
48881
|
+
})),
|
|
48882
|
+
labelText: string,
|
|
48883
|
+
size: string,
|
|
48884
|
+
coefficient: boolean,
|
|
48885
|
+
rightAlign: optional(boolean),
|
|
48886
|
+
static: boolean,
|
|
48887
|
+
answerForms: optional(array(object({
|
|
48888
|
+
name: parseMathFormat,
|
|
48889
|
+
simplify: optional(nullable(enumeration("required", "correct", "enforced", "optional")))
|
|
48890
|
+
})))
|
|
48891
|
+
}));
|
|
48892
|
+
|
|
48893
|
+
// There is an import cycle between orderer-widget.ts and perseus-renderer.ts.
|
|
48894
|
+
// This wrapper ensures that we don't refer to parsePerseusRenderer before
|
|
48895
|
+
// it's defined.
|
|
48896
|
+
function parseRenderer(rawValue, ctx) {
|
|
48897
|
+
return parsePerseusRenderer(rawValue, ctx);
|
|
48898
|
+
}
|
|
48899
|
+
const parseOrdererWidget = parseWidget(constant("orderer"), object({
|
|
48900
|
+
options: array(parseRenderer),
|
|
48901
|
+
correctOptions: array(parseRenderer),
|
|
48902
|
+
otherOptions: array(parseRenderer),
|
|
48903
|
+
height: string,
|
|
48904
|
+
layout: string
|
|
48905
|
+
}));
|
|
48906
|
+
|
|
48907
|
+
const parsePassageRefWidget = parseWidget(constant("passage-ref"), object({
|
|
48908
|
+
passageNumber: number,
|
|
48909
|
+
referenceNumber: number,
|
|
48910
|
+
summaryText: string
|
|
48911
|
+
}));
|
|
48912
|
+
|
|
48913
|
+
const parsePassageWidget = parseWidget(constant("passage"), object({
|
|
48914
|
+
footnotes: string,
|
|
48915
|
+
passageText: string,
|
|
48916
|
+
passageTitle: string,
|
|
48917
|
+
showLineNumbers: boolean,
|
|
48918
|
+
static: boolean
|
|
48919
|
+
}));
|
|
48920
|
+
|
|
48921
|
+
const parsePhetSimulationWidget = parseWidget(constant("phet-simulation"), object({
|
|
48922
|
+
url: string,
|
|
48923
|
+
description: string
|
|
48924
|
+
}));
|
|
48925
|
+
|
|
48926
|
+
const parsePlotterWidget = parseWidget(constant("plotter"), object({
|
|
48927
|
+
labels: array(string),
|
|
48928
|
+
categories: array(string),
|
|
48929
|
+
type: enumeration(...plotterPlotTypes),
|
|
48930
|
+
maxY: number,
|
|
48931
|
+
scaleY: number,
|
|
48932
|
+
labelInterval: optional(nullable(number)),
|
|
48933
|
+
snapsPerLine: number,
|
|
48934
|
+
starting: array(number),
|
|
48935
|
+
correct: array(number),
|
|
48936
|
+
picUrl: optional(nullable(string)),
|
|
48937
|
+
picSize: optional(nullable(number)),
|
|
48938
|
+
picBoxHeight: optional(nullable(number)),
|
|
48939
|
+
plotDimensions: array(number)
|
|
48940
|
+
}));
|
|
48941
|
+
|
|
48942
|
+
const parsePythonProgramWidget = parseWidget(constant("python-program"), object({
|
|
48943
|
+
programID: string,
|
|
48944
|
+
height: number
|
|
48945
|
+
}));
|
|
48946
|
+
|
|
48947
|
+
const parseRadioWidget = parseWidget(constant("radio"), object({
|
|
48948
|
+
choices: array(object({
|
|
48949
|
+
content: string,
|
|
48950
|
+
clue: optional(string),
|
|
48951
|
+
correct: optional(boolean),
|
|
48952
|
+
isNoneOfTheAbove: optional(boolean),
|
|
48953
|
+
// deprecated
|
|
48954
|
+
// There is an import cycle between radio-widget.ts and
|
|
48955
|
+
// widgets-map.ts. The anonymous function below ensures that we
|
|
48956
|
+
// don't refer to parseWidgetsMap before it's defined.
|
|
48957
|
+
widgets: optional((rawVal, ctx) => parseWidgetsMap(rawVal, ctx))
|
|
48958
|
+
})),
|
|
48959
|
+
hasNoneOfTheAbove: optional(boolean),
|
|
48960
|
+
countChoices: optional(boolean),
|
|
48961
|
+
randomize: optional(boolean),
|
|
48962
|
+
multipleSelect: optional(boolean),
|
|
48963
|
+
deselectEnabled: optional(boolean),
|
|
48964
|
+
// deprecated
|
|
48965
|
+
onePerLine: optional(boolean),
|
|
48966
|
+
// deprecated
|
|
48967
|
+
displayCount: optional(any),
|
|
48968
|
+
// v0 props
|
|
48969
|
+
// `noneOfTheAbove` is still in use (but only set to `false`).
|
|
48970
|
+
noneOfTheAbove: constant(false)
|
|
48971
|
+
}));
|
|
48972
|
+
|
|
48973
|
+
const parseSorterWidget = parseWidget(constant("sorter"), object({
|
|
48974
|
+
correct: array(string),
|
|
48975
|
+
padding: boolean,
|
|
48976
|
+
layout: enumeration("horizontal", "vertical")
|
|
48977
|
+
}));
|
|
48978
|
+
|
|
48979
|
+
const parseTableWidget = parseWidget(constant("table"), object({
|
|
48980
|
+
headers: array(string),
|
|
48981
|
+
rows: number,
|
|
48982
|
+
columns: number,
|
|
48983
|
+
answers: array(array(string))
|
|
48984
|
+
}));
|
|
48985
|
+
|
|
48986
|
+
const parseVideoWidget = parseWidget(constant("video"), object({
|
|
48987
|
+
location: string,
|
|
48988
|
+
static: optional(boolean)
|
|
48989
|
+
}));
|
|
48990
|
+
|
|
48483
48991
|
const parseWidgetsMap = (rawValue, ctx) => {
|
|
48484
48992
|
if (!isObject(rawValue)) {
|
|
48485
48993
|
return ctx.failure("PerseusWidgetsMap", rawValue);
|
|
@@ -48524,86 +49032,67 @@ const parseWidgetsMapEntry = ([key, widget], widgetMap, ctx) => {
|
|
|
48524
49032
|
case "expression":
|
|
48525
49033
|
return parseAndAssign(`expression ${id}`, parseExpressionWidget);
|
|
48526
49034
|
case "grapher":
|
|
48527
|
-
|
|
48528
|
-
return parseAndAssign(`grapher ${id}`, any);
|
|
49035
|
+
return parseAndAssign(`grapher ${id}`, parseGrapherWidget);
|
|
48529
49036
|
case "group":
|
|
48530
|
-
|
|
48531
|
-
return parseAndAssign(`group ${id}`, any);
|
|
49037
|
+
return parseAndAssign(`group ${id}`, parseGroupWidget);
|
|
48532
49038
|
case "graded-group":
|
|
48533
|
-
|
|
48534
|
-
return parseAndAssign(`graded-group ${id}`, any);
|
|
49039
|
+
return parseAndAssign(`graded-group ${id}`, parseGradedGroupWidget);
|
|
48535
49040
|
case "graded-group-set":
|
|
48536
|
-
|
|
48537
|
-
return parseAndAssign(`graded-group-set ${id}`, any);
|
|
49041
|
+
return parseAndAssign(`graded-group-set ${id}`, parseGradedGroupSetWidget);
|
|
48538
49042
|
case "iframe":
|
|
48539
|
-
|
|
48540
|
-
return parseAndAssign(`iframe ${id}`, any);
|
|
49043
|
+
return parseAndAssign(`iframe ${id}`, parseIframeWidget);
|
|
48541
49044
|
case "image":
|
|
48542
|
-
|
|
48543
|
-
return parseAndAssign(`image ${id}`, any);
|
|
49045
|
+
return parseAndAssign(`image ${id}`, parseImageWidget);
|
|
48544
49046
|
case "input-number":
|
|
48545
|
-
|
|
48546
|
-
return parseAndAssign(`input-number ${id}`, any);
|
|
49047
|
+
return parseAndAssign(`input-number ${id}`, parseInputNumberWidget);
|
|
48547
49048
|
case "interaction":
|
|
48548
|
-
|
|
48549
|
-
return parseAndAssign(`interaction ${id}`, any);
|
|
49049
|
+
return parseAndAssign(`interaction ${id}`, parseInteractionWidget);
|
|
48550
49050
|
case "interactive-graph":
|
|
48551
49051
|
return parseAndAssign(`interactive-graph ${id}`, parseInteractiveGraphWidget);
|
|
48552
49052
|
case "label-image":
|
|
48553
|
-
|
|
48554
|
-
return parseAndAssign(`label-image ${id}`, any);
|
|
49053
|
+
return parseAndAssign(`label-image ${id}`, parseLabelImageWidget);
|
|
48555
49054
|
case "matcher":
|
|
48556
|
-
|
|
48557
|
-
return parseAndAssign(`matcher ${id}`, any);
|
|
49055
|
+
return parseAndAssign(`matcher ${id}`, parseMatcherWidget);
|
|
48558
49056
|
case "matrix":
|
|
48559
|
-
|
|
48560
|
-
return parseAndAssign(`matrix ${id}`, any);
|
|
49057
|
+
return parseAndAssign(`matrix ${id}`, parseMatrixWidget);
|
|
48561
49058
|
case "measurer":
|
|
48562
|
-
|
|
48563
|
-
return parseAndAssign(`measurer ${id}`, any);
|
|
49059
|
+
return parseAndAssign(`measurer ${id}`, parseMeasurerWidget);
|
|
48564
49060
|
case "molecule-renderer":
|
|
48565
|
-
|
|
48566
|
-
return parseAndAssign(`molecule-renderer ${id}`, any);
|
|
49061
|
+
return parseAndAssign(`molecule-renderer ${id}`, parseMoleculeRendererWidget);
|
|
48567
49062
|
case "number-line":
|
|
48568
|
-
|
|
48569
|
-
return parseAndAssign(`number-line ${id}`, any);
|
|
49063
|
+
return parseAndAssign(`number-line ${id}`, parseNumberLineWidget);
|
|
48570
49064
|
case "numeric-input":
|
|
48571
|
-
|
|
48572
|
-
return parseAndAssign(`numeric-input ${id}`, any);
|
|
49065
|
+
return parseAndAssign(`numeric-input ${id}`, parseNumericInputWidget);
|
|
48573
49066
|
case "orderer":
|
|
48574
|
-
|
|
48575
|
-
return parseAndAssign(`orderer ${id}`, any);
|
|
49067
|
+
return parseAndAssign(`orderer ${id}`, parseOrdererWidget);
|
|
48576
49068
|
case "passage":
|
|
48577
|
-
|
|
48578
|
-
return parseAndAssign(`passage ${id}`, any);
|
|
49069
|
+
return parseAndAssign(`passage ${id}`, parsePassageWidget);
|
|
48579
49070
|
case "passage-ref":
|
|
48580
|
-
|
|
48581
|
-
return parseAndAssign(`passage-ref ${id}`, any);
|
|
49071
|
+
return parseAndAssign(`passage-ref ${id}`, parsePassageRefWidget);
|
|
48582
49072
|
case "passage-ref-target":
|
|
48583
|
-
//
|
|
49073
|
+
// NOTE(benchristel): as of 2024-11-12, passage-ref-target is only
|
|
49074
|
+
// used in test content. See:
|
|
49075
|
+
// https://www.khanacademy.org/devadmin/content/search?query=widget:passage-ref-target
|
|
48584
49076
|
return parseAndAssign(`passage-ref-target ${id}`, any);
|
|
48585
49077
|
case "phet-simulation":
|
|
48586
|
-
|
|
48587
|
-
return parseAndAssign(`phet-simulation ${id}`, any);
|
|
49078
|
+
return parseAndAssign(`phet-simulation ${id}`, parsePhetSimulationWidget);
|
|
48588
49079
|
case "plotter":
|
|
48589
|
-
|
|
48590
|
-
return parseAndAssign(`plotter ${id}`, any);
|
|
49080
|
+
return parseAndAssign(`plotter ${id}`, parsePlotterWidget);
|
|
48591
49081
|
case "python-program":
|
|
48592
|
-
|
|
48593
|
-
return parseAndAssign(`python-program ${id}`, any);
|
|
49082
|
+
return parseAndAssign(`python-program ${id}`, parsePythonProgramWidget);
|
|
48594
49083
|
case "radio":
|
|
48595
|
-
|
|
48596
|
-
return parseAndAssign(`radio ${id}`, any);
|
|
49084
|
+
return parseAndAssign(`radio ${id}`, parseRadioWidget);
|
|
48597
49085
|
case "sorter":
|
|
48598
|
-
|
|
48599
|
-
return parseAndAssign(`sorter ${id}`, any);
|
|
49086
|
+
return parseAndAssign(`sorter ${id}`, parseSorterWidget);
|
|
48600
49087
|
case "table":
|
|
48601
|
-
|
|
48602
|
-
return parseAndAssign(`table ${id}`, any);
|
|
49088
|
+
return parseAndAssign(`table ${id}`, parseTableWidget);
|
|
48603
49089
|
case "video":
|
|
48604
|
-
|
|
48605
|
-
return parseAndAssign(`video ${id}`, any);
|
|
49090
|
+
return parseAndAssign(`video ${id}`, parseVideoWidget);
|
|
48606
49091
|
default:
|
|
49092
|
+
if (getWidget(type)) {
|
|
49093
|
+
// @ts-expect-error - 'type' is not a valid widget type
|
|
49094
|
+
return parseAndAssign(`${type} ${id}`, any);
|
|
49095
|
+
}
|
|
48607
49096
|
return ctx.failure("a valid widget type", type);
|
|
48608
49097
|
}
|
|
48609
49098
|
};
|
|
@@ -48626,16 +49115,6 @@ const parseHint = object({
|
|
|
48626
49115
|
}))
|
|
48627
49116
|
});
|
|
48628
49117
|
|
|
48629
|
-
const parsePerseusRenderer = object({
|
|
48630
|
-
content: string,
|
|
48631
|
-
widgets: parseWidgetsMap,
|
|
48632
|
-
metadata: optional(array(string)),
|
|
48633
|
-
images: record(string, object({
|
|
48634
|
-
width: number,
|
|
48635
|
-
height: number
|
|
48636
|
-
}))
|
|
48637
|
-
});
|
|
48638
|
-
|
|
48639
49118
|
object({
|
|
48640
49119
|
question: parsePerseusRenderer,
|
|
48641
49120
|
hints: array(parseHint),
|