@khanacademy/perseus 36.1.2 → 37.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/all-widgets.d.ts +2 -0
- package/dist/basic-widgets.d.ts +2 -0
- package/dist/components/math-input.d.ts +1 -1
- package/dist/es/index.js +598 -766
- package/dist/es/index.js.map +1 -1
- package/dist/extra-widgets.d.ts +2 -0
- package/dist/index.js +463 -643
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -0
- package/dist/renderer-util.d.ts +8 -0
- package/dist/renderer.d.ts +19 -20
- package/dist/server-item-renderer.d.ts +1 -0
- package/dist/types.d.ts +13 -4
- package/dist/util/extract-perseus-data.d.ts +1 -1
- package/dist/util.d.ts +4 -0
- package/dist/validation.types.d.ts +14 -6
- package/dist/widgets/categorizer/categorizer.d.ts +4 -5
- package/dist/widgets/cs-program/cs-program.d.ts +3 -3
- package/dist/widgets/definition/definition.d.ts +4 -4
- package/dist/widgets/deprecated-standin/deprecated-standin.d.ts +36 -0
- package/dist/widgets/deprecated-standin/index.d.ts +1 -37
- package/dist/widgets/dropdown/dropdown.d.ts +3 -3
- package/dist/widgets/explanation/explanation.d.ts +5 -5
- package/dist/widgets/expression/expression.d.ts +11 -9
- package/dist/widgets/graded-group/graded-group.d.ts +2 -0
- package/dist/widgets/graded-group-set/graded-group-set.d.ts +2 -0
- package/dist/widgets/grapher/grapher.d.ts +3 -3
- package/dist/widgets/group/group.d.ts +9 -5
- package/dist/widgets/iframe/iframe.d.ts +3 -3
- package/dist/widgets/image/image.d.ts +4 -4
- package/dist/widgets/input-number/input-number.d.ts +3 -6
- package/dist/widgets/interaction/interaction.d.ts +4 -4
- package/dist/widgets/interactive-graph.d.ts +3 -4
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
- package/dist/widgets/label-image/label-image.d.ts +6 -4
- package/dist/widgets/matcher/matcher.d.ts +3 -3
- package/dist/widgets/matrix/matrix.d.ts +4 -5
- package/dist/widgets/measurer/measurer.d.ts +3 -4
- package/dist/widgets/molecule/molecule.d.ts +3 -4
- package/dist/widgets/number-line/number-line.d.ts +4 -4
- package/dist/widgets/numeric-input/numeric-input.d.ts +3 -4
- package/dist/widgets/orderer/orderer.d.ts +3 -3
- package/dist/widgets/passage/passage.d.ts +4 -9
- package/dist/widgets/passage-ref/passage-ref.d.ts +4 -4
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +3 -4
- package/dist/widgets/phet-simulation/phet-simulation.d.ts +3 -2
- package/dist/widgets/plotter/plotter.d.ts +3 -3
- package/dist/widgets/python-program/python-program.d.ts +2 -0
- package/dist/widgets/radio/radio-component.d.ts +2 -5
- package/dist/widgets/radio/radio.d.ts +2 -0
- package/dist/widgets/sorter/sorter.d.ts +3 -3
- package/dist/widgets/table/table.d.ts +4 -5
- package/dist/widgets/video/video.d.ts +3 -8
- package/dist/widgets.d.ts +3 -1
- package/package.json +2 -2
- package/dist/widgets/expression/expression.types.d.ts +0 -2
package/dist/es/index.js
CHANGED
|
@@ -53,16 +53,6 @@ function _extends() {
|
|
|
53
53
|
}, _extends.apply(null, arguments);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function _objectWithoutPropertiesLoose(r, e) {
|
|
57
|
-
if (null == r) return {};
|
|
58
|
-
var t = {};
|
|
59
|
-
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
60
|
-
if (e.includes(n)) continue;
|
|
61
|
-
t[n] = r[n];
|
|
62
|
-
}
|
|
63
|
-
return t;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
56
|
/**
|
|
67
57
|
* The translated strings that are used to render Perseus.
|
|
68
58
|
*/
|
|
@@ -2258,7 +2248,6 @@ function expressionValidator(userInput, rubric, strings, locale) {
|
|
|
2258
2248
|
};
|
|
2259
2249
|
}
|
|
2260
2250
|
|
|
2261
|
-
const _excluded$5 = ["scoring"];
|
|
2262
2251
|
// Map of international operator names to their English equivalents
|
|
2263
2252
|
const englishOperators = {
|
|
2264
2253
|
arctg: "arctan",
|
|
@@ -2281,13 +2270,6 @@ const anglicizeOperators = tex => {
|
|
|
2281
2270
|
const normalizeTex = tex => {
|
|
2282
2271
|
return anglicizeOperators(tex);
|
|
2283
2272
|
};
|
|
2284
|
-
const deriveKeypadVersion = apiOptions => {
|
|
2285
|
-
// We can derive which version of the keypad is in use. This is
|
|
2286
|
-
// a bit tricky, but this code will be relatively short-lived
|
|
2287
|
-
// as we coalesce onto the new, v2 Keypad, at which point we
|
|
2288
|
-
// can remove this `virtualKeypadVersion` field entirely.
|
|
2289
|
-
return apiOptions.nativeKeypadProxy != null ? "REACT_NATIVE_KEYPAD" : "MATH_INPUT_KEYPAD_V2";
|
|
2290
|
-
};
|
|
2291
2273
|
// The new, MathQuill input expression widget
|
|
2292
2274
|
class Expression extends React.Component {
|
|
2293
2275
|
constructor(..._args) {
|
|
@@ -2346,27 +2328,6 @@ class Expression extends React.Component {
|
|
|
2346
2328
|
});
|
|
2347
2329
|
}
|
|
2348
2330
|
};
|
|
2349
|
-
this.simpleValidate = _ref => {
|
|
2350
|
-
let {
|
|
2351
|
-
scoring
|
|
2352
|
-
} = _ref,
|
|
2353
|
-
rubric = _objectWithoutPropertiesLoose(_ref, _excluded$5);
|
|
2354
|
-
const score = expressionValidator(this.getUserInput(), rubric, this.context.strings, this.context.locale);
|
|
2355
|
-
|
|
2356
|
-
// "scoring" is a flag that indicates when we are checking answers.
|
|
2357
|
-
// otherwise, we may just be checking validity after changes.
|
|
2358
|
-
if (scoring && score.type !== "invalid") {
|
|
2359
|
-
var _this$props$analytics;
|
|
2360
|
-
(_this$props$analytics = this.props.analytics) == null || _this$props$analytics.onAnalyticsEvent({
|
|
2361
|
-
type: "perseus:expression-evaluated",
|
|
2362
|
-
payload: {
|
|
2363
|
-
result: score.earned === score.total ? "correct" : "incorrect",
|
|
2364
|
-
virtualKeypadVersion: deriveKeypadVersion(this.props.apiOptions)
|
|
2365
|
-
}
|
|
2366
|
-
});
|
|
2367
|
-
}
|
|
2368
|
-
return score;
|
|
2369
|
-
};
|
|
2370
2331
|
this.change = (...args) => {
|
|
2371
2332
|
return change.apply(this, args);
|
|
2372
2333
|
};
|
|
@@ -2384,8 +2345,8 @@ class Expression extends React.Component {
|
|
|
2384
2345
|
this.props.trackInteraction();
|
|
2385
2346
|
};
|
|
2386
2347
|
this._handleFocus = () => {
|
|
2387
|
-
var _this$props$
|
|
2388
|
-
(_this$props$
|
|
2348
|
+
var _this$props$analytics;
|
|
2349
|
+
(_this$props$analytics = this.props.analytics) == null || _this$props$analytics.onAnalyticsEvent({
|
|
2389
2350
|
type: "perseus:expression-focused",
|
|
2390
2351
|
payload: null
|
|
2391
2352
|
});
|
|
@@ -2412,22 +2373,9 @@ class Expression extends React.Component {
|
|
|
2412
2373
|
return [[]];
|
|
2413
2374
|
};
|
|
2414
2375
|
}
|
|
2415
|
-
// TODO remove this in favor of just using expressionValidator
|
|
2416
|
-
static validate(userInput, rubric, strings, locale) {
|
|
2417
|
-
return expressionValidator(userInput, rubric, strings, locale);
|
|
2418
|
-
}
|
|
2419
2376
|
static getUserInputFromProps(props) {
|
|
2420
2377
|
return normalizeTex(props.value);
|
|
2421
2378
|
}
|
|
2422
|
-
static getOneCorrectAnswerFromRubric(rubric) {
|
|
2423
|
-
const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
|
|
2424
|
-
if (correctAnswers.length === 0) {
|
|
2425
|
-
return;
|
|
2426
|
-
}
|
|
2427
|
-
return correctAnswers[0].value;
|
|
2428
|
-
}
|
|
2429
|
-
//#endregion
|
|
2430
|
-
|
|
2431
2379
|
getUserInput() {
|
|
2432
2380
|
return Expression.getUserInputFromProps(this.props);
|
|
2433
2381
|
}
|
|
@@ -2465,7 +2413,7 @@ class Expression extends React.Component {
|
|
|
2465
2413
|
}, cb);
|
|
2466
2414
|
}
|
|
2467
2415
|
render() {
|
|
2468
|
-
var _this$props$keypadCon, _this$props$
|
|
2416
|
+
var _this$props$keypadCon, _this$props$analytics2;
|
|
2469
2417
|
if (this.props.apiOptions.customKeypad) {
|
|
2470
2418
|
return /*#__PURE__*/React.createElement(View, {
|
|
2471
2419
|
className: css(styles$D.mobileLabelInputWrapper)
|
|
@@ -2538,7 +2486,7 @@ class Expression extends React.Component {
|
|
|
2538
2486
|
hasError: this.state.showErrorStyle,
|
|
2539
2487
|
ariaLabel: this.props.ariaLabel || this.context.strings.mathInputBox,
|
|
2540
2488
|
extraKeys: (_this$props$keypadCon = this.props.keypadConfiguration) == null ? void 0 : _this$props$keypadCon.extraKeys,
|
|
2541
|
-
analytics: (_this$props$
|
|
2489
|
+
analytics: (_this$props$analytics2 = this.props.analytics) != null ? _this$props$analytics2 : {
|
|
2542
2490
|
onAnalyticsEvent: async function () {}
|
|
2543
2491
|
}
|
|
2544
2492
|
}))));
|
|
@@ -2655,11 +2603,7 @@ const ExpressionWithDependencies = /*#__PURE__*/React.forwardRef((props, ref) =>
|
|
|
2655
2603
|
// methods and instead adjust Perseus to provide these facilities through
|
|
2656
2604
|
// instance methods on our Renderers.
|
|
2657
2605
|
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2658
|
-
ExpressionWithDependencies.validate = expressionValidator;
|
|
2659
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2660
2606
|
ExpressionWithDependencies.getUserInputFromProps = Expression.getUserInputFromProps;
|
|
2661
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2662
|
-
ExpressionWithDependencies.getOneCorrectAnswerFromRubric = Expression.getOneCorrectAnswerFromRubric;
|
|
2663
2607
|
var Expression$1 = {
|
|
2664
2608
|
name: "expression",
|
|
2665
2609
|
displayName: "Expression / Equation",
|
|
@@ -2691,7 +2635,15 @@ var Expression$1 = {
|
|
|
2691
2635
|
},
|
|
2692
2636
|
propUpgrades: propUpgrades$2,
|
|
2693
2637
|
// For use by the editor
|
|
2694
|
-
isLintable: true
|
|
2638
|
+
isLintable: true,
|
|
2639
|
+
validator: expressionValidator,
|
|
2640
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
2641
|
+
const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
|
|
2642
|
+
if (correctAnswers.length === 0) {
|
|
2643
|
+
return;
|
|
2644
|
+
}
|
|
2645
|
+
return correctAnswers[0].value;
|
|
2646
|
+
}
|
|
2695
2647
|
};
|
|
2696
2648
|
|
|
2697
2649
|
/**
|
|
@@ -2920,6 +2872,9 @@ function combineScores(scoreA, scoreB) {
|
|
|
2920
2872
|
}
|
|
2921
2873
|
});
|
|
2922
2874
|
}
|
|
2875
|
+
function flattenScores(widgetScoreMap) {
|
|
2876
|
+
return Object.values(widgetScoreMap).reduce(combineScores, noScore);
|
|
2877
|
+
}
|
|
2923
2878
|
function isCorrect(score) {
|
|
2924
2879
|
return score.type === "points" && score.earned >= score.total;
|
|
2925
2880
|
}
|
|
@@ -3452,6 +3407,7 @@ const Util = {
|
|
|
3452
3407
|
shuffle: shuffle$3,
|
|
3453
3408
|
split,
|
|
3454
3409
|
combineScores,
|
|
3410
|
+
flattenScores,
|
|
3455
3411
|
keScoreFromPerseusScore,
|
|
3456
3412
|
firstNumericalParse: firstNumericalParse$1,
|
|
3457
3413
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
@@ -9988,6 +9944,8 @@ const setLabelMargins = function setLabelMargins(span, size) {
|
|
|
9988
9944
|
});
|
|
9989
9945
|
} else {
|
|
9990
9946
|
var _$container$css, _$container$width, _$span$css;
|
|
9947
|
+
const currentHeightMatchesProps = span.scrollHeight === height;
|
|
9948
|
+
|
|
9991
9949
|
// We are using jQuery to collect information and calculate a scale
|
|
9992
9950
|
// since we don't have a way to pass it to this function.
|
|
9993
9951
|
// We need the width of the container in order to calculate the scale to apply to the label.
|
|
@@ -10009,6 +9967,17 @@ const setLabelMargins = function setLabelMargins(span, size) {
|
|
|
10009
9967
|
// Inherited line-height values can really mess up placement.
|
|
10010
9968
|
$container.css("line-height", "normal");
|
|
10011
9969
|
|
|
9970
|
+
// TODO: Verify that this change doesn't impact other graphies
|
|
9971
|
+
// Check the full list of consuming widgets.
|
|
9972
|
+
|
|
9973
|
+
// If the change in line-height affected the height of the element,
|
|
9974
|
+
// then the height used for calculations should be updated.
|
|
9975
|
+
// This can happen when the first label in the container calls this method,
|
|
9976
|
+
// and the line-height was different when the height measurement was originally referenced.
|
|
9977
|
+
if (currentHeightMatchesProps && span.scrollHeight !== height) {
|
|
9978
|
+
height = span.scrollHeight;
|
|
9979
|
+
}
|
|
9980
|
+
|
|
10012
9981
|
// The expected width of the graphie is found in the "max-width" property on ".svg-image" containers,
|
|
10013
9982
|
// and is found in the "width" property on ".graphie" containers.
|
|
10014
9983
|
const widthValues = (_$container$css = $container.css(["max-width", "width"])) != null ? _$container$css : {
|
|
@@ -14645,7 +14614,7 @@ const mapObject$1 = function mapObject(obj, lambda) {
|
|
|
14645
14614
|
* });
|
|
14646
14615
|
* {a: 'aa', b: 'bb'}
|
|
14647
14616
|
*/
|
|
14648
|
-
const mapObjectFromArray
|
|
14617
|
+
const mapObjectFromArray = function mapObjectFromArray(arr, lambda) {
|
|
14649
14618
|
const result = {};
|
|
14650
14619
|
_.each(arr, function (elem) {
|
|
14651
14620
|
result[elem] = lambda(elem);
|
|
@@ -14655,7 +14624,7 @@ const mapObjectFromArray$1 = function mapObjectFromArray(arr, lambda) {
|
|
|
14655
14624
|
var objective_ = {
|
|
14656
14625
|
pluck: pluck,
|
|
14657
14626
|
mapObject: mapObject$1,
|
|
14658
|
-
mapObjectFromArray: mapObjectFromArray
|
|
14627
|
+
mapObjectFromArray: mapObjectFromArray
|
|
14659
14628
|
};
|
|
14660
14629
|
|
|
14661
14630
|
/**
|
|
@@ -18818,169 +18787,6 @@ class QuestionParagraph extends React.Component {
|
|
|
18818
18787
|
}
|
|
18819
18788
|
}
|
|
18820
18789
|
|
|
18821
|
-
/**
|
|
18822
|
-
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
18823
|
-
*
|
|
18824
|
-
* The poentry linter checks for issues that prevent content from being
|
|
18825
|
-
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
18826
|
-
* anything in non-KA environments.
|
|
18827
|
-
*/
|
|
18828
|
-
|
|
18829
|
-
// A LintCB is called once the linter has been run.
|
|
18830
|
-
|
|
18831
|
-
// msec to wait before we actually call the linter after receiving the
|
|
18832
|
-
// last call. The timer is reset if the lint is called during the wait.
|
|
18833
|
-
const DEBOUNCE_TIMEOUT = 1000;
|
|
18834
|
-
class TranslationLinter {
|
|
18835
|
-
constructor() {
|
|
18836
|
-
// To avoid linting when nothing has changed.
|
|
18837
|
-
this.previousContent = null;
|
|
18838
|
-
/**
|
|
18839
|
-
* Runs the poentry linter on the given perseus string asynchronously.
|
|
18840
|
-
*
|
|
18841
|
-
* It doesn't do anything unless we're in a KA environment.
|
|
18842
|
-
*
|
|
18843
|
-
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
18844
|
-
* called if perseusStr is unchanged from the last call.
|
|
18845
|
-
*
|
|
18846
|
-
* Linting is relatively expensive -- so we debounce linting each instance
|
|
18847
|
-
* for some amount of time.
|
|
18848
|
-
*/
|
|
18849
|
-
this.runLinter = debounce$1((perseusStr, onLintErrorsGenerated) => {
|
|
18850
|
-
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
18851
|
-
if (typeof KA === "undefined") {
|
|
18852
|
-
return;
|
|
18853
|
-
}
|
|
18854
|
-
if (perseusStr === this.previousContent) {
|
|
18855
|
-
return;
|
|
18856
|
-
}
|
|
18857
|
-
this.previousContent = perseusStr;
|
|
18858
|
-
if (perseusStr === "") {
|
|
18859
|
-
onLintErrorsGenerated([]);
|
|
18860
|
-
return;
|
|
18861
|
-
}
|
|
18862
|
-
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
18863
|
-
headers: {
|
|
18864
|
-
"Content-Type": "application/json"
|
|
18865
|
-
},
|
|
18866
|
-
body: JSON.stringify({
|
|
18867
|
-
// The poentry linter verifies that the translation from
|
|
18868
|
-
// the original text to the translated text is sane. We
|
|
18869
|
-
// want to ensure that the translation from English to
|
|
18870
|
-
// English is sane, so msgid === mstr.
|
|
18871
|
-
msgid: perseusStr,
|
|
18872
|
-
// msgid is the original text
|
|
18873
|
-
msgstr: perseusStr,
|
|
18874
|
-
// msgstr is the translated text
|
|
18875
|
-
format: "perseus_text",
|
|
18876
|
-
filename: ""
|
|
18877
|
-
}),
|
|
18878
|
-
method: "POST"
|
|
18879
|
-
}).then(response => {
|
|
18880
|
-
if (response.status >= 400) {
|
|
18881
|
-
return {
|
|
18882
|
-
status: "error",
|
|
18883
|
-
message: "Could not run i18n linter."
|
|
18884
|
-
};
|
|
18885
|
-
}
|
|
18886
|
-
return response.json();
|
|
18887
|
-
}, rejection => {
|
|
18888
|
-
return {
|
|
18889
|
-
status: "error",
|
|
18890
|
-
message: "Could not run i18n linter."
|
|
18891
|
-
};
|
|
18892
|
-
}).then(json => {
|
|
18893
|
-
if (json.status === "error") {
|
|
18894
|
-
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
18895
|
-
} else {
|
|
18896
|
-
onLintErrorsGenerated([]);
|
|
18897
|
-
}
|
|
18898
|
-
});
|
|
18899
|
-
}, DEBOUNCE_TIMEOUT);
|
|
18900
|
-
}
|
|
18901
|
-
/**
|
|
18902
|
-
* Applies an array of errors generated by linters without position
|
|
18903
|
-
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
18904
|
-
* top of a Perseus tree.
|
|
18905
|
-
*/
|
|
18906
|
-
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
18907
|
-
// These lint errors do not have position data associated with
|
|
18908
|
-
// them, so we just plop them at the top.
|
|
18909
|
-
if (translationLintErrors.length) {
|
|
18910
|
-
const errorText = translationLintErrors.join("\n\n");
|
|
18911
|
-
parsedMarkdown.unshift({
|
|
18912
|
-
content: {
|
|
18913
|
-
type: "text",
|
|
18914
|
-
content: ""
|
|
18915
|
-
},
|
|
18916
|
-
insideTable: false,
|
|
18917
|
-
message: errorText,
|
|
18918
|
-
ruleName: "legacy-error",
|
|
18919
|
-
severity: Rule.Severity.ERROR,
|
|
18920
|
-
type: "lint"
|
|
18921
|
-
});
|
|
18922
|
-
}
|
|
18923
|
-
}
|
|
18924
|
-
}
|
|
18925
|
-
|
|
18926
|
-
/**
|
|
18927
|
-
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
18928
|
-
* to things is does.
|
|
18929
|
-
*/
|
|
18930
|
-
var preprocessTex = (texCode => texCode
|
|
18931
|
-
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
18932
|
-
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
18933
|
-
// the same is supported by KaTeX. It does the same for align*.
|
|
18934
|
-
// TODO(kevinb) update content to use aligned instead of align.
|
|
18935
|
-
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
18936
|
-
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
18937
|
-
// "aligned").
|
|
18938
|
-
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
18939
|
-
// Replace non-breaking spaces with regular spaces.
|
|
18940
|
-
.replace(/[\u00a0]/g, " "));
|
|
18941
|
-
|
|
18942
|
-
const {
|
|
18943
|
-
interactiveSizes
|
|
18944
|
-
} = constants$1;
|
|
18945
|
-
|
|
18946
|
-
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
18947
|
-
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
18948
|
-
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
18949
|
-
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
18950
|
-
const smMax = articleMaxWidthTableInPx;
|
|
18951
|
-
const mdMax = articleMaxWidthInPx;
|
|
18952
|
-
const containerSizeClass = {
|
|
18953
|
-
SMALL: "small",
|
|
18954
|
-
MEDIUM: "medium",
|
|
18955
|
-
LARGE: "large",
|
|
18956
|
-
XLARGE: "xlarge"
|
|
18957
|
-
};
|
|
18958
|
-
const getClassFromWidth = width => {
|
|
18959
|
-
if (!width) {
|
|
18960
|
-
return containerSizeClass.MEDIUM;
|
|
18961
|
-
}
|
|
18962
|
-
if (width <= smMax) {
|
|
18963
|
-
return containerSizeClass.SMALL;
|
|
18964
|
-
}
|
|
18965
|
-
if (width <= mdMax) {
|
|
18966
|
-
return containerSizeClass.MEDIUM;
|
|
18967
|
-
}
|
|
18968
|
-
return containerSizeClass.LARGE;
|
|
18969
|
-
};
|
|
18970
|
-
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
18971
|
-
if (sizeClass === containerSizeClass.SMALL) {
|
|
18972
|
-
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
18973
|
-
}
|
|
18974
|
-
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
18975
|
-
};
|
|
18976
|
-
|
|
18977
|
-
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
18978
|
-
__proto__: null,
|
|
18979
|
-
containerSizeClass: containerSizeClass,
|
|
18980
|
-
getClassFromWidth: getClassFromWidth,
|
|
18981
|
-
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
18982
|
-
});
|
|
18983
|
-
|
|
18984
18790
|
const DEFAULT_ALIGNMENT$1 = "block";
|
|
18985
18791
|
// NOTE(kevinb): "default" is not one in `validAlignments`.
|
|
18986
18792
|
const DEFAULT_SUPPORTED_ALIGNMENTS = ["default"];
|
|
@@ -19081,6 +18887,14 @@ const getWidget = name => {
|
|
|
19081
18887
|
}
|
|
19082
18888
|
return widgets[name].widget;
|
|
19083
18889
|
};
|
|
18890
|
+
const getWidgetExport = name => {
|
|
18891
|
+
var _widgets$name3;
|
|
18892
|
+
return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
|
|
18893
|
+
};
|
|
18894
|
+
const getWidgetValidator = name => {
|
|
18895
|
+
var _widgets$name$validat, _widgets$name4;
|
|
18896
|
+
return (_widgets$name$validat = (_widgets$name4 = widgets[name]) == null ? void 0 : _widgets$name4.validator) != null ? _widgets$name$validat : null;
|
|
18897
|
+
};
|
|
19084
18898
|
const getEditor = name => {
|
|
19085
18899
|
return _.has(editors, name) ? editors[name] : null;
|
|
19086
18900
|
};
|
|
@@ -19383,6 +19197,8 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19383
19197
|
replaceEditor: replaceEditor,
|
|
19384
19198
|
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
19385
19199
|
getWidget: getWidget,
|
|
19200
|
+
getWidgetExport: getWidgetExport,
|
|
19201
|
+
getWidgetValidator: getWidgetValidator,
|
|
19386
19202
|
getEditor: getEditor,
|
|
19387
19203
|
getTransform: getTransform,
|
|
19388
19204
|
getVersion: getVersion,
|
|
@@ -19402,6 +19218,222 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19402
19218
|
isLintable: isLintable
|
|
19403
19219
|
});
|
|
19404
19220
|
|
|
19221
|
+
function emptyWidgetsFunctional(widgets,
|
|
19222
|
+
// This is a port of old code, I'm not sure why
|
|
19223
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19224
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19225
|
+
return widgetIds.filter(id => {
|
|
19226
|
+
const widget = widgets[id];
|
|
19227
|
+
if (!widget || widget.static) {
|
|
19228
|
+
// Static widgets shouldn't count as empty
|
|
19229
|
+
return false;
|
|
19230
|
+
}
|
|
19231
|
+
let score = null;
|
|
19232
|
+
const userInput = userInputMap[id];
|
|
19233
|
+
const validator = getWidgetValidator(widget.type);
|
|
19234
|
+
if (widget.type === "group") {
|
|
19235
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19236
|
+
score = Util.flattenScores(scores);
|
|
19237
|
+
} else if (validator) {
|
|
19238
|
+
score = validator(userInput, widget.options, strings, locale);
|
|
19239
|
+
}
|
|
19240
|
+
if (score) {
|
|
19241
|
+
return Util.scoreIsEmpty(score);
|
|
19242
|
+
}
|
|
19243
|
+
});
|
|
19244
|
+
}
|
|
19245
|
+
function scoreWidgetsFunctional(widgets,
|
|
19246
|
+
// This is a port of old code, I'm not sure why
|
|
19247
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19248
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19249
|
+
const gradedWidgetIds = widgetIds.filter(id => {
|
|
19250
|
+
const props = widgets[id];
|
|
19251
|
+
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
19252
|
+
const widgetIsStatic = !!(props != null && props.static);
|
|
19253
|
+
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
19254
|
+
return widgetIsGraded && !widgetIsStatic;
|
|
19255
|
+
});
|
|
19256
|
+
const widgetScores = {};
|
|
19257
|
+
gradedWidgetIds.forEach(id => {
|
|
19258
|
+
const widget = widgets[id];
|
|
19259
|
+
if (!widget) {
|
|
19260
|
+
return;
|
|
19261
|
+
}
|
|
19262
|
+
const userInput = userInputMap[id];
|
|
19263
|
+
const validator = getWidgetValidator(widget.type);
|
|
19264
|
+
if (widget.type === "group") {
|
|
19265
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19266
|
+
widgetScores[id] = Util.flattenScores(scores);
|
|
19267
|
+
} else if (validator) {
|
|
19268
|
+
widgetScores[id] = validator(userInput, widget.options, strings, locale);
|
|
19269
|
+
}
|
|
19270
|
+
});
|
|
19271
|
+
return widgetScores;
|
|
19272
|
+
}
|
|
19273
|
+
|
|
19274
|
+
/**
|
|
19275
|
+
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
19276
|
+
*
|
|
19277
|
+
* The poentry linter checks for issues that prevent content from being
|
|
19278
|
+
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
19279
|
+
* anything in non-KA environments.
|
|
19280
|
+
*/
|
|
19281
|
+
|
|
19282
|
+
// A LintCB is called once the linter has been run.
|
|
19283
|
+
|
|
19284
|
+
// msec to wait before we actually call the linter after receiving the
|
|
19285
|
+
// last call. The timer is reset if the lint is called during the wait.
|
|
19286
|
+
const DEBOUNCE_TIMEOUT = 1000;
|
|
19287
|
+
class TranslationLinter {
|
|
19288
|
+
constructor() {
|
|
19289
|
+
// To avoid linting when nothing has changed.
|
|
19290
|
+
this.previousContent = null;
|
|
19291
|
+
/**
|
|
19292
|
+
* Runs the poentry linter on the given perseus string asynchronously.
|
|
19293
|
+
*
|
|
19294
|
+
* It doesn't do anything unless we're in a KA environment.
|
|
19295
|
+
*
|
|
19296
|
+
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
19297
|
+
* called if perseusStr is unchanged from the last call.
|
|
19298
|
+
*
|
|
19299
|
+
* Linting is relatively expensive -- so we debounce linting each instance
|
|
19300
|
+
* for some amount of time.
|
|
19301
|
+
*/
|
|
19302
|
+
this.runLinter = debounce$1((perseusStr, onLintErrorsGenerated) => {
|
|
19303
|
+
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
19304
|
+
if (typeof KA === "undefined") {
|
|
19305
|
+
return;
|
|
19306
|
+
}
|
|
19307
|
+
if (perseusStr === this.previousContent) {
|
|
19308
|
+
return;
|
|
19309
|
+
}
|
|
19310
|
+
this.previousContent = perseusStr;
|
|
19311
|
+
if (perseusStr === "") {
|
|
19312
|
+
onLintErrorsGenerated([]);
|
|
19313
|
+
return;
|
|
19314
|
+
}
|
|
19315
|
+
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
19316
|
+
headers: {
|
|
19317
|
+
"Content-Type": "application/json"
|
|
19318
|
+
},
|
|
19319
|
+
body: JSON.stringify({
|
|
19320
|
+
// The poentry linter verifies that the translation from
|
|
19321
|
+
// the original text to the translated text is sane. We
|
|
19322
|
+
// want to ensure that the translation from English to
|
|
19323
|
+
// English is sane, so msgid === mstr.
|
|
19324
|
+
msgid: perseusStr,
|
|
19325
|
+
// msgid is the original text
|
|
19326
|
+
msgstr: perseusStr,
|
|
19327
|
+
// msgstr is the translated text
|
|
19328
|
+
format: "perseus_text",
|
|
19329
|
+
filename: ""
|
|
19330
|
+
}),
|
|
19331
|
+
method: "POST"
|
|
19332
|
+
}).then(response => {
|
|
19333
|
+
if (response.status >= 400) {
|
|
19334
|
+
return {
|
|
19335
|
+
status: "error",
|
|
19336
|
+
message: "Could not run i18n linter."
|
|
19337
|
+
};
|
|
19338
|
+
}
|
|
19339
|
+
return response.json();
|
|
19340
|
+
}, rejection => {
|
|
19341
|
+
return {
|
|
19342
|
+
status: "error",
|
|
19343
|
+
message: "Could not run i18n linter."
|
|
19344
|
+
};
|
|
19345
|
+
}).then(json => {
|
|
19346
|
+
if (json.status === "error") {
|
|
19347
|
+
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
19348
|
+
} else {
|
|
19349
|
+
onLintErrorsGenerated([]);
|
|
19350
|
+
}
|
|
19351
|
+
});
|
|
19352
|
+
}, DEBOUNCE_TIMEOUT);
|
|
19353
|
+
}
|
|
19354
|
+
/**
|
|
19355
|
+
* Applies an array of errors generated by linters without position
|
|
19356
|
+
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
19357
|
+
* top of a Perseus tree.
|
|
19358
|
+
*/
|
|
19359
|
+
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
19360
|
+
// These lint errors do not have position data associated with
|
|
19361
|
+
// them, so we just plop them at the top.
|
|
19362
|
+
if (translationLintErrors.length) {
|
|
19363
|
+
const errorText = translationLintErrors.join("\n\n");
|
|
19364
|
+
parsedMarkdown.unshift({
|
|
19365
|
+
content: {
|
|
19366
|
+
type: "text",
|
|
19367
|
+
content: ""
|
|
19368
|
+
},
|
|
19369
|
+
insideTable: false,
|
|
19370
|
+
message: errorText,
|
|
19371
|
+
ruleName: "legacy-error",
|
|
19372
|
+
severity: Rule.Severity.ERROR,
|
|
19373
|
+
type: "lint"
|
|
19374
|
+
});
|
|
19375
|
+
}
|
|
19376
|
+
}
|
|
19377
|
+
}
|
|
19378
|
+
|
|
19379
|
+
/**
|
|
19380
|
+
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
19381
|
+
* to things is does.
|
|
19382
|
+
*/
|
|
19383
|
+
var preprocessTex = (texCode => texCode
|
|
19384
|
+
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
19385
|
+
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
19386
|
+
// the same is supported by KaTeX. It does the same for align*.
|
|
19387
|
+
// TODO(kevinb) update content to use aligned instead of align.
|
|
19388
|
+
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
19389
|
+
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
19390
|
+
// "aligned").
|
|
19391
|
+
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
19392
|
+
// Replace non-breaking spaces with regular spaces.
|
|
19393
|
+
.replace(/[\u00a0]/g, " "));
|
|
19394
|
+
|
|
19395
|
+
const {
|
|
19396
|
+
interactiveSizes
|
|
19397
|
+
} = constants$1;
|
|
19398
|
+
|
|
19399
|
+
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
19400
|
+
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
19401
|
+
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
19402
|
+
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
19403
|
+
const smMax = articleMaxWidthTableInPx;
|
|
19404
|
+
const mdMax = articleMaxWidthInPx;
|
|
19405
|
+
const containerSizeClass = {
|
|
19406
|
+
SMALL: "small",
|
|
19407
|
+
MEDIUM: "medium",
|
|
19408
|
+
LARGE: "large",
|
|
19409
|
+
XLARGE: "xlarge"
|
|
19410
|
+
};
|
|
19411
|
+
const getClassFromWidth = width => {
|
|
19412
|
+
if (!width) {
|
|
19413
|
+
return containerSizeClass.MEDIUM;
|
|
19414
|
+
}
|
|
19415
|
+
if (width <= smMax) {
|
|
19416
|
+
return containerSizeClass.SMALL;
|
|
19417
|
+
}
|
|
19418
|
+
if (width <= mdMax) {
|
|
19419
|
+
return containerSizeClass.MEDIUM;
|
|
19420
|
+
}
|
|
19421
|
+
return containerSizeClass.LARGE;
|
|
19422
|
+
};
|
|
19423
|
+
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
19424
|
+
if (sizeClass === containerSizeClass.SMALL) {
|
|
19425
|
+
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
19426
|
+
}
|
|
19427
|
+
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
19428
|
+
};
|
|
19429
|
+
|
|
19430
|
+
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
19431
|
+
__proto__: null,
|
|
19432
|
+
containerSizeClass: containerSizeClass,
|
|
19433
|
+
getClassFromWidth: getClassFromWidth,
|
|
19434
|
+
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
19435
|
+
});
|
|
19436
|
+
|
|
19405
19437
|
class WidgetContainer extends React.Component {
|
|
19406
19438
|
constructor(...args) {
|
|
19407
19439
|
super(...args);
|
|
@@ -19547,8 +19579,7 @@ WidgetContainer.defaultProps = {
|
|
|
19547
19579
|
};
|
|
19548
19580
|
|
|
19549
19581
|
const {
|
|
19550
|
-
mapObject
|
|
19551
|
-
mapObjectFromArray
|
|
19582
|
+
mapObject
|
|
19552
19583
|
} = objective_;
|
|
19553
19584
|
const rContainsNonWhitespace = /\S/;
|
|
19554
19585
|
const rImageURL = /(web\+graphie|https):\/\/[^\s]*/;
|
|
@@ -19713,11 +19744,7 @@ class Renderer extends React.Component {
|
|
|
19713
19744
|
}
|
|
19714
19745
|
let interactionTracker = this._interactionTrackers[id];
|
|
19715
19746
|
if (!interactionTracker) {
|
|
19716
|
-
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction,
|
|
19717
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
19718
|
-
widgetInfo && widgetInfo.type, id,
|
|
19719
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
19720
|
-
getTracking(widgetInfo && widgetInfo.type));
|
|
19747
|
+
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction, widgetInfo && widgetInfo.type, id, getTracking(widgetInfo && widgetInfo.type));
|
|
19721
19748
|
}
|
|
19722
19749
|
return _extends({}, widgetProps, {
|
|
19723
19750
|
widgetId: id,
|
|
@@ -20495,23 +20522,6 @@ class Renderer extends React.Component {
|
|
|
20495
20522
|
}, this);
|
|
20496
20523
|
return state;
|
|
20497
20524
|
};
|
|
20498
|
-
this.emptyWidgets = () => {
|
|
20499
|
-
// @ts-expect-error - TS2345 - Argument of type '(id: string) => boolean | undefined' is not assignable to parameter of type 'Iteratee<string[], boolean, string>'.
|
|
20500
|
-
return _.filter(this.widgetIds, id => {
|
|
20501
|
-
const widgetInfo = this._getWidgetInfo(id);
|
|
20502
|
-
if (widgetInfo.static) {
|
|
20503
|
-
// Static widgets shouldn't count as empty
|
|
20504
|
-
return false;
|
|
20505
|
-
}
|
|
20506
|
-
const widget = this.getWidgetInstance(id);
|
|
20507
|
-
if (widget && widget.simpleValidate) {
|
|
20508
|
-
const score = widget.simpleValidate(widgetInfo.options,
|
|
20509
|
-
// @ts-expect-error - TS2345 - Argument of type 'null' is not assignable to parameter of type '((widgetId: any, value: string, message?: string | null | undefined) => unknown) | undefined'.
|
|
20510
|
-
null);
|
|
20511
|
-
return Util.scoreIsEmpty(score);
|
|
20512
|
-
}
|
|
20513
|
-
});
|
|
20514
|
-
};
|
|
20515
20525
|
this._setWidgetProps = (id, newProps, cb, silent) => {
|
|
20516
20526
|
this.setState(prevState => {
|
|
20517
20527
|
const widgetProps = _extends({}, prevState.widgetProps, {
|
|
@@ -20568,19 +20578,6 @@ class Renderer extends React.Component {
|
|
|
20568
20578
|
// Widget handles parsing of the interWidgetPath.
|
|
20569
20579
|
widget == null || widget.setInputValue == null || widget.setInputValue(interWidgetPath, newValue, focus);
|
|
20570
20580
|
};
|
|
20571
|
-
/**
|
|
20572
|
-
* Returns an array of the widget `.getUserInput()` results
|
|
20573
|
-
*/
|
|
20574
|
-
this.getUserInput = () => {
|
|
20575
|
-
return this.widgetIds.map(id => {
|
|
20576
|
-
const widget = this.getWidgetInstance(id);
|
|
20577
|
-
if (widget && widget.getUserInput) {
|
|
20578
|
-
// TODO(Jeremy): Add the widget ID in here so we can more
|
|
20579
|
-
// easily correlate it to the widget state.
|
|
20580
|
-
return widget.getUserInput();
|
|
20581
|
-
}
|
|
20582
|
-
});
|
|
20583
|
-
};
|
|
20584
20581
|
/**
|
|
20585
20582
|
* Returns an array of all widget IDs in the order they occur in
|
|
20586
20583
|
* the content.
|
|
@@ -20588,56 +20585,6 @@ class Renderer extends React.Component {
|
|
|
20588
20585
|
this.getWidgetIds = () => {
|
|
20589
20586
|
return this.widgetIds;
|
|
20590
20587
|
};
|
|
20591
|
-
/**
|
|
20592
|
-
* Returns the result of `.getUserInput()` for each widget, in
|
|
20593
|
-
* a map from widgetId to userInput.
|
|
20594
|
-
* NOTE(jeremy): This function is hauntingly similar to `getUserInput` with
|
|
20595
|
-
* the major difference being that this function returns a map of
|
|
20596
|
-
* `widgetID` => UserInput and `getUserInput` simply returns an array. It
|
|
20597
|
-
* would be trivial to map between the results of each of these functions,
|
|
20598
|
-
* so we should aim to remove one of these functions.
|
|
20599
|
-
*/
|
|
20600
|
-
this.getUserInputForWidgets = () => {
|
|
20601
|
-
return mapObjectFromArray(this.widgetIds, id => {
|
|
20602
|
-
const widget = this.getWidgetInstance(id);
|
|
20603
|
-
if (widget && widget.getUserInput) {
|
|
20604
|
-
return widget.getUserInput();
|
|
20605
|
-
}
|
|
20606
|
-
});
|
|
20607
|
-
};
|
|
20608
|
-
/**
|
|
20609
|
-
* Returns an object mapping from widget ID to perseus-style score.
|
|
20610
|
-
* The keys of this object are the values of the array returned
|
|
20611
|
-
* from `getWidgetIds`.
|
|
20612
|
-
*/
|
|
20613
|
-
this.scoreWidgets = () => {
|
|
20614
|
-
const widgetProps = this.state.widgetInfo;
|
|
20615
|
-
const gradedWidgetIds = _.filter(this.widgetIds, id => {
|
|
20616
|
-
const props = widgetProps[id];
|
|
20617
|
-
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
20618
|
-
const widgetIsStatic = !!(props != null && props.static);
|
|
20619
|
-
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
20620
|
-
return widgetIsGraded && !widgetIsStatic;
|
|
20621
|
-
});
|
|
20622
|
-
const widgetScores = {};
|
|
20623
|
-
_.each(gradedWidgetIds, id => {
|
|
20624
|
-
const props = widgetProps[id];
|
|
20625
|
-
const widget = this.getWidgetInstance(id);
|
|
20626
|
-
// widget can be undefined if it hasn't yet been rendered
|
|
20627
|
-
if (widget && widget.simpleValidate) {
|
|
20628
|
-
widgetScores[id] = widget.simpleValidate(_extends({}, props == null ? void 0 : props.options, {
|
|
20629
|
-
scoring: true
|
|
20630
|
-
}));
|
|
20631
|
-
}
|
|
20632
|
-
});
|
|
20633
|
-
return widgetScores;
|
|
20634
|
-
};
|
|
20635
|
-
/**
|
|
20636
|
-
* Grades the content.
|
|
20637
|
-
*/
|
|
20638
|
-
this.score = () => {
|
|
20639
|
-
return _.reduce(this.scoreWidgets(), Util.combineScores, Util.noScore);
|
|
20640
|
-
};
|
|
20641
20588
|
this.guessAndScore = () => {
|
|
20642
20589
|
const totalGuess = this.getUserInput();
|
|
20643
20590
|
const totalScore = this.score();
|
|
@@ -20811,6 +20758,59 @@ class Renderer extends React.Component {
|
|
|
20811
20758
|
}
|
|
20812
20759
|
this._isMounted = false;
|
|
20813
20760
|
}
|
|
20761
|
+
emptyWidgets() {
|
|
20762
|
+
return emptyWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20763
|
+
}
|
|
20764
|
+
/**
|
|
20765
|
+
* Returns an array of the widget `.getUserInput()` results
|
|
20766
|
+
*
|
|
20767
|
+
* TODO: can we remove this?
|
|
20768
|
+
* @deprecated use getUserInputMap
|
|
20769
|
+
*/
|
|
20770
|
+
getUserInput() {
|
|
20771
|
+
return this.widgetIds.map(id => {
|
|
20772
|
+
const widget = this.getWidgetInstance(id);
|
|
20773
|
+
if (widget && widget.getUserInput) {
|
|
20774
|
+
// TODO(Jeremy): Add the widget ID in here so we can more
|
|
20775
|
+
// easily correlate it to the widget state.
|
|
20776
|
+
return widget.getUserInput();
|
|
20777
|
+
}
|
|
20778
|
+
});
|
|
20779
|
+
}
|
|
20780
|
+
|
|
20781
|
+
/**
|
|
20782
|
+
* Returns an object of the widget `.getUserInput()` results
|
|
20783
|
+
*/
|
|
20784
|
+
getUserInputMap() {
|
|
20785
|
+
const userInputMap = {};
|
|
20786
|
+
this.widgetIds.forEach(id => {
|
|
20787
|
+
const widget = this.getWidgetInstance(id);
|
|
20788
|
+
// Handle Groups, which have their own sets of widgets
|
|
20789
|
+
if (widget != null && widget.getUserInputMap) {
|
|
20790
|
+
userInputMap[id] = widget.getUserInputMap();
|
|
20791
|
+
} else if (widget != null && widget.getUserInput) {
|
|
20792
|
+
userInputMap[id] = widget.getUserInput();
|
|
20793
|
+
}
|
|
20794
|
+
});
|
|
20795
|
+
return userInputMap;
|
|
20796
|
+
}
|
|
20797
|
+
/**
|
|
20798
|
+
* Returns an object mapping from widget ID to perseus-style score.
|
|
20799
|
+
* The keys of this object are the values of the array returned
|
|
20800
|
+
* from `getWidgetIds`.
|
|
20801
|
+
*/
|
|
20802
|
+
scoreWidgets() {
|
|
20803
|
+
return scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20804
|
+
}
|
|
20805
|
+
|
|
20806
|
+
/**
|
|
20807
|
+
* Grades the content.
|
|
20808
|
+
*/
|
|
20809
|
+
score() {
|
|
20810
|
+
const scores = this.scoreWidgets();
|
|
20811
|
+
const combinedScore = Util.flattenScores(scores);
|
|
20812
|
+
return combinedScore;
|
|
20813
|
+
}
|
|
20814
20814
|
render() {
|
|
20815
20815
|
const apiOptions = this.getApiOptions();
|
|
20816
20816
|
if (this.reuseMarkdown) {
|
|
@@ -20885,11 +20885,11 @@ class Renderer extends React.Component {
|
|
|
20885
20885
|
// If highlightLint is true and lint is detected, this call
|
|
20886
20886
|
// will modify the parse tree by adding lint nodes that will
|
|
20887
20887
|
// serve to highlight the lint when rendered
|
|
20888
|
-
const
|
|
20888
|
+
const fullLinterContext = _extends({
|
|
20889
20889
|
content: this.props.content,
|
|
20890
20890
|
widgets: this.props.widgets
|
|
20891
20891
|
}, this.props.linterContext);
|
|
20892
|
-
PerseusLinter.runLinter(parsedMarkdown,
|
|
20892
|
+
PerseusLinter.runLinter(parsedMarkdown, fullLinterContext, true);
|
|
20893
20893
|
|
|
20894
20894
|
// Apply the lint errors from the last TranslationLinter run.
|
|
20895
20895
|
// TODO(joshuan): Support overlapping dots.
|
|
@@ -20911,6 +20911,7 @@ class Renderer extends React.Component {
|
|
|
20911
20911
|
return this.lastRenderedMarkdown;
|
|
20912
20912
|
}
|
|
20913
20913
|
}
|
|
20914
|
+
Renderer.contextType = PerseusI18nContext;
|
|
20914
20915
|
Renderer.defaultProps = {
|
|
20915
20916
|
content: "",
|
|
20916
20917
|
widgets: {},
|
|
@@ -21398,6 +21399,16 @@ InputWithExamples.defaultProps = {
|
|
|
21398
21399
|
className: ""
|
|
21399
21400
|
};
|
|
21400
21401
|
|
|
21402
|
+
function _objectWithoutPropertiesLoose(r, e) {
|
|
21403
|
+
if (null == r) return {};
|
|
21404
|
+
var t = {};
|
|
21405
|
+
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
21406
|
+
if (e.includes(n)) continue;
|
|
21407
|
+
t[n] = r[n];
|
|
21408
|
+
}
|
|
21409
|
+
return t;
|
|
21410
|
+
}
|
|
21411
|
+
|
|
21401
21412
|
const _excluded$4 = ["keypadElement", "onFocus", "value"];
|
|
21402
21413
|
class SimpleKeypadInput extends React.Component {
|
|
21403
21414
|
constructor(...args) {
|
|
@@ -21800,30 +21811,14 @@ class InputNumber extends React.Component {
|
|
|
21800
21811
|
return [strings.yourAnswer].concat(examples);
|
|
21801
21812
|
};
|
|
21802
21813
|
}
|
|
21803
|
-
static validate(state, rubric, strings) {
|
|
21804
|
-
return inputNumberValidator(state, rubric, strings);
|
|
21805
|
-
}
|
|
21806
21814
|
static getUserInputFromProps(props) {
|
|
21807
21815
|
return {
|
|
21808
21816
|
currentValue: props.currentValue
|
|
21809
21817
|
};
|
|
21810
21818
|
}
|
|
21811
|
-
static getOneCorrectAnswerFromRubric(rubric) {
|
|
21812
|
-
if (rubric.value == null) {
|
|
21813
|
-
return;
|
|
21814
|
-
}
|
|
21815
|
-
let answerString = String(rubric.value);
|
|
21816
|
-
if (rubric.inexact && rubric.maxError) {
|
|
21817
|
-
answerString += " \u00B1 " + rubric.maxError;
|
|
21818
|
-
}
|
|
21819
|
-
return answerString;
|
|
21820
|
-
}
|
|
21821
21819
|
getUserInput() {
|
|
21822
21820
|
return InputNumber.getUserInputFromProps(this.props);
|
|
21823
21821
|
}
|
|
21824
|
-
simpleValidate(rubric) {
|
|
21825
|
-
return inputNumberValidator(this.getUserInput(), rubric, this.context.strings);
|
|
21826
|
-
}
|
|
21827
21822
|
render() {
|
|
21828
21823
|
if (this.props.apiOptions.customKeypad) {
|
|
21829
21824
|
// TODO(charlie): Support "Review Mode".
|
|
@@ -21928,7 +21923,18 @@ var InputNumber$1 = {
|
|
|
21928
21923
|
hidden: true,
|
|
21929
21924
|
widget: InputNumber,
|
|
21930
21925
|
transform: propTransform$3,
|
|
21931
|
-
isLintable: true
|
|
21926
|
+
isLintable: true,
|
|
21927
|
+
validator: inputNumberValidator,
|
|
21928
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
21929
|
+
if (rubric.value == null) {
|
|
21930
|
+
return;
|
|
21931
|
+
}
|
|
21932
|
+
let answerString = String(rubric.value);
|
|
21933
|
+
if (rubric.inexact && rubric.maxError) {
|
|
21934
|
+
answerString += " \u00B1 " + rubric.maxError;
|
|
21935
|
+
}
|
|
21936
|
+
return answerString;
|
|
21937
|
+
}
|
|
21932
21938
|
};
|
|
21933
21939
|
|
|
21934
21940
|
const ParseTex = TexWrangler.parseTex;
|
|
@@ -22174,7 +22180,135 @@ class NumericInput extends React.Component {
|
|
|
22174
22180
|
currentValue: props.currentValue
|
|
22175
22181
|
};
|
|
22176
22182
|
}
|
|
22177
|
-
|
|
22183
|
+
getUserInput() {
|
|
22184
|
+
return NumericInput.getUserInputFromProps(this.props);
|
|
22185
|
+
}
|
|
22186
|
+
render() {
|
|
22187
|
+
let labelText = this.props.labelText;
|
|
22188
|
+
if (labelText == null || labelText === "") {
|
|
22189
|
+
labelText = this.context.strings.yourAnswerLabel;
|
|
22190
|
+
}
|
|
22191
|
+
|
|
22192
|
+
// To right align a custom keypad we need to wrap it.
|
|
22193
|
+
const maybeRightAlignKeypadInput = keypadInput => {
|
|
22194
|
+
return this.props.rightAlign ? /*#__PURE__*/React.createElement("div", {
|
|
22195
|
+
className: "perseus-input-right-align"
|
|
22196
|
+
}, keypadInput) : keypadInput;
|
|
22197
|
+
};
|
|
22198
|
+
if (this.props.apiOptions.customKeypad) {
|
|
22199
|
+
// TODO(charlie): Support "Review Mode".
|
|
22200
|
+
return maybeRightAlignKeypadInput( /*#__PURE__*/React.createElement(SimpleKeypadInput, {
|
|
22201
|
+
ref: ref => this.inputRef = ref,
|
|
22202
|
+
value: this.props.currentValue,
|
|
22203
|
+
keypadElement: this.props.keypadElement,
|
|
22204
|
+
onChange: this.handleChange,
|
|
22205
|
+
onFocus: this._handleFocus,
|
|
22206
|
+
onBlur: this._handleBlur
|
|
22207
|
+
}));
|
|
22208
|
+
}
|
|
22209
|
+
|
|
22210
|
+
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
22211
|
+
// you modify this, double-check if you also need to modify that
|
|
22212
|
+
// component.
|
|
22213
|
+
const styles = StyleSheet.create({
|
|
22214
|
+
input: {
|
|
22215
|
+
textAlign: this.props.rightAlign ? "right" : "left",
|
|
22216
|
+
width: this.props.size === "small" ? 40 : 80,
|
|
22217
|
+
padding: 0,
|
|
22218
|
+
height: "auto"
|
|
22219
|
+
}
|
|
22220
|
+
});
|
|
22221
|
+
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(InputWithExamples, {
|
|
22222
|
+
ref: ref => this.inputRef = ref,
|
|
22223
|
+
value: this.props.currentValue,
|
|
22224
|
+
onChange: this.handleChange,
|
|
22225
|
+
labelText: labelText,
|
|
22226
|
+
examples: this.examples(),
|
|
22227
|
+
shouldShowExamples: this.shouldShowExamples(),
|
|
22228
|
+
onFocus: this._handleFocus,
|
|
22229
|
+
onBlur: this._handleBlur,
|
|
22230
|
+
id: this.props.widgetId,
|
|
22231
|
+
disabled: this.props.apiOptions.readOnly,
|
|
22232
|
+
style: styles.input
|
|
22233
|
+
}));
|
|
22234
|
+
}
|
|
22235
|
+
}
|
|
22236
|
+
|
|
22237
|
+
// TODO(thomas): Currently we receive a list of lists of acceptable answer types
|
|
22238
|
+
// and union them down into a single set. It's worth considering whether it
|
|
22239
|
+
// wouldn't make more sense to have a single set of acceptable answer types for
|
|
22240
|
+
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
22241
|
+
// When should two answers to a problem take different answer types?
|
|
22242
|
+
// See D27790 for more discussion.
|
|
22243
|
+
NumericInput.contextType = PerseusI18nContext;
|
|
22244
|
+
NumericInput.defaultProps = {
|
|
22245
|
+
currentValue: "",
|
|
22246
|
+
size: "normal",
|
|
22247
|
+
rightAlign: false,
|
|
22248
|
+
apiOptions: ApiOptions.defaults,
|
|
22249
|
+
coefficient: false,
|
|
22250
|
+
answerForms: [],
|
|
22251
|
+
labelText: "",
|
|
22252
|
+
linterContext: linterContextDefault
|
|
22253
|
+
};
|
|
22254
|
+
const unionAnswerForms = function unionAnswerForms(answerFormsList) {
|
|
22255
|
+
// Takes a list of lists of answer forms, and returns a list of the forms
|
|
22256
|
+
// in each of these lists in the same order that they're listed in the
|
|
22257
|
+
// `formExamples` forms from above.
|
|
22258
|
+
|
|
22259
|
+
// uniqueBy takes a list of elements and a function which compares whether
|
|
22260
|
+
// two elements are equal, and returns a list of unique elements. This is
|
|
22261
|
+
// just a helper function here, but works generally.
|
|
22262
|
+
const uniqueBy = function uniqueBy(list, iteratee) {
|
|
22263
|
+
// @ts-expect-error - TS2347 - Untyped function calls may not accept type arguments.
|
|
22264
|
+
return list.reduce((uniqueList, element) => {
|
|
22265
|
+
// For each element, decide whether it's already in the list of
|
|
22266
|
+
// unique items.
|
|
22267
|
+
const inList = _.find(uniqueList, iteratee.bind(null, element));
|
|
22268
|
+
if (inList) {
|
|
22269
|
+
return uniqueList;
|
|
22270
|
+
}
|
|
22271
|
+
return uniqueList.concat([element]);
|
|
22272
|
+
}, []);
|
|
22273
|
+
};
|
|
22274
|
+
|
|
22275
|
+
// Pull out all of the forms from the different lists.
|
|
22276
|
+
const allForms = answerFormsList.flat();
|
|
22277
|
+
// Pull out the unique forms using uniqueBy.
|
|
22278
|
+
const uniqueForms = uniqueBy(allForms, _.isEqual);
|
|
22279
|
+
// Sort them by the order they appear in the `formExamples` list.
|
|
22280
|
+
const formExampleKeys = Object.keys(formExamples);
|
|
22281
|
+
return _.sortBy(uniqueForms, form => {
|
|
22282
|
+
return formExampleKeys.indexOf(form.name);
|
|
22283
|
+
});
|
|
22284
|
+
};
|
|
22285
|
+
const propsTransform = function propsTransform(widgetOptions) {
|
|
22286
|
+
const rendererProps = _.extend(_.omit(widgetOptions, "answers"), {
|
|
22287
|
+
answerForms: unionAnswerForms(
|
|
22288
|
+
// Pull out the name of each form and whether that form has
|
|
22289
|
+
// required simplification.
|
|
22290
|
+
widgetOptions.answers.map(answer => {
|
|
22291
|
+
// @ts-expect-error - TS2345 - Argument of type 'readonly MathFormat[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
22292
|
+
return _.map(answer.answerForms, form => {
|
|
22293
|
+
return {
|
|
22294
|
+
simplify: answer.simplify,
|
|
22295
|
+
name: form
|
|
22296
|
+
};
|
|
22297
|
+
});
|
|
22298
|
+
}))
|
|
22299
|
+
});
|
|
22300
|
+
return rendererProps;
|
|
22301
|
+
};
|
|
22302
|
+
var NumericInput$1 = {
|
|
22303
|
+
name: "numeric-input",
|
|
22304
|
+
displayName: "Numeric input",
|
|
22305
|
+
defaultAlignment: "inline-block",
|
|
22306
|
+
accessible: true,
|
|
22307
|
+
widget: NumericInput,
|
|
22308
|
+
transform: propsTransform,
|
|
22309
|
+
isLintable: true,
|
|
22310
|
+
validator: numericInputValidator,
|
|
22311
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
22178
22312
|
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
22179
22313
|
const answerStrings = correctAnswers.map(answer => {
|
|
22180
22314
|
// Figure out how this answer is supposed to be
|
|
@@ -22202,139 +22336,6 @@ class NumericInput extends React.Component {
|
|
|
22202
22336
|
}
|
|
22203
22337
|
return answerStrings[0];
|
|
22204
22338
|
}
|
|
22205
|
-
static validate(userInput, rubric, strings) {
|
|
22206
|
-
return numericInputValidator(userInput, rubric, strings);
|
|
22207
|
-
}
|
|
22208
|
-
simpleValidate(rubric) {
|
|
22209
|
-
return numericInputValidator(this.getUserInput(), rubric, this.context.strings);
|
|
22210
|
-
}
|
|
22211
|
-
getUserInput() {
|
|
22212
|
-
return NumericInput.getUserInputFromProps(this.props);
|
|
22213
|
-
}
|
|
22214
|
-
render() {
|
|
22215
|
-
let labelText = this.props.labelText;
|
|
22216
|
-
if (labelText == null || labelText === "") {
|
|
22217
|
-
labelText = this.context.strings.yourAnswerLabel;
|
|
22218
|
-
}
|
|
22219
|
-
|
|
22220
|
-
// To right align a custom keypad we need to wrap it.
|
|
22221
|
-
const maybeRightAlignKeypadInput = keypadInput => {
|
|
22222
|
-
return this.props.rightAlign ? /*#__PURE__*/React.createElement("div", {
|
|
22223
|
-
className: "perseus-input-right-align"
|
|
22224
|
-
}, keypadInput) : keypadInput;
|
|
22225
|
-
};
|
|
22226
|
-
if (this.props.apiOptions.customKeypad) {
|
|
22227
|
-
// TODO(charlie): Support "Review Mode".
|
|
22228
|
-
return maybeRightAlignKeypadInput( /*#__PURE__*/React.createElement(SimpleKeypadInput, {
|
|
22229
|
-
ref: ref => this.inputRef = ref,
|
|
22230
|
-
value: this.props.currentValue,
|
|
22231
|
-
keypadElement: this.props.keypadElement,
|
|
22232
|
-
onChange: this.handleChange,
|
|
22233
|
-
onFocus: this._handleFocus,
|
|
22234
|
-
onBlur: this._handleBlur
|
|
22235
|
-
}));
|
|
22236
|
-
}
|
|
22237
|
-
|
|
22238
|
-
// Note: This is _very_ similar to what `input-number.jsx` does. If
|
|
22239
|
-
// you modify this, double-check if you also need to modify that
|
|
22240
|
-
// component.
|
|
22241
|
-
const styles = StyleSheet.create({
|
|
22242
|
-
input: {
|
|
22243
|
-
textAlign: this.props.rightAlign ? "right" : "left",
|
|
22244
|
-
width: this.props.size === "small" ? 40 : 80,
|
|
22245
|
-
padding: 0,
|
|
22246
|
-
height: "auto"
|
|
22247
|
-
}
|
|
22248
|
-
});
|
|
22249
|
-
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(InputWithExamples, {
|
|
22250
|
-
ref: ref => this.inputRef = ref,
|
|
22251
|
-
value: this.props.currentValue,
|
|
22252
|
-
onChange: this.handleChange,
|
|
22253
|
-
labelText: labelText,
|
|
22254
|
-
examples: this.examples(),
|
|
22255
|
-
shouldShowExamples: this.shouldShowExamples(),
|
|
22256
|
-
onFocus: this._handleFocus,
|
|
22257
|
-
onBlur: this._handleBlur,
|
|
22258
|
-
id: this.props.widgetId,
|
|
22259
|
-
disabled: this.props.apiOptions.readOnly,
|
|
22260
|
-
style: styles.input
|
|
22261
|
-
}));
|
|
22262
|
-
}
|
|
22263
|
-
}
|
|
22264
|
-
|
|
22265
|
-
// TODO(thomas): Currently we receive a list of lists of acceptable answer types
|
|
22266
|
-
// and union them down into a single set. It's worth considering whether it
|
|
22267
|
-
// wouldn't make more sense to have a single set of acceptable answer types for
|
|
22268
|
-
// a given *problem* rather than for each possible [correct/wrong] *answer*.
|
|
22269
|
-
// When should two answers to a problem take different answer types?
|
|
22270
|
-
// See D27790 for more discussion.
|
|
22271
|
-
NumericInput.contextType = PerseusI18nContext;
|
|
22272
|
-
NumericInput.defaultProps = {
|
|
22273
|
-
currentValue: "",
|
|
22274
|
-
size: "normal",
|
|
22275
|
-
rightAlign: false,
|
|
22276
|
-
apiOptions: ApiOptions.defaults,
|
|
22277
|
-
coefficient: false,
|
|
22278
|
-
answerForms: [],
|
|
22279
|
-
labelText: "",
|
|
22280
|
-
linterContext: linterContextDefault
|
|
22281
|
-
};
|
|
22282
|
-
const unionAnswerForms = function unionAnswerForms(answerFormsList) {
|
|
22283
|
-
// Takes a list of lists of answer forms, and returns a list of the forms
|
|
22284
|
-
// in each of these lists in the same order that they're listed in the
|
|
22285
|
-
// `formExamples` forms from above.
|
|
22286
|
-
|
|
22287
|
-
// uniqueBy takes a list of elements and a function which compares whether
|
|
22288
|
-
// two elements are equal, and returns a list of unique elements. This is
|
|
22289
|
-
// just a helper function here, but works generally.
|
|
22290
|
-
const uniqueBy = function uniqueBy(list, iteratee) {
|
|
22291
|
-
// @ts-expect-error - TS2347 - Untyped function calls may not accept type arguments.
|
|
22292
|
-
return list.reduce((uniqueList, element) => {
|
|
22293
|
-
// For each element, decide whether it's already in the list of
|
|
22294
|
-
// unique items.
|
|
22295
|
-
const inList = _.find(uniqueList, iteratee.bind(null, element));
|
|
22296
|
-
if (inList) {
|
|
22297
|
-
return uniqueList;
|
|
22298
|
-
}
|
|
22299
|
-
return uniqueList.concat([element]);
|
|
22300
|
-
}, []);
|
|
22301
|
-
};
|
|
22302
|
-
|
|
22303
|
-
// Pull out all of the forms from the different lists.
|
|
22304
|
-
const allForms = answerFormsList.flat();
|
|
22305
|
-
// Pull out the unique forms using uniqueBy.
|
|
22306
|
-
const uniqueForms = uniqueBy(allForms, _.isEqual);
|
|
22307
|
-
// Sort them by the order they appear in the `formExamples` list.
|
|
22308
|
-
const formExampleKeys = Object.keys(formExamples);
|
|
22309
|
-
return _.sortBy(uniqueForms, form => {
|
|
22310
|
-
return formExampleKeys.indexOf(form.name);
|
|
22311
|
-
});
|
|
22312
|
-
};
|
|
22313
|
-
const propsTransform = function propsTransform(widgetOptions) {
|
|
22314
|
-
const rendererProps = _.extend(_.omit(widgetOptions, "answers"), {
|
|
22315
|
-
answerForms: unionAnswerForms(
|
|
22316
|
-
// Pull out the name of each form and whether that form has
|
|
22317
|
-
// required simplification.
|
|
22318
|
-
widgetOptions.answers.map(answer => {
|
|
22319
|
-
// @ts-expect-error - TS2345 - Argument of type 'readonly MathFormat[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
22320
|
-
return _.map(answer.answerForms, form => {
|
|
22321
|
-
return {
|
|
22322
|
-
simplify: answer.simplify,
|
|
22323
|
-
name: form
|
|
22324
|
-
};
|
|
22325
|
-
});
|
|
22326
|
-
}))
|
|
22327
|
-
});
|
|
22328
|
-
return rendererProps;
|
|
22329
|
-
};
|
|
22330
|
-
var NumericInput$1 = {
|
|
22331
|
-
name: "numeric-input",
|
|
22332
|
-
displayName: "Numeric input",
|
|
22333
|
-
defaultAlignment: "inline-block",
|
|
22334
|
-
accessible: true,
|
|
22335
|
-
widget: NumericInput,
|
|
22336
|
-
transform: propsTransform,
|
|
22337
|
-
isLintable: true
|
|
22338
22339
|
};
|
|
22339
22340
|
|
|
22340
22341
|
/**
|
|
@@ -24142,6 +24143,9 @@ class Passage extends React.Component {
|
|
|
24142
24143
|
this._onResize = void 0;
|
|
24143
24144
|
// @ts-expect-error - TS2564 - Property '_stylesAppiedTimer' has no initializer and is not definitely assigned in the constructor.
|
|
24144
24145
|
this._stylesAppiedTimer = void 0;
|
|
24146
|
+
// this just helps with TS weak typing when a Widget
|
|
24147
|
+
// doesn't implement any Widget methods
|
|
24148
|
+
this.isWidget = true;
|
|
24145
24149
|
this.state = {
|
|
24146
24150
|
nLines: null,
|
|
24147
24151
|
startLineNumbersAfter: 0,
|
|
@@ -24153,10 +24157,6 @@ class Passage extends React.Component {
|
|
|
24153
24157
|
});
|
|
24154
24158
|
};
|
|
24155
24159
|
}
|
|
24156
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24157
|
-
static validate() {
|
|
24158
|
-
return noopValidator();
|
|
24159
|
-
}
|
|
24160
24160
|
componentDidMount() {
|
|
24161
24161
|
this._updateState();
|
|
24162
24162
|
|
|
@@ -24361,21 +24361,6 @@ class Passage extends React.Component {
|
|
|
24361
24361
|
};
|
|
24362
24362
|
}
|
|
24363
24363
|
|
|
24364
|
-
/**
|
|
24365
|
-
* Misc functions
|
|
24366
|
-
*
|
|
24367
|
-
* These are misc widget functions used for the widget API
|
|
24368
|
-
*/
|
|
24369
|
-
|
|
24370
|
-
getUserInput() {
|
|
24371
|
-
return null;
|
|
24372
|
-
}
|
|
24373
|
-
|
|
24374
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24375
|
-
simpleValidate() {
|
|
24376
|
-
return noopValidator();
|
|
24377
|
-
}
|
|
24378
|
-
|
|
24379
24364
|
/**
|
|
24380
24365
|
* Rendering
|
|
24381
24366
|
*
|
|
@@ -24528,7 +24513,8 @@ var Passage$1 = {
|
|
|
24528
24513
|
transform: editorProps => {
|
|
24529
24514
|
return _.pick(editorProps, "passageTitle", "passageText", "footnotes", "showLineNumbers");
|
|
24530
24515
|
},
|
|
24531
|
-
isLintable: true
|
|
24516
|
+
isLintable: true,
|
|
24517
|
+
validator: () => noopValidator()
|
|
24532
24518
|
};
|
|
24533
24519
|
|
|
24534
24520
|
/**
|
|
@@ -24554,6 +24540,9 @@ class PassageRef extends React.Component {
|
|
|
24554
24540
|
this._isMounted = void 0;
|
|
24555
24541
|
// @ts-expect-error - TS2564 - Property '_throttledUpdateRange' has no initializer and is not definitely assigned in the constructor.
|
|
24556
24542
|
this._throttledUpdateRange = void 0;
|
|
24543
|
+
// this just helps with TS weak typing when a Widget
|
|
24544
|
+
// doesn't implement any Widget methods
|
|
24545
|
+
this.isWidget = true;
|
|
24557
24546
|
this.state = {
|
|
24558
24547
|
lineRange: null,
|
|
24559
24548
|
content: null
|
|
@@ -24582,10 +24571,6 @@ class PassageRef extends React.Component {
|
|
|
24582
24571
|
}
|
|
24583
24572
|
};
|
|
24584
24573
|
}
|
|
24585
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24586
|
-
static validate() {
|
|
24587
|
-
return noopValidator();
|
|
24588
|
-
}
|
|
24589
24574
|
componentDidMount() {
|
|
24590
24575
|
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
24591
24576
|
// this.isMounted() but is still considered an anti-pattern.
|
|
@@ -24604,15 +24589,6 @@ class PassageRef extends React.Component {
|
|
|
24604
24589
|
window.removeEventListener("resize", this._throttledUpdateRange);
|
|
24605
24590
|
this._isMounted = false;
|
|
24606
24591
|
}
|
|
24607
|
-
|
|
24608
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24609
|
-
getUserInput() {
|
|
24610
|
-
return null;
|
|
24611
|
-
}
|
|
24612
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24613
|
-
simpleValidate() {
|
|
24614
|
-
return noopValidator();
|
|
24615
|
-
}
|
|
24616
24592
|
render() {
|
|
24617
24593
|
const {
|
|
24618
24594
|
strings
|
|
@@ -24667,7 +24643,9 @@ var PassageRef$1 = {
|
|
|
24667
24643
|
version: {
|
|
24668
24644
|
major: 0,
|
|
24669
24645
|
minor: 1
|
|
24670
|
-
}
|
|
24646
|
+
},
|
|
24647
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
24648
|
+
validator: () => noopValidator()
|
|
24671
24649
|
};
|
|
24672
24650
|
|
|
24673
24651
|
/**
|
|
@@ -26169,7 +26147,7 @@ class Radio$1 extends React.Component {
|
|
|
26169
26147
|
choiceStates
|
|
26170
26148
|
} = this.props;
|
|
26171
26149
|
if (choiceStates) {
|
|
26172
|
-
const score = this.
|
|
26150
|
+
const score = radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26173
26151
|
const widgetCorrect = score.type === "points" && score.total === score.earned;
|
|
26174
26152
|
const newStates = choiceStates.map(state => _extends({}, state, {
|
|
26175
26153
|
highlighted: state.selected,
|
|
@@ -26217,9 +26195,6 @@ class Radio$1 extends React.Component {
|
|
|
26217
26195
|
}
|
|
26218
26196
|
};
|
|
26219
26197
|
}
|
|
26220
|
-
static validate(userInput, rubric, strings) {
|
|
26221
|
-
return radioValidator(userInput, rubric, strings);
|
|
26222
|
-
}
|
|
26223
26198
|
static getUserInputFromProps(props) {
|
|
26224
26199
|
// Return checked inputs in the form {choicesSelected: [bool]}. (Dear
|
|
26225
26200
|
// future timeline implementers: this used to be {value: i} before
|
|
@@ -26310,9 +26285,6 @@ class Radio$1 extends React.Component {
|
|
|
26310
26285
|
getUserInput() {
|
|
26311
26286
|
return Radio$1.getUserInputFromProps(this.props);
|
|
26312
26287
|
}
|
|
26313
|
-
simpleValidate(rubric) {
|
|
26314
|
-
return radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26315
|
-
}
|
|
26316
26288
|
render() {
|
|
26317
26289
|
const {
|
|
26318
26290
|
choices
|
|
@@ -26547,7 +26519,8 @@ var Radio = {
|
|
|
26547
26519
|
minor: 0
|
|
26548
26520
|
},
|
|
26549
26521
|
propUpgrades: propUpgrades$1,
|
|
26550
|
-
isLintable: true
|
|
26522
|
+
isLintable: true,
|
|
26523
|
+
validator: radioValidator
|
|
26551
26524
|
};
|
|
26552
26525
|
|
|
26553
26526
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -26590,9 +26563,6 @@ class Categorizer extends React.Component {
|
|
|
26590
26563
|
return change.apply(this, args);
|
|
26591
26564
|
};
|
|
26592
26565
|
}
|
|
26593
|
-
static validate(userInput, rubric, strings) {
|
|
26594
|
-
return categorizerValidator(userInput, rubric, strings);
|
|
26595
|
-
}
|
|
26596
26566
|
static getUserInputFromProps(props) {
|
|
26597
26567
|
return {
|
|
26598
26568
|
values: props.values
|
|
@@ -26608,9 +26578,6 @@ class Categorizer extends React.Component {
|
|
|
26608
26578
|
this.change("values", values);
|
|
26609
26579
|
this.props.trackInteraction();
|
|
26610
26580
|
}
|
|
26611
|
-
simpleValidate(rubric) {
|
|
26612
|
-
return categorizerValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26613
|
-
}
|
|
26614
26581
|
render() {
|
|
26615
26582
|
const self = this;
|
|
26616
26583
|
|
|
@@ -26756,7 +26723,8 @@ var Categorizer$1 = {
|
|
|
26756
26723
|
staticTransform: editorProps => {
|
|
26757
26724
|
return _.pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
26758
26725
|
},
|
|
26759
|
-
isLintable: true
|
|
26726
|
+
isLintable: true,
|
|
26727
|
+
validator: categorizerValidator
|
|
26760
26728
|
};
|
|
26761
26729
|
|
|
26762
26730
|
/**
|
|
@@ -26880,10 +26848,6 @@ class CSProgram extends React.Component {
|
|
|
26880
26848
|
return change.apply(this, args);
|
|
26881
26849
|
};
|
|
26882
26850
|
}
|
|
26883
|
-
// The widget's grading function
|
|
26884
|
-
static validate(state) {
|
|
26885
|
-
return csProgramValidator(state);
|
|
26886
|
-
}
|
|
26887
26851
|
componentDidMount() {
|
|
26888
26852
|
$(window).on("message", this.handleMessageEvent);
|
|
26889
26853
|
}
|
|
@@ -26896,9 +26860,6 @@ class CSProgram extends React.Component {
|
|
|
26896
26860
|
message: this.props.message
|
|
26897
26861
|
};
|
|
26898
26862
|
}
|
|
26899
|
-
simpleValidate() {
|
|
26900
|
-
return csProgramValidator(this.getUserInput());
|
|
26901
|
-
}
|
|
26902
26863
|
render() {
|
|
26903
26864
|
if (!this.props.programID) {
|
|
26904
26865
|
return /*#__PURE__*/React.createElement("div", null);
|
|
@@ -26980,21 +26941,16 @@ var CSProgram$1 = {
|
|
|
26980
26941
|
displayName: "CS Program",
|
|
26981
26942
|
supportedAlignments: ["block", "full-width"],
|
|
26982
26943
|
widget: CSProgram,
|
|
26983
|
-
hidden: true
|
|
26944
|
+
hidden: true,
|
|
26945
|
+
validator: csProgramValidator
|
|
26984
26946
|
};
|
|
26985
26947
|
|
|
26986
26948
|
class Definition extends React.Component {
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
|
|
26992
|
-
return {};
|
|
26993
|
-
}
|
|
26994
|
-
|
|
26995
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
26996
|
-
simpleValidate() {
|
|
26997
|
-
return noopValidator();
|
|
26949
|
+
constructor(...args) {
|
|
26950
|
+
super(...args);
|
|
26951
|
+
// this just helps with TS weak typing when a Widget
|
|
26952
|
+
// doesn't implement any Widget methods
|
|
26953
|
+
this.isWidget = true;
|
|
26998
26954
|
}
|
|
26999
26955
|
render() {
|
|
27000
26956
|
return /*#__PURE__*/React.createElement(DefinitionConsumer, null, ({
|
|
@@ -27050,22 +27006,19 @@ var Definition$1 = {
|
|
|
27050
27006
|
accessible: true,
|
|
27051
27007
|
defaultAlignment: "inline",
|
|
27052
27008
|
widget: Definition,
|
|
27053
|
-
transform: x => x
|
|
27009
|
+
transform: x => x,
|
|
27010
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27011
|
+
validator: () => noopValidator()
|
|
27054
27012
|
};
|
|
27055
27013
|
|
|
27056
27014
|
// The props are type `any` on purpose so that this can receive props
|
|
27057
27015
|
// from any deprecated widget
|
|
27058
27016
|
class DeprecatedStandin extends React__default.Component {
|
|
27059
|
-
|
|
27060
|
-
|
|
27061
|
-
//
|
|
27062
|
-
|
|
27063
|
-
|
|
27064
|
-
getUserInput() {
|
|
27065
|
-
return {};
|
|
27066
|
-
}
|
|
27067
|
-
simpleValidate() {
|
|
27068
|
-
return noopValidator(1);
|
|
27017
|
+
constructor(...args) {
|
|
27018
|
+
super(...args);
|
|
27019
|
+
// this just helps with TS weak typing when a Widget
|
|
27020
|
+
// doesn't implement any Widget methods
|
|
27021
|
+
this.isWidget = true;
|
|
27069
27022
|
}
|
|
27070
27023
|
render() {
|
|
27071
27024
|
return /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -27085,7 +27038,9 @@ var DeprecatedStandin$1 = {
|
|
|
27085
27038
|
name: "deprecated-standin",
|
|
27086
27039
|
displayName: "Deprecated Standin",
|
|
27087
27040
|
widget: DeprecatedStandin,
|
|
27088
|
-
hidden: true
|
|
27041
|
+
hidden: true,
|
|
27042
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27043
|
+
validator: () => noopValidator(1)
|
|
27089
27044
|
};
|
|
27090
27045
|
|
|
27091
27046
|
function dropdownValidator(userInput, rubric) {
|
|
@@ -27126,17 +27081,11 @@ class Dropdown extends React.Component {
|
|
|
27126
27081
|
});
|
|
27127
27082
|
};
|
|
27128
27083
|
}
|
|
27129
|
-
static validate(userInput, rubric) {
|
|
27130
|
-
return dropdownValidator(userInput, rubric);
|
|
27131
|
-
}
|
|
27132
27084
|
getUserInput() {
|
|
27133
27085
|
return {
|
|
27134
27086
|
value: this.props.selected
|
|
27135
27087
|
};
|
|
27136
27088
|
}
|
|
27137
|
-
simpleValidate(rubric) {
|
|
27138
|
-
return dropdownValidator(this.getUserInput(), rubric);
|
|
27139
|
-
}
|
|
27140
27089
|
render() {
|
|
27141
27090
|
const children = [/*#__PURE__*/React.createElement(OptionItem, {
|
|
27142
27091
|
key: "placeholder",
|
|
@@ -27183,7 +27132,8 @@ var Dropdown$1 = {
|
|
|
27183
27132
|
defaultAlignment: "inline-block",
|
|
27184
27133
|
accessible: true,
|
|
27185
27134
|
widget: Dropdown,
|
|
27186
|
-
transform: optionsTransform
|
|
27135
|
+
transform: optionsTransform,
|
|
27136
|
+
validator: dropdownValidator
|
|
27187
27137
|
};
|
|
27188
27138
|
|
|
27189
27139
|
// transform = _.identity
|
|
@@ -27197,6 +27147,9 @@ function mediaQueryIsMatched(mediaQuery) {
|
|
|
27197
27147
|
class Explanation extends React.Component {
|
|
27198
27148
|
constructor(..._args) {
|
|
27199
27149
|
super(..._args);
|
|
27150
|
+
// this just helps with TS weak typing when a Widget
|
|
27151
|
+
// doesn't implement any Widget methods
|
|
27152
|
+
this.isWidget = true;
|
|
27200
27153
|
this.state = {
|
|
27201
27154
|
expanded: false
|
|
27202
27155
|
};
|
|
@@ -27211,24 +27164,12 @@ class Explanation extends React.Component {
|
|
|
27211
27164
|
this.props.trackInteraction();
|
|
27212
27165
|
};
|
|
27213
27166
|
}
|
|
27214
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27215
|
-
static validate() {
|
|
27216
|
-
return noopValidator();
|
|
27217
|
-
}
|
|
27218
27167
|
componentDidMount() {
|
|
27219
27168
|
this._mounted = true;
|
|
27220
27169
|
}
|
|
27221
27170
|
componentWillUnmount() {
|
|
27222
27171
|
this._mounted = false;
|
|
27223
27172
|
}
|
|
27224
|
-
getUserInput() {
|
|
27225
|
-
return {};
|
|
27226
|
-
}
|
|
27227
|
-
|
|
27228
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27229
|
-
simpleValidate() {
|
|
27230
|
-
return noopValidator();
|
|
27231
|
-
}
|
|
27232
27173
|
render() {
|
|
27233
27174
|
const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
|
|
27234
27175
|
const caretIcon = this.state.expanded ? caretUp : caretDown;
|
|
@@ -27342,7 +27283,9 @@ var Explanation$1 = {
|
|
|
27342
27283
|
defaultAlignment: "inline",
|
|
27343
27284
|
widget: Explanation,
|
|
27344
27285
|
transform: _.identity,
|
|
27345
|
-
isLintable: true
|
|
27286
|
+
isLintable: true,
|
|
27287
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27288
|
+
validator: () => noopValidator()
|
|
27346
27289
|
};
|
|
27347
27290
|
|
|
27348
27291
|
class GradedGroupAnswerBar extends React.Component {
|
|
@@ -28942,9 +28885,6 @@ class Grapher extends React.Component {
|
|
|
28942
28885
|
}
|
|
28943
28886
|
};
|
|
28944
28887
|
}
|
|
28945
|
-
static validate(state, rubric) {
|
|
28946
|
-
return grapherValidator(state, rubric);
|
|
28947
|
-
}
|
|
28948
28888
|
static getUserInputFromProps(props) {
|
|
28949
28889
|
return props.plot;
|
|
28950
28890
|
}
|
|
@@ -28963,9 +28903,6 @@ class Grapher extends React.Component {
|
|
|
28963
28903
|
tickStep[1] = tickStep[1] / gridStep[1];
|
|
28964
28904
|
return tickStep;
|
|
28965
28905
|
}
|
|
28966
|
-
simpleValidate(rubric) {
|
|
28967
|
-
return grapherValidator(this.getUserInput(), rubric);
|
|
28968
|
-
}
|
|
28969
28906
|
getUserInput() {
|
|
28970
28907
|
return Grapher.getUserInputFromProps(this.props);
|
|
28971
28908
|
}
|
|
@@ -29053,7 +28990,8 @@ var Grapher$1 = {
|
|
|
29053
28990
|
hidden: true,
|
|
29054
28991
|
widget: Grapher,
|
|
29055
28992
|
transform: propTransform$2,
|
|
29056
|
-
staticTransform: staticTransform$4
|
|
28993
|
+
staticTransform: staticTransform$4,
|
|
28994
|
+
validator: grapherValidator
|
|
29057
28995
|
};
|
|
29058
28996
|
|
|
29059
28997
|
// exports has no 'transform'
|
|
@@ -29099,17 +29037,18 @@ class Group extends React.Component {
|
|
|
29099
29037
|
// the group with the correct number.
|
|
29100
29038
|
this.forceUpdate();
|
|
29101
29039
|
}
|
|
29102
|
-
|
|
29040
|
+
getUserInputMap() {
|
|
29103
29041
|
var _this$rendererRef7;
|
|
29104
|
-
return (_this$rendererRef7 = this.rendererRef) == null ? void 0 : _this$rendererRef7.
|
|
29105
|
-
}
|
|
29106
|
-
simpleValidate() {
|
|
29107
|
-
var _this$rendererRef$sco, _this$rendererRef8;
|
|
29108
|
-
return (_this$rendererRef$sco = (_this$rendererRef8 = this.rendererRef) == null ? void 0 : _this$rendererRef8.score()) != null ? _this$rendererRef$sco : {
|
|
29109
|
-
type: "invalid"
|
|
29110
|
-
};
|
|
29042
|
+
return (_this$rendererRef7 = this.rendererRef) == null ? void 0 : _this$rendererRef7.getUserInputMap();
|
|
29111
29043
|
}
|
|
29112
29044
|
|
|
29045
|
+
/**
|
|
29046
|
+
* @deprecated getUserInputMap should be used for Groups
|
|
29047
|
+
*/
|
|
29048
|
+
getUserInput() {
|
|
29049
|
+
var _this$rendererRef8;
|
|
29050
|
+
return (_this$rendererRef8 = this.rendererRef) == null ? void 0 : _this$rendererRef8.getUserInput();
|
|
29051
|
+
}
|
|
29113
29052
|
// Mobile API:
|
|
29114
29053
|
getInputPaths() {
|
|
29115
29054
|
var _this$rendererRef$get, _this$rendererRef9;
|
|
@@ -29270,9 +29209,6 @@ class Iframe extends React.Component {
|
|
|
29270
29209
|
return change.apply(this, args);
|
|
29271
29210
|
};
|
|
29272
29211
|
}
|
|
29273
|
-
static validate(state) {
|
|
29274
|
-
return iframeValidator(state);
|
|
29275
|
-
}
|
|
29276
29212
|
componentDidMount() {
|
|
29277
29213
|
$(window).on("message", this.handleMessageEvent);
|
|
29278
29214
|
}
|
|
@@ -29285,9 +29221,6 @@ class Iframe extends React.Component {
|
|
|
29285
29221
|
message: this.props.message
|
|
29286
29222
|
};
|
|
29287
29223
|
}
|
|
29288
|
-
simpleValidate() {
|
|
29289
|
-
return iframeValidator(this.getUserInput());
|
|
29290
|
-
}
|
|
29291
29224
|
render() {
|
|
29292
29225
|
const style = {
|
|
29293
29226
|
width: String(this.props.width),
|
|
@@ -29361,7 +29294,8 @@ var Iframe$1 = {
|
|
|
29361
29294
|
displayName: "Iframe (deprecated)",
|
|
29362
29295
|
widget: Iframe,
|
|
29363
29296
|
// Let's not expose it to all content creators yet
|
|
29364
|
-
hidden: true
|
|
29297
|
+
hidden: true,
|
|
29298
|
+
validator: iframeValidator
|
|
29365
29299
|
};
|
|
29366
29300
|
|
|
29367
29301
|
const defaultBoxSize = 400;
|
|
@@ -29379,22 +29313,13 @@ const DEFAULT_ALIGNMENT = "block";
|
|
|
29379
29313
|
class ImageWidget extends React.Component {
|
|
29380
29314
|
constructor(..._args) {
|
|
29381
29315
|
super(..._args);
|
|
29316
|
+
// this just helps with TS weak typing when a Widget
|
|
29317
|
+
// doesn't implement any Widget methods
|
|
29318
|
+
this.isWidget = true;
|
|
29382
29319
|
this.change = (...args) => {
|
|
29383
29320
|
return change.apply(this, args);
|
|
29384
29321
|
};
|
|
29385
29322
|
}
|
|
29386
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29387
|
-
static validate() {
|
|
29388
|
-
return noopValidator();
|
|
29389
|
-
}
|
|
29390
|
-
getUserInput() {
|
|
29391
|
-
return null;
|
|
29392
|
-
}
|
|
29393
|
-
|
|
29394
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29395
|
-
simpleValidate() {
|
|
29396
|
-
return noopValidator();
|
|
29397
|
-
}
|
|
29398
29323
|
render() {
|
|
29399
29324
|
let image;
|
|
29400
29325
|
const alt = this.props.caption === this.props.alt ? "" : this.props.alt;
|
|
@@ -29549,7 +29474,9 @@ var Image$1 = {
|
|
|
29549
29474
|
supportedAlignments: editorAlignments,
|
|
29550
29475
|
displayName: "Image",
|
|
29551
29476
|
widget: ImageWidget,
|
|
29552
|
-
isLintable: true
|
|
29477
|
+
isLintable: true,
|
|
29478
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
29479
|
+
validator: () => noopValidator()
|
|
29553
29480
|
};
|
|
29554
29481
|
|
|
29555
29482
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -29618,6 +29545,9 @@ const KAScompile = (expr, options) => {
|
|
|
29618
29545
|
class Interaction extends React.Component {
|
|
29619
29546
|
constructor(..._args) {
|
|
29620
29547
|
super(..._args);
|
|
29548
|
+
// this just helps with TS weak typing when a Widget
|
|
29549
|
+
// doesn't implement any Widget methods
|
|
29550
|
+
this.isWidget = true;
|
|
29621
29551
|
this.state = {
|
|
29622
29552
|
variables: _getInitialVariables(this.props.elements),
|
|
29623
29553
|
functions: _getInitialFunctions(this.props.elements)
|
|
@@ -29701,10 +29631,6 @@ class Interaction extends React.Component {
|
|
|
29701
29631
|
return change.apply(this, args);
|
|
29702
29632
|
};
|
|
29703
29633
|
}
|
|
29704
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29705
|
-
static validate() {
|
|
29706
|
-
return noopValidator();
|
|
29707
|
-
}
|
|
29708
29634
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
29709
29635
|
// HACK(michaelpolyak): This widget is not wired to use the Perseus
|
|
29710
29636
|
// `onChange` callback to save user changes. Perseus re-rendering of the
|
|
@@ -29723,18 +29649,6 @@ class Interaction extends React.Component {
|
|
|
29723
29649
|
});
|
|
29724
29650
|
}
|
|
29725
29651
|
}
|
|
29726
|
-
getUserInput() {
|
|
29727
|
-
// TODO(eater): Perhaps we want to be able to record the state of the
|
|
29728
|
-
// user's interaction. Unfortunately sending all the props will
|
|
29729
|
-
// probably make the attempt payload too large. So for now, don't send
|
|
29730
|
-
// anything.
|
|
29731
|
-
return {};
|
|
29732
|
-
}
|
|
29733
|
-
|
|
29734
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29735
|
-
simpleValidate() {
|
|
29736
|
-
return noopValidator();
|
|
29737
|
-
}
|
|
29738
29652
|
render() {
|
|
29739
29653
|
const range = this.props.graph.range;
|
|
29740
29654
|
let labels = this.props.graph.labels;
|
|
@@ -30153,7 +30067,9 @@ var Interactive = {
|
|
|
30153
30067
|
displayName: "Interaction",
|
|
30154
30068
|
widget: Interaction,
|
|
30155
30069
|
transform: _.identity,
|
|
30156
|
-
hidden: true
|
|
30070
|
+
hidden: true,
|
|
30071
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
30072
|
+
validator: () => noopValidator()
|
|
30157
30073
|
};
|
|
30158
30074
|
|
|
30159
30075
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -37239,9 +37155,6 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
37239
37155
|
getUserInput() {
|
|
37240
37156
|
return InteractiveGraph.getUserInputFromProps(this.props);
|
|
37241
37157
|
}
|
|
37242
|
-
simpleValidate(rubric) {
|
|
37243
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37244
|
-
}
|
|
37245
37158
|
render() {
|
|
37246
37159
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
37247
37160
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
@@ -37318,9 +37231,6 @@ class InteractiveGraph extends React.Component {
|
|
|
37318
37231
|
}
|
|
37319
37232
|
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
37320
37233
|
}
|
|
37321
|
-
simpleValidate(rubric) {
|
|
37322
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37323
|
-
}
|
|
37324
37234
|
render() {
|
|
37325
37235
|
var _this$props$apiOption;
|
|
37326
37236
|
// Mafs shim
|
|
@@ -37653,9 +37563,6 @@ class InteractiveGraph extends React.Component {
|
|
|
37653
37563
|
const angle = getClockwiseAngle(coords, allowReflexAngles);
|
|
37654
37564
|
return angle.toFixed(0) + "\u00B0 angle" + " at (" + coords[1].join(", ") + ")";
|
|
37655
37565
|
}
|
|
37656
|
-
static validate(userInput, rubric) {
|
|
37657
|
-
return interactiveGraphValidator(userInput, rubric);
|
|
37658
|
-
}
|
|
37659
37566
|
static getUserInputFromProps(props) {
|
|
37660
37567
|
return props.graph;
|
|
37661
37568
|
}
|
|
@@ -37691,7 +37598,7 @@ function shouldUseMafs(mafsFlags, graph) {
|
|
|
37691
37598
|
// TODO(benchristel): add a feature flag for the "unlimited"
|
|
37692
37599
|
// case once we've implemented polygon graphs with unlimited
|
|
37693
37600
|
// sides
|
|
37694
|
-
return
|
|
37601
|
+
return Boolean(mafsFlags["unlimited-polygon"]);
|
|
37695
37602
|
}
|
|
37696
37603
|
return Boolean(mafsFlags["polygon"]);
|
|
37697
37604
|
default:
|
|
@@ -37704,7 +37611,8 @@ var InteractiveGraph$1 = {
|
|
|
37704
37611
|
name: "interactive-graph",
|
|
37705
37612
|
displayName: "Interactive graph (Assessments only)",
|
|
37706
37613
|
widget: InteractiveGraph,
|
|
37707
|
-
staticTransform: staticTransform$3
|
|
37614
|
+
staticTransform: staticTransform$3,
|
|
37615
|
+
validator: interactiveGraphValidator
|
|
37708
37616
|
};
|
|
37709
37617
|
|
|
37710
37618
|
const black = "#000000";
|
|
@@ -39069,10 +38977,6 @@ const styles$b = StyleSheet.create({
|
|
|
39069
38977
|
// TODO: should this be using WidgetProps / PerseusLabelImageWidgetOptions?
|
|
39070
38978
|
|
|
39071
38979
|
class LabelImage extends React.Component {
|
|
39072
|
-
static validate(state, rubric) {
|
|
39073
|
-
return labelImageValidator(state);
|
|
39074
|
-
}
|
|
39075
|
-
|
|
39076
38980
|
/**
|
|
39077
38981
|
* Test whether point is contained within triangle.
|
|
39078
38982
|
*
|
|
@@ -39267,9 +39171,6 @@ class LabelImage extends React.Component {
|
|
|
39267
39171
|
componentWillUnmount() {
|
|
39268
39172
|
this._mounted = false;
|
|
39269
39173
|
}
|
|
39270
|
-
simpleValidate(rubric) {
|
|
39271
|
-
return labelImageValidator(this.getUserInput());
|
|
39272
|
-
}
|
|
39273
39174
|
getUserInput() {
|
|
39274
39175
|
const {
|
|
39275
39176
|
markers
|
|
@@ -39626,19 +39527,13 @@ const LabelImageWithDependencies = /*#__PURE__*/React.forwardRef((props, ref) =>
|
|
|
39626
39527
|
analytics: deps.analytics
|
|
39627
39528
|
}, props));
|
|
39628
39529
|
});
|
|
39629
|
-
|
|
39630
|
-
// HACK: Propogate "static" methods onto our wrapper component.
|
|
39631
|
-
// In the future we should adjust client apps to not depend on these static
|
|
39632
|
-
// methods and instead adjust Peresus to provide these facilities through
|
|
39633
|
-
// instance methods on our Renderers.
|
|
39634
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
39635
|
-
LabelImageWithDependencies.validate = labelImageValidator;
|
|
39636
39530
|
var LabelImage$1 = {
|
|
39637
39531
|
name: "label-image",
|
|
39638
39532
|
displayName: "Label Image",
|
|
39639
39533
|
widget: LabelImageWithDependencies,
|
|
39640
39534
|
accessible: true,
|
|
39641
|
-
isLintable: true
|
|
39535
|
+
isLintable: true,
|
|
39536
|
+
validator: labelImageValidator
|
|
39642
39537
|
};
|
|
39643
39538
|
|
|
39644
39539
|
var ItemState = /*#__PURE__*/function (ItemState) {
|
|
@@ -40423,12 +40318,6 @@ class Matcher extends React.Component {
|
|
|
40423
40318
|
this.refs.right.moveOptionToIndex(option, index);
|
|
40424
40319
|
};
|
|
40425
40320
|
}
|
|
40426
|
-
static validate(state, rubric) {
|
|
40427
|
-
return matcherValidator(state, rubric);
|
|
40428
|
-
}
|
|
40429
|
-
simpleValidate(rubric) {
|
|
40430
|
-
return matcherValidator(this.getUserInput(), rubric);
|
|
40431
|
-
}
|
|
40432
40321
|
render() {
|
|
40433
40322
|
// To minimize layout shift, we display a spinner until our math
|
|
40434
40323
|
// renderer is ready to render the math inside the matcher. To
|
|
@@ -40566,7 +40455,8 @@ var Matcher$1 = {
|
|
|
40566
40455
|
name: "matcher",
|
|
40567
40456
|
displayName: "Matcher (two column)",
|
|
40568
40457
|
widget: Matcher,
|
|
40569
|
-
isLintable: true
|
|
40458
|
+
isLintable: true,
|
|
40459
|
+
validator: matcherValidator
|
|
40570
40460
|
};
|
|
40571
40461
|
|
|
40572
40462
|
function matrixValidator(state, rubric, strings) {
|
|
@@ -40828,9 +40718,6 @@ class Matrix extends React.Component {
|
|
|
40828
40718
|
this.props.trackInteraction();
|
|
40829
40719
|
};
|
|
40830
40720
|
}
|
|
40831
|
-
static validate(state, rubric, strings) {
|
|
40832
|
-
return matrixValidator(state, rubric, strings);
|
|
40833
|
-
}
|
|
40834
40721
|
componentDidMount() {
|
|
40835
40722
|
// Used in the `onBlur` and `onFocus` handlers
|
|
40836
40723
|
this.cursorPosition = [0, 0];
|
|
@@ -40845,9 +40732,6 @@ class Matrix extends React.Component {
|
|
|
40845
40732
|
answers: this.props.answers
|
|
40846
40733
|
};
|
|
40847
40734
|
}
|
|
40848
|
-
simpleValidate(rubric) {
|
|
40849
|
-
return matrixValidator(this.getUserInput(), rubric, this.context.strings);
|
|
40850
|
-
}
|
|
40851
40735
|
render() {
|
|
40852
40736
|
// Set the input sizes through JS so we can control the size of the
|
|
40853
40737
|
// brackets. (If we set them in CSS we won't know values until the
|
|
@@ -41040,7 +40924,8 @@ var Matrix$1 = {
|
|
|
41040
40924
|
widget: Matrix,
|
|
41041
40925
|
transform: propTransform$1,
|
|
41042
40926
|
staticTransform: staticTransform$2,
|
|
41043
|
-
isLintable: true
|
|
40927
|
+
isLintable: true,
|
|
40928
|
+
validator: matrixValidator
|
|
41044
40929
|
};
|
|
41045
40930
|
|
|
41046
40931
|
const defaultImage = {
|
|
@@ -41051,6 +40936,9 @@ const defaultImage = {
|
|
|
41051
40936
|
class Measurer extends React.Component {
|
|
41052
40937
|
constructor(...args) {
|
|
41053
40938
|
super(...args);
|
|
40939
|
+
// this just helps with TS weak typing when a Widget
|
|
40940
|
+
// doesn't implement any Widget methods
|
|
40941
|
+
this.isWidget = true;
|
|
41054
40942
|
this.state = {};
|
|
41055
40943
|
this.ruler = void 0;
|
|
41056
40944
|
this.protractor = void 0;
|
|
@@ -41104,12 +40992,6 @@ class Measurer extends React.Component {
|
|
|
41104
40992
|
});
|
|
41105
40993
|
}
|
|
41106
40994
|
}
|
|
41107
|
-
getUserInput() {
|
|
41108
|
-
return {};
|
|
41109
|
-
}
|
|
41110
|
-
simpleValidate() {
|
|
41111
|
-
return noopValidator(1);
|
|
41112
|
-
}
|
|
41113
40995
|
render() {
|
|
41114
40996
|
const image = _.extend({}, defaultImage, this.props.image);
|
|
41115
40997
|
|
|
@@ -41135,7 +41017,6 @@ class Measurer extends React.Component {
|
|
|
41135
41017
|
}));
|
|
41136
41018
|
}
|
|
41137
41019
|
}
|
|
41138
|
-
Measurer.validate = noopValidator;
|
|
41139
41020
|
Measurer.defaultProps = {
|
|
41140
41021
|
box: [480, 480],
|
|
41141
41022
|
image: {},
|
|
@@ -41169,7 +41050,9 @@ var Measurer$1 = {
|
|
|
41169
41050
|
major: 1,
|
|
41170
41051
|
minor: 0
|
|
41171
41052
|
},
|
|
41172
|
-
propUpgrades: propUpgrades
|
|
41053
|
+
propUpgrades: propUpgrades,
|
|
41054
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
41055
|
+
validator: () => noopValidator(1)
|
|
41173
41056
|
};
|
|
41174
41057
|
|
|
41175
41058
|
/**
|
|
@@ -42036,17 +41919,11 @@ class Molecule extends React.Component {
|
|
|
42036
41919
|
}
|
|
42037
41920
|
Molecule.contextType = PerseusI18nContext;
|
|
42038
41921
|
class MoleculeWidget extends React.Component {
|
|
42039
|
-
|
|
42040
|
-
|
|
42041
|
-
|
|
42042
|
-
|
|
42043
|
-
|
|
42044
|
-
return [];
|
|
42045
|
-
}
|
|
42046
|
-
|
|
42047
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
42048
|
-
validate() {
|
|
42049
|
-
return noopValidator();
|
|
41922
|
+
constructor(...args) {
|
|
41923
|
+
super(...args);
|
|
41924
|
+
// this just helps with TS weak typing when a Widget
|
|
41925
|
+
// doesn't implement any Widget methods
|
|
41926
|
+
this.isWidget = true;
|
|
42050
41927
|
}
|
|
42051
41928
|
render() {
|
|
42052
41929
|
return /*#__PURE__*/React.createElement(Molecule, {
|
|
@@ -42063,7 +41940,8 @@ var Molecule$1 = {
|
|
|
42063
41940
|
name: "molecule-renderer",
|
|
42064
41941
|
displayName: "Molecule renderer",
|
|
42065
41942
|
hidden: true,
|
|
42066
|
-
widget: MoleculeWidget
|
|
41943
|
+
widget: MoleculeWidget,
|
|
41944
|
+
validator: () => noopValidator()
|
|
42067
41945
|
};
|
|
42068
41946
|
|
|
42069
41947
|
function numberLineValidator(state, rubric) {
|
|
@@ -42208,18 +42086,16 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
42208
42086
|
results.push(graphie.line([x, -0.2], [x, 0.2]));
|
|
42209
42087
|
const labelTicks = props.labelTicks;
|
|
42210
42088
|
if (labelTicks || props.labelStyle === "decimal ticks") {
|
|
42211
|
-
|
|
42089
|
+
if (x === leftLabel || x === rightLabel) {
|
|
42090
|
+
results.push(graphie.style({
|
|
42091
|
+
color: KhanColors.BLUE
|
|
42092
|
+
}, () => _label(graphie, props.labelStyle, x, x, base)));
|
|
42093
|
+
} else {
|
|
42094
|
+
results.push(_label(graphie, props.labelStyle, x, x, base));
|
|
42095
|
+
}
|
|
42212
42096
|
}
|
|
42213
42097
|
}
|
|
42214
42098
|
|
|
42215
|
-
// Render the text labels
|
|
42216
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42217
|
-
color: KhanColors.BLUE
|
|
42218
|
-
} : {}, () => _label(graphie, props.labelStyle, leftLabel, leftLabel, base)));
|
|
42219
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42220
|
-
color: KhanColors.BLUE
|
|
42221
|
-
} : {}, () => _label(graphie, props.labelStyle, rightLabel, rightLabel, base)));
|
|
42222
|
-
|
|
42223
42099
|
// Render the labels' lines
|
|
42224
42100
|
graphie.style({
|
|
42225
42101
|
stroke: KhanColors.BLUE,
|
|
@@ -42494,9 +42370,6 @@ class NumberLine extends React.Component {
|
|
|
42494
42370
|
});
|
|
42495
42371
|
};
|
|
42496
42372
|
}
|
|
42497
|
-
static validate(state, rubric) {
|
|
42498
|
-
return numberLineValidator(state, rubric);
|
|
42499
|
-
}
|
|
42500
42373
|
focus() {
|
|
42501
42374
|
if (this.props.isTickCtrl) {
|
|
42502
42375
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -42526,9 +42399,6 @@ class NumberLine extends React.Component {
|
|
|
42526
42399
|
divisionRange: this.props.divisionRange
|
|
42527
42400
|
};
|
|
42528
42401
|
}
|
|
42529
|
-
simpleValidate(rubric) {
|
|
42530
|
-
return numberLineValidator(this.getUserInput(), rubric);
|
|
42531
|
-
}
|
|
42532
42402
|
render() {
|
|
42533
42403
|
const {
|
|
42534
42404
|
strings
|
|
@@ -42647,7 +42517,8 @@ var NumberLine$1 = {
|
|
|
42647
42517
|
displayName: "Number line",
|
|
42648
42518
|
widget: NumberLine,
|
|
42649
42519
|
transform: numberLineTransform,
|
|
42650
|
-
staticTransform: staticTransform$1
|
|
42520
|
+
staticTransform: staticTransform$1,
|
|
42521
|
+
validator: numberLineValidator
|
|
42651
42522
|
};
|
|
42652
42523
|
|
|
42653
42524
|
function ordererValidator(userInput, rubric) {
|
|
@@ -43080,9 +42951,6 @@ class Orderer extends React.Component {
|
|
|
43080
42951
|
});
|
|
43081
42952
|
};
|
|
43082
42953
|
}
|
|
43083
|
-
static validate(userInput, rubric) {
|
|
43084
|
-
return ordererValidator(userInput, rubric);
|
|
43085
|
-
}
|
|
43086
42954
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
43087
42955
|
if (!_.isEqual(this.props.current, nextProps.current)) {
|
|
43088
42956
|
this.setState({
|
|
@@ -43097,9 +42965,6 @@ class Orderer extends React.Component {
|
|
|
43097
42965
|
})
|
|
43098
42966
|
};
|
|
43099
42967
|
}
|
|
43100
|
-
simpleValidate(rubric) {
|
|
43101
|
-
return ordererValidator(this.getUserInput(), rubric);
|
|
43102
|
-
}
|
|
43103
42968
|
render() {
|
|
43104
42969
|
// This is the card we are currently dragging
|
|
43105
42970
|
const dragging = this.state.dragging && /*#__PURE__*/React.createElement(Card
|
|
@@ -43217,31 +43082,22 @@ var Orderer$1 = {
|
|
|
43217
43082
|
displayName: "Orderer",
|
|
43218
43083
|
hidden: true,
|
|
43219
43084
|
widget: Orderer,
|
|
43220
|
-
isLintable: true
|
|
43085
|
+
isLintable: true,
|
|
43086
|
+
validator: ordererValidator
|
|
43221
43087
|
};
|
|
43222
43088
|
|
|
43223
43089
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
43224
43090
|
class PassageRefTarget extends React.Component {
|
|
43225
43091
|
constructor(..._args) {
|
|
43226
43092
|
super(..._args);
|
|
43093
|
+
// this just helps with TS weak typing when a Widget
|
|
43094
|
+
// doesn't implement any Widget methods
|
|
43095
|
+
this.isWidget = true;
|
|
43227
43096
|
// TODO passage-ref-target isn't interactive; remove
|
|
43228
43097
|
this.change = (...args) => {
|
|
43229
43098
|
return change.apply(this, args);
|
|
43230
43099
|
};
|
|
43231
43100
|
}
|
|
43232
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43233
|
-
static validate() {
|
|
43234
|
-
return noopValidator();
|
|
43235
|
-
}
|
|
43236
|
-
|
|
43237
|
-
// TODO passage-ref-target isn't interactive; remove
|
|
43238
|
-
getUserInput() {
|
|
43239
|
-
return null;
|
|
43240
|
-
}
|
|
43241
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43242
|
-
simpleValidate() {
|
|
43243
|
-
return noopValidator();
|
|
43244
|
-
}
|
|
43245
43101
|
render() {
|
|
43246
43102
|
return /*#__PURE__*/React.createElement(Renderer, {
|
|
43247
43103
|
content: this.props.content
|
|
@@ -43275,7 +43131,9 @@ var PassageRefTarget$1 = {
|
|
|
43275
43131
|
major: 0,
|
|
43276
43132
|
minor: 0
|
|
43277
43133
|
},
|
|
43278
|
-
isLintable: true
|
|
43134
|
+
isLintable: true,
|
|
43135
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
43136
|
+
validator: () => noopValidator()
|
|
43279
43137
|
};
|
|
43280
43138
|
|
|
43281
43139
|
/**
|
|
@@ -43288,6 +43146,9 @@ class PhetSimulation extends React.Component {
|
|
|
43288
43146
|
super(props);
|
|
43289
43147
|
this.iframeRef = /*#__PURE__*/React.createRef();
|
|
43290
43148
|
this.locale = void 0;
|
|
43149
|
+
// this just helps with TS weak typing when a Widget
|
|
43150
|
+
// doesn't implement any Widget methods
|
|
43151
|
+
this.isWidget = true;
|
|
43291
43152
|
this.state = {
|
|
43292
43153
|
url: null,
|
|
43293
43154
|
banner: null
|
|
@@ -43330,11 +43191,6 @@ class PhetSimulation extends React.Component {
|
|
|
43330
43191
|
await this.updateSimState(this.props.url);
|
|
43331
43192
|
}
|
|
43332
43193
|
}
|
|
43333
|
-
|
|
43334
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43335
|
-
getUserInput() {
|
|
43336
|
-
return null;
|
|
43337
|
-
}
|
|
43338
43194
|
async updateSimState(urlString) {
|
|
43339
43195
|
const url = makeSafeUrl(urlString, this.locale);
|
|
43340
43196
|
if (url === null) {
|
|
@@ -44233,9 +44089,6 @@ class Plotter extends React.Component {
|
|
|
44233
44089
|
});
|
|
44234
44090
|
};
|
|
44235
44091
|
}
|
|
44236
|
-
static validate(userInput, rubric) {
|
|
44237
|
-
return plotterValidator(userInput, rubric);
|
|
44238
|
-
}
|
|
44239
44092
|
componentDidMount() {
|
|
44240
44093
|
this._isMounted = true;
|
|
44241
44094
|
this.setupGraphie(this.state);
|
|
@@ -44262,9 +44115,6 @@ class Plotter extends React.Component {
|
|
|
44262
44115
|
getUserInput() {
|
|
44263
44116
|
return this.state.values;
|
|
44264
44117
|
}
|
|
44265
|
-
simpleValidate(rubric) {
|
|
44266
|
-
return plotterValidator(this.getUserInput(), rubric);
|
|
44267
|
-
}
|
|
44268
44118
|
render() {
|
|
44269
44119
|
// TODO(kevinb) actually compute the size of the graphie correctly and
|
|
44270
44120
|
// make it that size so we don't have to add extra padding. The value
|
|
@@ -44304,7 +44154,8 @@ var Plotter$1 = {
|
|
|
44304
44154
|
displayName: "Plotter",
|
|
44305
44155
|
hidden: true,
|
|
44306
44156
|
widget: Plotter,
|
|
44307
|
-
staticTransform: staticTransform
|
|
44157
|
+
staticTransform: staticTransform,
|
|
44158
|
+
validator: plotterValidator
|
|
44308
44159
|
};
|
|
44309
44160
|
|
|
44310
44161
|
/**
|
|
@@ -44420,9 +44271,6 @@ class Sorter extends React.Component {
|
|
|
44420
44271
|
this.refs.sortable.moveOptionToIndex(option, index);
|
|
44421
44272
|
};
|
|
44422
44273
|
}
|
|
44423
|
-
static validate(userInput, rubric) {
|
|
44424
|
-
return sorterValidator(userInput, rubric);
|
|
44425
|
-
}
|
|
44426
44274
|
componentDidMount() {
|
|
44427
44275
|
this._isMounted = true;
|
|
44428
44276
|
}
|
|
@@ -44438,9 +44286,6 @@ class Sorter extends React.Component {
|
|
|
44438
44286
|
changed: this.state.changed
|
|
44439
44287
|
};
|
|
44440
44288
|
}
|
|
44441
|
-
simpleValidate(rubric) {
|
|
44442
|
-
return sorterValidator(this.getUserInput(), rubric);
|
|
44443
|
-
}
|
|
44444
44289
|
render() {
|
|
44445
44290
|
const options = shuffle(this.props.correct, this.props.problemNum, /* ensurePermuted */true);
|
|
44446
44291
|
const {
|
|
@@ -44474,7 +44319,8 @@ var Sorter$1 = {
|
|
|
44474
44319
|
name: "sorter",
|
|
44475
44320
|
displayName: "Sorter",
|
|
44476
44321
|
widget: Sorter,
|
|
44477
|
-
isLintable: true
|
|
44322
|
+
isLintable: true,
|
|
44323
|
+
validator: sorterValidator
|
|
44478
44324
|
};
|
|
44479
44325
|
|
|
44480
44326
|
function tableValidator(state, rubric, strings) {
|
|
@@ -44653,15 +44499,9 @@ class Table extends React.Component {
|
|
|
44653
44499
|
}, cb);
|
|
44654
44500
|
};
|
|
44655
44501
|
}
|
|
44656
|
-
static validate(state, rubric, strings) {
|
|
44657
|
-
return tableValidator(state, rubric, strings);
|
|
44658
|
-
}
|
|
44659
44502
|
getUserInput() {
|
|
44660
44503
|
return _.map(this.props.answers, _.clone);
|
|
44661
44504
|
}
|
|
44662
|
-
simpleValidate(rubric) {
|
|
44663
|
-
return tableValidator(this.getUserInput(), rubric, this.context.strings);
|
|
44664
|
-
}
|
|
44665
44505
|
getDOMNodeForPath(path) {
|
|
44666
44506
|
const inputID = getRefForPath(path);
|
|
44667
44507
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -44762,7 +44602,8 @@ var Table$1 = {
|
|
|
44762
44602
|
widget: Table,
|
|
44763
44603
|
transform: propTransform,
|
|
44764
44604
|
hidden: true,
|
|
44765
|
-
isLintable: true
|
|
44605
|
+
isLintable: true,
|
|
44606
|
+
validator: tableValidator
|
|
44766
44607
|
};
|
|
44767
44608
|
|
|
44768
44609
|
/**
|
|
@@ -44850,26 +44691,14 @@ const IS_VIMEO = /(vimeo\.com)/;
|
|
|
44850
44691
|
class Video extends React.Component {
|
|
44851
44692
|
constructor(..._args) {
|
|
44852
44693
|
super(..._args);
|
|
44853
|
-
this
|
|
44854
|
-
|
|
44855
|
-
|
|
44694
|
+
// this just helps with TS weak typing when a Widget
|
|
44695
|
+
// doesn't implement any Widget methods
|
|
44696
|
+
this.isWidget = true;
|
|
44856
44697
|
this.change = (...args) => {
|
|
44857
44698
|
// @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
|
|
44858
44699
|
return change.apply(this, args);
|
|
44859
44700
|
};
|
|
44860
44701
|
}
|
|
44861
|
-
/**
|
|
44862
|
-
* This is the widget's grading function.
|
|
44863
|
-
* Points for videos are tallied by the embedded video itself, in the case
|
|
44864
|
-
* of Khan Academy videos.
|
|
44865
|
-
*/ // TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44866
|
-
static validate() {
|
|
44867
|
-
return noopValidator();
|
|
44868
|
-
}
|
|
44869
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44870
|
-
simpleValidate() {
|
|
44871
|
-
return noopValidator();
|
|
44872
|
-
}
|
|
44873
44702
|
render() {
|
|
44874
44703
|
const {
|
|
44875
44704
|
InitialRequestUrl
|
|
@@ -44929,7 +44758,9 @@ var Video$1 = {
|
|
|
44929
44758
|
displayName: "Video",
|
|
44930
44759
|
defaultAlignment: "block",
|
|
44931
44760
|
supportedAlignments: ["block", "float-left", "float-right", "full-width"],
|
|
44932
|
-
widget: Video
|
|
44761
|
+
widget: Video,
|
|
44762
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
44763
|
+
validator: () => noopValidator()
|
|
44933
44764
|
};
|
|
44934
44765
|
|
|
44935
44766
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -44973,7 +44804,7 @@ const init = function init(options) {
|
|
|
44973
44804
|
|
|
44974
44805
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44975
44806
|
const libName = "@khanacademy/perseus";
|
|
44976
|
-
const libVersion = "
|
|
44807
|
+
const libVersion = "37.0.1";
|
|
44977
44808
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44978
44809
|
|
|
44979
44810
|
const apiVersion = {
|
|
@@ -45549,7 +45380,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
45549
45380
|
});
|
|
45550
45381
|
|
|
45551
45382
|
// Call the interactionCallback, if it exists, with the current user input data
|
|
45552
|
-
(_this$props$apiOption = this.props.apiOptions) == null || _this$props$apiOption.interactionCallback == null || _this$props$apiOption.interactionCallback(this.questionRenderer.
|
|
45383
|
+
(_this$props$apiOption = this.props.apiOptions) == null || _this$props$apiOption.interactionCallback == null || _this$props$apiOption.interactionCallback(this.questionRenderer.getUserInputMap());
|
|
45553
45384
|
};
|
|
45554
45385
|
// This must be pre-bound otherwise SvgImage's shouldComponentUpdate
|
|
45555
45386
|
// won't behave correctly and we'll get an infinite loop.
|
|
@@ -48221,9 +48052,7 @@ const getCorrectAnswerForWidgetId = (widgetId, itemData) => {
|
|
|
48221
48052
|
const rubric = itemData.question.widgets[widgetId].options;
|
|
48222
48053
|
const widgetMap = getWidgetsMapFromItemData(itemData);
|
|
48223
48054
|
const widgetType = getWidgetTypeByWidgetId(widgetId, widgetMap);
|
|
48224
|
-
const widget =
|
|
48225
|
-
|
|
48226
|
-
// @ts-expect-error - TS2339 - Property 'getOneCorrectAnswerFromRubric' does not exist on type 'ComponentType<any>'.
|
|
48055
|
+
const widget = getWidgetExport(widgetType);
|
|
48227
48056
|
return widget == null || widget.getOneCorrectAnswerFromRubric == null ? void 0 : widget.getOneCorrectAnswerFromRubric(rubric);
|
|
48228
48057
|
};
|
|
48229
48058
|
|
|
@@ -48313,12 +48142,12 @@ function parsePerseusItem(json) {
|
|
|
48313
48142
|
}
|
|
48314
48143
|
throw new Error("Something went wrong.");
|
|
48315
48144
|
}
|
|
48316
|
-
function buildRandomString() {
|
|
48145
|
+
function buildRandomString(capitalize = false) {
|
|
48317
48146
|
let randomString = "";
|
|
48318
48147
|
const randomLength = Math.floor(Math.random() * 8) + 3;
|
|
48319
48148
|
for (let i = 0; i < randomLength; i++) {
|
|
48320
48149
|
const randomLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
48321
|
-
randomString += randomLetter;
|
|
48150
|
+
randomString += capitalize && i === 0 ? randomLetter.toUpperCase() : randomLetter;
|
|
48322
48151
|
}
|
|
48323
48152
|
return randomString;
|
|
48324
48153
|
}
|
|
@@ -48326,9 +48155,12 @@ function buildRandomPhrase() {
|
|
|
48326
48155
|
const phrases = [];
|
|
48327
48156
|
const randomLength = Math.floor(Math.random() * 10) + 5;
|
|
48328
48157
|
for (let i = 0; i < randomLength; i++) {
|
|
48329
|
-
phrases.push(buildRandomString());
|
|
48158
|
+
phrases.push(buildRandomString(i === 0));
|
|
48330
48159
|
}
|
|
48331
|
-
|
|
48160
|
+
const modifierStart = ["**", "$"];
|
|
48161
|
+
const modifierEnd = ["**", "$"];
|
|
48162
|
+
const modifierIndex = Math.floor(Math.random() * modifierStart.length);
|
|
48163
|
+
return `${modifierStart[modifierIndex]}${phrases.join(" ")}${modifierEnd[modifierIndex]}`;
|
|
48332
48164
|
}
|
|
48333
48165
|
function buildTestData(testObject) {
|
|
48334
48166
|
return `{"data":{"assessmentItem":{"__typename":"AssessmentItemOrError","error":null,"item":{"__typename":"AssessmentItem","id":"x890b3c70f3e8f4a6","itemData":"${testObject}","problemType":"Type 1","sha":"c7284a3ad65214b4e62bccce236d92f7f5d35941"}}}}`;
|