@khanacademy/perseus 36.1.1 → 37.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/all-widgets.d.ts +1 -0
- package/dist/basic-widgets.d.ts +1 -0
- package/dist/components/math-input.d.ts +1 -1
- package/dist/es/index.js +523 -660
- package/dist/es/index.js.map +1 -1
- package/dist/extra-widgets.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +489 -635
- package/dist/index.js.map +1 -1
- package/dist/renderer-util.d.ts +8 -0
- package/dist/renderer.d.ts +19 -20
- package/dist/server-item-renderer.d.ts +3 -1
- package/dist/types.d.ts +11 -3
- package/dist/util/graphie.d.ts +1 -1
- package/dist/util.d.ts +4 -0
- package/dist/validation.types.d.ts +19 -9
- package/dist/widgets/categorizer/categorizer.d.ts +3 -5
- package/dist/widgets/cs-program/cs-program.d.ts +4 -8
- package/dist/widgets/definition/definition.d.ts +3 -4
- package/dist/widgets/deprecated-standin/deprecated-standin.d.ts +35 -0
- package/dist/widgets/deprecated-standin/index.d.ts +1 -37
- package/dist/widgets/dropdown/dropdown.d.ts +2 -3
- package/dist/widgets/explanation/explanation.d.ts +4 -5
- package/dist/widgets/expression/expression.d.ts +4 -8
- package/dist/widgets/graded-group/graded-group.d.ts +1 -0
- package/dist/widgets/graded-group-set/graded-group-set.d.ts +1 -0
- package/dist/widgets/grapher/grapher.d.ts +2 -3
- package/dist/widgets/group/group.d.ts +8 -5
- package/dist/widgets/iframe/iframe.d.ts +2 -3
- package/dist/widgets/image/image.d.ts +3 -4
- package/dist/widgets/input-number/input-number.d.ts +2 -5
- package/dist/widgets/interaction/interaction.d.ts +3 -4
- package/dist/widgets/interactive-graph.d.ts +3 -5
- package/dist/widgets/interactive-graphs/math/angles.d.ts +3 -1
- package/dist/widgets/interactive-graphs/math/index.d.ts +1 -1
- package/dist/widgets/label-image/label-image.d.ts +3 -4
- package/dist/widgets/matcher/matcher.d.ts +2 -3
- package/dist/widgets/matrix/matrix.d.ts +3 -5
- package/dist/widgets/measurer/measurer.d.ts +2 -4
- package/dist/widgets/molecule/molecule.d.ts +2 -4
- package/dist/widgets/number-line/number-line.d.ts +3 -4
- package/dist/widgets/numeric-input/numeric-input.d.ts +2 -3
- package/dist/widgets/orderer/orderer.d.ts +2 -3
- package/dist/widgets/passage/passage.d.ts +3 -9
- package/dist/widgets/passage-ref/passage-ref.d.ts +3 -4
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +2 -4
- package/dist/widgets/phet-simulation/phet-simulation.d.ts +2 -2
- package/dist/widgets/plotter/plotter.d.ts +2 -3
- package/dist/widgets/python-program/python-program.d.ts +1 -0
- package/dist/widgets/radio/radio-component.d.ts +2 -5
- package/dist/widgets/radio/radio.d.ts +1 -0
- package/dist/widgets/sorter/sorter.d.ts +2 -3
- package/dist/widgets/table/table.d.ts +3 -5
- package/dist/widgets/video/video.d.ts +2 -8
- package/dist/widgets.d.ts +2 -1
- package/package.json +9 -9
- 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,10 +2373,6 @@ 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
|
}
|
|
@@ -2465,7 +2422,7 @@ class Expression extends React.Component {
|
|
|
2465
2422
|
}, cb);
|
|
2466
2423
|
}
|
|
2467
2424
|
render() {
|
|
2468
|
-
var _this$props$keypadCon, _this$props$
|
|
2425
|
+
var _this$props$keypadCon, _this$props$analytics2;
|
|
2469
2426
|
if (this.props.apiOptions.customKeypad) {
|
|
2470
2427
|
return /*#__PURE__*/React.createElement(View, {
|
|
2471
2428
|
className: css(styles$D.mobileLabelInputWrapper)
|
|
@@ -2538,7 +2495,7 @@ class Expression extends React.Component {
|
|
|
2538
2495
|
hasError: this.state.showErrorStyle,
|
|
2539
2496
|
ariaLabel: this.props.ariaLabel || this.context.strings.mathInputBox,
|
|
2540
2497
|
extraKeys: (_this$props$keypadCon = this.props.keypadConfiguration) == null ? void 0 : _this$props$keypadCon.extraKeys,
|
|
2541
|
-
analytics: (_this$props$
|
|
2498
|
+
analytics: (_this$props$analytics2 = this.props.analytics) != null ? _this$props$analytics2 : {
|
|
2542
2499
|
onAnalyticsEvent: async function () {}
|
|
2543
2500
|
}
|
|
2544
2501
|
}))));
|
|
@@ -2691,7 +2648,8 @@ var Expression$1 = {
|
|
|
2691
2648
|
},
|
|
2692
2649
|
propUpgrades: propUpgrades$2,
|
|
2693
2650
|
// For use by the editor
|
|
2694
|
-
isLintable: true
|
|
2651
|
+
isLintable: true,
|
|
2652
|
+
validator: expressionValidator
|
|
2695
2653
|
};
|
|
2696
2654
|
|
|
2697
2655
|
/**
|
|
@@ -2920,6 +2878,9 @@ function combineScores(scoreA, scoreB) {
|
|
|
2920
2878
|
}
|
|
2921
2879
|
});
|
|
2922
2880
|
}
|
|
2881
|
+
function flattenScores(widgetScoreMap) {
|
|
2882
|
+
return Object.values(widgetScoreMap).reduce(combineScores, noScore);
|
|
2883
|
+
}
|
|
2923
2884
|
function isCorrect(score) {
|
|
2924
2885
|
return score.type === "points" && score.earned >= score.total;
|
|
2925
2886
|
}
|
|
@@ -3452,6 +3413,7 @@ const Util = {
|
|
|
3452
3413
|
shuffle: shuffle$3,
|
|
3453
3414
|
split,
|
|
3454
3415
|
combineScores,
|
|
3416
|
+
flattenScores,
|
|
3455
3417
|
keScoreFromPerseusScore,
|
|
3456
3418
|
firstNumericalParse: firstNumericalParse$1,
|
|
3457
3419
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
@@ -9988,6 +9950,8 @@ const setLabelMargins = function setLabelMargins(span, size) {
|
|
|
9988
9950
|
});
|
|
9989
9951
|
} else {
|
|
9990
9952
|
var _$container$css, _$container$width, _$span$css;
|
|
9953
|
+
const currentHeightMatchesProps = span.scrollHeight === height;
|
|
9954
|
+
|
|
9991
9955
|
// We are using jQuery to collect information and calculate a scale
|
|
9992
9956
|
// since we don't have a way to pass it to this function.
|
|
9993
9957
|
// We need the width of the container in order to calculate the scale to apply to the label.
|
|
@@ -10009,6 +9973,17 @@ const setLabelMargins = function setLabelMargins(span, size) {
|
|
|
10009
9973
|
// Inherited line-height values can really mess up placement.
|
|
10010
9974
|
$container.css("line-height", "normal");
|
|
10011
9975
|
|
|
9976
|
+
// TODO: Verify that this change doesn't impact other graphies
|
|
9977
|
+
// Check the full list of consuming widgets.
|
|
9978
|
+
|
|
9979
|
+
// If the change in line-height affected the height of the element,
|
|
9980
|
+
// then the height used for calculations should be updated.
|
|
9981
|
+
// This can happen when the first label in the container calls this method,
|
|
9982
|
+
// and the line-height was different when the height measurement was originally referenced.
|
|
9983
|
+
if (currentHeightMatchesProps && span.scrollHeight !== height) {
|
|
9984
|
+
height = span.scrollHeight;
|
|
9985
|
+
}
|
|
9986
|
+
|
|
10012
9987
|
// The expected width of the graphie is found in the "max-width" property on ".svg-image" containers,
|
|
10013
9988
|
// and is found in the "width" property on ".graphie" containers.
|
|
10014
9989
|
const widthValues = (_$container$css = $container.css(["max-width", "width"])) != null ? _$container$css : {
|
|
@@ -10070,7 +10045,10 @@ const GraphUtils = {
|
|
|
10070
10045
|
return point.distanceToPoint(point1, point2);
|
|
10071
10046
|
},
|
|
10072
10047
|
// Find the angle in degrees between two or three points
|
|
10073
|
-
|
|
10048
|
+
// This function is deprecated as it has several issues calculating
|
|
10049
|
+
// correctly when dealing with reflex angles or the position of point2
|
|
10050
|
+
// (LEMS-2202) Remove this function while removing the Legacy Interactive Graph.
|
|
10051
|
+
findAngleDeprecated: function (point1, point2, vertex) {
|
|
10074
10052
|
if (vertex === undefined) {
|
|
10075
10053
|
const x = point1[0] - point2[0];
|
|
10076
10054
|
const y = point1[1] - point2[1];
|
|
@@ -10079,7 +10057,7 @@ const GraphUtils = {
|
|
|
10079
10057
|
}
|
|
10080
10058
|
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
10081
10059
|
}
|
|
10082
|
-
return GraphUtils.
|
|
10060
|
+
return GraphUtils.findAngleDeprecated(point1, vertex) - GraphUtils.findAngleDeprecated(point2, vertex);
|
|
10083
10061
|
},
|
|
10084
10062
|
graphs: {}
|
|
10085
10063
|
};
|
|
@@ -11095,8 +11073,8 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11095
11073
|
p1 = options.point3;
|
|
11096
11074
|
p3 = options.point1;
|
|
11097
11075
|
}
|
|
11098
|
-
const startAngle = GraphUtils.
|
|
11099
|
-
const endAngle = GraphUtils.
|
|
11076
|
+
const startAngle = GraphUtils.findAngleDeprecated(p1, vertex);
|
|
11077
|
+
const endAngle = GraphUtils.findAngleDeprecated(p3, vertex);
|
|
11100
11078
|
const angle = (endAngle + 360 - startAngle) % 360;
|
|
11101
11079
|
const halfAngle = (startAngle + angle / 2) % 360;
|
|
11102
11080
|
const sPadding = 5 * options.pushOut;
|
|
@@ -11263,15 +11241,15 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11263
11241
|
let angle = 135;
|
|
11264
11242
|
let halfAngle;
|
|
11265
11243
|
if (p1 && p3) {
|
|
11266
|
-
const startAngle = GraphUtils.
|
|
11267
|
-
const endAngle = GraphUtils.
|
|
11244
|
+
const startAngle = GraphUtils.findAngleDeprecated(p1, vertex);
|
|
11245
|
+
const endAngle = GraphUtils.findAngleDeprecated(p3, vertex);
|
|
11268
11246
|
angle = (endAngle + 360 - startAngle) % 360;
|
|
11269
11247
|
halfAngle = (startAngle + angle / 2 + 180) % 360;
|
|
11270
11248
|
} else if (p1) {
|
|
11271
|
-
const parallelAngle = GraphUtils.
|
|
11249
|
+
const parallelAngle = GraphUtils.findAngleDeprecated(vertex, p1);
|
|
11272
11250
|
halfAngle = parallelAngle + 90;
|
|
11273
11251
|
} else if (p3) {
|
|
11274
|
-
const parallelAngle = GraphUtils.
|
|
11252
|
+
const parallelAngle = GraphUtils.findAngleDeprecated(p3, vertex);
|
|
11275
11253
|
halfAngle = parallelAngle + 90;
|
|
11276
11254
|
} else {
|
|
11277
11255
|
// Standalone point
|
|
@@ -11477,7 +11455,7 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11477
11455
|
const vertex = constraints.fixedAngle.vertex.coord || constraints.fixedAngle.vertex;
|
|
11478
11456
|
const ref = constraints.fixedAngle.ref.coord || constraints.fixedAngle.ref;
|
|
11479
11457
|
const distPoint = constraints.fixedDistance.point.coord || constraints.fixedDistance.point;
|
|
11480
|
-
const constrainedAngle = (constraints.fixedAngle.angle + GraphUtils.
|
|
11458
|
+
const constrainedAngle = (constraints.fixedAngle.angle + GraphUtils.findAngleDeprecated(ref, vertex)) * Math.PI / 180;
|
|
11481
11459
|
const length = constraints.fixedDistance.dist;
|
|
11482
11460
|
newCoord[0] = length * Math.cos(constrainedAngle) + distPoint[0];
|
|
11483
11461
|
newCoord[1] = length * Math.sin(constrainedAngle) + distPoint[1];
|
|
@@ -11486,8 +11464,8 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11486
11464
|
} else if (typeof constraints.fixedAngle.angle === "number") {
|
|
11487
11465
|
const vertex = constraints.fixedAngle.vertex.coord || constraints.fixedAngle.vertex;
|
|
11488
11466
|
const ref = constraints.fixedAngle.ref.coord || constraints.fixedAngle.ref;
|
|
11489
|
-
const constrainedAngle = (constraints.fixedAngle.angle + GraphUtils.
|
|
11490
|
-
const angle = GraphUtils.
|
|
11467
|
+
const constrainedAngle = (constraints.fixedAngle.angle + GraphUtils.findAngleDeprecated(ref, vertex)) * Math.PI / 180;
|
|
11468
|
+
const angle = GraphUtils.findAngleDeprecated(coord, vertex) * Math.PI / 180;
|
|
11491
11469
|
const distance = GraphUtils.getDistance(coord, vertex);
|
|
11492
11470
|
let length = distance * Math.cos(constrainedAngle - angle);
|
|
11493
11471
|
length = length < 1.0 ? 1.0 : length;
|
|
@@ -11497,7 +11475,7 @@ _.extend(GraphUtils.Graphie.prototype, {
|
|
|
11497
11475
|
// distance is constrained
|
|
11498
11476
|
} else if (typeof constraints.fixedDistance.dist === "number") {
|
|
11499
11477
|
const distPoint = constraints.fixedDistance.point.coord || constraints.fixedDistance.point;
|
|
11500
|
-
let angle = GraphUtils.
|
|
11478
|
+
let angle = GraphUtils.findAngleDeprecated(coord, distPoint);
|
|
11501
11479
|
const length = constraints.fixedDistance.dist;
|
|
11502
11480
|
angle = angle * Math.PI / 180;
|
|
11503
11481
|
newCoord[0] = length * Math.cos(angle) + distPoint[0];
|
|
@@ -13697,7 +13675,7 @@ _.extend(MovableAngle.prototype, {
|
|
|
13697
13675
|
_.each([0, 2], function (i) {
|
|
13698
13676
|
const oldPoint = points[i].coord;
|
|
13699
13677
|
let newPoint = vector$1.add(oldPoint, delta);
|
|
13700
|
-
let angle = GraphUtils.
|
|
13678
|
+
let angle = GraphUtils.findAngleDeprecated(newVertex, newPoint);
|
|
13701
13679
|
angle *= Math.PI / 180;
|
|
13702
13680
|
newPoint = graphie.constrainToBoundsOnAngle(newPoint, 10, angle);
|
|
13703
13681
|
newPoints[i] = newPoint;
|
|
@@ -13730,7 +13708,7 @@ _.extend(MovableAngle.prototype, {
|
|
|
13730
13708
|
return false;
|
|
13731
13709
|
}
|
|
13732
13710
|
if (snap) {
|
|
13733
|
-
let angle = GraphUtils.
|
|
13711
|
+
let angle = GraphUtils.findAngleDeprecated(newPoint, vertex);
|
|
13734
13712
|
angle = Math.round((angle - snapOffset) / snap) * snap + snapOffset;
|
|
13735
13713
|
const distance = GraphUtils.getDistance(newPoint, vertex);
|
|
13736
13714
|
return vector$1.add(vertex, polar$1(distance, angle));
|
|
@@ -13818,7 +13796,7 @@ _.extend(MovableAngle.prototype, {
|
|
|
13818
13796
|
* coords when interpreted in a clockwise direction.
|
|
13819
13797
|
*/
|
|
13820
13798
|
_getClockwiseAngle: function (coords) {
|
|
13821
|
-
const rawAngle = GraphUtils.
|
|
13799
|
+
const rawAngle = GraphUtils.findAngleDeprecated(
|
|
13822
13800
|
// The order of these is "weird" to match what a clockwise
|
|
13823
13801
|
// order is in graphie.labelAngle
|
|
13824
13802
|
coords[2],
|
|
@@ -14642,7 +14620,7 @@ const mapObject$1 = function mapObject(obj, lambda) {
|
|
|
14642
14620
|
* });
|
|
14643
14621
|
* {a: 'aa', b: 'bb'}
|
|
14644
14622
|
*/
|
|
14645
|
-
const mapObjectFromArray
|
|
14623
|
+
const mapObjectFromArray = function mapObjectFromArray(arr, lambda) {
|
|
14646
14624
|
const result = {};
|
|
14647
14625
|
_.each(arr, function (elem) {
|
|
14648
14626
|
result[elem] = lambda(elem);
|
|
@@ -14652,7 +14630,7 @@ const mapObjectFromArray$1 = function mapObjectFromArray(arr, lambda) {
|
|
|
14652
14630
|
var objective_ = {
|
|
14653
14631
|
pluck: pluck,
|
|
14654
14632
|
mapObject: mapObject$1,
|
|
14655
|
-
mapObjectFromArray: mapObjectFromArray
|
|
14633
|
+
mapObjectFromArray: mapObjectFromArray
|
|
14656
14634
|
};
|
|
14657
14635
|
|
|
14658
14636
|
/**
|
|
@@ -18815,169 +18793,6 @@ class QuestionParagraph extends React.Component {
|
|
|
18815
18793
|
}
|
|
18816
18794
|
}
|
|
18817
18795
|
|
|
18818
|
-
/**
|
|
18819
|
-
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
18820
|
-
*
|
|
18821
|
-
* The poentry linter checks for issues that prevent content from being
|
|
18822
|
-
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
18823
|
-
* anything in non-KA environments.
|
|
18824
|
-
*/
|
|
18825
|
-
|
|
18826
|
-
// A LintCB is called once the linter has been run.
|
|
18827
|
-
|
|
18828
|
-
// msec to wait before we actually call the linter after receiving the
|
|
18829
|
-
// last call. The timer is reset if the lint is called during the wait.
|
|
18830
|
-
const DEBOUNCE_TIMEOUT = 1000;
|
|
18831
|
-
class TranslationLinter {
|
|
18832
|
-
constructor() {
|
|
18833
|
-
// To avoid linting when nothing has changed.
|
|
18834
|
-
this.previousContent = null;
|
|
18835
|
-
/**
|
|
18836
|
-
* Runs the poentry linter on the given perseus string asynchronously.
|
|
18837
|
-
*
|
|
18838
|
-
* It doesn't do anything unless we're in a KA environment.
|
|
18839
|
-
*
|
|
18840
|
-
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
18841
|
-
* called if perseusStr is unchanged from the last call.
|
|
18842
|
-
*
|
|
18843
|
-
* Linting is relatively expensive -- so we debounce linting each instance
|
|
18844
|
-
* for some amount of time.
|
|
18845
|
-
*/
|
|
18846
|
-
this.runLinter = debounce$1((perseusStr, onLintErrorsGenerated) => {
|
|
18847
|
-
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
18848
|
-
if (typeof KA === "undefined") {
|
|
18849
|
-
return;
|
|
18850
|
-
}
|
|
18851
|
-
if (perseusStr === this.previousContent) {
|
|
18852
|
-
return;
|
|
18853
|
-
}
|
|
18854
|
-
this.previousContent = perseusStr;
|
|
18855
|
-
if (perseusStr === "") {
|
|
18856
|
-
onLintErrorsGenerated([]);
|
|
18857
|
-
return;
|
|
18858
|
-
}
|
|
18859
|
-
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
18860
|
-
headers: {
|
|
18861
|
-
"Content-Type": "application/json"
|
|
18862
|
-
},
|
|
18863
|
-
body: JSON.stringify({
|
|
18864
|
-
// The poentry linter verifies that the translation from
|
|
18865
|
-
// the original text to the translated text is sane. We
|
|
18866
|
-
// want to ensure that the translation from English to
|
|
18867
|
-
// English is sane, so msgid === mstr.
|
|
18868
|
-
msgid: perseusStr,
|
|
18869
|
-
// msgid is the original text
|
|
18870
|
-
msgstr: perseusStr,
|
|
18871
|
-
// msgstr is the translated text
|
|
18872
|
-
format: "perseus_text",
|
|
18873
|
-
filename: ""
|
|
18874
|
-
}),
|
|
18875
|
-
method: "POST"
|
|
18876
|
-
}).then(response => {
|
|
18877
|
-
if (response.status >= 400) {
|
|
18878
|
-
return {
|
|
18879
|
-
status: "error",
|
|
18880
|
-
message: "Could not run i18n linter."
|
|
18881
|
-
};
|
|
18882
|
-
}
|
|
18883
|
-
return response.json();
|
|
18884
|
-
}, rejection => {
|
|
18885
|
-
return {
|
|
18886
|
-
status: "error",
|
|
18887
|
-
message: "Could not run i18n linter."
|
|
18888
|
-
};
|
|
18889
|
-
}).then(json => {
|
|
18890
|
-
if (json.status === "error") {
|
|
18891
|
-
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
18892
|
-
} else {
|
|
18893
|
-
onLintErrorsGenerated([]);
|
|
18894
|
-
}
|
|
18895
|
-
});
|
|
18896
|
-
}, DEBOUNCE_TIMEOUT);
|
|
18897
|
-
}
|
|
18898
|
-
/**
|
|
18899
|
-
* Applies an array of errors generated by linters without position
|
|
18900
|
-
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
18901
|
-
* top of a Perseus tree.
|
|
18902
|
-
*/
|
|
18903
|
-
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
18904
|
-
// These lint errors do not have position data associated with
|
|
18905
|
-
// them, so we just plop them at the top.
|
|
18906
|
-
if (translationLintErrors.length) {
|
|
18907
|
-
const errorText = translationLintErrors.join("\n\n");
|
|
18908
|
-
parsedMarkdown.unshift({
|
|
18909
|
-
content: {
|
|
18910
|
-
type: "text",
|
|
18911
|
-
content: ""
|
|
18912
|
-
},
|
|
18913
|
-
insideTable: false,
|
|
18914
|
-
message: errorText,
|
|
18915
|
-
ruleName: "legacy-error",
|
|
18916
|
-
severity: Rule.Severity.ERROR,
|
|
18917
|
-
type: "lint"
|
|
18918
|
-
});
|
|
18919
|
-
}
|
|
18920
|
-
}
|
|
18921
|
-
}
|
|
18922
|
-
|
|
18923
|
-
/**
|
|
18924
|
-
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
18925
|
-
* to things is does.
|
|
18926
|
-
*/
|
|
18927
|
-
var preprocessTex = (texCode => texCode
|
|
18928
|
-
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
18929
|
-
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
18930
|
-
// the same is supported by KaTeX. It does the same for align*.
|
|
18931
|
-
// TODO(kevinb) update content to use aligned instead of align.
|
|
18932
|
-
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
18933
|
-
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
18934
|
-
// "aligned").
|
|
18935
|
-
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
18936
|
-
// Replace non-breaking spaces with regular spaces.
|
|
18937
|
-
.replace(/[\u00a0]/g, " "));
|
|
18938
|
-
|
|
18939
|
-
const {
|
|
18940
|
-
interactiveSizes
|
|
18941
|
-
} = constants$1;
|
|
18942
|
-
|
|
18943
|
-
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
18944
|
-
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
18945
|
-
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
18946
|
-
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
18947
|
-
const smMax = articleMaxWidthTableInPx;
|
|
18948
|
-
const mdMax = articleMaxWidthInPx;
|
|
18949
|
-
const containerSizeClass = {
|
|
18950
|
-
SMALL: "small",
|
|
18951
|
-
MEDIUM: "medium",
|
|
18952
|
-
LARGE: "large",
|
|
18953
|
-
XLARGE: "xlarge"
|
|
18954
|
-
};
|
|
18955
|
-
const getClassFromWidth = width => {
|
|
18956
|
-
if (!width) {
|
|
18957
|
-
return containerSizeClass.MEDIUM;
|
|
18958
|
-
}
|
|
18959
|
-
if (width <= smMax) {
|
|
18960
|
-
return containerSizeClass.SMALL;
|
|
18961
|
-
}
|
|
18962
|
-
if (width <= mdMax) {
|
|
18963
|
-
return containerSizeClass.MEDIUM;
|
|
18964
|
-
}
|
|
18965
|
-
return containerSizeClass.LARGE;
|
|
18966
|
-
};
|
|
18967
|
-
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
18968
|
-
if (sizeClass === containerSizeClass.SMALL) {
|
|
18969
|
-
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
18970
|
-
}
|
|
18971
|
-
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
18972
|
-
};
|
|
18973
|
-
|
|
18974
|
-
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
18975
|
-
__proto__: null,
|
|
18976
|
-
containerSizeClass: containerSizeClass,
|
|
18977
|
-
getClassFromWidth: getClassFromWidth,
|
|
18978
|
-
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
18979
|
-
});
|
|
18980
|
-
|
|
18981
18796
|
const DEFAULT_ALIGNMENT$1 = "block";
|
|
18982
18797
|
// NOTE(kevinb): "default" is not one in `validAlignments`.
|
|
18983
18798
|
const DEFAULT_SUPPORTED_ALIGNMENTS = ["default"];
|
|
@@ -19078,6 +18893,10 @@ const getWidget = name => {
|
|
|
19078
18893
|
}
|
|
19079
18894
|
return widgets[name].widget;
|
|
19080
18895
|
};
|
|
18896
|
+
const getWidgetValidator = name => {
|
|
18897
|
+
var _widgets$name$validat, _widgets$name3;
|
|
18898
|
+
return (_widgets$name$validat = (_widgets$name3 = widgets[name]) == null ? void 0 : _widgets$name3.validator) != null ? _widgets$name$validat : null;
|
|
18899
|
+
};
|
|
19081
18900
|
const getEditor = name => {
|
|
19082
18901
|
return _.has(editors, name) ? editors[name] : null;
|
|
19083
18902
|
};
|
|
@@ -19380,6 +19199,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19380
19199
|
replaceEditor: replaceEditor,
|
|
19381
19200
|
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
19382
19201
|
getWidget: getWidget,
|
|
19202
|
+
getWidgetValidator: getWidgetValidator,
|
|
19383
19203
|
getEditor: getEditor,
|
|
19384
19204
|
getTransform: getTransform,
|
|
19385
19205
|
getVersion: getVersion,
|
|
@@ -19399,6 +19219,222 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19399
19219
|
isLintable: isLintable
|
|
19400
19220
|
});
|
|
19401
19221
|
|
|
19222
|
+
function emptyWidgetsFunctional(widgets,
|
|
19223
|
+
// This is a port of old code, I'm not sure why
|
|
19224
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19225
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19226
|
+
return widgetIds.filter(id => {
|
|
19227
|
+
const widget = widgets[id];
|
|
19228
|
+
if (!widget || widget.static) {
|
|
19229
|
+
// Static widgets shouldn't count as empty
|
|
19230
|
+
return false;
|
|
19231
|
+
}
|
|
19232
|
+
let score = null;
|
|
19233
|
+
const userInput = userInputMap[id];
|
|
19234
|
+
const validator = getWidgetValidator(widget.type);
|
|
19235
|
+
if (widget.type === "group") {
|
|
19236
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19237
|
+
score = Util.flattenScores(scores);
|
|
19238
|
+
} else if (validator) {
|
|
19239
|
+
score = validator(userInput, widget.options, strings, locale);
|
|
19240
|
+
}
|
|
19241
|
+
if (score) {
|
|
19242
|
+
return Util.scoreIsEmpty(score);
|
|
19243
|
+
}
|
|
19244
|
+
});
|
|
19245
|
+
}
|
|
19246
|
+
function scoreWidgetsFunctional(widgets,
|
|
19247
|
+
// This is a port of old code, I'm not sure why
|
|
19248
|
+
// we need widgetIds vs the keys of the widgets object
|
|
19249
|
+
widgetIds, userInputMap, strings, locale) {
|
|
19250
|
+
const gradedWidgetIds = widgetIds.filter(id => {
|
|
19251
|
+
const props = widgets[id];
|
|
19252
|
+
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
19253
|
+
const widgetIsStatic = !!(props != null && props.static);
|
|
19254
|
+
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
19255
|
+
return widgetIsGraded && !widgetIsStatic;
|
|
19256
|
+
});
|
|
19257
|
+
const widgetScores = {};
|
|
19258
|
+
gradedWidgetIds.forEach(id => {
|
|
19259
|
+
const widget = widgets[id];
|
|
19260
|
+
if (!widget) {
|
|
19261
|
+
return;
|
|
19262
|
+
}
|
|
19263
|
+
const userInput = userInputMap[id];
|
|
19264
|
+
const validator = getWidgetValidator(widget.type);
|
|
19265
|
+
if (widget.type === "group") {
|
|
19266
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, Object.keys(widget.options.widgets), userInputMap[id], strings, locale);
|
|
19267
|
+
widgetScores[id] = Util.flattenScores(scores);
|
|
19268
|
+
} else if (validator) {
|
|
19269
|
+
widgetScores[id] = validator(userInput, widget.options, strings, locale);
|
|
19270
|
+
}
|
|
19271
|
+
});
|
|
19272
|
+
return widgetScores;
|
|
19273
|
+
}
|
|
19274
|
+
|
|
19275
|
+
/**
|
|
19276
|
+
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
19277
|
+
*
|
|
19278
|
+
* The poentry linter checks for issues that prevent content from being
|
|
19279
|
+
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
19280
|
+
* anything in non-KA environments.
|
|
19281
|
+
*/
|
|
19282
|
+
|
|
19283
|
+
// A LintCB is called once the linter has been run.
|
|
19284
|
+
|
|
19285
|
+
// msec to wait before we actually call the linter after receiving the
|
|
19286
|
+
// last call. The timer is reset if the lint is called during the wait.
|
|
19287
|
+
const DEBOUNCE_TIMEOUT = 1000;
|
|
19288
|
+
class TranslationLinter {
|
|
19289
|
+
constructor() {
|
|
19290
|
+
// To avoid linting when nothing has changed.
|
|
19291
|
+
this.previousContent = null;
|
|
19292
|
+
/**
|
|
19293
|
+
* Runs the poentry linter on the given perseus string asynchronously.
|
|
19294
|
+
*
|
|
19295
|
+
* It doesn't do anything unless we're in a KA environment.
|
|
19296
|
+
*
|
|
19297
|
+
* onLintErrorsGenerated is called even if there are no errors. It is not
|
|
19298
|
+
* called if perseusStr is unchanged from the last call.
|
|
19299
|
+
*
|
|
19300
|
+
* Linting is relatively expensive -- so we debounce linting each instance
|
|
19301
|
+
* for some amount of time.
|
|
19302
|
+
*/
|
|
19303
|
+
this.runLinter = debounce$1((perseusStr, onLintErrorsGenerated) => {
|
|
19304
|
+
// TODO(FEI-5003): Do we still need to check for 'KA'?
|
|
19305
|
+
if (typeof KA === "undefined") {
|
|
19306
|
+
return;
|
|
19307
|
+
}
|
|
19308
|
+
if (perseusStr === this.previousContent) {
|
|
19309
|
+
return;
|
|
19310
|
+
}
|
|
19311
|
+
this.previousContent = perseusStr;
|
|
19312
|
+
if (perseusStr === "") {
|
|
19313
|
+
onLintErrorsGenerated([]);
|
|
19314
|
+
return;
|
|
19315
|
+
}
|
|
19316
|
+
fetch("/api/internal/translations/lint_poentry?preview=1&lang=en", {
|
|
19317
|
+
headers: {
|
|
19318
|
+
"Content-Type": "application/json"
|
|
19319
|
+
},
|
|
19320
|
+
body: JSON.stringify({
|
|
19321
|
+
// The poentry linter verifies that the translation from
|
|
19322
|
+
// the original text to the translated text is sane. We
|
|
19323
|
+
// want to ensure that the translation from English to
|
|
19324
|
+
// English is sane, so msgid === mstr.
|
|
19325
|
+
msgid: perseusStr,
|
|
19326
|
+
// msgid is the original text
|
|
19327
|
+
msgstr: perseusStr,
|
|
19328
|
+
// msgstr is the translated text
|
|
19329
|
+
format: "perseus_text",
|
|
19330
|
+
filename: ""
|
|
19331
|
+
}),
|
|
19332
|
+
method: "POST"
|
|
19333
|
+
}).then(response => {
|
|
19334
|
+
if (response.status >= 400) {
|
|
19335
|
+
return {
|
|
19336
|
+
status: "error",
|
|
19337
|
+
message: "Could not run i18n linter."
|
|
19338
|
+
};
|
|
19339
|
+
}
|
|
19340
|
+
return response.json();
|
|
19341
|
+
}, rejection => {
|
|
19342
|
+
return {
|
|
19343
|
+
status: "error",
|
|
19344
|
+
message: "Could not run i18n linter."
|
|
19345
|
+
};
|
|
19346
|
+
}).then(json => {
|
|
19347
|
+
if (json.status === "error") {
|
|
19348
|
+
onLintErrorsGenerated(["Some part of this text makes it untranslatable. " + "The specific message from the i18n linter was: " + json.message.replace(/\n/g, " ")]);
|
|
19349
|
+
} else {
|
|
19350
|
+
onLintErrorsGenerated([]);
|
|
19351
|
+
}
|
|
19352
|
+
});
|
|
19353
|
+
}, DEBOUNCE_TIMEOUT);
|
|
19354
|
+
}
|
|
19355
|
+
/**
|
|
19356
|
+
* Applies an array of errors generated by linters without position
|
|
19357
|
+
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
19358
|
+
* top of a Perseus tree.
|
|
19359
|
+
*/
|
|
19360
|
+
applyLintErrors(parsedMarkdown, translationLintErrors) {
|
|
19361
|
+
// These lint errors do not have position data associated with
|
|
19362
|
+
// them, so we just plop them at the top.
|
|
19363
|
+
if (translationLintErrors.length) {
|
|
19364
|
+
const errorText = translationLintErrors.join("\n\n");
|
|
19365
|
+
parsedMarkdown.unshift({
|
|
19366
|
+
content: {
|
|
19367
|
+
type: "text",
|
|
19368
|
+
content: ""
|
|
19369
|
+
},
|
|
19370
|
+
insideTable: false,
|
|
19371
|
+
message: errorText,
|
|
19372
|
+
ruleName: "legacy-error",
|
|
19373
|
+
severity: Rule.Severity.ERROR,
|
|
19374
|
+
type: "lint"
|
|
19375
|
+
});
|
|
19376
|
+
}
|
|
19377
|
+
}
|
|
19378
|
+
}
|
|
19379
|
+
|
|
19380
|
+
/**
|
|
19381
|
+
* Preprocess TeX code to convert things that MathJax doesn't know how to handle
|
|
19382
|
+
* to things is does.
|
|
19383
|
+
*/
|
|
19384
|
+
var preprocessTex = (texCode => texCode
|
|
19385
|
+
// Replace uses of \begin{align}...\end{align} which KaTeX doesn't
|
|
19386
|
+
// support (yet) with \begin{aligned}...\end{aligned} which renders
|
|
19387
|
+
// the same is supported by KaTeX. It does the same for align*.
|
|
19388
|
+
// TODO(kevinb) update content to use aligned instead of align.
|
|
19389
|
+
// TODO(LEMS-1608) Remove this replacement as MathJax supports the
|
|
19390
|
+
// "align" macro correctly (and, in fact, it is not synonymous with
|
|
19391
|
+
// "aligned").
|
|
19392
|
+
.replace(/\{align[*]?\}/g, "{aligned}")
|
|
19393
|
+
// Replace non-breaking spaces with regular spaces.
|
|
19394
|
+
.replace(/[\u00a0]/g, " "));
|
|
19395
|
+
|
|
19396
|
+
const {
|
|
19397
|
+
interactiveSizes
|
|
19398
|
+
} = constants$1;
|
|
19399
|
+
|
|
19400
|
+
// Note: these size cutoffs represent content-width cutoffs as specified in
|
|
19401
|
+
// http://zpl.io/1mVmvU (broken link - we no longer use Zeplin)
|
|
19402
|
+
// TODO(benkomalo): these values aren't used in JS outside of this file, but
|
|
19403
|
+
// are coupled to the values in styles/styles.less - DRY it up at some point
|
|
19404
|
+
const smMax = articleMaxWidthTableInPx;
|
|
19405
|
+
const mdMax = articleMaxWidthInPx;
|
|
19406
|
+
const containerSizeClass = {
|
|
19407
|
+
SMALL: "small",
|
|
19408
|
+
MEDIUM: "medium",
|
|
19409
|
+
LARGE: "large",
|
|
19410
|
+
XLARGE: "xlarge"
|
|
19411
|
+
};
|
|
19412
|
+
const getClassFromWidth = width => {
|
|
19413
|
+
if (!width) {
|
|
19414
|
+
return containerSizeClass.MEDIUM;
|
|
19415
|
+
}
|
|
19416
|
+
if (width <= smMax) {
|
|
19417
|
+
return containerSizeClass.SMALL;
|
|
19418
|
+
}
|
|
19419
|
+
if (width <= mdMax) {
|
|
19420
|
+
return containerSizeClass.MEDIUM;
|
|
19421
|
+
}
|
|
19422
|
+
return containerSizeClass.LARGE;
|
|
19423
|
+
};
|
|
19424
|
+
const getInteractiveBoxFromSizeClass = sizeClass => {
|
|
19425
|
+
if (sizeClass === containerSizeClass.SMALL) {
|
|
19426
|
+
return [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall];
|
|
19427
|
+
}
|
|
19428
|
+
return [interactiveSizes.defaultBoxSize, interactiveSizes.defaultBoxSize];
|
|
19429
|
+
};
|
|
19430
|
+
|
|
19431
|
+
var sizingUtils = /*#__PURE__*/Object.freeze({
|
|
19432
|
+
__proto__: null,
|
|
19433
|
+
containerSizeClass: containerSizeClass,
|
|
19434
|
+
getClassFromWidth: getClassFromWidth,
|
|
19435
|
+
getInteractiveBoxFromSizeClass: getInteractiveBoxFromSizeClass
|
|
19436
|
+
});
|
|
19437
|
+
|
|
19402
19438
|
class WidgetContainer extends React.Component {
|
|
19403
19439
|
constructor(...args) {
|
|
19404
19440
|
super(...args);
|
|
@@ -19544,8 +19580,7 @@ WidgetContainer.defaultProps = {
|
|
|
19544
19580
|
};
|
|
19545
19581
|
|
|
19546
19582
|
const {
|
|
19547
|
-
mapObject
|
|
19548
|
-
mapObjectFromArray
|
|
19583
|
+
mapObject
|
|
19549
19584
|
} = objective_;
|
|
19550
19585
|
const rContainsNonWhitespace = /\S/;
|
|
19551
19586
|
const rImageURL = /(web\+graphie|https):\/\/[^\s]*/;
|
|
@@ -19710,11 +19745,7 @@ class Renderer extends React.Component {
|
|
|
19710
19745
|
}
|
|
19711
19746
|
let interactionTracker = this._interactionTrackers[id];
|
|
19712
19747
|
if (!interactionTracker) {
|
|
19713
|
-
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction,
|
|
19714
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
19715
|
-
widgetInfo && widgetInfo.type, id,
|
|
19716
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
|
|
19717
|
-
getTracking(widgetInfo && widgetInfo.type));
|
|
19748
|
+
interactionTracker = this._interactionTrackers[id] = new InteractionTracker(apiOptions.trackInteraction, widgetInfo && widgetInfo.type, id, getTracking(widgetInfo && widgetInfo.type));
|
|
19718
19749
|
}
|
|
19719
19750
|
return _extends({}, widgetProps, {
|
|
19720
19751
|
widgetId: id,
|
|
@@ -20492,23 +20523,6 @@ class Renderer extends React.Component {
|
|
|
20492
20523
|
}, this);
|
|
20493
20524
|
return state;
|
|
20494
20525
|
};
|
|
20495
|
-
this.emptyWidgets = () => {
|
|
20496
|
-
// @ts-expect-error - TS2345 - Argument of type '(id: string) => boolean | undefined' is not assignable to parameter of type 'Iteratee<string[], boolean, string>'.
|
|
20497
|
-
return _.filter(this.widgetIds, id => {
|
|
20498
|
-
const widgetInfo = this._getWidgetInfo(id);
|
|
20499
|
-
if (widgetInfo.static) {
|
|
20500
|
-
// Static widgets shouldn't count as empty
|
|
20501
|
-
return false;
|
|
20502
|
-
}
|
|
20503
|
-
const widget = this.getWidgetInstance(id);
|
|
20504
|
-
if (widget && widget.simpleValidate) {
|
|
20505
|
-
const score = widget.simpleValidate(widgetInfo.options,
|
|
20506
|
-
// @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'.
|
|
20507
|
-
null);
|
|
20508
|
-
return Util.scoreIsEmpty(score);
|
|
20509
|
-
}
|
|
20510
|
-
});
|
|
20511
|
-
};
|
|
20512
20526
|
this._setWidgetProps = (id, newProps, cb, silent) => {
|
|
20513
20527
|
this.setState(prevState => {
|
|
20514
20528
|
const widgetProps = _extends({}, prevState.widgetProps, {
|
|
@@ -20565,19 +20579,6 @@ class Renderer extends React.Component {
|
|
|
20565
20579
|
// Widget handles parsing of the interWidgetPath.
|
|
20566
20580
|
widget == null || widget.setInputValue == null || widget.setInputValue(interWidgetPath, newValue, focus);
|
|
20567
20581
|
};
|
|
20568
|
-
/**
|
|
20569
|
-
* Returns an array of the widget `.getUserInput()` results
|
|
20570
|
-
*/
|
|
20571
|
-
this.getUserInput = () => {
|
|
20572
|
-
return this.widgetIds.map(id => {
|
|
20573
|
-
const widget = this.getWidgetInstance(id);
|
|
20574
|
-
if (widget && widget.getUserInput) {
|
|
20575
|
-
// TODO(Jeremy): Add the widget ID in here so we can more
|
|
20576
|
-
// easily correlate it to the widget state.
|
|
20577
|
-
return widget.getUserInput();
|
|
20578
|
-
}
|
|
20579
|
-
});
|
|
20580
|
-
};
|
|
20581
20582
|
/**
|
|
20582
20583
|
* Returns an array of all widget IDs in the order they occur in
|
|
20583
20584
|
* the content.
|
|
@@ -20585,56 +20586,6 @@ class Renderer extends React.Component {
|
|
|
20585
20586
|
this.getWidgetIds = () => {
|
|
20586
20587
|
return this.widgetIds;
|
|
20587
20588
|
};
|
|
20588
|
-
/**
|
|
20589
|
-
* Returns the result of `.getUserInput()` for each widget, in
|
|
20590
|
-
* a map from widgetId to userInput.
|
|
20591
|
-
* NOTE(jeremy): This function is hauntingly similar to `getUserInput` with
|
|
20592
|
-
* the major difference being that this function returns a map of
|
|
20593
|
-
* `widgetID` => UserInput and `getUserInput` simply returns an array. It
|
|
20594
|
-
* would be trivial to map between the results of each of these functions,
|
|
20595
|
-
* so we should aim to remove one of these functions.
|
|
20596
|
-
*/
|
|
20597
|
-
this.getUserInputForWidgets = () => {
|
|
20598
|
-
return mapObjectFromArray(this.widgetIds, id => {
|
|
20599
|
-
const widget = this.getWidgetInstance(id);
|
|
20600
|
-
if (widget && widget.getUserInput) {
|
|
20601
|
-
return widget.getUserInput();
|
|
20602
|
-
}
|
|
20603
|
-
});
|
|
20604
|
-
};
|
|
20605
|
-
/**
|
|
20606
|
-
* Returns an object mapping from widget ID to perseus-style score.
|
|
20607
|
-
* The keys of this object are the values of the array returned
|
|
20608
|
-
* from `getWidgetIds`.
|
|
20609
|
-
*/
|
|
20610
|
-
this.scoreWidgets = () => {
|
|
20611
|
-
const widgetProps = this.state.widgetInfo;
|
|
20612
|
-
const gradedWidgetIds = _.filter(this.widgetIds, id => {
|
|
20613
|
-
const props = widgetProps[id];
|
|
20614
|
-
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
20615
|
-
const widgetIsStatic = !!(props != null && props.static);
|
|
20616
|
-
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
20617
|
-
return widgetIsGraded && !widgetIsStatic;
|
|
20618
|
-
});
|
|
20619
|
-
const widgetScores = {};
|
|
20620
|
-
_.each(gradedWidgetIds, id => {
|
|
20621
|
-
const props = widgetProps[id];
|
|
20622
|
-
const widget = this.getWidgetInstance(id);
|
|
20623
|
-
// widget can be undefined if it hasn't yet been rendered
|
|
20624
|
-
if (widget && widget.simpleValidate) {
|
|
20625
|
-
widgetScores[id] = widget.simpleValidate(_extends({}, props == null ? void 0 : props.options, {
|
|
20626
|
-
scoring: true
|
|
20627
|
-
}));
|
|
20628
|
-
}
|
|
20629
|
-
});
|
|
20630
|
-
return widgetScores;
|
|
20631
|
-
};
|
|
20632
|
-
/**
|
|
20633
|
-
* Grades the content.
|
|
20634
|
-
*/
|
|
20635
|
-
this.score = () => {
|
|
20636
|
-
return _.reduce(this.scoreWidgets(), Util.combineScores, Util.noScore);
|
|
20637
|
-
};
|
|
20638
20589
|
this.guessAndScore = () => {
|
|
20639
20590
|
const totalGuess = this.getUserInput();
|
|
20640
20591
|
const totalScore = this.score();
|
|
@@ -20808,6 +20759,59 @@ class Renderer extends React.Component {
|
|
|
20808
20759
|
}
|
|
20809
20760
|
this._isMounted = false;
|
|
20810
20761
|
}
|
|
20762
|
+
emptyWidgets() {
|
|
20763
|
+
return emptyWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20764
|
+
}
|
|
20765
|
+
/**
|
|
20766
|
+
* Returns an array of the widget `.getUserInput()` results
|
|
20767
|
+
*
|
|
20768
|
+
* TODO: can we remove this?
|
|
20769
|
+
* @deprecated use getUserInputMap
|
|
20770
|
+
*/
|
|
20771
|
+
getUserInput() {
|
|
20772
|
+
return this.widgetIds.map(id => {
|
|
20773
|
+
const widget = this.getWidgetInstance(id);
|
|
20774
|
+
if (widget && widget.getUserInput) {
|
|
20775
|
+
// TODO(Jeremy): Add the widget ID in here so we can more
|
|
20776
|
+
// easily correlate it to the widget state.
|
|
20777
|
+
return widget.getUserInput();
|
|
20778
|
+
}
|
|
20779
|
+
});
|
|
20780
|
+
}
|
|
20781
|
+
|
|
20782
|
+
/**
|
|
20783
|
+
* Returns an object of the widget `.getUserInput()` results
|
|
20784
|
+
*/
|
|
20785
|
+
getUserInputMap() {
|
|
20786
|
+
const userInputMap = {};
|
|
20787
|
+
this.widgetIds.forEach(id => {
|
|
20788
|
+
const widget = this.getWidgetInstance(id);
|
|
20789
|
+
// Handle Groups, which have their own sets of widgets
|
|
20790
|
+
if (widget != null && widget.getUserInputMap) {
|
|
20791
|
+
userInputMap[id] = widget.getUserInputMap();
|
|
20792
|
+
} else if (widget != null && widget.getUserInput) {
|
|
20793
|
+
userInputMap[id] = widget.getUserInput();
|
|
20794
|
+
}
|
|
20795
|
+
});
|
|
20796
|
+
return userInputMap;
|
|
20797
|
+
}
|
|
20798
|
+
/**
|
|
20799
|
+
* Returns an object mapping from widget ID to perseus-style score.
|
|
20800
|
+
* The keys of this object are the values of the array returned
|
|
20801
|
+
* from `getWidgetIds`.
|
|
20802
|
+
*/
|
|
20803
|
+
scoreWidgets() {
|
|
20804
|
+
return scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20805
|
+
}
|
|
20806
|
+
|
|
20807
|
+
/**
|
|
20808
|
+
* Grades the content.
|
|
20809
|
+
*/
|
|
20810
|
+
score() {
|
|
20811
|
+
const scores = this.scoreWidgets();
|
|
20812
|
+
const combinedScore = Util.flattenScores(scores);
|
|
20813
|
+
return combinedScore;
|
|
20814
|
+
}
|
|
20811
20815
|
render() {
|
|
20812
20816
|
const apiOptions = this.getApiOptions();
|
|
20813
20817
|
if (this.reuseMarkdown) {
|
|
@@ -20882,11 +20886,11 @@ class Renderer extends React.Component {
|
|
|
20882
20886
|
// If highlightLint is true and lint is detected, this call
|
|
20883
20887
|
// will modify the parse tree by adding lint nodes that will
|
|
20884
20888
|
// serve to highlight the lint when rendered
|
|
20885
|
-
const
|
|
20889
|
+
const fullLinterContext = _extends({
|
|
20886
20890
|
content: this.props.content,
|
|
20887
20891
|
widgets: this.props.widgets
|
|
20888
20892
|
}, this.props.linterContext);
|
|
20889
|
-
PerseusLinter.runLinter(parsedMarkdown,
|
|
20893
|
+
PerseusLinter.runLinter(parsedMarkdown, fullLinterContext, true);
|
|
20890
20894
|
|
|
20891
20895
|
// Apply the lint errors from the last TranslationLinter run.
|
|
20892
20896
|
// TODO(joshuan): Support overlapping dots.
|
|
@@ -20908,6 +20912,7 @@ class Renderer extends React.Component {
|
|
|
20908
20912
|
return this.lastRenderedMarkdown;
|
|
20909
20913
|
}
|
|
20910
20914
|
}
|
|
20915
|
+
Renderer.contextType = PerseusI18nContext;
|
|
20911
20916
|
Renderer.defaultProps = {
|
|
20912
20917
|
content: "",
|
|
20913
20918
|
widgets: {},
|
|
@@ -21395,6 +21400,16 @@ InputWithExamples.defaultProps = {
|
|
|
21395
21400
|
className: ""
|
|
21396
21401
|
};
|
|
21397
21402
|
|
|
21403
|
+
function _objectWithoutPropertiesLoose(r, e) {
|
|
21404
|
+
if (null == r) return {};
|
|
21405
|
+
var t = {};
|
|
21406
|
+
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
21407
|
+
if (e.includes(n)) continue;
|
|
21408
|
+
t[n] = r[n];
|
|
21409
|
+
}
|
|
21410
|
+
return t;
|
|
21411
|
+
}
|
|
21412
|
+
|
|
21398
21413
|
const _excluded$4 = ["keypadElement", "onFocus", "value"];
|
|
21399
21414
|
class SimpleKeypadInput extends React.Component {
|
|
21400
21415
|
constructor(...args) {
|
|
@@ -21797,9 +21812,6 @@ class InputNumber extends React.Component {
|
|
|
21797
21812
|
return [strings.yourAnswer].concat(examples);
|
|
21798
21813
|
};
|
|
21799
21814
|
}
|
|
21800
|
-
static validate(state, rubric, strings) {
|
|
21801
|
-
return inputNumberValidator(state, rubric, strings);
|
|
21802
|
-
}
|
|
21803
21815
|
static getUserInputFromProps(props) {
|
|
21804
21816
|
return {
|
|
21805
21817
|
currentValue: props.currentValue
|
|
@@ -21818,9 +21830,6 @@ class InputNumber extends React.Component {
|
|
|
21818
21830
|
getUserInput() {
|
|
21819
21831
|
return InputNumber.getUserInputFromProps(this.props);
|
|
21820
21832
|
}
|
|
21821
|
-
simpleValidate(rubric) {
|
|
21822
|
-
return inputNumberValidator(this.getUserInput(), rubric, this.context.strings);
|
|
21823
|
-
}
|
|
21824
21833
|
render() {
|
|
21825
21834
|
if (this.props.apiOptions.customKeypad) {
|
|
21826
21835
|
// TODO(charlie): Support "Review Mode".
|
|
@@ -21925,7 +21934,8 @@ var InputNumber$1 = {
|
|
|
21925
21934
|
hidden: true,
|
|
21926
21935
|
widget: InputNumber,
|
|
21927
21936
|
transform: propTransform$3,
|
|
21928
|
-
isLintable: true
|
|
21937
|
+
isLintable: true,
|
|
21938
|
+
validator: inputNumberValidator
|
|
21929
21939
|
};
|
|
21930
21940
|
|
|
21931
21941
|
const ParseTex = TexWrangler.parseTex;
|
|
@@ -22199,12 +22209,6 @@ class NumericInput extends React.Component {
|
|
|
22199
22209
|
}
|
|
22200
22210
|
return answerStrings[0];
|
|
22201
22211
|
}
|
|
22202
|
-
static validate(userInput, rubric, strings) {
|
|
22203
|
-
return numericInputValidator(userInput, rubric, strings);
|
|
22204
|
-
}
|
|
22205
|
-
simpleValidate(rubric) {
|
|
22206
|
-
return numericInputValidator(this.getUserInput(), rubric, this.context.strings);
|
|
22207
|
-
}
|
|
22208
22212
|
getUserInput() {
|
|
22209
22213
|
return NumericInput.getUserInputFromProps(this.props);
|
|
22210
22214
|
}
|
|
@@ -22331,7 +22335,8 @@ var NumericInput$1 = {
|
|
|
22331
22335
|
accessible: true,
|
|
22332
22336
|
widget: NumericInput,
|
|
22333
22337
|
transform: propsTransform,
|
|
22334
|
-
isLintable: true
|
|
22338
|
+
isLintable: true,
|
|
22339
|
+
validator: numericInputValidator
|
|
22335
22340
|
};
|
|
22336
22341
|
|
|
22337
22342
|
/**
|
|
@@ -24139,6 +24144,9 @@ class Passage extends React.Component {
|
|
|
24139
24144
|
this._onResize = void 0;
|
|
24140
24145
|
// @ts-expect-error - TS2564 - Property '_stylesAppiedTimer' has no initializer and is not definitely assigned in the constructor.
|
|
24141
24146
|
this._stylesAppiedTimer = void 0;
|
|
24147
|
+
// this just helps with TS weak typing when a Widget
|
|
24148
|
+
// doesn't implement any Widget methods
|
|
24149
|
+
this.isWidget = true;
|
|
24142
24150
|
this.state = {
|
|
24143
24151
|
nLines: null,
|
|
24144
24152
|
startLineNumbersAfter: 0,
|
|
@@ -24150,10 +24158,6 @@ class Passage extends React.Component {
|
|
|
24150
24158
|
});
|
|
24151
24159
|
};
|
|
24152
24160
|
}
|
|
24153
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24154
|
-
static validate() {
|
|
24155
|
-
return noopValidator();
|
|
24156
|
-
}
|
|
24157
24161
|
componentDidMount() {
|
|
24158
24162
|
this._updateState();
|
|
24159
24163
|
|
|
@@ -24358,21 +24362,6 @@ class Passage extends React.Component {
|
|
|
24358
24362
|
};
|
|
24359
24363
|
}
|
|
24360
24364
|
|
|
24361
|
-
/**
|
|
24362
|
-
* Misc functions
|
|
24363
|
-
*
|
|
24364
|
-
* These are misc widget functions used for the widget API
|
|
24365
|
-
*/
|
|
24366
|
-
|
|
24367
|
-
getUserInput() {
|
|
24368
|
-
return null;
|
|
24369
|
-
}
|
|
24370
|
-
|
|
24371
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24372
|
-
simpleValidate() {
|
|
24373
|
-
return noopValidator();
|
|
24374
|
-
}
|
|
24375
|
-
|
|
24376
24365
|
/**
|
|
24377
24366
|
* Rendering
|
|
24378
24367
|
*
|
|
@@ -24525,7 +24514,8 @@ var Passage$1 = {
|
|
|
24525
24514
|
transform: editorProps => {
|
|
24526
24515
|
return _.pick(editorProps, "passageTitle", "passageText", "footnotes", "showLineNumbers");
|
|
24527
24516
|
},
|
|
24528
|
-
isLintable: true
|
|
24517
|
+
isLintable: true,
|
|
24518
|
+
validator: () => noopValidator()
|
|
24529
24519
|
};
|
|
24530
24520
|
|
|
24531
24521
|
/**
|
|
@@ -24551,6 +24541,9 @@ class PassageRef extends React.Component {
|
|
|
24551
24541
|
this._isMounted = void 0;
|
|
24552
24542
|
// @ts-expect-error - TS2564 - Property '_throttledUpdateRange' has no initializer and is not definitely assigned in the constructor.
|
|
24553
24543
|
this._throttledUpdateRange = void 0;
|
|
24544
|
+
// this just helps with TS weak typing when a Widget
|
|
24545
|
+
// doesn't implement any Widget methods
|
|
24546
|
+
this.isWidget = true;
|
|
24554
24547
|
this.state = {
|
|
24555
24548
|
lineRange: null,
|
|
24556
24549
|
content: null
|
|
@@ -24579,10 +24572,6 @@ class PassageRef extends React.Component {
|
|
|
24579
24572
|
}
|
|
24580
24573
|
};
|
|
24581
24574
|
}
|
|
24582
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24583
|
-
static validate() {
|
|
24584
|
-
return noopValidator();
|
|
24585
|
-
}
|
|
24586
24575
|
componentDidMount() {
|
|
24587
24576
|
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
24588
24577
|
// this.isMounted() but is still considered an anti-pattern.
|
|
@@ -24601,15 +24590,6 @@ class PassageRef extends React.Component {
|
|
|
24601
24590
|
window.removeEventListener("resize", this._throttledUpdateRange);
|
|
24602
24591
|
this._isMounted = false;
|
|
24603
24592
|
}
|
|
24604
|
-
|
|
24605
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24606
|
-
getUserInput() {
|
|
24607
|
-
return null;
|
|
24608
|
-
}
|
|
24609
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
24610
|
-
simpleValidate() {
|
|
24611
|
-
return noopValidator();
|
|
24612
|
-
}
|
|
24613
24593
|
render() {
|
|
24614
24594
|
const {
|
|
24615
24595
|
strings
|
|
@@ -24664,7 +24644,9 @@ var PassageRef$1 = {
|
|
|
24664
24644
|
version: {
|
|
24665
24645
|
major: 0,
|
|
24666
24646
|
minor: 1
|
|
24667
|
-
}
|
|
24647
|
+
},
|
|
24648
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
24649
|
+
validator: () => noopValidator()
|
|
24668
24650
|
};
|
|
24669
24651
|
|
|
24670
24652
|
/**
|
|
@@ -26166,7 +26148,7 @@ class Radio$1 extends React.Component {
|
|
|
26166
26148
|
choiceStates
|
|
26167
26149
|
} = this.props;
|
|
26168
26150
|
if (choiceStates) {
|
|
26169
|
-
const score = this.
|
|
26151
|
+
const score = radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26170
26152
|
const widgetCorrect = score.type === "points" && score.total === score.earned;
|
|
26171
26153
|
const newStates = choiceStates.map(state => _extends({}, state, {
|
|
26172
26154
|
highlighted: state.selected,
|
|
@@ -26214,9 +26196,6 @@ class Radio$1 extends React.Component {
|
|
|
26214
26196
|
}
|
|
26215
26197
|
};
|
|
26216
26198
|
}
|
|
26217
|
-
static validate(userInput, rubric, strings) {
|
|
26218
|
-
return radioValidator(userInput, rubric, strings);
|
|
26219
|
-
}
|
|
26220
26199
|
static getUserInputFromProps(props) {
|
|
26221
26200
|
// Return checked inputs in the form {choicesSelected: [bool]}. (Dear
|
|
26222
26201
|
// future timeline implementers: this used to be {value: i} before
|
|
@@ -26307,9 +26286,6 @@ class Radio$1 extends React.Component {
|
|
|
26307
26286
|
getUserInput() {
|
|
26308
26287
|
return Radio$1.getUserInputFromProps(this.props);
|
|
26309
26288
|
}
|
|
26310
|
-
simpleValidate(rubric) {
|
|
26311
|
-
return radioValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26312
|
-
}
|
|
26313
26289
|
render() {
|
|
26314
26290
|
const {
|
|
26315
26291
|
choices
|
|
@@ -26544,7 +26520,8 @@ var Radio = {
|
|
|
26544
26520
|
minor: 0
|
|
26545
26521
|
},
|
|
26546
26522
|
propUpgrades: propUpgrades$1,
|
|
26547
|
-
isLintable: true
|
|
26523
|
+
isLintable: true,
|
|
26524
|
+
validator: radioValidator
|
|
26548
26525
|
};
|
|
26549
26526
|
|
|
26550
26527
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -26587,9 +26564,6 @@ class Categorizer extends React.Component {
|
|
|
26587
26564
|
return change.apply(this, args);
|
|
26588
26565
|
};
|
|
26589
26566
|
}
|
|
26590
|
-
static validate(userInput, rubric, strings) {
|
|
26591
|
-
return categorizerValidator(userInput, rubric, strings);
|
|
26592
|
-
}
|
|
26593
26567
|
static getUserInputFromProps(props) {
|
|
26594
26568
|
return {
|
|
26595
26569
|
values: props.values
|
|
@@ -26605,9 +26579,6 @@ class Categorizer extends React.Component {
|
|
|
26605
26579
|
this.change("values", values);
|
|
26606
26580
|
this.props.trackInteraction();
|
|
26607
26581
|
}
|
|
26608
|
-
simpleValidate(rubric) {
|
|
26609
|
-
return categorizerValidator(this.getUserInput(), rubric, this.context.strings);
|
|
26610
|
-
}
|
|
26611
26582
|
render() {
|
|
26612
26583
|
const self = this;
|
|
26613
26584
|
|
|
@@ -26753,7 +26724,8 @@ var Categorizer$1 = {
|
|
|
26753
26724
|
staticTransform: editorProps => {
|
|
26754
26725
|
return _.pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
26755
26726
|
},
|
|
26756
|
-
isLintable: true
|
|
26727
|
+
isLintable: true,
|
|
26728
|
+
validator: categorizerValidator
|
|
26757
26729
|
};
|
|
26758
26730
|
|
|
26759
26731
|
/**
|
|
@@ -26877,10 +26849,6 @@ class CSProgram extends React.Component {
|
|
|
26877
26849
|
return change.apply(this, args);
|
|
26878
26850
|
};
|
|
26879
26851
|
}
|
|
26880
|
-
// The widget's grading function
|
|
26881
|
-
static validate(state) {
|
|
26882
|
-
return csProgramValidator(state);
|
|
26883
|
-
}
|
|
26884
26852
|
componentDidMount() {
|
|
26885
26853
|
$(window).on("message", this.handleMessageEvent);
|
|
26886
26854
|
}
|
|
@@ -26893,9 +26861,6 @@ class CSProgram extends React.Component {
|
|
|
26893
26861
|
message: this.props.message
|
|
26894
26862
|
};
|
|
26895
26863
|
}
|
|
26896
|
-
simpleValidate() {
|
|
26897
|
-
return csProgramValidator(this.getUserInput());
|
|
26898
|
-
}
|
|
26899
26864
|
render() {
|
|
26900
26865
|
if (!this.props.programID) {
|
|
26901
26866
|
return /*#__PURE__*/React.createElement("div", null);
|
|
@@ -26977,21 +26942,16 @@ var CSProgram$1 = {
|
|
|
26977
26942
|
displayName: "CS Program",
|
|
26978
26943
|
supportedAlignments: ["block", "full-width"],
|
|
26979
26944
|
widget: CSProgram,
|
|
26980
|
-
hidden: true
|
|
26945
|
+
hidden: true,
|
|
26946
|
+
validator: csProgramValidator
|
|
26981
26947
|
};
|
|
26982
26948
|
|
|
26983
26949
|
class Definition extends React.Component {
|
|
26984
|
-
|
|
26985
|
-
|
|
26986
|
-
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
return {};
|
|
26990
|
-
}
|
|
26991
|
-
|
|
26992
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
26993
|
-
simpleValidate() {
|
|
26994
|
-
return noopValidator();
|
|
26950
|
+
constructor(...args) {
|
|
26951
|
+
super(...args);
|
|
26952
|
+
// this just helps with TS weak typing when a Widget
|
|
26953
|
+
// doesn't implement any Widget methods
|
|
26954
|
+
this.isWidget = true;
|
|
26995
26955
|
}
|
|
26996
26956
|
render() {
|
|
26997
26957
|
return /*#__PURE__*/React.createElement(DefinitionConsumer, null, ({
|
|
@@ -27047,22 +27007,19 @@ var Definition$1 = {
|
|
|
27047
27007
|
accessible: true,
|
|
27048
27008
|
defaultAlignment: "inline",
|
|
27049
27009
|
widget: Definition,
|
|
27050
|
-
transform: x => x
|
|
27010
|
+
transform: x => x,
|
|
27011
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27012
|
+
validator: () => noopValidator()
|
|
27051
27013
|
};
|
|
27052
27014
|
|
|
27053
27015
|
// The props are type `any` on purpose so that this can receive props
|
|
27054
27016
|
// from any deprecated widget
|
|
27055
27017
|
class DeprecatedStandin extends React__default.Component {
|
|
27056
|
-
|
|
27057
|
-
|
|
27058
|
-
//
|
|
27059
|
-
|
|
27060
|
-
|
|
27061
|
-
getUserInput() {
|
|
27062
|
-
return {};
|
|
27063
|
-
}
|
|
27064
|
-
simpleValidate() {
|
|
27065
|
-
return noopValidator(1);
|
|
27018
|
+
constructor(...args) {
|
|
27019
|
+
super(...args);
|
|
27020
|
+
// this just helps with TS weak typing when a Widget
|
|
27021
|
+
// doesn't implement any Widget methods
|
|
27022
|
+
this.isWidget = true;
|
|
27066
27023
|
}
|
|
27067
27024
|
render() {
|
|
27068
27025
|
return /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -27082,7 +27039,9 @@ var DeprecatedStandin$1 = {
|
|
|
27082
27039
|
name: "deprecated-standin",
|
|
27083
27040
|
displayName: "Deprecated Standin",
|
|
27084
27041
|
widget: DeprecatedStandin,
|
|
27085
|
-
hidden: true
|
|
27042
|
+
hidden: true,
|
|
27043
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27044
|
+
validator: () => noopValidator(1)
|
|
27086
27045
|
};
|
|
27087
27046
|
|
|
27088
27047
|
function dropdownValidator(userInput, rubric) {
|
|
@@ -27123,17 +27082,11 @@ class Dropdown extends React.Component {
|
|
|
27123
27082
|
});
|
|
27124
27083
|
};
|
|
27125
27084
|
}
|
|
27126
|
-
static validate(userInput, rubric) {
|
|
27127
|
-
return dropdownValidator(userInput, rubric);
|
|
27128
|
-
}
|
|
27129
27085
|
getUserInput() {
|
|
27130
27086
|
return {
|
|
27131
27087
|
value: this.props.selected
|
|
27132
27088
|
};
|
|
27133
27089
|
}
|
|
27134
|
-
simpleValidate(rubric) {
|
|
27135
|
-
return dropdownValidator(this.getUserInput(), rubric);
|
|
27136
|
-
}
|
|
27137
27090
|
render() {
|
|
27138
27091
|
const children = [/*#__PURE__*/React.createElement(OptionItem, {
|
|
27139
27092
|
key: "placeholder",
|
|
@@ -27180,7 +27133,8 @@ var Dropdown$1 = {
|
|
|
27180
27133
|
defaultAlignment: "inline-block",
|
|
27181
27134
|
accessible: true,
|
|
27182
27135
|
widget: Dropdown,
|
|
27183
|
-
transform: optionsTransform
|
|
27136
|
+
transform: optionsTransform,
|
|
27137
|
+
validator: dropdownValidator
|
|
27184
27138
|
};
|
|
27185
27139
|
|
|
27186
27140
|
// transform = _.identity
|
|
@@ -27194,6 +27148,9 @@ function mediaQueryIsMatched(mediaQuery) {
|
|
|
27194
27148
|
class Explanation extends React.Component {
|
|
27195
27149
|
constructor(..._args) {
|
|
27196
27150
|
super(..._args);
|
|
27151
|
+
// this just helps with TS weak typing when a Widget
|
|
27152
|
+
// doesn't implement any Widget methods
|
|
27153
|
+
this.isWidget = true;
|
|
27197
27154
|
this.state = {
|
|
27198
27155
|
expanded: false
|
|
27199
27156
|
};
|
|
@@ -27208,24 +27165,12 @@ class Explanation extends React.Component {
|
|
|
27208
27165
|
this.props.trackInteraction();
|
|
27209
27166
|
};
|
|
27210
27167
|
}
|
|
27211
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27212
|
-
static validate() {
|
|
27213
|
-
return noopValidator();
|
|
27214
|
-
}
|
|
27215
27168
|
componentDidMount() {
|
|
27216
27169
|
this._mounted = true;
|
|
27217
27170
|
}
|
|
27218
27171
|
componentWillUnmount() {
|
|
27219
27172
|
this._mounted = false;
|
|
27220
27173
|
}
|
|
27221
|
-
getUserInput() {
|
|
27222
|
-
return {};
|
|
27223
|
-
}
|
|
27224
|
-
|
|
27225
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
27226
|
-
simpleValidate() {
|
|
27227
|
-
return noopValidator();
|
|
27228
|
-
}
|
|
27229
27174
|
render() {
|
|
27230
27175
|
const promptText = this.state.expanded ? this.props.hidePrompt : this.props.showPrompt;
|
|
27231
27176
|
const caretIcon = this.state.expanded ? caretUp : caretDown;
|
|
@@ -27339,7 +27284,9 @@ var Explanation$1 = {
|
|
|
27339
27284
|
defaultAlignment: "inline",
|
|
27340
27285
|
widget: Explanation,
|
|
27341
27286
|
transform: _.identity,
|
|
27342
|
-
isLintable: true
|
|
27287
|
+
isLintable: true,
|
|
27288
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
27289
|
+
validator: () => noopValidator()
|
|
27343
27290
|
};
|
|
27344
27291
|
|
|
27345
27292
|
class GradedGroupAnswerBar extends React.Component {
|
|
@@ -28939,9 +28886,6 @@ class Grapher extends React.Component {
|
|
|
28939
28886
|
}
|
|
28940
28887
|
};
|
|
28941
28888
|
}
|
|
28942
|
-
static validate(state, rubric) {
|
|
28943
|
-
return grapherValidator(state, rubric);
|
|
28944
|
-
}
|
|
28945
28889
|
static getUserInputFromProps(props) {
|
|
28946
28890
|
return props.plot;
|
|
28947
28891
|
}
|
|
@@ -28960,9 +28904,6 @@ class Grapher extends React.Component {
|
|
|
28960
28904
|
tickStep[1] = tickStep[1] / gridStep[1];
|
|
28961
28905
|
return tickStep;
|
|
28962
28906
|
}
|
|
28963
|
-
simpleValidate(rubric) {
|
|
28964
|
-
return grapherValidator(this.getUserInput(), rubric);
|
|
28965
|
-
}
|
|
28966
28907
|
getUserInput() {
|
|
28967
28908
|
return Grapher.getUserInputFromProps(this.props);
|
|
28968
28909
|
}
|
|
@@ -29050,7 +28991,8 @@ var Grapher$1 = {
|
|
|
29050
28991
|
hidden: true,
|
|
29051
28992
|
widget: Grapher,
|
|
29052
28993
|
transform: propTransform$2,
|
|
29053
|
-
staticTransform: staticTransform$4
|
|
28994
|
+
staticTransform: staticTransform$4,
|
|
28995
|
+
validator: grapherValidator
|
|
29054
28996
|
};
|
|
29055
28997
|
|
|
29056
28998
|
// exports has no 'transform'
|
|
@@ -29096,17 +29038,18 @@ class Group extends React.Component {
|
|
|
29096
29038
|
// the group with the correct number.
|
|
29097
29039
|
this.forceUpdate();
|
|
29098
29040
|
}
|
|
29099
|
-
|
|
29041
|
+
getUserInputMap() {
|
|
29100
29042
|
var _this$rendererRef7;
|
|
29101
|
-
return (_this$rendererRef7 = this.rendererRef) == null ? void 0 : _this$rendererRef7.
|
|
29102
|
-
}
|
|
29103
|
-
simpleValidate() {
|
|
29104
|
-
var _this$rendererRef$sco, _this$rendererRef8;
|
|
29105
|
-
return (_this$rendererRef$sco = (_this$rendererRef8 = this.rendererRef) == null ? void 0 : _this$rendererRef8.score()) != null ? _this$rendererRef$sco : {
|
|
29106
|
-
type: "invalid"
|
|
29107
|
-
};
|
|
29043
|
+
return (_this$rendererRef7 = this.rendererRef) == null ? void 0 : _this$rendererRef7.getUserInputMap();
|
|
29108
29044
|
}
|
|
29109
29045
|
|
|
29046
|
+
/**
|
|
29047
|
+
* @deprecated getUserInputMap should be used for Groups
|
|
29048
|
+
*/
|
|
29049
|
+
getUserInput() {
|
|
29050
|
+
var _this$rendererRef8;
|
|
29051
|
+
return (_this$rendererRef8 = this.rendererRef) == null ? void 0 : _this$rendererRef8.getUserInput();
|
|
29052
|
+
}
|
|
29110
29053
|
// Mobile API:
|
|
29111
29054
|
getInputPaths() {
|
|
29112
29055
|
var _this$rendererRef$get, _this$rendererRef9;
|
|
@@ -29267,9 +29210,6 @@ class Iframe extends React.Component {
|
|
|
29267
29210
|
return change.apply(this, args);
|
|
29268
29211
|
};
|
|
29269
29212
|
}
|
|
29270
|
-
static validate(state) {
|
|
29271
|
-
return iframeValidator(state);
|
|
29272
|
-
}
|
|
29273
29213
|
componentDidMount() {
|
|
29274
29214
|
$(window).on("message", this.handleMessageEvent);
|
|
29275
29215
|
}
|
|
@@ -29282,9 +29222,6 @@ class Iframe extends React.Component {
|
|
|
29282
29222
|
message: this.props.message
|
|
29283
29223
|
};
|
|
29284
29224
|
}
|
|
29285
|
-
simpleValidate() {
|
|
29286
|
-
return iframeValidator(this.getUserInput());
|
|
29287
|
-
}
|
|
29288
29225
|
render() {
|
|
29289
29226
|
const style = {
|
|
29290
29227
|
width: String(this.props.width),
|
|
@@ -29358,7 +29295,8 @@ var Iframe$1 = {
|
|
|
29358
29295
|
displayName: "Iframe (deprecated)",
|
|
29359
29296
|
widget: Iframe,
|
|
29360
29297
|
// Let's not expose it to all content creators yet
|
|
29361
|
-
hidden: true
|
|
29298
|
+
hidden: true,
|
|
29299
|
+
validator: iframeValidator
|
|
29362
29300
|
};
|
|
29363
29301
|
|
|
29364
29302
|
const defaultBoxSize = 400;
|
|
@@ -29376,22 +29314,13 @@ const DEFAULT_ALIGNMENT = "block";
|
|
|
29376
29314
|
class ImageWidget extends React.Component {
|
|
29377
29315
|
constructor(..._args) {
|
|
29378
29316
|
super(..._args);
|
|
29317
|
+
// this just helps with TS weak typing when a Widget
|
|
29318
|
+
// doesn't implement any Widget methods
|
|
29319
|
+
this.isWidget = true;
|
|
29379
29320
|
this.change = (...args) => {
|
|
29380
29321
|
return change.apply(this, args);
|
|
29381
29322
|
};
|
|
29382
29323
|
}
|
|
29383
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29384
|
-
static validate() {
|
|
29385
|
-
return noopValidator();
|
|
29386
|
-
}
|
|
29387
|
-
getUserInput() {
|
|
29388
|
-
return null;
|
|
29389
|
-
}
|
|
29390
|
-
|
|
29391
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29392
|
-
simpleValidate() {
|
|
29393
|
-
return noopValidator();
|
|
29394
|
-
}
|
|
29395
29324
|
render() {
|
|
29396
29325
|
let image;
|
|
29397
29326
|
const alt = this.props.caption === this.props.alt ? "" : this.props.alt;
|
|
@@ -29546,7 +29475,9 @@ var Image$1 = {
|
|
|
29546
29475
|
supportedAlignments: editorAlignments,
|
|
29547
29476
|
displayName: "Image",
|
|
29548
29477
|
widget: ImageWidget,
|
|
29549
|
-
isLintable: true
|
|
29478
|
+
isLintable: true,
|
|
29479
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
29480
|
+
validator: () => noopValidator()
|
|
29550
29481
|
};
|
|
29551
29482
|
|
|
29552
29483
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -29615,6 +29546,9 @@ const KAScompile = (expr, options) => {
|
|
|
29615
29546
|
class Interaction extends React.Component {
|
|
29616
29547
|
constructor(..._args) {
|
|
29617
29548
|
super(..._args);
|
|
29549
|
+
// this just helps with TS weak typing when a Widget
|
|
29550
|
+
// doesn't implement any Widget methods
|
|
29551
|
+
this.isWidget = true;
|
|
29618
29552
|
this.state = {
|
|
29619
29553
|
variables: _getInitialVariables(this.props.elements),
|
|
29620
29554
|
functions: _getInitialFunctions(this.props.elements)
|
|
@@ -29698,10 +29632,6 @@ class Interaction extends React.Component {
|
|
|
29698
29632
|
return change.apply(this, args);
|
|
29699
29633
|
};
|
|
29700
29634
|
}
|
|
29701
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29702
|
-
static validate() {
|
|
29703
|
-
return noopValidator();
|
|
29704
|
-
}
|
|
29705
29635
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
29706
29636
|
// HACK(michaelpolyak): This widget is not wired to use the Perseus
|
|
29707
29637
|
// `onChange` callback to save user changes. Perseus re-rendering of the
|
|
@@ -29720,18 +29650,6 @@ class Interaction extends React.Component {
|
|
|
29720
29650
|
});
|
|
29721
29651
|
}
|
|
29722
29652
|
}
|
|
29723
|
-
getUserInput() {
|
|
29724
|
-
// TODO(eater): Perhaps we want to be able to record the state of the
|
|
29725
|
-
// user's interaction. Unfortunately sending all the props will
|
|
29726
|
-
// probably make the attempt payload too large. So for now, don't send
|
|
29727
|
-
// anything.
|
|
29728
|
-
return {};
|
|
29729
|
-
}
|
|
29730
|
-
|
|
29731
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
29732
|
-
simpleValidate() {
|
|
29733
|
-
return noopValidator();
|
|
29734
|
-
}
|
|
29735
29653
|
render() {
|
|
29736
29654
|
const range = this.props.graph.range;
|
|
29737
29655
|
let labels = this.props.graph.labels;
|
|
@@ -30150,7 +30068,9 @@ var Interactive = {
|
|
|
30150
30068
|
displayName: "Interaction",
|
|
30151
30069
|
widget: Interaction,
|
|
30152
30070
|
transform: _.identity,
|
|
30153
|
-
hidden: true
|
|
30071
|
+
hidden: true,
|
|
30072
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
30073
|
+
validator: () => noopValidator()
|
|
30154
30074
|
};
|
|
30155
30075
|
|
|
30156
30076
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -30672,16 +30592,39 @@ function polar(r, th) {
|
|
|
30672
30592
|
th = th * Math.PI / 180;
|
|
30673
30593
|
return [r[0] * Math.cos(th), r[1] * Math.sin(th)];
|
|
30674
30594
|
}
|
|
30675
|
-
|
|
30676
|
-
|
|
30677
|
-
|
|
30678
|
-
|
|
30679
|
-
|
|
30680
|
-
|
|
30681
|
-
|
|
30682
|
-
return
|
|
30595
|
+
// This function calculates the angle between two points and an optional vertex.
|
|
30596
|
+
// If the vertex is not provided, the angle is measured between the two points.
|
|
30597
|
+
// This does not account for reflex angles or clockwise position.
|
|
30598
|
+
const getAngleFromVertex = (point, vertex) => {
|
|
30599
|
+
const x = point[0] - vertex[0];
|
|
30600
|
+
const y = point[1] - vertex[1];
|
|
30601
|
+
if (!x && !y) {
|
|
30602
|
+
return 0;
|
|
30683
30603
|
}
|
|
30684
|
-
return
|
|
30604
|
+
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
30605
|
+
};
|
|
30606
|
+
|
|
30607
|
+
// This function calculates the clockwise angle between three points,
|
|
30608
|
+
// and is used to generate the labels and equation strings of the
|
|
30609
|
+
// current angle for the interactive graph.
|
|
30610
|
+
const getClockwiseAngle = (coords, allowReflexAngles = false) => {
|
|
30611
|
+
const coordsCopy = [...coords];
|
|
30612
|
+
// The coords are saved as [point1, vertex, point2] in the interactive graph
|
|
30613
|
+
const areClockwise = clockwise$1([coordsCopy[0], coordsCopy[2], coordsCopy[1]]);
|
|
30614
|
+
|
|
30615
|
+
// We may need to reverse the coordinates if we allow
|
|
30616
|
+
// reflex angles and the points are not in clockwise order.
|
|
30617
|
+
const shouldReverseCoords = !areClockwise || allowReflexAngles;
|
|
30618
|
+
|
|
30619
|
+
// Reverse the coordinates accordingly to ensure the angle is calculated correctly
|
|
30620
|
+
const clockwiseCoords = shouldReverseCoords ? coordsCopy.reverse() : coordsCopy;
|
|
30621
|
+
|
|
30622
|
+
// Calculate the angles between the two points and get the difference
|
|
30623
|
+
// between the two angles to get the clockwise angle.
|
|
30624
|
+
const startAngle = getAngleFromVertex(clockwiseCoords[0], clockwiseCoords[1]);
|
|
30625
|
+
const endAngle = getAngleFromVertex(clockwiseCoords[2], clockwiseCoords[1]);
|
|
30626
|
+
const angle = (startAngle + 360 - endAngle) % 360;
|
|
30627
|
+
return angle;
|
|
30685
30628
|
};
|
|
30686
30629
|
|
|
30687
30630
|
const defaultGraphConfig = {
|
|
@@ -33103,8 +33046,8 @@ const Angle = ({
|
|
|
33103
33046
|
const clockwiseCoords = shouldReverseCoords ? coords : coords.reverse();
|
|
33104
33047
|
|
|
33105
33048
|
// Calculate the angles between the two points
|
|
33106
|
-
const startAngle =
|
|
33107
|
-
const endAngle =
|
|
33049
|
+
const startAngle = getAngleFromVertex(clockwiseCoords[0], vertex);
|
|
33050
|
+
const endAngle = getAngleFromVertex(clockwiseCoords[1], vertex);
|
|
33108
33051
|
const angle = (startAngle + 360 - endAngle) % 360;
|
|
33109
33052
|
|
|
33110
33053
|
// Check if the angle is reflexive
|
|
@@ -34183,7 +34126,9 @@ const MafsGraph = props => {
|
|
|
34183
34126
|
analytics.onAnalyticsEvent({
|
|
34184
34127
|
type: "perseus:interactive-graph-widget:rendered",
|
|
34185
34128
|
payload: {
|
|
34186
|
-
type
|
|
34129
|
+
type,
|
|
34130
|
+
widgetType: "INTERACTIVE_GRAPH",
|
|
34131
|
+
widgetId: "interactive-graph"
|
|
34187
34132
|
}
|
|
34188
34133
|
});
|
|
34189
34134
|
});
|
|
@@ -35423,7 +35368,7 @@ function boundAndSnapAngleVertex({
|
|
|
35423
35368
|
for (const i of [0, 2]) {
|
|
35424
35369
|
const oldPoint = coordsCopy[i];
|
|
35425
35370
|
let newPoint = vec.add(oldPoint, delta);
|
|
35426
|
-
let angle =
|
|
35371
|
+
let angle = getAngleFromVertex(newVertex, newPoint);
|
|
35427
35372
|
angle *= Math.PI / 180;
|
|
35428
35373
|
newPoint = constrainToBoundsOnAngle(newPoint, angle, range, snapStep);
|
|
35429
35374
|
newPoints[i] = newPoint;
|
|
@@ -35494,7 +35439,7 @@ function boundAndSnapAngleEndPoints(destinationPoint, {
|
|
|
35494
35439
|
const vertex = coords[1];
|
|
35495
35440
|
|
|
35496
35441
|
// Gets the angle between the coords and the vertex
|
|
35497
|
-
let angle =
|
|
35442
|
+
let angle = getAngleFromVertex(coordsCopy[index], vertex);
|
|
35498
35443
|
|
|
35499
35444
|
// Snap the angle to the nearest multiple of snapDegrees (if provided)
|
|
35500
35445
|
angle = Math.round((angle - offsetDegrees) / snap) * snap + offsetDegrees;
|
|
@@ -35540,8 +35485,8 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
35540
35485
|
angles[rel(j)] = Math.round(angles[rel(j)]);
|
|
35541
35486
|
});
|
|
35542
35487
|
const getAngle = function getAngle(a, vertex, b) {
|
|
35543
|
-
const angle =
|
|
35544
|
-
return
|
|
35488
|
+
const angle = getClockwiseAngle([coordsCopy[rel(a)], coordsCopy[rel(vertex)], coordsCopy[rel(b)]]);
|
|
35489
|
+
return angle;
|
|
35545
35490
|
};
|
|
35546
35491
|
const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
|
|
35547
35492
|
innerAngles[2] = 180 - (innerAngles[0] + innerAngles[1]);
|
|
@@ -35568,7 +35513,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
35568
35513
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
35569
35514
|
|
|
35570
35515
|
// Angle at the second vertex of the polygon
|
|
35571
|
-
const outerAngle =
|
|
35516
|
+
const outerAngle = getAngleFromVertex(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
35572
35517
|
|
|
35573
35518
|
// Uses the length of the side of the polygon (radial coordinate)
|
|
35574
35519
|
// and the angle between the first and second sides of the
|
|
@@ -35618,7 +35563,7 @@ function boundAndSnapToSides(destinationPoint, {
|
|
|
35618
35563
|
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
35619
35564
|
|
|
35620
35565
|
// Angle at the second vertex of the polygon
|
|
35621
|
-
const outerAngle =
|
|
35566
|
+
const outerAngle = getAngleFromVertex(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
35622
35567
|
|
|
35623
35568
|
// Returns true if the points form a counter-clockwise turn;
|
|
35624
35569
|
// a.k.a if the point is on the left or right of the polygon.
|
|
@@ -35725,7 +35670,8 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
35725
35670
|
const numPoints = graph.type === "point" ? graph.numPoints : null;
|
|
35726
35671
|
const numSides = graph.type === "polygon" ? graph.numSides : null;
|
|
35727
35672
|
const snapTo = graph.type === "polygon" ? graph.snapTo : null;
|
|
35728
|
-
const showAngles = graph.type === "polygon" ? graph.showAngles : null;
|
|
35673
|
+
const showAngles = graph.type === "polygon" || graph.type === "angle" ? graph.showAngles : null;
|
|
35674
|
+
const allowReflexAngles = graph.type === "angle" ? graph.allowReflexAngles : null;
|
|
35729
35675
|
const showSides = graph.type === "polygon" ? graph.showSides : null;
|
|
35730
35676
|
const startCoords = "startCoords" in graph ? graph.startCoords : undefined;
|
|
35731
35677
|
const originalPropsRef = useRef(props);
|
|
@@ -35738,7 +35684,7 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
35738
35684
|
if (latestPropsRef.current !== originalPropsRef.current) {
|
|
35739
35685
|
dispatch(reinitialize(latestPropsRef.current));
|
|
35740
35686
|
}
|
|
35741
|
-
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, startCoords]);
|
|
35687
|
+
}, [graph.type, numPoints, numSegments, numSides, snapTo, showAngles, showSides, latestPropsRef, startCoords, allowReflexAngles]);
|
|
35742
35688
|
|
|
35743
35689
|
// If the graph is static, it always displays the correct answer. This is
|
|
35744
35690
|
// standard behavior for Perseus widgets (e.g. compare the Radio widget).
|
|
@@ -35927,17 +35873,15 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
35927
35873
|
} else if (userInput.type === "angle" && rubric.correct.type === "angle") {
|
|
35928
35874
|
const guess = userInput.coords;
|
|
35929
35875
|
const correct = rubric.correct.coords;
|
|
35876
|
+
const allowReflexAngles = rubric.correct.allowReflexAngles;
|
|
35930
35877
|
let match;
|
|
35931
35878
|
if (rubric.correct.match === "congruent") {
|
|
35932
35879
|
const angles = _.map([guess, correct], function (coords) {
|
|
35933
|
-
|
|
35934
|
-
|
|
35935
|
-
|
|
35936
|
-
|
|
35937
|
-
|
|
35938
|
-
// @ts-expect-error - TS2532 - Object is possibly 'undefined'.
|
|
35939
|
-
coords[1]);
|
|
35940
|
-
return (angle + 360) % 360;
|
|
35880
|
+
if (!coords) {
|
|
35881
|
+
return false;
|
|
35882
|
+
}
|
|
35883
|
+
const angle = getClockwiseAngle(coords, allowReflexAngles);
|
|
35884
|
+
return angle;
|
|
35941
35885
|
});
|
|
35942
35886
|
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
35943
35887
|
match = eq$1(...angles);
|
|
@@ -36805,7 +36749,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
36805
36749
|
angles[rel(j)] = Math.round(angles[rel(j)]);
|
|
36806
36750
|
});
|
|
36807
36751
|
const getAngle = function getAngle(a, vertex, b) {
|
|
36808
|
-
const angle = GraphUtils.
|
|
36752
|
+
const angle = GraphUtils.findAngleDeprecated(coords[rel(a)], coords[rel(b)], coords[rel(vertex)]);
|
|
36809
36753
|
return (angle + 360) % 360;
|
|
36810
36754
|
};
|
|
36811
36755
|
const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
|
|
@@ -36824,7 +36768,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
36824
36768
|
|
|
36825
36769
|
// Solve for side by using the law of sines
|
|
36826
36770
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
36827
|
-
const outerAngle = GraphUtils.
|
|
36771
|
+
const outerAngle = GraphUtils.findAngleDeprecated(coords[rel(1)], coords[rel(-1)]);
|
|
36828
36772
|
const offset = polar$1(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
36829
36773
|
return (_this$graphie5 = this.graphie) == null ? void 0 : _this$graphie5.addPoints(coords[rel(-1)], offset);
|
|
36830
36774
|
}
|
|
@@ -36848,7 +36792,7 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
36848
36792
|
|
|
36849
36793
|
// Solve for angle by using the law of cosines
|
|
36850
36794
|
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
36851
|
-
const outerAngle = GraphUtils.
|
|
36795
|
+
const outerAngle = GraphUtils.findAngleDeprecated(coords[rel(1)], coords[rel(-1)]);
|
|
36852
36796
|
const onLeft = sign(ccw(coords[rel(-1)], coords[rel(1)], coords[i])) === 1;
|
|
36853
36797
|
const offset = polar$1(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
|
|
36854
36798
|
return (_this$graphie6 = this.graphie) == null ? void 0 : _this$graphie6.addPoints(coords[rel(-1)], offset);
|
|
@@ -37212,9 +37156,6 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
37212
37156
|
getUserInput() {
|
|
37213
37157
|
return InteractiveGraph.getUserInputFromProps(this.props);
|
|
37214
37158
|
}
|
|
37215
|
-
simpleValidate(rubric) {
|
|
37216
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37217
|
-
}
|
|
37218
37159
|
render() {
|
|
37219
37160
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
37220
37161
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
@@ -37291,9 +37232,6 @@ class InteractiveGraph extends React.Component {
|
|
|
37291
37232
|
}
|
|
37292
37233
|
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
37293
37234
|
}
|
|
37294
|
-
simpleValidate(rubric) {
|
|
37295
|
-
return interactiveGraphValidator(this.getUserInput(), rubric);
|
|
37296
|
-
}
|
|
37297
37235
|
render() {
|
|
37298
37236
|
var _this$props$apiOption;
|
|
37299
37237
|
// Mafs shim
|
|
@@ -37622,12 +37560,10 @@ class InteractiveGraph extends React.Component {
|
|
|
37622
37560
|
throw makeInvalidTypeError("getAngleEquationString", "angle");
|
|
37623
37561
|
}
|
|
37624
37562
|
const coords = InteractiveGraph.getAngleCoords(props.graph, props);
|
|
37625
|
-
const
|
|
37563
|
+
const allowReflexAngles = props.graph.allowReflexAngles;
|
|
37564
|
+
const angle = getClockwiseAngle(coords, allowReflexAngles);
|
|
37626
37565
|
return angle.toFixed(0) + "\u00B0 angle" + " at (" + coords[1].join(", ") + ")";
|
|
37627
37566
|
}
|
|
37628
|
-
static validate(userInput, rubric) {
|
|
37629
|
-
return interactiveGraphValidator(userInput, rubric);
|
|
37630
|
-
}
|
|
37631
37567
|
static getUserInputFromProps(props) {
|
|
37632
37568
|
return props.graph;
|
|
37633
37569
|
}
|
|
@@ -37676,7 +37612,8 @@ var InteractiveGraph$1 = {
|
|
|
37676
37612
|
name: "interactive-graph",
|
|
37677
37613
|
displayName: "Interactive graph (Assessments only)",
|
|
37678
37614
|
widget: InteractiveGraph,
|
|
37679
|
-
staticTransform: staticTransform$3
|
|
37615
|
+
staticTransform: staticTransform$3,
|
|
37616
|
+
validator: interactiveGraphValidator
|
|
37680
37617
|
};
|
|
37681
37618
|
|
|
37682
37619
|
const black = "#000000";
|
|
@@ -39041,10 +38978,6 @@ const styles$b = StyleSheet.create({
|
|
|
39041
38978
|
// TODO: should this be using WidgetProps / PerseusLabelImageWidgetOptions?
|
|
39042
38979
|
|
|
39043
38980
|
class LabelImage extends React.Component {
|
|
39044
|
-
static validate(state, rubric) {
|
|
39045
|
-
return labelImageValidator(state);
|
|
39046
|
-
}
|
|
39047
|
-
|
|
39048
38981
|
/**
|
|
39049
38982
|
* Test whether point is contained within triangle.
|
|
39050
38983
|
*
|
|
@@ -39239,9 +39172,6 @@ class LabelImage extends React.Component {
|
|
|
39239
39172
|
componentWillUnmount() {
|
|
39240
39173
|
this._mounted = false;
|
|
39241
39174
|
}
|
|
39242
|
-
simpleValidate(rubric) {
|
|
39243
|
-
return labelImageValidator(this.getUserInput());
|
|
39244
|
-
}
|
|
39245
39175
|
getUserInput() {
|
|
39246
39176
|
const {
|
|
39247
39177
|
markers
|
|
@@ -39598,19 +39528,13 @@ const LabelImageWithDependencies = /*#__PURE__*/React.forwardRef((props, ref) =>
|
|
|
39598
39528
|
analytics: deps.analytics
|
|
39599
39529
|
}, props));
|
|
39600
39530
|
});
|
|
39601
|
-
|
|
39602
|
-
// HACK: Propogate "static" methods onto our wrapper component.
|
|
39603
|
-
// In the future we should adjust client apps to not depend on these static
|
|
39604
|
-
// methods and instead adjust Peresus to provide these facilities through
|
|
39605
|
-
// instance methods on our Renderers.
|
|
39606
|
-
// @ts-expect-error - TS2339 - Property 'validate' does not exist on type
|
|
39607
|
-
LabelImageWithDependencies.validate = labelImageValidator;
|
|
39608
39531
|
var LabelImage$1 = {
|
|
39609
39532
|
name: "label-image",
|
|
39610
39533
|
displayName: "Label Image",
|
|
39611
39534
|
widget: LabelImageWithDependencies,
|
|
39612
39535
|
accessible: true,
|
|
39613
|
-
isLintable: true
|
|
39536
|
+
isLintable: true,
|
|
39537
|
+
validator: labelImageValidator
|
|
39614
39538
|
};
|
|
39615
39539
|
|
|
39616
39540
|
var ItemState = /*#__PURE__*/function (ItemState) {
|
|
@@ -40395,12 +40319,6 @@ class Matcher extends React.Component {
|
|
|
40395
40319
|
this.refs.right.moveOptionToIndex(option, index);
|
|
40396
40320
|
};
|
|
40397
40321
|
}
|
|
40398
|
-
static validate(state, rubric) {
|
|
40399
|
-
return matcherValidator(state, rubric);
|
|
40400
|
-
}
|
|
40401
|
-
simpleValidate(rubric) {
|
|
40402
|
-
return matcherValidator(this.getUserInput(), rubric);
|
|
40403
|
-
}
|
|
40404
40322
|
render() {
|
|
40405
40323
|
// To minimize layout shift, we display a spinner until our math
|
|
40406
40324
|
// renderer is ready to render the math inside the matcher. To
|
|
@@ -40538,7 +40456,8 @@ var Matcher$1 = {
|
|
|
40538
40456
|
name: "matcher",
|
|
40539
40457
|
displayName: "Matcher (two column)",
|
|
40540
40458
|
widget: Matcher,
|
|
40541
|
-
isLintable: true
|
|
40459
|
+
isLintable: true,
|
|
40460
|
+
validator: matcherValidator
|
|
40542
40461
|
};
|
|
40543
40462
|
|
|
40544
40463
|
function matrixValidator(state, rubric, strings) {
|
|
@@ -40800,9 +40719,6 @@ class Matrix extends React.Component {
|
|
|
40800
40719
|
this.props.trackInteraction();
|
|
40801
40720
|
};
|
|
40802
40721
|
}
|
|
40803
|
-
static validate(state, rubric, strings) {
|
|
40804
|
-
return matrixValidator(state, rubric, strings);
|
|
40805
|
-
}
|
|
40806
40722
|
componentDidMount() {
|
|
40807
40723
|
// Used in the `onBlur` and `onFocus` handlers
|
|
40808
40724
|
this.cursorPosition = [0, 0];
|
|
@@ -40817,9 +40733,6 @@ class Matrix extends React.Component {
|
|
|
40817
40733
|
answers: this.props.answers
|
|
40818
40734
|
};
|
|
40819
40735
|
}
|
|
40820
|
-
simpleValidate(rubric) {
|
|
40821
|
-
return matrixValidator(this.getUserInput(), rubric, this.context.strings);
|
|
40822
|
-
}
|
|
40823
40736
|
render() {
|
|
40824
40737
|
// Set the input sizes through JS so we can control the size of the
|
|
40825
40738
|
// brackets. (If we set them in CSS we won't know values until the
|
|
@@ -41012,7 +40925,8 @@ var Matrix$1 = {
|
|
|
41012
40925
|
widget: Matrix,
|
|
41013
40926
|
transform: propTransform$1,
|
|
41014
40927
|
staticTransform: staticTransform$2,
|
|
41015
|
-
isLintable: true
|
|
40928
|
+
isLintable: true,
|
|
40929
|
+
validator: matrixValidator
|
|
41016
40930
|
};
|
|
41017
40931
|
|
|
41018
40932
|
const defaultImage = {
|
|
@@ -41023,6 +40937,9 @@ const defaultImage = {
|
|
|
41023
40937
|
class Measurer extends React.Component {
|
|
41024
40938
|
constructor(...args) {
|
|
41025
40939
|
super(...args);
|
|
40940
|
+
// this just helps with TS weak typing when a Widget
|
|
40941
|
+
// doesn't implement any Widget methods
|
|
40942
|
+
this.isWidget = true;
|
|
41026
40943
|
this.state = {};
|
|
41027
40944
|
this.ruler = void 0;
|
|
41028
40945
|
this.protractor = void 0;
|
|
@@ -41076,12 +40993,6 @@ class Measurer extends React.Component {
|
|
|
41076
40993
|
});
|
|
41077
40994
|
}
|
|
41078
40995
|
}
|
|
41079
|
-
getUserInput() {
|
|
41080
|
-
return {};
|
|
41081
|
-
}
|
|
41082
|
-
simpleValidate() {
|
|
41083
|
-
return noopValidator(1);
|
|
41084
|
-
}
|
|
41085
40996
|
render() {
|
|
41086
40997
|
const image = _.extend({}, defaultImage, this.props.image);
|
|
41087
40998
|
|
|
@@ -41107,7 +41018,6 @@ class Measurer extends React.Component {
|
|
|
41107
41018
|
}));
|
|
41108
41019
|
}
|
|
41109
41020
|
}
|
|
41110
|
-
Measurer.validate = noopValidator;
|
|
41111
41021
|
Measurer.defaultProps = {
|
|
41112
41022
|
box: [480, 480],
|
|
41113
41023
|
image: {},
|
|
@@ -41141,7 +41051,9 @@ var Measurer$1 = {
|
|
|
41141
41051
|
major: 1,
|
|
41142
41052
|
minor: 0
|
|
41143
41053
|
},
|
|
41144
|
-
propUpgrades: propUpgrades
|
|
41054
|
+
propUpgrades: propUpgrades,
|
|
41055
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
41056
|
+
validator: () => noopValidator(1)
|
|
41145
41057
|
};
|
|
41146
41058
|
|
|
41147
41059
|
/**
|
|
@@ -42008,17 +41920,11 @@ class Molecule extends React.Component {
|
|
|
42008
41920
|
}
|
|
42009
41921
|
Molecule.contextType = PerseusI18nContext;
|
|
42010
41922
|
class MoleculeWidget extends React.Component {
|
|
42011
|
-
|
|
42012
|
-
|
|
42013
|
-
|
|
42014
|
-
|
|
42015
|
-
|
|
42016
|
-
return [];
|
|
42017
|
-
}
|
|
42018
|
-
|
|
42019
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
42020
|
-
validate() {
|
|
42021
|
-
return noopValidator();
|
|
41923
|
+
constructor(...args) {
|
|
41924
|
+
super(...args);
|
|
41925
|
+
// this just helps with TS weak typing when a Widget
|
|
41926
|
+
// doesn't implement any Widget methods
|
|
41927
|
+
this.isWidget = true;
|
|
42022
41928
|
}
|
|
42023
41929
|
render() {
|
|
42024
41930
|
return /*#__PURE__*/React.createElement(Molecule, {
|
|
@@ -42035,7 +41941,8 @@ var Molecule$1 = {
|
|
|
42035
41941
|
name: "molecule-renderer",
|
|
42036
41942
|
displayName: "Molecule renderer",
|
|
42037
41943
|
hidden: true,
|
|
42038
|
-
widget: MoleculeWidget
|
|
41944
|
+
widget: MoleculeWidget,
|
|
41945
|
+
validator: () => noopValidator()
|
|
42039
41946
|
};
|
|
42040
41947
|
|
|
42041
41948
|
function numberLineValidator(state, rubric) {
|
|
@@ -42180,18 +42087,16 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
42180
42087
|
results.push(graphie.line([x, -0.2], [x, 0.2]));
|
|
42181
42088
|
const labelTicks = props.labelTicks;
|
|
42182
42089
|
if (labelTicks || props.labelStyle === "decimal ticks") {
|
|
42183
|
-
|
|
42090
|
+
if (x === leftLabel || x === rightLabel) {
|
|
42091
|
+
results.push(graphie.style({
|
|
42092
|
+
color: KhanColors.BLUE
|
|
42093
|
+
}, () => _label(graphie, props.labelStyle, x, x, base)));
|
|
42094
|
+
} else {
|
|
42095
|
+
results.push(_label(graphie, props.labelStyle, x, x, base));
|
|
42096
|
+
}
|
|
42184
42097
|
}
|
|
42185
42098
|
}
|
|
42186
42099
|
|
|
42187
|
-
// Render the text labels
|
|
42188
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42189
|
-
color: KhanColors.BLUE
|
|
42190
|
-
} : {}, () => _label(graphie, props.labelStyle, leftLabel, leftLabel, base)));
|
|
42191
|
-
results.push(graphie.style(props.isMobile ? {
|
|
42192
|
-
color: KhanColors.BLUE
|
|
42193
|
-
} : {}, () => _label(graphie, props.labelStyle, rightLabel, rightLabel, base)));
|
|
42194
|
-
|
|
42195
42100
|
// Render the labels' lines
|
|
42196
42101
|
graphie.style({
|
|
42197
42102
|
stroke: KhanColors.BLUE,
|
|
@@ -42466,9 +42371,6 @@ class NumberLine extends React.Component {
|
|
|
42466
42371
|
});
|
|
42467
42372
|
};
|
|
42468
42373
|
}
|
|
42469
|
-
static validate(state, rubric) {
|
|
42470
|
-
return numberLineValidator(state, rubric);
|
|
42471
|
-
}
|
|
42472
42374
|
focus() {
|
|
42473
42375
|
if (this.props.isTickCtrl) {
|
|
42474
42376
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -42498,9 +42400,6 @@ class NumberLine extends React.Component {
|
|
|
42498
42400
|
divisionRange: this.props.divisionRange
|
|
42499
42401
|
};
|
|
42500
42402
|
}
|
|
42501
|
-
simpleValidate(rubric) {
|
|
42502
|
-
return numberLineValidator(this.getUserInput(), rubric);
|
|
42503
|
-
}
|
|
42504
42403
|
render() {
|
|
42505
42404
|
const {
|
|
42506
42405
|
strings
|
|
@@ -42619,7 +42518,8 @@ var NumberLine$1 = {
|
|
|
42619
42518
|
displayName: "Number line",
|
|
42620
42519
|
widget: NumberLine,
|
|
42621
42520
|
transform: numberLineTransform,
|
|
42622
|
-
staticTransform: staticTransform$1
|
|
42521
|
+
staticTransform: staticTransform$1,
|
|
42522
|
+
validator: numberLineValidator
|
|
42623
42523
|
};
|
|
42624
42524
|
|
|
42625
42525
|
function ordererValidator(userInput, rubric) {
|
|
@@ -43052,9 +42952,6 @@ class Orderer extends React.Component {
|
|
|
43052
42952
|
});
|
|
43053
42953
|
};
|
|
43054
42954
|
}
|
|
43055
|
-
static validate(userInput, rubric) {
|
|
43056
|
-
return ordererValidator(userInput, rubric);
|
|
43057
|
-
}
|
|
43058
42955
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
43059
42956
|
if (!_.isEqual(this.props.current, nextProps.current)) {
|
|
43060
42957
|
this.setState({
|
|
@@ -43069,9 +42966,6 @@ class Orderer extends React.Component {
|
|
|
43069
42966
|
})
|
|
43070
42967
|
};
|
|
43071
42968
|
}
|
|
43072
|
-
simpleValidate(rubric) {
|
|
43073
|
-
return ordererValidator(this.getUserInput(), rubric);
|
|
43074
|
-
}
|
|
43075
42969
|
render() {
|
|
43076
42970
|
// This is the card we are currently dragging
|
|
43077
42971
|
const dragging = this.state.dragging && /*#__PURE__*/React.createElement(Card
|
|
@@ -43189,31 +43083,22 @@ var Orderer$1 = {
|
|
|
43189
43083
|
displayName: "Orderer",
|
|
43190
43084
|
hidden: true,
|
|
43191
43085
|
widget: Orderer,
|
|
43192
|
-
isLintable: true
|
|
43086
|
+
isLintable: true,
|
|
43087
|
+
validator: ordererValidator
|
|
43193
43088
|
};
|
|
43194
43089
|
|
|
43195
43090
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
43196
43091
|
class PassageRefTarget extends React.Component {
|
|
43197
43092
|
constructor(..._args) {
|
|
43198
43093
|
super(..._args);
|
|
43094
|
+
// this just helps with TS weak typing when a Widget
|
|
43095
|
+
// doesn't implement any Widget methods
|
|
43096
|
+
this.isWidget = true;
|
|
43199
43097
|
// TODO passage-ref-target isn't interactive; remove
|
|
43200
43098
|
this.change = (...args) => {
|
|
43201
43099
|
return change.apply(this, args);
|
|
43202
43100
|
};
|
|
43203
43101
|
}
|
|
43204
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43205
|
-
static validate() {
|
|
43206
|
-
return noopValidator();
|
|
43207
|
-
}
|
|
43208
|
-
|
|
43209
|
-
// TODO passage-ref-target isn't interactive; remove
|
|
43210
|
-
getUserInput() {
|
|
43211
|
-
return null;
|
|
43212
|
-
}
|
|
43213
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43214
|
-
simpleValidate() {
|
|
43215
|
-
return noopValidator();
|
|
43216
|
-
}
|
|
43217
43102
|
render() {
|
|
43218
43103
|
return /*#__PURE__*/React.createElement(Renderer, {
|
|
43219
43104
|
content: this.props.content
|
|
@@ -43247,7 +43132,9 @@ var PassageRefTarget$1 = {
|
|
|
43247
43132
|
major: 0,
|
|
43248
43133
|
minor: 0
|
|
43249
43134
|
},
|
|
43250
|
-
isLintable: true
|
|
43135
|
+
isLintable: true,
|
|
43136
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
43137
|
+
validator: () => noopValidator()
|
|
43251
43138
|
};
|
|
43252
43139
|
|
|
43253
43140
|
/**
|
|
@@ -43260,6 +43147,9 @@ class PhetSimulation extends React.Component {
|
|
|
43260
43147
|
super(props);
|
|
43261
43148
|
this.iframeRef = /*#__PURE__*/React.createRef();
|
|
43262
43149
|
this.locale = void 0;
|
|
43150
|
+
// this just helps with TS weak typing when a Widget
|
|
43151
|
+
// doesn't implement any Widget methods
|
|
43152
|
+
this.isWidget = true;
|
|
43263
43153
|
this.state = {
|
|
43264
43154
|
url: null,
|
|
43265
43155
|
banner: null
|
|
@@ -43302,11 +43192,6 @@ class PhetSimulation extends React.Component {
|
|
|
43302
43192
|
await this.updateSimState(this.props.url);
|
|
43303
43193
|
}
|
|
43304
43194
|
}
|
|
43305
|
-
|
|
43306
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
43307
|
-
getUserInput() {
|
|
43308
|
-
return null;
|
|
43309
|
-
}
|
|
43310
43195
|
async updateSimState(urlString) {
|
|
43311
43196
|
const url = makeSafeUrl(urlString, this.locale);
|
|
43312
43197
|
if (url === null) {
|
|
@@ -44205,9 +44090,6 @@ class Plotter extends React.Component {
|
|
|
44205
44090
|
});
|
|
44206
44091
|
};
|
|
44207
44092
|
}
|
|
44208
|
-
static validate(userInput, rubric) {
|
|
44209
|
-
return plotterValidator(userInput, rubric);
|
|
44210
|
-
}
|
|
44211
44093
|
componentDidMount() {
|
|
44212
44094
|
this._isMounted = true;
|
|
44213
44095
|
this.setupGraphie(this.state);
|
|
@@ -44234,9 +44116,6 @@ class Plotter extends React.Component {
|
|
|
44234
44116
|
getUserInput() {
|
|
44235
44117
|
return this.state.values;
|
|
44236
44118
|
}
|
|
44237
|
-
simpleValidate(rubric) {
|
|
44238
|
-
return plotterValidator(this.getUserInput(), rubric);
|
|
44239
|
-
}
|
|
44240
44119
|
render() {
|
|
44241
44120
|
// TODO(kevinb) actually compute the size of the graphie correctly and
|
|
44242
44121
|
// make it that size so we don't have to add extra padding. The value
|
|
@@ -44276,7 +44155,8 @@ var Plotter$1 = {
|
|
|
44276
44155
|
displayName: "Plotter",
|
|
44277
44156
|
hidden: true,
|
|
44278
44157
|
widget: Plotter,
|
|
44279
|
-
staticTransform: staticTransform
|
|
44158
|
+
staticTransform: staticTransform,
|
|
44159
|
+
validator: plotterValidator
|
|
44280
44160
|
};
|
|
44281
44161
|
|
|
44282
44162
|
/**
|
|
@@ -44392,9 +44272,6 @@ class Sorter extends React.Component {
|
|
|
44392
44272
|
this.refs.sortable.moveOptionToIndex(option, index);
|
|
44393
44273
|
};
|
|
44394
44274
|
}
|
|
44395
|
-
static validate(userInput, rubric) {
|
|
44396
|
-
return sorterValidator(userInput, rubric);
|
|
44397
|
-
}
|
|
44398
44275
|
componentDidMount() {
|
|
44399
44276
|
this._isMounted = true;
|
|
44400
44277
|
}
|
|
@@ -44410,9 +44287,6 @@ class Sorter extends React.Component {
|
|
|
44410
44287
|
changed: this.state.changed
|
|
44411
44288
|
};
|
|
44412
44289
|
}
|
|
44413
|
-
simpleValidate(rubric) {
|
|
44414
|
-
return sorterValidator(this.getUserInput(), rubric);
|
|
44415
|
-
}
|
|
44416
44290
|
render() {
|
|
44417
44291
|
const options = shuffle(this.props.correct, this.props.problemNum, /* ensurePermuted */true);
|
|
44418
44292
|
const {
|
|
@@ -44446,7 +44320,8 @@ var Sorter$1 = {
|
|
|
44446
44320
|
name: "sorter",
|
|
44447
44321
|
displayName: "Sorter",
|
|
44448
44322
|
widget: Sorter,
|
|
44449
|
-
isLintable: true
|
|
44323
|
+
isLintable: true,
|
|
44324
|
+
validator: sorterValidator
|
|
44450
44325
|
};
|
|
44451
44326
|
|
|
44452
44327
|
function tableValidator(state, rubric, strings) {
|
|
@@ -44625,15 +44500,9 @@ class Table extends React.Component {
|
|
|
44625
44500
|
}, cb);
|
|
44626
44501
|
};
|
|
44627
44502
|
}
|
|
44628
|
-
static validate(state, rubric, strings) {
|
|
44629
|
-
return tableValidator(state, rubric, strings);
|
|
44630
|
-
}
|
|
44631
44503
|
getUserInput() {
|
|
44632
44504
|
return _.map(this.props.answers, _.clone);
|
|
44633
44505
|
}
|
|
44634
|
-
simpleValidate(rubric) {
|
|
44635
|
-
return tableValidator(this.getUserInput(), rubric, this.context.strings);
|
|
44636
|
-
}
|
|
44637
44506
|
getDOMNodeForPath(path) {
|
|
44638
44507
|
const inputID = getRefForPath(path);
|
|
44639
44508
|
// eslint-disable-next-line react/no-string-refs
|
|
@@ -44734,7 +44603,8 @@ var Table$1 = {
|
|
|
44734
44603
|
widget: Table,
|
|
44735
44604
|
transform: propTransform,
|
|
44736
44605
|
hidden: true,
|
|
44737
|
-
isLintable: true
|
|
44606
|
+
isLintable: true,
|
|
44607
|
+
validator: tableValidator
|
|
44738
44608
|
};
|
|
44739
44609
|
|
|
44740
44610
|
/**
|
|
@@ -44822,26 +44692,14 @@ const IS_VIMEO = /(vimeo\.com)/;
|
|
|
44822
44692
|
class Video extends React.Component {
|
|
44823
44693
|
constructor(..._args) {
|
|
44824
44694
|
super(..._args);
|
|
44825
|
-
this
|
|
44826
|
-
|
|
44827
|
-
|
|
44695
|
+
// this just helps with TS weak typing when a Widget
|
|
44696
|
+
// doesn't implement any Widget methods
|
|
44697
|
+
this.isWidget = true;
|
|
44828
44698
|
this.change = (...args) => {
|
|
44829
44699
|
// @ts-expect-error - TS2345 - Argument of type 'readonly unknown[]' is not assignable to parameter of type 'any[]'.
|
|
44830
44700
|
return change.apply(this, args);
|
|
44831
44701
|
};
|
|
44832
44702
|
}
|
|
44833
|
-
/**
|
|
44834
|
-
* This is the widget's grading function.
|
|
44835
|
-
* Points for videos are tallied by the embedded video itself, in the case
|
|
44836
|
-
* of Khan Academy videos.
|
|
44837
|
-
*/ // TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44838
|
-
static validate() {
|
|
44839
|
-
return noopValidator();
|
|
44840
|
-
}
|
|
44841
|
-
// TODO (LEMS-2396): remove validation logic from widgets that don't validate
|
|
44842
|
-
simpleValidate() {
|
|
44843
|
-
return noopValidator();
|
|
44844
|
-
}
|
|
44845
44703
|
render() {
|
|
44846
44704
|
const {
|
|
44847
44705
|
InitialRequestUrl
|
|
@@ -44901,7 +44759,9 @@ var Video$1 = {
|
|
|
44901
44759
|
displayName: "Video",
|
|
44902
44760
|
defaultAlignment: "block",
|
|
44903
44761
|
supportedAlignments: ["block", "float-left", "float-right", "full-width"],
|
|
44904
|
-
widget: Video
|
|
44762
|
+
widget: Video,
|
|
44763
|
+
// TODO: things that aren't interactive shouldn't need validators
|
|
44764
|
+
validator: () => noopValidator()
|
|
44905
44765
|
};
|
|
44906
44766
|
|
|
44907
44767
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -44945,7 +44805,7 @@ const init = function init(options) {
|
|
|
44945
44805
|
|
|
44946
44806
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44947
44807
|
const libName = "@khanacademy/perseus";
|
|
44948
|
-
const libVersion = "
|
|
44808
|
+
const libVersion = "37.0.0";
|
|
44949
44809
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44950
44810
|
|
|
44951
44811
|
const apiVersion = {
|
|
@@ -45521,7 +45381,7 @@ class ServerItemRenderer extends React.Component {
|
|
|
45521
45381
|
});
|
|
45522
45382
|
|
|
45523
45383
|
// Call the interactionCallback, if it exists, with the current user input data
|
|
45524
|
-
(_this$props$apiOption = this.props.apiOptions) == null || _this$props$apiOption.interactionCallback == null || _this$props$apiOption.interactionCallback(this.questionRenderer.
|
|
45384
|
+
(_this$props$apiOption = this.props.apiOptions) == null || _this$props$apiOption.interactionCallback == null || _this$props$apiOption.interactionCallback(this.questionRenderer.getUserInputMap());
|
|
45525
45385
|
};
|
|
45526
45386
|
// This must be pre-bound otherwise SvgImage's shouldComponentUpdate
|
|
45527
45387
|
// won't behave correctly and we'll get an infinite loop.
|
|
@@ -48285,12 +48145,12 @@ function parsePerseusItem(json) {
|
|
|
48285
48145
|
}
|
|
48286
48146
|
throw new Error("Something went wrong.");
|
|
48287
48147
|
}
|
|
48288
|
-
function buildRandomString() {
|
|
48148
|
+
function buildRandomString(capitalize = false) {
|
|
48289
48149
|
let randomString = "";
|
|
48290
48150
|
const randomLength = Math.floor(Math.random() * 8) + 3;
|
|
48291
48151
|
for (let i = 0; i < randomLength; i++) {
|
|
48292
48152
|
const randomLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
48293
|
-
randomString += randomLetter;
|
|
48153
|
+
randomString += capitalize && i === 0 ? randomLetter.toUpperCase() : randomLetter;
|
|
48294
48154
|
}
|
|
48295
48155
|
return randomString;
|
|
48296
48156
|
}
|
|
@@ -48298,9 +48158,12 @@ function buildRandomPhrase() {
|
|
|
48298
48158
|
const phrases = [];
|
|
48299
48159
|
const randomLength = Math.floor(Math.random() * 10) + 5;
|
|
48300
48160
|
for (let i = 0; i < randomLength; i++) {
|
|
48301
|
-
phrases.push(buildRandomString());
|
|
48161
|
+
phrases.push(buildRandomString(i === 0));
|
|
48302
48162
|
}
|
|
48303
|
-
|
|
48163
|
+
const modifierStart = ["**", "$"];
|
|
48164
|
+
const modifierEnd = ["**", "$"];
|
|
48165
|
+
const modifierIndex = Math.floor(Math.random() * modifierStart.length);
|
|
48166
|
+
return `${modifierStart[modifierIndex]}${phrases.join(" ")}${modifierEnd[modifierIndex]}`;
|
|
48304
48167
|
}
|
|
48305
48168
|
function buildTestData(testObject) {
|
|
48306
48169
|
return `{"data":{"assessmentItem":{"__typename":"AssessmentItemOrError","error":null,"item":{"__typename":"AssessmentItem","id":"x890b3c70f3e8f4a6","itemData":"${testObject}","problemType":"Type 1","sha":"c7284a3ad65214b4e62bccce236d92f7f5d35941"}}}}`;
|
|
@@ -48505,5 +48368,5 @@ const EditorJsonify = {
|
|
|
48505
48368
|
}
|
|
48506
48369
|
};
|
|
48507
48370
|
|
|
48508
|
-
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
48371
|
+
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
48509
48372
|
//# sourceMappingURL=index.js.map
|