@khanacademy/perseus 43.0.1 → 43.1.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 +5 -3
- package/dist/components/text-input.d.ts +4 -2
- package/dist/es/index.js +433 -238
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +424 -229
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +14 -7
- package/dist/util/parse-perseus-json/general-purpose-parsers/defaulted.d.ts +1 -1
- package/dist/util/parse-perseus-json/general-purpose-parsers/index.d.ts +2 -0
- package/dist/util/parse-perseus-json/general-purpose-parsers/pipe-parsers.d.ts +7 -0
- package/dist/util/parse-perseus-json/general-purpose-parsers/pipe-parsers.typetest.d.ts +1 -0
- package/dist/util/parse-perseus-json/general-purpose-parsers/unknown.d.ts +2 -0
- package/dist/util/parse-perseus-json/perseus-parsers/images-map.d.ts +5 -0
- package/dist/util/parse-perseus-json/perseus-parsers/widget.d.ts +4 -0
- package/dist/validation.types.d.ts +14 -6
- package/dist/widgets/categorizer/categorizer.d.ts +2 -2
- package/dist/widgets/categorizer/score-categorizer.d.ts +2 -2
- package/dist/widgets/categorizer/validate-categorizer.d.ts +15 -0
- package/dist/widgets/dropdown/validate-dropdown.d.ts +10 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +11 -7
- package/dist/widgets/interactive-graphs/graphs/components/use-control-point.d.ts +7 -3
- package/dist/widgets/interactive-graphs/types.d.ts +1 -0
- package/dist/widgets/matrix/matrix.d.ts +12 -5
- package/dist/widgets/measurer/measurer.d.ts +1 -1
- package/dist/widgets/orderer/validate-orderer.d.ts +12 -0
- package/dist/widgets/plotter/plotter.d.ts +2 -2
- package/dist/widgets/plotter/score-plotter.d.ts +2 -2
- package/dist/widgets/plotter/validate-plotter.d.ts +12 -0
- package/dist/widgets/radio/radio.d.ts +1 -1
- package/dist/widgets/radio/validate-radio.d.ts +14 -0
- package/dist/widgets/sorter/validate-sorter.d.ts +13 -0
- package/package.json +4 -4
- package/dist/util/parse-perseus-json/general-purpose-parsers/compose-parsers.d.ts +0 -2
package/dist/es/index.js
CHANGED
|
@@ -2760,8 +2760,6 @@ async function getImageSizeModern(url) {
|
|
|
2760
2760
|
});
|
|
2761
2761
|
}
|
|
2762
2762
|
|
|
2763
|
-
/* eslint-disable @babel/no-invalid-this, getter-return, one-var */
|
|
2764
|
-
|
|
2765
2763
|
// TODO: dedupe this with Coord in interactive2/types.js
|
|
2766
2764
|
|
|
2767
2765
|
let supportsPassive = false;
|
|
@@ -2837,8 +2835,8 @@ function shuffle$3(array, randomSeed, ensurePermuted = false) {
|
|
|
2837
2835
|
do {
|
|
2838
2836
|
// Fischer-Yates shuffle
|
|
2839
2837
|
for (let top = shuffled.length; top > 0; top--) {
|
|
2840
|
-
const newEnd = Math.floor(random() * top)
|
|
2841
|
-
|
|
2838
|
+
const newEnd = Math.floor(random() * top);
|
|
2839
|
+
const temp = shuffled[newEnd];
|
|
2842
2840
|
|
|
2843
2841
|
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
2844
2842
|
shuffled[newEnd] = shuffled[top - 1];
|
|
@@ -3170,13 +3168,13 @@ function eq$4(x, y) {
|
|
|
3170
3168
|
* Deep approximate equality on primitives, numbers, arrays, and objects.
|
|
3171
3169
|
* Recursive.
|
|
3172
3170
|
*/
|
|
3173
|
-
function deepEq$
|
|
3171
|
+
function deepEq$7(x, y) {
|
|
3174
3172
|
if (Array.isArray(x) && Array.isArray(y)) {
|
|
3175
3173
|
if (x.length !== y.length) {
|
|
3176
3174
|
return false;
|
|
3177
3175
|
}
|
|
3178
3176
|
for (let i = 0; i < x.length; i++) {
|
|
3179
|
-
if (!deepEq$
|
|
3177
|
+
if (!deepEq$7(x[i], y[i])) {
|
|
3180
3178
|
return false;
|
|
3181
3179
|
}
|
|
3182
3180
|
}
|
|
@@ -3194,10 +3192,10 @@ function deepEq$6(x, y) {
|
|
|
3194
3192
|
if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
|
|
3195
3193
|
return x === y || _.all(x, function (v, k) {
|
|
3196
3194
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
3197
|
-
return deepEq$
|
|
3195
|
+
return deepEq$7(y[k], v);
|
|
3198
3196
|
}) && _.all(y, function (v, k) {
|
|
3199
3197
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
3200
|
-
return deepEq$
|
|
3198
|
+
return deepEq$7(x[k], v);
|
|
3201
3199
|
});
|
|
3202
3200
|
}
|
|
3203
3201
|
if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
|
|
@@ -3478,7 +3476,7 @@ const Util = {
|
|
|
3478
3476
|
tickStepFromNumTicks,
|
|
3479
3477
|
constrainedTickStepsFromTickSteps,
|
|
3480
3478
|
eq: eq$4,
|
|
3481
|
-
deepEq: deepEq$
|
|
3479
|
+
deepEq: deepEq$7,
|
|
3482
3480
|
parseQueryString,
|
|
3483
3481
|
updateQueryString: updateQueryString$2,
|
|
3484
3482
|
strongEncodeURIComponent,
|
|
@@ -10509,7 +10507,9 @@ const getClipPoint = function getClipPoint(graph, coord, angle) {
|
|
|
10509
10507
|
return clipPoint;
|
|
10510
10508
|
};
|
|
10511
10509
|
|
|
10512
|
-
|
|
10510
|
+
/**
|
|
10511
|
+
* Default methods for a wrapped movable.
|
|
10512
|
+
*/
|
|
10513
10513
|
|
|
10514
10514
|
/*
|
|
10515
10515
|
* attr() and animate() simply pass the
|
|
@@ -10767,7 +10767,7 @@ class WrappedLine extends WrappedDrawing {
|
|
|
10767
10767
|
*/
|
|
10768
10768
|
const {
|
|
10769
10769
|
eq: eq$3,
|
|
10770
|
-
deepEq: deepEq$
|
|
10770
|
+
deepEq: deepEq$6
|
|
10771
10771
|
} = Util;
|
|
10772
10772
|
|
|
10773
10773
|
// This should really be a readonly tuple of [number, number]
|
|
@@ -10927,7 +10927,7 @@ function similar(coords1, coords2, tolerance) {
|
|
|
10927
10927
|
angles = rotate(angles, i);
|
|
10928
10928
|
// @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
|
|
10929
10929
|
sides = rotate(sides, i);
|
|
10930
|
-
if (deepEq$
|
|
10930
|
+
if (deepEq$6(angles1, angles)) {
|
|
10931
10931
|
const sidePairs = _.zip(sides1, sides);
|
|
10932
10932
|
const factors = _.map(sidePairs, function (pair) {
|
|
10933
10933
|
return pair[0] / pair[1];
|
|
@@ -13865,7 +13865,7 @@ _.extend(MovableAngle.prototype, {
|
|
|
13865
13865
|
|
|
13866
13866
|
/* eslint-disable @babel/no-invalid-this */
|
|
13867
13867
|
const nestedMap$1 = Util.nestedMap;
|
|
13868
|
-
const deepEq$
|
|
13868
|
+
const deepEq$5 = Util.deepEq;
|
|
13869
13869
|
|
|
13870
13870
|
/**
|
|
13871
13871
|
* A base class for all Graphie Movables
|
|
@@ -13962,7 +13962,7 @@ const createSimpleClass = function createSimpleClass(addFunction) {
|
|
|
13962
13962
|
this._prevProps = this.props;
|
|
13963
13963
|
},
|
|
13964
13964
|
modify: function (graphie) {
|
|
13965
|
-
if (!deepEq$
|
|
13965
|
+
if (!deepEq$5(this.props, this._prevProps)) {
|
|
13966
13966
|
this.remove();
|
|
13967
13967
|
this.add(graphie);
|
|
13968
13968
|
this._prevProps = this.props;
|
|
@@ -16576,7 +16576,7 @@ var Movables = {
|
|
|
16576
16576
|
const GraphieMovable = GraphieClasses.GraphieMovable;
|
|
16577
16577
|
const createGraphie = GraphUtils.createGraphie;
|
|
16578
16578
|
const {
|
|
16579
|
-
deepEq: deepEq$
|
|
16579
|
+
deepEq: deepEq$4,
|
|
16580
16580
|
nestedMap
|
|
16581
16581
|
} = Util;
|
|
16582
16582
|
const {
|
|
@@ -16818,7 +16818,7 @@ class Graphie extends React.Component {
|
|
|
16818
16818
|
if (this.props.setup !== prevProps.setup) {
|
|
16819
16819
|
Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", Errors.Internal);
|
|
16820
16820
|
}
|
|
16821
|
-
if (!deepEq$
|
|
16821
|
+
if (!deepEq$4(this.props.options, prevProps.options) || !deepEq$4(this.props.box, prevProps.box) || !deepEq$4(this.props.range, prevProps.range)) {
|
|
16822
16822
|
this._setupGraphie();
|
|
16823
16823
|
}
|
|
16824
16824
|
this._updateMovables();
|
|
@@ -18536,7 +18536,7 @@ const rules$1 = _extends({}, pureMarkdownRules, {
|
|
|
18536
18536
|
// The href prop should always be here, but just in case somehow the article's
|
|
18537
18537
|
// link was not put together properly, let's make sure it's there so we
|
|
18538
18538
|
// don't break the entire page.
|
|
18539
|
-
const isKAUrl = href ? href.match(/https?:\/\/[
|
|
18539
|
+
const isKAUrl = href ? href.match(/https?:\/\/[^/]*khanacademy.org|^\//) : false;
|
|
18540
18540
|
if (!isKAUrl) {
|
|
18541
18541
|
// Prevents "reverse tabnabbing" phishing attacks
|
|
18542
18542
|
// @ts-expect-error - TS2322 - Type '"noopener noreferrer"' is not assignable to type 'null'.
|
|
@@ -20889,36 +20889,36 @@ function uniqueIdForInput(prefix = "input-") {
|
|
|
20889
20889
|
class TextInput extends React.Component {
|
|
20890
20890
|
constructor(props) {
|
|
20891
20891
|
super(props);
|
|
20892
|
+
this.inputRef = /*#__PURE__*/React.createRef();
|
|
20892
20893
|
this.id = void 0;
|
|
20894
|
+
this._getInput = () => {
|
|
20895
|
+
if (!this.inputRef.current) {
|
|
20896
|
+
throw new PerseusError("Input ref accessed before set", Errors.Internal);
|
|
20897
|
+
}
|
|
20898
|
+
return this.inputRef.current;
|
|
20899
|
+
};
|
|
20893
20900
|
this.focus = () => {
|
|
20894
|
-
|
|
20895
|
-
ReactDOM__default.findDOMNode(this).focus();
|
|
20901
|
+
this._getInput().focus();
|
|
20896
20902
|
};
|
|
20897
20903
|
this.blur = () => {
|
|
20898
|
-
|
|
20899
|
-
ReactDOM__default.findDOMNode(this).blur();
|
|
20904
|
+
this._getInput().blur();
|
|
20900
20905
|
};
|
|
20901
20906
|
this.getValue = () => {
|
|
20902
|
-
var
|
|
20903
|
-
|
|
20904
|
-
return (_ReactDOM$findDOMNode = ReactDOM__default.findDOMNode(this)) == null ? void 0 : _ReactDOM$findDOMNode.value;
|
|
20907
|
+
var _this$inputRef$curren;
|
|
20908
|
+
return (_this$inputRef$curren = this.inputRef.current) == null ? void 0 : _this$inputRef$curren.value;
|
|
20905
20909
|
};
|
|
20906
20910
|
this.getStringValue = () => {
|
|
20907
|
-
var
|
|
20908
|
-
|
|
20909
|
-
return (_ReactDOM$findDOMNode2 = ReactDOM__default.findDOMNode(this)) == null ? void 0 : _ReactDOM$findDOMNode2.value.toString();
|
|
20911
|
+
var _this$inputRef$curren2;
|
|
20912
|
+
return (_this$inputRef$curren2 = this.inputRef.current) == null ? void 0 : _this$inputRef$curren2.value.toString();
|
|
20910
20913
|
};
|
|
20911
20914
|
this.setSelectionRange = (selectionStart, selectionEnd) => {
|
|
20912
|
-
|
|
20913
|
-
ReactDOM__default.findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
|
|
20915
|
+
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
20914
20916
|
};
|
|
20915
20917
|
this.getSelectionStart = () => {
|
|
20916
|
-
|
|
20917
|
-
return ReactDOM__default.findDOMNode(this).selectionStart;
|
|
20918
|
+
return this._getInput().selectionStart;
|
|
20918
20919
|
};
|
|
20919
20920
|
this.getSelectionEnd = () => {
|
|
20920
|
-
|
|
20921
|
-
return ReactDOM__default.findDOMNode(this).selectionEnd;
|
|
20921
|
+
return this._getInput().selectionEnd;
|
|
20922
20922
|
};
|
|
20923
20923
|
if (props.id) {
|
|
20924
20924
|
this.id = props.id;
|
|
@@ -20939,6 +20939,7 @@ class TextInput extends React.Component {
|
|
|
20939
20939
|
} = this.props;
|
|
20940
20940
|
const formattedValue = value === null ? "" : value.toString();
|
|
20941
20941
|
return /*#__PURE__*/React.createElement(TextField, {
|
|
20942
|
+
ref: this.inputRef,
|
|
20942
20943
|
style: style,
|
|
20943
20944
|
disabled: disabled,
|
|
20944
20945
|
id: this.id,
|
|
@@ -20973,7 +20974,7 @@ function _objectWithoutPropertiesLoose(r, e) {
|
|
|
20973
20974
|
return t;
|
|
20974
20975
|
}
|
|
20975
20976
|
|
|
20976
|
-
const _excluded$
|
|
20977
|
+
const _excluded$8 = ["position", "visibility", "left", "top"];
|
|
20977
20978
|
const zIndex = 10;
|
|
20978
20979
|
let HorizontalDirection = /*#__PURE__*/function (HorizontalDirection) {
|
|
20979
20980
|
HorizontalDirection["Left"] = "left";
|
|
@@ -21024,7 +21025,7 @@ const TooltipArrow = _ref => {
|
|
|
21024
21025
|
left = 100,
|
|
21025
21026
|
top = 0
|
|
21026
21027
|
} = _ref,
|
|
21027
|
-
props = _objectWithoutPropertiesLoose(_ref, _excluded$
|
|
21028
|
+
props = _objectWithoutPropertiesLoose(_ref, _excluded$8);
|
|
21028
21029
|
// TODO(aria): Think about adding a box-shadow to the triangle here
|
|
21029
21030
|
// See http://css-tricks.com/triangle-with-shadow/
|
|
21030
21031
|
|
|
@@ -21384,7 +21385,7 @@ InputWithExamples.defaultProps = {
|
|
|
21384
21385
|
className: ""
|
|
21385
21386
|
};
|
|
21386
21387
|
|
|
21387
|
-
const _excluded$
|
|
21388
|
+
const _excluded$7 = ["keypadElement", "onFocus", "value"];
|
|
21388
21389
|
class SimpleKeypadInput extends React.Component {
|
|
21389
21390
|
constructor(...args) {
|
|
21390
21391
|
super(...args);
|
|
@@ -21429,7 +21430,7 @@ class SimpleKeypadInput extends React.Component {
|
|
|
21429
21430
|
onFocus,
|
|
21430
21431
|
value
|
|
21431
21432
|
} = _this$props,
|
|
21432
|
-
rest = _objectWithoutPropertiesLoose(_this$props, _excluded$
|
|
21433
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded$7);
|
|
21433
21434
|
return (
|
|
21434
21435
|
/*#__PURE__*/
|
|
21435
21436
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
@@ -21991,7 +21992,7 @@ function maybeParsePercentInput(inputValue, normalizedAnswerExpected) {
|
|
|
21991
21992
|
return value / 100;
|
|
21992
21993
|
}
|
|
21993
21994
|
|
|
21994
|
-
// Otherwise, we return input
|
|
21995
|
+
// Otherwise, we return input value (number) stripped of the "%".
|
|
21995
21996
|
return value;
|
|
21996
21997
|
}
|
|
21997
21998
|
function scoreNumericInput(userInput, rubric, strings) {
|
|
@@ -25662,14 +25663,14 @@ var Choice$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.
|
|
|
25662
25663
|
forwardedRef: ref
|
|
25663
25664
|
})));
|
|
25664
25665
|
|
|
25665
|
-
const _excluded$
|
|
25666
|
+
const _excluded$6 = ["content", "forwardedRef", "showContent"];
|
|
25666
25667
|
const ChoiceNoneAbove = function ChoiceNoneAbove(_ref) {
|
|
25667
25668
|
let {
|
|
25668
25669
|
content,
|
|
25669
25670
|
forwardedRef,
|
|
25670
25671
|
showContent = true
|
|
25671
25672
|
} = _ref,
|
|
25672
|
-
rest = _objectWithoutPropertiesLoose(_ref, _excluded$
|
|
25673
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$6);
|
|
25673
25674
|
const {
|
|
25674
25675
|
strings
|
|
25675
25676
|
} = usePerseusI18n();
|
|
@@ -26040,7 +26041,15 @@ const styles$p = StyleSheet.create({
|
|
|
26040
26041
|
}
|
|
26041
26042
|
});
|
|
26042
26043
|
|
|
26043
|
-
|
|
26044
|
+
/**
|
|
26045
|
+
* Checks if the user has selected at least one option. Additional validation
|
|
26046
|
+
* is done in scoreRadio to check if the number of selected options is correct
|
|
26047
|
+
* and if the user has selected both a correct option and the "none of the above"
|
|
26048
|
+
* option.
|
|
26049
|
+
* @param userInput
|
|
26050
|
+
* @see `scoreRadio` for the additional validation logic and the scoring logic.
|
|
26051
|
+
*/
|
|
26052
|
+
function validateRadio(userInput) {
|
|
26044
26053
|
const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
26045
26054
|
return sum + (selected ? 1 : 0);
|
|
26046
26055
|
}, 0);
|
|
@@ -26050,6 +26059,17 @@ function scoreRadio(userInput, rubric, strings) {
|
|
|
26050
26059
|
message: null
|
|
26051
26060
|
};
|
|
26052
26061
|
}
|
|
26062
|
+
return null;
|
|
26063
|
+
}
|
|
26064
|
+
|
|
26065
|
+
function scoreRadio(userInput, rubric, strings) {
|
|
26066
|
+
const validationError = validateRadio(userInput);
|
|
26067
|
+
if (validationError) {
|
|
26068
|
+
return validationError;
|
|
26069
|
+
}
|
|
26070
|
+
const numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
26071
|
+
return sum + (selected ? 1 : 0);
|
|
26072
|
+
}, 0);
|
|
26053
26073
|
const numCorrect = rubric.choices.reduce((sum, currentChoice) => {
|
|
26054
26074
|
return currentChoice.correct ? sum + 1 : sum;
|
|
26055
26075
|
}, 0);
|
|
@@ -26426,6 +26446,7 @@ Radio$1.defaultProps = {
|
|
|
26426
26446
|
showSolutions: "none"
|
|
26427
26447
|
};
|
|
26428
26448
|
|
|
26449
|
+
const _excluded$5 = ["noneOfTheAbove"];
|
|
26429
26450
|
const {
|
|
26430
26451
|
shuffle: shuffle$2,
|
|
26431
26452
|
random
|
|
@@ -26514,17 +26535,15 @@ const transform = (widgetOptions, strings, problemNum) => {
|
|
|
26514
26535
|
};
|
|
26515
26536
|
const propUpgrades$1 = {
|
|
26516
26537
|
"1": v0props => {
|
|
26517
|
-
|
|
26518
|
-
|
|
26519
|
-
|
|
26520
|
-
|
|
26521
|
-
|
|
26522
|
-
} else {
|
|
26538
|
+
const {
|
|
26539
|
+
noneOfTheAbove
|
|
26540
|
+
} = v0props,
|
|
26541
|
+
rest = _objectWithoutPropertiesLoose(v0props, _excluded$5);
|
|
26542
|
+
if (noneOfTheAbove) {
|
|
26523
26543
|
throw new Error("radio widget v0 no longer supports auto noneOfTheAbove");
|
|
26524
26544
|
}
|
|
26525
|
-
return
|
|
26526
|
-
|
|
26527
|
-
hasNoneOfTheAbove: hasNoneOfTheAbove
|
|
26545
|
+
return _extends({}, rest, {
|
|
26546
|
+
hasNoneOfTheAbove: false
|
|
26528
26547
|
});
|
|
26529
26548
|
}
|
|
26530
26549
|
};
|
|
@@ -26562,23 +26581,36 @@ const getPromptJSON$n = (renderProps, userInput) => {
|
|
|
26562
26581
|
};
|
|
26563
26582
|
};
|
|
26564
26583
|
|
|
26565
|
-
|
|
26566
|
-
|
|
26567
|
-
|
|
26568
|
-
|
|
26569
|
-
|
|
26570
|
-
|
|
26571
|
-
|
|
26572
|
-
|
|
26573
|
-
|
|
26574
|
-
|
|
26575
|
-
|
|
26576
|
-
if (!completed) {
|
|
26584
|
+
/**
|
|
26585
|
+
* Checks userInput from the categorizer widget to see if the user has selected
|
|
26586
|
+
* a category for each item.
|
|
26587
|
+
* @param userInput - The user's input corresponding to an array of indices that
|
|
26588
|
+
* represent the selected category for each row/item.
|
|
26589
|
+
* @param validationData - An array of strings corresponding to each row/item
|
|
26590
|
+
* @param strings - Used to provide a validation message
|
|
26591
|
+
*/
|
|
26592
|
+
function validateCategorizer(userInput, validationData, strings) {
|
|
26593
|
+
const incomplete = validationData.items.some((_, i) => userInput.values[i] == null);
|
|
26594
|
+
if (incomplete) {
|
|
26577
26595
|
return {
|
|
26578
26596
|
type: "invalid",
|
|
26579
26597
|
message: strings.invalidSelection
|
|
26580
26598
|
};
|
|
26581
26599
|
}
|
|
26600
|
+
return null;
|
|
26601
|
+
}
|
|
26602
|
+
|
|
26603
|
+
function scoreCategorizer(userInput, scoringData, strings) {
|
|
26604
|
+
const validationError = validateCategorizer(userInput, scoringData, strings);
|
|
26605
|
+
if (validationError) {
|
|
26606
|
+
return validationError;
|
|
26607
|
+
}
|
|
26608
|
+
let allCorrect = true;
|
|
26609
|
+
scoringData.values.forEach((value, i) => {
|
|
26610
|
+
if (userInput.values[i] !== value) {
|
|
26611
|
+
allCorrect = false;
|
|
26612
|
+
}
|
|
26613
|
+
});
|
|
26582
26614
|
return {
|
|
26583
26615
|
type: "points",
|
|
26584
26616
|
earned: allCorrect ? 1 : 0,
|
|
@@ -27124,15 +27156,26 @@ const getPromptJSON$k = (renderProps, userInput) => {
|
|
|
27124
27156
|
};
|
|
27125
27157
|
};
|
|
27126
27158
|
|
|
27127
|
-
|
|
27128
|
-
|
|
27129
|
-
|
|
27159
|
+
/**
|
|
27160
|
+
* Checks if the user has selected an item from the dropdown before scoring.
|
|
27161
|
+
* This is shown with a userInput value / index other than 0.
|
|
27162
|
+
*/
|
|
27163
|
+
function validateDropdown(userInput) {
|
|
27164
|
+
if (userInput.value === 0) {
|
|
27130
27165
|
return {
|
|
27131
27166
|
type: "invalid",
|
|
27132
27167
|
message: null
|
|
27133
27168
|
};
|
|
27134
27169
|
}
|
|
27135
|
-
|
|
27170
|
+
return null;
|
|
27171
|
+
}
|
|
27172
|
+
|
|
27173
|
+
function scoreDropdown(userInput, rubric) {
|
|
27174
|
+
const validationError = validateDropdown(userInput);
|
|
27175
|
+
if (validationError) {
|
|
27176
|
+
return validationError;
|
|
27177
|
+
}
|
|
27178
|
+
const correct = rubric.choices[userInput.value - 1].correct;
|
|
27136
27179
|
return {
|
|
27137
27180
|
type: "points",
|
|
27138
27181
|
earned: correct ? 1 : 0,
|
|
@@ -27519,8 +27562,6 @@ const getNextState = (currentState, answerable) => {
|
|
|
27519
27562
|
}
|
|
27520
27563
|
};
|
|
27521
27564
|
|
|
27522
|
-
// exports has no 'transform'
|
|
27523
|
-
|
|
27524
27565
|
// A Graded Group is more or less a Group widget that displays a check
|
|
27525
27566
|
// answer button below the rendered content. When clicked, the widget grades
|
|
27526
27567
|
// the stuff inside and displays feedback about whether the inputted answer was
|
|
@@ -28184,7 +28225,6 @@ const getPromptJSON$g = (renderProps, userInput) => {
|
|
|
28184
28225
|
};
|
|
28185
28226
|
};
|
|
28186
28227
|
|
|
28187
|
-
/* eslint-disable one-var */
|
|
28188
28228
|
// @ts-expect-error - TS2339 - Property 'Plot' does not exist on type 'typeof Graphie'.
|
|
28189
28229
|
const Plot$1 = Graphie.Plot;
|
|
28190
28230
|
const DEFAULT_BACKGROUND_IMAGE = {
|
|
@@ -28285,14 +28325,14 @@ const Linear = _.extend({}, PlotDefaults, {
|
|
|
28285
28325
|
return [m, b];
|
|
28286
28326
|
},
|
|
28287
28327
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28288
|
-
const m = coeffs[0]
|
|
28289
|
-
|
|
28328
|
+
const m = coeffs[0];
|
|
28329
|
+
const b = coeffs[1];
|
|
28290
28330
|
return m * x + b;
|
|
28291
28331
|
},
|
|
28292
28332
|
getEquationString: function (coords) {
|
|
28293
28333
|
const coeffs = this.getCoefficients(coords);
|
|
28294
|
-
const m = coeffs[0]
|
|
28295
|
-
|
|
28334
|
+
const m = coeffs[0];
|
|
28335
|
+
const b = coeffs[1];
|
|
28296
28336
|
return "y = " + m.toFixed(3) + "x + " + b.toFixed(3);
|
|
28297
28337
|
}
|
|
28298
28338
|
});
|
|
@@ -28316,9 +28356,9 @@ const Quadratic = _.extend({}, PlotDefaults, {
|
|
|
28316
28356
|
return [a, b, c];
|
|
28317
28357
|
},
|
|
28318
28358
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28319
|
-
const a = coeffs[0]
|
|
28320
|
-
|
|
28321
|
-
|
|
28359
|
+
const a = coeffs[0];
|
|
28360
|
+
const b = coeffs[1];
|
|
28361
|
+
const c = coeffs[2];
|
|
28322
28362
|
return (a * x + b) * x + c;
|
|
28323
28363
|
},
|
|
28324
28364
|
getPropsForCoeffs: function (coeffs) {
|
|
@@ -28330,9 +28370,9 @@ const Quadratic = _.extend({}, PlotDefaults, {
|
|
|
28330
28370
|
},
|
|
28331
28371
|
getEquationString: function (coords) {
|
|
28332
28372
|
const coeffs = this.getCoefficients(coords);
|
|
28333
|
-
const a = coeffs[0]
|
|
28334
|
-
|
|
28335
|
-
|
|
28373
|
+
const a = coeffs[0];
|
|
28374
|
+
const b = coeffs[1];
|
|
28375
|
+
const c = coeffs[2];
|
|
28336
28376
|
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
28337
28377
|
}
|
|
28338
28378
|
});
|
|
@@ -28351,10 +28391,10 @@ const Sinusoid = _.extend({}, PlotDefaults, {
|
|
|
28351
28391
|
return [a, b, c, d];
|
|
28352
28392
|
},
|
|
28353
28393
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28354
|
-
const a = coeffs[0]
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28394
|
+
const a = coeffs[0];
|
|
28395
|
+
const b = coeffs[1];
|
|
28396
|
+
const c = coeffs[2];
|
|
28397
|
+
const d = coeffs[3];
|
|
28358
28398
|
return a * Math.sin(b * x - c) + d;
|
|
28359
28399
|
},
|
|
28360
28400
|
getPropsForCoeffs: function (coeffs) {
|
|
@@ -28367,10 +28407,10 @@ const Sinusoid = _.extend({}, PlotDefaults, {
|
|
|
28367
28407
|
},
|
|
28368
28408
|
getEquationString: function (coords) {
|
|
28369
28409
|
const coeffs = this.getCoefficients(coords);
|
|
28370
|
-
const a = coeffs[0]
|
|
28371
|
-
|
|
28372
|
-
|
|
28373
|
-
|
|
28410
|
+
const a = coeffs[0];
|
|
28411
|
+
const b = coeffs[1];
|
|
28412
|
+
const c = coeffs[2];
|
|
28413
|
+
const d = coeffs[3];
|
|
28374
28414
|
return "y = " + a.toFixed(3) + " sin(" + b.toFixed(3) + "x - " + c.toFixed(3) + ") + " + d.toFixed(3);
|
|
28375
28415
|
},
|
|
28376
28416
|
areEqual: function (coeffs1, coeffs2) {
|
|
@@ -28390,18 +28430,18 @@ const Tangent = _.extend({}, PlotDefaults, {
|
|
|
28390
28430
|
return [a, b, c, d];
|
|
28391
28431
|
},
|
|
28392
28432
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28393
|
-
const a = coeffs[0]
|
|
28394
|
-
|
|
28395
|
-
|
|
28396
|
-
|
|
28433
|
+
const a = coeffs[0];
|
|
28434
|
+
const b = coeffs[1];
|
|
28435
|
+
const c = coeffs[2];
|
|
28436
|
+
const d = coeffs[3];
|
|
28397
28437
|
return a * Math.tan(b * x - c) + d;
|
|
28398
28438
|
},
|
|
28399
28439
|
getEquationString: function (coords) {
|
|
28400
28440
|
const coeffs = this.getCoefficients(coords);
|
|
28401
|
-
const a = coeffs[0]
|
|
28402
|
-
|
|
28403
|
-
|
|
28404
|
-
|
|
28441
|
+
const a = coeffs[0];
|
|
28442
|
+
const b = coeffs[1];
|
|
28443
|
+
const c = coeffs[2];
|
|
28444
|
+
const d = coeffs[3];
|
|
28405
28445
|
return "y = " + a.toFixed(3) + " sin(" + b.toFixed(3) + "x - " + c.toFixed(3) + ") + " + d.toFixed(3);
|
|
28406
28446
|
},
|
|
28407
28447
|
areEqual: function (coeffs1, coeffs2) {
|
|
@@ -28460,9 +28500,9 @@ const Exponential = _.extend({}, PlotDefaults, {
|
|
|
28460
28500
|
return [a, b, c];
|
|
28461
28501
|
},
|
|
28462
28502
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28463
|
-
const a = coeffs[0]
|
|
28464
|
-
|
|
28465
|
-
|
|
28503
|
+
const a = coeffs[0];
|
|
28504
|
+
const b = coeffs[1];
|
|
28505
|
+
const c = coeffs[2];
|
|
28466
28506
|
return a * Math.exp(b * x) + c;
|
|
28467
28507
|
},
|
|
28468
28508
|
getEquationString: function (coords, asymptote) {
|
|
@@ -28470,9 +28510,9 @@ const Exponential = _.extend({}, PlotDefaults, {
|
|
|
28470
28510
|
return null;
|
|
28471
28511
|
}
|
|
28472
28512
|
const coeffs = this.getCoefficients(coords, asymptote);
|
|
28473
|
-
const a = coeffs[0]
|
|
28474
|
-
|
|
28475
|
-
|
|
28513
|
+
const a = coeffs[0];
|
|
28514
|
+
const b = coeffs[1];
|
|
28515
|
+
const c = coeffs[2];
|
|
28476
28516
|
return "y = " + a.toFixed(3) + "e^(" + b.toFixed(3) + "x) + " + c.toFixed(3);
|
|
28477
28517
|
}
|
|
28478
28518
|
});
|
|
@@ -28517,9 +28557,9 @@ const Logarithm = _.extend({}, PlotDefaults, {
|
|
|
28517
28557
|
}
|
|
28518
28558
|
},
|
|
28519
28559
|
getFunctionForCoeffs: function (coeffs, x, asymptote) {
|
|
28520
|
-
const a = coeffs[0]
|
|
28521
|
-
|
|
28522
|
-
|
|
28560
|
+
const a = coeffs[0];
|
|
28561
|
+
const b = coeffs[1];
|
|
28562
|
+
const c = coeffs[2];
|
|
28523
28563
|
return a * Math.log(b * x + c);
|
|
28524
28564
|
},
|
|
28525
28565
|
getEquationString: function (coords, asymptote) {
|
|
@@ -28527,9 +28567,9 @@ const Logarithm = _.extend({}, PlotDefaults, {
|
|
|
28527
28567
|
return null;
|
|
28528
28568
|
}
|
|
28529
28569
|
const coeffs = this.getCoefficients(coords, asymptote);
|
|
28530
|
-
const a = coeffs[0]
|
|
28531
|
-
|
|
28532
|
-
|
|
28570
|
+
const a = coeffs[0];
|
|
28571
|
+
const b = coeffs[1];
|
|
28572
|
+
const c = coeffs[2];
|
|
28533
28573
|
return "y = ln(" + a.toFixed(3) + "x + " + b.toFixed(3) + ") + " + c.toFixed(3);
|
|
28534
28574
|
}
|
|
28535
28575
|
});
|
|
@@ -28553,16 +28593,16 @@ const AbsoluteValue = _.extend({}, PlotDefaults, {
|
|
|
28553
28593
|
return [m, horizontalOffset, verticalOffset];
|
|
28554
28594
|
},
|
|
28555
28595
|
getFunctionForCoeffs: function (coeffs, x) {
|
|
28556
|
-
const m = coeffs[0]
|
|
28557
|
-
|
|
28558
|
-
|
|
28596
|
+
const m = coeffs[0];
|
|
28597
|
+
const horizontalOffset = coeffs[1];
|
|
28598
|
+
const verticalOffset = coeffs[2];
|
|
28559
28599
|
return m * Math.abs(x - horizontalOffset) + verticalOffset;
|
|
28560
28600
|
},
|
|
28561
28601
|
getEquationString: function (coords) {
|
|
28562
28602
|
const coeffs = this.getCoefficients(coords);
|
|
28563
|
-
const m = coeffs[0]
|
|
28564
|
-
|
|
28565
|
-
|
|
28603
|
+
const m = coeffs[0];
|
|
28604
|
+
const horizontalOffset = coeffs[1];
|
|
28605
|
+
const verticalOffset = coeffs[2];
|
|
28566
28606
|
return "y = " + m.toFixed(3) + "| x - " + horizontalOffset.toFixed(3) + "| + " + verticalOffset.toFixed(3);
|
|
28567
28607
|
}
|
|
28568
28608
|
});
|
|
@@ -31726,7 +31766,7 @@ const styles$e = StyleSheet.create({
|
|
|
31726
31766
|
}
|
|
31727
31767
|
});
|
|
31728
31768
|
|
|
31729
|
-
const _excluded$
|
|
31769
|
+
const _excluded$4 = ["onFormatChange", "checkValidity", "useArrowKeys"];
|
|
31730
31770
|
const {
|
|
31731
31771
|
firstNumericalParse,
|
|
31732
31772
|
captureScratchpadTouchStart
|
|
@@ -31756,22 +31796,25 @@ const getNumericFormat = KhanMath.getNumericFormat;
|
|
|
31756
31796
|
class NumberInput extends React.Component {
|
|
31757
31797
|
constructor(...args) {
|
|
31758
31798
|
super(...args);
|
|
31799
|
+
this.inputRef = /*#__PURE__*/React.createRef();
|
|
31759
31800
|
this.state = {
|
|
31760
31801
|
format: this.props.format
|
|
31761
31802
|
};
|
|
31803
|
+
this._getInput = () => {
|
|
31804
|
+
if (!this.inputRef.current) {
|
|
31805
|
+
throw new PerseusError("Input ref accessed before set", Errors.Internal);
|
|
31806
|
+
}
|
|
31807
|
+
return this.inputRef.current;
|
|
31808
|
+
};
|
|
31762
31809
|
/* Return the current "value" of this input
|
|
31763
31810
|
* If empty, it returns the placeholder (if it is a number) or null
|
|
31764
31811
|
*/
|
|
31765
31812
|
this.getValue = () => {
|
|
31766
|
-
return this.parseInputValue(
|
|
31767
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
31768
|
-
ReactDOM__default.findDOMNode(this.refs.input).value // eslint-disable-line react/no-string-refs
|
|
31769
|
-
);
|
|
31813
|
+
return this.parseInputValue(this._getInput().value);
|
|
31770
31814
|
};
|
|
31771
31815
|
/* Return the current string value of this input */
|
|
31772
31816
|
this.getStringValue = () => {
|
|
31773
|
-
|
|
31774
|
-
return ReactDOM__default.findDOMNode(this.refs.input).value.toString(); // eslint-disable-line react/no-string-refs
|
|
31817
|
+
return this._getInput().toString();
|
|
31775
31818
|
};
|
|
31776
31819
|
this.parseInputValue = value => {
|
|
31777
31820
|
if (value === "") {
|
|
@@ -31783,26 +31826,21 @@ class NumberInput extends React.Component {
|
|
|
31783
31826
|
};
|
|
31784
31827
|
/* Set text input focus to this input */
|
|
31785
31828
|
this.focus = () => {
|
|
31786
|
-
|
|
31787
|
-
ReactDOM__default.findDOMNode(this.refs.input).focus(); // eslint-disable-line react/no-string-refs
|
|
31829
|
+
this._getInput().focus();
|
|
31788
31830
|
this._handleFocus();
|
|
31789
31831
|
};
|
|
31790
31832
|
this.blur = () => {
|
|
31791
|
-
|
|
31792
|
-
ReactDOM__default.findDOMNode(this.refs.input).blur(); // eslint-disable-line react/no-string-refs
|
|
31833
|
+
this._getInput().blur();
|
|
31793
31834
|
this._handleBlur();
|
|
31794
31835
|
};
|
|
31795
31836
|
this.setSelectionRange = (selectionStart, selectionEnd) => {
|
|
31796
|
-
|
|
31797
|
-
ReactDOM__default.findDOMNode(this).setSelectionRange(selectionStart, selectionEnd);
|
|
31837
|
+
this._getInput().setSelectionRange(selectionStart, selectionEnd);
|
|
31798
31838
|
};
|
|
31799
31839
|
this.getSelectionStart = () => {
|
|
31800
|
-
|
|
31801
|
-
return ReactDOM__default.findDOMNode(this).selectionStart;
|
|
31840
|
+
return this._getInput().selectionStart;
|
|
31802
31841
|
};
|
|
31803
31842
|
this.getSelectionEnd = () => {
|
|
31804
|
-
|
|
31805
|
-
return ReactDOM__default.findDOMNode(this).selectionEnd;
|
|
31843
|
+
return this._getInput().selectionEnd;
|
|
31806
31844
|
};
|
|
31807
31845
|
this._checkValidity = value => {
|
|
31808
31846
|
if (value == null) {
|
|
@@ -31862,9 +31900,7 @@ class NumberInput extends React.Component {
|
|
|
31862
31900
|
}
|
|
31863
31901
|
};
|
|
31864
31902
|
this._setValue = (val, format) => {
|
|
31865
|
-
|
|
31866
|
-
// @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'val' does not exist on type 'JQueryStatic'.
|
|
31867
|
-
$(ReactDOM__default.findDOMNode(this.refs.input)).val(toNumericString(val, format));
|
|
31903
|
+
this._getInput().value = toNumericString(val, format);
|
|
31868
31904
|
};
|
|
31869
31905
|
}
|
|
31870
31906
|
componentDidUpdate(prevProps) {
|
|
@@ -31884,13 +31920,11 @@ class NumberInput extends React.Component {
|
|
|
31884
31920
|
classes = classes + " " + this.props.className;
|
|
31885
31921
|
}
|
|
31886
31922
|
const _this$props = this.props,
|
|
31887
|
-
restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$
|
|
31923
|
+
restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$4);
|
|
31888
31924
|
return /*#__PURE__*/React.createElement("input", _extends({}, restProps, {
|
|
31889
31925
|
className: classes,
|
|
31890
|
-
type: "text"
|
|
31891
|
-
|
|
31892
|
-
,
|
|
31893
|
-
ref: "input",
|
|
31926
|
+
type: "text",
|
|
31927
|
+
ref: this.inputRef,
|
|
31894
31928
|
onChange: this._handleChange,
|
|
31895
31929
|
onFocus: this._handleFocus,
|
|
31896
31930
|
onBlur: this._handleBlur,
|
|
@@ -32811,12 +32845,12 @@ const MafsCssTransformWrapper = ({
|
|
|
32811
32845
|
}
|
|
32812
32846
|
}, children);
|
|
32813
32847
|
|
|
32814
|
-
const _excluded$
|
|
32848
|
+
const _excluded$3 = ["children"];
|
|
32815
32849
|
const TextLabel = _ref => {
|
|
32816
32850
|
let {
|
|
32817
32851
|
children
|
|
32818
32852
|
} = _ref,
|
|
32819
|
-
rest = _objectWithoutPropertiesLoose(_ref, _excluded$
|
|
32853
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded$3);
|
|
32820
32854
|
return /*#__PURE__*/React__default.createElement(Text$1, _extends({
|
|
32821
32855
|
size: 16,
|
|
32822
32856
|
svgTextProps: {
|
|
@@ -33397,15 +33431,18 @@ function useControlPoint(params) {
|
|
|
33397
33431
|
} = useGraphConfig();
|
|
33398
33432
|
const {
|
|
33399
33433
|
point,
|
|
33400
|
-
|
|
33434
|
+
ariaDescribedBy,
|
|
33435
|
+
ariaLabel,
|
|
33436
|
+
ariaLive = "polite",
|
|
33401
33437
|
color,
|
|
33402
|
-
cursor,
|
|
33403
33438
|
constrain = p => snap(snapStep, p),
|
|
33439
|
+
cursor,
|
|
33440
|
+
forwardedRef = noop$1,
|
|
33441
|
+
sequenceNumber = 1,
|
|
33404
33442
|
onMove = noop$1,
|
|
33405
33443
|
onClick = noop$1,
|
|
33406
33444
|
onFocus = noop$1,
|
|
33407
|
-
onBlur = noop$1
|
|
33408
|
-
forwardedRef = noop$1
|
|
33445
|
+
onBlur = noop$1
|
|
33409
33446
|
} = params;
|
|
33410
33447
|
const {
|
|
33411
33448
|
strings,
|
|
@@ -33428,6 +33465,13 @@ function useControlPoint(params) {
|
|
|
33428
33465
|
onMove,
|
|
33429
33466
|
constrainKeyboardMovement: constrain
|
|
33430
33467
|
});
|
|
33468
|
+
|
|
33469
|
+
// if custom aria label is not provided, will use default of sequence number and point coordinates
|
|
33470
|
+
const pointAriaLabel = ariaLabel || strings.srPointAtCoordinates({
|
|
33471
|
+
num: sequenceNumber,
|
|
33472
|
+
x: srFormatNumber(point[X], locale),
|
|
33473
|
+
y: srFormatNumber(point[Y], locale)
|
|
33474
|
+
});
|
|
33431
33475
|
useLayoutEffect(() => {
|
|
33432
33476
|
setForwardedRef(forwardedRef, focusableHandleRef.current);
|
|
33433
33477
|
}, [forwardedRef]);
|
|
@@ -33437,15 +33481,9 @@ function useControlPoint(params) {
|
|
|
33437
33481
|
tabIndex: disableKeyboardInteraction ? -1 : 0,
|
|
33438
33482
|
ref: focusableHandleRef,
|
|
33439
33483
|
role: "button",
|
|
33440
|
-
"aria-
|
|
33441
|
-
|
|
33442
|
-
|
|
33443
|
-
y: srFormatNumber(point[Y], locale)
|
|
33444
|
-
})
|
|
33445
|
-
// aria-live="assertive" causes the new location of the point to be
|
|
33446
|
-
// announced immediately on move.
|
|
33447
|
-
,
|
|
33448
|
-
"aria-live": "assertive",
|
|
33484
|
+
"aria-describedby": ariaDescribedBy,
|
|
33485
|
+
"aria-label": pointAriaLabel,
|
|
33486
|
+
"aria-live": ariaLive,
|
|
33449
33487
|
onFocus: event => {
|
|
33450
33488
|
onFocus(event);
|
|
33451
33489
|
setFocused(true);
|
|
@@ -36451,7 +36489,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
36451
36489
|
});
|
|
36452
36490
|
|
|
36453
36491
|
const eq$1 = Util.eq;
|
|
36454
|
-
const deepEq$
|
|
36492
|
+
const deepEq$3 = Util.deepEq;
|
|
36455
36493
|
function scoreInteractiveGraph(userInput, rubric) {
|
|
36456
36494
|
// None-type graphs are not graded
|
|
36457
36495
|
if (userInput.type === "none" && rubric.correct.type === "none") {
|
|
@@ -36501,7 +36539,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36501
36539
|
// If the parabola coefficients match, it's correct.
|
|
36502
36540
|
const guessCoeffs = getQuadraticCoefficients(userInput.coords);
|
|
36503
36541
|
const correctCoeffs = getQuadraticCoefficients(rubric.correct.coords);
|
|
36504
|
-
if (deepEq$
|
|
36542
|
+
if (deepEq$3(guessCoeffs, correctCoeffs)) {
|
|
36505
36543
|
return {
|
|
36506
36544
|
type: "points",
|
|
36507
36545
|
earned: 1,
|
|
@@ -36515,7 +36553,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36515
36553
|
const canonicalGuessCoeffs = canonicalSineCoefficients$1(guessCoeffs);
|
|
36516
36554
|
const canonicalCorrectCoeffs = canonicalSineCoefficients$1(correctCoeffs);
|
|
36517
36555
|
// If the canonical coefficients match, it's correct.
|
|
36518
|
-
if (deepEq$
|
|
36556
|
+
if (deepEq$3(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
|
|
36519
36557
|
return {
|
|
36520
36558
|
type: "points",
|
|
36521
36559
|
earned: 1,
|
|
@@ -36524,7 +36562,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36524
36562
|
};
|
|
36525
36563
|
}
|
|
36526
36564
|
} else if (userInput.type === "circle" && rubric.correct.type === "circle") {
|
|
36527
|
-
if (deepEq$
|
|
36565
|
+
if (deepEq$3(userInput.center, rubric.correct.center) && eq$1(userInput.radius, rubric.correct.radius)) {
|
|
36528
36566
|
return {
|
|
36529
36567
|
type: "points",
|
|
36530
36568
|
earned: 1,
|
|
@@ -36546,7 +36584,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36546
36584
|
guess == null || guess.sort();
|
|
36547
36585
|
// @ts-expect-error - TS2339 - Property 'sort' does not exist on type 'readonly Coord[]'.
|
|
36548
36586
|
correct.sort();
|
|
36549
|
-
if (deepEq$
|
|
36587
|
+
if (deepEq$3(guess, correct)) {
|
|
36550
36588
|
return {
|
|
36551
36589
|
type: "points",
|
|
36552
36590
|
earned: 1,
|
|
@@ -36568,7 +36606,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36568
36606
|
/* exact */
|
|
36569
36607
|
guess.sort();
|
|
36570
36608
|
correct.sort();
|
|
36571
|
-
match = deepEq$
|
|
36609
|
+
match = deepEq$3(guess, correct);
|
|
36572
36610
|
}
|
|
36573
36611
|
if (match) {
|
|
36574
36612
|
return {
|
|
@@ -36583,7 +36621,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36583
36621
|
let correct = Util.deepClone(rubric.correct.coords);
|
|
36584
36622
|
guess = _.invoke(guess, "sort").sort();
|
|
36585
36623
|
correct = _.invoke(correct, "sort").sort();
|
|
36586
|
-
if (deepEq$
|
|
36624
|
+
if (deepEq$3(guess, correct)) {
|
|
36587
36625
|
return {
|
|
36588
36626
|
type: "points",
|
|
36589
36627
|
earned: 1,
|
|
@@ -36594,7 +36632,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36594
36632
|
} else if (userInput.type === "ray" && rubric.correct.type === "ray" && userInput.coords != null) {
|
|
36595
36633
|
const guess = userInput.coords;
|
|
36596
36634
|
const correct = rubric.correct.coords;
|
|
36597
|
-
if (deepEq$
|
|
36635
|
+
if (deepEq$3(guess[0], correct[0]) && collinear(correct[0], correct[1], guess[1])) {
|
|
36598
36636
|
return {
|
|
36599
36637
|
type: "points",
|
|
36600
36638
|
earned: 1,
|
|
@@ -36621,7 +36659,7 @@ function scoreInteractiveGraph(userInput, rubric) {
|
|
|
36621
36659
|
/* exact */
|
|
36622
36660
|
match =
|
|
36623
36661
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
36624
|
-
deepEq$
|
|
36662
|
+
deepEq$3(guess[1], correct[1]) &&
|
|
36625
36663
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
36626
36664
|
collinear(correct[1], correct[0], guess[0]) &&
|
|
36627
36665
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
@@ -40795,6 +40833,7 @@ const getPromptJSON$7 = () => {
|
|
|
40795
40833
|
return getUnsupportedPromptJSON("measurer");
|
|
40796
40834
|
};
|
|
40797
40835
|
|
|
40836
|
+
const _excluded$2 = ["imageUrl", "imageTop", "imageLeft"];
|
|
40798
40837
|
const defaultImage = {
|
|
40799
40838
|
url: null,
|
|
40800
40839
|
top: 0,
|
|
@@ -40901,14 +40940,19 @@ Measurer.defaultProps = {
|
|
|
40901
40940
|
};
|
|
40902
40941
|
const propUpgrades = {
|
|
40903
40942
|
"1": v0props => {
|
|
40904
|
-
const
|
|
40943
|
+
const {
|
|
40944
|
+
imageUrl,
|
|
40945
|
+
imageTop,
|
|
40946
|
+
imageLeft
|
|
40947
|
+
} = v0props,
|
|
40948
|
+
rest = _objectWithoutPropertiesLoose(v0props, _excluded$2);
|
|
40949
|
+
return _extends({}, rest, {
|
|
40905
40950
|
image: {
|
|
40906
|
-
url:
|
|
40907
|
-
top:
|
|
40908
|
-
left:
|
|
40951
|
+
url: imageUrl,
|
|
40952
|
+
top: imageTop,
|
|
40953
|
+
left: imageLeft
|
|
40909
40954
|
}
|
|
40910
|
-
})
|
|
40911
|
-
return v1props;
|
|
40955
|
+
});
|
|
40912
40956
|
}
|
|
40913
40957
|
};
|
|
40914
40958
|
var Measurer$1 = {
|
|
@@ -42436,14 +42480,28 @@ const getPromptJSON$5 = (renderProps, userInput) => {
|
|
|
42436
42480
|
};
|
|
42437
42481
|
};
|
|
42438
42482
|
|
|
42439
|
-
|
|
42483
|
+
/**
|
|
42484
|
+
* Checks user input from the orderer widget to see if the user has started
|
|
42485
|
+
* ordering the options, making the widget scorable.
|
|
42486
|
+
* @param userInput
|
|
42487
|
+
* @see `scoreOrderer` for more details.
|
|
42488
|
+
*/
|
|
42489
|
+
function validateOrderer(userInput) {
|
|
42440
42490
|
if (userInput.current.length === 0) {
|
|
42441
42491
|
return {
|
|
42442
42492
|
type: "invalid",
|
|
42443
42493
|
message: null
|
|
42444
42494
|
};
|
|
42445
42495
|
}
|
|
42446
|
-
|
|
42496
|
+
return null;
|
|
42497
|
+
}
|
|
42498
|
+
|
|
42499
|
+
function scoreOrderer(userInput, rubric) {
|
|
42500
|
+
const validateError = validateOrderer(userInput);
|
|
42501
|
+
if (validateError) {
|
|
42502
|
+
return validateError;
|
|
42503
|
+
}
|
|
42504
|
+
const correct = _.isEqual(userInput.current, rubric.correctOptions.map(option => option.content));
|
|
42447
42505
|
return {
|
|
42448
42506
|
type: "points",
|
|
42449
42507
|
earned: correct ? 1 : 0,
|
|
@@ -42623,8 +42681,6 @@ Card.defaultProps = {
|
|
|
42623
42681
|
animating: false,
|
|
42624
42682
|
linterContext: linterContextDefault
|
|
42625
42683
|
};
|
|
42626
|
-
const NORMAL = "normal";
|
|
42627
|
-
const HORIZONTAL = "horizontal";
|
|
42628
42684
|
class Orderer extends React.Component {
|
|
42629
42685
|
constructor(...args) {
|
|
42630
42686
|
super(...args);
|
|
@@ -42771,7 +42827,7 @@ class Orderer extends React.Component {
|
|
|
42771
42827
|
};
|
|
42772
42828
|
this.findCorrectIndex = (draggable, list) => {
|
|
42773
42829
|
// Find the correct index for a card given the current cards.
|
|
42774
|
-
const isHorizontal = this.props.layout ===
|
|
42830
|
+
const isHorizontal = this.props.layout === "horizontal";
|
|
42775
42831
|
// eslint-disable-next-line react/no-string-refs
|
|
42776
42832
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
42777
42833
|
const $dragList = $(ReactDOM__default.findDOMNode(this.refs.dragList));
|
|
@@ -42821,28 +42877,24 @@ class Orderer extends React.Component {
|
|
|
42821
42877
|
if (draggable == null) {
|
|
42822
42878
|
return false;
|
|
42823
42879
|
}
|
|
42824
|
-
const isHorizontal = this.props.layout ===
|
|
42825
|
-
|
|
42826
|
-
|
|
42827
|
-
|
|
42828
|
-
|
|
42829
|
-
|
|
42830
|
-
|
|
42831
|
-
|
|
42832
|
-
|
|
42833
|
-
|
|
42834
|
-
|
|
42835
|
-
|
|
42836
|
-
|
|
42837
|
-
|
|
42838
|
-
|
|
42839
|
-
|
|
42840
|
-
|
|
42841
|
-
|
|
42842
|
-
// @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'width' does not exist on type 'JQueryStatic'.
|
|
42843
|
-
$(dragList).width();
|
|
42844
|
-
const // @ts-expect-error - TS2339 - Property 'outerWidth' does not exist on type 'JQueryStatic'.
|
|
42845
|
-
draggableWidth = $draggable.outerWidth(true);
|
|
42880
|
+
const isHorizontal = this.props.layout === "horizontal";
|
|
42881
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
42882
|
+
const $draggable = $(ReactDOM__default.findDOMNode(draggable));
|
|
42883
|
+
// eslint-disable-next-line react/no-string-refs
|
|
42884
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
42885
|
+
const $bank = $(ReactDOM__default.findDOMNode(this.refs.bank));
|
|
42886
|
+
// @ts-expect-error - TS2339 - Property 'offset' does not exist on type 'JQueryStatic'.
|
|
42887
|
+
const draggableOffset = $draggable.offset();
|
|
42888
|
+
// @ts-expect-error - TS2339 - Property 'offset' does not exist on type 'JQueryStatic'.
|
|
42889
|
+
const bankOffset = $bank.offset();
|
|
42890
|
+
// @ts-expect-error - TS2339 - Property 'outerHeight' does not exist on type 'JQueryStatic'.
|
|
42891
|
+
const draggableHeight = $draggable.outerHeight(true);
|
|
42892
|
+
// @ts-expect-error - TS2339 - Property 'outerHeight' does not exist on type 'JQueryStatic'.
|
|
42893
|
+
const bankHeight = $bank.outerHeight(true);
|
|
42894
|
+
// @ts-expect-error - TS2339 - Property 'outerWidth' does not exist on type 'JQueryStatic'.
|
|
42895
|
+
const bankWidth = $bank.outerWidth(true);
|
|
42896
|
+
// @ts-expect-error - TS2339 - Property 'outerWidth' does not exist on type 'JQueryStatic'.
|
|
42897
|
+
const draggableWidth = $draggable.outerWidth(true);
|
|
42846
42898
|
if (isHorizontal) {
|
|
42847
42899
|
return draggableOffset.top + draggableHeight / 2 < bankOffset.top + bankHeight;
|
|
42848
42900
|
}
|
|
@@ -42991,8 +43043,8 @@ Orderer.defaultProps = {
|
|
|
42991
43043
|
current: [],
|
|
42992
43044
|
options: [],
|
|
42993
43045
|
correctOptions: [],
|
|
42994
|
-
height:
|
|
42995
|
-
layout:
|
|
43046
|
+
height: "normal",
|
|
43047
|
+
layout: "horizontal",
|
|
42996
43048
|
linterContext: linterContextDefault
|
|
42997
43049
|
};
|
|
42998
43050
|
var Orderer$1 = {
|
|
@@ -43271,18 +43323,36 @@ const getPromptJSON$3 = () => {
|
|
|
43271
43323
|
};
|
|
43272
43324
|
|
|
43273
43325
|
const {
|
|
43274
|
-
deepEq: deepEq$
|
|
43326
|
+
deepEq: deepEq$2
|
|
43275
43327
|
} = Util;
|
|
43276
|
-
|
|
43277
|
-
|
|
43328
|
+
|
|
43329
|
+
/**
|
|
43330
|
+
* Checks user input to confirm it is not the same as the starting values for the graph.
|
|
43331
|
+
* This means the user has modified the graph, and the question can be scored.
|
|
43332
|
+
*
|
|
43333
|
+
* @see 'scorePlotter' for more details on scoring.
|
|
43334
|
+
*/
|
|
43335
|
+
function validatePlotter(userInput, validationData) {
|
|
43336
|
+
if (deepEq$2(userInput, validationData.starting)) {
|
|
43278
43337
|
return {
|
|
43279
43338
|
type: "invalid",
|
|
43280
43339
|
message: null
|
|
43281
43340
|
};
|
|
43282
43341
|
}
|
|
43342
|
+
return null;
|
|
43343
|
+
}
|
|
43344
|
+
|
|
43345
|
+
const {
|
|
43346
|
+
deepEq: deepEq$1
|
|
43347
|
+
} = Util;
|
|
43348
|
+
function scorePlotter(userInput, scoringData) {
|
|
43349
|
+
const validationError = validatePlotter(userInput, scoringData);
|
|
43350
|
+
if (validationError) {
|
|
43351
|
+
return validationError;
|
|
43352
|
+
}
|
|
43283
43353
|
return {
|
|
43284
43354
|
type: "points",
|
|
43285
|
-
earned: deepEq$1(userInput,
|
|
43355
|
+
earned: deepEq$1(userInput, scoringData.correct) ? 1 : 0,
|
|
43286
43356
|
total: 1,
|
|
43287
43357
|
message: null
|
|
43288
43358
|
};
|
|
@@ -44167,7 +44237,14 @@ const getPromptJSON$1 = userInput => {
|
|
|
44167
44237
|
};
|
|
44168
44238
|
};
|
|
44169
44239
|
|
|
44170
|
-
|
|
44240
|
+
/**
|
|
44241
|
+
* Checks user input for the sorter widget to ensure that the user has made
|
|
44242
|
+
* changes before attempting to score the widget.
|
|
44243
|
+
* @param userInput
|
|
44244
|
+
* @see 'scoreSorter' in 'packages/perseus/src/widgets/sorter/score-sorter.ts'
|
|
44245
|
+
* for more details on how the sorter widget is scored.
|
|
44246
|
+
*/
|
|
44247
|
+
function validateSorter(userInput) {
|
|
44171
44248
|
// If the sorter widget hasn't been changed yet, we treat it as "empty" which
|
|
44172
44249
|
// prevents the "Check" button from becoming active. We want the user
|
|
44173
44250
|
// to make a change before trying to move forward. This makes an
|
|
@@ -44180,6 +44257,14 @@ function scoreSorter(userInput, rubric) {
|
|
|
44180
44257
|
message: null
|
|
44181
44258
|
};
|
|
44182
44259
|
}
|
|
44260
|
+
return null;
|
|
44261
|
+
}
|
|
44262
|
+
|
|
44263
|
+
function scoreSorter(userInput, rubric) {
|
|
44264
|
+
const validationError = validateSorter(userInput);
|
|
44265
|
+
if (validationError) {
|
|
44266
|
+
return validationError;
|
|
44267
|
+
}
|
|
44183
44268
|
const correct = Util.deepEq(userInput.options, rubric.correct);
|
|
44184
44269
|
return {
|
|
44185
44270
|
type: "points",
|
|
@@ -44758,7 +44843,7 @@ const init = function init() {
|
|
|
44758
44843
|
|
|
44759
44844
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44760
44845
|
const libName = "@khanacademy/perseus";
|
|
44761
|
-
const libVersion = "43.0
|
|
44846
|
+
const libVersion = "43.1.0";
|
|
44762
44847
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44763
44848
|
|
|
44764
44849
|
const apiVersion = {
|
|
@@ -46362,7 +46447,7 @@ const str = {
|
|
|
46362
46447
|
}
|
|
46363
46448
|
};
|
|
46364
46449
|
|
|
46365
|
-
const _excluded = ["item", "children", "shape", "serializedState", "onSerializedStateUpdated"];
|
|
46450
|
+
const _excluded$1 = ["item", "children", "shape", "serializedState", "onSerializedStateUpdated"];
|
|
46366
46451
|
|
|
46367
46452
|
// TODO(mdr)
|
|
46368
46453
|
// TODO(mdr)
|
|
@@ -46447,7 +46532,7 @@ class MultiRenderer extends React.Component {
|
|
|
46447
46532
|
// explicitly pulling them out of `this.props` so I don't pass them to
|
|
46448
46533
|
// `<Renderer>`. I'm not sure how else to do this.
|
|
46449
46534
|
const _this$props = this.props,
|
|
46450
|
-
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
46535
|
+
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
46451
46536
|
return _extends({}, otherProps, {
|
|
46452
46537
|
strings: this.context.strings
|
|
46453
46538
|
});
|
|
@@ -48251,6 +48336,27 @@ function pair(parseA, parseB) {
|
|
|
48251
48336
|
};
|
|
48252
48337
|
}
|
|
48253
48338
|
|
|
48339
|
+
function pipeParsers(p) {
|
|
48340
|
+
return new ParserPipeline(p);
|
|
48341
|
+
}
|
|
48342
|
+
class ParserPipeline {
|
|
48343
|
+
constructor(parser) {
|
|
48344
|
+
this.parser = parser;
|
|
48345
|
+
}
|
|
48346
|
+
then(nextParser) {
|
|
48347
|
+
return new ParserPipeline(composeParsers(this.parser, nextParser));
|
|
48348
|
+
}
|
|
48349
|
+
}
|
|
48350
|
+
function composeParsers(parserA, parserB) {
|
|
48351
|
+
return (rawValue, ctx) => {
|
|
48352
|
+
const partialResult = parserA(rawValue, ctx);
|
|
48353
|
+
if (isFailure(partialResult)) {
|
|
48354
|
+
return partialResult;
|
|
48355
|
+
}
|
|
48356
|
+
return parserB(partialResult.value, ctx);
|
|
48357
|
+
};
|
|
48358
|
+
}
|
|
48359
|
+
|
|
48254
48360
|
function record(parseKey, parseValue) {
|
|
48255
48361
|
return (rawValue, ctx) => {
|
|
48256
48362
|
if (!isObject(rawValue)) {
|
|
@@ -48331,6 +48437,20 @@ function either(parseA, parseB) {
|
|
|
48331
48437
|
};
|
|
48332
48438
|
}
|
|
48333
48439
|
|
|
48440
|
+
function defaulted(parser, fallback) {
|
|
48441
|
+
return (rawValue, ctx) => {
|
|
48442
|
+
if (rawValue == null) {
|
|
48443
|
+
return success(fallback(rawValue));
|
|
48444
|
+
}
|
|
48445
|
+
return parser(rawValue, ctx);
|
|
48446
|
+
};
|
|
48447
|
+
}
|
|
48448
|
+
|
|
48449
|
+
const parseImages = defaulted(record(string, object({
|
|
48450
|
+
width: number,
|
|
48451
|
+
height: number
|
|
48452
|
+
})), () => ({}));
|
|
48453
|
+
|
|
48334
48454
|
function parseWidget(parseType, parseOptions) {
|
|
48335
48455
|
return object({
|
|
48336
48456
|
type: parseType,
|
|
@@ -48339,10 +48459,21 @@ function parseWidget(parseType, parseOptions) {
|
|
|
48339
48459
|
alignment: optional(string),
|
|
48340
48460
|
options: parseOptions,
|
|
48341
48461
|
key: optional(number),
|
|
48342
|
-
version: object({
|
|
48462
|
+
version: optional(object({
|
|
48343
48463
|
major: number,
|
|
48344
48464
|
minor: number
|
|
48345
|
-
})
|
|
48465
|
+
}))
|
|
48466
|
+
});
|
|
48467
|
+
}
|
|
48468
|
+
function parseWidgetWithVersion(parseVersion, parseType, parseOptions) {
|
|
48469
|
+
return object({
|
|
48470
|
+
type: parseType,
|
|
48471
|
+
static: optional(boolean),
|
|
48472
|
+
graded: optional(boolean),
|
|
48473
|
+
alignment: optional(string),
|
|
48474
|
+
options: parseOptions,
|
|
48475
|
+
key: optional(number),
|
|
48476
|
+
version: parseVersion
|
|
48346
48477
|
});
|
|
48347
48478
|
}
|
|
48348
48479
|
|
|
@@ -48350,7 +48481,7 @@ const parseCategorizerWidget = parseWidget(constant("categorizer"), object({
|
|
|
48350
48481
|
items: array(string),
|
|
48351
48482
|
categories: array(string),
|
|
48352
48483
|
randomizeItems: boolean,
|
|
48353
|
-
static: boolean,
|
|
48484
|
+
static: defaulted(boolean, () => false),
|
|
48354
48485
|
values: array(number),
|
|
48355
48486
|
highlightLint: optional(boolean),
|
|
48356
48487
|
linterContext: optional(object({
|
|
@@ -48382,7 +48513,7 @@ const parseDefinitionWidget = parseWidget(constant("definition"), object({
|
|
|
48382
48513
|
|
|
48383
48514
|
const parseDropdownWidget = parseWidget(constant("dropdown"), object({
|
|
48384
48515
|
placeholder: string,
|
|
48385
|
-
static: boolean,
|
|
48516
|
+
static: defaulted(boolean, () => false),
|
|
48386
48517
|
choices: array(object({
|
|
48387
48518
|
content: string,
|
|
48388
48519
|
correct: boolean
|
|
@@ -48405,9 +48536,12 @@ const parseAnswerForm = object({
|
|
|
48405
48536
|
form: boolean,
|
|
48406
48537
|
simplify: boolean,
|
|
48407
48538
|
considered: enumeration("correct", "wrong", "ungraded"),
|
|
48408
|
-
key: optional(string)
|
|
48539
|
+
key: pipeParsers(optional(union(string).or(number).parser)).then((key, ctx) => ctx.success(String(key))).parser
|
|
48409
48540
|
});
|
|
48410
|
-
const
|
|
48541
|
+
const parseExpressionWidgetV1 = parseWidgetWithVersion(object({
|
|
48542
|
+
major: constant(1),
|
|
48543
|
+
minor: number
|
|
48544
|
+
}), constant("expression"), object({
|
|
48411
48545
|
answerForms: array(parseAnswerForm),
|
|
48412
48546
|
functions: array(string),
|
|
48413
48547
|
times: boolean,
|
|
@@ -48416,23 +48550,68 @@ const parseExpressionWidget = parseWidget(constant("expression"), object({
|
|
|
48416
48550
|
buttonSets: array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")),
|
|
48417
48551
|
buttonsVisible: optional(enumeration("always", "never", "focused"))
|
|
48418
48552
|
}));
|
|
48553
|
+
const parseExpressionWidgetV0 = parseWidgetWithVersion(optional(object({
|
|
48554
|
+
major: constant(0),
|
|
48555
|
+
minor: number
|
|
48556
|
+
})), constant("expression"), object({
|
|
48557
|
+
functions: array(string),
|
|
48558
|
+
times: boolean,
|
|
48559
|
+
visibleLabel: optional(string),
|
|
48560
|
+
ariaLabel: optional(string),
|
|
48561
|
+
form: boolean,
|
|
48562
|
+
simplify: boolean,
|
|
48563
|
+
value: string,
|
|
48564
|
+
buttonSets: array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")),
|
|
48565
|
+
buttonsVisible: optional(enumeration("always", "never", "focused"))
|
|
48566
|
+
}));
|
|
48567
|
+
function migrateV0ToV1(widget, ctx) {
|
|
48568
|
+
const {
|
|
48569
|
+
options
|
|
48570
|
+
} = widget;
|
|
48571
|
+
return ctx.success(_extends({}, widget, {
|
|
48572
|
+
version: {
|
|
48573
|
+
major: 1,
|
|
48574
|
+
minor: 0
|
|
48575
|
+
},
|
|
48576
|
+
options: {
|
|
48577
|
+
times: options.times,
|
|
48578
|
+
buttonSets: options.buttonSets,
|
|
48579
|
+
functions: options.functions,
|
|
48580
|
+
buttonsVisible: options.buttonsVisible,
|
|
48581
|
+
visibleLabel: options.visibleLabel,
|
|
48582
|
+
ariaLabel: options.ariaLabel,
|
|
48583
|
+
answerForms: [{
|
|
48584
|
+
considered: "correct",
|
|
48585
|
+
form: options.form,
|
|
48586
|
+
simplify: options.simplify,
|
|
48587
|
+
value: options.value
|
|
48588
|
+
}]
|
|
48589
|
+
}
|
|
48590
|
+
}));
|
|
48591
|
+
}
|
|
48592
|
+
const parseExpressionWidget = union(parseExpressionWidgetV1).or(pipeParsers(parseExpressionWidgetV0).then(migrateV0ToV1).parser).parser;
|
|
48419
48593
|
|
|
48420
|
-
const parsePerseusRenderer = object({
|
|
48421
|
-
|
|
48594
|
+
const parsePerseusRenderer = defaulted(object({
|
|
48595
|
+
// TODO(benchristel): content is also defaulted to empty string in
|
|
48596
|
+
// renderer.tsx. See if we can remove one default or the other.
|
|
48597
|
+
content: defaulted(string, () => ""),
|
|
48422
48598
|
// This module has an import cycle with parseWidgetsMap, because the
|
|
48423
48599
|
// `group` widget can contain another renderer.
|
|
48424
48600
|
// The anonymous function below ensures that we don't try to access
|
|
48425
48601
|
// parseWidgetsMap before it's defined.
|
|
48426
|
-
widgets: (rawVal, ctx) => parseWidgetsMap(rawVal, ctx),
|
|
48602
|
+
widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => ({})),
|
|
48427
48603
|
metadata: optional(array(string)),
|
|
48428
|
-
images:
|
|
48429
|
-
|
|
48430
|
-
|
|
48431
|
-
|
|
48432
|
-
|
|
48604
|
+
images: parseImages
|
|
48605
|
+
}),
|
|
48606
|
+
// Default value
|
|
48607
|
+
() => ({
|
|
48608
|
+
content: "",
|
|
48609
|
+
widgets: {},
|
|
48610
|
+
images: {}
|
|
48611
|
+
}));
|
|
48433
48612
|
|
|
48434
48613
|
const parseGradedGroupWidgetOptions = object({
|
|
48435
|
-
title: string,
|
|
48614
|
+
title: defaulted(string, () => ""),
|
|
48436
48615
|
hasHint: optional(nullable(boolean)),
|
|
48437
48616
|
// This module has an import cycle with parsePerseusRenderer.
|
|
48438
48617
|
// The anonymous function below ensures that we don't try to access
|
|
@@ -48526,7 +48705,7 @@ const parseIframeWidget = parseWidget(constant("iframe"), object({
|
|
|
48526
48705
|
height: union(number).or(string).parser,
|
|
48527
48706
|
allowFullScreen: boolean,
|
|
48528
48707
|
allowTopNavigation: optional(boolean),
|
|
48529
|
-
static: boolean
|
|
48708
|
+
static: defaulted(boolean, () => false)
|
|
48530
48709
|
}));
|
|
48531
48710
|
|
|
48532
48711
|
const parsePerseusImageBackground = object({
|
|
@@ -48905,13 +49084,13 @@ const parseMatcherWidget = parseWidget(constant("matcher"), object({
|
|
|
48905
49084
|
padding: boolean
|
|
48906
49085
|
}));
|
|
48907
49086
|
|
|
48908
|
-
const parseMatrixWidget = parseWidget(constant("matrix"), object({
|
|
48909
|
-
prefix: string,
|
|
48910
|
-
suffix: string,
|
|
49087
|
+
const parseMatrixWidget = parseWidget(defaulted(constant("matrix"), () => "matrix"), object({
|
|
49088
|
+
prefix: optional(string),
|
|
49089
|
+
suffix: optional(string),
|
|
48911
49090
|
answers: array(array(number)),
|
|
48912
|
-
cursorPosition: array(number),
|
|
49091
|
+
cursorPosition: optional(array(number)),
|
|
48913
49092
|
matrixBoardSize: array(number),
|
|
48914
|
-
static: boolean
|
|
49093
|
+
static: optional(boolean)
|
|
48915
49094
|
}));
|
|
48916
49095
|
|
|
48917
49096
|
const parseMeasurerWidget = parseWidget(constant("measurer"), object({
|
|
@@ -48981,8 +49160,8 @@ const parseOrdererWidget = parseWidget(constant("orderer"), object({
|
|
|
48981
49160
|
options: array(parseRenderer),
|
|
48982
49161
|
correctOptions: array(parseRenderer),
|
|
48983
49162
|
otherOptions: array(parseRenderer),
|
|
48984
|
-
height:
|
|
48985
|
-
layout:
|
|
49163
|
+
height: enumeration("normal", "auto"),
|
|
49164
|
+
layout: enumeration("horizontal", "vertical")
|
|
48986
49165
|
}));
|
|
48987
49166
|
|
|
48988
49167
|
const parsePassageRefWidget = parseWidget(constant("passage-ref"), object({
|
|
@@ -49027,7 +49206,7 @@ const parsePythonProgramWidget = parseWidget(constant("python-program"), object(
|
|
|
49027
49206
|
|
|
49028
49207
|
const parseRadioWidget = parseWidget(constant("radio"), object({
|
|
49029
49208
|
choices: array(object({
|
|
49030
|
-
content: string,
|
|
49209
|
+
content: defaulted(string, () => ""),
|
|
49031
49210
|
clue: optional(string),
|
|
49032
49211
|
correct: optional(boolean),
|
|
49033
49212
|
isNoneOfTheAbove: optional(boolean),
|
|
@@ -49188,26 +49367,42 @@ const parseWidgetMapKeyComponents = pair(string, parseStringToPositiveInt);
|
|
|
49188
49367
|
const parseHint = object({
|
|
49189
49368
|
replace: optional(boolean),
|
|
49190
49369
|
content: string,
|
|
49191
|
-
widgets: parseWidgetsMap,
|
|
49370
|
+
widgets: defaulted(parseWidgetsMap, () => ({})),
|
|
49192
49371
|
metadata: optional(array(string)),
|
|
49193
|
-
images:
|
|
49194
|
-
width: number,
|
|
49195
|
-
height: number
|
|
49196
|
-
}))
|
|
49372
|
+
images: parseImages
|
|
49197
49373
|
});
|
|
49198
49374
|
|
|
49375
|
+
const _excluded = ["type", "options"];
|
|
49199
49376
|
object({
|
|
49200
49377
|
question: parsePerseusRenderer,
|
|
49201
|
-
hints: array(parseHint),
|
|
49202
|
-
answerArea: record(enumeration(...ItemExtras), boolean),
|
|
49203
|
-
itemDataVersion: object({
|
|
49378
|
+
hints: defaulted(array(parseHint), () => []),
|
|
49379
|
+
answerArea: pipeParsers(defaulted(object({}), () => ({}))).then(migrateAnswerArea).then(record(enumeration(...ItemExtras), boolean)).parser,
|
|
49380
|
+
itemDataVersion: optional(object({
|
|
49204
49381
|
major: number,
|
|
49205
49382
|
minor: number
|
|
49206
|
-
}),
|
|
49383
|
+
})),
|
|
49207
49384
|
// Deprecated field
|
|
49208
49385
|
answer: any
|
|
49209
49386
|
});
|
|
49210
49387
|
|
|
49388
|
+
// Some answerAreas have extra fields, like:
|
|
49389
|
+
//
|
|
49390
|
+
// "answerArea": {
|
|
49391
|
+
// "type": "multiple",
|
|
49392
|
+
// "options": {
|
|
49393
|
+
// "content": "",
|
|
49394
|
+
// "images": {},
|
|
49395
|
+
// "widgets": {}
|
|
49396
|
+
// }
|
|
49397
|
+
// }
|
|
49398
|
+
//
|
|
49399
|
+
// The "type" and "options" fields don't seem to be used anywhere. This
|
|
49400
|
+
// migration function removes them.
|
|
49401
|
+
function migrateAnswerArea(rawValue, ctx) {
|
|
49402
|
+
const rest = _objectWithoutPropertiesLoose(rawValue, _excluded);
|
|
49403
|
+
return ctx.success(rest);
|
|
49404
|
+
}
|
|
49405
|
+
|
|
49211
49406
|
/**
|
|
49212
49407
|
* Helper to parse PerseusItem JSON
|
|
49213
49408
|
* Why not just use JSON.parse? We want:
|