@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/index.js
CHANGED
|
@@ -2386,35 +2386,14 @@ const anglicizeOperators = tex => {
|
|
|
2386
2386
|
const normalizeTex = tex => {
|
|
2387
2387
|
return anglicizeOperators(tex);
|
|
2388
2388
|
};
|
|
2389
|
-
const deriveKeypadVersion = apiOptions => {
|
|
2390
|
-
// We can derive which version of the keypad is in use. This is
|
|
2391
|
-
// a bit tricky, but this code will be relatively short-lived
|
|
2392
|
-
// as we coalesce onto the new, v2 Keypad, at which point we
|
|
2393
|
-
// can remove this `virtualKeypadVersion` field entirely.
|
|
2394
|
-
return apiOptions.nativeKeypadProxy != null ? "REACT_NATIVE_KEYPAD" : "MATH_INPUT_KEYPAD_V2";
|
|
2395
|
-
};
|
|
2396
2389
|
// The new, MathQuill input expression widget
|
|
2397
2390
|
class Expression extends React__namespace.Component {
|
|
2398
2391
|
static contextType = PerseusI18nContext;
|
|
2399
2392
|
_textareaId = `expression_textarea_${Date.now()}`;
|
|
2400
2393
|
_isMounted = false;
|
|
2401
|
-
|
|
2402
|
-
// TODO remove this in favor of just using expressionValidator
|
|
2403
|
-
static validate(userInput, rubric, strings, locale) {
|
|
2404
|
-
return expressionValidator(userInput, rubric, strings, locale);
|
|
2405
|
-
}
|
|
2406
2394
|
static getUserInputFromProps(props) {
|
|
2407
2395
|
return normalizeTex(props.value);
|
|
2408
2396
|
}
|
|
2409
|
-
static getOneCorrectAnswerFromRubric(rubric) {
|
|
2410
|
-
const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
|
|
2411
|
-
if (correctAnswers.length === 0) {
|
|
2412
|
-
return;
|
|
2413
|
-
}
|
|
2414
|
-
return correctAnswers[0].value;
|
|
2415
|
-
}
|
|
2416
|
-
//#endregion
|
|
2417
|
-
|
|
2418
2397
|
static defaultProps = {
|
|
2419
2398
|
value: "",
|
|
2420
2399
|
times: false,
|
|
@@ -2478,26 +2457,6 @@ class Expression extends React__namespace.Component {
|
|
|
2478
2457
|
});
|
|
2479
2458
|
}
|
|
2480
2459
|
};
|
|
2481
|
-
simpleValidate = _ref => {
|
|
2482
|
-
let {
|
|
2483
|
-
scoring,
|
|
2484
|
-
...rubric
|
|
2485
|
-
} = _ref;
|
|
2486
|
-
const score = expressionValidator(this.getUserInput(), rubric, this.context.strings, this.context.locale);
|
|
2487
|
-
|
|
2488
|
-
// "scoring" is a flag that indicates when we are checking answers.
|
|
2489
|
-
// otherwise, we may just be checking validity after changes.
|
|
2490
|
-
if (scoring && score.type !== "invalid") {
|
|
2491
|
-
this.props.analytics?.onAnalyticsEvent({
|
|
2492
|
-
type: "perseus:expression-evaluated",
|
|
2493
|
-
payload: {
|
|
2494
|
-
result: score.earned === score.total ? "correct" : "incorrect",
|
|
2495
|
-
virtualKeypadVersion: deriveKeypadVersion(this.props.apiOptions)
|
|
2496
|
-
}
|
|
2497
|
-
});
|
|
2498
|
-
}
|
|
2499
|
-
return score;
|
|
2500
|
-
};
|
|
2501
2460
|
getUserInput() {
|
|
2502
2461
|
return Expression.getUserInputFromProps(this.props);
|
|
2503
2462
|
}
|
|
@@ -2760,11 +2719,7 @@ const ExpressionWithDependencies = /*#__PURE__*/React__namespace.forwardRef((pro
|
|
|
2760
2719
|
// methods and instead adjust Perseus to provide these facilities through
|
|
2761
2720
|
// instance methods on our Renderers.
|
|
2762
2721
|
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2763
|
-
ExpressionWithDependencies.validate = expressionValidator;
|
|
2764
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2765
2722
|
ExpressionWithDependencies.getUserInputFromProps = Expression.getUserInputFromProps;
|
|
2766
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
2767
|
-
ExpressionWithDependencies.getOneCorrectAnswerFromRubric = Expression.getOneCorrectAnswerFromRubric;
|
|
2768
2723
|
var Expression$1 = {
|
|
2769
2724
|
name: "expression",
|
|
2770
2725
|
displayName: "Expression / Equation",
|
|
@@ -2796,7 +2751,15 @@ var Expression$1 = {
|
|
|
2796
2751
|
},
|
|
2797
2752
|
propUpgrades: propUpgrades$2,
|
|
2798
2753
|
// For use by the editor
|
|
2799
|
-
isLintable: true
|
|
2754
|
+
isLintable: true,
|
|
2755
|
+
validator: expressionValidator,
|
|
2756
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
2757
|
+
const correctAnswers = (rubric.answerForms || []).filter(answerForm => answerForm.considered === "correct");
|
|
2758
|
+
if (correctAnswers.length === 0) {
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
return correctAnswers[0].value;
|
|
2762
|
+
}
|
|
2800
2763
|
};
|
|
2801
2764
|
|
|
2802
2765
|
/**
|
|
@@ -3026,6 +2989,9 @@ function combineScores(scoreA, scoreB) {
|
|
|
3026
2989
|
}
|
|
3027
2990
|
});
|
|
3028
2991
|
}
|
|
2992
|
+
function flattenScores(widgetScoreMap) {
|
|
2993
|
+
return Object.values(widgetScoreMap).reduce(combineScores, noScore);
|
|
2994
|
+
}
|
|
3029
2995
|
function isCorrect(score) {
|
|
3030
2996
|
return score.type === "points" && score.earned >= score.total;
|
|
3031
2997
|
}
|
|
@@ -3556,6 +3522,7 @@ const Util = {
|
|
|
3556
3522
|
shuffle: shuffle$3,
|
|
3557
3523
|
split,
|
|
3558
3524
|
combineScores,
|
|
3525
|
+
flattenScores,
|
|
3559
3526
|
keScoreFromPerseusScore,
|
|
3560
3527
|
firstNumericalParse: firstNumericalParse$1,
|
|
3561
3528
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
@@ -10094,6 +10061,8 @@ const setLabelMargins = function (span, size) {
|
|
|
10094
10061
|
marginTop: -height / 2 - y * scale
|
|
10095
10062
|
});
|
|
10096
10063
|
} else {
|
|
10064
|
+
const currentHeightMatchesProps = span.scrollHeight === height;
|
|
10065
|
+
|
|
10097
10066
|
// We are using jQuery to collect information and calculate a scale
|
|
10098
10067
|
// since we don't have a way to pass it to this function.
|
|
10099
10068
|
// We need the width of the container in order to calculate the scale to apply to the label.
|
|
@@ -10115,6 +10084,17 @@ const setLabelMargins = function (span, size) {
|
|
|
10115
10084
|
// Inherited line-height values can really mess up placement.
|
|
10116
10085
|
$container.css("line-height", "normal");
|
|
10117
10086
|
|
|
10087
|
+
// TODO: Verify that this change doesn't impact other graphies
|
|
10088
|
+
// Check the full list of consuming widgets.
|
|
10089
|
+
|
|
10090
|
+
// If the change in line-height affected the height of the element,
|
|
10091
|
+
// then the height used for calculations should be updated.
|
|
10092
|
+
// This can happen when the first label in the container calls this method,
|
|
10093
|
+
// and the line-height was different when the height measurement was originally referenced.
|
|
10094
|
+
if (currentHeightMatchesProps && span.scrollHeight !== height) {
|
|
10095
|
+
height = span.scrollHeight;
|
|
10096
|
+
}
|
|
10097
|
+
|
|
10118
10098
|
// The expected width of the graphie is found in the "max-width" property on ".svg-image" containers,
|
|
10119
10099
|
// and is found in the "width" property on ".graphie" containers.
|
|
10120
10100
|
const widthValues = $container.css(["max-width", "width"]) ?? {
|
|
@@ -14777,7 +14757,7 @@ const mapObject$1 = function (obj, lambda) {
|
|
|
14777
14757
|
* });
|
|
14778
14758
|
* {a: 'aa', b: 'bb'}
|
|
14779
14759
|
*/
|
|
14780
|
-
const mapObjectFromArray
|
|
14760
|
+
const mapObjectFromArray = function (arr, lambda) {
|
|
14781
14761
|
const result = {};
|
|
14782
14762
|
___default["default"].each(arr, function (elem) {
|
|
14783
14763
|
result[elem] = lambda(elem);
|
|
@@ -14787,7 +14767,7 @@ const mapObjectFromArray$1 = function (arr, lambda) {
|
|
|
14787
14767
|
var objective_ = {
|
|
14788
14768
|
pluck: pluck,
|
|
14789
14769
|
mapObject: mapObject$1,
|
|
14790
|
-
mapObjectFromArray: mapObjectFromArray
|
|
14770
|
+
mapObjectFromArray: mapObjectFromArray
|
|
14791
14771
|
};
|
|
14792
14772
|
|
|
14793
14773
|
/**
|
|
@@ -19003,169 +18983,6 @@ class QuestionParagraph extends React__namespace.Component {
|
|
|
19003
18983
|
}
|
|
19004
18984
|
}
|
|
19005
18985
|
|
|
19006
|
-
/**
|
|
19007
|
-
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
19008
|
-
*
|
|
19009
|
-
* The poentry linter checks for issues that prevent content from being
|
|
19010
|
-
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
19011
|
-
* anything in non-KA environments.
|
|
19012
|
-
*/
|
|
19013
|
-
|
|
19014
|
-
// A LintCB is called once the linter has been run.
|
|
19015
|
-
|
|
19016
|
-
// msec to wait before we actually call the linter after receiving the
|
|
19017
|
-
// last call. The timer is reset if the lint is called during the wait.
|
|
19018
|
-
const DEBOUNCE_TIMEOUT = 1000;
|
|
19019
|
-
class TranslationLinter {
|
|
19020
|
-
// To avoid linting when nothing has changed.
|
|
19021
|
-
previousContent = null;
|
|
19022
|
-
|
|
19023
|
-
/**
|
|
19024
|
-
* Runs the poentry linter on the given perseus string asynchronously.
|
|
19025
|
-
*
|
|
19026
|
-
* It doesn't do anything unless we're in a KA environment.
|
|
19027
|
-
*
|
|
19028
|
-
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
19029
|
-
* called if perseusStr is unchanged from the last call.
|
|
19030
|
-
*
|
|
19031
|
-
* Linting is relatively expensive -- so we debounce linting each instance
|
|
19032
|
-
* for some amount of time.
|
|
19033
|
-
*/
|
|
19034
|
-
runLinter = _.debounce((perseusStr, onLintErrorsGenerated) => {
|
|
19035
|
-
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
19036
|
-
if (typeof KA === "undefined") {
|
|
19037
|
-
return;
|
|
19038
|
-
}
|
|
19039
|
-
if (perseusStr === this.previousContent) {
|
|
19040
|
-
return;
|
|
19041
|
-
}
|
|
19042
|
-
this.previousContent = perseusStr;
|
|
19043
|
-
if (perseusStr === "") {
|
|
19044
|
-
onLintErrorsGenerated([]);
|
|
19045
|
-
return;
|
|
19046
|
-
}
|
|
19047
|
-
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
19048
|
-
headers: {
|
|
19049
|
-
"Content-Type": "application/json"
|
|
19050
|
-
},
|
|
19051
|
-
body: JSON.stringify({
|
|
19052
|
-
// The poentry linter verifies that the translation from
|
|
19053
|
-
// the original text to the translated text is sane. We
|
|
19054
|
-
// want to ensure that the translation from English to
|
|
19055
|
-
// English is sane, so msgid === mstr.
|
|
19056
|
-
msgid: perseusStr,
|
|
19057
|
-
// msgid is the original text
|
|
19058
|
-
msgstr: perseusStr,
|
|
19059
|
-
// msgstr is the translated text
|
|
19060
|
-
format: "perseus_text",
|
|
19061
|
-
filename: ""
|
|
19062
|
-
}),
|
|
19063
|
-
method: "POST"
|
|
19064
|
-
}).then(response => {
|
|
19065
|
-
if (response.status >= 400) {
|
|
19066
|
-
return {
|
|
19067
|
-
status: "error",
|
|
19068
|
-
message: "Could not run i18n linter."
|
|
19069
|
-
};
|
|
19070
|
-
}
|
|
19071
|
-
return response.json();
|
|
19072
|
-
}, rejection => {
|
|
19073
|
-
return {
|
|
19074
|
-
status: "error",
|
|
19075
|
-
message: "Could not run i18n linter."
|
|
19076
|
-
};
|
|
19077
|
-
}).then(json => {
|
|
19078
|
-
if (json.status === "error") {
|
|
19079
|
-
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
19080
|
-
} else {
|
|
19081
|
-
onLintErrorsGenerated([]);
|
|
19082
|
-
}
|
|
19083
|
-
});
|
|
19084
|
-
}, DEBOUNCE_TIMEOUT);
|
|
19085
|
-
|
|
19086
|
-
/**
|
|
19087
|
-
* Applies an array of errors generated by linters without position
|
|
19088
|
-
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
19089
|
-
* top of a Perseus tree.
|
|
19090
|
-
*/
|
|
19091
|
-
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
19092
|
-
// These lint errors do not have position data associated with
|
|
19093
|
-
// them, so we just plop them at the top.
|
|
19094
|
-
if (translationLintErrors.length) {
|
|
19095
|
-
const errorText = translationLintErrors.join("\n\n");
|
|
19096
|
-
parsedMarkdown.unshift({
|
|
19097
|
-
content: {
|
|
19098
|
-
type: "text",
|
|
19099
|
-
content: ""
|
|
19100
|
-
},
|
|
19101
|
-
insideTable: false,
|
|
19102
|
-
message: errorText,
|
|
19103
|
-
ruleName: "legacy-error",
|
|
19104
|
-
severity: PerseusLinter.Rule.Severity.ERROR,
|
|
19105
|
-
type: "lint"
|
|
19106
|
-
});
|
|
19107
|
-
}
|
|
19108
|
-
}
|
|
19109
|
-
}
|
|
19110
|
-
|
|
19111
|
-
/**
|
|
19112
|
-
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
19113
|
-
* to things is does.
|
|
19114
|
-
*/
|
|
19115
|
-
var preprocessTex = (texCode => texCode
|
|
19116
|
-
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
19117
|
-
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
19118
|
-
// the same is supported by KaTeX. It does the same for align*.
|
|
19119
|
-
// TODO(kevinb) update content to use aligned instead of align.
|
|
19120
|
-
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
19121
|
-
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
19122
|
-
// "aligned").
|
|
19123
|
-
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
19124
|
-
// Replace non-breaking spaces with regular spaces.
|
|
19125
|
-
.replace(/[\u00a0]/g, " "));
|
|
19126
|
-
|
|
19127
|
-
const {
|
|
19128
|
-
interactiveSizes
|
|
19129
|
-
} = constants$1;
|
|
19130
|
-
|
|
19131
|
-
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
19132
|
-
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
19133
|
-
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
19134
|
-
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
19135
|
-
const smMax = articleMaxWidthTableInPx;
|
|
19136
|
-
const mdMax = articleMaxWidthInPx;
|
|
19137
|
-
const containerSizeClass = {
|
|
19138
|
-
SMALL: "small",
|
|
19139
|
-
MEDIUM: "medium",
|
|
19140
|
-
LARGE: "large",
|
|
19141
|
-
XLARGE: "xlarge"
|
|
19142
|
-
};
|
|
19143
|
-
const getClassFromWidth = width => {
|
|
19144
|
-
if (!width) {
|
|
19145
|
-
return containerSizeClass.MEDIUM;
|
|
19146
|
-
}
|
|
19147
|
-
if (width <= smMax) {
|
|
19148
|
-
return containerSizeClass.SMALL;
|
|
19149
|
-
}
|
|
19150
|
-
if (width <= mdMax) {
|
|
19151
|
-
return containerSizeClass.MEDIUM;
|
|
19152
|
-
}
|
|
19153
|
-
return containerSizeClass.LARGE;
|
|
19154
|
-
};
|
|
19155
|
-
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
19156
|
-
if (sizeClass === containerSizeClass.SMALL) {
|
|
19157
|
-
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
19158
|
-
}
|
|
19159
|
-
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
19160
|
-
};
|
|
19161
|
-
|
|
19162
|
-
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
19163
|
-
__proto__: null,
|
|
19164
|
-
containerSizeClass: containerSizeClass,
|
|
19165
|
-
getClassFromWidth: getClassFromWidth,
|
|
19166
|
-
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
19167
|
-
});
|
|
19168
|
-
|
|
19169
18986
|
const DEFAULT_ALIGNMENT$1 = "block";
|
|
19170
18987
|
// NOTE(kevinb): "default" is not one in `validAlignments`.
|
|
19171
18988
|
const DEFAULT_SUPPORTED_ALIGNMENTS = ["default"];
|
|
@@ -19264,6 +19081,12 @@ const getWidget = name => {
|
|
|
19264
19081
|
}
|
|
19265
19082
|
return widgets[name].widget;
|
|
19266
19083
|
};
|
|
19084
|
+
const getWidgetExport = name => {
|
|
19085
|
+
return widgets[name] ?? null;
|
|
19086
|
+
};
|
|
19087
|
+
const getWidgetValidator = name => {
|
|
19088
|
+
return widgets[name]?.validator ?? null;
|
|
19089
|
+
};
|
|
19267
19090
|
const getEditor = name => {
|
|
19268
19091
|
return ___default["default"].has(editors, name) ? editors[name] : null;
|
|
19269
19092
|
};
|
|
@@ -19569,6 +19392,8 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19569
19392
|
replaceEditor: replaceEditor,
|
|
19570
19393
|
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
19571
19394
|
getWidget: getWidget,
|
|
19395
|
+
getWidgetExport: getWidgetExport,
|
|
19396
|
+
getWidgetValidator: getWidgetValidator,
|
|
19572
19397
|
getEditor: getEditor,
|
|
19573
19398
|
getTransform: getTransform,
|
|
19574
19399
|
getVersion: getVersion,
|
|
@@ -19588,6 +19413,222 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19588
19413
|
isLintable: isLintable
|
|
19589
19414
|
});
|
|
19590
19415
|
|
|
19416
|
+
function emptyWidgetsFunctional(widgets,
|
|
19417
|
+
// This is a port of old code, I'm not sure why
|
|
19418
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19419
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19420
|
+
return widgetIds.filter(id => {
|
|
19421
|
+
const widget = widgets[id];
|
|
19422
|
+
if (!widget || widget.static) {
|
|
19423
|
+
// Static widgets shouldn't count as empty
|
|
19424
|
+
return false;
|
|
19425
|
+
}
|
|
19426
|
+
let score = null;
|
|
19427
|
+
const userInput = userInputMap[id];
|
|
19428
|
+
const validator = getWidgetValidator(widget.type);
|
|
19429
|
+
if (widget.type === "group") {
|
|
19430
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19431
|
+
score = Util.flattenScores(scores);
|
|
19432
|
+
} else if (validator) {
|
|
19433
|
+
score = validator(userInput, widget.options, strings, locale);
|
|
19434
|
+
}
|
|
19435
|
+
if (score) {
|
|
19436
|
+
return Util.scoreIsEmpty(score);
|
|
19437
|
+
}
|
|
19438
|
+
});
|
|
19439
|
+
}
|
|
19440
|
+
function scoreWidgetsFunctional(widgets,
|
|
19441
|
+
// This is a port of old code, I'm not sure why
|
|
19442
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19443
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19444
|
+
const gradedWidgetIds = widgetIds.filter(id => {
|
|
19445
|
+
const props = widgets[id];
|
|
19446
|
+
const widgetIsGraded = props?.graded == null || props.graded;
|
|
19447
|
+
const widgetIsStatic = !!props?.static;
|
|
19448
|
+
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
19449
|
+
return widgetIsGraded && !widgetIsStatic;
|
|
19450
|
+
});
|
|
19451
|
+
const widgetScores = {};
|
|
19452
|
+
gradedWidgetIds.forEach(id => {
|
|
19453
|
+
const widget = widgets[id];
|
|
19454
|
+
if (!widget) {
|
|
19455
|
+
return;
|
|
19456
|
+
}
|
|
19457
|
+
const userInput = userInputMap[id];
|
|
19458
|
+
const validator = getWidgetValidator(widget.type);
|
|
19459
|
+
if (widget.type === "group") {
|
|
19460
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19461
|
+
widgetScores[id] = Util.flattenScores(scores);
|
|
19462
|
+
} else if (validator) {
|
|
19463
|
+
widgetScores[id] = validator(userInput, widget.options, strings, locale);
|
|
19464
|
+
}
|
|
19465
|
+
});
|
|
19466
|
+
return widgetScores;
|
|
19467
|
+
}
|
|
19468
|
+
|
|
19469
|
+
/**
|
|
19470
|
+
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
19471
|
+
*
|
|
19472
|
+
* The poentry linter checks for issues that prevent content from being
|
|
19473
|
+
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
19474
|
+
* anything in non-KA environments.
|
|
19475
|
+
*/
|
|
19476
|
+
|
|
19477
|
+
// A LintCB is called once the linter has been run.
|
|
19478
|
+
|
|
19479
|
+
// msec to wait before we actually call the linter after receiving the
|
|
19480
|
+
// last call. The timer is reset if the lint is called during the wait.
|
|
19481
|
+
const DEBOUNCE_TIMEOUT = 1000;
|
|
19482
|
+
class TranslationLinter {
|
|
19483
|
+
// To avoid linting when nothing has changed.
|
|
19484
|
+
previousContent = null;
|
|
19485
|
+
|
|
19486
|
+
/**
|
|
19487
|
+
* Runs the poentry linter on the given perseus string asynchronously.
|
|
19488
|
+
*
|
|
19489
|
+
* It doesn't do anything unless we're in a KA environment.
|
|
19490
|
+
*
|
|
19491
|
+
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
19492
|
+
* called if perseusStr is unchanged from the last call.
|
|
19493
|
+
*
|
|
19494
|
+
* Linting is relatively expensive -- so we debounce linting each instance
|
|
19495
|
+
* for some amount of time.
|
|
19496
|
+
*/
|
|
19497
|
+
runLinter = _.debounce((perseusStr, onLintErrorsGenerated) => {
|
|
19498
|
+
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
19499
|
+
if (typeof KA === "undefined") {
|
|
19500
|
+
return;
|
|
19501
|
+
}
|
|
19502
|
+
if (perseusStr === this.previousContent) {
|
|
19503
|
+
return;
|
|
19504
|
+
}
|
|
19505
|
+
this.previousContent = perseusStr;
|
|
19506
|
+
if (perseusStr === "") {
|
|
19507
|
+
onLintErrorsGenerated([]);
|
|
19508
|
+
return;
|
|
19509
|
+
}
|
|
19510
|
+
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
19511
|
+
headers: {
|
|
19512
|
+
"Content-Type": "application/json"
|
|
19513
|
+
},
|
|
19514
|
+
body: JSON.stringify({
|
|
19515
|
+
// The poentry linter verifies that the translation from
|
|
19516
|
+
// the original text to the translated text is sane. We
|
|
19517
|
+
// want to ensure that the translation from English to
|
|
19518
|
+
// English is sane, so msgid === mstr.
|
|
19519
|
+
msgid: perseusStr,
|
|
19520
|
+
// msgid is the original text
|
|
19521
|
+
msgstr: perseusStr,
|
|
19522
|
+
// msgstr is the translated text
|
|
19523
|
+
format: "perseus_text",
|
|
19524
|
+
filename: ""
|
|
19525
|
+
}),
|
|
19526
|
+
method: "POST"
|
|
19527
|
+
}).then(response => {
|
|
19528
|
+
if (response.status >= 400) {
|
|
19529
|
+
return {
|
|
19530
|
+
status: "error",
|
|
19531
|
+
message: "Could not run i18n linter."
|
|
19532
|
+
};
|
|
19533
|
+
}
|
|
19534
|
+
return response.json();
|
|
19535
|
+
}, rejection => {
|
|
19536
|
+
return {
|
|
19537
|
+
status: "error",
|
|
19538
|
+
message: "Could not run i18n linter."
|
|
19539
|
+
};
|
|
19540
|
+
}).then(json => {
|
|
19541
|
+
if (json.status === "error") {
|
|
19542
|
+
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
19543
|
+
} else {
|
|
19544
|
+
onLintErrorsGenerated([]);
|
|
19545
|
+
}
|
|
19546
|
+
});
|
|
19547
|
+
}, DEBOUNCE_TIMEOUT);
|
|
19548
|
+
|
|
19549
|
+
/**
|
|
19550
|
+
* Applies an array of errors generated by linters without position
|
|
19551
|
+
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
19552
|
+
* top of a Perseus tree.
|
|
19553
|
+
*/
|
|
19554
|
+
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
19555
|
+
// These lint errors do not have position data associated with
|
|
19556
|
+
// them, so we just plop them at the top.
|
|
19557
|
+
if (translationLintErrors.length) {
|
|
19558
|
+
const errorText = translationLintErrors.join("\n\n");
|
|
19559
|
+
parsedMarkdown.unshift({
|
|
19560
|
+
content: {
|
|
19561
|
+
type: "text",
|
|
19562
|
+
content: ""
|
|
19563
|
+
},
|
|
19564
|
+
insideTable: false,
|
|
19565
|
+
message: errorText,
|
|
19566
|
+
ruleName: "legacy-error",
|
|
19567
|
+
severity: PerseusLinter.Rule.Severity.ERROR,
|
|
19568
|
+
type: "lint"
|
|
19569
|
+
});
|
|
19570
|
+
}
|
|
19571
|
+
}
|
|
19572
|
+
}
|
|
19573
|
+
|
|
19574
|
+
/**
|
|
19575
|
+
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
19576
|
+
* to things is does.
|
|
19577
|
+
*/
|
|
19578
|
+
var preprocessTex = (texCode => texCode
|
|
19579
|
+
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
19580
|
+
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
19581
|
+
// the same is supported by KaTeX. It does the same for align*.
|
|
19582
|
+
// TODO(kevinb) update content to use aligned instead of align.
|
|
19583
|
+
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
19584
|
+
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
19585
|
+
// "aligned").
|
|
19586
|
+
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
19587
|
+
// Replace non-breaking spaces with regular spaces.
|
|
19588
|
+
.replace(/[\u00a0]/g, " "));
|
|
19589
|
+
|
|
19590
|
+
const {
|
|
19591
|
+
interactiveSizes
|
|
19592
|
+
} = constants$1;
|
|
19593
|
+
|
|
19594
|
+
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
19595
|
+
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
19596
|
+
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
19597
|
+
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
19598
|
+
const smMax = articleMaxWidthTableInPx;
|
|
19599
|
+
const mdMax = articleMaxWidthInPx;
|
|
19600
|
+
const containerSizeClass = {
|
|
19601
|
+
SMALL: "small",
|
|
19602
|
+
MEDIUM: "medium",
|
|
19603
|
+
LARGE: "large",
|
|
19604
|
+
XLARGE: "xlarge"
|
|
19605
|
+
};
|
|
19606
|
+
const getClassFromWidth = width => {
|
|
19607
|
+
if (!width) {
|
|
19608
|
+
return containerSizeClass.MEDIUM;
|
|
19609
|
+
}
|
|
19610
|
+
if (width <= smMax) {
|
|
19611
|
+
return containerSizeClass.SMALL;
|
|
19612
|
+
}
|
|
19613
|
+
if (width <= mdMax) {
|
|
19614
|
+
return containerSizeClass.MEDIUM;
|
|
19615
|
+
}
|
|
19616
|
+
return containerSizeClass.LARGE;
|
|
19617
|
+
};
|
|
19618
|
+
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
19619
|
+
if (sizeClass === containerSizeClass.SMALL) {
|
|
19620
|
+
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
19621
|
+
}
|
|
19622
|
+
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
19623
|
+
};
|
|
19624
|
+
|
|
19625
|
+
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
19626
|
+
__proto__: null,
|
|
19627
|
+
containerSizeClass: containerSizeClass,
|
|
19628
|
+
getClassFromWidth: getClassFromWidth,
|
|
19629
|
+
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
19630
|
+
});
|
|
19631
|
+
|
|
19591
19632
|
class WidgetContainer extends React__namespace.Component {
|
|
19592
19633
|
widgetRef = /*#__PURE__*/React__namespace.createRef();
|
|
19593
19634
|
static defaultProps = {
|
|
@@ -19734,8 +19775,7 @@ class WidgetContainer extends React__namespace.Component {
|
|
|
19734
19775
|
}
|
|
19735
19776
|
|
|
19736
19777
|
const {
|
|
19737
|
-
mapObject
|
|
19738
|
-
mapObjectFromArray
|
|
19778
|
+
mapObject
|
|
19739
19779
|
} = objective_;
|
|
19740
19780
|
const rContainsNonWhitespace = /\S/;
|
|
19741
19781
|
const rImageURL = /(web\+graphie|https):\/\/[^\s]*/;
|
|
@@ -19762,6 +19802,7 @@ const isIdPathPrefix = function (prefixArray, wholeArray) {
|
|
|
19762
19802
|
});
|
|
19763
19803
|
};
|
|
19764
19804
|
class Renderer extends React__namespace.Component {
|
|
19805
|
+
static contextType = PerseusI18nContext;
|
|
19765
19806
|
_currentFocus;
|
|
19766
19807
|
// @ts-expect-error - TS2564 - Property '_foundTextNodes' has no initializer and is not definitely assigned in the constructor.
|
|
19767
19808
|
_foundTextNodes;
|
|
@@ -20065,11 +20106,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20065
20106
|
}
|
|
20066
20107
|
let interactionTracker = this._interactionTrackers[id];
|
|
20067
20108
|
if (!interactionTracker) {
|
|
20068
|
-
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction,
|
|
20069
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
20070
|
-
widgetInfo && widgetInfo.type, id,
|
|
20071
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
20072
|
-
getTracking(widgetInfo && widgetInfo.type));
|
|
20109
|
+
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction, widgetInfo && widgetInfo.type, id, getTracking(widgetInfo && widgetInfo.type));
|
|
20073
20110
|
}
|
|
20074
20111
|
return {
|
|
20075
20112
|
...widgetProps,
|
|
@@ -20883,23 +20920,9 @@ class Renderer extends React__namespace.Component {
|
|
|
20883
20920
|
}, this);
|
|
20884
20921
|
return state;
|
|
20885
20922
|
};
|
|
20886
|
-
emptyWidgets
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
const widgetInfo = this._getWidgetInfo(id);
|
|
20890
|
-
if (widgetInfo.static) {
|
|
20891
|
-
// Static widgets shouldn't count as empty
|
|
20892
|
-
return false;
|
|
20893
|
-
}
|
|
20894
|
-
const widget = this.getWidgetInstance(id);
|
|
20895
|
-
if (widget && widget.simpleValidate) {
|
|
20896
|
-
const score = widget.simpleValidate(widgetInfo.options,
|
|
20897
|
-
// @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'.
|
|
20898
|
-
null);
|
|
20899
|
-
return Util.scoreIsEmpty(score);
|
|
20900
|
-
}
|
|
20901
|
-
});
|
|
20902
|
-
};
|
|
20923
|
+
emptyWidgets() {
|
|
20924
|
+
return emptyWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20925
|
+
}
|
|
20903
20926
|
_setWidgetProps = (id, newProps, cb, silent) => {
|
|
20904
20927
|
this.setState(prevState => {
|
|
20905
20928
|
const widgetProps = {
|
|
@@ -20963,8 +20986,11 @@ class Renderer extends React__namespace.Component {
|
|
|
20963
20986
|
|
|
20964
20987
|
/**
|
|
20965
20988
|
* Returns an array of the widget `.getUserInput()` results
|
|
20989
|
+
*
|
|
20990
|
+
* TODO: can we remove this?
|
|
20991
|
+
* @deprecated use getUserInputMap
|
|
20966
20992
|
*/
|
|
20967
|
-
getUserInput
|
|
20993
|
+
getUserInput() {
|
|
20968
20994
|
return this.widgetIds.map(id => {
|
|
20969
20995
|
const widget = this.getWidgetInstance(id);
|
|
20970
20996
|
if (widget && widget.getUserInput) {
|
|
@@ -20973,7 +20999,24 @@ class Renderer extends React__namespace.Component {
|
|
|
20973
20999
|
return widget.getUserInput();
|
|
20974
21000
|
}
|
|
20975
21001
|
});
|
|
20976
|
-
}
|
|
21002
|
+
}
|
|
21003
|
+
|
|
21004
|
+
/**
|
|
21005
|
+
* Returns an object of the widget `.getUserInput()` results
|
|
21006
|
+
*/
|
|
21007
|
+
getUserInputMap() {
|
|
21008
|
+
const userInputMap = {};
|
|
21009
|
+
this.widgetIds.forEach(id => {
|
|
21010
|
+
const widget = this.getWidgetInstance(id);
|
|
21011
|
+
// Handle Groups, which have their own sets of widgets
|
|
21012
|
+
if (widget?.getUserInputMap) {
|
|
21013
|
+
userInputMap[id] = widget.getUserInputMap();
|
|
21014
|
+
} else if (widget?.getUserInput) {
|
|
21015
|
+
userInputMap[id] = widget.getUserInput();
|
|
21016
|
+
}
|
|
21017
|
+
});
|
|
21018
|
+
return userInputMap;
|
|
21019
|
+
}
|
|
20977
21020
|
|
|
20978
21021
|
/**
|
|
20979
21022
|
* Returns an array of all widget IDs in the order they occur in
|
|
@@ -20983,59 +21026,23 @@ class Renderer extends React__namespace.Component {
|
|
|
20983
21026
|
return this.widgetIds;
|
|
20984
21027
|
};
|
|
20985
21028
|
|
|
20986
|
-
/**
|
|
20987
|
-
* Returns the result of `.getUserInput()` for each widget, in
|
|
20988
|
-
* a map from widgetId to userInput.
|
|
20989
|
-
* NOTE(jeremy): This function is hauntingly similar to `getUserInput` with
|
|
20990
|
-
* the major difference being that this function returns a map of
|
|
20991
|
-
* `widgetID` => UserInput and `getUserInput` simply returns an array. It
|
|
20992
|
-
* would be trivial to map between the results of each of these functions,
|
|
20993
|
-
* so we should aim to remove one of these functions.
|
|
20994
|
-
*/
|
|
20995
|
-
getUserInputForWidgets = () => {
|
|
20996
|
-
return mapObjectFromArray(this.widgetIds, id => {
|
|
20997
|
-
const widget = this.getWidgetInstance(id);
|
|
20998
|
-
if (widget && widget.getUserInput) {
|
|
20999
|
-
return widget.getUserInput();
|
|
21000
|
-
}
|
|
21001
|
-
});
|
|
21002
|
-
};
|
|
21003
|
-
|
|
21004
21029
|
/**
|
|
21005
21030
|
* Returns an object mapping from widget ID to perseus-style score.
|
|
21006
21031
|
* The keys of this object are the values of the array returned
|
|
21007
21032
|
* from `getWidgetIds`.
|
|
21008
21033
|
*/
|
|
21009
|
-
scoreWidgets
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
const props = widgetProps[id];
|
|
21013
|
-
const widgetIsGraded = props?.graded == null || props.graded;
|
|
21014
|
-
const widgetIsStatic = !!props?.static;
|
|
21015
|
-
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
21016
|
-
return widgetIsGraded && !widgetIsStatic;
|
|
21017
|
-
});
|
|
21018
|
-
const widgetScores = {};
|
|
21019
|
-
___default["default"].each(gradedWidgetIds, id => {
|
|
21020
|
-
const props = widgetProps[id];
|
|
21021
|
-
const widget = this.getWidgetInstance(id);
|
|
21022
|
-
// widget can be undefined if it hasn't yet been rendered
|
|
21023
|
-
if (widget && widget.simpleValidate) {
|
|
21024
|
-
widgetScores[id] = widget.simpleValidate({
|
|
21025
|
-
...props?.options,
|
|
21026
|
-
scoring: true
|
|
21027
|
-
});
|
|
21028
|
-
}
|
|
21029
|
-
});
|
|
21030
|
-
return widgetScores;
|
|
21031
|
-
};
|
|
21034
|
+
scoreWidgets() {
|
|
21035
|
+
return scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
21036
|
+
}
|
|
21032
21037
|
|
|
21033
21038
|
/**
|
|
21034
21039
|
* Grades the content.
|
|
21035
21040
|
*/
|
|
21036
|
-
score
|
|
21037
|
-
|
|
21038
|
-
|
|
21041
|
+
score() {
|
|
21042
|
+
const scores = this.scoreWidgets();
|
|
21043
|
+
const combinedScore = Util.flattenScores(scores);
|
|
21044
|
+
return combinedScore;
|
|
21045
|
+
}
|
|
21039
21046
|
guessAndScore = () => {
|
|
21040
21047
|
const totalGuess = this.getUserInput();
|
|
21041
21048
|
const totalScore = this.score();
|
|
@@ -21147,12 +21154,12 @@ class Renderer extends React__namespace.Component {
|
|
|
21147
21154
|
// If highlightLint is true and lint is detected, this call
|
|
21148
21155
|
// will modify the parse tree by adding lint nodes that will
|
|
21149
21156
|
// serve to highlight the lint when rendered
|
|
21150
|
-
const
|
|
21157
|
+
const fullLinterContext = {
|
|
21151
21158
|
content: this.props.content,
|
|
21152
21159
|
widgets: this.props.widgets,
|
|
21153
21160
|
...this.props.linterContext
|
|
21154
21161
|
};
|
|
21155
|
-
PerseusLinter__namespace.runLinter(parsedMarkdown,
|
|
21162
|
+
PerseusLinter__namespace.runLinter(parsedMarkdown, fullLinterContext, true);
|
|
21156
21163
|
|
|
21157
21164
|
// Apply the lint errors from the last TranslationLinter run.
|
|
21158
21165
|
// TODO(joshuan): Support overlapping dots.
|
|
@@ -21974,24 +21981,11 @@ class InputNumber extends React__namespace.Component {
|
|
|
21974
21981
|
apiOptions: ApiOptions.defaults,
|
|
21975
21982
|
linterContext: PerseusLinter.linterContextDefault
|
|
21976
21983
|
};
|
|
21977
|
-
static validate(state, rubric, strings) {
|
|
21978
|
-
return inputNumberValidator(state, rubric, strings);
|
|
21979
|
-
}
|
|
21980
21984
|
static getUserInputFromProps(props) {
|
|
21981
21985
|
return {
|
|
21982
21986
|
currentValue: props.currentValue
|
|
21983
21987
|
};
|
|
21984
21988
|
}
|
|
21985
|
-
static getOneCorrectAnswerFromRubric(rubric) {
|
|
21986
|
-
if (rubric.value == null) {
|
|
21987
|
-
return;
|
|
21988
|
-
}
|
|
21989
|
-
let answerString = String(rubric.value);
|
|
21990
|
-
if (rubric.inexact && rubric.maxError) {
|
|
21991
|
-
answerString += " \u00B1 " + rubric.maxError;
|
|
21992
|
-
}
|
|
21993
|
-
return answerString;
|
|
21994
|
-
}
|
|
21995
21989
|
shouldShowExamples = () => {
|
|
21996
21990
|
return this.props.answerType !== "number";
|
|
21997
21991
|
};
|
|
@@ -22047,9 +22041,6 @@ class InputNumber extends React__namespace.Component {
|
|
|
22047
22041
|
getUserInput() {
|
|
22048
22042
|
return InputNumber.getUserInputFromProps(this.props);
|
|
22049
22043
|
}
|
|
22050
|
-
simpleValidate(rubric) {
|
|
22051
|
-
return inputNumberValidator(this.getUserInput(), rubric, this.context.strings);
|
|
22052
|
-
}
|
|
22053
22044
|
examples = () => {
|
|
22054
22045
|
const {
|
|
22055
22046
|
strings
|
|
@@ -22152,7 +22143,18 @@ var InputNumber$1 = {
|
|
|
22152
22143
|
hidden: true,
|
|
22153
22144
|
widget: InputNumber,
|
|
22154
22145
|
transform: propTransform$3,
|
|
22155
|
-
isLintable: true
|
|
22146
|
+
isLintable: true,
|
|
22147
|
+
validator: inputNumberValidator,
|
|
22148
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
22149
|
+
if (rubric.value == null) {
|
|
22150
|
+
return;
|
|
22151
|
+
}
|
|
22152
|
+
let answerString = String(rubric.value);
|
|
22153
|
+
if (rubric.inexact && rubric.maxError) {
|
|
22154
|
+
answerString += " \u00B1 " + rubric.maxError;
|
|
22155
|
+
}
|
|
22156
|
+
return answerString;
|
|
22157
|
+
}
|
|
22156
22158
|
};
|
|
22157
22159
|
|
|
22158
22160
|
const ParseTex = TexWrangler.parseTex;
|
|
@@ -22331,37 +22333,6 @@ class NumericInput extends React__namespace.Component {
|
|
|
22331
22333
|
currentValue: props.currentValue
|
|
22332
22334
|
};
|
|
22333
22335
|
}
|
|
22334
|
-
static getOneCorrectAnswerFromRubric(rubric) {
|
|
22335
|
-
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
22336
|
-
const answerStrings = correctAnswers.map(answer => {
|
|
22337
|
-
// Figure out how this answer is supposed to be
|
|
22338
|
-
// displayed
|
|
22339
|
-
let format = "decimal";
|
|
22340
|
-
if (answer.answerForms && answer.answerForms[0]) {
|
|
22341
|
-
// NOTE(johnsullivan): This isn't exactly ideal, but
|
|
22342
|
-
// it does behave well for all the currently known
|
|
22343
|
-
// problems. See D14742 for some discussion on
|
|
22344
|
-
// alternate strategies.
|
|
22345
|
-
format = answer.answerForms[0];
|
|
22346
|
-
}
|
|
22347
|
-
|
|
22348
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
22349
|
-
let answerString = KhanMath.toNumericString(answer.value, format);
|
|
22350
|
-
if (answer.maxError) {
|
|
22351
|
-
answerString += " \u00B1 " +
|
|
22352
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
22353
|
-
KhanMath.toNumericString(answer.maxError, format);
|
|
22354
|
-
}
|
|
22355
|
-
return answerString;
|
|
22356
|
-
});
|
|
22357
|
-
if (answerStrings.length === 0) {
|
|
22358
|
-
return;
|
|
22359
|
-
}
|
|
22360
|
-
return answerStrings[0];
|
|
22361
|
-
}
|
|
22362
|
-
static validate(userInput, rubric, strings) {
|
|
22363
|
-
return numericInputValidator(userInput, rubric, strings);
|
|
22364
|
-
}
|
|
22365
22336
|
state = {
|
|
22366
22337
|
// keeps track of the other set of values when switching
|
|
22367
22338
|
// between 0 and finite solutions
|
|
@@ -22394,9 +22365,6 @@ class NumericInput extends React__namespace.Component {
|
|
|
22394
22365
|
const allFormsAccepted = answerFormNames.length >= Object.keys(formExamples).length;
|
|
22395
22366
|
return !noFormsAccepted && !allFormsAccepted;
|
|
22396
22367
|
};
|
|
22397
|
-
simpleValidate(rubric) {
|
|
22398
|
-
return numericInputValidator(this.getUserInput(), rubric, this.context.strings);
|
|
22399
|
-
}
|
|
22400
22368
|
focus = () => {
|
|
22401
22369
|
this.inputRef?.focus();
|
|
22402
22370
|
return true;
|
|
@@ -22550,7 +22518,36 @@ var NumericInput$1 = {
|
|
|
22550
22518
|
accessible: true,
|
|
22551
22519
|
widget: NumericInput,
|
|
22552
22520
|
transform: propsTransform,
|
|
22553
|
-
isLintable: true
|
|
22521
|
+
isLintable: true,
|
|
22522
|
+
validator: numericInputValidator,
|
|
22523
|
+
getOneCorrectAnswerFromRubric(rubric) {
|
|
22524
|
+
const correctAnswers = rubric.answers.filter(answer => answer.status === "correct");
|
|
22525
|
+
const answerStrings = correctAnswers.map(answer => {
|
|
22526
|
+
// Figure out how this answer is supposed to be
|
|
22527
|
+
// displayed
|
|
22528
|
+
let format = "decimal";
|
|
22529
|
+
if (answer.answerForms && answer.answerForms[0]) {
|
|
22530
|
+
// NOTE(johnsullivan): This isn't exactly ideal, but
|
|
22531
|
+
// it does behave well for all the currently known
|
|
22532
|
+
// problems. See D14742 for some discussion on
|
|
22533
|
+
// alternate strategies.
|
|
22534
|
+
format = answer.answerForms[0];
|
|
22535
|
+
}
|
|
22536
|
+
|
|
22537
|
+
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
22538
|
+
let answerString = KhanMath.toNumericString(answer.value, format);
|
|
22539
|
+
if (answer.maxError) {
|
|
22540
|
+
answerString += " \u00B1 " +
|
|
22541
|
+
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'MathFormat | undefined'.
|
|
22542
|
+
KhanMath.toNumericString(answer.maxError, format);
|
|
22543
|
+
}
|
|
22544
|
+
return answerString;
|
|
22545
|
+
});
|
|
22546
|
+
if (answerStrings.length === 0) {
|
|
22547
|
+
return;
|
|
22548
|
+
}
|
|
22549
|
+
return answerStrings[0];
|
|
22550
|
+
}
|
|
22554
22551
|
};
|
|
22555
22552
|
|
|
22556
22553
|
/**
|
|
@@ -24371,16 +24368,15 @@ class Passage extends React__namespace.Component {
|
|
|
24371
24368
|
highlights: {},
|
|
24372
24369
|
linterContext: PerseusLinter.linterContextDefault
|
|
24373
24370
|
};
|
|
24371
|
+
|
|
24372
|
+
// this just helps with TS weak typing when a Widget
|
|
24373
|
+
// doesn't implement any Widget methods
|
|
24374
|
+
isWidget = true;
|
|
24374
24375
|
state = {
|
|
24375
24376
|
nLines: null,
|
|
24376
24377
|
startLineNumbersAfter: 0,
|
|
24377
24378
|
stylesAreApplied: false
|
|
24378
24379
|
};
|
|
24379
|
-
|
|
24380
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24381
|
-
static validate() {
|
|
24382
|
-
return noopValidator();
|
|
24383
|
-
}
|
|
24384
24380
|
componentDidMount() {
|
|
24385
24381
|
this._updateState();
|
|
24386
24382
|
|
|
@@ -24589,21 +24585,6 @@ class Passage extends React__namespace.Component {
|
|
|
24589
24585
|
};
|
|
24590
24586
|
}
|
|
24591
24587
|
|
|
24592
|
-
/**
|
|
24593
|
-
* Misc functions
|
|
24594
|
-
*
|
|
24595
|
-
* These are misc widget functions used for the widget API
|
|
24596
|
-
*/
|
|
24597
|
-
|
|
24598
|
-
getUserInput() {
|
|
24599
|
-
return null;
|
|
24600
|
-
}
|
|
24601
|
-
|
|
24602
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24603
|
-
simpleValidate() {
|
|
24604
|
-
return noopValidator();
|
|
24605
|
-
}
|
|
24606
|
-
|
|
24607
24588
|
/**
|
|
24608
24589
|
* Rendering
|
|
24609
24590
|
*
|
|
@@ -24747,7 +24728,8 @@ var Passage$1 = {
|
|
|
24747
24728
|
transform: editorProps => {
|
|
24748
24729
|
return ___default["default"].pick(editorProps, "passageTitle", "passageText", "footnotes", "showLineNumbers");
|
|
24749
24730
|
},
|
|
24750
|
-
isLintable: true
|
|
24731
|
+
isLintable: true,
|
|
24732
|
+
validator: () => noopValidator()
|
|
24751
24733
|
};
|
|
24752
24734
|
|
|
24753
24735
|
/**
|
|
@@ -24777,15 +24759,14 @@ class PassageRef extends React__namespace.Component {
|
|
|
24777
24759
|
referenceNumber: 1,
|
|
24778
24760
|
summaryText: ""
|
|
24779
24761
|
};
|
|
24762
|
+
|
|
24763
|
+
// this just helps with TS weak typing when a Widget
|
|
24764
|
+
// doesn't implement any Widget methods
|
|
24765
|
+
isWidget = true;
|
|
24780
24766
|
state = {
|
|
24781
24767
|
lineRange: null,
|
|
24782
24768
|
content: null
|
|
24783
24769
|
};
|
|
24784
|
-
|
|
24785
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24786
|
-
static validate() {
|
|
24787
|
-
return noopValidator();
|
|
24788
|
-
}
|
|
24789
24770
|
componentDidMount() {
|
|
24790
24771
|
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
24791
24772
|
// this.isMounted() but is still considered an anti-pattern.
|
|
@@ -24804,11 +24785,6 @@ class PassageRef extends React__namespace.Component {
|
|
|
24804
24785
|
window.removeEventListener("resize", this._throttledUpdateRange);
|
|
24805
24786
|
this._isMounted = false;
|
|
24806
24787
|
}
|
|
24807
|
-
|
|
24808
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24809
|
-
getUserInput() {
|
|
24810
|
-
return null;
|
|
24811
|
-
}
|
|
24812
24788
|
change = (() => {
|
|
24813
24789
|
var _this = this;
|
|
24814
24790
|
return function () {
|
|
@@ -24838,11 +24814,6 @@ class PassageRef extends React__namespace.Component {
|
|
|
24838
24814
|
}
|
|
24839
24815
|
}
|
|
24840
24816
|
};
|
|
24841
|
-
|
|
24842
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24843
|
-
simpleValidate() {
|
|
24844
|
-
return noopValidator();
|
|
24845
|
-
}
|
|
24846
24817
|
render() {
|
|
24847
24818
|
const {
|
|
24848
24819
|
strings
|
|
@@ -24891,7 +24862,9 @@ var PassageRef$1 = {
|
|
|
24891
24862
|
version: {
|
|
24892
24863
|
major: 0,
|
|
24893
24864
|
minor: 1
|
|
24894
|
-
}
|
|
24865
|
+
},
|
|
24866
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
24867
|
+
validator: () => noopValidator()
|
|
24895
24868
|
};
|
|
24896
24869
|
|
|
24897
24870
|
/**
|
|
@@ -26310,9 +26283,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26310
26283
|
linterContext: PerseusLinter.linterContextDefault,
|
|
26311
26284
|
showSolutions: "none"
|
|
26312
26285
|
};
|
|
26313
|
-
static validate(userInput, rubric, strings) {
|
|
26314
|
-
return radioValidator(userInput, rubric, strings);
|
|
26315
|
-
}
|
|
26316
26286
|
static getUserInputFromProps(props) {
|
|
26317
26287
|
// Return checked inputs in the form {choicesSelected: [bool]}. (Dear
|
|
26318
26288
|
// future timeline implementers: this used to be {value: i} before
|
|
@@ -26499,9 +26469,6 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26499
26469
|
getUserInput() {
|
|
26500
26470
|
return Radio$1.getUserInputFromProps(this.props);
|
|
26501
26471
|
}
|
|
26502
|
-
simpleValidate(rubric) {
|
|
26503
|
-
return radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26504
|
-
}
|
|
26505
26472
|
|
|
26506
26473
|
/**
|
|
26507
26474
|
* Turn on rationale display for the currently selected choices. Note that
|
|
@@ -26514,7 +26481,7 @@ class Radio$1 extends React__namespace.Component {
|
|
|
26514
26481
|
choiceStates
|
|
26515
26482
|
} = this.props;
|
|
26516
26483
|
if (choiceStates) {
|
|
26517
|
-
const score = this.
|
|
26484
|
+
const score = radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26518
26485
|
const widgetCorrect = score.type === "points" && score.total === score.earned;
|
|
26519
26486
|
const newStates = choiceStates.map(state => ({
|
|
26520
26487
|
...state,
|
|
@@ -26794,7 +26761,8 @@ var Radio = {
|
|
|
26794
26761
|
minor: 0
|
|
26795
26762
|
},
|
|
26796
26763
|
propUpgrades: propUpgrades$1,
|
|
26797
|
-
isLintable: true
|
|
26764
|
+
isLintable: true,
|
|
26765
|
+
validator: radioValidator
|
|
26798
26766
|
};
|
|
26799
26767
|
|
|
26800
26768
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -26837,9 +26805,6 @@ class Categorizer extends React__namespace.Component {
|
|
|
26837
26805
|
state = {
|
|
26838
26806
|
uniqueId: ___default["default"].uniqueId("perseus_radio_")
|
|
26839
26807
|
};
|
|
26840
|
-
static validate(userInput, rubric, strings) {
|
|
26841
|
-
return categorizerValidator(userInput, rubric, strings);
|
|
26842
|
-
}
|
|
26843
26808
|
static getUserInputFromProps(props) {
|
|
26844
26809
|
return {
|
|
26845
26810
|
values: props.values
|
|
@@ -26865,9 +26830,6 @@ class Categorizer extends React__namespace.Component {
|
|
|
26865
26830
|
this.change("values", values);
|
|
26866
26831
|
this.props.trackInteraction();
|
|
26867
26832
|
}
|
|
26868
|
-
simpleValidate(rubric) {
|
|
26869
|
-
return categorizerValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26870
|
-
}
|
|
26871
26833
|
render() {
|
|
26872
26834
|
const self = this;
|
|
26873
26835
|
|
|
@@ -27006,7 +26968,8 @@ var Categorizer$1 = {
|
|
|
27006
26968
|
staticTransform: editorProps => {
|
|
27007
26969
|
return ___default["default"].pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
27008
26970
|
},
|
|
27009
|
-
isLintable: true
|
|
26971
|
+
isLintable: true,
|
|
26972
|
+
validator: categorizerValidator
|
|
27010
26973
|
};
|
|
27011
26974
|
|
|
27012
26975
|
/**
|
|
@@ -27111,11 +27074,6 @@ class CSProgram extends React__namespace.Component {
|
|
|
27111
27074
|
// optional message
|
|
27112
27075
|
message: null
|
|
27113
27076
|
};
|
|
27114
|
-
|
|
27115
|
-
// The widget's grading function
|
|
27116
|
-
static validate(state) {
|
|
27117
|
-
return csProgramValidator(state);
|
|
27118
|
-
}
|
|
27119
27077
|
componentDidMount() {
|
|
27120
27078
|
$__default["default"](window).on("message", this.handleMessageEvent);
|
|
27121
27079
|
}
|
|
@@ -27157,9 +27115,6 @@ class CSProgram extends React__namespace.Component {
|
|
|
27157
27115
|
message: this.props.message
|
|
27158
27116
|
};
|
|
27159
27117
|
}
|
|
27160
|
-
simpleValidate() {
|
|
27161
|
-
return csProgramValidator(this.getUserInput());
|
|
27162
|
-
}
|
|
27163
27118
|
render() {
|
|
27164
27119
|
if (!this.props.programID) {
|
|
27165
27120
|
return /*#__PURE__*/React__namespace.createElement("div", null);
|
|
@@ -27234,7 +27189,8 @@ var CSProgram$1 = {
|
|
|
27234
27189
|
displayName: "CS Program",
|
|
27235
27190
|
supportedAlignments: ["block", "full-width"],
|
|
27236
27191
|
widget: CSProgram,
|
|
27237
|
-
hidden: true
|
|
27192
|
+
hidden: true,
|
|
27193
|
+
validator: csProgramValidator
|
|
27238
27194
|
};
|
|
27239
27195
|
|
|
27240
27196
|
class Definition extends React__namespace.Component {
|
|
@@ -27244,18 +27200,9 @@ class Definition extends React__namespace.Component {
|
|
|
27244
27200
|
definition: "definition goes here"
|
|
27245
27201
|
};
|
|
27246
27202
|
|
|
27247
|
-
//
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
}
|
|
27251
|
-
getUserInput() {
|
|
27252
|
-
return {};
|
|
27253
|
-
}
|
|
27254
|
-
|
|
27255
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27256
|
-
simpleValidate() {
|
|
27257
|
-
return noopValidator();
|
|
27258
|
-
}
|
|
27203
|
+
// this just helps with TS weak typing when a Widget
|
|
27204
|
+
// doesn't implement any Widget methods
|
|
27205
|
+
isWidget = true;
|
|
27259
27206
|
render() {
|
|
27260
27207
|
return /*#__PURE__*/React__namespace.createElement(DefinitionConsumer, null, _ref => {
|
|
27261
27208
|
let {
|
|
@@ -27311,24 +27258,18 @@ var Definition$1 = {
|
|
|
27311
27258
|
accessible: true,
|
|
27312
27259
|
defaultAlignment: "inline",
|
|
27313
27260
|
widget: Definition,
|
|
27314
|
-
transform: x => x
|
|
27261
|
+
transform: x => x,
|
|
27262
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27263
|
+
validator: () => noopValidator()
|
|
27315
27264
|
};
|
|
27316
27265
|
|
|
27317
27266
|
// The props are type `any` on purpose so that this can receive props
|
|
27318
27267
|
// from any deprecated widget
|
|
27319
27268
|
class DeprecatedStandin extends React__default["default"].Component {
|
|
27320
27269
|
static contextType = PerseusI18nContext;
|
|
27321
|
-
|
|
27322
|
-
|
|
27323
|
-
|
|
27324
|
-
return noopValidator(1);
|
|
27325
|
-
}
|
|
27326
|
-
getUserInput() {
|
|
27327
|
-
return {};
|
|
27328
|
-
}
|
|
27329
|
-
simpleValidate() {
|
|
27330
|
-
return noopValidator(1);
|
|
27331
|
-
}
|
|
27270
|
+
// this just helps with TS weak typing when a Widget
|
|
27271
|
+
// doesn't implement any Widget methods
|
|
27272
|
+
isWidget = true;
|
|
27332
27273
|
render() {
|
|
27333
27274
|
return /*#__PURE__*/React__default["default"].createElement("div", {
|
|
27334
27275
|
style: {
|
|
@@ -27346,7 +27287,9 @@ var DeprecatedStandin$1 = {
|
|
|
27346
27287
|
name: "deprecated-standin",
|
|
27347
27288
|
displayName: "Deprecated Standin",
|
|
27348
27289
|
widget: DeprecatedStandin,
|
|
27349
|
-
hidden: true
|
|
27290
|
+
hidden: true,
|
|
27291
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27292
|
+
validator: () => noopValidator(1)
|
|
27350
27293
|
};
|
|
27351
27294
|
|
|
27352
27295
|
function dropdownValidator(userInput, rubric) {
|
|
@@ -27373,9 +27316,6 @@ class Dropdown extends React__namespace.Component {
|
|
|
27373
27316
|
placeholder: "",
|
|
27374
27317
|
apiOptions: ApiOptions.defaults
|
|
27375
27318
|
};
|
|
27376
|
-
static validate(userInput, rubric) {
|
|
27377
|
-
return dropdownValidator(userInput, rubric);
|
|
27378
|
-
}
|
|
27379
27319
|
focus = () => {
|
|
27380
27320
|
// TODO(LP-10797): This focus() call doesn't do anything because our
|
|
27381
27321
|
// root element is a <div> and that cannot be focused without a
|
|
@@ -27398,9 +27338,6 @@ class Dropdown extends React__namespace.Component {
|
|
|
27398
27338
|
value: this.props.selected
|
|
27399
27339
|
};
|
|
27400
27340
|
}
|
|
27401
|
-
simpleValidate(rubric) {
|
|
27402
|
-
return dropdownValidator(this.getUserInput(), rubric);
|
|
27403
|
-
}
|
|
27404
27341
|
render() {
|
|
27405
27342
|
const children = [/*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
|
|
27406
27343
|
key: "placeholder",
|
|
@@ -27441,7 +27378,8 @@ var Dropdown$1 = {
|
|
|
27441
27378
|
defaultAlignment: "inline-block",
|
|
27442
27379
|
accessible: true,
|
|
27443
27380
|
widget: Dropdown,
|
|
27444
|
-
transform: optionsTransform
|
|
27381
|
+
transform: optionsTransform,
|
|
27382
|
+
validator: dropdownValidator
|
|
27445
27383
|
};
|
|
27446
27384
|
|
|
27447
27385
|
// transform = _.identity
|
|
@@ -27454,10 +27392,6 @@ function mediaQueryIsMatched(mediaQuery) {
|
|
|
27454
27392
|
}
|
|
27455
27393
|
class Explanation extends React__namespace.Component {
|
|
27456
27394
|
static contextType = PerseusI18nContext;
|
|
27457
|
-
state = {
|
|
27458
|
-
expanded: false
|
|
27459
|
-
};
|
|
27460
|
-
_mounted = false;
|
|
27461
27395
|
static defaultProps = {
|
|
27462
27396
|
showPrompt: "Explain",
|
|
27463
27397
|
hidePrompt: "Hide explanation",
|
|
@@ -27466,10 +27400,13 @@ class Explanation extends React__namespace.Component {
|
|
|
27466
27400
|
linterContext: PerseusLinter.linterContextDefault
|
|
27467
27401
|
};
|
|
27468
27402
|
|
|
27469
|
-
//
|
|
27470
|
-
|
|
27471
|
-
|
|
27472
|
-
|
|
27403
|
+
// this just helps with TS weak typing when a Widget
|
|
27404
|
+
// doesn't implement any Widget methods
|
|
27405
|
+
isWidget = true;
|
|
27406
|
+
state = {
|
|
27407
|
+
expanded: false
|
|
27408
|
+
};
|
|
27409
|
+
_mounted = false;
|
|
27473
27410
|
componentDidMount() {
|
|
27474
27411
|
this._mounted = true;
|
|
27475
27412
|
}
|
|
@@ -27491,14 +27428,6 @@ class Explanation extends React__namespace.Component {
|
|
|
27491
27428
|
});
|
|
27492
27429
|
this.props.trackInteraction();
|
|
27493
27430
|
};
|
|
27494
|
-
getUserInput() {
|
|
27495
|
-
return {};
|
|
27496
|
-
}
|
|
27497
|
-
|
|
27498
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27499
|
-
simpleValidate() {
|
|
27500
|
-
return noopValidator();
|
|
27501
|
-
}
|
|
27502
27431
|
render() {
|
|
27503
27432
|
const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
|
|
27504
27433
|
const caretIcon = this.state.expanded ? caretUp__default["default"] : caretDown__default["default"];
|
|
@@ -27604,7 +27533,9 @@ var Explanation$1 = {
|
|
|
27604
27533
|
defaultAlignment: "inline",
|
|
27605
27534
|
widget: Explanation,
|
|
27606
27535
|
transform: ___default["default"].identity,
|
|
27607
|
-
isLintable: true
|
|
27536
|
+
isLintable: true,
|
|
27537
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27538
|
+
validator: () => noopValidator()
|
|
27608
27539
|
};
|
|
27609
27540
|
|
|
27610
27541
|
class GradedGroupAnswerBar extends React__namespace.Component {
|
|
@@ -29136,9 +29067,6 @@ class Grapher extends React__namespace.Component {
|
|
|
29136
29067
|
horizHairline;
|
|
29137
29068
|
vertHairline;
|
|
29138
29069
|
static defaultProps = DEFAULT_GRAPHER_PROPS;
|
|
29139
|
-
static validate(state, rubric) {
|
|
29140
|
-
return grapherValidator(state, rubric);
|
|
29141
|
-
}
|
|
29142
29070
|
static getUserInputFromProps(props) {
|
|
29143
29071
|
return props.plot;
|
|
29144
29072
|
}
|
|
@@ -29241,9 +29169,6 @@ class Grapher extends React__namespace.Component {
|
|
|
29241
29169
|
this.vertHairline.hide();
|
|
29242
29170
|
}
|
|
29243
29171
|
};
|
|
29244
|
-
simpleValidate(rubric) {
|
|
29245
|
-
return grapherValidator(this.getUserInput(), rubric);
|
|
29246
|
-
}
|
|
29247
29172
|
getUserInput() {
|
|
29248
29173
|
return Grapher.getUserInputFromProps(this.props);
|
|
29249
29174
|
}
|
|
@@ -29335,7 +29260,8 @@ var Grapher$1 = {
|
|
|
29335
29260
|
hidden: true,
|
|
29336
29261
|
widget: Grapher,
|
|
29337
29262
|
transform: propTransform$2,
|
|
29338
|
-
staticTransform: staticTransform$4
|
|
29263
|
+
staticTransform: staticTransform$4,
|
|
29264
|
+
validator: grapherValidator
|
|
29339
29265
|
};
|
|
29340
29266
|
|
|
29341
29267
|
// exports has no 'transform'
|
|
@@ -29364,6 +29290,13 @@ class Group extends React__namespace.Component {
|
|
|
29364
29290
|
return change.apply(_this, args);
|
|
29365
29291
|
};
|
|
29366
29292
|
})();
|
|
29293
|
+
getUserInputMap() {
|
|
29294
|
+
return this.rendererRef?.getUserInputMap();
|
|
29295
|
+
}
|
|
29296
|
+
|
|
29297
|
+
/**
|
|
29298
|
+
* @deprecated getUserInputMap should be used for Groups
|
|
29299
|
+
*/
|
|
29367
29300
|
getUserInput() {
|
|
29368
29301
|
return this.rendererRef?.getUserInput();
|
|
29369
29302
|
}
|
|
@@ -29376,11 +29309,6 @@ class Group extends React__namespace.Component {
|
|
|
29376
29309
|
// (all our changes were in state):
|
|
29377
29310
|
return null;
|
|
29378
29311
|
};
|
|
29379
|
-
simpleValidate() {
|
|
29380
|
-
return this.rendererRef?.score() ?? {
|
|
29381
|
-
type: "invalid"
|
|
29382
|
-
};
|
|
29383
|
-
}
|
|
29384
29312
|
|
|
29385
29313
|
// Mobile API:
|
|
29386
29314
|
getInputPaths() {
|
|
@@ -29530,9 +29458,6 @@ class Iframe extends React__namespace.Component {
|
|
|
29530
29458
|
allowFullScreen: false,
|
|
29531
29459
|
allowTopNavigation: false
|
|
29532
29460
|
};
|
|
29533
|
-
static validate(state) {
|
|
29534
|
-
return iframeValidator(state);
|
|
29535
|
-
}
|
|
29536
29461
|
componentDidMount() {
|
|
29537
29462
|
$__default["default"](window).on("message", this.handleMessageEvent);
|
|
29538
29463
|
}
|
|
@@ -29574,9 +29499,6 @@ class Iframe extends React__namespace.Component {
|
|
|
29574
29499
|
return change.apply(_this, args);
|
|
29575
29500
|
};
|
|
29576
29501
|
})();
|
|
29577
|
-
simpleValidate() {
|
|
29578
|
-
return iframeValidator(this.getUserInput());
|
|
29579
|
-
}
|
|
29580
29502
|
render() {
|
|
29581
29503
|
const style = {
|
|
29582
29504
|
width: String(this.props.width),
|
|
@@ -29644,7 +29566,8 @@ var Iframe$1 = {
|
|
|
29644
29566
|
displayName: "Iframe (deprecated)",
|
|
29645
29567
|
widget: Iframe,
|
|
29646
29568
|
// Let's not expose it to all content creators yet
|
|
29647
|
-
hidden: true
|
|
29569
|
+
hidden: true,
|
|
29570
|
+
validator: iframeValidator
|
|
29648
29571
|
};
|
|
29649
29572
|
|
|
29650
29573
|
const defaultBoxSize = 400;
|
|
@@ -29673,10 +29596,9 @@ class ImageWidget extends React__namespace.Component {
|
|
|
29673
29596
|
linterContext: PerseusLinter.linterContextDefault
|
|
29674
29597
|
};
|
|
29675
29598
|
|
|
29676
|
-
//
|
|
29677
|
-
|
|
29678
|
-
|
|
29679
|
-
}
|
|
29599
|
+
// this just helps with TS weak typing when a Widget
|
|
29600
|
+
// doesn't implement any Widget methods
|
|
29601
|
+
isWidget = true;
|
|
29680
29602
|
change = (() => {
|
|
29681
29603
|
var _this = this;
|
|
29682
29604
|
return function () {
|
|
@@ -29686,14 +29608,6 @@ class ImageWidget extends React__namespace.Component {
|
|
|
29686
29608
|
return change.apply(_this, args);
|
|
29687
29609
|
};
|
|
29688
29610
|
})();
|
|
29689
|
-
getUserInput() {
|
|
29690
|
-
return null;
|
|
29691
|
-
}
|
|
29692
|
-
|
|
29693
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29694
|
-
simpleValidate() {
|
|
29695
|
-
return noopValidator();
|
|
29696
|
-
}
|
|
29697
29611
|
render() {
|
|
29698
29612
|
let image;
|
|
29699
29613
|
const alt = this.props.caption === this.props.alt ? "" : this.props.alt;
|
|
@@ -29839,7 +29753,9 @@ var Image$1 = {
|
|
|
29839
29753
|
supportedAlignments: editorAlignments,
|
|
29840
29754
|
displayName: "Image",
|
|
29841
29755
|
widget: ImageWidget,
|
|
29842
|
-
isLintable: true
|
|
29756
|
+
isLintable: true,
|
|
29757
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
29758
|
+
validator: () => noopValidator()
|
|
29843
29759
|
};
|
|
29844
29760
|
|
|
29845
29761
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -29918,10 +29834,9 @@ class Interaction extends React__namespace.Component {
|
|
|
29918
29834
|
elements: []
|
|
29919
29835
|
};
|
|
29920
29836
|
|
|
29921
|
-
//
|
|
29922
|
-
|
|
29923
|
-
|
|
29924
|
-
}
|
|
29837
|
+
// this just helps with TS weak typing when a Widget
|
|
29838
|
+
// doesn't implement any Widget methods
|
|
29839
|
+
isWidget = true;
|
|
29925
29840
|
state = {
|
|
29926
29841
|
variables: _getInitialVariables(this.props.elements),
|
|
29927
29842
|
functions: _getInitialFunctions(this.props.elements)
|
|
@@ -30029,18 +29944,6 @@ class Interaction extends React__namespace.Component {
|
|
|
30029
29944
|
return change.apply(_this, args);
|
|
30030
29945
|
};
|
|
30031
29946
|
})();
|
|
30032
|
-
getUserInput() {
|
|
30033
|
-
// TODO(eater): Perhaps we want to be able to record the state of the
|
|
30034
|
-
// user's interaction. Unfortunately sending all the props will
|
|
30035
|
-
// probably make the attempt payload too large. So for now, don't send
|
|
30036
|
-
// anything.
|
|
30037
|
-
return {};
|
|
30038
|
-
}
|
|
30039
|
-
|
|
30040
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
30041
|
-
simpleValidate() {
|
|
30042
|
-
return noopValidator();
|
|
30043
|
-
}
|
|
30044
29947
|
render() {
|
|
30045
29948
|
const range = this.props.graph.range;
|
|
30046
29949
|
let labels = this.props.graph.labels;
|
|
@@ -30448,7 +30351,9 @@ var Interactive = {
|
|
|
30448
30351
|
displayName: "Interaction",
|
|
30449
30352
|
widget: Interaction,
|
|
30450
30353
|
transform: ___default["default"].identity,
|
|
30451
|
-
hidden: true
|
|
30354
|
+
hidden: true,
|
|
30355
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
30356
|
+
validator: () => noopValidator()
|
|
30452
30357
|
};
|
|
30453
30358
|
|
|
30454
30359
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -37605,9 +37510,6 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
37605
37510
|
getUserInput() {
|
|
37606
37511
|
return InteractiveGraph.getUserInputFromProps(this.props);
|
|
37607
37512
|
}
|
|
37608
|
-
simpleValidate(rubric) {
|
|
37609
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37610
|
-
}
|
|
37611
37513
|
focus = $__default["default"].noop;
|
|
37612
37514
|
render() {
|
|
37613
37515
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
@@ -37680,9 +37582,6 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
37680
37582
|
}
|
|
37681
37583
|
throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered", perseusCore.Errors.NotAllowed);
|
|
37682
37584
|
}
|
|
37683
|
-
simpleValidate(rubric) {
|
|
37684
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37685
|
-
}
|
|
37686
37585
|
render() {
|
|
37687
37586
|
// Mafs shim
|
|
37688
37587
|
const mafsFlags = this.props.apiOptions?.flags?.["mafs"];
|
|
@@ -38013,9 +37912,6 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
38013
37912
|
const angle = getClockwiseAngle(coords, allowReflexAngles);
|
|
38014
37913
|
return angle.toFixed(0) + "\u00B0 angle" + " at (" + coords[1].join(", ") + ")";
|
|
38015
37914
|
}
|
|
38016
|
-
static validate(userInput, rubric) {
|
|
38017
|
-
return interactiveGraphValidator(userInput, rubric);
|
|
38018
|
-
}
|
|
38019
37915
|
static getUserInputFromProps(props) {
|
|
38020
37916
|
return props.graph;
|
|
38021
37917
|
}
|
|
@@ -38039,7 +37935,7 @@ function shouldUseMafs(mafsFlags, graph) {
|
|
|
38039
37935
|
// TODO(benchristel): add a feature flag for the "unlimited"
|
|
38040
37936
|
// case once we've implemented polygon graphs with unlimited
|
|
38041
37937
|
// sides
|
|
38042
|
-
return
|
|
37938
|
+
return Boolean(mafsFlags["unlimited-polygon"]);
|
|
38043
37939
|
}
|
|
38044
37940
|
return Boolean(mafsFlags["polygon"]);
|
|
38045
37941
|
default:
|
|
@@ -38052,7 +37948,8 @@ var InteractiveGraph$1 = {
|
|
|
38052
37948
|
name: "interactive-graph",
|
|
38053
37949
|
displayName: "Interactive graph (Assessments only)",
|
|
38054
37950
|
widget: InteractiveGraph,
|
|
38055
|
-
staticTransform: staticTransform$3
|
|
37951
|
+
staticTransform: staticTransform$3,
|
|
37952
|
+
validator: interactiveGraphValidator
|
|
38056
37953
|
};
|
|
38057
37954
|
|
|
38058
37955
|
const black = "#000000";
|
|
@@ -39428,9 +39325,6 @@ class LabelImage extends React__namespace.Component {
|
|
|
39428
39325
|
// The rendered markers on the question image for labeling.
|
|
39429
39326
|
_markers;
|
|
39430
39327
|
_mounted = false;
|
|
39431
|
-
static validate(state, rubric) {
|
|
39432
|
-
return labelImageValidator(state);
|
|
39433
|
-
}
|
|
39434
39328
|
|
|
39435
39329
|
/**
|
|
39436
39330
|
* Test whether point is contained within triangle.
|
|
@@ -39623,9 +39517,6 @@ class LabelImage extends React__namespace.Component {
|
|
|
39623
39517
|
componentWillUnmount() {
|
|
39624
39518
|
this._mounted = false;
|
|
39625
39519
|
}
|
|
39626
|
-
simpleValidate(rubric) {
|
|
39627
|
-
return labelImageValidator(this.getUserInput());
|
|
39628
|
-
}
|
|
39629
39520
|
getUserInput() {
|
|
39630
39521
|
const {
|
|
39631
39522
|
markers
|
|
@@ -39991,19 +39882,13 @@ const LabelImageWithDependencies = /*#__PURE__*/React__namespace.forwardRef((pro
|
|
|
39991
39882
|
analytics: deps.analytics
|
|
39992
39883
|
}, props));
|
|
39993
39884
|
});
|
|
39994
|
-
|
|
39995
|
-
// HACK: Propogate "static" methods onto our wrapper component.
|
|
39996
|
-
// In the future we should adjust client apps to not depend on these static
|
|
39997
|
-
// methods and instead adjust Peresus to provide these facilities through
|
|
39998
|
-
// instance methods on our Renderers.
|
|
39999
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
40000
|
-
LabelImageWithDependencies.validate = labelImageValidator;
|
|
40001
39885
|
var LabelImage$1 = {
|
|
40002
39886
|
name: "label-image",
|
|
40003
39887
|
displayName: "Label Image",
|
|
40004
39888
|
widget: LabelImageWithDependencies,
|
|
40005
39889
|
accessible: true,
|
|
40006
|
-
isLintable: true
|
|
39890
|
+
isLintable: true,
|
|
39891
|
+
validator: labelImageValidator
|
|
40007
39892
|
};
|
|
40008
39893
|
|
|
40009
39894
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -40745,9 +40630,6 @@ class Matcher extends React__namespace.Component {
|
|
|
40745
40630
|
rightHeight: 0,
|
|
40746
40631
|
texRendererLoaded: false
|
|
40747
40632
|
};
|
|
40748
|
-
static validate(state, rubric) {
|
|
40749
|
-
return matcherValidator(state, rubric);
|
|
40750
|
-
}
|
|
40751
40633
|
changeAndTrack = e => {
|
|
40752
40634
|
this.props.onChange(e);
|
|
40753
40635
|
this.props.trackInteraction();
|
|
@@ -40799,9 +40681,6 @@ class Matcher extends React__namespace.Component {
|
|
|
40799
40681
|
// @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
|
|
40800
40682
|
this.refs.right.moveOptionToIndex(option, index);
|
|
40801
40683
|
};
|
|
40802
|
-
simpleValidate(rubric) {
|
|
40803
|
-
return matcherValidator(this.getUserInput(), rubric);
|
|
40804
|
-
}
|
|
40805
40684
|
render() {
|
|
40806
40685
|
// To minimize layout shift, we display a spinner until our math
|
|
40807
40686
|
// renderer is ready to render the math inside the matcher. To
|
|
@@ -40928,7 +40807,8 @@ var Matcher$1 = {
|
|
|
40928
40807
|
name: "matcher",
|
|
40929
40808
|
displayName: "Matcher (two column)",
|
|
40930
40809
|
widget: Matcher,
|
|
40931
|
-
isLintable: true
|
|
40810
|
+
isLintable: true,
|
|
40811
|
+
validator: matcherValidator
|
|
40932
40812
|
};
|
|
40933
40813
|
|
|
40934
40814
|
function matrixValidator(state, rubric, strings) {
|
|
@@ -41069,9 +40949,6 @@ class Matrix extends React__namespace.Component {
|
|
|
41069
40949
|
apiOptions: ApiOptions.defaults,
|
|
41070
40950
|
linterContext: PerseusLinter.linterContextDefault
|
|
41071
40951
|
};
|
|
41072
|
-
static validate(state, rubric, strings) {
|
|
41073
|
-
return matrixValidator(state, rubric, strings);
|
|
41074
|
-
}
|
|
41075
40952
|
state = {
|
|
41076
40953
|
enterTheMatrix: 0
|
|
41077
40954
|
};
|
|
@@ -41214,9 +41091,6 @@ class Matrix extends React__namespace.Component {
|
|
|
41214
41091
|
answers: this.props.answers
|
|
41215
41092
|
};
|
|
41216
41093
|
}
|
|
41217
|
-
simpleValidate(rubric) {
|
|
41218
|
-
return matrixValidator(this.getUserInput(), rubric, this.context.strings);
|
|
41219
|
-
}
|
|
41220
41094
|
render() {
|
|
41221
41095
|
// Set the input sizes through JS so we can control the size of the
|
|
41222
41096
|
// brackets. (If we set them in CSS we won't know values until the
|
|
@@ -41401,7 +41275,8 @@ var Matrix$1 = {
|
|
|
41401
41275
|
widget: Matrix,
|
|
41402
41276
|
transform: propTransform$1,
|
|
41403
41277
|
staticTransform: staticTransform$2,
|
|
41404
|
-
isLintable: true
|
|
41278
|
+
isLintable: true,
|
|
41279
|
+
validator: matrixValidator
|
|
41405
41280
|
};
|
|
41406
41281
|
|
|
41407
41282
|
const defaultImage = {
|
|
@@ -41410,7 +41285,6 @@ const defaultImage = {
|
|
|
41410
41285
|
left: 0
|
|
41411
41286
|
};
|
|
41412
41287
|
class Measurer extends React__namespace.Component {
|
|
41413
|
-
static validate = noopValidator;
|
|
41414
41288
|
static defaultProps = {
|
|
41415
41289
|
box: [480, 480],
|
|
41416
41290
|
image: {},
|
|
@@ -41423,6 +41297,10 @@ class Measurer extends React__namespace.Component {
|
|
|
41423
41297
|
rulerPixels: 40,
|
|
41424
41298
|
rulerLength: 10
|
|
41425
41299
|
};
|
|
41300
|
+
|
|
41301
|
+
// this just helps with TS weak typing when a Widget
|
|
41302
|
+
// doesn't implement any Widget methods
|
|
41303
|
+
isWidget = true;
|
|
41426
41304
|
state = {};
|
|
41427
41305
|
ruler;
|
|
41428
41306
|
protractor;
|
|
@@ -41475,12 +41353,6 @@ class Measurer extends React__namespace.Component {
|
|
|
41475
41353
|
});
|
|
41476
41354
|
}
|
|
41477
41355
|
}
|
|
41478
|
-
getUserInput() {
|
|
41479
|
-
return {};
|
|
41480
|
-
}
|
|
41481
|
-
simpleValidate() {
|
|
41482
|
-
return noopValidator(1);
|
|
41483
|
-
}
|
|
41484
41356
|
render() {
|
|
41485
41357
|
const image = ___default["default"].extend({}, defaultImage, this.props.image);
|
|
41486
41358
|
|
|
@@ -41527,7 +41399,9 @@ var Measurer$1 = {
|
|
|
41527
41399
|
major: 1,
|
|
41528
41400
|
minor: 0
|
|
41529
41401
|
},
|
|
41530
|
-
propUpgrades: propUpgrades
|
|
41402
|
+
propUpgrades: propUpgrades,
|
|
41403
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
41404
|
+
validator: () => noopValidator(1)
|
|
41531
41405
|
};
|
|
41532
41406
|
|
|
41533
41407
|
/**
|
|
@@ -42400,18 +42274,9 @@ class MoleculeWidget extends React__namespace.Component {
|
|
|
42400
42274
|
rotationAngle: 0
|
|
42401
42275
|
};
|
|
42402
42276
|
|
|
42403
|
-
//
|
|
42404
|
-
|
|
42405
|
-
|
|
42406
|
-
}
|
|
42407
|
-
getUserInput() {
|
|
42408
|
-
return [];
|
|
42409
|
-
}
|
|
42410
|
-
|
|
42411
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
42412
|
-
validate() {
|
|
42413
|
-
return noopValidator();
|
|
42414
|
-
}
|
|
42277
|
+
// this just helps with TS weak typing when a Widget
|
|
42278
|
+
// doesn't implement any Widget methods
|
|
42279
|
+
isWidget = true;
|
|
42415
42280
|
render() {
|
|
42416
42281
|
return /*#__PURE__*/React__namespace.createElement(Molecule, {
|
|
42417
42282
|
widgetId: this.props.widgetId,
|
|
@@ -42424,7 +42289,8 @@ var Molecule$1 = {
|
|
|
42424
42289
|
name: "molecule-renderer",
|
|
42425
42290
|
displayName: "Molecule renderer",
|
|
42426
42291
|
hidden: true,
|
|
42427
|
-
widget: MoleculeWidget
|
|
42292
|
+
widget: MoleculeWidget,
|
|
42293
|
+
validator: () => noopValidator()
|
|
42428
42294
|
};
|
|
42429
42295
|
|
|
42430
42296
|
function numberLineValidator(state, rubric) {
|
|
@@ -42569,18 +42435,16 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
42569
42435
|
results.push(graphie.line([x, -0.2], [x, 0.2]));
|
|
42570
42436
|
const labelTicks = props.labelTicks;
|
|
42571
42437
|
if (labelTicks || props.labelStyle === "decimal ticks") {
|
|
42572
|
-
|
|
42438
|
+
if (x === leftLabel || x === rightLabel) {
|
|
42439
|
+
results.push(graphie.style({
|
|
42440
|
+
color: KhanColors.BLUE
|
|
42441
|
+
}, () => _label(graphie, props.labelStyle, x, x, base)));
|
|
42442
|
+
} else {
|
|
42443
|
+
results.push(_label(graphie, props.labelStyle, x, x, base));
|
|
42444
|
+
}
|
|
42573
42445
|
}
|
|
42574
42446
|
}
|
|
42575
42447
|
|
|
42576
|
-
// Render the text labels
|
|
42577
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42578
|
-
color: KhanColors.BLUE
|
|
42579
|
-
} : {}, () => _label(graphie, props.labelStyle, leftLabel, leftLabel, base)));
|
|
42580
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42581
|
-
color: KhanColors.BLUE
|
|
42582
|
-
} : {}, () => _label(graphie, props.labelStyle, rightLabel, rightLabel, base)));
|
|
42583
|
-
|
|
42584
42448
|
// Render the labels' lines
|
|
42585
42449
|
graphie.style({
|
|
42586
42450
|
stroke: KhanColors.BLUE,
|
|
@@ -42613,9 +42477,6 @@ class NumberLine extends React__namespace.Component {
|
|
|
42613
42477
|
state = {
|
|
42614
42478
|
numDivisionsEmpty: false
|
|
42615
42479
|
};
|
|
42616
|
-
static validate(state, rubric) {
|
|
42617
|
-
return numberLineValidator(state, rubric);
|
|
42618
|
-
}
|
|
42619
42480
|
change = (() => {
|
|
42620
42481
|
var _this = this;
|
|
42621
42482
|
return function () {
|
|
@@ -42908,9 +42769,6 @@ class NumberLine extends React__namespace.Component {
|
|
|
42908
42769
|
divisionRange: this.props.divisionRange
|
|
42909
42770
|
};
|
|
42910
42771
|
}
|
|
42911
|
-
simpleValidate(rubric) {
|
|
42912
|
-
return numberLineValidator(this.getUserInput(), rubric);
|
|
42913
|
-
}
|
|
42914
42772
|
render() {
|
|
42915
42773
|
const {
|
|
42916
42774
|
strings
|
|
@@ -43014,7 +42872,8 @@ var NumberLine$1 = {
|
|
|
43014
42872
|
displayName: "Number line",
|
|
43015
42873
|
widget: NumberLine,
|
|
43016
42874
|
transform: numberLineTransform,
|
|
43017
|
-
staticTransform: staticTransform$1
|
|
42875
|
+
staticTransform: staticTransform$1,
|
|
42876
|
+
validator: numberLineValidator
|
|
43018
42877
|
};
|
|
43019
42878
|
|
|
43020
42879
|
function ordererValidator(userInput, rubric) {
|
|
@@ -43224,9 +43083,6 @@ class Orderer extends React__namespace.Component {
|
|
|
43224
43083
|
animateTo: null,
|
|
43225
43084
|
grabPos: null
|
|
43226
43085
|
};
|
|
43227
|
-
static validate(userInput, rubric) {
|
|
43228
|
-
return ordererValidator(userInput, rubric);
|
|
43229
|
-
}
|
|
43230
43086
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
43231
43087
|
if (!___default["default"].isEqual(this.props.current, nextProps.current)) {
|
|
43232
43088
|
this.setState({
|
|
@@ -43466,9 +43322,6 @@ class Orderer extends React__namespace.Component {
|
|
|
43466
43322
|
})
|
|
43467
43323
|
};
|
|
43468
43324
|
}
|
|
43469
|
-
simpleValidate(rubric) {
|
|
43470
|
-
return ordererValidator(this.getUserInput(), rubric);
|
|
43471
|
-
}
|
|
43472
43325
|
render() {
|
|
43473
43326
|
// This is the card we are currently dragging
|
|
43474
43327
|
const dragging = this.state.dragging && /*#__PURE__*/React__namespace.createElement(Card
|
|
@@ -43578,7 +43431,8 @@ var Orderer$1 = {
|
|
|
43578
43431
|
displayName: "Orderer",
|
|
43579
43432
|
hidden: true,
|
|
43580
43433
|
widget: Orderer,
|
|
43581
|
-
isLintable: true
|
|
43434
|
+
isLintable: true,
|
|
43435
|
+
validator: ordererValidator
|
|
43582
43436
|
};
|
|
43583
43437
|
|
|
43584
43438
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -43589,15 +43443,9 @@ class PassageRefTarget extends React__namespace.Component {
|
|
|
43589
43443
|
linterContext: PerseusLinter.linterContextDefault
|
|
43590
43444
|
};
|
|
43591
43445
|
|
|
43592
|
-
//
|
|
43593
|
-
|
|
43594
|
-
|
|
43595
|
-
}
|
|
43596
|
-
|
|
43597
|
-
// TODO passage-ref-target isn't interactive; remove
|
|
43598
|
-
getUserInput() {
|
|
43599
|
-
return null;
|
|
43600
|
-
}
|
|
43446
|
+
// this just helps with TS weak typing when a Widget
|
|
43447
|
+
// doesn't implement any Widget methods
|
|
43448
|
+
isWidget = true;
|
|
43601
43449
|
|
|
43602
43450
|
// TODO passage-ref-target isn't interactive; remove
|
|
43603
43451
|
change = (() => {
|
|
@@ -43609,11 +43457,6 @@ class PassageRefTarget extends React__namespace.Component {
|
|
|
43609
43457
|
return change.apply(_this, args);
|
|
43610
43458
|
};
|
|
43611
43459
|
})();
|
|
43612
|
-
|
|
43613
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43614
|
-
simpleValidate() {
|
|
43615
|
-
return noopValidator();
|
|
43616
|
-
}
|
|
43617
43460
|
render() {
|
|
43618
43461
|
return /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
43619
43462
|
content: this.props.content
|
|
@@ -43642,7 +43485,9 @@ var PassageRefTarget$1 = {
|
|
|
43642
43485
|
major: 0,
|
|
43643
43486
|
minor: 0
|
|
43644
43487
|
},
|
|
43645
|
-
isLintable: true
|
|
43488
|
+
isLintable: true,
|
|
43489
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
43490
|
+
validator: () => noopValidator()
|
|
43646
43491
|
};
|
|
43647
43492
|
|
|
43648
43493
|
/**
|
|
@@ -43654,6 +43499,10 @@ class PhetSimulation extends React__namespace.Component {
|
|
|
43654
43499
|
static contextType = PerseusI18nContext;
|
|
43655
43500
|
iframeRef = /*#__PURE__*/React__namespace.createRef();
|
|
43656
43501
|
locale;
|
|
43502
|
+
|
|
43503
|
+
// this just helps with TS weak typing when a Widget
|
|
43504
|
+
// doesn't implement any Widget methods
|
|
43505
|
+
isWidget = true;
|
|
43657
43506
|
state = {
|
|
43658
43507
|
url: null,
|
|
43659
43508
|
banner: null
|
|
@@ -43672,11 +43521,6 @@ class PhetSimulation extends React__namespace.Component {
|
|
|
43672
43521
|
}
|
|
43673
43522
|
}
|
|
43674
43523
|
|
|
43675
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43676
|
-
getUserInput() {
|
|
43677
|
-
return null;
|
|
43678
|
-
}
|
|
43679
|
-
|
|
43680
43524
|
// kaLocales and PhET locales use different formats and abbreviations.
|
|
43681
43525
|
// PhET accepts different formats, i.e. kaLocale's hyphens, but it does not accept
|
|
43682
43526
|
// different abbreviations, so in points of divergence of abbreviations, we need to
|
|
@@ -43896,9 +43740,6 @@ class Plotter extends React__namespace.Component {
|
|
|
43896
43740
|
// bottom label.
|
|
43897
43741
|
categoryHeights: {}
|
|
43898
43742
|
};
|
|
43899
|
-
static validate(userInput, rubric) {
|
|
43900
|
-
return plotterValidator(userInput, rubric);
|
|
43901
|
-
}
|
|
43902
43743
|
componentDidMount() {
|
|
43903
43744
|
this._isMounted = true;
|
|
43904
43745
|
this.setupGraphie(this.state);
|
|
@@ -44643,9 +44484,6 @@ class Plotter extends React__namespace.Component {
|
|
|
44643
44484
|
getUserInput() {
|
|
44644
44485
|
return this.state.values;
|
|
44645
44486
|
}
|
|
44646
|
-
simpleValidate(rubric) {
|
|
44647
|
-
return plotterValidator(this.getUserInput(), rubric);
|
|
44648
|
-
}
|
|
44649
44487
|
render() {
|
|
44650
44488
|
// TODO(kevinb) actually compute the size of the graphie correctly and
|
|
44651
44489
|
// make it that size so we don't have to add extra padding. The value
|
|
@@ -44671,7 +44509,8 @@ var Plotter$1 = {
|
|
|
44671
44509
|
displayName: "Plotter",
|
|
44672
44510
|
hidden: true,
|
|
44673
44511
|
widget: Plotter,
|
|
44674
|
-
staticTransform: staticTransform
|
|
44512
|
+
staticTransform: staticTransform,
|
|
44513
|
+
validator: plotterValidator
|
|
44675
44514
|
};
|
|
44676
44515
|
|
|
44677
44516
|
/**
|
|
@@ -44766,9 +44605,6 @@ class Sorter extends React__namespace.Component {
|
|
|
44766
44605
|
onChange: function () {},
|
|
44767
44606
|
linterContext: PerseusLinter.linterContextDefault
|
|
44768
44607
|
};
|
|
44769
|
-
static validate(userInput, rubric) {
|
|
44770
|
-
return sorterValidator(userInput, rubric);
|
|
44771
|
-
}
|
|
44772
44608
|
state = {
|
|
44773
44609
|
changed: false
|
|
44774
44610
|
};
|
|
@@ -44811,9 +44647,6 @@ class Sorter extends React__namespace.Component {
|
|
|
44811
44647
|
// @ts-expect-error - TS2339 - Property 'moveOptionToIndex' does not exist on type 'ReactInstance'.
|
|
44812
44648
|
this.refs.sortable.moveOptionToIndex(option, index);
|
|
44813
44649
|
};
|
|
44814
|
-
simpleValidate(rubric) {
|
|
44815
|
-
return sorterValidator(this.getUserInput(), rubric);
|
|
44816
|
-
}
|
|
44817
44650
|
render() {
|
|
44818
44651
|
const options = shuffle(this.props.correct, this.props.problemNum, /* ensurePermuted */true);
|
|
44819
44652
|
const {
|
|
@@ -44839,7 +44672,8 @@ var Sorter$1 = {
|
|
|
44839
44672
|
name: "sorter",
|
|
44840
44673
|
displayName: "Sorter",
|
|
44841
44674
|
widget: Sorter,
|
|
44842
|
-
isLintable: true
|
|
44675
|
+
isLintable: true,
|
|
44676
|
+
validator: sorterValidator
|
|
44843
44677
|
};
|
|
44844
44678
|
|
|
44845
44679
|
function tableValidator(state, rubric, strings) {
|
|
@@ -44947,9 +44781,6 @@ class Table extends React__namespace.Component {
|
|
|
44947
44781
|
linterContext: PerseusLinter.linterContextDefault
|
|
44948
44782
|
};
|
|
44949
44783
|
}();
|
|
44950
|
-
static validate(state, rubric, strings) {
|
|
44951
|
-
return tableValidator(state, rubric, strings);
|
|
44952
|
-
}
|
|
44953
44784
|
_getRows = () => {
|
|
44954
44785
|
return this.props.answers.length;
|
|
44955
44786
|
};
|
|
@@ -44978,9 +44809,6 @@ class Table extends React__namespace.Component {
|
|
|
44978
44809
|
headers: headers
|
|
44979
44810
|
});
|
|
44980
44811
|
};
|
|
44981
|
-
simpleValidate(rubric) {
|
|
44982
|
-
return tableValidator(this.getUserInput(), rubric, this.context.strings);
|
|
44983
|
-
}
|
|
44984
44812
|
_handleFocus = inputPath => {
|
|
44985
44813
|
this.props.onFocus(inputPath);
|
|
44986
44814
|
};
|
|
@@ -45124,7 +44952,8 @@ var Table$1 = {
|
|
|
45124
44952
|
widget: Table,
|
|
45125
44953
|
transform: propTransform,
|
|
45126
44954
|
hidden: true,
|
|
45127
|
-
isLintable: true
|
|
44955
|
+
isLintable: true,
|
|
44956
|
+
validator: tableValidator
|
|
45128
44957
|
};
|
|
45129
44958
|
|
|
45130
44959
|
/**
|
|
@@ -45210,22 +45039,9 @@ const IS_VIMEO = /(vimeo\.com)/;
|
|
|
45210
45039
|
*/
|
|
45211
45040
|
class Video extends React__namespace.Component {
|
|
45212
45041
|
static contextType = PerseusI18nContext;
|
|
45213
|
-
|
|
45214
|
-
|
|
45215
|
-
|
|
45216
|
-
* of Khan Academy videos.
|
|
45217
|
-
*/ // TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
45218
|
-
static validate() {
|
|
45219
|
-
return noopValidator();
|
|
45220
|
-
}
|
|
45221
|
-
getUserInput = () => {
|
|
45222
|
-
return null;
|
|
45223
|
-
};
|
|
45224
|
-
|
|
45225
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
45226
|
-
simpleValidate() {
|
|
45227
|
-
return noopValidator();
|
|
45228
|
-
}
|
|
45042
|
+
// this just helps with TS weak typing when a Widget
|
|
45043
|
+
// doesn't implement any Widget methods
|
|
45044
|
+
isWidget = true;
|
|
45229
45045
|
change = (() => {
|
|
45230
45046
|
var _this = this;
|
|
45231
45047
|
return function () {
|
|
@@ -45294,7 +45110,9 @@ var Video$1 = {
|
|
|
45294
45110
|
displayName: "Video",
|
|
45295
45111
|
defaultAlignment: "block",
|
|
45296
45112
|
supportedAlignments: ["block", "float-left", "float-right", "full-width"],
|
|
45297
|
-
widget: Video
|
|
45113
|
+
widget: Video,
|
|
45114
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
45115
|
+
validator: () => noopValidator()
|
|
45298
45116
|
};
|
|
45299
45117
|
|
|
45300
45118
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -45338,7 +45156,7 @@ const init = function (options) {
|
|
|
45338
45156
|
|
|
45339
45157
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45340
45158
|
const libName = "@khanacademy/perseus";
|
|
45341
|
-
const libVersion = "
|
|
45159
|
+
const libVersion = "37.0.1";
|
|
45342
45160
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45343
45161
|
|
|
45344
45162
|
const apiVersion = {
|
|
@@ -46064,7 +45882,7 @@ class ServerItemRenderer extends React__namespace.Component {
|
|
|
46064
45882
|
});
|
|
46065
45883
|
|
|
46066
45884
|
// Call the interactionCallback, if it exists, with the current user input data
|
|
46067
|
-
this.props.apiOptions?.interactionCallback?.(this.questionRenderer.
|
|
45885
|
+
this.props.apiOptions?.interactionCallback?.(this.questionRenderer.getUserInputMap());
|
|
46068
45886
|
};
|
|
46069
45887
|
focus() {
|
|
46070
45888
|
return this.questionRenderer.focus();
|
|
@@ -48597,9 +48415,7 @@ const getCorrectAnswerForWidgetId = (widgetId, itemData) => {
|
|
|
48597
48415
|
const rubric = itemData.question.widgets[widgetId].options;
|
|
48598
48416
|
const widgetMap = getWidgetsMapFromItemData(itemData);
|
|
48599
48417
|
const widgetType = getWidgetTypeByWidgetId(widgetId, widgetMap);
|
|
48600
|
-
const widget =
|
|
48601
|
-
|
|
48602
|
-
// @ts-expect-error - TS2339 - Property 'getOneCorrectAnswerFromRubric' does not exist on type 'ComponentType<any>'.
|
|
48418
|
+
const widget = getWidgetExport(widgetType);
|
|
48603
48419
|
return widget?.getOneCorrectAnswerFromRubric?.(rubric);
|
|
48604
48420
|
};
|
|
48605
48421
|
|
|
@@ -48690,11 +48506,12 @@ function parsePerseusItem(json) {
|
|
|
48690
48506
|
throw new Error("Something went wrong.");
|
|
48691
48507
|
}
|
|
48692
48508
|
function buildRandomString() {
|
|
48509
|
+
let capitalize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
48693
48510
|
let randomString = "";
|
|
48694
48511
|
const randomLength = Math.floor(Math.random() * 8) + 3;
|
|
48695
48512
|
for (let i = 0; i < randomLength; i++) {
|
|
48696
48513
|
const randomLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
48697
|
-
randomString += randomLetter;
|
|
48514
|
+
randomString += capitalize && i === 0 ? randomLetter.toUpperCase() : randomLetter;
|
|
48698
48515
|
}
|
|
48699
48516
|
return randomString;
|
|
48700
48517
|
}
|
|
@@ -48702,9 +48519,12 @@ function buildRandomPhrase() {
|
|
|
48702
48519
|
const phrases = [];
|
|
48703
48520
|
const randomLength = Math.floor(Math.random() * 10) + 5;
|
|
48704
48521
|
for (let i = 0; i < randomLength; i++) {
|
|
48705
|
-
phrases.push(buildRandomString());
|
|
48522
|
+
phrases.push(buildRandomString(i === 0));
|
|
48706
48523
|
}
|
|
48707
|
-
|
|
48524
|
+
const modifierStart = ["**", "$"];
|
|
48525
|
+
const modifierEnd = ["**", "$"];
|
|
48526
|
+
const modifierIndex = Math.floor(Math.random() * modifierStart.length);
|
|
48527
|
+
return `${modifierStart[modifierIndex]}${phrases.join(" ")}${modifierEnd[modifierIndex]}`;
|
|
48708
48528
|
}
|
|
48709
48529
|
function buildTestData(testObject) {
|
|
48710
48530
|
return `{"data":{"assessmentItem":{"__typename":"AssessmentItemOrError","error":null,"item":{"__typename":"AssessmentItem","id":"x890b3c70f3e8f4a6","itemData":"${testObject}","problemType":"Type 1","sha":"c7284a3ad65214b4e62bccce236d92f7f5d35941"}}}}`;
|