@khanacademy/perseus 43.1.0 → 45.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 +2 -23
- package/dist/basic-widgets.d.ts +2 -23
- package/dist/components/graph.d.ts +1 -0
- package/dist/components/icon.d.ts +0 -1
- package/dist/components/multi-button-group.d.ts +1 -0
- package/dist/components/tooltip.d.ts +1 -0
- package/dist/es/index.js +276 -212
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +4 -2
- package/dist/es/strings.js.map +1 -1
- package/dist/extra-widgets.d.ts +2 -23
- package/dist/index.d.ts +4 -2
- package/dist/index.js +273 -205
- package/dist/index.js.map +1 -1
- package/dist/interactive2/interactive-util.d.ts +1 -1
- package/dist/interactive2/movable-point-options.d.ts +2 -2
- package/dist/interactive2/movable-point.d.ts +7 -7
- package/dist/interactive2/objective_.d.ts +1 -1
- package/dist/jipt-paragraphs.d.ts +2 -2
- package/dist/perseus-api.d.ts +2 -77
- package/dist/perseus-types.d.ts +3 -10
- package/dist/renderer-util.d.ts +4 -2
- package/dist/renderer.d.ts +6 -10
- package/dist/server-item-renderer.d.ts +58 -50
- package/dist/strings.d.ts +1 -0
- package/dist/strings.js +4 -2
- package/dist/strings.js.map +1 -1
- package/dist/styles/global-styles.d.ts +0 -1
- package/dist/styles/shared.d.ts +0 -1
- package/dist/traversal.d.ts +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/util/a11y.d.ts +0 -1
- package/dist/util/debounce.d.ts +1 -1
- package/dist/util/parse-perseus-json/perseus-parsers/graded-group-widget.d.ts +2 -2
- package/dist/widgets/definition/definition.d.ts +1 -1
- package/dist/widgets/deprecated-standin/deprecated-standin.d.ts +1 -1
- package/dist/widgets/dropdown/dropdown.d.ts +9 -1
- package/dist/widgets/explanation/explanation.d.ts +1 -1
- package/dist/widgets/expression/expression.d.ts +92 -217
- package/dist/widgets/group/group.d.ts +1 -1
- package/dist/widgets/image/image.d.ts +1 -1
- package/dist/widgets/interaction/interaction.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/quadratic.d.ts +1 -1
- package/dist/widgets/label-image/answer-pill.d.ts +0 -1
- package/dist/widgets/label-image/label-image.d.ts +5 -65
- package/dist/widgets/label-image/marker.d.ts +0 -1
- package/dist/widgets/measurer/measurer.d.ts +1 -1
- package/dist/widgets/molecule/molecule.d.ts +1 -1
- package/dist/widgets/passage/passage-markdown.d.ts +2 -2
- package/dist/widgets/passage/passage.d.ts +1 -1
- package/dist/widgets/passage-ref/passage-ref.d.ts +1 -1
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +1 -1
- package/dist/widgets/radio/choice-icon/shared-styles.d.ts +0 -1
- package/dist/widgets/radio/choice-none-above.d.ts +1 -1
- package/dist/widgets/radio/radio.d.ts +2 -2
- package/dist/widgets/video/video.d.ts +1 -1
- package/package.json +2 -2
package/dist/es/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
|
4
4
|
import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
|
|
5
5
|
import { View, RenderStateRoot, UniqueIDProvider, useOnMountEffect, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
|
|
7
|
-
import { HeadingMedium, LabelSmall, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
7
|
+
import { HeadingMedium, LabelSmall, LabelLarge, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
8
8
|
import { StyleSheet, css } from 'aphrodite';
|
|
9
9
|
import classNames$1 from 'classnames';
|
|
10
10
|
import * as React from 'react';
|
|
@@ -249,7 +249,8 @@ const mockStrings = {
|
|
|
249
249
|
srInteractiveElements: ({
|
|
250
250
|
elements
|
|
251
251
|
}) => `Interactive elements: ${elements}`,
|
|
252
|
-
srNoInteractiveElements: "No interactive elements"
|
|
252
|
+
srNoInteractiveElements: "No interactive elements",
|
|
253
|
+
selectAnAnswer: "Select an answer"
|
|
253
254
|
};
|
|
254
255
|
|
|
255
256
|
/**
|
|
@@ -14608,9 +14609,9 @@ const pluck = function pluck(table, subKey) {
|
|
|
14608
14609
|
* });
|
|
14609
14610
|
* {a: 2, b: 3}
|
|
14610
14611
|
*/
|
|
14611
|
-
const mapObject$
|
|
14612
|
+
const mapObject$2 = function mapObject(obj, lambda) {
|
|
14612
14613
|
const result = {};
|
|
14613
|
-
|
|
14614
|
+
Object.keys(obj).forEach(key => {
|
|
14614
14615
|
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'K'.
|
|
14615
14616
|
result[key] = lambda(obj[key], key);
|
|
14616
14617
|
});
|
|
@@ -14627,14 +14628,14 @@ const mapObject$1 = function mapObject(obj, lambda) {
|
|
|
14627
14628
|
*/
|
|
14628
14629
|
const mapObjectFromArray = function mapObjectFromArray(arr, lambda) {
|
|
14629
14630
|
const result = {};
|
|
14630
|
-
|
|
14631
|
+
arr.forEach(elem => {
|
|
14631
14632
|
result[elem] = lambda(elem);
|
|
14632
14633
|
});
|
|
14633
14634
|
return result;
|
|
14634
14635
|
};
|
|
14635
14636
|
var objective_ = {
|
|
14636
14637
|
pluck: pluck,
|
|
14637
|
-
mapObject: mapObject$
|
|
14638
|
+
mapObject: mapObject$2,
|
|
14638
14639
|
mapObjectFromArray: mapObjectFromArray
|
|
14639
14640
|
};
|
|
14640
14641
|
|
|
@@ -16629,7 +16630,7 @@ class Graphie extends React.Component {
|
|
|
16629
16630
|
};
|
|
16630
16631
|
this._setupGraphie = () => {
|
|
16631
16632
|
this._removeMovables();
|
|
16632
|
-
const graphieDiv =
|
|
16633
|
+
const graphieDiv = this.graphieDivRef.current;
|
|
16633
16634
|
if (graphieDiv == null || graphieDiv instanceof Text) {
|
|
16634
16635
|
throw new Error("No graphie container div found");
|
|
16635
16636
|
}
|
|
@@ -18718,6 +18719,140 @@ class QuestionParagraph extends React.Component {
|
|
|
18718
18719
|
}
|
|
18719
18720
|
}
|
|
18720
18721
|
|
|
18722
|
+
// These are all the current widgets that require user-input and are supported for automatic scoring
|
|
18723
|
+
const QUESTION_WIDGETS = ["numeric-input", "input-number", "radio", "interactive-graph", "interactive-number-line", "categorizer", "plotter", "orderer", "protractor", "matcher", "sorter"];
|
|
18724
|
+
|
|
18725
|
+
/**
|
|
18726
|
+
* Regex for widget placeholders in a string.
|
|
18727
|
+
*
|
|
18728
|
+
* First capture group is the widget ID (ex. 'radio 1')
|
|
18729
|
+
* Second capture group is the widget type (ex. "radio)
|
|
18730
|
+
* exec return will look like: ['[[☃ radio 1]]', 'radio 1', 'radio']
|
|
18731
|
+
*/
|
|
18732
|
+
function getWidgetRegex() {
|
|
18733
|
+
return /\[\[☃ ([A-Za-z0-9- ]+)\]\]/g;
|
|
18734
|
+
}
|
|
18735
|
+
|
|
18736
|
+
/**
|
|
18737
|
+
* Add a widget placeholder using the widget ID.
|
|
18738
|
+
* ex. addWidget("radio 1") => "[[☃ radio 1]]"
|
|
18739
|
+
*
|
|
18740
|
+
* @param {string} id
|
|
18741
|
+
* @returns {string}
|
|
18742
|
+
*/
|
|
18743
|
+
function addWidget(id) {
|
|
18744
|
+
return `[[☃ ${id}]]`;
|
|
18745
|
+
}
|
|
18746
|
+
|
|
18747
|
+
/**
|
|
18748
|
+
* Get a widget type by a widget's ID
|
|
18749
|
+
* (please don't derive type from ID)
|
|
18750
|
+
*
|
|
18751
|
+
* @param {string} widgetId the ID of the widget
|
|
18752
|
+
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
18753
|
+
* @returns {string} the widget type (ie "radio")
|
|
18754
|
+
*/
|
|
18755
|
+
function getWidgetTypeByWidgetId(WidgetId, widgetMap) {
|
|
18756
|
+
var _widget$type;
|
|
18757
|
+
const widget = widgetMap[WidgetId];
|
|
18758
|
+
return (_widget$type = widget == null ? void 0 : widget.type) != null ? _widget$type : null;
|
|
18759
|
+
}
|
|
18760
|
+
|
|
18761
|
+
/**
|
|
18762
|
+
* Does the content have a specific type of widget?
|
|
18763
|
+
*
|
|
18764
|
+
* @param {string} type the type of the widget in question (ie "radio")
|
|
18765
|
+
* @param {string} content the string to search through
|
|
18766
|
+
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
18767
|
+
* @returns {boolean} if the content includes the widget type
|
|
18768
|
+
*/
|
|
18769
|
+
function contentHasWidgetType(type, content, widgetMap) {
|
|
18770
|
+
return getWidgetIdsFromContentByType(type, content, widgetMap).length > 0;
|
|
18771
|
+
}
|
|
18772
|
+
|
|
18773
|
+
/**
|
|
18774
|
+
* Extract all widget IDs, which includes the widget type and instance number.
|
|
18775
|
+
* example output: ['radio 1', 'categorizer 1', 'categorizor 2']
|
|
18776
|
+
*
|
|
18777
|
+
* Content should contain Perseus widget placeholders,
|
|
18778
|
+
* which look like: '[[☃ radio 1]]'.
|
|
18779
|
+
*
|
|
18780
|
+
* @param {string} content
|
|
18781
|
+
* @returns {ReadonlyArray<string>} widgetIds
|
|
18782
|
+
*/
|
|
18783
|
+
function getWidgetIdsFromContent(content) {
|
|
18784
|
+
const widgets = [];
|
|
18785
|
+
const localWidgetRegex = getWidgetRegex();
|
|
18786
|
+
let match = localWidgetRegex.exec(content);
|
|
18787
|
+
while (match !== null) {
|
|
18788
|
+
widgets.push(match[1]);
|
|
18789
|
+
match = localWidgetRegex.exec(content);
|
|
18790
|
+
}
|
|
18791
|
+
return widgets;
|
|
18792
|
+
}
|
|
18793
|
+
|
|
18794
|
+
/**
|
|
18795
|
+
* Get a list of widget IDs from content,
|
|
18796
|
+
* but only for specific widget types
|
|
18797
|
+
*
|
|
18798
|
+
* @param {string} type the type of widget (ie "radio")
|
|
18799
|
+
* @param {string} content the string to parse
|
|
18800
|
+
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
18801
|
+
* @returns {ReadonlyArray<string>} the widget type (ie "radio")
|
|
18802
|
+
*/
|
|
18803
|
+
function getWidgetIdsFromContentByType(type, content, widgetMap) {
|
|
18804
|
+
const rv = [];
|
|
18805
|
+
const widgetIdsInContent = getWidgetIdsFromContent(content);
|
|
18806
|
+
widgetIdsInContent.forEach(widgetId => {
|
|
18807
|
+
const widget = widgetMap[widgetId];
|
|
18808
|
+
if ((widget == null ? void 0 : widget.type) === type) {
|
|
18809
|
+
rv.push(widgetId);
|
|
18810
|
+
}
|
|
18811
|
+
});
|
|
18812
|
+
return rv;
|
|
18813
|
+
}
|
|
18814
|
+
|
|
18815
|
+
/**
|
|
18816
|
+
* Pull the widget map out of ItemData
|
|
18817
|
+
*
|
|
18818
|
+
* @param {PerseusItem} PerseusItem containing a widgetMap
|
|
18819
|
+
* @returns {WidgetMap} the widget map in the PerseusItem
|
|
18820
|
+
*/
|
|
18821
|
+
function getWidgetsMapFromItemData(itemData) {
|
|
18822
|
+
return itemData.question.widgets;
|
|
18823
|
+
}
|
|
18824
|
+
|
|
18825
|
+
/**
|
|
18826
|
+
* Get the widget information from a WidgetMap
|
|
18827
|
+
*
|
|
18828
|
+
* @param {string} widgetId the ID of the widget
|
|
18829
|
+
* @returns {PerseusWidget | null} the widget data if it exists, otherwise null
|
|
18830
|
+
*/
|
|
18831
|
+
function getWidgetFromWidgetMap(widgetId, widgetMap) {
|
|
18832
|
+
var _widgetMap$widgetId;
|
|
18833
|
+
return (_widgetMap$widgetId = widgetMap[widgetId]) != null ? _widgetMap$widgetId : null;
|
|
18834
|
+
}
|
|
18835
|
+
|
|
18836
|
+
/**
|
|
18837
|
+
* Get select widgets from a widget map.
|
|
18838
|
+
* Useful for multi-items that needs to split
|
|
18839
|
+
* one PerseusItem into several
|
|
18840
|
+
*
|
|
18841
|
+
* @param {ReadonlyArray<string>} widgetIds to extract
|
|
18842
|
+
* @param {PerseusWidgetsMap} widgetMap to extract from
|
|
18843
|
+
* @return {PerseusWidgetsMap} a new widget map with requested widgets
|
|
18844
|
+
*/
|
|
18845
|
+
function getWidgetsFromWidgetMap(widgetIds, widgetMap) {
|
|
18846
|
+
const widgets = {};
|
|
18847
|
+
widgetIds.forEach(widgetId => {
|
|
18848
|
+
const widget = getWidgetFromWidgetMap(widgetId, widgetMap);
|
|
18849
|
+
if (widget) {
|
|
18850
|
+
widgets[widgetId] = widget;
|
|
18851
|
+
}
|
|
18852
|
+
});
|
|
18853
|
+
return widgets;
|
|
18854
|
+
}
|
|
18855
|
+
|
|
18721
18856
|
const DEFAULT_ALIGNMENT$1 = "block";
|
|
18722
18857
|
// NOTE(kevinb): "default" is not one in `validAlignments`.
|
|
18723
18858
|
const DEFAULT_SUPPORTED_ALIGNMENTS = ["default"];
|
|
@@ -19149,12 +19284,35 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
19149
19284
|
isLintable: isLintable
|
|
19150
19285
|
});
|
|
19151
19286
|
|
|
19287
|
+
const {
|
|
19288
|
+
mapObject: mapObject$1
|
|
19289
|
+
} = objective_;
|
|
19290
|
+
function getUpgradedWidgetOptions(oldWidgetOptions) {
|
|
19291
|
+
// @ts-expect-error - TS2322 - Type '(props: Props) => Partial<Record<string, CategorizerWidget | CSProgramWidget | DefinitionWidget | DropdownWidget | ... 35 more ... | VideoWidget>>' is not assignable to type '(props: Props) => { [key: string]: PerseusWidget; }'.
|
|
19292
|
+
return mapObject$1(oldWidgetOptions, (widgetInfo, widgetId) => {
|
|
19293
|
+
if (!widgetInfo.type || !widgetInfo.alignment) {
|
|
19294
|
+
const newValues = {};
|
|
19295
|
+
if (!widgetInfo.type) {
|
|
19296
|
+
// TODO: why does widget have no type?
|
|
19297
|
+
// We don't want to derive type from widget ID
|
|
19298
|
+
// see: LEMS-1845
|
|
19299
|
+
newValues.type = widgetId.split(" ")[0];
|
|
19300
|
+
}
|
|
19301
|
+
if (!widgetInfo.alignment) {
|
|
19302
|
+
newValues.alignment = "default";
|
|
19303
|
+
}
|
|
19304
|
+
widgetInfo = _extends({}, widgetInfo, newValues);
|
|
19305
|
+
}
|
|
19306
|
+
return upgradeWidgetInfoToLatestVersion(widgetInfo);
|
|
19307
|
+
});
|
|
19308
|
+
}
|
|
19152
19309
|
function emptyWidgetsFunctional(widgets,
|
|
19153
19310
|
// This is a port of old code, I'm not sure why
|
|
19154
19311
|
// we need widgetIds vs the keys of the widgets object
|
|
19155
19312
|
widgetIds, userInputMap, strings, locale) {
|
|
19313
|
+
const upgradedWidgets = getUpgradedWidgetOptions(widgets);
|
|
19156
19314
|
return widgetIds.filter(id => {
|
|
19157
|
-
const widget =
|
|
19315
|
+
const widget = upgradedWidgets[id];
|
|
19158
19316
|
if (!widget || widget.static) {
|
|
19159
19317
|
// Static widgets shouldn't count as empty
|
|
19160
19318
|
return false;
|
|
@@ -19173,12 +19331,27 @@ widgetIds, userInputMap, strings, locale) {
|
|
|
19173
19331
|
}
|
|
19174
19332
|
});
|
|
19175
19333
|
}
|
|
19334
|
+
|
|
19335
|
+
// TODO: combine scorePerseusItem with scoreWidgetsFunctional
|
|
19336
|
+
// once scorePerseusItem is the only one calling scoreWidgetsFunctional
|
|
19337
|
+
function scorePerseusItem(perseusRenderData, userInputMap,
|
|
19338
|
+
// TODO(LEMS-2461,LEMS-2391): these probably
|
|
19339
|
+
// need to be removed before we move this to the server
|
|
19340
|
+
strings, locale) {
|
|
19341
|
+
// There seems to be a chance that PerseusRenderer.widgets might include
|
|
19342
|
+
// widget data for widgets that are not in PerseusRenderer.content,
|
|
19343
|
+
// so this checks that the widgets are being used before scoring them
|
|
19344
|
+
const usedWidgetIds = getWidgetIdsFromContent(perseusRenderData.content);
|
|
19345
|
+
const scores = scoreWidgetsFunctional(perseusRenderData.widgets, usedWidgetIds, userInputMap, strings, locale);
|
|
19346
|
+
return Util.flattenScores(scores);
|
|
19347
|
+
}
|
|
19176
19348
|
function scoreWidgetsFunctional(widgets,
|
|
19177
19349
|
// This is a port of old code, I'm not sure why
|
|
19178
19350
|
// we need widgetIds vs the keys of the widgets object
|
|
19179
19351
|
widgetIds, userInputMap, strings, locale) {
|
|
19352
|
+
const upgradedWidgets = getUpgradedWidgetOptions(widgets);
|
|
19180
19353
|
const gradedWidgetIds = widgetIds.filter(id => {
|
|
19181
|
-
const props =
|
|
19354
|
+
const props = upgradedWidgets[id];
|
|
19182
19355
|
const widgetIsGraded = (props == null ? void 0 : props.graded) == null || props.graded;
|
|
19183
19356
|
const widgetIsStatic = !!(props != null && props.static);
|
|
19184
19357
|
// Ungraded widgets or widgets set to static shouldn't be graded.
|
|
@@ -19186,14 +19359,14 @@ widgetIds, userInputMap, strings, locale) {
|
|
|
19186
19359
|
});
|
|
19187
19360
|
const widgetScores = {};
|
|
19188
19361
|
gradedWidgetIds.forEach(id => {
|
|
19189
|
-
const widget =
|
|
19362
|
+
const widget = upgradedWidgets[id];
|
|
19190
19363
|
if (!widget) {
|
|
19191
19364
|
return;
|
|
19192
19365
|
}
|
|
19193
19366
|
const userInput = userInputMap[id];
|
|
19194
19367
|
const scorer = getWidgetScorer(widget.type);
|
|
19195
19368
|
if (widget.type === "group") {
|
|
19196
|
-
const scores = scoreWidgetsFunctional(widget.options.widgets,
|
|
19369
|
+
const scores = scoreWidgetsFunctional(widget.options.widgets, getWidgetIdsFromContent(widget.options.content), userInputMap[id], strings, locale);
|
|
19197
19370
|
widgetScores[id] = Util.flattenScores(scores);
|
|
19198
19371
|
} else if (scorer) {
|
|
19199
19372
|
widgetScores[id] = scorer(userInput, widget.options, strings, locale);
|
|
@@ -19555,31 +19728,12 @@ class Renderer extends React.Component {
|
|
|
19555
19728
|
return _extends({}, ApiOptions.defaults, this.props.apiOptions);
|
|
19556
19729
|
};
|
|
19557
19730
|
this._getInitialWidgetState = props => {
|
|
19558
|
-
const allWidgetInfo =
|
|
19731
|
+
const allWidgetInfo = getUpgradedWidgetOptions(props.widgets);
|
|
19559
19732
|
return {
|
|
19560
19733
|
widgetInfo: allWidgetInfo,
|
|
19561
19734
|
widgetProps: this._getAllWidgetsStartProps(allWidgetInfo, props)
|
|
19562
19735
|
};
|
|
19563
19736
|
};
|
|
19564
|
-
// @ts-expect-error - TS2322 - Type '(props: Props) => Partial<Record<string, CategorizerWidget | CSProgramWidget | DefinitionWidget | DropdownWidget | ... 35 more ... | VideoWidget>>' is not assignable to type '(props: Props) => { [key: string]: PerseusWidget; }'.
|
|
19565
|
-
this._getAllWidgetsInfo = props => {
|
|
19566
|
-
return mapObject(props.widgets, (widgetInfo, widgetId) => {
|
|
19567
|
-
if (!widgetInfo.type || !widgetInfo.alignment) {
|
|
19568
|
-
const newValues = {};
|
|
19569
|
-
if (!widgetInfo.type) {
|
|
19570
|
-
// TODO: why does widget have no type?
|
|
19571
|
-
// We don't want to derive type from widget ID
|
|
19572
|
-
// see: LEMS-1845
|
|
19573
|
-
newValues.type = widgetId.split(" ")[0];
|
|
19574
|
-
}
|
|
19575
|
-
if (!widgetInfo.alignment) {
|
|
19576
|
-
newValues.alignment = "default";
|
|
19577
|
-
}
|
|
19578
|
-
widgetInfo = _.extend({}, widgetInfo, newValues);
|
|
19579
|
-
}
|
|
19580
|
-
return upgradeWidgetInfoToLatestVersion(widgetInfo);
|
|
19581
|
-
});
|
|
19582
|
-
};
|
|
19583
19737
|
this._getAllWidgetsStartProps = (allWidgetInfo, props) => {
|
|
19584
19738
|
const {
|
|
19585
19739
|
apiOptions,
|
|
@@ -20025,7 +20179,7 @@ class Renderer extends React.Component {
|
|
|
20025
20179
|
// Instead, we center them with css magic in styles.less
|
|
20026
20180
|
// /cry(aria)
|
|
20027
20181
|
this._foundTextNodes = true;
|
|
20028
|
-
if (
|
|
20182
|
+
if (this.widgetIds.includes(node.id)) {
|
|
20029
20183
|
// We don't want to render a duplicate widget key/ref,
|
|
20030
20184
|
// as this causes problems with react (for obvious
|
|
20031
20185
|
// reasons). Instead we just notify the
|
|
@@ -20329,7 +20483,7 @@ class Renderer extends React.Component {
|
|
|
20329
20483
|
};
|
|
20330
20484
|
this.getInputPaths = () => {
|
|
20331
20485
|
const inputPaths = [];
|
|
20332
|
-
|
|
20486
|
+
this.widgetIds.forEach(widgetId => {
|
|
20333
20487
|
const widget = this.getWidgetInstance(widgetId);
|
|
20334
20488
|
if (widget && widget.getInputPaths) {
|
|
20335
20489
|
// Grab all input paths and add widgetID to the front
|
|
@@ -20337,7 +20491,7 @@ class Renderer extends React.Component {
|
|
|
20337
20491
|
// Prefix paths with their widgetID and add to collective
|
|
20338
20492
|
// list of paths.
|
|
20339
20493
|
// @ts-expect-error - TS2345 - Argument of type '(inputPath: string) => void' is not assignable to parameter of type 'CollectionIterator<FocusPath, void, readonly FocusPath[]>'.
|
|
20340
|
-
|
|
20494
|
+
widgetInputPaths.forEach(inputPath => {
|
|
20341
20495
|
const relativeInputPath = [widgetId].concat(inputPath);
|
|
20342
20496
|
inputPaths.push(relativeInputPath);
|
|
20343
20497
|
});
|
|
@@ -20466,12 +20620,20 @@ class Renderer extends React.Component {
|
|
|
20466
20620
|
this.getWidgetIds = () => {
|
|
20467
20621
|
return this.widgetIds;
|
|
20468
20622
|
};
|
|
20623
|
+
/**
|
|
20624
|
+
* @deprecated use scorePerseusItem
|
|
20625
|
+
*/
|
|
20626
|
+
this.guessAndScore = () => {
|
|
20627
|
+
const totalGuess = this.getUserInput();
|
|
20628
|
+
const totalScore = this.score();
|
|
20629
|
+
return [totalGuess, totalScore];
|
|
20630
|
+
};
|
|
20469
20631
|
this.examples = () => {
|
|
20470
20632
|
const widgetIds = this.widgetIds;
|
|
20471
|
-
const examples =
|
|
20633
|
+
const examples = widgetIds.map(widgetId => {
|
|
20472
20634
|
const widget = this.getWidgetInstance(widgetId);
|
|
20473
20635
|
return widget != null && widget.examples ? widget.examples() : null;
|
|
20474
|
-
}));
|
|
20636
|
+
}).filter(Boolean);
|
|
20475
20637
|
|
|
20476
20638
|
// no widgets with examples
|
|
20477
20639
|
if (!examples.length) {
|
|
@@ -20726,27 +20888,15 @@ class Renderer extends React.Component {
|
|
|
20726
20888
|
}
|
|
20727
20889
|
|
|
20728
20890
|
/**
|
|
20729
|
-
*
|
|
20730
|
-
*
|
|
20731
|
-
*
|
|
20732
|
-
*/
|
|
20733
|
-
scoreWidgets() {
|
|
20734
|
-
return scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20735
|
-
}
|
|
20736
|
-
|
|
20737
|
-
/**
|
|
20738
|
-
* Grades the content.
|
|
20891
|
+
* Scores the content.
|
|
20892
|
+
*
|
|
20893
|
+
* @deprecated use scorePerseusItem
|
|
20739
20894
|
*/
|
|
20740
20895
|
score() {
|
|
20741
|
-
const scores = this.
|
|
20896
|
+
const scores = scoreWidgetsFunctional(this.state.widgetInfo, this.widgetIds, this.getUserInputMap(), this.props.strings, this.context.locale);
|
|
20742
20897
|
const combinedScore = Util.flattenScores(scores);
|
|
20743
20898
|
return combinedScore;
|
|
20744
20899
|
}
|
|
20745
|
-
guessAndScore() {
|
|
20746
|
-
const totalGuess = this.getUserInput();
|
|
20747
|
-
const totalScore = this.score();
|
|
20748
|
-
return [totalGuess, totalScore];
|
|
20749
|
-
}
|
|
20750
20900
|
render() {
|
|
20751
20901
|
const apiOptions = this.getApiOptions();
|
|
20752
20902
|
if (this.reuseMarkdown) {
|
|
@@ -21135,6 +21285,7 @@ const HORIZONTAL_ALIGNMNENTS = {
|
|
|
21135
21285
|
class Tooltip extends React.Component {
|
|
21136
21286
|
constructor(...args) {
|
|
21137
21287
|
super(...args);
|
|
21288
|
+
this.tooltipContainerRef = /*#__PURE__*/React.createRef();
|
|
21138
21289
|
this.state = {
|
|
21139
21290
|
height: null // used for offsetting "top" positioned tooltips
|
|
21140
21291
|
};
|
|
@@ -21209,8 +21360,7 @@ class Tooltip extends React.Component {
|
|
|
21209
21360
|
display: this.props.show ? "block" : "none"
|
|
21210
21361
|
}
|
|
21211
21362
|
}, /*#__PURE__*/React.createElement("div", {
|
|
21212
|
-
|
|
21213
|
-
ref: "tooltipContainer",
|
|
21363
|
+
ref: this.tooltipContainerRef,
|
|
21214
21364
|
className: "tooltipContainer",
|
|
21215
21365
|
style: {
|
|
21216
21366
|
position: "absolute",
|
|
@@ -21237,10 +21387,8 @@ class Tooltip extends React.Component {
|
|
|
21237
21387
|
}, this.props.children.slice(1)), arrowBelow));
|
|
21238
21388
|
}
|
|
21239
21389
|
_updateHeight() {
|
|
21240
|
-
const tooltipContainer =
|
|
21241
|
-
|
|
21242
|
-
this.refs.tooltipContainer);
|
|
21243
|
-
const height = tooltipContainer.offsetHeight;
|
|
21390
|
+
const tooltipContainer = this.tooltipContainerRef.current;
|
|
21391
|
+
const height = (tooltipContainer == null ? void 0 : tooltipContainer.offsetHeight) || 0;
|
|
21244
21392
|
if (height !== this.state.height) {
|
|
21245
21393
|
this.setState({
|
|
21246
21394
|
height
|
|
@@ -27224,23 +27372,40 @@ class Dropdown extends React.Component {
|
|
|
27224
27372
|
value: String(i + 1),
|
|
27225
27373
|
label: choice
|
|
27226
27374
|
}))];
|
|
27227
|
-
return /*#__PURE__*/React.createElement(
|
|
27228
|
-
|
|
27229
|
-
|
|
27375
|
+
return /*#__PURE__*/React.createElement(UniqueIDProvider, {
|
|
27376
|
+
scope: "dropdown-widget",
|
|
27377
|
+
mockOnFirstRender: true
|
|
27378
|
+
}, ids => /*#__PURE__*/React.createElement(View
|
|
27379
|
+
// NOTE(jared): These are required to prevent weird behavior
|
|
27380
|
+
// When there's a dropdown in a zoomable table.
|
|
27381
|
+
, {
|
|
27230
27382
|
onClick: e => {
|
|
27231
27383
|
e.stopPropagation();
|
|
27232
27384
|
},
|
|
27233
27385
|
onTouchStart: e => {
|
|
27234
27386
|
e.stopPropagation();
|
|
27235
27387
|
}
|
|
27236
|
-
}, /*#__PURE__*/React.createElement(
|
|
27388
|
+
}, this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelLarge, {
|
|
27389
|
+
tag: "label",
|
|
27390
|
+
id: ids.get("dropdown-label")
|
|
27391
|
+
}, this.props.visibleLabel), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
27392
|
+
id: ids.get("dropdown"),
|
|
27237
27393
|
placeholder: "",
|
|
27238
27394
|
onChange: value => this._handleChange(parseInt(value)),
|
|
27239
27395
|
selectedValue: String(this.props.selected),
|
|
27240
|
-
disabled: this.props.apiOptions.readOnly
|
|
27241
|
-
|
|
27396
|
+
disabled: this.props.apiOptions.readOnly,
|
|
27397
|
+
"aria-label": this.props.ariaLabel || this.context.strings.selectAnAnswer,
|
|
27398
|
+
"aria-labelledby": ids.get("dropdown-label")
|
|
27399
|
+
// This is currently necessary for SRs to read the labels properly.
|
|
27400
|
+
// However, WB is working on a change to add the "combobox" role to
|
|
27401
|
+
// all dropdowns.
|
|
27402
|
+
// See https://khanacademy.atlassian.net/browse/WB-1671
|
|
27403
|
+
,
|
|
27404
|
+
role: "combobox"
|
|
27405
|
+
}, children)));
|
|
27242
27406
|
}
|
|
27243
27407
|
}
|
|
27408
|
+
Dropdown.contextType = PerseusI18nContext;
|
|
27244
27409
|
Dropdown.defaultProps = {
|
|
27245
27410
|
choices: [],
|
|
27246
27411
|
selected: 0,
|
|
@@ -27250,6 +27415,8 @@ Dropdown.defaultProps = {
|
|
|
27250
27415
|
const optionsTransform = widgetOptions => {
|
|
27251
27416
|
return {
|
|
27252
27417
|
placeholder: widgetOptions.placeholder,
|
|
27418
|
+
visibleLabel: widgetOptions.visibleLabel,
|
|
27419
|
+
ariaLabel: widgetOptions.ariaLabel,
|
|
27253
27420
|
choices: widgetOptions.choices.map(choice => choice.content)
|
|
27254
27421
|
};
|
|
27255
27422
|
};
|
|
@@ -29309,6 +29476,9 @@ class Group extends React.Component {
|
|
|
29309
29476
|
this.change("widgets", this.rendererRef.props.widgets);
|
|
29310
29477
|
}
|
|
29311
29478
|
};
|
|
29479
|
+
|
|
29480
|
+
// TODO(LEMS-2391): replace this when there's a separate check
|
|
29481
|
+
// for valid/invalid state
|
|
29312
29482
|
const score = (_this$rendererRef12 = this.rendererRef) == null ? void 0 : _this$rendererRef12.score();
|
|
29313
29483
|
const isValid = score && score.type !== "invalid";
|
|
29314
29484
|
const isInvalid = score && score.type === "invalid";
|
|
@@ -30345,6 +30515,7 @@ function numSteps$1(range, step) {
|
|
|
30345
30515
|
class Graph extends React.Component {
|
|
30346
30516
|
constructor(...args) {
|
|
30347
30517
|
super(...args);
|
|
30518
|
+
this.graphieDivRef = /*#__PURE__*/React.createRef();
|
|
30348
30519
|
this.protractor = void 0;
|
|
30349
30520
|
this.ruler = void 0;
|
|
30350
30521
|
this._graphie = void 0;
|
|
@@ -30388,9 +30559,7 @@ class Graph extends React.Component {
|
|
|
30388
30559
|
if (this._hasSetupGraphieThisUpdate) {
|
|
30389
30560
|
return;
|
|
30390
30561
|
}
|
|
30391
|
-
|
|
30392
|
-
// eslint-disable-next-line react/no-string-refs
|
|
30393
|
-
const graphieDiv = ReactDOM__default.findDOMNode(this.refs.graphieDiv);
|
|
30562
|
+
const graphieDiv = this.graphieDivRef.current;
|
|
30394
30563
|
// @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'empty' does not exist on type 'JQueryStatic'.
|
|
30395
30564
|
$(graphieDiv).empty();
|
|
30396
30565
|
|
|
@@ -30598,7 +30767,7 @@ class Graph extends React.Component {
|
|
|
30598
30767
|
onClick: this.onClick
|
|
30599
30768
|
}, image, /*#__PURE__*/React.createElement("div", {
|
|
30600
30769
|
className: "graphie",
|
|
30601
|
-
ref:
|
|
30770
|
+
ref: this.graphieDivRef
|
|
30602
30771
|
}));
|
|
30603
30772
|
}
|
|
30604
30773
|
}
|
|
@@ -31686,6 +31855,7 @@ class InfoTip extends React.Component {
|
|
|
31686
31855
|
class MultiButtonGroup extends React.Component {
|
|
31687
31856
|
constructor(...args) {
|
|
31688
31857
|
super(...args);
|
|
31858
|
+
this.buttonContainerRef = /*#__PURE__*/React.createRef();
|
|
31689
31859
|
this.toggleSelect = newValue => {
|
|
31690
31860
|
const values = (this.props.values || []).slice(0);
|
|
31691
31861
|
const allowEmpty = this.props.allowEmpty;
|
|
@@ -31702,9 +31872,8 @@ class MultiButtonGroup extends React.Component {
|
|
|
31702
31872
|
};
|
|
31703
31873
|
}
|
|
31704
31874
|
focus() {
|
|
31705
|
-
var
|
|
31706
|
-
|
|
31707
|
-
(_ReactDOM$findDOMNode = ReactDOM.findDOMNode(this)) == null || _ReactDOM$findDOMNode.focus();
|
|
31875
|
+
var _this$buttonContainer;
|
|
31876
|
+
(_this$buttonContainer = this.buttonContainerRef.current) == null || _this$buttonContainer.focus();
|
|
31708
31877
|
return true;
|
|
31709
31878
|
}
|
|
31710
31879
|
render() {
|
|
@@ -31725,7 +31894,8 @@ class MultiButtonGroup extends React.Component {
|
|
|
31725
31894
|
display: "inline-block"
|
|
31726
31895
|
};
|
|
31727
31896
|
return /*#__PURE__*/React.createElement("div", {
|
|
31728
|
-
style: outerStyle
|
|
31897
|
+
style: outerStyle,
|
|
31898
|
+
ref: this.buttonContainerRef
|
|
31729
31899
|
}, buttons);
|
|
31730
31900
|
}
|
|
31731
31901
|
}
|
|
@@ -44843,7 +45013,7 @@ const init = function init() {
|
|
|
44843
45013
|
|
|
44844
45014
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44845
45015
|
const libName = "@khanacademy/perseus";
|
|
44846
|
-
const libVersion = "
|
|
45016
|
+
const libVersion = "45.0.0";
|
|
44847
45017
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44848
45018
|
|
|
44849
45019
|
const apiVersion = {
|
|
@@ -45467,6 +45637,13 @@ class ServerItemRenderer extends React.Component {
|
|
|
45467
45637
|
this.props.onRendered(true);
|
|
45468
45638
|
}
|
|
45469
45639
|
}
|
|
45640
|
+
if (this.props.score && this.props.score !== prevProps.score) {
|
|
45641
|
+
const emptyQuestionAreaWidgets = this.questionRenderer.emptyWidgets();
|
|
45642
|
+
this.setState({
|
|
45643
|
+
questionCompleted: this.props.score.correct,
|
|
45644
|
+
questionHighlightedWidgets: emptyQuestionAreaWidgets
|
|
45645
|
+
});
|
|
45646
|
+
}
|
|
45470
45647
|
}
|
|
45471
45648
|
componentWillUnmount() {
|
|
45472
45649
|
if (this.blurTimeoutID != null) {
|
|
@@ -45584,18 +45761,37 @@ class ServerItemRenderer extends React.Component {
|
|
|
45584
45761
|
return this.questionRenderer.getPromptJSON();
|
|
45585
45762
|
}
|
|
45586
45763
|
|
|
45764
|
+
/**
|
|
45765
|
+
* Returns an array of the widget `.getUserInput()` results
|
|
45766
|
+
*
|
|
45767
|
+
* TODO: can we remove this? Seems to be just for backwards
|
|
45768
|
+
* compatibility with old Perseus Chrome logging
|
|
45769
|
+
* @deprecated use getUserInput
|
|
45770
|
+
*/
|
|
45771
|
+
getUserInputLegacy() {
|
|
45772
|
+
return this.questionRenderer.getUserInput();
|
|
45773
|
+
}
|
|
45774
|
+
|
|
45775
|
+
/**
|
|
45776
|
+
* Returns an object of the widget `.getUserInput()` results
|
|
45777
|
+
*/
|
|
45778
|
+
getUserInput() {
|
|
45779
|
+
return this.questionRenderer.getUserInputMap();
|
|
45780
|
+
}
|
|
45781
|
+
|
|
45587
45782
|
/**
|
|
45588
45783
|
* Grades the item.
|
|
45784
|
+
*
|
|
45785
|
+
* @deprecated use scorePerseusItem
|
|
45589
45786
|
*/
|
|
45590
45787
|
scoreInput() {
|
|
45591
|
-
const
|
|
45592
|
-
const
|
|
45593
|
-
const score = guessAndScore[1];
|
|
45788
|
+
const guess = this.getUserInput();
|
|
45789
|
+
const score = scorePerseusItem(this.props.item.question, guess, this.context.strings, this.context.locale);
|
|
45594
45790
|
|
|
45595
45791
|
// Continue to include an empty guess for the now defunct answer area.
|
|
45596
45792
|
// TODO(alex): Check whether we rely on the format here for
|
|
45597
45793
|
// analyzing ProblemLogs. If not, remove this layer.
|
|
45598
|
-
const maxCompatGuess = [
|
|
45794
|
+
const maxCompatGuess = [this.questionRenderer.getUserInput(), []];
|
|
45599
45795
|
const keScore = Util.keScoreFromPerseusScore(score, maxCompatGuess, this.questionRenderer.getSerializedState());
|
|
45600
45796
|
const emptyQuestionAreaWidgets = this.questionRenderer.emptyWidgets();
|
|
45601
45797
|
this.setState({
|
|
@@ -47443,140 +47639,6 @@ const registerAllWidgetsForTesting = () => {
|
|
|
47443
47639
|
replaceDeprecatedWidgets();
|
|
47444
47640
|
};
|
|
47445
47641
|
|
|
47446
|
-
// These are all the current widgets that require user-input and are supported for automatic scoring
|
|
47447
|
-
const QUESTION_WIDGETS = ["numeric-input", "input-number", "radio", "interactive-graph", "interactive-number-line", "categorizer", "plotter", "orderer", "protractor", "matcher", "sorter"];
|
|
47448
|
-
|
|
47449
|
-
/**
|
|
47450
|
-
* Regex for widget placeholders in a string.
|
|
47451
|
-
*
|
|
47452
|
-
* First capture group is the widget ID (ex. 'radio 1')
|
|
47453
|
-
* Second capture group is the widget type (ex. "radio)
|
|
47454
|
-
* exec return will look like: ['[[☃ radio 1]]', 'radio 1', 'radio']
|
|
47455
|
-
*/
|
|
47456
|
-
function getWidgetRegex() {
|
|
47457
|
-
return /\[\[☃ ([A-Za-z0-9- ]+)\]\]/g;
|
|
47458
|
-
}
|
|
47459
|
-
|
|
47460
|
-
/**
|
|
47461
|
-
* Add a widget placeholder using the widget ID.
|
|
47462
|
-
* ex. addWidget("radio 1") => "[[☃ radio 1]]"
|
|
47463
|
-
*
|
|
47464
|
-
* @param {string} id
|
|
47465
|
-
* @returns {string}
|
|
47466
|
-
*/
|
|
47467
|
-
function addWidget(id) {
|
|
47468
|
-
return `[[☃ ${id}]]`;
|
|
47469
|
-
}
|
|
47470
|
-
|
|
47471
|
-
/**
|
|
47472
|
-
* Get a widget type by a widget's ID
|
|
47473
|
-
* (please don't derive type from ID)
|
|
47474
|
-
*
|
|
47475
|
-
* @param {string} widgetId the ID of the widget
|
|
47476
|
-
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
47477
|
-
* @returns {string} the widget type (ie "radio")
|
|
47478
|
-
*/
|
|
47479
|
-
function getWidgetTypeByWidgetId(WidgetId, widgetMap) {
|
|
47480
|
-
var _widget$type;
|
|
47481
|
-
const widget = widgetMap[WidgetId];
|
|
47482
|
-
return (_widget$type = widget == null ? void 0 : widget.type) != null ? _widget$type : null;
|
|
47483
|
-
}
|
|
47484
|
-
|
|
47485
|
-
/**
|
|
47486
|
-
* Does the content have a specific type of widget?
|
|
47487
|
-
*
|
|
47488
|
-
* @param {string} type the type of the widget in question (ie "radio")
|
|
47489
|
-
* @param {string} content the string to search through
|
|
47490
|
-
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
47491
|
-
* @returns {boolean} if the content includes the widget type
|
|
47492
|
-
*/
|
|
47493
|
-
function contentHasWidgetType(type, content, widgetMap) {
|
|
47494
|
-
return getWidgetIdsFromContentByType(type, content, widgetMap).length > 0;
|
|
47495
|
-
}
|
|
47496
|
-
|
|
47497
|
-
/**
|
|
47498
|
-
* Extract all widget IDs, which includes the widget type and instance number.
|
|
47499
|
-
* example output: ['radio 1', 'categorizer 1', 'categorizor 2']
|
|
47500
|
-
*
|
|
47501
|
-
* Content should contain Perseus widget placeholders,
|
|
47502
|
-
* which look like: '[[☃ radio 1]]'.
|
|
47503
|
-
*
|
|
47504
|
-
* @param {string} content
|
|
47505
|
-
* @returns {ReadonlyArray<string>} widgetIds
|
|
47506
|
-
*/
|
|
47507
|
-
function getWidgetIdsFromContent(content) {
|
|
47508
|
-
const widgets = [];
|
|
47509
|
-
const localWidgetRegex = getWidgetRegex();
|
|
47510
|
-
let match = localWidgetRegex.exec(content);
|
|
47511
|
-
while (match !== null) {
|
|
47512
|
-
widgets.push(match[1]);
|
|
47513
|
-
match = localWidgetRegex.exec(content);
|
|
47514
|
-
}
|
|
47515
|
-
return widgets;
|
|
47516
|
-
}
|
|
47517
|
-
|
|
47518
|
-
/**
|
|
47519
|
-
* Get a list of widget IDs from content,
|
|
47520
|
-
* but only for specific widget types
|
|
47521
|
-
*
|
|
47522
|
-
* @param {string} type the type of widget (ie "radio")
|
|
47523
|
-
* @param {string} content the string to parse
|
|
47524
|
-
* @param {PerseusWidgetsMap} widgetMap widget ID to widget map
|
|
47525
|
-
* @returns {ReadonlyArray<string>} the widget type (ie "radio")
|
|
47526
|
-
*/
|
|
47527
|
-
function getWidgetIdsFromContentByType(type, content, widgetMap) {
|
|
47528
|
-
const rv = [];
|
|
47529
|
-
const widgetIdsInContent = getWidgetIdsFromContent(content);
|
|
47530
|
-
widgetIdsInContent.forEach(widgetId => {
|
|
47531
|
-
const widget = widgetMap[widgetId];
|
|
47532
|
-
if ((widget == null ? void 0 : widget.type) === type) {
|
|
47533
|
-
rv.push(widgetId);
|
|
47534
|
-
}
|
|
47535
|
-
});
|
|
47536
|
-
return rv;
|
|
47537
|
-
}
|
|
47538
|
-
|
|
47539
|
-
/**
|
|
47540
|
-
* Pull the widget map out of ItemData
|
|
47541
|
-
*
|
|
47542
|
-
* @param {PerseusItem} PerseusItem containing a widgetMap
|
|
47543
|
-
* @returns {WidgetMap} the widget map in the PerseusItem
|
|
47544
|
-
*/
|
|
47545
|
-
function getWidgetsMapFromItemData(itemData) {
|
|
47546
|
-
return itemData.question.widgets;
|
|
47547
|
-
}
|
|
47548
|
-
|
|
47549
|
-
/**
|
|
47550
|
-
* Get the widget information from a WidgetMap
|
|
47551
|
-
*
|
|
47552
|
-
* @param {string} widgetId the ID of the widget
|
|
47553
|
-
* @returns {PerseusWidget | null} the widget data if it exists, otherwise null
|
|
47554
|
-
*/
|
|
47555
|
-
function getWidgetFromWidgetMap(widgetId, widgetMap) {
|
|
47556
|
-
var _widgetMap$widgetId;
|
|
47557
|
-
return (_widgetMap$widgetId = widgetMap[widgetId]) != null ? _widgetMap$widgetId : null;
|
|
47558
|
-
}
|
|
47559
|
-
|
|
47560
|
-
/**
|
|
47561
|
-
* Get select widgets from a widget map.
|
|
47562
|
-
* Useful for multi-items that needs to split
|
|
47563
|
-
* one PerseusItem into several
|
|
47564
|
-
*
|
|
47565
|
-
* @param {ReadonlyArray<string>} widgetIds to extract
|
|
47566
|
-
* @param {PerseusWidgetsMap} widgetMap to extract from
|
|
47567
|
-
* @return {PerseusWidgetsMap} a new widget map with requested widgets
|
|
47568
|
-
*/
|
|
47569
|
-
function getWidgetsFromWidgetMap(widgetIds, widgetMap) {
|
|
47570
|
-
const widgets = {};
|
|
47571
|
-
widgetIds.forEach(widgetId => {
|
|
47572
|
-
const widget = getWidgetFromWidgetMap(widgetId, widgetMap);
|
|
47573
|
-
if (widget) {
|
|
47574
|
-
widgets[widgetId] = widget;
|
|
47575
|
-
}
|
|
47576
|
-
});
|
|
47577
|
-
return widgets;
|
|
47578
|
-
}
|
|
47579
|
-
|
|
47580
47642
|
/**
|
|
47581
47643
|
* This function extracts the answers from the widgets.
|
|
47582
47644
|
*
|
|
@@ -48513,6 +48575,8 @@ const parseDefinitionWidget = parseWidget(constant("definition"), object({
|
|
|
48513
48575
|
|
|
48514
48576
|
const parseDropdownWidget = parseWidget(constant("dropdown"), object({
|
|
48515
48577
|
placeholder: string,
|
|
48578
|
+
ariaLabel: optional(string),
|
|
48579
|
+
visibleLabel: optional(string),
|
|
48516
48580
|
static: defaulted(boolean, () => false),
|
|
48517
48581
|
choices: array(object({
|
|
48518
48582
|
content: string,
|
|
@@ -49631,5 +49695,5 @@ const GrapherUtil = {
|
|
|
49631
49695
|
typeToButton
|
|
49632
49696
|
};
|
|
49633
49697
|
|
|
49634
|
-
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, 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, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, buildEmptyItemTreeForShape, buildMapper, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
49698
|
+
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, 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, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, addWidget, apiVersion, bodyXsmallBold, buildEmptyItemTreeForShape, buildMapper, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getClockwiseAngle, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, makeSafeUrl, mathOnlyParser, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, scorePerseusItem, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
49635
49699
|
//# sourceMappingURL=index.js.map
|