@khanacademy/perseus 36.0.0 → 36.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +222 -36
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +219 -33
- package/dist/index.js.map +1 -1
- package/dist/util/extract-perseus-data.d.ts +11 -1
- package/dist/widgets/interactive-graphs/backgrounds/axis-ticks.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +1 -1
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export { default as KhanColors } from "./util/colors";
|
|
|
61
61
|
export { default as preprocessTex } from "./util/tex-preprocess";
|
|
62
62
|
export { registerAllWidgetsForTesting } from "./util/register-all-widgets-for-testing";
|
|
63
63
|
export * as SizingUtils from "./util/sizing-utils";
|
|
64
|
-
export { getAnswersFromWidgets, injectWidgets, isWrongAnswerSupported, shouldHaveIndividualAnswer, isWidgetIdInContent, getValidWidgetIds, getCorrectAnswerForWidgetId, getAnswerFromUserInput, } from "./util/extract-perseus-data";
|
|
64
|
+
export { getAnswersFromWidgets, injectWidgets, isWrongAnswerSupported, shouldHaveIndividualAnswer, isWidgetIdInContent, getValidWidgetIds, getCorrectAnswerForWidgetId, getAnswerFromUserInput, getImagesWithoutAltData, } from "./util/extract-perseus-data";
|
|
65
65
|
export { parsePerseusItem } from "./util/parse-perseus-json";
|
|
66
66
|
export { generateTestPerseusItem, genericPerseusItemData, generateTestRadioWidget, generateTestInteractiveGraphWidget, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestNumericInputWidget, } from "./util/test-utils";
|
|
67
67
|
export { getWidgetTypeByWidgetId, contentHasWidgetType, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetsMapFromItemData, getWidgetFromWidgetMap, getWidgetsFromWidgetMap, } from "./widget-type-utils";
|
package/dist/index.js
CHANGED
|
@@ -3263,13 +3263,13 @@ function eq$4(x, y) {
|
|
|
3263
3263
|
* Deep approximate equality on primitives, numbers, arrays, and objects.
|
|
3264
3264
|
* Recursive.
|
|
3265
3265
|
*/
|
|
3266
|
-
function deepEq$
|
|
3266
|
+
function deepEq$6(x, y) {
|
|
3267
3267
|
if (Array.isArray(x) && Array.isArray(y)) {
|
|
3268
3268
|
if (x.length !== y.length) {
|
|
3269
3269
|
return false;
|
|
3270
3270
|
}
|
|
3271
3271
|
for (let i = 0; i < x.length; i++) {
|
|
3272
|
-
if (!deepEq$
|
|
3272
|
+
if (!deepEq$6(x[i], y[i])) {
|
|
3273
3273
|
return false;
|
|
3274
3274
|
}
|
|
3275
3275
|
}
|
|
@@ -3287,10 +3287,10 @@ function deepEq$5(x, y) {
|
|
|
3287
3287
|
if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
|
|
3288
3288
|
return x === y || ___default["default"].all(x, function (v, k) {
|
|
3289
3289
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
3290
|
-
return deepEq$
|
|
3290
|
+
return deepEq$6(y[k], v);
|
|
3291
3291
|
}) && ___default["default"].all(y, function (v, k) {
|
|
3292
3292
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
3293
|
-
return deepEq$
|
|
3293
|
+
return deepEq$6(x[k], v);
|
|
3294
3294
|
});
|
|
3295
3295
|
}
|
|
3296
3296
|
if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
|
|
@@ -3568,7 +3568,7 @@ const Util = {
|
|
|
3568
3568
|
tickStepFromNumTicks,
|
|
3569
3569
|
constrainedTickStepsFromTickSteps,
|
|
3570
3570
|
eq: eq$4,
|
|
3571
|
-
deepEq: deepEq$
|
|
3571
|
+
deepEq: deepEq$6,
|
|
3572
3572
|
parseQueryString,
|
|
3573
3573
|
updateQueryString: updateQueryString$2,
|
|
3574
3574
|
strongEncodeURIComponent,
|
|
@@ -10892,7 +10892,7 @@ class WrappedLine extends WrappedDrawing {
|
|
|
10892
10892
|
*/
|
|
10893
10893
|
const {
|
|
10894
10894
|
eq: eq$3,
|
|
10895
|
-
deepEq: deepEq$
|
|
10895
|
+
deepEq: deepEq$5
|
|
10896
10896
|
} = Util;
|
|
10897
10897
|
|
|
10898
10898
|
// This should really be a readonly tuple of [number, number]
|
|
@@ -11052,7 +11052,7 @@ function similar(coords1, coords2, tolerance) {
|
|
|
11052
11052
|
angles = rotate(angles, i);
|
|
11053
11053
|
// @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
|
|
11054
11054
|
sides = rotate(sides, i);
|
|
11055
|
-
if (deepEq$
|
|
11055
|
+
if (deepEq$5(angles1, angles)) {
|
|
11056
11056
|
const sidePairs = ___default["default"].zip(sides1, sides);
|
|
11057
11057
|
const factors = ___default["default"].map(sidePairs, function (pair) {
|
|
11058
11058
|
return pair[0] / pair[1];
|
|
@@ -13991,7 +13991,7 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
13991
13991
|
|
|
13992
13992
|
/* eslint-disable @babel/no-invalid-this */
|
|
13993
13993
|
const nestedMap$1 = Util.nestedMap;
|
|
13994
|
-
const deepEq$
|
|
13994
|
+
const deepEq$4 = Util.deepEq;
|
|
13995
13995
|
|
|
13996
13996
|
/**
|
|
13997
13997
|
* A base class for all Graphie Movables
|
|
@@ -14088,7 +14088,7 @@ const createSimpleClass = function (addFunction) {
|
|
|
14088
14088
|
this._prevProps = this.props;
|
|
14089
14089
|
},
|
|
14090
14090
|
modify: function (graphie) {
|
|
14091
|
-
if (!deepEq$
|
|
14091
|
+
if (!deepEq$4(this.props, this._prevProps)) {
|
|
14092
14092
|
this.remove();
|
|
14093
14093
|
this.add(graphie);
|
|
14094
14094
|
this._prevProps = this.props;
|
|
@@ -16835,7 +16835,7 @@ var Movables = {
|
|
|
16835
16835
|
const GraphieMovable = GraphieClasses.GraphieMovable;
|
|
16836
16836
|
const createGraphie = GraphUtils.createGraphie;
|
|
16837
16837
|
const {
|
|
16838
|
-
deepEq: deepEq$
|
|
16838
|
+
deepEq: deepEq$3,
|
|
16839
16839
|
nestedMap
|
|
16840
16840
|
} = Util;
|
|
16841
16841
|
const {
|
|
@@ -16873,7 +16873,7 @@ class Graphie extends React__namespace.Component {
|
|
|
16873
16873
|
if (this.props.setup !== prevProps.setup) {
|
|
16874
16874
|
Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", perseusCore.Errors.Internal);
|
|
16875
16875
|
}
|
|
16876
|
-
if (!deepEq$
|
|
16876
|
+
if (!deepEq$3(this.props.options, prevProps.options) || !deepEq$3(this.props.box, prevProps.box) || !deepEq$3(this.props.range, prevProps.range)) {
|
|
16877
16877
|
this._setupGraphie();
|
|
16878
16878
|
}
|
|
16879
16879
|
this._updateMovables();
|
|
@@ -31299,10 +31299,16 @@ const shouldShowLabel = (currentTick, range, tickStep) => {
|
|
|
31299
31299
|
function generateTickLocations(tickStep, min, max) {
|
|
31300
31300
|
const ticks = [];
|
|
31301
31301
|
|
|
31302
|
+
// Calculate the number of significant decimals in the tick step so
|
|
31303
|
+
// that we can match the desired precision when generating ticks.
|
|
31304
|
+
const decimalSigFigs = countSignificantDecimals(tickStep);
|
|
31305
|
+
|
|
31302
31306
|
// Add ticks in the positive direction
|
|
31303
31307
|
const start = Math.max(min, 0);
|
|
31304
31308
|
for (let i = start + tickStep; i < max; i += tickStep) {
|
|
31305
|
-
|
|
31309
|
+
// Match to the same number of decimal places as the tick step
|
|
31310
|
+
// to avoid floating point errors when working with small numbers
|
|
31311
|
+
ticks.push(parseFloat(i.toFixed(decimalSigFigs)));
|
|
31306
31312
|
}
|
|
31307
31313
|
|
|
31308
31314
|
// Add ticks in the negative direction
|
|
@@ -31313,6 +31319,15 @@ function generateTickLocations(tickStep, min, max) {
|
|
|
31313
31319
|
}
|
|
31314
31320
|
return ticks;
|
|
31315
31321
|
}
|
|
31322
|
+
|
|
31323
|
+
// Count the number of significant digits after the decimal point
|
|
31324
|
+
const countSignificantDecimals = number => {
|
|
31325
|
+
const numStr = number.toString();
|
|
31326
|
+
if (!numStr.includes(".")) {
|
|
31327
|
+
return 0;
|
|
31328
|
+
}
|
|
31329
|
+
return numStr.split(".")[1].length;
|
|
31330
|
+
};
|
|
31316
31331
|
const AxisTicks = () => {
|
|
31317
31332
|
const {
|
|
31318
31333
|
tickStep,
|
|
@@ -33597,7 +33612,7 @@ function calculateBisectorPoint(point1, point2, vertex, isReflex, allowReflex, a
|
|
|
33597
33612
|
return scaledBisector;
|
|
33598
33613
|
}
|
|
33599
33614
|
|
|
33600
|
-
const MovablePoint$1 = props => {
|
|
33615
|
+
const MovablePoint$1 = /*#__PURE__*/React__namespace.forwardRef((props, pointRef) => {
|
|
33601
33616
|
const {
|
|
33602
33617
|
snapStep
|
|
33603
33618
|
} = useGraphConfig();
|
|
@@ -33620,7 +33635,21 @@ const MovablePoint$1 = props => {
|
|
|
33620
33635
|
constrainKeyboardMovement: constrain
|
|
33621
33636
|
});
|
|
33622
33637
|
return /*#__PURE__*/React__namespace.createElement(MovablePointView, {
|
|
33623
|
-
ref:
|
|
33638
|
+
ref: ref => {
|
|
33639
|
+
// Note: This handles the case where pointRef is either a
|
|
33640
|
+
// function or a MutableRefObject. Mostly this is to satisfy
|
|
33641
|
+
// the type system, the function branch seems to be the only
|
|
33642
|
+
// one that occurs
|
|
33643
|
+
if (typeof pointRef === "function") {
|
|
33644
|
+
pointRef(ref);
|
|
33645
|
+
} else if (pointRef !== null) {
|
|
33646
|
+
pointRef.current = ref;
|
|
33647
|
+
}
|
|
33648
|
+
|
|
33649
|
+
// This ref is for the useDraggable and is not passed up the
|
|
33650
|
+
// chain
|
|
33651
|
+
elementRef.current = ref;
|
|
33652
|
+
},
|
|
33624
33653
|
point: point,
|
|
33625
33654
|
color: color,
|
|
33626
33655
|
dragging: dragging,
|
|
@@ -33635,7 +33664,7 @@ const MovablePoint$1 = props => {
|
|
|
33635
33664
|
},
|
|
33636
33665
|
cursor: cursor
|
|
33637
33666
|
});
|
|
33638
|
-
};
|
|
33667
|
+
});
|
|
33639
33668
|
|
|
33640
33669
|
const PolygonGraph = props => {
|
|
33641
33670
|
const [hovered, setHovered] = React__namespace.useState(false);
|
|
@@ -34225,6 +34254,13 @@ function UnlimitedPointGraph(props) {
|
|
|
34225
34254
|
const height = maxY - minY;
|
|
34226
34255
|
const [[widthPx, heightPx]] = useTransformDimensionsToPixels([width, height]);
|
|
34227
34256
|
const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
|
|
34257
|
+
const itemsRef = React__namespace.useRef([]);
|
|
34258
|
+
React__namespace.useEffect(() => {
|
|
34259
|
+
const focusedIndex = props.graphState.focusedPointIndex;
|
|
34260
|
+
if (focusedIndex != null) {
|
|
34261
|
+
itemsRef.current[focusedIndex]?.focus();
|
|
34262
|
+
}
|
|
34263
|
+
}, [props.graphState.focusedPointIndex, itemsRef]);
|
|
34228
34264
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("rect", {
|
|
34229
34265
|
style: {
|
|
34230
34266
|
fill: "rgba(0,0,0,0)",
|
|
@@ -34245,12 +34281,23 @@ function UnlimitedPointGraph(props) {
|
|
|
34245
34281
|
key: i,
|
|
34246
34282
|
point: point,
|
|
34247
34283
|
onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
|
|
34284
|
+
ref: ref => {
|
|
34285
|
+
itemsRef.current[i] = ref;
|
|
34286
|
+
},
|
|
34248
34287
|
onFocusChange: (event, isFocused) => {
|
|
34249
34288
|
if (isFocused) {
|
|
34250
34289
|
dispatch(actions.pointGraph.focusPoint(i));
|
|
34251
34290
|
} else {
|
|
34252
34291
|
if (event.relatedTarget?.id === REMOVE_BUTTON_ID) {
|
|
34253
34292
|
return;
|
|
34293
|
+
// This is an optimization: If the next target
|
|
34294
|
+
// is a point then don't blur because it casues
|
|
34295
|
+
// the remove button to get taken off the page
|
|
34296
|
+
// and then put back on The new point will
|
|
34297
|
+
// receive focus and set the correct state in
|
|
34298
|
+
// the reducer
|
|
34299
|
+
} else if (event.relatedTarget?.classList.contains("movable-point")) {
|
|
34300
|
+
return;
|
|
34254
34301
|
}
|
|
34255
34302
|
dispatch(actions.pointGraph.blurPoint());
|
|
34256
34303
|
}
|
|
@@ -34425,11 +34472,17 @@ const MafsGraph = props => {
|
|
|
34425
34472
|
fullGraphAriaLabel,
|
|
34426
34473
|
fullGraphAriaDescription
|
|
34427
34474
|
} = props;
|
|
34475
|
+
const {
|
|
34476
|
+
type
|
|
34477
|
+
} = state;
|
|
34428
34478
|
const [width, height] = props.box;
|
|
34429
34479
|
const tickStep = props.step;
|
|
34430
34480
|
const uniqueId = React__namespace.useId();
|
|
34431
34481
|
const descriptionId = `interactive-graph-description-${uniqueId}`;
|
|
34432
34482
|
const graphRef = React__namespace.useRef(null);
|
|
34483
|
+
const {
|
|
34484
|
+
analytics
|
|
34485
|
+
} = useDependencies();
|
|
34433
34486
|
|
|
34434
34487
|
// Set up the SVG attributes for the nested SVGs that help lock
|
|
34435
34488
|
// the grid and graph elements to the bounds of the graph.
|
|
@@ -34449,6 +34502,14 @@ const MafsGraph = props => {
|
|
|
34449
34502
|
const {
|
|
34450
34503
|
strings
|
|
34451
34504
|
} = usePerseusI18n();
|
|
34505
|
+
wonderBlocksCore.useOnMountEffect(() => {
|
|
34506
|
+
analytics.onAnalyticsEvent({
|
|
34507
|
+
type: "perseus:interactive-graph-widget:rendered",
|
|
34508
|
+
payload: {
|
|
34509
|
+
type
|
|
34510
|
+
}
|
|
34511
|
+
});
|
|
34512
|
+
});
|
|
34452
34513
|
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
34453
34514
|
value: {
|
|
34454
34515
|
range: state.range,
|
|
@@ -35233,11 +35294,14 @@ function doFocusPoint(state, action) {
|
|
|
35233
35294
|
function doBlurPoint(state, action) {
|
|
35234
35295
|
switch (state.type) {
|
|
35235
35296
|
case "point":
|
|
35236
|
-
|
|
35297
|
+
const nextState = {
|
|
35237
35298
|
...state,
|
|
35238
|
-
focusedPointIndex: null,
|
|
35239
35299
|
showRemovePointButton: false
|
|
35240
35300
|
};
|
|
35301
|
+
if (state.interactionMode === "mouse") {
|
|
35302
|
+
nextState.focusedPointIndex = null;
|
|
35303
|
+
}
|
|
35304
|
+
return nextState;
|
|
35241
35305
|
default:
|
|
35242
35306
|
return state;
|
|
35243
35307
|
}
|
|
@@ -35640,17 +35704,24 @@ function doAddPoint(state, action) {
|
|
|
35640
35704
|
...state,
|
|
35641
35705
|
hasBeenInteractedWith: true,
|
|
35642
35706
|
coords: [...state.coords, snappedPoint],
|
|
35643
|
-
showRemovePointButton: false
|
|
35707
|
+
showRemovePointButton: false,
|
|
35708
|
+
focusedPointIndex: state.coords.length
|
|
35644
35709
|
};
|
|
35645
35710
|
}
|
|
35646
35711
|
function doRemovePoint(state, action) {
|
|
35647
35712
|
if (state.type !== "point") {
|
|
35648
35713
|
return state;
|
|
35649
35714
|
}
|
|
35715
|
+
let nextFocusedPointIndex;
|
|
35716
|
+
if (state.interactionMode === "mouse") {
|
|
35717
|
+
nextFocusedPointIndex = null;
|
|
35718
|
+
} else {
|
|
35719
|
+
nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
|
|
35720
|
+
}
|
|
35650
35721
|
return {
|
|
35651
35722
|
...state,
|
|
35652
35723
|
coords: state.coords.filter((_, i) => i !== action.index),
|
|
35653
|
-
focusedPointIndex:
|
|
35724
|
+
focusedPointIndex: nextFocusedPointIndex,
|
|
35654
35725
|
showRemovePointButton: false
|
|
35655
35726
|
};
|
|
35656
35727
|
}
|
|
@@ -36063,7 +36134,7 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
36063
36134
|
});
|
|
36064
36135
|
|
|
36065
36136
|
const eq$1 = Util.eq;
|
|
36066
|
-
const deepEq$
|
|
36137
|
+
const deepEq$2 = Util.deepEq;
|
|
36067
36138
|
function interactiveGraphValidator(userInput, rubric) {
|
|
36068
36139
|
// None-type graphs are not graded
|
|
36069
36140
|
if (userInput.type === "none" && rubric.correct.type === "none") {
|
|
@@ -36119,7 +36190,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36119
36190
|
const correctCoeffs = getQuadraticCoefficients(
|
|
36120
36191
|
// @ts-expect-error - TS2345 - Argument of type 'readonly Coord[] | undefined' is not assignable to parameter of type 'readonly Coord[]'.
|
|
36121
36192
|
rubric.correct.coords);
|
|
36122
|
-
if (deepEq$
|
|
36193
|
+
if (deepEq$2(guessCoeffs, correctCoeffs)) {
|
|
36123
36194
|
return {
|
|
36124
36195
|
type: "points",
|
|
36125
36196
|
earned: 1,
|
|
@@ -36135,7 +36206,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36135
36206
|
const canonicalGuessCoeffs = canonicalSineCoefficients$1(guessCoeffs);
|
|
36136
36207
|
const canonicalCorrectCoeffs = canonicalSineCoefficients$1(correctCoeffs);
|
|
36137
36208
|
// If the canonical coefficients match, it's correct.
|
|
36138
|
-
if (deepEq$
|
|
36209
|
+
if (deepEq$2(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
|
|
36139
36210
|
return {
|
|
36140
36211
|
type: "points",
|
|
36141
36212
|
earned: 1,
|
|
@@ -36144,7 +36215,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36144
36215
|
};
|
|
36145
36216
|
}
|
|
36146
36217
|
} else if (userInput.type === "circle" && rubric.correct.type === "circle") {
|
|
36147
|
-
if (deepEq$
|
|
36218
|
+
if (deepEq$2(userInput.center, rubric.correct.center) && eq$1(userInput.radius, rubric.correct.radius)) {
|
|
36148
36219
|
return {
|
|
36149
36220
|
type: "points",
|
|
36150
36221
|
earned: 1,
|
|
@@ -36166,7 +36237,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36166
36237
|
guess?.sort();
|
|
36167
36238
|
// @ts-expect-error - TS2339 - Property 'sort' does not exist on type 'readonly Coord[]'.
|
|
36168
36239
|
correct.sort();
|
|
36169
|
-
if (deepEq$
|
|
36240
|
+
if (deepEq$2(guess, correct)) {
|
|
36170
36241
|
return {
|
|
36171
36242
|
type: "points",
|
|
36172
36243
|
earned: 1,
|
|
@@ -36189,7 +36260,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36189
36260
|
/* exact */
|
|
36190
36261
|
guess.sort();
|
|
36191
36262
|
correct.sort();
|
|
36192
|
-
match = deepEq$
|
|
36263
|
+
match = deepEq$2(guess, correct);
|
|
36193
36264
|
}
|
|
36194
36265
|
if (match) {
|
|
36195
36266
|
return {
|
|
@@ -36205,7 +36276,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36205
36276
|
guess = ___default["default"].invoke(guess, "sort").sort();
|
|
36206
36277
|
// @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
36207
36278
|
correct = ___default["default"].invoke(correct, "sort").sort();
|
|
36208
|
-
if (deepEq$
|
|
36279
|
+
if (deepEq$2(guess, correct)) {
|
|
36209
36280
|
return {
|
|
36210
36281
|
type: "points",
|
|
36211
36282
|
earned: 1,
|
|
@@ -36218,7 +36289,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36218
36289
|
const correct = rubric.correct.coords;
|
|
36219
36290
|
if (
|
|
36220
36291
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'.
|
|
36221
|
-
deepEq$
|
|
36292
|
+
deepEq$2(guess[0], correct[0]) &&
|
|
36222
36293
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
36223
36294
|
collinear(correct[0], correct[1], guess[1])) {
|
|
36224
36295
|
return {
|
|
@@ -36249,7 +36320,7 @@ function interactiveGraphValidator(userInput, rubric) {
|
|
|
36249
36320
|
/* exact */
|
|
36250
36321
|
match =
|
|
36251
36322
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
36252
|
-
deepEq$
|
|
36323
|
+
deepEq$2(guess[1], correct[1]) &&
|
|
36253
36324
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
36254
36325
|
collinear(correct[1], correct[0], guess[0]) &&
|
|
36255
36326
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
@@ -43750,10 +43821,10 @@ var PhetSimulation$1 = {
|
|
|
43750
43821
|
};
|
|
43751
43822
|
|
|
43752
43823
|
const {
|
|
43753
|
-
deepEq
|
|
43824
|
+
deepEq: deepEq$1
|
|
43754
43825
|
} = Util;
|
|
43755
43826
|
function plotterValidator(userInput, rubric) {
|
|
43756
|
-
if (deepEq(userInput, rubric.starting)) {
|
|
43827
|
+
if (deepEq$1(userInput, rubric.starting)) {
|
|
43757
43828
|
return {
|
|
43758
43829
|
type: "invalid",
|
|
43759
43830
|
message: null
|
|
@@ -43761,7 +43832,7 @@ function plotterValidator(userInput, rubric) {
|
|
|
43761
43832
|
}
|
|
43762
43833
|
return {
|
|
43763
43834
|
type: "points",
|
|
43764
|
-
earned: deepEq(userInput, rubric.correct) ? 1 : 0,
|
|
43835
|
+
earned: deepEq$1(userInput, rubric.correct) ? 1 : 0,
|
|
43765
43836
|
total: 1,
|
|
43766
43837
|
message: null
|
|
43767
43838
|
};
|
|
@@ -45238,7 +45309,7 @@ const init = function (options) {
|
|
|
45238
45309
|
|
|
45239
45310
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45240
45311
|
const libName = "@khanacademy/perseus";
|
|
45241
|
-
const libVersion = "36.
|
|
45312
|
+
const libVersion = "36.1.1";
|
|
45242
45313
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45243
45314
|
|
|
45244
45315
|
const apiVersion = {
|
|
@@ -48426,6 +48497,38 @@ function injectWidgets(content, widgets, widgetProps) {
|
|
|
48426
48497
|
return context;
|
|
48427
48498
|
}
|
|
48428
48499
|
|
|
48500
|
+
/**
|
|
48501
|
+
* Looks through widgets to identify images that do not have alt text.
|
|
48502
|
+
*
|
|
48503
|
+
* We pass in the fuller perseusRenderer object to allow for the possibility
|
|
48504
|
+
* of expanding to include other img data from content & images in the future.
|
|
48505
|
+
*
|
|
48506
|
+
* @param {PerseusRenderer} perseusRenderer
|
|
48507
|
+
* @returns a stringified list of {widgetId, imageUrl} for imgs that don't have alt text
|
|
48508
|
+
*/
|
|
48509
|
+
function getImagesWithoutAltData(perseusRenderer) {
|
|
48510
|
+
if (!perseusRenderer.widgets) {
|
|
48511
|
+
return "";
|
|
48512
|
+
}
|
|
48513
|
+
const imgsWithoutAltData = [];
|
|
48514
|
+
Object.entries(perseusRenderer.widgets).forEach(_ref3 => {
|
|
48515
|
+
let [widgetId, widget] = _ref3;
|
|
48516
|
+
if (!widget.options) {
|
|
48517
|
+
return;
|
|
48518
|
+
}
|
|
48519
|
+
|
|
48520
|
+
// Add to imagesWithoutAltData if img alt is missing and
|
|
48521
|
+
// image has valid img url data.
|
|
48522
|
+
if (widget.type === "image" && !widget.options.alt && widget.options.backgroundImage?.url) {
|
|
48523
|
+
imgsWithoutAltData.push({
|
|
48524
|
+
widgetId,
|
|
48525
|
+
imgUrl: widget.options.backgroundImage.url
|
|
48526
|
+
});
|
|
48527
|
+
}
|
|
48528
|
+
});
|
|
48529
|
+
return JSON.stringify(imgsWithoutAltData);
|
|
48530
|
+
}
|
|
48531
|
+
|
|
48429
48532
|
/* Widgets that have individual answers */
|
|
48430
48533
|
const INDIVIDUAL_ANSWER_WIDGETS = ["interactive-graph", "categorizer", "grapher"];
|
|
48431
48534
|
|
|
@@ -48484,6 +48587,8 @@ const getValidWidgetIds = perseusItem => {
|
|
|
48484
48587
|
return wonderStuffCore.keys(widgets).filter(id => isWidgetIdInContent(perseusItem, id));
|
|
48485
48588
|
};
|
|
48486
48589
|
|
|
48590
|
+
const deepEq = Util.deepEq;
|
|
48591
|
+
|
|
48487
48592
|
/**
|
|
48488
48593
|
* Helper to parse PerseusItem JSON
|
|
48489
48594
|
* Why not just use JSON.parse? We want:
|
|
@@ -48493,7 +48598,87 @@ const getValidWidgetIds = perseusItem => {
|
|
|
48493
48598
|
* @returns {PerseusItem} the parsed PerseusItem object
|
|
48494
48599
|
*/
|
|
48495
48600
|
function parsePerseusItem(json) {
|
|
48496
|
-
|
|
48601
|
+
const randomPhrase = buildRandomPhrase();
|
|
48602
|
+
const randomHintPhrase = buildRandomPhrase();
|
|
48603
|
+
const randomString = buildRandomString();
|
|
48604
|
+
const testingObject = JSON.stringify({
|
|
48605
|
+
answerArea: {
|
|
48606
|
+
calculator: false,
|
|
48607
|
+
chi2Table: false,
|
|
48608
|
+
financialCalculatorMonthlyPayment: false,
|
|
48609
|
+
financialCalculatorTimeToPayOff: false,
|
|
48610
|
+
financialCalculatorTotalAmount: false,
|
|
48611
|
+
periodicTable: false,
|
|
48612
|
+
periodicTableWithKey: false,
|
|
48613
|
+
tTable: false,
|
|
48614
|
+
zTable: false
|
|
48615
|
+
},
|
|
48616
|
+
hints: [randomHintPhrase, `=${Math.floor(Math.random() * 50) + 1}`],
|
|
48617
|
+
itemDataVersion: {
|
|
48618
|
+
major: 0,
|
|
48619
|
+
minor: 1
|
|
48620
|
+
},
|
|
48621
|
+
question: {
|
|
48622
|
+
content: `${randomPhrase}`,
|
|
48623
|
+
images: {},
|
|
48624
|
+
widgets: {
|
|
48625
|
+
expression1: {
|
|
48626
|
+
alignment: "default",
|
|
48627
|
+
graded: false,
|
|
48628
|
+
options: {
|
|
48629
|
+
answerForms: [{
|
|
48630
|
+
considered: "wrong",
|
|
48631
|
+
form: false,
|
|
48632
|
+
key: 0,
|
|
48633
|
+
simplify: false,
|
|
48634
|
+
value: `${randomString}`
|
|
48635
|
+
}],
|
|
48636
|
+
ariaLabel: "Answer",
|
|
48637
|
+
buttonSets: ["basic"],
|
|
48638
|
+
functions: ["f", "g", "h"],
|
|
48639
|
+
static: true,
|
|
48640
|
+
times: false,
|
|
48641
|
+
visibleLabel: "Answer"
|
|
48642
|
+
},
|
|
48643
|
+
static: true,
|
|
48644
|
+
type: "expression",
|
|
48645
|
+
version: {
|
|
48646
|
+
major: 1,
|
|
48647
|
+
minor: 0
|
|
48648
|
+
}
|
|
48649
|
+
}
|
|
48650
|
+
}
|
|
48651
|
+
}
|
|
48652
|
+
});
|
|
48653
|
+
// @ts-expect-error TS2550: Property 'replaceAll' does not exist on type 'string'.
|
|
48654
|
+
const testJSON = buildTestData(testingObject.replaceAll('"', '\\"'));
|
|
48655
|
+
const parsedJSON = JSON.parse(testJSON);
|
|
48656
|
+
const parsedItemData = parsedJSON.data.assessmentItem.item.itemData;
|
|
48657
|
+
const isNotCheating = deepEq(parsedItemData, testingObject);
|
|
48658
|
+
if (isNotCheating) {
|
|
48659
|
+
return JSON.parse(json);
|
|
48660
|
+
}
|
|
48661
|
+
throw new Error("Something went wrong.");
|
|
48662
|
+
}
|
|
48663
|
+
function buildRandomString() {
|
|
48664
|
+
let randomString = "";
|
|
48665
|
+
const randomLength = Math.floor(Math.random() * 8) + 3;
|
|
48666
|
+
for (let i = 0; i < randomLength; i++) {
|
|
48667
|
+
const randomLetter = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
48668
|
+
randomString += randomLetter;
|
|
48669
|
+
}
|
|
48670
|
+
return randomString;
|
|
48671
|
+
}
|
|
48672
|
+
function buildRandomPhrase() {
|
|
48673
|
+
const phrases = [];
|
|
48674
|
+
const randomLength = Math.floor(Math.random() * 10) + 5;
|
|
48675
|
+
for (let i = 0; i < randomLength; i++) {
|
|
48676
|
+
phrases.push(buildRandomString());
|
|
48677
|
+
}
|
|
48678
|
+
return phrases.join(" ");
|
|
48679
|
+
}
|
|
48680
|
+
function buildTestData(testObject) {
|
|
48681
|
+
return `{"data":{"assessmentItem":{"__typename":"AssessmentItemOrError","error":null,"item":{"__typename":"AssessmentItem","id":"x890b3c70f3e8f4a6","itemData":"${testObject}","problemType":"Type 1","sha":"c7284a3ad65214b4e62bccce236d92f7f5d35941"}}}}`;
|
|
48497
48682
|
}
|
|
48498
48683
|
|
|
48499
48684
|
const genericPerseusItemData = {
|
|
@@ -48758,6 +48943,7 @@ exports.getAnswerFromUserInput = getAnswerFromUserInput;
|
|
|
48758
48943
|
exports.getAnswersFromWidgets = getAnswersFromWidgets;
|
|
48759
48944
|
exports.getCircleCoords = getCircleCoords;
|
|
48760
48945
|
exports.getCorrectAnswerForWidgetId = getCorrectAnswerForWidgetId;
|
|
48946
|
+
exports.getImagesWithoutAltData = getImagesWithoutAltData;
|
|
48761
48947
|
exports.getLineCoords = getLineCoords;
|
|
48762
48948
|
exports.getLinearSystemCoords = getLinearSystemCoords;
|
|
48763
48949
|
exports.getPointCoords = getPointCoords;
|