@khanacademy/perseus 0.4.2 → 1.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/.eslintrc.js +11 -0
- package/CHANGELOG.md +47 -0
- package/dist/es/index.js +1078 -1299
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +1077 -1304
- package/dist/index.js.map +1 -1
- package/dist/strings.js +0 -4
- package/package.json +9 -8
- package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +110 -110
- package/src/perseus-api.jsx +10 -36
- package/src/perseus-types.js +0 -138
- package/src/styles/constants.js +0 -2
- package/src/styles/variables.less +0 -2
- package/src/types.js +18 -35
- package/src/util.js +0 -6
- package/src/version.js +1 -1
- package/src/widgets/__testdata__/base-radio_testdata.js +22 -0
- package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +110 -110
- package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +1136 -1160
- package/src/widgets/__tests__/radio/base-radio_test.jsx +243 -41
- package/src/widgets/__tests__/radio/choice-icon_test.jsx +67 -0
- package/src/widgets/__tests__/radio/choice_test.jsx +201 -0
- package/src/widgets/__tests__/radio/focus-ring_test.jsx +23 -0
- package/src/widgets/__tests__/radio/option-status_test.jsx +65 -0
- package/src/widgets/passage/__tests__/passage-markdown_test.jsx +0 -9
- package/src/widgets/passage/get-line-height-for-node.js +4 -5
- package/src/widgets/passage/passage-markdown.jsx +176 -120
- package/src/widgets/passage.jsx +48 -46
- package/src/widgets/radio/__stories__/base-radio.stories.jsx +164 -17
- package/src/widgets/radio/__stories__/choice-icon.stories.jsx +202 -111
- package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +21 -6
- package/src/widgets/radio/__stories__/choice.stories.jsx +138 -0
- package/src/widgets/radio/__stories__/focus-ring.stories.jsx +29 -23
- package/src/widgets/radio/__stories__/option-status.stories.jsx +93 -99
- package/src/widgets/radio/base-radio.jsx +483 -556
- package/src/widgets/radio/choice-icon/choice-icon.jsx +155 -0
- package/src/widgets/radio/choice-icon/cross-out-line.jsx +55 -0
- package/src/widgets/radio/choice-icon/library-choice-icon.jsx +219 -0
- package/src/widgets/radio/choice-icon/sat-choice-icon.jsx +129 -0
- package/src/widgets/radio/choice-icon/shared-styles.js +17 -0
- package/src/widgets/radio/choice-none-above.jsx +49 -40
- package/src/widgets/radio/choice.jsx +282 -353
- package/src/widgets/radio/choice.jsx.fixture.js +0 -18
- package/src/widgets/radio/focus-ring.jsx +29 -22
- package/src/widgets/radio/option-status.jsx +58 -36
- package/src/widgets/radio/widget.jsx +181 -136
- package/src/widgets/radio.jsx +16 -17
- package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +0 -64
- package/src/widgets/radio/choice-icon.jsx +0 -469
- package/src/widgets/radio/cross-out-button.jsx +0 -134
package/dist/es/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Rule, linterContextDefault, linterContextProps } from '@khanacademy/per
|
|
|
5
5
|
import * as i18n from '@khanacademy/wonder-blocks-i18n';
|
|
6
6
|
import classNames from 'classnames';
|
|
7
7
|
import * as React from 'react';
|
|
8
|
+
import { useState, useEffect, useRef } from 'react';
|
|
8
9
|
import _, { debounce } from 'underscore';
|
|
9
10
|
import PropTypes from 'prop-types';
|
|
10
11
|
import $ from 'jquery';
|
|
@@ -31,7 +32,7 @@ import Link from '@khanacademy/wonder-blocks-link';
|
|
|
31
32
|
|
|
32
33
|
var version = {
|
|
33
34
|
apiVersion: {
|
|
34
|
-
major:
|
|
35
|
+
major: 12,
|
|
35
36
|
minor: 0
|
|
36
37
|
},
|
|
37
38
|
itemDataVersion: {
|
|
@@ -493,38 +494,9 @@ var ApiOptions = {
|
|
|
493
494
|
// values. For now, though, you must either specify all fields
|
|
494
495
|
// of `styling`, or omit the `styling` option entirely.
|
|
495
496
|
styling: PropTypes.shape({
|
|
496
|
-
//
|
|
497
|
-
//
|
|
498
|
-
|
|
499
|
-
// "legacy" was the version of the widget display after XOM but
|
|
500
|
-
// before we started adding MCR styles. It doesn't have support
|
|
501
|
-
// for rationales. It has since been removed.
|
|
502
|
-
//
|
|
503
|
-
// "intermediate" is a design which adds several new additions
|
|
504
|
-
// to the "legacy" styles such as:
|
|
505
|
-
// 1. Using the XOM "desktop" styles (with a visible check icon
|
|
506
|
-
// and lines in between choices) on mobile devices.
|
|
507
|
-
// 2. Designs for rationales
|
|
508
|
-
// 3. Using the single-select styles for multi-select styles
|
|
509
|
-
//
|
|
510
|
-
// "final" is a design which will build off of the
|
|
511
|
-
// "intermediate" designs and adds some improved designs as well
|
|
512
|
-
// as:
|
|
513
|
-
// 1. a/b/c/d/etc. letters inside of the prompt check box
|
|
514
|
-
// 2. New iconography and styles to indicate choice correctness
|
|
515
|
-
//
|
|
516
|
-
// The "legacy" and "intermediate" designs will be A/B tested
|
|
517
|
-
// against each other to ensure that its changes don't cause
|
|
518
|
-
// problems due to the new designs. Once the "intermediate"
|
|
519
|
-
// designs are finished, they will be A/B tested against the
|
|
520
|
-
// "final" designs.
|
|
521
|
-
//
|
|
522
|
-
// If no flag is provided, "legacy" styles will be shown.
|
|
523
|
-
//
|
|
524
|
-
// TODO(emily): Remove this by Aug 1, 2017, at which point all
|
|
525
|
-
// callsites should have been switched to using the "final"
|
|
526
|
-
// designs.
|
|
527
|
-
radioStyleVersion: PropTypes.oneOf(["intermediate", "final"])
|
|
497
|
+
// TODO(Nicole): Remove this after landing wonderblock-ifying
|
|
498
|
+
// the radio widget
|
|
499
|
+
primaryProductColor: PropTypes.string
|
|
528
500
|
}),
|
|
529
501
|
// The color used for the hint progress indicator (eg. 1 / 3)
|
|
530
502
|
hintProgressColor: PropTypes.string,
|
|
@@ -575,9 +547,7 @@ var ApiOptions = {
|
|
|
575
547
|
},
|
|
576
548
|
setDrawingAreaAvailable: function setDrawingAreaAvailable() {},
|
|
577
549
|
useDraftEditor: false,
|
|
578
|
-
styling: {
|
|
579
|
-
radioStyleVersion: "final"
|
|
580
|
-
},
|
|
550
|
+
styling: {},
|
|
581
551
|
canScrollPage: false,
|
|
582
552
|
inModal: false,
|
|
583
553
|
crossOutEnabled: false,
|
|
@@ -1701,16 +1671,10 @@ function inputPathsEqual(a, b) {
|
|
|
1701
1671
|
return a.length === b.length && a.every((item, index) => {
|
|
1702
1672
|
return b[index] === item;
|
|
1703
1673
|
});
|
|
1704
|
-
}
|
|
1705
|
-
// in content_internal/perseus_traversal.py
|
|
1706
|
-
// sync-start:widget-id-regex 1271666319 services/content-editing/perseus/translation/content_traversal.go
|
|
1707
|
-
// sync-start:widget-id-regex 680240484 services/static/javascript/perseus-merged-editor-package/editor.jsx
|
|
1708
|
-
// sync-start:widget-id-regex 1400368396 content_internal/perseus_traversal.py
|
|
1709
|
-
|
|
1674
|
+
}
|
|
1710
1675
|
|
|
1711
1676
|
var rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
|
|
1712
|
-
var rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
|
|
1713
|
-
|
|
1677
|
+
var rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
|
|
1714
1678
|
var rWidgetParts = new RegExp(rWidgetRule.source + "$");
|
|
1715
1679
|
var snowman = "\u2603";
|
|
1716
1680
|
var noScore = {
|
|
@@ -3143,11 +3107,10 @@ var warningColor = "#f86700";
|
|
|
3143
3107
|
var warningColorHover = "#df5c00";
|
|
3144
3108
|
var warningColorActive = "#c75300";
|
|
3145
3109
|
var publishBlockingErrorColor = "#be2612";
|
|
3146
|
-
var radioBorderColor$
|
|
3147
|
-
var checkedColor$1 = "#71B307";
|
|
3148
|
-
|
|
3110
|
+
var radioBorderColor$1 = "#BABEC2";
|
|
3111
|
+
var checkedColor$1 = "#71B307";
|
|
3149
3112
|
var articleMaxWidthInPx = 688;
|
|
3150
|
-
var articleMaxWidthTableInPx = 512;
|
|
3113
|
+
var articleMaxWidthTableInPx = 512;
|
|
3151
3114
|
|
|
3152
3115
|
var constants$1 = /*#__PURE__*/Object.freeze({
|
|
3153
3116
|
__proto__: null,
|
|
@@ -3212,7 +3175,7 @@ var constants$1 = /*#__PURE__*/Object.freeze({
|
|
|
3212
3175
|
warningColorHover: warningColorHover,
|
|
3213
3176
|
warningColorActive: warningColorActive,
|
|
3214
3177
|
publishBlockingErrorColor: publishBlockingErrorColor,
|
|
3215
|
-
radioBorderColor: radioBorderColor$
|
|
3178
|
+
radioBorderColor: radioBorderColor$1,
|
|
3216
3179
|
checkedColor: checkedColor$1,
|
|
3217
3180
|
articleMaxWidthInPx: articleMaxWidthInPx,
|
|
3218
3181
|
articleMaxWidthTableInPx: articleMaxWidthTableInPx
|
|
@@ -17996,17 +17959,17 @@ class Lint extends React.Component {
|
|
|
17996
17959
|
var warningTextStyle;
|
|
17997
17960
|
|
|
17998
17961
|
if (this.props.severity === 1) {
|
|
17999
|
-
severityStyle = styles$
|
|
17962
|
+
severityStyle = styles$A.indicatorError;
|
|
18000
17963
|
warningText = "Error";
|
|
18001
|
-
warningTextStyle = styles$
|
|
17964
|
+
warningTextStyle = styles$A.publishBlockingError;
|
|
18002
17965
|
} else if (this.props.severity === 2) {
|
|
18003
|
-
severityStyle = styles$
|
|
17966
|
+
severityStyle = styles$A.indicatorWarning;
|
|
18004
17967
|
warningText = "Warning";
|
|
18005
|
-
warningTextStyle = styles$
|
|
17968
|
+
warningTextStyle = styles$A.warning;
|
|
18006
17969
|
} else {
|
|
18007
|
-
severityStyle = styles$
|
|
17970
|
+
severityStyle = styles$A.indicatorGuideline;
|
|
18008
17971
|
warningText = "Recommendation";
|
|
18009
|
-
warningTextStyle = styles$
|
|
17972
|
+
warningTextStyle = styles$A.warning;
|
|
18010
17973
|
}
|
|
18011
17974
|
|
|
18012
17975
|
return /*#__PURE__*/React.createElement("a", {
|
|
@@ -18014,16 +17977,16 @@ class Lint extends React.Component {
|
|
|
18014
17977
|
target: "lint-help-window",
|
|
18015
17978
|
className: css(style)
|
|
18016
17979
|
}, /*#__PURE__*/React.createElement("span", {
|
|
18017
|
-
className: css(styles$
|
|
17980
|
+
className: css(styles$A.indicator, severityStyle)
|
|
18018
17981
|
}, this.props.severity === 1 && /*#__PURE__*/React.createElement(InlineIcon, exclamationIcon)), /*#__PURE__*/React.createElement("div", {
|
|
18019
|
-
className: css(styles$
|
|
17982
|
+
className: css(styles$A.tooltip, tooltipAbove && styles$A.tooltipAbove)
|
|
18020
17983
|
}, this.props.message.split("\n\n").map((m, i) => /*#__PURE__*/React.createElement("p", {
|
|
18021
17984
|
key: i,
|
|
18022
|
-
className: css(styles$
|
|
17985
|
+
className: css(styles$A.tooltipParagraph)
|
|
18023
17986
|
}, /*#__PURE__*/React.createElement("span", {
|
|
18024
17987
|
className: css(warningTextStyle)
|
|
18025
17988
|
}, warningText, ":", " "), m)), /*#__PURE__*/React.createElement("div", {
|
|
18026
|
-
className: css(styles$
|
|
17989
|
+
className: css(styles$A.tail, tooltipAbove && styles$A.tailAbove)
|
|
18027
17990
|
})));
|
|
18028
17991
|
});
|
|
18029
17992
|
}
|
|
@@ -18071,19 +18034,19 @@ class Lint extends React.Component {
|
|
|
18071
18034
|
|
|
18072
18035
|
if (blockHighlight) {
|
|
18073
18036
|
return /*#__PURE__*/React.createElement("span", {
|
|
18074
|
-
className: css(styles$
|
|
18075
|
-
}, this.renderLink(styles$
|
|
18037
|
+
className: css(styles$A.lintContainer, styles$A.lintContainerBlock)
|
|
18038
|
+
}, this.renderLink(styles$A.radioWidgetHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
|
|
18076
18039
|
}
|
|
18077
18040
|
|
|
18078
18041
|
if (inline) {
|
|
18079
18042
|
return /*#__PURE__*/React.createElement("span", {
|
|
18080
|
-
className: css(styles$
|
|
18081
|
-
}, this.renderLink(styles$
|
|
18043
|
+
className: css(styles$A.lintContainer)
|
|
18044
|
+
}, this.renderLink(styles$A.inlineHoverTarget), /*#__PURE__*/React.createElement("span", null, children));
|
|
18082
18045
|
}
|
|
18083
18046
|
|
|
18084
18047
|
return /*#__PURE__*/React.createElement("div", {
|
|
18085
|
-
className: css(styles$
|
|
18086
|
-
}, this.renderLink(styles$
|
|
18048
|
+
className: css(styles$A.lintContainer)
|
|
18049
|
+
}, this.renderLink(styles$A.hoverTarget), /*#__PURE__*/React.createElement("div", null, children));
|
|
18087
18050
|
}
|
|
18088
18051
|
|
|
18089
18052
|
} // $FlowFixMe[prop-missing]
|
|
@@ -18108,7 +18071,7 @@ _defineProperty(Lint, "propTypes", {
|
|
|
18108
18071
|
severity: PropTypes.number
|
|
18109
18072
|
});
|
|
18110
18073
|
|
|
18111
|
-
var styles$
|
|
18074
|
+
var styles$A = StyleSheet.create({
|
|
18112
18075
|
// This is the class of the outermost element.
|
|
18113
18076
|
// We use relative positioning so that the lint indicator can be
|
|
18114
18077
|
// positioned absolutely relative to the position of the linty container.
|
|
@@ -19998,7 +19961,7 @@ class Renderer extends React.Component {
|
|
|
19998
19961
|
paddingRight: margin
|
|
19999
19962
|
};
|
|
20000
19963
|
|
|
20001
|
-
var mobileInnerStyle = _objectSpread2(_objectSpread2({}, innerStyle), styles$
|
|
19964
|
+
var mobileInnerStyle = _objectSpread2(_objectSpread2({}, innerStyle), styles$z.mobileZoomableParentFix);
|
|
20002
19965
|
|
|
20003
19966
|
return /*#__PURE__*/React.createElement("div", {
|
|
20004
19967
|
key: state.key,
|
|
@@ -20136,7 +20099,7 @@ class Renderer extends React.Component {
|
|
|
20136
20099
|
paddingRight: 0
|
|
20137
20100
|
};
|
|
20138
20101
|
|
|
20139
|
-
var _mobileInnerStyle = _objectSpread2(_objectSpread2({}, _innerStyle), styles$
|
|
20102
|
+
var _mobileInnerStyle = _objectSpread2(_objectSpread2({}, _innerStyle), styles$z.mobileZoomableParentFix);
|
|
20140
20103
|
|
|
20141
20104
|
var wrappedOutput = /*#__PURE__*/React.createElement("div", {
|
|
20142
20105
|
style: _objectSpread2(_objectSpread2({}, _mobileInnerStyle), {}, {
|
|
@@ -20815,7 +20778,7 @@ _defineProperty(Renderer, "defaultProps", {
|
|
|
20815
20778
|
linterContext: PerseusLinter.linterContextDefault
|
|
20816
20779
|
});
|
|
20817
20780
|
|
|
20818
|
-
var styles$
|
|
20781
|
+
var styles$z = {
|
|
20819
20782
|
mobileZoomableParentFix: {
|
|
20820
20783
|
// NOTE(abdul): There is an issue where transform animations will
|
|
20821
20784
|
// cause the Zoomable component to disappear when running on the
|
|
@@ -22991,7 +22954,7 @@ _defineProperty(PossibleAnswers, "propTypes", {
|
|
|
22991
22954
|
answers: PropTypes.arrayOf(PropTypes.string)
|
|
22992
22955
|
});
|
|
22993
22956
|
|
|
22994
|
-
var _excluded$
|
|
22957
|
+
var _excluded$3 = ["keypadElement", "onFocus", "value"];
|
|
22995
22958
|
var SimpleKeypadInput = createReactClass({
|
|
22996
22959
|
displayName: "SimpleKeypadInput",
|
|
22997
22960
|
propTypes: {
|
|
@@ -23036,7 +22999,7 @@ var SimpleKeypadInput = createReactClass({
|
|
|
23036
22999
|
onFocus: _onFocus,
|
|
23037
23000
|
value
|
|
23038
23001
|
} = _this$props,
|
|
23039
|
-
rest = _objectWithoutProperties(_this$props, _excluded$
|
|
23002
|
+
rest = _objectWithoutProperties(_this$props, _excluded$3);
|
|
23040
23003
|
|
|
23041
23004
|
return /*#__PURE__*/React.createElement(KeypadInput // eslint-disable-next-line react/no-string-refs
|
|
23042
23005
|
, _extends({
|
|
@@ -24122,7 +24085,7 @@ var mediaQueries = {
|
|
|
24122
24085
|
var {
|
|
24123
24086
|
zIndexAboveScratchpad,
|
|
24124
24087
|
zIndexInteractiveComponent,
|
|
24125
|
-
radioBorderColor
|
|
24088
|
+
radioBorderColor,
|
|
24126
24089
|
checkedColor,
|
|
24127
24090
|
circleSize,
|
|
24128
24091
|
radioMarginWidth
|
|
@@ -24177,7 +24140,7 @@ var sharedStyles = StyleSheet.create({
|
|
|
24177
24140
|
},
|
|
24178
24141
|
backgroundColor: "#fff",
|
|
24179
24142
|
border: "2px solid #fff",
|
|
24180
|
-
boxShadow: "0 0px 0px 1px ".concat(radioBorderColor
|
|
24143
|
+
boxShadow: "0 0px 0px 1px ".concat(radioBorderColor),
|
|
24181
24144
|
outline: "none",
|
|
24182
24145
|
boxSizing: "border-box",
|
|
24183
24146
|
flexShrink: 0,
|
|
@@ -24430,36 +24393,6 @@ _defineProperty(Icon, "defaultProps", {
|
|
|
24430
24393
|
color: "currentColor"
|
|
24431
24394
|
});
|
|
24432
24395
|
|
|
24433
|
-
class FocusRing extends React.Component {
|
|
24434
|
-
render() {
|
|
24435
|
-
var borderColor = this.props.visible ? this.props.color : "transparent";
|
|
24436
|
-
var style = {
|
|
24437
|
-
borderColor: borderColor
|
|
24438
|
-
};
|
|
24439
|
-
return /*#__PURE__*/React.createElement("span", {
|
|
24440
|
-
className: css(styles$u.ring),
|
|
24441
|
-
style: style
|
|
24442
|
-
}, this.props.children);
|
|
24443
|
-
}
|
|
24444
|
-
|
|
24445
|
-
}
|
|
24446
|
-
|
|
24447
|
-
_defineProperty(FocusRing, "defaultProps", {
|
|
24448
|
-
visible: true,
|
|
24449
|
-
color: kaGreen$1
|
|
24450
|
-
});
|
|
24451
|
-
|
|
24452
|
-
var styles$u = StyleSheet.create({
|
|
24453
|
-
ring: {
|
|
24454
|
-
margin: "auto",
|
|
24455
|
-
display: "inline-block",
|
|
24456
|
-
borderRadius: "50%",
|
|
24457
|
-
borderWidth: 2,
|
|
24458
|
-
padding: 2,
|
|
24459
|
-
borderStyle: "solid"
|
|
24460
|
-
}
|
|
24461
|
-
});
|
|
24462
|
-
|
|
24463
24396
|
/**
|
|
24464
24397
|
* Given a choice's position in the radio widget, return the corresponding
|
|
24465
24398
|
* "choice letter". (For example, in English, `getChoiceLetter(0)` is "A",
|
|
@@ -24490,179 +24423,57 @@ function getChoiceLetter(pos) {
|
|
|
24490
24423
|
return " ";
|
|
24491
24424
|
}
|
|
24492
24425
|
|
|
24493
|
-
|
|
24494
|
-
|
|
24495
|
-
|
|
24496
|
-
// TODO(amy): figure out a better scheme for specifying these
|
|
24497
|
-
// styles that isn't such a pain to grok. See some neat ideas
|
|
24498
|
-
// from MDR in https://phabricator.khanacademy.org/D35249.
|
|
24499
|
-
constructStyles(reviewMode, correct, checked) {
|
|
24500
|
-
var backgroundColor;
|
|
24501
|
-
var borderColor = satBlue;
|
|
24502
|
-
var color = satBlue;
|
|
24503
|
-
|
|
24504
|
-
if (reviewMode) {
|
|
24505
|
-
if (correct) {
|
|
24506
|
-
borderColor = satCorrectColor;
|
|
24507
|
-
color = checked ? white$1 : satCorrectColor;
|
|
24508
|
-
backgroundColor = checked ? satCorrectColor : white$1;
|
|
24509
|
-
} else if (checked) {
|
|
24510
|
-
borderColor = satIncorrectColor;
|
|
24511
|
-
color = white$1;
|
|
24512
|
-
backgroundColor = satIncorrectColor;
|
|
24513
|
-
}
|
|
24514
|
-
} else if (checked) {
|
|
24515
|
-
color = white$1;
|
|
24516
|
-
backgroundColor = satBlue;
|
|
24517
|
-
}
|
|
24518
|
-
|
|
24519
|
-
return {
|
|
24520
|
-
color,
|
|
24521
|
-
backgroundColor,
|
|
24522
|
-
borderColor
|
|
24523
|
-
};
|
|
24524
|
-
}
|
|
24525
|
-
|
|
24526
|
-
render() {
|
|
24527
|
-
var {
|
|
24528
|
-
letter,
|
|
24529
|
-
a11yText,
|
|
24530
|
-
reviewMode,
|
|
24531
|
-
checked,
|
|
24532
|
-
correct,
|
|
24533
|
-
crossedOut
|
|
24534
|
-
} = this.props;
|
|
24535
|
-
var {
|
|
24536
|
-
color,
|
|
24537
|
-
backgroundColor,
|
|
24538
|
-
borderColor
|
|
24539
|
-
} = this.constructStyles(reviewMode, correct, checked);
|
|
24540
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
24541
|
-
className: css(styles$t.iconWrapper)
|
|
24542
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
24543
|
-
className: css(styles$t.satCircle),
|
|
24544
|
-
style: {
|
|
24545
|
-
backgroundColor,
|
|
24546
|
-
borderColor
|
|
24547
|
-
}
|
|
24548
|
-
}), /*#__PURE__*/React.createElement("div", {
|
|
24549
|
-
style: {
|
|
24550
|
-
color
|
|
24551
|
-
},
|
|
24552
|
-
className: css(styles$t.letter)
|
|
24553
|
-
}, /*#__PURE__*/React.createElement("span", {
|
|
24554
|
-
className: "perseus-sr-only"
|
|
24555
|
-
}, a11yText), /*#__PURE__*/React.createElement("span", {
|
|
24556
|
-
"aria-hidden": "true"
|
|
24557
|
-
}, letter)), crossedOut && /*#__PURE__*/React.createElement(CrossOutLine, {
|
|
24558
|
-
color: borderColor,
|
|
24559
|
-
sat: true
|
|
24560
|
-
}));
|
|
24561
|
-
}
|
|
24426
|
+
/**
|
|
24427
|
+
* Renders a circular selection ring around the child.
|
|
24428
|
+
*/
|
|
24562
24429
|
|
|
24430
|
+
function FocusRing(props) {
|
|
24431
|
+
var {
|
|
24432
|
+
visible,
|
|
24433
|
+
color,
|
|
24434
|
+
children,
|
|
24435
|
+
multipleSelect
|
|
24436
|
+
} = props;
|
|
24437
|
+
var borderColor = visible ? color : "transparent";
|
|
24438
|
+
var borderRadius = multipleSelect ? 5 : "50%";
|
|
24439
|
+
var style = {
|
|
24440
|
+
borderColor,
|
|
24441
|
+
borderRadius
|
|
24442
|
+
};
|
|
24443
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
24444
|
+
"data-test-id": "focus-ring",
|
|
24445
|
+
className: css(styles$y.ring),
|
|
24446
|
+
style: style
|
|
24447
|
+
}, children);
|
|
24563
24448
|
}
|
|
24564
24449
|
|
|
24565
|
-
|
|
24566
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
24569
|
-
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
}
|
|
24578
|
-
|
|
24579
|
-
if (correct) {
|
|
24580
|
-
return /*#__PURE__*/React.createElement(InlineIcon, _extends({}, iconCheck, {
|
|
24581
|
-
style: {
|
|
24582
|
-
position: "relative",
|
|
24583
|
-
top: -1
|
|
24584
|
-
}
|
|
24585
|
-
}));
|
|
24586
|
-
}
|
|
24587
|
-
|
|
24588
|
-
return /*#__PURE__*/React.createElement(InlineIcon, iconMinus);
|
|
24589
|
-
} // Handle dynamic styling of the multiple choice icon. Most
|
|
24590
|
-
// MC icon styles are constant, but we do allow the caller
|
|
24591
|
-
// to specify the selected color, and thus must control styles
|
|
24592
|
-
// related to the selected state dynamically.
|
|
24593
|
-
|
|
24594
|
-
|
|
24595
|
-
getDynamicStyles() {
|
|
24596
|
-
var {
|
|
24597
|
-
checked,
|
|
24598
|
-
showCorrectness,
|
|
24599
|
-
pressed,
|
|
24600
|
-
primaryProductColor,
|
|
24601
|
-
correct,
|
|
24602
|
-
transparentBackground
|
|
24603
|
-
} = this.props;
|
|
24604
|
-
|
|
24605
|
-
if (!showCorrectness && pressed) {
|
|
24606
|
-
return {
|
|
24607
|
-
borderColor: primaryProductColor,
|
|
24608
|
-
color: primaryProductColor,
|
|
24609
|
-
backgroundColor: transparentBackground ? "transparent" : white$1
|
|
24610
|
-
};
|
|
24611
|
-
}
|
|
24612
|
-
|
|
24613
|
-
if (checked) {
|
|
24614
|
-
// Note: kaGreen is not only the default product color,
|
|
24615
|
-
// but also the "correctness" color
|
|
24616
|
-
var bg = showCorrectness && correct ? Color.green : primaryProductColor;
|
|
24617
|
-
return {
|
|
24618
|
-
color: white$1,
|
|
24619
|
-
backgroundColor: bg,
|
|
24620
|
-
borderColor: bg
|
|
24621
|
-
};
|
|
24622
|
-
}
|
|
24623
|
-
|
|
24624
|
-
return {
|
|
24625
|
-
borderColor: Color.offBlack64,
|
|
24626
|
-
color: Color.offBlack64
|
|
24627
|
-
};
|
|
24450
|
+
FocusRing.defaultProps = {
|
|
24451
|
+
visible: true,
|
|
24452
|
+
color: kaGreen$1,
|
|
24453
|
+
multipleSelect: false
|
|
24454
|
+
};
|
|
24455
|
+
var styles$y = StyleSheet.create({
|
|
24456
|
+
ring: {
|
|
24457
|
+
margin: "auto",
|
|
24458
|
+
display: "inline-block",
|
|
24459
|
+
borderWidth: 2,
|
|
24460
|
+
padding: 2,
|
|
24461
|
+
borderStyle: "solid"
|
|
24628
24462
|
}
|
|
24463
|
+
});
|
|
24629
24464
|
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
|
|
24633
|
-
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
correct,
|
|
24637
|
-
focused,
|
|
24638
|
-
primaryProductColor,
|
|
24639
|
-
previouslyAnswered
|
|
24640
|
-
} = this.props;
|
|
24641
|
-
var dynamicStyles = this.getDynamicStyles();
|
|
24642
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
24643
|
-
className: css(styles$t.iconWrapper)
|
|
24644
|
-
}, /*#__PURE__*/React.createElement(FocusRing, {
|
|
24645
|
-
color: primaryProductColor,
|
|
24646
|
-
visible: focused
|
|
24647
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
24648
|
-
style: dynamicStyles,
|
|
24649
|
-
className: css(styles$t.libraryCircle, showCorrectness && correct && styles$t.libraryCircleCorrect, showCorrectness && !correct && styles$t.libraryCircleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$t.libraryCircleIncorrectAnswered) // used in BaseRadio to check if we actually clicked on the
|
|
24650
|
-
// radio icon
|
|
24651
|
-
,
|
|
24652
|
-
"data-is-radio-icon": true
|
|
24653
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
24654
|
-
className: "perseus-sr-only"
|
|
24655
|
-
}, a11yText), /*#__PURE__*/React.createElement("div", {
|
|
24656
|
-
"aria-hidden": true
|
|
24657
|
-
}, this.getChoiceInner()))), crossedOut && /*#__PURE__*/React.createElement(CrossOutLine, {
|
|
24658
|
-
color: dynamicStyles.borderColor
|
|
24659
|
-
}));
|
|
24465
|
+
var SAT_ICON_SIZE = 25;
|
|
24466
|
+
var LIBRARY_ICON_SIZE = 24;
|
|
24467
|
+
var styles$x = StyleSheet.create({
|
|
24468
|
+
iconWrapper: {
|
|
24469
|
+
display: "inline-block",
|
|
24470
|
+
position: "relative"
|
|
24660
24471
|
}
|
|
24472
|
+
});
|
|
24661
24473
|
|
|
24662
|
-
|
|
24474
|
+
/* Component for rendering a letter icon in radio choice */
|
|
24663
24475
|
// extra space for the cute rounded line cap.
|
|
24664
24476
|
|
|
24665
|
-
|
|
24666
24477
|
var CROSS_OUT_LINE_PADDING = 2;
|
|
24667
24478
|
var CROSS_OUT_LINE_SIZE = LIBRARY_ICON_SIZE + CROSS_OUT_LINE_PADDING * 2;
|
|
24668
24479
|
var SAT_CROSS_OUT_LINE_SIZE = SAT_ICON_SIZE + CROSS_OUT_LINE_PADDING * 2;
|
|
@@ -24677,7 +24488,7 @@ function CrossOutLine(props) {
|
|
|
24677
24488
|
width: crossOutLineSize,
|
|
24678
24489
|
height: crossOutLineSize,
|
|
24679
24490
|
viewBox: "0 0 ".concat(crossOutLineSize, " ").concat(crossOutLineSize),
|
|
24680
|
-
className: css(styles$
|
|
24491
|
+
className: css(styles$w.crossOutLine)
|
|
24681
24492
|
}, /*#__PURE__*/React.createElement("line", {
|
|
24682
24493
|
// The line stretches from the bottom-left to top-right.
|
|
24683
24494
|
// We don't quite go to the _very_ corner, because the cute
|
|
@@ -24692,151 +24503,129 @@ function CrossOutLine(props) {
|
|
|
24692
24503
|
}));
|
|
24693
24504
|
}
|
|
24694
24505
|
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24702
|
-
|
|
24703
|
-
// whether the answer was checked/crossed-out/neither, and whether the
|
|
24704
|
-
// answer is correct/incorrect/not-yet-revealed.
|
|
24705
|
-
//
|
|
24706
|
-
// Translation is tricky for cross-product situations like this, so
|
|
24707
|
-
// we've just enumerated all 9 possibilities as separate strings.
|
|
24708
|
-
|
|
24709
|
-
if (showCorrectness && correct) {
|
|
24710
|
-
if (checked) {
|
|
24711
|
-
return i18n._("(Choice %(letter)s, Checked, Correct)", {
|
|
24712
|
-
letter
|
|
24713
|
-
});
|
|
24714
|
-
}
|
|
24715
|
-
|
|
24716
|
-
if (crossedOut) {
|
|
24717
|
-
return i18n._("(Choice %(letter)s, Crossed out, Correct)", {
|
|
24718
|
-
letter
|
|
24719
|
-
});
|
|
24720
|
-
}
|
|
24506
|
+
var styles$w = StyleSheet.create({
|
|
24507
|
+
crossOutLine: {
|
|
24508
|
+
// Center the icon within the container.
|
|
24509
|
+
position: "absolute",
|
|
24510
|
+
top: "calc(50% - ".concat(CROSS_OUT_LINE_SIZE / 2, "px)"),
|
|
24511
|
+
left: "calc(50% - ".concat(CROSS_OUT_LINE_SIZE / 2, "px)")
|
|
24512
|
+
}
|
|
24513
|
+
});
|
|
24721
24514
|
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24515
|
+
function ChoiceInner(props) {
|
|
24516
|
+
var {
|
|
24517
|
+
letter,
|
|
24518
|
+
showCorrectness,
|
|
24519
|
+
correct
|
|
24520
|
+
} = props;
|
|
24726
24521
|
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
letter
|
|
24731
|
-
});
|
|
24732
|
-
}
|
|
24522
|
+
if (!showCorrectness) {
|
|
24523
|
+
return letter;
|
|
24524
|
+
}
|
|
24733
24525
|
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
|
|
24526
|
+
if (correct) {
|
|
24527
|
+
return /*#__PURE__*/React.createElement(InlineIcon, _extends({}, iconCheck, {
|
|
24528
|
+
style: {
|
|
24529
|
+
position: "relative",
|
|
24530
|
+
top: -1
|
|
24738
24531
|
}
|
|
24739
|
-
|
|
24740
|
-
return i18n._("(Choice %(letter)s, Incorrect)", {
|
|
24741
|
-
letter
|
|
24742
|
-
});
|
|
24743
|
-
}
|
|
24744
|
-
|
|
24745
|
-
if (checked) {
|
|
24746
|
-
return i18n._("(Choice %(letter)s, Checked)", {
|
|
24747
|
-
letter
|
|
24748
|
-
});
|
|
24749
|
-
}
|
|
24750
|
-
|
|
24751
|
-
if (crossedOut) {
|
|
24752
|
-
return i18n._("(Choice %(letter)s, Crossed out)", {
|
|
24753
|
-
letter
|
|
24754
|
-
});
|
|
24755
|
-
}
|
|
24756
|
-
|
|
24757
|
-
return i18n._("(Choice %(letter)s)", {
|
|
24758
|
-
letter
|
|
24759
|
-
});
|
|
24532
|
+
}));
|
|
24760
24533
|
}
|
|
24761
24534
|
|
|
24762
|
-
|
|
24763
|
-
|
|
24764
|
-
|
|
24765
|
-
|
|
24766
|
-
|
|
24767
|
-
|
|
24768
|
-
|
|
24769
|
-
|
|
24770
|
-
|
|
24771
|
-
|
|
24772
|
-
|
|
24773
|
-
|
|
24774
|
-
|
|
24775
|
-
|
|
24776
|
-
|
|
24777
|
-
|
|
24535
|
+
return /*#__PURE__*/React.createElement(InlineIcon, iconMinus);
|
|
24536
|
+
} // Handle dynamic styling of the multiple choice icon. Most
|
|
24537
|
+
// MC icon styles are constant, but we do allow the caller
|
|
24538
|
+
// to specify the selected color, and thus must control styles
|
|
24539
|
+
// related to the selected state dynamically.
|
|
24540
|
+
|
|
24541
|
+
|
|
24542
|
+
function getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, primaryProductColor, correct, transparentBackground) {
|
|
24543
|
+
var backgroundColor;
|
|
24544
|
+
var borderColor;
|
|
24545
|
+
var color;
|
|
24546
|
+
|
|
24547
|
+
if (!showCorrectness && pressed) {
|
|
24548
|
+
borderColor = primaryProductColor;
|
|
24549
|
+
color = primaryProductColor;
|
|
24550
|
+
backgroundColor = transparentBackground ? "transparent" : white$1;
|
|
24551
|
+
} else if (checked) {
|
|
24552
|
+
// Note: kaGreen is not only the default product color,
|
|
24553
|
+
// but also the "correctness" color
|
|
24554
|
+
var bg = showCorrectness && correct ? Color.green : primaryProductColor;
|
|
24555
|
+
color = white$1;
|
|
24556
|
+
backgroundColor = bg;
|
|
24557
|
+
borderColor = bg;
|
|
24558
|
+
} else {
|
|
24559
|
+
borderColor = Color.offBlack64;
|
|
24560
|
+
color = Color.offBlack64;
|
|
24561
|
+
} // define shape
|
|
24778
24562
|
|
|
24779
|
-
if (product === "sat") {
|
|
24780
|
-
return /*#__PURE__*/React.createElement(SATChoiceIcon, {
|
|
24781
|
-
letter: letter,
|
|
24782
|
-
a11yText: this.a11yText(letter),
|
|
24783
|
-
reviewMode: reviewMode,
|
|
24784
|
-
checked: checked,
|
|
24785
|
-
correct: correct,
|
|
24786
|
-
crossedOut: crossedOut
|
|
24787
|
-
});
|
|
24788
|
-
}
|
|
24789
24563
|
|
|
24790
|
-
|
|
24791
|
-
|
|
24792
|
-
|
|
24793
|
-
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
pressed: pressed,
|
|
24797
|
-
focused: focused,
|
|
24798
|
-
correct: correct,
|
|
24799
|
-
showCorrectness: showCorrectness,
|
|
24800
|
-
primaryProductColor: primaryProductColor,
|
|
24801
|
-
previouslyAnswered: previouslyAnswered,
|
|
24802
|
-
transparentBackground: transparentBackground
|
|
24803
|
-
});
|
|
24564
|
+
var borderRadius;
|
|
24565
|
+
|
|
24566
|
+
if (multipleSelect) {
|
|
24567
|
+
borderRadius = 3;
|
|
24568
|
+
} else {
|
|
24569
|
+
borderRadius = LIBRARY_ICON_SIZE;
|
|
24804
24570
|
}
|
|
24805
24571
|
|
|
24572
|
+
return {
|
|
24573
|
+
backgroundColor,
|
|
24574
|
+
borderColor,
|
|
24575
|
+
color,
|
|
24576
|
+
borderRadius
|
|
24577
|
+
};
|
|
24806
24578
|
}
|
|
24807
24579
|
|
|
24808
|
-
|
|
24809
|
-
|
|
24810
|
-
|
|
24580
|
+
function LibraryChoiceIcon(props) {
|
|
24581
|
+
var {
|
|
24582
|
+
a11yText,
|
|
24583
|
+
checked,
|
|
24584
|
+
crossedOut,
|
|
24585
|
+
showCorrectness,
|
|
24586
|
+
correct,
|
|
24587
|
+
focused,
|
|
24588
|
+
hovered,
|
|
24589
|
+
multipleSelect,
|
|
24590
|
+
primaryProductColor,
|
|
24591
|
+
previouslyAnswered,
|
|
24592
|
+
letter,
|
|
24593
|
+
pressed,
|
|
24594
|
+
transparentBackground
|
|
24595
|
+
} = props;
|
|
24596
|
+
var dynamicStyles = getDynamicStyles(checked, showCorrectness, pressed, multipleSelect, primaryProductColor, correct, transparentBackground);
|
|
24597
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24598
|
+
className: css(styles$x.iconWrapper)
|
|
24599
|
+
}, /*#__PURE__*/React.createElement(FocusRing, {
|
|
24600
|
+
color: primaryProductColor,
|
|
24601
|
+
visible: focused || hovered,
|
|
24602
|
+
multipleSelect: multipleSelect
|
|
24603
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
24604
|
+
style: dynamicStyles,
|
|
24605
|
+
"data-test-id": "choice-icon__library-choice-icon",
|
|
24606
|
+
className: css(styles$v.circle, showCorrectness && correct && styles$v.circleCorrect, showCorrectness && !correct && styles$v.circleIncorrect, showCorrectness && !correct && (checked || previouslyAnswered) && styles$v.circleIncorrectAnswered) // used in BaseRadio to check if we actually clicked on the
|
|
24607
|
+
// radio icon
|
|
24608
|
+
,
|
|
24609
|
+
"data-is-radio-icon": true
|
|
24610
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
24611
|
+
className: "perseus-sr-only"
|
|
24612
|
+
}, a11yText), /*#__PURE__*/React.createElement("div", {
|
|
24613
|
+
"aria-hidden": true
|
|
24614
|
+
}, /*#__PURE__*/React.createElement(ChoiceInner, {
|
|
24615
|
+
letter: letter,
|
|
24616
|
+
showCorrectness: showCorrectness,
|
|
24617
|
+
correct: correct
|
|
24618
|
+
})))), crossedOut && /*#__PURE__*/React.createElement(CrossOutLine, {
|
|
24619
|
+
color: dynamicStyles.borderColor
|
|
24620
|
+
}));
|
|
24621
|
+
}
|
|
24811
24622
|
|
|
24812
|
-
var styles$
|
|
24813
|
-
|
|
24814
|
-
display: "block",
|
|
24815
|
-
borderRadius: SAT_ICON_SIZE,
|
|
24816
|
-
borderStyle: "solid",
|
|
24817
|
-
borderWidth: 2,
|
|
24818
|
-
content: "''",
|
|
24819
|
-
height: SAT_ICON_SIZE,
|
|
24820
|
-
width: SAT_ICON_SIZE,
|
|
24821
|
-
top: 1,
|
|
24822
|
-
left: 1
|
|
24823
|
-
},
|
|
24824
|
-
iconWrapper: {
|
|
24825
|
-
display: "inline-block",
|
|
24826
|
-
position: "relative"
|
|
24827
|
-
},
|
|
24828
|
-
crossOutLine: {
|
|
24829
|
-
// Center the icon within the container.
|
|
24830
|
-
position: "absolute",
|
|
24831
|
-
top: "calc(50% - ".concat(CROSS_OUT_LINE_SIZE / 2, "px)"),
|
|
24832
|
-
left: "calc(50% - ".concat(CROSS_OUT_LINE_SIZE / 2, "px)")
|
|
24833
|
-
},
|
|
24834
|
-
libraryCircle: {
|
|
24623
|
+
var styles$v = StyleSheet.create({
|
|
24624
|
+
circle: {
|
|
24835
24625
|
// Make the circle
|
|
24836
24626
|
width: LIBRARY_ICON_SIZE,
|
|
24837
24627
|
height: LIBRARY_ICON_SIZE,
|
|
24838
24628
|
boxSizing: "border-box",
|
|
24839
|
-
borderRadius: LIBRARY_ICON_SIZE,
|
|
24840
24629
|
borderStyle: "solid",
|
|
24841
24630
|
borderWidth: 2,
|
|
24842
24631
|
// The default icons have letters in them. Style those letters.
|
|
@@ -24857,18 +24646,113 @@ var styles$t = StyleSheet.create({
|
|
|
24857
24646
|
// pixel so it is much better centered.
|
|
24858
24647
|
lineHeight: "1px"
|
|
24859
24648
|
},
|
|
24860
|
-
|
|
24649
|
+
circleCorrect: {
|
|
24861
24650
|
fontSize: LIBRARY_ICON_SIZE
|
|
24862
24651
|
},
|
|
24863
|
-
|
|
24652
|
+
circleIncorrect: {
|
|
24864
24653
|
fontSize: LIBRARY_ICON_SIZE,
|
|
24865
24654
|
borderColor: gray68,
|
|
24866
24655
|
color: gray68
|
|
24867
24656
|
},
|
|
24868
|
-
|
|
24657
|
+
circleIncorrectAnswered: {
|
|
24869
24658
|
backgroundColor: Color.red,
|
|
24870
24659
|
borderColor: Color.red,
|
|
24871
24660
|
color: Color.white
|
|
24661
|
+
}
|
|
24662
|
+
});
|
|
24663
|
+
|
|
24664
|
+
/* Component for rendering a letter icon in a SAT radio choice */
|
|
24665
|
+
|
|
24666
|
+
// TODO(amy): figure out a better scheme for specifying these
|
|
24667
|
+
// styles that isn't such a pain to grok. See some neat ideas
|
|
24668
|
+
// from MDR in https://phabricator.khanacademy.org/D35249.
|
|
24669
|
+
function constructSATStyles(reviewMode, correct, checked, multipleSelect) {
|
|
24670
|
+
var backgroundColor;
|
|
24671
|
+
var borderColor = satBlue;
|
|
24672
|
+
var color = satBlue;
|
|
24673
|
+
|
|
24674
|
+
if (reviewMode) {
|
|
24675
|
+
if (correct) {
|
|
24676
|
+
borderColor = satCorrectColor;
|
|
24677
|
+
color = checked ? white$1 : satCorrectColor;
|
|
24678
|
+
backgroundColor = checked ? satCorrectColor : white$1;
|
|
24679
|
+
} else if (checked) {
|
|
24680
|
+
borderColor = satIncorrectColor;
|
|
24681
|
+
color = white$1;
|
|
24682
|
+
backgroundColor = satIncorrectColor;
|
|
24683
|
+
}
|
|
24684
|
+
} else if (checked) {
|
|
24685
|
+
color = white$1;
|
|
24686
|
+
backgroundColor = satBlue;
|
|
24687
|
+
}
|
|
24688
|
+
|
|
24689
|
+
var borderRadius;
|
|
24690
|
+
|
|
24691
|
+
if (multipleSelect) {
|
|
24692
|
+
borderRadius = 3;
|
|
24693
|
+
} else {
|
|
24694
|
+
borderRadius = SAT_ICON_SIZE;
|
|
24695
|
+
}
|
|
24696
|
+
|
|
24697
|
+
return {
|
|
24698
|
+
color,
|
|
24699
|
+
backgroundColor,
|
|
24700
|
+
borderColor,
|
|
24701
|
+
borderRadius
|
|
24702
|
+
};
|
|
24703
|
+
}
|
|
24704
|
+
|
|
24705
|
+
function SATChoiceIcon(props) {
|
|
24706
|
+
var {
|
|
24707
|
+
letter,
|
|
24708
|
+
a11yText,
|
|
24709
|
+
crossedOut,
|
|
24710
|
+
reviewMode,
|
|
24711
|
+
correct,
|
|
24712
|
+
checked,
|
|
24713
|
+
multipleSelect
|
|
24714
|
+
} = props;
|
|
24715
|
+
var {
|
|
24716
|
+
color,
|
|
24717
|
+
backgroundColor,
|
|
24718
|
+
borderColor,
|
|
24719
|
+
borderRadius
|
|
24720
|
+
} = constructSATStyles(reviewMode, correct, checked, multipleSelect);
|
|
24721
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24722
|
+
className: css(styles$x.iconWrapper)
|
|
24723
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
24724
|
+
className: css(styles$u.satCircle),
|
|
24725
|
+
"data-test-id": "choice-icon__sat-choice-icon",
|
|
24726
|
+
style: {
|
|
24727
|
+
backgroundColor,
|
|
24728
|
+
borderColor,
|
|
24729
|
+
borderRadius
|
|
24730
|
+
}
|
|
24731
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
24732
|
+
style: {
|
|
24733
|
+
color
|
|
24734
|
+
},
|
|
24735
|
+
className: css(styles$u.letter)
|
|
24736
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
24737
|
+
className: "perseus-sr-only"
|
|
24738
|
+
}, a11yText), /*#__PURE__*/React.createElement("span", {
|
|
24739
|
+
"aria-hidden": "true"
|
|
24740
|
+
}, letter)), crossedOut && /*#__PURE__*/React.createElement(CrossOutLine, {
|
|
24741
|
+
color: borderColor,
|
|
24742
|
+
sat: true
|
|
24743
|
+
}));
|
|
24744
|
+
}
|
|
24745
|
+
|
|
24746
|
+
var styles$u = StyleSheet.create({
|
|
24747
|
+
satCircle: {
|
|
24748
|
+
display: "block",
|
|
24749
|
+
borderStyle: "solid",
|
|
24750
|
+
borderWidth: 2,
|
|
24751
|
+
content: "''",
|
|
24752
|
+
height: SAT_ICON_SIZE,
|
|
24753
|
+
width: SAT_ICON_SIZE,
|
|
24754
|
+
top: 1,
|
|
24755
|
+
left: 1
|
|
24872
24756
|
},
|
|
24873
24757
|
letter: {
|
|
24874
24758
|
// These properties make sure that this element has the exact
|
|
@@ -24888,6 +24772,118 @@ var styles$t = StyleSheet.create({
|
|
|
24888
24772
|
}
|
|
24889
24773
|
});
|
|
24890
24774
|
|
|
24775
|
+
/* Component for rendering a letter icon in radio choice */
|
|
24776
|
+
|
|
24777
|
+
function getA11yText(letter, checked, correct, crossedOut, showCorrectness) {
|
|
24778
|
+
// There are two pieces of metadata we want to add to each a11yText:
|
|
24779
|
+
// whether the answer was checked/crossed-out/neither, and whether the
|
|
24780
|
+
// answer is correct/incorrect/not-yet-revealed.
|
|
24781
|
+
//
|
|
24782
|
+
// Translation is tricky for cross-product situations like this, so
|
|
24783
|
+
// we've just enumerated all 9 possibilities as separate strings.
|
|
24784
|
+
if (showCorrectness && correct) {
|
|
24785
|
+
if (checked) {
|
|
24786
|
+
return i18n._("(Choice %(letter)s, Checked, Correct)", {
|
|
24787
|
+
letter
|
|
24788
|
+
});
|
|
24789
|
+
}
|
|
24790
|
+
|
|
24791
|
+
if (crossedOut) {
|
|
24792
|
+
return i18n._("(Choice %(letter)s, Crossed out, Correct)", {
|
|
24793
|
+
letter
|
|
24794
|
+
});
|
|
24795
|
+
}
|
|
24796
|
+
|
|
24797
|
+
return i18n._("(Choice %(letter)s, Correct)", {
|
|
24798
|
+
letter
|
|
24799
|
+
});
|
|
24800
|
+
}
|
|
24801
|
+
|
|
24802
|
+
if (showCorrectness && !correct) {
|
|
24803
|
+
if (checked) {
|
|
24804
|
+
return i18n._("(Choice %(letter)s, Checked, Incorrect)", {
|
|
24805
|
+
letter
|
|
24806
|
+
});
|
|
24807
|
+
}
|
|
24808
|
+
|
|
24809
|
+
if (crossedOut) {
|
|
24810
|
+
return i18n._("(Choice %(letter)s, Crossed out, Incorrect)", {
|
|
24811
|
+
letter
|
|
24812
|
+
});
|
|
24813
|
+
}
|
|
24814
|
+
|
|
24815
|
+
return i18n._("(Choice %(letter)s, Incorrect)", {
|
|
24816
|
+
letter
|
|
24817
|
+
});
|
|
24818
|
+
}
|
|
24819
|
+
|
|
24820
|
+
if (checked) {
|
|
24821
|
+
return i18n._("(Choice %(letter)s, Checked)", {
|
|
24822
|
+
letter
|
|
24823
|
+
});
|
|
24824
|
+
}
|
|
24825
|
+
|
|
24826
|
+
if (crossedOut) {
|
|
24827
|
+
return i18n._("(Choice %(letter)s, Crossed out)", {
|
|
24828
|
+
letter
|
|
24829
|
+
});
|
|
24830
|
+
}
|
|
24831
|
+
|
|
24832
|
+
return i18n._("(Choice %(letter)s)", {
|
|
24833
|
+
letter
|
|
24834
|
+
});
|
|
24835
|
+
}
|
|
24836
|
+
|
|
24837
|
+
function ChoiceIcon(props) {
|
|
24838
|
+
var {
|
|
24839
|
+
pos,
|
|
24840
|
+
reviewMode,
|
|
24841
|
+
checked,
|
|
24842
|
+
crossedOut,
|
|
24843
|
+
correct,
|
|
24844
|
+
product,
|
|
24845
|
+
multipleSelect,
|
|
24846
|
+
showCorrectness,
|
|
24847
|
+
focused,
|
|
24848
|
+
hovered,
|
|
24849
|
+
pressed,
|
|
24850
|
+
primaryProductColor = Color.blue,
|
|
24851
|
+
previouslyAnswered,
|
|
24852
|
+
transparentBackground
|
|
24853
|
+
} = props;
|
|
24854
|
+
var letter = getChoiceLetter(pos);
|
|
24855
|
+
var a11yText = getA11yText(letter, checked, correct, crossedOut, showCorrectness);
|
|
24856
|
+
|
|
24857
|
+
if (product === "sat") {
|
|
24858
|
+
return /*#__PURE__*/React.createElement(SATChoiceIcon, {
|
|
24859
|
+
letter: letter,
|
|
24860
|
+
a11yText: a11yText,
|
|
24861
|
+
reviewMode: reviewMode,
|
|
24862
|
+
checked: checked,
|
|
24863
|
+
correct: correct,
|
|
24864
|
+
crossedOut: crossedOut,
|
|
24865
|
+
multipleSelect: multipleSelect
|
|
24866
|
+
});
|
|
24867
|
+
}
|
|
24868
|
+
|
|
24869
|
+
return /*#__PURE__*/React.createElement(LibraryChoiceIcon, {
|
|
24870
|
+
letter: letter,
|
|
24871
|
+
a11yText: a11yText,
|
|
24872
|
+
reviewMode: reviewMode,
|
|
24873
|
+
checked: checked,
|
|
24874
|
+
crossedOut: crossedOut,
|
|
24875
|
+
focused: focused,
|
|
24876
|
+
hovered: hovered,
|
|
24877
|
+
pressed: pressed,
|
|
24878
|
+
correct: correct,
|
|
24879
|
+
showCorrectness: showCorrectness,
|
|
24880
|
+
primaryProductColor: primaryProductColor,
|
|
24881
|
+
previouslyAnswered: previouslyAnswered,
|
|
24882
|
+
transparentBackground: transparentBackground,
|
|
24883
|
+
multipleSelect: multipleSelect
|
|
24884
|
+
});
|
|
24885
|
+
}
|
|
24886
|
+
|
|
24891
24887
|
/**
|
|
24892
24888
|
* Renders text indicating whether the choice was correct or
|
|
24893
24889
|
* not and whether the choice was selected or not.
|
|
@@ -24896,63 +24892,68 @@ var styles$t = StyleSheet.create({
|
|
|
24896
24892
|
* between the states more immediately clear to users.
|
|
24897
24893
|
*/
|
|
24898
24894
|
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
}
|
|
24895
|
+
function renderText(checked, correct, crossedOut) {
|
|
24896
|
+
if (correct) {
|
|
24897
|
+
// For correct answers, we surface checked _or_ crossedOut state,
|
|
24898
|
+
// because any interaction with the correct answer is noteworthy!
|
|
24899
|
+
if (checked) {
|
|
24900
|
+
return i18n._("Correct (selected)");
|
|
24901
|
+
}
|
|
24906
24902
|
|
|
24907
|
-
if (
|
|
24908
|
-
|
|
24909
|
-
|
|
24910
|
-
if (checked) {
|
|
24911
|
-
return i18n._("Correct (selected)");
|
|
24912
|
-
}
|
|
24903
|
+
if (crossedOut) {
|
|
24904
|
+
return i18n._("Correct (but you crossed it out)");
|
|
24905
|
+
}
|
|
24913
24906
|
|
|
24914
|
-
|
|
24915
|
-
|
|
24916
|
-
|
|
24907
|
+
return i18n._("Correct");
|
|
24908
|
+
} // But, for incorrect answers, we only surface checked state,
|
|
24909
|
+
// because crossing out an incorrect answer is not noteworthy.
|
|
24917
24910
|
|
|
24918
|
-
return i18n._("Correct");
|
|
24919
|
-
} // But, for incorrect answers, we only surface checked state,
|
|
24920
|
-
// because crossing out an incorrect answer is not noteworthy.
|
|
24921
24911
|
|
|
24912
|
+
if (checked) {
|
|
24913
|
+
return i18n._("Incorrect (selected)");
|
|
24914
|
+
}
|
|
24922
24915
|
|
|
24923
|
-
|
|
24924
|
-
|
|
24925
|
-
}
|
|
24916
|
+
return i18n._("Incorrect");
|
|
24917
|
+
}
|
|
24926
24918
|
|
|
24927
|
-
|
|
24919
|
+
function OptionStatus(props) {
|
|
24920
|
+
var {
|
|
24921
|
+
checked,
|
|
24922
|
+
correct,
|
|
24923
|
+
crossedOut,
|
|
24924
|
+
previouslyAnswered,
|
|
24925
|
+
reviewMode,
|
|
24926
|
+
satStyling
|
|
24927
|
+
} = props; // Option status is exclued for SAT
|
|
24928
|
+
|
|
24929
|
+
if (satStyling) {
|
|
24930
|
+
return null;
|
|
24931
|
+
} // Option status is shown only in review mode, or for incorrectly
|
|
24932
|
+
// answered items.
|
|
24933
|
+
|
|
24934
|
+
|
|
24935
|
+
if (!reviewMode && !previouslyAnswered) {
|
|
24936
|
+
return null;
|
|
24928
24937
|
}
|
|
24929
24938
|
|
|
24930
|
-
|
|
24931
|
-
var {
|
|
24932
|
-
checked,
|
|
24933
|
-
correct,
|
|
24934
|
-
previouslyAnswered
|
|
24935
|
-
} = this.props;
|
|
24936
|
-
var textStyle;
|
|
24939
|
+
var textStyle;
|
|
24937
24940
|
|
|
24938
|
-
|
|
24939
|
-
|
|
24941
|
+
if (correct) {
|
|
24942
|
+
textStyle = styles$t.correct;
|
|
24943
|
+
} else {
|
|
24944
|
+
if (checked || previouslyAnswered) {
|
|
24945
|
+
textStyle = styles$t.incorrectAnswered;
|
|
24940
24946
|
} else {
|
|
24941
|
-
|
|
24942
|
-
textStyle = styles$s.incorrectAnswered;
|
|
24943
|
-
} else {
|
|
24944
|
-
textStyle = styles$s.incorrect;
|
|
24945
|
-
}
|
|
24947
|
+
textStyle = styles$t.incorrect;
|
|
24946
24948
|
}
|
|
24947
|
-
|
|
24948
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
24949
|
-
className: css(styles$s.text, textStyle)
|
|
24950
|
-
}, this._renderText());
|
|
24951
24949
|
}
|
|
24952
24950
|
|
|
24951
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24952
|
+
className: css(styles$t.text, textStyle)
|
|
24953
|
+
}, renderText(checked, correct, crossedOut));
|
|
24953
24954
|
}
|
|
24954
24955
|
|
|
24955
|
-
var styles$
|
|
24956
|
+
var styles$t = StyleSheet.create({
|
|
24956
24957
|
text: {
|
|
24957
24958
|
alignItems: "center",
|
|
24958
24959
|
display: "flex",
|
|
@@ -24979,316 +24980,206 @@ var ellipsisHorizontalIcon = {
|
|
|
24979
24980
|
height: 27.284
|
|
24980
24981
|
};
|
|
24981
24982
|
|
|
24982
|
-
|
|
24983
|
-
|
|
24984
|
-
|
|
24985
|
-
|
|
24986
|
-
|
|
24987
|
-
|
|
24988
|
-
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
|
|
25004
|
-
|
|
25005
|
-
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25009
|
-
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
} // Option status is shown only in review mode, or for incorrectly
|
|
25013
|
-
// answered items.
|
|
25014
|
-
|
|
25015
|
-
|
|
25016
|
-
if (!reviewMode && !previouslyAnswered) {
|
|
25017
|
-
return null;
|
|
25018
|
-
}
|
|
25019
|
-
|
|
25020
|
-
return /*#__PURE__*/React.createElement(OptionStatus, {
|
|
25021
|
-
checked: checked,
|
|
25022
|
-
correct: correct,
|
|
25023
|
-
crossedOut: crossedOut,
|
|
25024
|
-
previouslyAnswered: previouslyAnswered
|
|
25025
|
-
});
|
|
25026
|
-
});
|
|
25027
|
-
|
|
25028
|
-
_defineProperty(this, "renderChoiceIcon", _ref => {
|
|
25029
|
-
var {
|
|
25030
|
-
isFocused,
|
|
25031
|
-
isPressed
|
|
25032
|
-
} = _ref;
|
|
25033
|
-
var {
|
|
25034
|
-
radioStyleVersion,
|
|
25035
|
-
primaryProductColor
|
|
25036
|
-
} = this.props.apiOptions.styling;
|
|
25037
|
-
var finalStyles = typeof radioStyleVersion === "undefined" ? false : radioStyleVersion === "final";
|
|
25038
|
-
|
|
25039
|
-
if (!finalStyles && !this.props.apiOptions.satStyling) {
|
|
25040
|
-
return null;
|
|
25041
|
-
}
|
|
25042
|
-
|
|
25043
|
-
return /*#__PURE__*/React.createElement(ChoiceIcon, {
|
|
25044
|
-
pos: this.props.pos,
|
|
25045
|
-
correct: this.props.correct,
|
|
25046
|
-
crossedOut: this.props.crossedOut,
|
|
25047
|
-
pressed: isPressed,
|
|
25048
|
-
focused: isFocused,
|
|
25049
|
-
checked: this.props.checked,
|
|
25050
|
-
showCorrectness: this.props.showCorrectness,
|
|
25051
|
-
reviewMode: this.props.reviewMode,
|
|
25052
|
-
product: this.props.apiOptions.satStyling ? "sat" : "library",
|
|
25053
|
-
primaryProductColor: primaryProductColor,
|
|
25054
|
-
previouslyAnswered: this.props.previouslyAnswered
|
|
25055
|
-
});
|
|
25056
|
-
});
|
|
24983
|
+
function Choice(props) {
|
|
24984
|
+
var {
|
|
24985
|
+
disabled,
|
|
24986
|
+
checked,
|
|
24987
|
+
content,
|
|
24988
|
+
crossedOut,
|
|
24989
|
+
showCorrectness,
|
|
24990
|
+
multipleSelect,
|
|
24991
|
+
onChange,
|
|
24992
|
+
reviewMode,
|
|
24993
|
+
correct,
|
|
24994
|
+
apiOptions,
|
|
24995
|
+
previouslyAnswered,
|
|
24996
|
+
pos,
|
|
24997
|
+
showRationale,
|
|
24998
|
+
rationale,
|
|
24999
|
+
forwardedRef
|
|
25000
|
+
} = props;
|
|
25001
|
+
var [isInputFocused, setIsInputFocused] = useState(false);
|
|
25002
|
+
useEffect(() => {
|
|
25003
|
+
if (isInputFocused && disabled) {
|
|
25004
|
+
setIsInputFocused(false);
|
|
25005
|
+
}
|
|
25006
|
+
}, [disabled, isInputFocused, setIsInputFocused]); // Call `this.props.onChange` with the given values. Any keys that are not
|
|
25007
|
+
// specified will be filled in with the current value. (For example, if
|
|
25008
|
+
// `checked` is specified but `crossedOut` is not, then `crossedOut` will
|
|
25009
|
+
// be filled in with `this.props.crossedOut`.)
|
|
25010
|
+
//
|
|
25011
|
+
// This enables us to use shorthand inside this component, while
|
|
25012
|
+
// maintaining a consistent API for the parent.
|
|
25057
25013
|
|
|
25058
|
-
|
|
25059
|
-
|
|
25014
|
+
function sendChange(newValues) {
|
|
25015
|
+
var _newValues$checked, _newValues$crossedOut;
|
|
25060
25016
|
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25064
|
-
|
|
25065
|
-
|
|
25066
|
-
});
|
|
25017
|
+
var updatedChecked = (_newValues$checked = newValues.checked) !== null && _newValues$checked !== void 0 ? _newValues$checked : checked;
|
|
25018
|
+
var updatedCrossedOut = (_newValues$crossedOut = newValues.crossedOut) !== null && _newValues$crossedOut !== void 0 ? _newValues$crossedOut : crossedOut;
|
|
25019
|
+
onChange({
|
|
25020
|
+
checked: updatedChecked,
|
|
25021
|
+
crossedOut: updatedCrossedOut
|
|
25067
25022
|
});
|
|
25023
|
+
} // HACK: while most of the styling for rendering SAT items is handled
|
|
25024
|
+
// via aphrodite, we also need to assign normal CSS classnames here to
|
|
25025
|
+
// special-case the coloring of MathJax formulas (see .MathJax .math in
|
|
25026
|
+
// stylesheets/task-package/tasks.less)
|
|
25068
25027
|
|
|
25069
|
-
_defineProperty(this, "focusInput", () => {
|
|
25070
|
-
var _this$_input;
|
|
25071
25028
|
|
|
25072
|
-
|
|
25073
|
-
|
|
25074
|
-
|
|
25029
|
+
var satCorrectChoice = apiOptions.satStyling && reviewMode && correct;
|
|
25030
|
+
var satIncorrectChecked = apiOptions.satStyling && reviewMode && !correct && checked;
|
|
25031
|
+
var descriptionClassName = classNames("description", satCorrectChoice && "sat-correct", satIncorrectChecked && "sat-incorrect", css(!apiOptions.satStyling && styles$s.description, apiOptions.satStyling && styles$s.satDescription, satCorrectChoice && styles$s.satDescriptionCorrect, satCorrectChoice && checked && styles$s.satDescriptionCorrectChecked, satIncorrectChecked && styles$s.satDescriptionIncorrectChecked));
|
|
25032
|
+
var rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$s.rationale, !apiOptions.satStyling && styles$s.nonSatRationale, apiOptions.satStyling && styles$s.satReviewRationale)); // We want to show the choices as dimmed out when the choices are
|
|
25033
|
+
// disabled. However, we don't want to do this in the SAT product and
|
|
25034
|
+
// we also don't want to do this when we're in review mode in the
|
|
25035
|
+
// content library.
|
|
25075
25036
|
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25037
|
+
var showDimmed = !apiOptions.satStyling && !reviewMode && apiOptions.readOnly || crossedOut;
|
|
25038
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
25039
|
+
style: {
|
|
25040
|
+
dispay: "flex",
|
|
25041
|
+
flexDirection: "column"
|
|
25081
25042
|
}
|
|
25082
|
-
}
|
|
25043
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
25044
|
+
style: {
|
|
25045
|
+
display: "flex",
|
|
25046
|
+
flexDirection: "row",
|
|
25047
|
+
width: "100%",
|
|
25048
|
+
opacity: showDimmed ? 0.5 : 1.0
|
|
25049
|
+
}
|
|
25050
|
+
}, /*#__PURE__*/React.createElement(Clickable, {
|
|
25051
|
+
onClick: () => {
|
|
25052
|
+
// If we're checking a crossed-out option, let's
|
|
25053
|
+
// also uncross it.
|
|
25054
|
+
sendChange({
|
|
25055
|
+
checked: !checked,
|
|
25056
|
+
crossedOut: false
|
|
25057
|
+
});
|
|
25058
|
+
},
|
|
25059
|
+
className: descriptionClassName,
|
|
25060
|
+
disabled: disabled || apiOptions.staticRender || apiOptions.readOnly,
|
|
25061
|
+
"aria-label": "Select Choice ".concat(getChoiceLetter(pos)),
|
|
25062
|
+
"aria-checked": checked ? "true" : "false",
|
|
25063
|
+
role: "checkbox",
|
|
25064
|
+
style: {
|
|
25065
|
+
flex: 1
|
|
25066
|
+
},
|
|
25067
|
+
ref: forwardedRef
|
|
25068
|
+
}, _ref => {
|
|
25069
|
+
var _apiOptions$styling;
|
|
25083
25070
|
|
|
25084
|
-
render() {
|
|
25085
|
-
var sat = this.props.apiOptions.satStyling;
|
|
25086
25071
|
var {
|
|
25087
|
-
|
|
25088
|
-
|
|
25089
|
-
|
|
25090
|
-
} =
|
|
25091
|
-
// via aphrodite, we also need to assign normal CSS classnames here to
|
|
25092
|
-
// special-case the coloring of MathJax formulas (see .MathJax .math in
|
|
25093
|
-
// stylesheets/task-package/tasks.less)
|
|
25094
|
-
|
|
25095
|
-
var satCorrectChoice = sat && reviewMode && correct;
|
|
25096
|
-
var satIncorrectChecked = sat && reviewMode && !correct && checked;
|
|
25097
|
-
var descriptionClassName = classNames("description", satCorrectChoice && "sat-correct", satIncorrectChecked && "sat-incorrect", css(!sat && styles$r.description, sat && styles$r.satDescription, satCorrectChoice && styles$r.satDescriptionCorrect, satCorrectChoice && checked && styles$r.satDescriptionCorrectChecked, satIncorrectChecked && styles$r.satDescriptionIncorrectChecked));
|
|
25098
|
-
var rationaleClassName = classNames("perseus-radio-rationale-content", css(styles$r.rationale, !sat && styles$r.nonSatRationale, sat && styles$r.satReviewRationale)); // We want to show the choices as dimmed out when the choices are
|
|
25099
|
-
// disabled. However, we don't want to do this in the SAT product and
|
|
25100
|
-
// we also don't want to do this when we're in review mode in the
|
|
25101
|
-
// content library.
|
|
25102
|
-
|
|
25103
|
-
var showDimmed = !sat && !reviewMode && this.props.apiOptions.readOnly || this.props.crossedOut;
|
|
25072
|
+
hovered,
|
|
25073
|
+
focused,
|
|
25074
|
+
pressed
|
|
25075
|
+
} = _ref;
|
|
25104
25076
|
return /*#__PURE__*/React.createElement("div", {
|
|
25105
|
-
style: {
|
|
25106
|
-
dispay: "flex",
|
|
25107
|
-
flexDirection: "column"
|
|
25108
|
-
}
|
|
25109
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
25110
25077
|
style: {
|
|
25111
25078
|
display: "flex",
|
|
25112
25079
|
flexDirection: "row",
|
|
25113
|
-
|
|
25114
|
-
|
|
25080
|
+
justifyContent: "center",
|
|
25081
|
+
alignContent: "center",
|
|
25082
|
+
paddingTop: Spacing.xSmall_8,
|
|
25083
|
+
paddingBottom: Spacing.xSmall_8
|
|
25115
25084
|
}
|
|
25116
|
-
}, /*#__PURE__*/React.createElement(
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25085
|
+
}, /*#__PURE__*/React.createElement(ChoiceIcon, {
|
|
25086
|
+
pos: pos,
|
|
25087
|
+
correct: correct,
|
|
25088
|
+
crossedOut: crossedOut,
|
|
25089
|
+
pressed: pressed,
|
|
25090
|
+
focused: focused,
|
|
25091
|
+
checked: checked,
|
|
25092
|
+
hovered: hovered,
|
|
25093
|
+
showCorrectness: showCorrectness,
|
|
25094
|
+
multipleSelect: multipleSelect,
|
|
25095
|
+
reviewMode: reviewMode,
|
|
25096
|
+
product: apiOptions.satStyling ? "sat" : "library",
|
|
25097
|
+
primaryProductColor: (_apiOptions$styling = apiOptions.styling) === null || _apiOptions$styling === void 0 ? void 0 : _apiOptions$styling.primaryProductColor,
|
|
25098
|
+
previouslyAnswered: previouslyAnswered
|
|
25099
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
25130
25100
|
style: {
|
|
25131
|
-
|
|
25101
|
+
paddingLeft: Spacing.small_12,
|
|
25102
|
+
textAlign: "left",
|
|
25103
|
+
flex: 1,
|
|
25104
|
+
paddingTop: 4
|
|
25132
25105
|
}
|
|
25133
|
-
},
|
|
25106
|
+
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(OptionStatus, {
|
|
25107
|
+
checked: checked,
|
|
25108
|
+
correct: correct,
|
|
25109
|
+
crossedOut: crossedOut,
|
|
25110
|
+
previouslyAnswered: previouslyAnswered,
|
|
25111
|
+
reviewMode: reviewMode,
|
|
25112
|
+
satStyling: apiOptions.satStyling
|
|
25113
|
+
})), /*#__PURE__*/React.createElement("div", null, content)));
|
|
25114
|
+
}), apiOptions.crossOutEnabled && !reviewMode && /*#__PURE__*/React.createElement(Popover, {
|
|
25115
|
+
dismissEnabled: true,
|
|
25116
|
+
content: _ref2 => {
|
|
25134
25117
|
var {
|
|
25135
|
-
|
|
25136
|
-
focused,
|
|
25137
|
-
pressed
|
|
25118
|
+
close
|
|
25138
25119
|
} = _ref2;
|
|
25139
|
-
return /*#__PURE__*/React.createElement(
|
|
25140
|
-
|
|
25141
|
-
|
|
25142
|
-
|
|
25143
|
-
|
|
25144
|
-
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
close
|
|
25164
|
-
} = _ref3;
|
|
25165
|
-
return /*#__PURE__*/React.createElement(PopoverContent, {
|
|
25166
|
-
title: "Cross out",
|
|
25167
|
-
content: "Cross out option",
|
|
25168
|
-
closeButtonVisible: true,
|
|
25169
|
-
actions: /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
|
|
25170
|
-
size: Spacing.medium_16
|
|
25171
|
-
}), /*#__PURE__*/React.createElement(Button, {
|
|
25172
|
-
kind: "primary",
|
|
25173
|
-
"aria-label": "Cross out Choice ".concat(getChoiceLetter(this.props.pos)),
|
|
25174
|
-
disabled: this.props.apiOptions.readOnly || reviewMode,
|
|
25175
|
-
onClick: () => {
|
|
25176
|
-
if (!this.props.crossedOut) {
|
|
25177
|
-
// If we're crossing
|
|
25178
|
-
// out a checked
|
|
25179
|
-
// option, let's also
|
|
25180
|
-
// uncheck it.
|
|
25181
|
-
this._sendChange({
|
|
25182
|
-
checked: false,
|
|
25183
|
-
crossedOut: true
|
|
25184
|
-
});
|
|
25185
|
-
} else {
|
|
25186
|
-
this._sendChange({
|
|
25187
|
-
crossedOut: false
|
|
25188
|
-
});
|
|
25189
|
-
}
|
|
25190
|
-
|
|
25191
|
-
close();
|
|
25120
|
+
return /*#__PURE__*/React.createElement(PopoverContent, {
|
|
25121
|
+
title: "Cross out",
|
|
25122
|
+
content: "Cross out option",
|
|
25123
|
+
closeButtonVisible: true,
|
|
25124
|
+
actions: /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Strut, {
|
|
25125
|
+
size: Spacing.medium_16
|
|
25126
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
25127
|
+
kind: "primary",
|
|
25128
|
+
"aria-label": "Cross out Choice ".concat(getChoiceLetter(pos)),
|
|
25129
|
+
disabled: apiOptions.readOnly || reviewMode,
|
|
25130
|
+
onClick: () => {
|
|
25131
|
+
if (!crossedOut) {
|
|
25132
|
+
// If we're crossing
|
|
25133
|
+
// out a checked
|
|
25134
|
+
// option, let's also
|
|
25135
|
+
// uncheck it.
|
|
25136
|
+
sendChange({
|
|
25137
|
+
checked: false,
|
|
25138
|
+
crossedOut: true
|
|
25139
|
+
});
|
|
25140
|
+
} else {
|
|
25141
|
+
sendChange({
|
|
25142
|
+
crossedOut: false
|
|
25143
|
+
});
|
|
25192
25144
|
}
|
|
25193
|
-
|
|
25194
|
-
|
|
25195
|
-
|
|
25145
|
+
|
|
25146
|
+
close();
|
|
25147
|
+
}
|
|
25148
|
+
}, crossedOut ? "Bring back" : "Cross out"))
|
|
25149
|
+
});
|
|
25150
|
+
}
|
|
25151
|
+
}, _ref3 => {
|
|
25152
|
+
var {
|
|
25153
|
+
open
|
|
25154
|
+
} = _ref3;
|
|
25155
|
+
return /*#__PURE__*/React.createElement(Clickable, {
|
|
25156
|
+
onClick: open,
|
|
25157
|
+
"aria-label": "Open menu for Choice ".concat(getChoiceLetter(pos)),
|
|
25158
|
+
disabled: apiOptions.staticRender
|
|
25196
25159
|
}, _ref4 => {
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
onClick: open,
|
|
25202
|
-
"aria-label": "Open menu for Choice ".concat(getChoiceLetter(this.props.pos)),
|
|
25203
|
-
disabled: this.props.apiOptions.staticRender
|
|
25204
|
-
}, _ref5 => {
|
|
25205
|
-
return /*#__PURE__*/React.createElement(Icon, {
|
|
25206
|
-
icon: ellipsisHorizontalIcon,
|
|
25207
|
-
size: 3,
|
|
25208
|
-
color: Color.offBlack64
|
|
25209
|
-
});
|
|
25160
|
+
return /*#__PURE__*/React.createElement(Icon, {
|
|
25161
|
+
icon: ellipsisHorizontalIcon,
|
|
25162
|
+
size: 3,
|
|
25163
|
+
color: Color.offBlack64
|
|
25210
25164
|
});
|
|
25211
|
-
})
|
|
25212
|
-
|
|
25213
|
-
|
|
25214
|
-
|
|
25215
|
-
}
|
|
25216
|
-
|
|
25165
|
+
});
|
|
25166
|
+
})), showRationale && /*#__PURE__*/React.createElement("div", {
|
|
25167
|
+
className: rationaleClassName,
|
|
25168
|
+
"data-test-id": "perseus-radio-rationale-content-".concat(pos)
|
|
25169
|
+
}, rationale));
|
|
25217
25170
|
}
|
|
25218
25171
|
|
|
25219
|
-
|
|
25220
|
-
|
|
25221
|
-
// This change will also require make sure that item-renderer.jsx and
|
|
25222
|
-
// server-item-renderer.jsx have appropriate defaults for apiOptions
|
|
25223
|
-
// because many of the properties on Options.propTypes are required.
|
|
25224
|
-
apiOptions: PropTypes.shape({
|
|
25225
|
-
satStyling: PropTypes.bool,
|
|
25226
|
-
isMobile: PropTypes.bool,
|
|
25227
|
-
styling: PropTypes.shape({
|
|
25228
|
-
radioStyleVersion: PropTypes.oneOf(["intermediate", "final"]),
|
|
25229
|
-
primaryProductColor: PropTypes.string
|
|
25230
|
-
}),
|
|
25231
|
-
readOnly: PropTypes.bool
|
|
25232
|
-
}),
|
|
25233
|
-
checked: PropTypes.bool,
|
|
25234
|
-
className: PropTypes.string,
|
|
25235
|
-
rationale: PropTypes.node,
|
|
25236
|
-
content: PropTypes.node,
|
|
25237
|
-
correct: PropTypes.bool,
|
|
25238
|
-
deselectEnabled: PropTypes.bool,
|
|
25239
|
-
disabled: PropTypes.bool,
|
|
25240
|
-
editMode: PropTypes.bool,
|
|
25241
|
-
groupName: PropTypes.string,
|
|
25242
|
-
isLastChoice: PropTypes.bool,
|
|
25243
|
-
// Needed for border styling
|
|
25244
|
-
// This indicates the position of the choice relative to others
|
|
25245
|
-
// (so that we can display a nice little (A), (B), etc. next to it)
|
|
25246
|
-
// Also used to generate an id for each input.
|
|
25247
|
-
pos: PropTypes.number,
|
|
25248
|
-
reviewMode: PropTypes.bool,
|
|
25249
|
-
showRationale: PropTypes.bool,
|
|
25250
|
-
showCorrectness: PropTypes.bool,
|
|
25251
|
-
type: PropTypes.string,
|
|
25252
|
-
// Indicates whether the user has "crossed out" this choice, meaning
|
|
25253
|
-
// that they don't think it's correct. This value does not affect
|
|
25254
|
-
// scoring or other behavior; it's just a note for the user's
|
|
25255
|
-
// reference.
|
|
25256
|
-
crossedOut: PropTypes.bool,
|
|
25257
|
-
// Indicates that the user has previously selected this answer. These
|
|
25258
|
-
// answers may be rendered orange in review, rather than grey if
|
|
25259
|
-
// incorrect.
|
|
25260
|
-
previouslyAnswered: PropTypes.bool,
|
|
25261
|
-
// A callback indicating that this choice has changed. Its argument is
|
|
25262
|
-
// an object with two keys: `checked` and `crossedOut`. Each contains a
|
|
25263
|
-
// boolean value specifying the new checked and crossed-out value of
|
|
25264
|
-
// this choice.
|
|
25265
|
-
onChange: PropTypes.func,
|
|
25266
|
-
// Callbacks for when the user presses the up arrow or down arrow
|
|
25267
|
-
// (respectively) to navigate between choices. When called, the parent
|
|
25268
|
-
// finds the prev/next choice, focuses the input, and checks the radio
|
|
25269
|
-
// button if appropriate. (The reason we have custom behavior is that
|
|
25270
|
-
// we actually _don't_ want to auto-select crossed-out choices!)
|
|
25271
|
-
goToPrevChoice: PropTypes.func.isRequired,
|
|
25272
|
-
goToNextChoice: PropTypes.func.isRequired
|
|
25273
|
-
});
|
|
25274
|
-
|
|
25275
|
-
_defineProperty(Choice, "defaultProps", {
|
|
25276
|
-
apiOptions: {
|
|
25277
|
-
styling: {}
|
|
25278
|
-
},
|
|
25172
|
+
Choice.defaultProps = {
|
|
25173
|
+
disabled: false,
|
|
25279
25174
|
checked: false,
|
|
25280
|
-
|
|
25175
|
+
onChange: newValues => {},
|
|
25281
25176
|
correct: false,
|
|
25282
|
-
|
|
25283
|
-
|
|
25284
|
-
onChange: function onChange() {},
|
|
25285
|
-
showRationale: false,
|
|
25286
|
-
type: "radio",
|
|
25177
|
+
apiOptions: ApiOptions.defaults,
|
|
25178
|
+
previouslyAnswered: false,
|
|
25287
25179
|
pos: 0,
|
|
25288
|
-
|
|
25289
|
-
}
|
|
25290
|
-
|
|
25291
|
-
var styles$r = StyleSheet.create({
|
|
25180
|
+
showRationale: false
|
|
25181
|
+
};
|
|
25182
|
+
var styles$s = StyleSheet.create({
|
|
25292
25183
|
description: {
|
|
25293
25184
|
display: "inline-block",
|
|
25294
25185
|
width: "100%"
|
|
@@ -25328,185 +25219,87 @@ var styles$r = StyleSheet.create({
|
|
|
25328
25219
|
marginLeft: 45
|
|
25329
25220
|
}
|
|
25330
25221
|
});
|
|
25222
|
+
var Choice$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(Choice, _extends({}, props, {
|
|
25223
|
+
forwardedRef: ref
|
|
25224
|
+
})));
|
|
25331
25225
|
|
|
25332
|
-
|
|
25333
|
-
constructor() {
|
|
25334
|
-
super(...arguments);
|
|
25226
|
+
var _excluded$2 = ["showContent", "content", "forwardedRef"];
|
|
25335
25227
|
|
|
25336
|
-
|
|
25337
|
-
|
|
25338
|
-
|
|
25339
|
-
|
|
25340
|
-
|
|
25341
|
-
}
|
|
25342
|
-
|
|
25343
|
-
|
|
25344
|
-
|
|
25345
|
-
|
|
25346
|
-
|
|
25347
|
-
|
|
25348
|
-
|
|
25349
|
-
|
|
25350
|
-
|
|
25351
|
-
|
|
25352
|
-
|
|
25353
|
-
|
|
25354
|
-
|
|
25355
|
-
|
|
25356
|
-
|
|
25357
|
-
|
|
25358
|
-
|
|
25359
|
-
|
|
25360
|
-
})
|
|
25361
|
-
|
|
25362
|
-
return /*#__PURE__*/React.createElement(Choice, choiceProps);
|
|
25363
|
-
}
|
|
25228
|
+
function ChoiceNoneAbove(props) {
|
|
25229
|
+
var {
|
|
25230
|
+
showContent,
|
|
25231
|
+
content,
|
|
25232
|
+
forwardedRef
|
|
25233
|
+
} = props,
|
|
25234
|
+
rest = _objectWithoutProperties(props, _excluded$2);
|
|
25235
|
+
|
|
25236
|
+
var choiceProps = _objectSpread2(_objectSpread2({}, rest), {}, {
|
|
25237
|
+
content: showContent ? content :
|
|
25238
|
+
/*#__PURE__*/
|
|
25239
|
+
// We use a Renderer here because that is how
|
|
25240
|
+
// `this.props.content` is wrapped otherwise.
|
|
25241
|
+
// We pass in a key here so that we avoid a semi-spurious
|
|
25242
|
+
// react warning when we render this in the same place
|
|
25243
|
+
// as the previous choice content renderer.
|
|
25244
|
+
// Note this destroys state, but since all we're doing
|
|
25245
|
+
// is outputting "None of the above", that is okay.
|
|
25246
|
+
//
|
|
25247
|
+
// todo(matthewc): this seems like way overkill
|
|
25248
|
+
// just to render a string
|
|
25249
|
+
React.createElement(Renderer, {
|
|
25250
|
+
key: "noneOfTheAboveRenderer",
|
|
25251
|
+
content: i18n._("None of the above")
|
|
25252
|
+
})
|
|
25253
|
+
});
|
|
25364
25254
|
|
|
25255
|
+
return /*#__PURE__*/React.createElement(Choice$1, _extends({}, choiceProps, {
|
|
25256
|
+
ref: forwardedRef
|
|
25257
|
+
}));
|
|
25365
25258
|
}
|
|
25366
25259
|
|
|
25367
|
-
|
|
25368
|
-
className: PropTypes.string,
|
|
25369
|
-
content: PropTypes.node,
|
|
25370
|
-
showContent: PropTypes.bool
|
|
25371
|
-
});
|
|
25372
|
-
|
|
25373
|
-
_defineProperty(ChoiceNoneAbove, "defaultProps", {
|
|
25260
|
+
ChoiceNoneAbove.defaultProps = {
|
|
25374
25261
|
showContent: true
|
|
25375
|
-
}
|
|
25262
|
+
};
|
|
25263
|
+
var ChoiceNoneAbove$1 = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(ChoiceNoneAbove, _extends({}, props, {
|
|
25264
|
+
forwardedRef: ref
|
|
25265
|
+
})));
|
|
25376
25266
|
|
|
25377
25267
|
var {
|
|
25378
25268
|
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
25379
|
-
} = Util;
|
|
25380
|
-
var ChoicesType = PropTypes.arrayOf(PropTypes.shape({
|
|
25381
|
-
// Indicates whether this choice is checked.
|
|
25382
|
-
checked: PropTypes.bool,
|
|
25383
|
-
// Indicates whether the user has "crossed out" this choice, meaning
|
|
25384
|
-
// that they don't think it's correct. This value does not affect
|
|
25385
|
-
// scoring or other behavior; it's just a note for the user's
|
|
25386
|
-
// reference.
|
|
25387
|
-
crossedOut: PropTypes.bool,
|
|
25388
|
-
content: PropTypes.node,
|
|
25389
|
-
rationale: PropTypes.node,
|
|
25390
|
-
hasRationale: PropTypes.bool,
|
|
25391
|
-
showRationale: PropTypes.bool,
|
|
25392
|
-
showCorrectness: PropTypes.bool,
|
|
25393
|
-
correct: PropTypes.bool,
|
|
25394
|
-
originalIndex: PropTypes.number,
|
|
25395
|
-
isNoneOfTheAbove: PropTypes.bool
|
|
25396
|
-
}));
|
|
25397
|
-
var radioBorderColor = radioBorderColor$2;
|
|
25398
|
-
|
|
25399
|
-
class BaseRadio extends React.Component {
|
|
25400
|
-
constructor() {
|
|
25401
|
-
super(...arguments);
|
|
25402
|
-
|
|
25403
|
-
_defineProperty(this, "state", {
|
|
25404
|
-
// TODO(mdr): This keeps the ID stable across re-renders on the
|
|
25405
|
-
// same machine, but, at time of writing, the server's state
|
|
25406
|
-
// isn't rehydrated to the client during SSR, so the server and
|
|
25407
|
-
// client will generate different IDs and cause a mismatch
|
|
25408
|
-
// during SSR :(
|
|
25409
|
-
radioGroupName: _.uniqueId("perseus_radio_")
|
|
25410
|
-
});
|
|
25411
|
-
|
|
25412
|
-
_defineProperty(this, "updateChoice", (choiceIndex, newValues) => {
|
|
25413
|
-
// Get the baseline `checked` values. If we're checking a new answer
|
|
25414
|
-
// and multiple-select is not on, we should clear all choices to be
|
|
25415
|
-
// unchecked. Otherwise, we should copy the old checked values.
|
|
25416
|
-
var newCheckedList;
|
|
25417
|
-
|
|
25418
|
-
if (newValues.checked && !this.props.multipleSelect) {
|
|
25419
|
-
newCheckedList = this.props.choices.map(_ => false);
|
|
25420
|
-
} else {
|
|
25421
|
-
newCheckedList = this.props.choices.map(c => c.checked);
|
|
25422
|
-
} // Get the baseline `crossedOut` values.
|
|
25269
|
+
} = Util; // exported for tests
|
|
25423
25270
|
|
|
25424
|
-
|
|
25425
|
-
|
|
25426
|
-
|
|
25427
|
-
|
|
25428
|
-
|
|
25429
|
-
this.props.onChange({
|
|
25430
|
-
checked: newCheckedList,
|
|
25431
|
-
crossedOut: newCrossedOutList
|
|
25271
|
+
function getInstructionsText(multipleSelect, countChoices, numCorrect) {
|
|
25272
|
+
if (multipleSelect) {
|
|
25273
|
+
if (countChoices) {
|
|
25274
|
+
return i18n._("Choose %(numCorrect)s answers:", {
|
|
25275
|
+
numCorrect: numCorrect
|
|
25432
25276
|
});
|
|
25433
|
-
}
|
|
25434
|
-
|
|
25435
|
-
_defineProperty(this, "focus", i => {
|
|
25436
|
-
// $FlowFixMe[incompatible-use]
|
|
25437
|
-
// $FlowFixMe[prop-missing]
|
|
25438
|
-
ReactDOM__default.findDOMNode(this.refs["radio" + (i || 0)]).focus(); // eslint-disable-line react/no-string-refs
|
|
25439
|
-
|
|
25440
|
-
return true;
|
|
25441
|
-
});
|
|
25442
|
-
|
|
25443
|
-
_defineProperty(this, "getInstructionsText", () => {
|
|
25444
|
-
if (this.props.multipleSelect) {
|
|
25445
|
-
if (this.props.countChoices) {
|
|
25446
|
-
return i18n._("Choose %(numCorrect)s answers:", {
|
|
25447
|
-
numCorrect: this.props.numCorrect
|
|
25448
|
-
});
|
|
25449
|
-
}
|
|
25450
|
-
|
|
25451
|
-
return i18n._("Choose all answers that apply:");
|
|
25452
|
-
}
|
|
25453
|
-
|
|
25454
|
-
return i18n._("Choose 1 answer:");
|
|
25455
|
-
});
|
|
25456
|
-
|
|
25457
|
-
_defineProperty(this, "deselectEnabled", () => {
|
|
25458
|
-
// We want to force enable deselect on mobile.
|
|
25459
|
-
return this.props.apiOptions.isMobile || this.props.deselectEnabled;
|
|
25460
|
-
});
|
|
25461
|
-
|
|
25462
|
-
_defineProperty(this, "goToChoice", newChoiceIndex => {
|
|
25463
|
-
var numChoices = this.props.choices.length; // Wrap the newChoiceIndex around the start/end, if necessary.
|
|
25464
|
-
|
|
25465
|
-
if (newChoiceIndex < 0) {
|
|
25466
|
-
newChoiceIndex += numChoices;
|
|
25467
|
-
}
|
|
25468
|
-
|
|
25469
|
-
if (newChoiceIndex >= numChoices) {
|
|
25470
|
-
newChoiceIndex -= numChoices;
|
|
25471
|
-
} // Focus the new choice's input element.
|
|
25472
|
-
// eslint-disable-next-line react/no-string-refs
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
var choiceInstance = this.refs["radio".concat(newChoiceIndex)];
|
|
25476
|
-
|
|
25477
|
-
if (!choiceInstance) {
|
|
25478
|
-
Log.error("found no choice at index ".concat(newChoiceIndex, ", even after ") + "wrapping it to be within bounds", Errors.Internal, {
|
|
25479
|
-
loggedMetadata: {
|
|
25480
|
-
choices: JSON.stringify(this.props.choices)
|
|
25481
|
-
}
|
|
25482
|
-
});
|
|
25483
|
-
return;
|
|
25484
|
-
}
|
|
25485
|
-
|
|
25486
|
-
choiceInstance.focusInput(); // We aren't going to change any choices' crossed-out state, but we
|
|
25487
|
-
// _are_ going to deselect all choices.
|
|
25488
|
-
|
|
25489
|
-
var newCrossedOutList = this.props.choices.map(c => c.crossedOut);
|
|
25490
|
-
var newCheckedList = this.props.choices.map(c => false); // And, if the new choice isn't crossed out, we'll select it.
|
|
25491
|
-
|
|
25492
|
-
if (!this.props.choices[newChoiceIndex].crossedOut) {
|
|
25493
|
-
newCheckedList[newChoiceIndex] = true;
|
|
25494
|
-
}
|
|
25277
|
+
}
|
|
25495
25278
|
|
|
25496
|
-
|
|
25497
|
-
checked: newCheckedList,
|
|
25498
|
-
crossedOut: newCrossedOutList
|
|
25499
|
-
});
|
|
25500
|
-
});
|
|
25279
|
+
return i18n._("Choose all answers that apply:");
|
|
25501
25280
|
}
|
|
25502
25281
|
|
|
25503
|
-
|
|
25504
|
-
|
|
25505
|
-
|
|
25506
|
-
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
|
|
25282
|
+
return i18n._("Choose 1 answer:");
|
|
25283
|
+
}
|
|
25284
|
+
|
|
25285
|
+
function BaseRadio(props) {
|
|
25286
|
+
var {
|
|
25287
|
+
apiOptions,
|
|
25288
|
+
reviewModeRubric,
|
|
25289
|
+
choices,
|
|
25290
|
+
editMode,
|
|
25291
|
+
multipleSelect,
|
|
25292
|
+
labelWrap,
|
|
25293
|
+
countChoices,
|
|
25294
|
+
numCorrect,
|
|
25295
|
+
isLastUsedWidget,
|
|
25296
|
+
registerFocusFunction
|
|
25297
|
+
} = props; // useEffect doesn't have previous props
|
|
25298
|
+
|
|
25299
|
+
var prevReviewModeRubric = useRef();
|
|
25300
|
+
var choiceRefs = useRef([]);
|
|
25301
|
+
useEffect(() => {
|
|
25302
|
+
// Switching into review mode can sometimes cause the selected answer
|
|
25510
25303
|
// to scroll out of view - for example, when we reveal all those tall
|
|
25511
25304
|
// rationales. This can be disorienting for the user.
|
|
25512
25305
|
//
|
|
@@ -25519,17 +25312,25 @@ class BaseRadio extends React.Component {
|
|
|
25519
25312
|
// the most recently used widget (because, if the user has since
|
|
25520
25313
|
// touched something else, they're probably not trying to keep their
|
|
25521
25314
|
// eye on this widget anymore).
|
|
25522
|
-
|
|
25523
|
-
if (apiOptions.canScrollPage && isLastUsedWidget && reviewModeRubric && !prevProps.reviewModeRubric) {
|
|
25315
|
+
if (apiOptions.canScrollPage && isLastUsedWidget && reviewModeRubric && !prevReviewModeRubric.current) {
|
|
25524
25316
|
var checkedIndex = choices.findIndex(c => c.checked);
|
|
25525
25317
|
|
|
25526
25318
|
if (checkedIndex >= 0) {
|
|
25527
|
-
var
|
|
25528
|
-
|
|
25529
|
-
|
|
25319
|
+
var ref = choiceRefs.current[checkedIndex]; // note(matthew): we know this is only getting passed
|
|
25320
|
+
// to a WB Clickable button, so we force it to be of
|
|
25321
|
+
// type HTMLButtonElement
|
|
25322
|
+
|
|
25323
|
+
var anyNode = ReactDOM__default.findDOMNode(ref.current);
|
|
25324
|
+
var buttonNode = anyNode;
|
|
25325
|
+
|
|
25326
|
+
if (buttonNode) {
|
|
25327
|
+
scrollElementIntoView(buttonNode);
|
|
25328
|
+
}
|
|
25530
25329
|
}
|
|
25531
25330
|
}
|
|
25532
|
-
|
|
25331
|
+
|
|
25332
|
+
prevReviewModeRubric.current = reviewModeRubric;
|
|
25333
|
+
}, [apiOptions, choices, isLastUsedWidget, reviewModeRubric]); // When a particular choice's `onChange` handler is called, indicating a
|
|
25533
25334
|
// change in a single choice's values, we need to call our `onChange`
|
|
25534
25335
|
// handler in order to notify our parent. However, our API with our parent
|
|
25535
25336
|
// is that we always provide *all* values for *all* choices, even if just
|
|
@@ -25538,181 +25339,196 @@ class BaseRadio extends React.Component {
|
|
|
25538
25339
|
// will usually cause the old answer to become unchecked.)
|
|
25539
25340
|
//
|
|
25540
25341
|
// So, given the new values for a particular choice, compute the new values
|
|
25541
|
-
// for all choices, and pass them to `
|
|
25342
|
+
// for all choices, and pass them to `onChange`.
|
|
25542
25343
|
//
|
|
25543
25344
|
// `newValues` is an object with two keys: `checked` and `crossedOut`. Each
|
|
25544
25345
|
// contains a boolean value specifying the new checked and crossed-out
|
|
25545
25346
|
// value of this choice.
|
|
25546
25347
|
|
|
25348
|
+
function updateChoice(choiceIndex, newValues) {
|
|
25349
|
+
var {
|
|
25350
|
+
multipleSelect,
|
|
25351
|
+
choices,
|
|
25352
|
+
onChange
|
|
25353
|
+
} = props; // Get the baseline `checked` values. If we're checking a new answer
|
|
25354
|
+
// and multiple-select is not on, we should clear all choices to be
|
|
25355
|
+
// unchecked. Otherwise, we should copy the old checked values.
|
|
25547
25356
|
|
|
25548
|
-
|
|
25549
|
-
var inputType = this.props.multipleSelect ? "checkbox" : "radio";
|
|
25550
|
-
var rubric = this.props.reviewModeRubric;
|
|
25551
|
-
var reviewMode = !!rubric;
|
|
25552
|
-
var styles = BaseRadio.styles;
|
|
25553
|
-
var sat = this.props.apiOptions.satStyling;
|
|
25554
|
-
var isMobile = this.props.apiOptions.isMobile;
|
|
25555
|
-
var choices = this.props.choices;
|
|
25556
|
-
var firstChoiceHighlighted = choices[0].highlighted;
|
|
25557
|
-
var lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
25558
|
-
var className = classNames("perseus-widget-radio", !this.props.editMode && "perseus-rendered-radio", css(styles.radio, // SAT doesn't use the "responsive styling" as it conflicts
|
|
25559
|
-
// with their custom theming.
|
|
25560
|
-
!sat && styles.responsiveRadioContainer, !sat && firstChoiceHighlighted && isMobile && styles.radioContainerFirstHighlighted, !sat && lastChoiceHighlighted && isMobile && styles.radioContainerLastHighlighted, sat && styles.satRadio));
|
|
25561
|
-
var instructionsClassName = classNames("instructions", css(styles.instructions, isMobile && styles.instructionsMobile));
|
|
25562
|
-
var instructions = this.getInstructionsText();
|
|
25563
|
-
var shouldShowInstructions = !sat;
|
|
25564
|
-
var responsiveClassName = css(styles.responsiveFieldset);
|
|
25565
|
-
var fieldset = /*#__PURE__*/React.createElement("fieldset", {
|
|
25566
|
-
className: "perseus-widget-radio-fieldset ".concat(responsiveClassName)
|
|
25567
|
-
}, /*#__PURE__*/React.createElement("legend", {
|
|
25568
|
-
className: "perseus-sr-only"
|
|
25569
|
-
}, instructions), shouldShowInstructions && /*#__PURE__*/React.createElement("div", {
|
|
25570
|
-
className: instructionsClassName
|
|
25571
|
-
}, instructions), /*#__PURE__*/React.createElement("ul", {
|
|
25572
|
-
className: className,
|
|
25573
|
-
style: {
|
|
25574
|
-
listStyle: "none"
|
|
25575
|
-
}
|
|
25576
|
-
}, this.props.choices.map(function (choice, i) {
|
|
25577
|
-
var Element = Choice;
|
|
25578
|
-
var elementProps = {
|
|
25579
|
-
ref: "radio".concat(i),
|
|
25580
|
-
apiOptions: this.props.apiOptions,
|
|
25581
|
-
checked: choice.checked,
|
|
25582
|
-
crossedOut: choice.crossedOut,
|
|
25583
|
-
previouslyAnswered: choice.previouslyAnswered,
|
|
25584
|
-
reviewMode,
|
|
25585
|
-
correct: choice.correct,
|
|
25586
|
-
rationale: choice.rationale,
|
|
25587
|
-
content: choice.content,
|
|
25588
|
-
disabled: this.props.apiOptions.readOnly || choice.disabled,
|
|
25589
|
-
editMode: this.props.editMode,
|
|
25590
|
-
groupName: this.state.radioGroupName,
|
|
25591
|
-
isLastChoice: i === this.props.choices.length - 1,
|
|
25592
|
-
showCorrectness: reviewMode || !!choice.showCorrectness,
|
|
25593
|
-
showRationale: choice.hasRationale && (reviewMode || choice.showRationale),
|
|
25594
|
-
type: inputType,
|
|
25595
|
-
pos: i,
|
|
25596
|
-
deselectEnabled: this.deselectEnabled(),
|
|
25597
|
-
onChange: newValues => {
|
|
25598
|
-
this.updateChoice(i, newValues);
|
|
25599
|
-
},
|
|
25600
|
-
goToPrevChoice: () => this.goToChoice(i - 1),
|
|
25601
|
-
goToNextChoice: () => this.goToChoice(i + 1)
|
|
25602
|
-
};
|
|
25357
|
+
var newCheckedList;
|
|
25603
25358
|
|
|
25604
|
-
|
|
25605
|
-
|
|
25359
|
+
if (newValues.checked && !multipleSelect) {
|
|
25360
|
+
newCheckedList = choices.map(_ => false);
|
|
25361
|
+
} else {
|
|
25362
|
+
newCheckedList = choices.map(c => c.checked);
|
|
25363
|
+
} // Get the baseline `crossedOut` values.
|
|
25606
25364
|
|
|
25607
|
-
_.extend(elementProps, {
|
|
25608
|
-
showContent: choice.revealNoneOfTheAbove
|
|
25609
|
-
});
|
|
25610
|
-
}
|
|
25611
25365
|
|
|
25612
|
-
|
|
25613
|
-
|
|
25614
|
-
|
|
25615
|
-
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25621
|
-
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
|
|
25625
|
-
|
|
25626
|
-
|
|
25627
|
-
|
|
25628
|
-
|
|
25629
|
-
|
|
25630
|
-
|
|
25631
|
-
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
|
|
25636
|
-
|
|
25637
|
-
|
|
25638
|
-
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
|
|
25642
|
-
|
|
25643
|
-
|
|
25644
|
-
|
|
25645
|
-
|
|
25646
|
-
|
|
25647
|
-
|
|
25648
|
-
|
|
25649
|
-
|
|
25650
|
-
|
|
25651
|
-
|
|
25652
|
-
|
|
25653
|
-
|
|
25366
|
+
var newCrossedOutList = choices.map(c => c.crossedOut); // Update this choice's `checked` and `crossedOut` values.
|
|
25367
|
+
|
|
25368
|
+
newCheckedList[choiceIndex] = newValues.checked;
|
|
25369
|
+
newCrossedOutList[choiceIndex] = newValues.crossedOut;
|
|
25370
|
+
onChange({
|
|
25371
|
+
checked: newCheckedList,
|
|
25372
|
+
crossedOut: newCrossedOutList
|
|
25373
|
+
});
|
|
25374
|
+
} // register a callback with the parent that allows
|
|
25375
|
+
// the parent to focus an individual choice
|
|
25376
|
+
|
|
25377
|
+
|
|
25378
|
+
registerFocusFunction === null || registerFocusFunction === void 0 ? void 0 : registerFocusFunction(choiceIndex => {
|
|
25379
|
+
var ref = choiceRefs.current[choiceIndex || 0]; // note(matthew): we know this is only getting passed
|
|
25380
|
+
// to a WB Clickable button, so we force it to be of
|
|
25381
|
+
// type HTMLButtonElement
|
|
25382
|
+
|
|
25383
|
+
var anyNode = ReactDOM__default.findDOMNode(ref.current);
|
|
25384
|
+
var buttonNode = anyNode;
|
|
25385
|
+
|
|
25386
|
+
if (buttonNode) {
|
|
25387
|
+
buttonNode.focus();
|
|
25388
|
+
} else {
|
|
25389
|
+
return false;
|
|
25390
|
+
}
|
|
25391
|
+
|
|
25392
|
+
return true;
|
|
25393
|
+
}); // some commonly used shorthands
|
|
25394
|
+
|
|
25395
|
+
var reviewMode = !!reviewModeRubric;
|
|
25396
|
+
var sat = apiOptions.satStyling;
|
|
25397
|
+
var isMobile = apiOptions.isMobile;
|
|
25398
|
+
var firstChoiceHighlighted = choices[0].highlighted;
|
|
25399
|
+
var lastChoiceHighlighted = choices[choices.length - 1].highlighted;
|
|
25400
|
+
var className = classNames("perseus-widget-radio", !editMode && "perseus-rendered-radio", css(styles$r.radio, // SAT doesn't use the "responsive styling" as it conflicts
|
|
25401
|
+
// with their custom theming.
|
|
25402
|
+
!sat && styles$r.responsiveRadioContainer, !sat && firstChoiceHighlighted && isMobile && styles$r.radioContainerFirstHighlighted, !sat && lastChoiceHighlighted && isMobile && styles$r.radioContainerLastHighlighted, sat && styles$r.satRadio));
|
|
25403
|
+
var instructionsClassName = classNames("instructions", css(styles$r.instructions, isMobile && styles$r.instructionsMobile));
|
|
25404
|
+
var instructions = getInstructionsText(multipleSelect, countChoices, numCorrect);
|
|
25405
|
+
var shouldShowInstructions = !sat;
|
|
25406
|
+
var responsiveClassName = css(styles$r.responsiveFieldset);
|
|
25407
|
+
var fieldset = /*#__PURE__*/React.createElement("fieldset", {
|
|
25408
|
+
className: "perseus-widget-radio-fieldset ".concat(responsiveClassName)
|
|
25409
|
+
}, /*#__PURE__*/React.createElement("legend", {
|
|
25410
|
+
className: "perseus-sr-only"
|
|
25411
|
+
}, instructions), shouldShowInstructions && /*#__PURE__*/React.createElement("div", {
|
|
25412
|
+
className: instructionsClassName
|
|
25413
|
+
}, instructions), /*#__PURE__*/React.createElement("ul", {
|
|
25414
|
+
className: className,
|
|
25415
|
+
style: {
|
|
25416
|
+
listStyle: "none"
|
|
25417
|
+
}
|
|
25418
|
+
}, choices.map(function (choice, i) {
|
|
25419
|
+
var Element = Choice$1;
|
|
25420
|
+
var ref = /*#__PURE__*/React.createRef();
|
|
25421
|
+
choiceRefs.current[i] = ref;
|
|
25422
|
+
var elementProps = {
|
|
25423
|
+
apiOptions: apiOptions,
|
|
25424
|
+
multipleSelect: multipleSelect,
|
|
25425
|
+
checked: choice.checked,
|
|
25426
|
+
crossedOut: choice.crossedOut,
|
|
25427
|
+
previouslyAnswered: choice.previouslyAnswered,
|
|
25428
|
+
reviewMode,
|
|
25429
|
+
correct: choice.correct,
|
|
25430
|
+
rationale: choice.rationale,
|
|
25431
|
+
content: choice.content,
|
|
25432
|
+
disabled: apiOptions.readOnly || choice.disabled,
|
|
25433
|
+
showCorrectness: reviewMode || !!choice.showCorrectness,
|
|
25434
|
+
showRationale: choice.hasRationale && (reviewMode || choice.showRationale),
|
|
25435
|
+
pos: i,
|
|
25436
|
+
onChange: newValues => {
|
|
25437
|
+
updateChoice(i, newValues);
|
|
25438
|
+
},
|
|
25439
|
+
ref
|
|
25440
|
+
};
|
|
25441
|
+
|
|
25442
|
+
if (choice.isNoneOfTheAbove) {
|
|
25443
|
+
Element = ChoiceNoneAbove$1;
|
|
25444
|
+
|
|
25445
|
+
_.extend(elementProps, {
|
|
25446
|
+
showContent: choice.revealNoneOfTheAbove
|
|
25447
|
+
});
|
|
25448
|
+
}
|
|
25449
|
+
|
|
25450
|
+
var nextChoice = choices[i + 1];
|
|
25451
|
+
var nextChoiceHighlighted = !!nextChoice && nextChoice.highlighted;
|
|
25452
|
+
|
|
25453
|
+
var aphroditeClassName = checked => {
|
|
25454
|
+
// Whether or not to show correctness borders
|
|
25455
|
+
// for this choice and the next choice.
|
|
25456
|
+
var satShowCorrectness = sat && reviewMode && checked;
|
|
25457
|
+
var satShowCorrectnessNext = sat && reviewMode && nextChoice && nextChoice.checked;
|
|
25458
|
+
return css(sharedStyles.aboveScratchpad, styles$r.item, !sat && styles$r.responsiveItem, !sat && checked && styles$r.selectedItem, !sat && checked && choice.highlighted && styles$r.aboveBackdrop, !sat && checked && choice.highlighted && apiOptions.isMobile && styles$r.aboveBackdropMobile, !sat && nextChoiceHighlighted && apiOptions.isMobile && styles$r.nextHighlighted, sat && styles$r.satRadioOption, satShowCorrectness && !choice.correct && styles$r.satRadioOptionIncorrect, satShowCorrectness && choice.correct && styles$r.satRadioOptionCorrect, satShowCorrectnessNext && !nextChoice.correct && styles$r.satRadioOptionNextIncorrect, satShowCorrectnessNext && nextChoice.correct && styles$r.satRadioOptionNextCorrect, sat && reviewModeRubric && styles$r.satReviewRadioOption);
|
|
25459
|
+
}; // HACK(abdulrahman): Preloads the selection-state
|
|
25460
|
+
// css because of a bug that causes iOS to lag
|
|
25461
|
+
// when selecting the button for the first time.
|
|
25654
25462
|
|
|
25655
|
-
|
|
25463
|
+
|
|
25464
|
+
aphroditeClassName(true);
|
|
25465
|
+
var correctnessClass; // reviewMode is only true if there's a rubric
|
|
25466
|
+
// but Flow doesn't understand that
|
|
25467
|
+
|
|
25468
|
+
if (reviewMode && reviewModeRubric) {
|
|
25469
|
+
correctnessClass = reviewModeRubric.choices[i].correct ? ClassNames.CORRECT : ClassNames.INCORRECT;
|
|
25470
|
+
}
|
|
25471
|
+
|
|
25472
|
+
var className = classNames(aphroditeClassName(choice.checked), // TODO(aria): Make test case for these API
|
|
25473
|
+
// classNames
|
|
25474
|
+
ClassNames.RADIO.OPTION, choice.checked && ClassNames.RADIO.SELECTED, correctnessClass); // In edit mode, the Choice renders a Div in order to
|
|
25475
|
+
// allow for the contentEditable area to be selected
|
|
25476
|
+
// (label forces any clicks inside to select the input
|
|
25477
|
+
// element) We have to add some extra behavior to make
|
|
25478
|
+
// sure that we can still check the choice.
|
|
25479
|
+
|
|
25480
|
+
var listElem = null;
|
|
25481
|
+
var clickHandler = null;
|
|
25482
|
+
|
|
25483
|
+
if (editMode) {
|
|
25484
|
+
clickHandler = e => {
|
|
25485
|
+
// Traverse the parent nodes of the clicked
|
|
25486
|
+
// element.
|
|
25487
|
+
var elem = e.target;
|
|
25488
|
+
|
|
25489
|
+
while (elem && elem !== listElem) {
|
|
25490
|
+
// If the clicked element is inside of the
|
|
25491
|
+
// radio icon, then we want to trigger the
|
|
25492
|
+
// check by flipping the choice of the icon.
|
|
25493
|
+
if (elem.getAttribute("data-is-radio-icon")) {
|
|
25494
|
+
this.updateChoice(i, {
|
|
25495
|
+
checked: !choice.checked,
|
|
25496
|
+
crossedOut: choice.crossedOut
|
|
25497
|
+
});
|
|
25498
|
+
return;
|
|
25656
25499
|
}
|
|
25657
|
-
};
|
|
25658
|
-
} // TODO(mattdr): Index isn't a *good* choice of key
|
|
25659
|
-
// here; is there a better one? Can we use choice
|
|
25660
|
-
// content somehow? Would changing our choice of key
|
|
25661
|
-
// somehow break something happening inside a choice's
|
|
25662
|
-
// child Renderers, by changing when we mount/unmount?
|
|
25663
25500
|
|
|
25501
|
+
elem = elem.parentNode;
|
|
25502
|
+
}
|
|
25503
|
+
};
|
|
25504
|
+
} // TODO(mattdr): Index isn't a *good* choice of key
|
|
25505
|
+
// here; is there a better one? Can we use choice
|
|
25506
|
+
// content somehow? Would changing our choice of key
|
|
25507
|
+
// somehow break something happening inside a choice's
|
|
25508
|
+
// child Renderers, by changing when we mount/unmount?
|
|
25664
25509
|
|
|
25665
|
-
return /*#__PURE__*/React.createElement("li", {
|
|
25666
|
-
key: i,
|
|
25667
|
-
ref: e => listElem = e,
|
|
25668
|
-
className: className,
|
|
25669
|
-
onClick: clickHandler,
|
|
25670
|
-
onTouchStart: !this.props.labelWrap ? null : captureScratchpadTouchStart$2
|
|
25671
|
-
}, /*#__PURE__*/React.createElement(Element, elementProps));
|
|
25672
|
-
}, this))); // Allow for horizontal scrolling if content is too wide, which may be
|
|
25673
|
-
// an issue especially on phones.
|
|
25674
|
-
// This is disabled in SAT, since it conflicts with their theming.
|
|
25675
25510
|
|
|
25676
|
-
return /*#__PURE__*/React.createElement("
|
|
25677
|
-
|
|
25678
|
-
|
|
25679
|
-
|
|
25511
|
+
return /*#__PURE__*/React.createElement("li", {
|
|
25512
|
+
key: i,
|
|
25513
|
+
ref: e => listElem = e,
|
|
25514
|
+
className: className,
|
|
25515
|
+
onClick: clickHandler,
|
|
25516
|
+
onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$2
|
|
25517
|
+
}, /*#__PURE__*/React.createElement(Element, elementProps));
|
|
25518
|
+
}, this))); // Allow for horizontal scrolling if content is too wide, which may be
|
|
25519
|
+
// an issue especially on phones.
|
|
25520
|
+
// This is disabled in SAT, since it conflicts with their theming.
|
|
25680
25521
|
|
|
25522
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
25523
|
+
className: css(!sat && styles$r.responsiveContainer)
|
|
25524
|
+
}, fieldset);
|
|
25681
25525
|
}
|
|
25682
25526
|
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
styling: PropTypes.shape({
|
|
25689
|
-
radioStyleVersion: PropTypes.oneOf(["intermediate", "final"])
|
|
25690
|
-
}),
|
|
25691
|
-
canScrollPage: PropTypes.bool
|
|
25692
|
-
}),
|
|
25693
|
-
choices: ChoicesType,
|
|
25694
|
-
deselectEnabled: PropTypes.bool,
|
|
25695
|
-
editMode: PropTypes.bool,
|
|
25696
|
-
labelWrap: PropTypes.bool,
|
|
25697
|
-
countChoices: PropTypes.bool,
|
|
25698
|
-
numCorrect: PropTypes.number,
|
|
25699
|
-
multipleSelect: PropTypes.bool,
|
|
25700
|
-
reviewModeRubric: PropTypes.shape({
|
|
25701
|
-
choices: ChoicesType
|
|
25702
|
-
}),
|
|
25703
|
-
// A callback indicating that this choice has changed. Its argument is
|
|
25704
|
-
// an object with two keys: `checked` and `crossedOut`. Each contains
|
|
25705
|
-
// an array of boolean values, specifying the new checked and
|
|
25706
|
-
// crossed-out value of each choice.
|
|
25707
|
-
onChange: PropTypes.func,
|
|
25708
|
-
// Whether this widget was the most recently used widget in this
|
|
25709
|
-
// Renderer. Determines whether we'll auto-scroll the page upon
|
|
25710
|
-
// entering review mode.
|
|
25711
|
-
isLastUsedWidget: PropTypes.bool
|
|
25712
|
-
});
|
|
25713
|
-
|
|
25714
|
-
_defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
25715
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25527
|
+
BaseRadio.defaultProps = {
|
|
25528
|
+
editMode: false,
|
|
25529
|
+
multipleSelect: false
|
|
25530
|
+
};
|
|
25531
|
+
var styles$r = StyleSheet.create({
|
|
25716
25532
|
instructions: {
|
|
25717
25533
|
display: "block",
|
|
25718
25534
|
color: gray17,
|
|
@@ -25722,7 +25538,6 @@ _defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
|
25722
25538
|
fontWeight: "bold",
|
|
25723
25539
|
marginBottom: 16
|
|
25724
25540
|
},
|
|
25725
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25726
25541
|
instructionsMobile: {
|
|
25727
25542
|
fontSize: 18,
|
|
25728
25543
|
[mediaQueries.smOrSmaller]: {
|
|
@@ -25736,36 +25551,30 @@ _defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
|
25736
25551
|
fontSize: 20
|
|
25737
25552
|
}
|
|
25738
25553
|
},
|
|
25739
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25740
25554
|
radio: {
|
|
25741
25555
|
// Avoid centering
|
|
25742
25556
|
width: "100%"
|
|
25743
25557
|
},
|
|
25744
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25745
25558
|
responsiveRadioContainer: {
|
|
25746
|
-
borderBottom: "1px solid ".concat(radioBorderColor),
|
|
25747
|
-
borderTop: "1px solid ".concat(radioBorderColor),
|
|
25559
|
+
borderBottom: "1px solid ".concat(radioBorderColor$1),
|
|
25560
|
+
borderTop: "1px solid ".concat(radioBorderColor$1),
|
|
25748
25561
|
width: "auto",
|
|
25749
25562
|
[mediaQueries.smOrSmaller]: {
|
|
25750
25563
|
marginLeft: negativePhoneMargin,
|
|
25751
25564
|
marginRight: negativePhoneMargin
|
|
25752
25565
|
}
|
|
25753
25566
|
},
|
|
25754
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25755
25567
|
radioContainerFirstHighlighted: {
|
|
25756
25568
|
borderTop: "1px solid rgba(0, 0, 0, 0)"
|
|
25757
25569
|
},
|
|
25758
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25759
25570
|
radioContainerLastHighlighted: {
|
|
25760
25571
|
borderBottom: "1px solid rgba(0, 0, 0, 0)"
|
|
25761
25572
|
},
|
|
25762
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25763
25573
|
satRadio: {
|
|
25764
25574
|
background: "none",
|
|
25765
25575
|
marginLeft: 0,
|
|
25766
25576
|
userSelect: "none"
|
|
25767
25577
|
},
|
|
25768
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25769
25578
|
satRadioOption: {
|
|
25770
25579
|
margin: 0,
|
|
25771
25580
|
padding: 0,
|
|
@@ -25774,57 +25583,40 @@ _defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
|
25774
25583
|
borderTop: "1px solid #ccc"
|
|
25775
25584
|
}
|
|
25776
25585
|
},
|
|
25777
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25778
25586
|
satRadioOptionCorrect: {
|
|
25779
25587
|
borderBottomColor: satCorrectBorderColor,
|
|
25780
25588
|
":first-child": {
|
|
25781
25589
|
borderTopColor: satCorrectBorderColor
|
|
25782
25590
|
}
|
|
25783
25591
|
},
|
|
25784
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25785
25592
|
satRadioOptionIncorrect: {
|
|
25786
25593
|
borderBottomColor: satIncorrectBorderColor,
|
|
25787
25594
|
":first-child": {
|
|
25788
25595
|
borderTopColor: satIncorrectBorderColor
|
|
25789
25596
|
}
|
|
25790
25597
|
},
|
|
25791
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25792
25598
|
satRadioOptionNextCorrect: {
|
|
25793
25599
|
borderBottomColor: satCorrectBorderColor
|
|
25794
25600
|
},
|
|
25795
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25796
25601
|
satRadioOptionNextIncorrect: {
|
|
25797
25602
|
borderBottomColor: satIncorrectBorderColor
|
|
25798
25603
|
},
|
|
25799
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25800
25604
|
satReviewRadioOption: {
|
|
25801
25605
|
pointerEvents: "none"
|
|
25802
25606
|
},
|
|
25803
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25804
25607
|
item: {
|
|
25805
25608
|
marginLeft: 20
|
|
25806
25609
|
},
|
|
25807
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25808
|
-
inlineItem: {
|
|
25809
|
-
display: "inline-block",
|
|
25810
|
-
paddingLeft: 20,
|
|
25811
|
-
verticalAlign: "middle" // See http://stackoverflow.com/q/8120466 for explanation of
|
|
25812
|
-
// why vertical align property is needed
|
|
25813
|
-
|
|
25814
|
-
},
|
|
25815
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25816
25610
|
responsiveItem: {
|
|
25817
25611
|
marginLeft: 0,
|
|
25818
25612
|
padding: 0,
|
|
25819
25613
|
":not(:last-child)": {
|
|
25820
|
-
borderBottom: "1px solid ".concat(radioBorderColor)
|
|
25614
|
+
borderBottom: "1px solid ".concat(radioBorderColor$1)
|
|
25821
25615
|
}
|
|
25822
25616
|
},
|
|
25823
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25824
25617
|
selectedItem: {
|
|
25825
25618
|
background: "white"
|
|
25826
25619
|
},
|
|
25827
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25828
25620
|
aboveBackdrop: {
|
|
25829
25621
|
position: "relative",
|
|
25830
25622
|
// HACK(emily): We want selected choices to show up above our
|
|
@@ -25833,20 +25625,17 @@ _defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
|
25833
25625
|
// coordinated between here and webapp. :(
|
|
25834
25626
|
zIndex: 1062
|
|
25835
25627
|
},
|
|
25836
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25837
25628
|
aboveBackdropMobile: {
|
|
25838
25629
|
boxShadow: "0 0 4px 0 rgba(0, 0, 0, 0.2)," + "0 0 2px 0 rgba(0, 0, 0, 0.1)",
|
|
25839
25630
|
":not(:last-child)": {
|
|
25840
25631
|
borderBottom: "1px solid rgba(0, 0, 0, 0)"
|
|
25841
25632
|
}
|
|
25842
25633
|
},
|
|
25843
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25844
25634
|
nextHighlighted: {
|
|
25845
25635
|
":not(:last-child)": {
|
|
25846
25636
|
borderBottom: "1px solid rgba(0, 0, 0, 0)"
|
|
25847
25637
|
}
|
|
25848
25638
|
},
|
|
25849
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25850
25639
|
responsiveContainer: {
|
|
25851
25640
|
overflow: "auto",
|
|
25852
25641
|
marginLeft: negativePhoneMargin,
|
|
@@ -25854,22 +25643,22 @@ _defineProperty(BaseRadio, "styles", StyleSheet.create({
|
|
|
25854
25643
|
paddingLeft: phoneMargin // paddingRight is handled by responsiveFieldset
|
|
25855
25644
|
|
|
25856
25645
|
},
|
|
25857
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
25858
25646
|
responsiveFieldset: {
|
|
25859
25647
|
paddingRight: phoneMargin
|
|
25860
25648
|
}
|
|
25861
|
-
}));
|
|
25862
|
-
|
|
25863
|
-
_defineProperty(BaseRadio, "defaultProps", {
|
|
25864
|
-
editMode: false
|
|
25865
25649
|
});
|
|
25866
25650
|
|
|
25867
25651
|
class Radio$1 extends React.Component {
|
|
25868
25652
|
constructor() {
|
|
25653
|
+
var _this;
|
|
25654
|
+
|
|
25869
25655
|
super(...arguments);
|
|
25656
|
+
_this = this;
|
|
25870
25657
|
|
|
25871
|
-
_defineProperty(this, "
|
|
25872
|
-
|
|
25658
|
+
_defineProperty(this, "focusFunction", void 0);
|
|
25659
|
+
|
|
25660
|
+
_defineProperty(this, "_renderRenderer", function () {
|
|
25661
|
+
var content = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
|
|
25873
25662
|
var nextPassageRefId = 1;
|
|
25874
25663
|
var widgets = {};
|
|
25875
25664
|
var modContent = content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g, (match, passageNum, refNum, summaryText) => {
|
|
@@ -25901,19 +25690,14 @@ class Radio$1 extends React.Component {
|
|
|
25901
25690
|
key: "choiceContentRenderer",
|
|
25902
25691
|
content: modContent,
|
|
25903
25692
|
widgets: widgets,
|
|
25904
|
-
findExternalWidgets:
|
|
25693
|
+
findExternalWidgets: _this.props.findWidgets,
|
|
25905
25694
|
alwaysUpdate: true,
|
|
25906
|
-
linterContext: _objectSpread2(_objectSpread2({},
|
|
25695
|
+
linterContext: _objectSpread2(_objectSpread2({}, _this.props.linterContext), {}, {
|
|
25907
25696
|
blockHighlight: true
|
|
25908
25697
|
})
|
|
25909
25698
|
});
|
|
25910
25699
|
});
|
|
25911
25700
|
|
|
25912
|
-
_defineProperty(this, "focus", i => {
|
|
25913
|
-
// eslint-disable-next-line react/no-string-refs
|
|
25914
|
-
return this.refs.baseRadio.focus(i);
|
|
25915
|
-
});
|
|
25916
|
-
|
|
25917
25701
|
_defineProperty(this, "updateChoices", newValueLists => {
|
|
25918
25702
|
var {
|
|
25919
25703
|
choiceStates,
|
|
@@ -25924,24 +25708,17 @@ class Radio$1 extends React.Component {
|
|
|
25924
25708
|
// should clone the old `choiceStates` objects, in preparation to
|
|
25925
25709
|
// mutate them.
|
|
25926
25710
|
|
|
25927
|
-
var newChoiceStates
|
|
25928
|
-
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
25935
|
-
|
|
25936
|
-
rationaleShown: false,
|
|
25937
|
-
correctnessShown: false,
|
|
25938
|
-
previouslyAnswered: false,
|
|
25939
|
-
readOnly: false
|
|
25940
|
-
}));
|
|
25941
|
-
} // Mutate the new `choiceState` objects, according to the new `checked`
|
|
25711
|
+
var newChoiceStates = choiceStates ? choiceStates.map(state => _objectSpread2({}, state)) : choices.map(() => ({
|
|
25712
|
+
selected: false,
|
|
25713
|
+
crossedOut: false,
|
|
25714
|
+
highlighted: false,
|
|
25715
|
+
rationaleShown: false,
|
|
25716
|
+
correctnessShown: false,
|
|
25717
|
+
previouslyAnswered: false,
|
|
25718
|
+
readOnly: false
|
|
25719
|
+
})); // Mutate the new `choiceState` objects, according to the new `checked`
|
|
25942
25720
|
// and `crossedOut` values provided in `newValueLists`.
|
|
25943
25721
|
|
|
25944
|
-
|
|
25945
25722
|
newChoiceStates.forEach((choiceState, i) => {
|
|
25946
25723
|
choiceState.selected = newValueLists.checked[i];
|
|
25947
25724
|
choiceState.crossedOut = newValueLists.crossedOut[i];
|
|
@@ -26005,14 +25782,47 @@ class Radio$1 extends React.Component {
|
|
|
26005
25782
|
});
|
|
26006
25783
|
}
|
|
26007
25784
|
|
|
25785
|
+
// TODO(LP-10672): I think this might be unused right now. I can't find anywhere
|
|
25786
|
+
// that we pass a value to `.focus()` and it seems to have been used for
|
|
25787
|
+
// adding hints when editing.
|
|
25788
|
+
// See: https://github.com/Khan/perseus/blame/e18582b4b69959270b90e237ef1813899711ddfa/src/widgets/radio.js#L169
|
|
25789
|
+
focus(choiceIndex) {
|
|
25790
|
+
if (this.focusFunction) {
|
|
25791
|
+
return this.focusFunction(choiceIndex);
|
|
25792
|
+
}
|
|
25793
|
+
|
|
25794
|
+
return false;
|
|
25795
|
+
} // lets BaseRadio regiser a focus callback so widget
|
|
25796
|
+
// can focus an individual choice
|
|
25797
|
+
|
|
25798
|
+
|
|
25799
|
+
registerFocusFunction(fun) {
|
|
25800
|
+
this.focusFunction = fun;
|
|
25801
|
+
} // When `BaseRadio`'s `onChange` handler is called, indicating a change in
|
|
25802
|
+
// our choices' state, we need to call our `onChange` handler in order to
|
|
25803
|
+
// persist those changes in the item's Perseus state.
|
|
25804
|
+
//
|
|
25805
|
+
// So, given the new values for each choice, construct the new
|
|
25806
|
+
// `choiceStates` objects, and pass them to `this.props.onChange`.
|
|
25807
|
+
//
|
|
25808
|
+
// `newValueLists` is an object with two keys: `checked` and `crossedOut`.
|
|
25809
|
+
// Each contains an array of boolean values, specifying the new checked and
|
|
25810
|
+
// crossed-out value of each choice.
|
|
25811
|
+
//
|
|
25812
|
+
// NOTE(mdr): This method expects to be auto-bound. If this component is
|
|
25813
|
+
// converted to an ES6 class, take care to auto-bind this method!
|
|
25814
|
+
|
|
25815
|
+
|
|
26008
25816
|
render() {
|
|
26009
|
-
var
|
|
25817
|
+
var {
|
|
25818
|
+
choices
|
|
25819
|
+
} = this.props;
|
|
26010
25820
|
var choiceStates;
|
|
26011
25821
|
|
|
26012
25822
|
if (this.props.static) {
|
|
26013
|
-
choiceStates =
|
|
26014
|
-
selected:
|
|
26015
|
-
crossedOut:
|
|
25823
|
+
choiceStates = choices.map(choice => ({
|
|
25824
|
+
selected: !!choice.correct,
|
|
25825
|
+
crossedOut: false,
|
|
26016
25826
|
readOnly: true,
|
|
26017
25827
|
highlighted: false,
|
|
26018
25828
|
rationaleShown: true,
|
|
@@ -26020,12 +25830,12 @@ class Radio$1 extends React.Component {
|
|
|
26020
25830
|
previouslyAnswered: false
|
|
26021
25831
|
}));
|
|
26022
25832
|
} else if (this.props.choiceStates) {
|
|
26023
|
-
choiceStates = this.props.choiceStates;
|
|
25833
|
+
choiceStates = this.props.choiceStates;
|
|
26024
25834
|
} else if (this.props.values) {
|
|
26025
25835
|
// Support legacy choiceStates implementation
|
|
26026
25836
|
|
|
26027
25837
|
/* istanbul ignore next - props.values is deprecated */
|
|
26028
|
-
choiceStates =
|
|
25838
|
+
choiceStates = this.props.values.map(val => ({
|
|
26029
25839
|
selected: val,
|
|
26030
25840
|
crossedOut: false,
|
|
26031
25841
|
readOnly: false,
|
|
@@ -26035,7 +25845,7 @@ class Radio$1 extends React.Component {
|
|
|
26035
25845
|
previouslyAnswered: false
|
|
26036
25846
|
}));
|
|
26037
25847
|
} else {
|
|
26038
|
-
choiceStates =
|
|
25848
|
+
choiceStates = choices.map(() => ({
|
|
26039
25849
|
selected: false,
|
|
26040
25850
|
crossedOut: false,
|
|
26041
25851
|
readOnly: false,
|
|
@@ -26046,7 +25856,7 @@ class Radio$1 extends React.Component {
|
|
|
26046
25856
|
}));
|
|
26047
25857
|
}
|
|
26048
25858
|
|
|
26049
|
-
|
|
25859
|
+
var choicesProp = choices.map((choice, i) => {
|
|
26050
25860
|
var content = choice.isNoneOfTheAbove && !choice.content ? // we use i18n._ instead of $_ here because the content
|
|
26051
25861
|
// sent to a renderer needs to be a string, not a react
|
|
26052
25862
|
// node (/renderable/fragment).
|
|
@@ -26074,37 +25884,36 @@ class Radio$1 extends React.Component {
|
|
|
26074
25884
|
// TODO(emily): Come up with a more comprehensive way to solve
|
|
26075
25885
|
// this sort of "serialized state breaks when internal
|
|
26076
25886
|
// structure changes" problem.
|
|
26077
|
-
correct:
|
|
25887
|
+
correct: choice.correct === undefined ? !!reviewChoice && !!reviewChoice.correct : choice.correct,
|
|
26078
25888
|
disabled: readOnly,
|
|
26079
25889
|
hasRationale: !!choice.clue,
|
|
26080
25890
|
rationale: this._renderRenderer(choice.clue),
|
|
26081
25891
|
showRationale: rationaleShown,
|
|
26082
25892
|
showCorrectness: correctnessShown,
|
|
26083
|
-
isNoneOfTheAbove: choice.isNoneOfTheAbove,
|
|
26084
|
-
revealNoneOfTheAbove: this.props.questionCompleted && selected,
|
|
25893
|
+
isNoneOfTheAbove: !!choice.isNoneOfTheAbove,
|
|
25894
|
+
revealNoneOfTheAbove: !!(this.props.questionCompleted && selected),
|
|
26085
25895
|
crossedOut,
|
|
26086
25896
|
highlighted,
|
|
26087
25897
|
previouslyAnswered: previouslyAnswered
|
|
26088
25898
|
};
|
|
26089
25899
|
});
|
|
26090
|
-
return /*#__PURE__*/React.createElement(BaseRadio
|
|
26091
|
-
, {
|
|
26092
|
-
ref: "baseRadio",
|
|
25900
|
+
return /*#__PURE__*/React.createElement(BaseRadio, {
|
|
26093
25901
|
labelWrap: true,
|
|
26094
25902
|
multipleSelect: this.props.multipleSelect,
|
|
26095
25903
|
countChoices: this.props.countChoices,
|
|
26096
25904
|
numCorrect: this.props.numCorrect,
|
|
26097
|
-
choices:
|
|
25905
|
+
choices: choicesProp,
|
|
26098
25906
|
onChange: this.updateChoices,
|
|
26099
25907
|
reviewModeRubric: this.props.reviewModeRubric,
|
|
26100
25908
|
deselectEnabled: this.props.deselectEnabled,
|
|
26101
25909
|
apiOptions: this.props.apiOptions,
|
|
26102
|
-
isLastUsedWidget: this.props.isLastUsedWidget
|
|
25910
|
+
isLastUsedWidget: this.props.isLastUsedWidget,
|
|
25911
|
+
registerFocusFunction: i => this.registerFocusFunction(i)
|
|
26103
25912
|
});
|
|
26104
25913
|
}
|
|
26105
25914
|
|
|
26106
25915
|
static validate(userInput, rubric) {
|
|
26107
|
-
var numSelected =
|
|
25916
|
+
var numSelected = userInput.choicesSelected.reduce((sum, selected) => {
|
|
26108
25917
|
return sum + (selected ? 1 : 0);
|
|
26109
25918
|
}, 0);
|
|
26110
25919
|
|
|
@@ -26113,10 +25922,9 @@ class Radio$1 extends React.Component {
|
|
|
26113
25922
|
type: "invalid",
|
|
26114
25923
|
message: null
|
|
26115
25924
|
};
|
|
26116
|
-
}
|
|
26117
|
-
|
|
25925
|
+
}
|
|
26118
25926
|
|
|
26119
|
-
if (userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
25927
|
+
if (userInput.numCorrect && userInput.numCorrect > 1 && numSelected !== userInput.numCorrect) {
|
|
26120
25928
|
return {
|
|
26121
25929
|
type: "invalid",
|
|
26122
25930
|
message: i18n._("Please choose the correct number of answers.")
|
|
@@ -26129,14 +25937,12 @@ class Radio$1 extends React.Component {
|
|
|
26129
25937
|
message: i18n._("'None of the above' may not be selected " + "when other answers are selected.")
|
|
26130
25938
|
};
|
|
26131
25939
|
}
|
|
26132
|
-
/* jshint -W018 */
|
|
26133
|
-
|
|
26134
25940
|
|
|
26135
|
-
var correct =
|
|
25941
|
+
var correct = userInput.choicesSelected.every((selected, i) => {
|
|
26136
25942
|
var isCorrect;
|
|
26137
25943
|
|
|
26138
25944
|
if (userInput.noneOfTheAboveIndex === i) {
|
|
26139
|
-
isCorrect =
|
|
25945
|
+
isCorrect = rubric.choices.every((choice, j) => {
|
|
26140
25946
|
return i === j || !choice.correct;
|
|
26141
25947
|
});
|
|
26142
25948
|
} else {
|
|
@@ -26145,9 +25951,6 @@ class Radio$1 extends React.Component {
|
|
|
26145
25951
|
|
|
26146
25952
|
return isCorrect === selected;
|
|
26147
25953
|
});
|
|
26148
|
-
/* jshint +W018 */
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
25954
|
return {
|
|
26152
25955
|
type: "points",
|
|
26153
25956
|
earned: correct ? 1 : 0,
|
|
@@ -26169,9 +25972,7 @@ class Radio$1 extends React.Component {
|
|
|
26169
25972
|
var numCorrect = props.numCorrect;
|
|
26170
25973
|
|
|
26171
25974
|
for (var i = 0; i < choicesSelected.length; i++) {
|
|
26172
|
-
|
|
26173
|
-
var index = props.choices[i].originalIndex; // $FlowFixMe[incompatible-use]
|
|
26174
|
-
|
|
25975
|
+
var index = props.choices[i].originalIndex;
|
|
26175
25976
|
choicesSelected[index] = choiceStates[i].selected;
|
|
26176
25977
|
|
|
26177
25978
|
if (props.choices[i].isNoneOfTheAbove) {
|
|
@@ -26192,31 +25993,35 @@ class Radio$1 extends React.Component {
|
|
|
26192
25993
|
}; // Support legacy choiceState implementation
|
|
26193
25994
|
}
|
|
26194
25995
|
/* istanbul ignore if - props.values is deprecated */
|
|
26195
|
-
// $FlowFixMe[prop-missing]
|
|
26196
25996
|
|
|
26197
25997
|
|
|
26198
|
-
|
|
25998
|
+
var {
|
|
25999
|
+
values
|
|
26000
|
+
} = props;
|
|
26001
|
+
|
|
26002
|
+
if (values) {
|
|
26199
26003
|
var _noneOfTheAboveIndex = null;
|
|
26200
26004
|
var _noneOfTheAboveSelected = false;
|
|
26201
|
-
var
|
|
26005
|
+
var _choicesSelected = [...values];
|
|
26202
26006
|
var _countChoices = props.countChoices;
|
|
26203
26007
|
var _numCorrect = props.numCorrect;
|
|
26008
|
+
var valuesLength = values.length;
|
|
26204
26009
|
|
|
26205
|
-
for (var _i = 0; _i <
|
|
26010
|
+
for (var _i = 0; _i < valuesLength; _i++) {
|
|
26206
26011
|
var _index = props.choices[_i].originalIndex;
|
|
26207
|
-
|
|
26012
|
+
_choicesSelected[_index] = values[_i];
|
|
26208
26013
|
|
|
26209
26014
|
if (props.choices[_i].isNoneOfTheAbove) {
|
|
26210
26015
|
_noneOfTheAboveIndex = _index;
|
|
26211
26016
|
|
|
26212
|
-
if (
|
|
26017
|
+
if (_choicesSelected[_i]) {
|
|
26213
26018
|
_noneOfTheAboveSelected = true;
|
|
26214
26019
|
}
|
|
26215
26020
|
}
|
|
26216
26021
|
}
|
|
26217
26022
|
|
|
26218
26023
|
return {
|
|
26219
|
-
choicesSelected:
|
|
26024
|
+
choicesSelected: _choicesSelected,
|
|
26220
26025
|
noneOfTheAboveIndex: _noneOfTheAboveIndex,
|
|
26221
26026
|
noneOfTheAboveSelected: _noneOfTheAboveSelected,
|
|
26222
26027
|
countChoices: _countChoices,
|
|
@@ -26226,15 +26031,14 @@ class Radio$1 extends React.Component {
|
|
|
26226
26031
|
|
|
26227
26032
|
|
|
26228
26033
|
return {
|
|
26229
|
-
choicesSelected:
|
|
26034
|
+
choicesSelected: props.choices.map(() => false)
|
|
26230
26035
|
};
|
|
26231
26036
|
}
|
|
26232
26037
|
|
|
26233
26038
|
}
|
|
26234
26039
|
|
|
26235
26040
|
_defineProperty(Radio$1, "defaultProps", {
|
|
26236
|
-
choices: [
|
|
26237
|
-
displayCount: null,
|
|
26041
|
+
choices: [],
|
|
26238
26042
|
multipleSelect: false,
|
|
26239
26043
|
countChoices: false,
|
|
26240
26044
|
deselectEnabled: false,
|
|
@@ -26265,14 +26069,14 @@ var _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
26265
26069
|
|
|
26266
26070
|
var _addNoneOfAbove = function _addNoneOfAbove(choices) {
|
|
26267
26071
|
var noneOfTheAbove = null;
|
|
26268
|
-
|
|
26269
|
-
var newChoices = _.reject(choices, function (choice, index) {
|
|
26072
|
+
var newChoices = choices.filter((choice, index) => {
|
|
26270
26073
|
if (choice.isNoneOfTheAbove) {
|
|
26271
26074
|
noneOfTheAbove = choice;
|
|
26272
|
-
return
|
|
26075
|
+
return false;
|
|
26273
26076
|
}
|
|
26274
|
-
}); // Place the "None of the above" options last
|
|
26275
26077
|
|
|
26078
|
+
return true;
|
|
26079
|
+
}); // Place the "None of the above" options last
|
|
26276
26080
|
|
|
26277
26081
|
if (noneOfTheAbove) {
|
|
26278
26082
|
newChoices.push(noneOfTheAbove);
|
|
@@ -26292,9 +26096,8 @@ var _choiceTransform = (widgetOptions, problemNum) => {
|
|
|
26292
26096
|
}; // Add meta-information to choices
|
|
26293
26097
|
|
|
26294
26098
|
|
|
26295
|
-
var choices = widgetOptions.choices.
|
|
26296
|
-
|
|
26297
|
-
return _.extend({}, choice, {
|
|
26099
|
+
var choices = widgetOptions.choices.map((choice, i) => {
|
|
26100
|
+
return _objectSpread2(_objectSpread2({}, choice), {}, {
|
|
26298
26101
|
originalIndex: i,
|
|
26299
26102
|
correct: Boolean(choice.correct)
|
|
26300
26103
|
});
|
|
@@ -41132,43 +40935,23 @@ var styles$9 = StyleSheet.create({
|
|
|
41132
40935
|
}
|
|
41133
40936
|
});
|
|
41134
40937
|
|
|
41135
|
-
var getLineHeightForNode = (
|
|
41136
|
-
return $line2.offset().top - $line1.offset().top;
|
|
40938
|
+
var getLineHeightForNode = (line1, line2) => {
|
|
40939
|
+
return $(line2).offset().top - $(line1).offset().top;
|
|
41137
40940
|
};
|
|
41138
40941
|
|
|
41139
|
-
|
|
41140
|
-
|
|
41141
|
-
|
|
41142
|
-
|
|
41143
|
-
|
|
41144
|
-
|
|
41145
|
-
|
|
41146
|
-
|
|
41147
|
-
|
|
41148
|
-
|
|
41149
|
-
|
|
41150
|
-
|
|
41151
|
-
}
|
|
41152
|
-
var SQUARE_LABEL_STYLE = {
|
|
41153
|
-
display: "inline-block",
|
|
41154
|
-
color: "rgb(255, 255, 255)",
|
|
41155
|
-
backgroundColor: "rgb(90, 90, 90)",
|
|
41156
|
-
paddingLeft: 10,
|
|
41157
|
-
paddingRight: 10,
|
|
41158
|
-
userSelect: "none",
|
|
41159
|
-
WebkitUserSelect: "none"
|
|
41160
|
-
};
|
|
41161
|
-
var CIRCLE_LABEL_STYLE = {
|
|
41162
|
-
display: "inline-block",
|
|
41163
|
-
color: "rgb(255, 255, 255)",
|
|
41164
|
-
backgroundColor: "rgb(90, 90, 90)",
|
|
41165
|
-
userSelect: "none",
|
|
41166
|
-
WebkitUserSelect: "none",
|
|
41167
|
-
width: 22,
|
|
41168
|
-
height: 22,
|
|
41169
|
-
borderRadius: "50%",
|
|
41170
|
-
textAlign: "center"
|
|
41171
|
-
};
|
|
40942
|
+
function getInitialParseState() {
|
|
40943
|
+
return {
|
|
40944
|
+
currentRef: [],
|
|
40945
|
+
useRefs: true,
|
|
40946
|
+
lastRef: 0,
|
|
40947
|
+
firstSentenceRef: null,
|
|
40948
|
+
firstQuestionRef: null,
|
|
40949
|
+
lastFootnote: {
|
|
40950
|
+
id: 0,
|
|
40951
|
+
text: ""
|
|
40952
|
+
}
|
|
40953
|
+
};
|
|
40954
|
+
}
|
|
41172
40955
|
|
|
41173
40956
|
class RefStart extends React.Component {
|
|
41174
40957
|
constructor() {
|
|
@@ -41187,10 +40970,6 @@ class RefStart extends React.Component {
|
|
|
41187
40970
|
|
|
41188
40971
|
}
|
|
41189
40972
|
|
|
41190
|
-
_defineProperty(RefStart, "propTypes", {
|
|
41191
|
-
refContent: PropTypes.node.isRequired
|
|
41192
|
-
});
|
|
41193
|
-
|
|
41194
40973
|
class RefEnd extends React.Component {
|
|
41195
40974
|
render() {
|
|
41196
40975
|
return /*#__PURE__*/React.createElement("span", {
|
|
@@ -41201,20 +40980,11 @@ class RefEnd extends React.Component {
|
|
|
41201
40980
|
}
|
|
41202
40981
|
|
|
41203
40982
|
var rules = {
|
|
41204
|
-
// $FlowFixMe[prop-missing]
|
|
41205
|
-
// $FlowFixMe[incompatible-use]
|
|
41206
40983
|
newline: SimpleMarkdown.defaultRules.newline,
|
|
41207
|
-
// $FlowFixMe[prop-missing]
|
|
41208
|
-
// $FlowFixMe[incompatible-use]
|
|
41209
40984
|
paragraph: SimpleMarkdown.defaultRules.paragraph,
|
|
41210
|
-
// $FlowFixMe[prop-missing]
|
|
41211
|
-
// $FlowFixMe[incompatible-use]
|
|
41212
40985
|
escape: SimpleMarkdown.defaultRules.escape,
|
|
41213
40986
|
passageFootnote: {
|
|
41214
|
-
// $FlowFixMe[prop-missing]
|
|
41215
|
-
// $FlowFixMe[incompatible-use]
|
|
41216
40987
|
order: SimpleMarkdown.defaultRules.escape.order + 0.1,
|
|
41217
|
-
// $FlowFixMe[prop-missing]
|
|
41218
40988
|
match: SimpleMarkdown.inlineRegex(/^\^/),
|
|
41219
40989
|
parse: (capture, _parse, state) => {
|
|
41220
40990
|
// if no footnotes have been seen, we're id 1. otherwise,
|
|
@@ -41243,10 +41013,8 @@ var rules = {
|
|
|
41243
41013
|
}
|
|
41244
41014
|
},
|
|
41245
41015
|
refStart: {
|
|
41246
|
-
// $FlowFixMe[prop-missing]
|
|
41247
|
-
// $FlowFixMe[incompatible-use]
|
|
41248
41016
|
order: SimpleMarkdown.defaultRules.escape.order + 0.2,
|
|
41249
|
-
match: function match(source
|
|
41017
|
+
match: function match(source) {
|
|
41250
41018
|
var capture = /^\{\{/.exec(source);
|
|
41251
41019
|
|
|
41252
41020
|
if (capture) {
|
|
@@ -41277,12 +41045,14 @@ var rules = {
|
|
|
41277
41045
|
}
|
|
41278
41046
|
|
|
41279
41047
|
closeIndex++;
|
|
41280
|
-
}
|
|
41281
|
-
|
|
41282
|
-
var refText = source.slice(2, closeIndex); // A "magic" capture that matches the opening {{
|
|
41048
|
+
} // A "magic" capture that matches the opening {{
|
|
41283
41049
|
// but captures the full ref text internally :D
|
|
41050
|
+
// unfortunately the "magic" makes Flow upset,
|
|
41051
|
+
// so there's this questionable workaround
|
|
41052
|
+
|
|
41284
41053
|
|
|
41285
|
-
|
|
41054
|
+
capture[1] = source.slice(2, closeIndex);
|
|
41055
|
+
return capture;
|
|
41286
41056
|
}
|
|
41287
41057
|
|
|
41288
41058
|
return null;
|
|
@@ -41306,7 +41076,7 @@ var rules = {
|
|
|
41306
41076
|
// to make those refs into react refs on the
|
|
41307
41077
|
// passage, for instance!
|
|
41308
41078
|
useRefs: false
|
|
41309
|
-
},
|
|
41079
|
+
}, getInitialParseState()));
|
|
41310
41080
|
|
|
41311
41081
|
return {
|
|
41312
41082
|
ref: ref,
|
|
@@ -41314,26 +41084,27 @@ var rules = {
|
|
|
41314
41084
|
};
|
|
41315
41085
|
},
|
|
41316
41086
|
react: (node, output, state) => {
|
|
41317
|
-
|
|
41087
|
+
var ref = node.ref;
|
|
41088
|
+
|
|
41089
|
+
if (ref == null) {
|
|
41318
41090
|
return null;
|
|
41319
41091
|
} // We don't pass state here because this is parsed
|
|
41320
41092
|
// and output out-of-band. We don't want to affect
|
|
41321
41093
|
// our state by the double-output here :).
|
|
41322
41094
|
|
|
41323
41095
|
|
|
41324
|
-
var refContent = output(node.refContent, {});
|
|
41096
|
+
var refContent = output(node.refContent, {}); // note(matthewc) the refs created here become the refs
|
|
41097
|
+
// pulled from `this.refs` in passage.jsx
|
|
41098
|
+
|
|
41325
41099
|
return /*#__PURE__*/React.createElement(RefStart, {
|
|
41326
|
-
ref: START_REF_PREFIX +
|
|
41327
|
-
key: START_REF_PREFIX +
|
|
41100
|
+
ref: START_REF_PREFIX + ref,
|
|
41101
|
+
key: START_REF_PREFIX + ref,
|
|
41328
41102
|
refContent: refContent
|
|
41329
41103
|
});
|
|
41330
41104
|
}
|
|
41331
41105
|
},
|
|
41332
41106
|
refEnd: {
|
|
41333
|
-
// $FlowFixMe[prop-missing]
|
|
41334
|
-
// $FlowFixMe[incompatible-use]
|
|
41335
41107
|
order: SimpleMarkdown.defaultRules.escape.order + 0.3,
|
|
41336
|
-
// $FlowFixMe[prop-missing]
|
|
41337
41108
|
match: SimpleMarkdown.inlineRegex(/^\}\}/),
|
|
41338
41109
|
parse: (capture, _parse3, state) => {
|
|
41339
41110
|
if (!state.useRefs) {
|
|
@@ -41349,6 +41120,8 @@ var rules = {
|
|
|
41349
41120
|
},
|
|
41350
41121
|
react: (node, output, state) => {
|
|
41351
41122
|
if (node.ref != null) {
|
|
41123
|
+
// note(matthewc) the refs created here become the refs
|
|
41124
|
+
// pulled from `this.refs` in passage.jsx
|
|
41352
41125
|
return /*#__PURE__*/React.createElement(RefEnd, {
|
|
41353
41126
|
ref: END_REF_PREFIX + node.ref,
|
|
41354
41127
|
key: END_REF_PREFIX + node.ref
|
|
@@ -41362,10 +41135,7 @@ var rules = {
|
|
|
41362
41135
|
}
|
|
41363
41136
|
},
|
|
41364
41137
|
squareLabel: {
|
|
41365
|
-
// $FlowFixMe[prop-missing]
|
|
41366
|
-
// $FlowFixMe[incompatible-use]
|
|
41367
41138
|
order: SimpleMarkdown.defaultRules.escape.order + 0.4,
|
|
41368
|
-
// $FlowFixMe[prop-missing]
|
|
41369
41139
|
match: SimpleMarkdown.inlineRegex(/^\[\[(\w+)\]\]( *)/),
|
|
41370
41140
|
parse: (capture, _parse4, state) => {
|
|
41371
41141
|
if (!state.firstQuestionRef) {
|
|
@@ -41394,10 +41164,7 @@ var rules = {
|
|
|
41394
41164
|
}
|
|
41395
41165
|
},
|
|
41396
41166
|
circleLabel: {
|
|
41397
|
-
// $FlowFixMe[prop-missing]
|
|
41398
|
-
// $FlowFixMe[incompatible-use]
|
|
41399
41167
|
order: SimpleMarkdown.defaultRules.escape.order + 0.5,
|
|
41400
|
-
// $FlowFixMe[prop-missing]
|
|
41401
41168
|
match: SimpleMarkdown.inlineRegex(/^\(\((\w+)\)\)( *)/),
|
|
41402
41169
|
parse: (capture, _parse5, state) => {
|
|
41403
41170
|
return {
|
|
@@ -41422,10 +41189,7 @@ var rules = {
|
|
|
41422
41189
|
}
|
|
41423
41190
|
},
|
|
41424
41191
|
squareBracketRef: {
|
|
41425
|
-
// $FlowFixMe[prop-missing]
|
|
41426
|
-
// $FlowFixMe[incompatible-use]
|
|
41427
41192
|
order: SimpleMarkdown.defaultRules.escape.order + 0.6,
|
|
41428
|
-
// $FlowFixMe[prop-missing]
|
|
41429
41193
|
match: SimpleMarkdown.inlineRegex(/^\[(\d+)\]( *)/),
|
|
41430
41194
|
parse: (capture, _parse6, state) => {
|
|
41431
41195
|
if (!state.firstSentenceRef) {
|
|
@@ -41451,10 +41215,7 @@ var rules = {
|
|
|
41451
41215
|
}
|
|
41452
41216
|
},
|
|
41453
41217
|
highlight: {
|
|
41454
|
-
// $FlowFixMe[prop-missing]
|
|
41455
|
-
// $FlowFixMe[incompatible-use]
|
|
41456
41218
|
order: SimpleMarkdown.defaultRules.escape.order + 0.7,
|
|
41457
|
-
// $FlowFixMe[prop-missing]
|
|
41458
41219
|
match: SimpleMarkdown.inlineRegex(/^{highlighting.start}(.+?){highlighting.end}/),
|
|
41459
41220
|
parse: (capture, _parse7, state) => {
|
|
41460
41221
|
return {
|
|
@@ -41469,10 +41230,7 @@ var rules = {
|
|
|
41469
41230
|
}
|
|
41470
41231
|
},
|
|
41471
41232
|
reviewHighlight: {
|
|
41472
|
-
// $FlowFixMe[prop-missing]
|
|
41473
|
-
// $FlowFixMe[incompatible-use]
|
|
41474
41233
|
order: SimpleMarkdown.defaultRules.escape.order + 0.7,
|
|
41475
|
-
// $FlowFixMe[prop-missing]
|
|
41476
41234
|
match: SimpleMarkdown.inlineRegex(/^{review-highlighting.start}(.+?){review-highlighting.end}/),
|
|
41477
41235
|
parse: (capture, _parse8, state) => {
|
|
41478
41236
|
return {
|
|
@@ -41486,17 +41244,9 @@ var rules = {
|
|
|
41486
41244
|
}, node.content)];
|
|
41487
41245
|
}
|
|
41488
41246
|
},
|
|
41489
|
-
// $FlowFixMe[prop-missing]
|
|
41490
|
-
// $FlowFixMe[incompatible-use]
|
|
41491
41247
|
strong: SimpleMarkdown.defaultRules.strong,
|
|
41492
|
-
// $FlowFixMe[prop-missing]
|
|
41493
|
-
// $FlowFixMe[incompatible-use]
|
|
41494
41248
|
u: SimpleMarkdown.defaultRules.u,
|
|
41495
|
-
// $FlowFixMe[prop-missing]
|
|
41496
|
-
// $FlowFixMe[incompatible-use]
|
|
41497
41249
|
em: SimpleMarkdown.defaultRules.em,
|
|
41498
|
-
// $FlowFixMe[prop-missing]
|
|
41499
|
-
// $FlowFixMe[incompatible-use]
|
|
41500
41250
|
del: SimpleMarkdown.defaultRules.del,
|
|
41501
41251
|
text: _objectSpread2(_objectSpread2({}, SimpleMarkdown.defaultRules.text), {}, {
|
|
41502
41252
|
react(node, output, state) {
|
|
@@ -41507,32 +41257,54 @@ var rules = {
|
|
|
41507
41257
|
|
|
41508
41258
|
})
|
|
41509
41259
|
};
|
|
41510
|
-
var
|
|
41511
|
-
|
|
41512
|
-
|
|
41513
|
-
|
|
41514
|
-
|
|
41515
|
-
|
|
41516
|
-
|
|
41517
|
-
|
|
41518
|
-
|
|
41519
|
-
|
|
41260
|
+
var START_REF_PREFIX = "start-ref-";
|
|
41261
|
+
var END_REF_PREFIX = "end-ref-";
|
|
41262
|
+
var REF_STYLE = {
|
|
41263
|
+
display: "inline-block",
|
|
41264
|
+
width: 0,
|
|
41265
|
+
visibility: "hidden"
|
|
41266
|
+
};
|
|
41267
|
+
var LABEL_OUTER_STYLE = {
|
|
41268
|
+
// for some reason we need these to keep the nbsp from wrapping when the
|
|
41269
|
+
// inner circle/square is display: inline-block
|
|
41270
|
+
display: "inline",
|
|
41271
|
+
whiteSpace: "nowrap"
|
|
41272
|
+
};
|
|
41273
|
+
var SQUARE_LABEL_STYLE = {
|
|
41274
|
+
display: "inline-block",
|
|
41275
|
+
color: "rgb(255, 255, 255)",
|
|
41276
|
+
backgroundColor: "rgb(90, 90, 90)",
|
|
41277
|
+
paddingLeft: 10,
|
|
41278
|
+
paddingRight: 10,
|
|
41279
|
+
userSelect: "none",
|
|
41280
|
+
WebkitUserSelect: "none"
|
|
41281
|
+
};
|
|
41282
|
+
var CIRCLE_LABEL_STYLE = {
|
|
41283
|
+
display: "inline-block",
|
|
41284
|
+
color: "rgb(255, 255, 255)",
|
|
41285
|
+
backgroundColor: "rgb(90, 90, 90)",
|
|
41286
|
+
userSelect: "none",
|
|
41287
|
+
WebkitUserSelect: "none",
|
|
41288
|
+
width: 22,
|
|
41289
|
+
height: 22,
|
|
41290
|
+
borderRadius: "50%",
|
|
41291
|
+
textAlign: "center"
|
|
41292
|
+
};
|
|
41520
41293
|
var builtParser = SimpleMarkdown.parserFor(rules);
|
|
41521
41294
|
|
|
41522
41295
|
var parse = (source, state) => {
|
|
41523
41296
|
state = state || {};
|
|
41524
41297
|
var paragraphedSource = source + "\n\n";
|
|
41525
|
-
return builtParser(paragraphedSource, _.extend(state,
|
|
41298
|
+
return builtParser(paragraphedSource, _.extend(state, getInitialParseState()));
|
|
41526
41299
|
};
|
|
41527
41300
|
|
|
41301
|
+
var output = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, "react"));
|
|
41528
41302
|
var PassageMarkdown = {
|
|
41529
|
-
parse
|
|
41530
|
-
|
|
41531
|
-
|
|
41532
|
-
|
|
41533
|
-
|
|
41534
|
-
END_REF_PREFIX: END_REF_PREFIX,
|
|
41535
|
-
_rulesForTesting: rules
|
|
41303
|
+
parse,
|
|
41304
|
+
output,
|
|
41305
|
+
START_REF_PREFIX,
|
|
41306
|
+
END_REF_PREFIX,
|
|
41307
|
+
getInitialParseState
|
|
41536
41308
|
};
|
|
41537
41309
|
|
|
41538
41310
|
// A fake paragraph to measure the line height of the passage. In CSS we always
|
|
@@ -41545,9 +41317,9 @@ class LineHeightMeasurer extends React.Component {
|
|
|
41545
41317
|
|
|
41546
41318
|
_defineProperty(this, "_cachedLineHeight", void 0);
|
|
41547
41319
|
|
|
41548
|
-
_defineProperty(this, "
|
|
41320
|
+
_defineProperty(this, "body", void 0);
|
|
41549
41321
|
|
|
41550
|
-
_defineProperty(this, "
|
|
41322
|
+
_defineProperty(this, "end", void 0);
|
|
41551
41323
|
}
|
|
41552
41324
|
|
|
41553
41325
|
measureLineHeight() {
|
|
@@ -41559,23 +41331,30 @@ class LineHeightMeasurer extends React.Component {
|
|
|
41559
41331
|
}
|
|
41560
41332
|
|
|
41561
41333
|
forceMeasureLineHeight() {
|
|
41562
|
-
|
|
41563
|
-
this
|
|
41334
|
+
var body = this.body;
|
|
41335
|
+
var end = this.end;
|
|
41336
|
+
|
|
41337
|
+
if (!body || !end) {
|
|
41338
|
+
return;
|
|
41339
|
+
} // Add some text which magically fills an entire line.
|
|
41340
|
+
|
|
41341
|
+
|
|
41342
|
+
body.textContent = " \u0080"; // Now, the line height is the difference between the top of the
|
|
41564
41343
|
// second line and the top of the first line.
|
|
41565
41344
|
|
|
41566
|
-
this._cachedLineHeight = getLineHeightForNode(
|
|
41345
|
+
this._cachedLineHeight = getLineHeightForNode(body, end); // Clear out the first line so it doesn't overlap the passage.
|
|
41567
41346
|
|
|
41568
|
-
|
|
41347
|
+
body.textContent = "";
|
|
41569
41348
|
}
|
|
41570
41349
|
|
|
41571
41350
|
render() {
|
|
41572
41351
|
return /*#__PURE__*/React.createElement("div", {
|
|
41573
41352
|
className: css(styles$8.measurer)
|
|
41574
41353
|
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
41575
|
-
ref:
|
|
41354
|
+
ref: _ref => this.body = _ref,
|
|
41576
41355
|
className: "paragraph"
|
|
41577
41356
|
}), /*#__PURE__*/React.createElement("div", {
|
|
41578
|
-
ref:
|
|
41357
|
+
ref: _ref2 => this.end = _ref2
|
|
41579
41358
|
})));
|
|
41580
41359
|
}
|
|
41581
41360
|
|
|
@@ -41594,9 +41373,11 @@ class Passage extends React.Component {
|
|
|
41594
41373
|
constructor() {
|
|
41595
41374
|
super(...arguments);
|
|
41596
41375
|
|
|
41597
|
-
_defineProperty(this, "
|
|
41376
|
+
_defineProperty(this, "_contentRef", void 0);
|
|
41377
|
+
|
|
41378
|
+
_defineProperty(this, "_lineHeightMeasurerRef", void 0);
|
|
41598
41379
|
|
|
41599
|
-
_defineProperty(this, "
|
|
41380
|
+
_defineProperty(this, "_onResize", void 0);
|
|
41600
41381
|
|
|
41601
41382
|
_defineProperty(this, "_stylesAppiedTimer", void 0);
|
|
41602
41383
|
|
|
@@ -41617,6 +41398,8 @@ class Passage extends React.Component {
|
|
|
41617
41398
|
this._updateState();
|
|
41618
41399
|
|
|
41619
41400
|
this._onResize = _.throttle(() => {
|
|
41401
|
+
var _this$_lineHeightMeas;
|
|
41402
|
+
|
|
41620
41403
|
// If we're rendering JIPT text, we won't have line numbers or a
|
|
41621
41404
|
// line height measurer, so skip handling this resize.
|
|
41622
41405
|
if (this.shouldRenderJipt()) {
|
|
@@ -41627,7 +41410,7 @@ class Passage extends React.Component {
|
|
|
41627
41410
|
// listen for resize events.
|
|
41628
41411
|
|
|
41629
41412
|
|
|
41630
|
-
this.
|
|
41413
|
+
(_this$_lineHeightMeas = this._lineHeightMeasurerRef) === null || _this$_lineHeightMeas === void 0 ? void 0 : _this$_lineHeightMeas.forceMeasureLineHeight();
|
|
41631
41414
|
|
|
41632
41415
|
this._updateState();
|
|
41633
41416
|
}, 500);
|
|
@@ -41690,9 +41473,8 @@ class Passage extends React.Component {
|
|
|
41690
41473
|
}
|
|
41691
41474
|
|
|
41692
41475
|
_measureLines() {
|
|
41693
|
-
|
|
41694
|
-
var
|
|
41695
|
-
var contentsHeight = $renderer.height();
|
|
41476
|
+
var renderer = ReactDOM__default.findDOMNode(this._contentRef);
|
|
41477
|
+
var contentsHeight = $(renderer).height();
|
|
41696
41478
|
|
|
41697
41479
|
var lineHeight = this._getLineHeight();
|
|
41698
41480
|
|
|
@@ -41719,7 +41501,9 @@ class Passage extends React.Component {
|
|
|
41719
41501
|
}
|
|
41720
41502
|
|
|
41721
41503
|
_getLineHeight() {
|
|
41722
|
-
|
|
41504
|
+
var _this$_lineHeightMeas2;
|
|
41505
|
+
|
|
41506
|
+
return ((_this$_lineHeightMeas2 = this._lineHeightMeasurerRef) === null || _this$_lineHeightMeas2 === void 0 ? void 0 : _this$_lineHeightMeas2.measureLineHeight()) || 0;
|
|
41723
41507
|
}
|
|
41724
41508
|
|
|
41725
41509
|
getLineCount() {
|
|
@@ -41735,12 +41519,16 @@ class Passage extends React.Component {
|
|
|
41735
41519
|
* These are functions to support the passage refs inter-widgets feature
|
|
41736
41520
|
* where other widgets can fetch the line numbers of a reference inside of
|
|
41737
41521
|
* a passage.
|
|
41522
|
+
*
|
|
41523
|
+
* todo(matthewc): The refs are created by PassageMarkdown's refStart and refEnd,
|
|
41524
|
+
* somehow bubbling up to Passage's `this.refs`. This runs against
|
|
41525
|
+
* current best practices for refs by using string refs, but also
|
|
41526
|
+
* by breaking our expectation of explicit data flow.
|
|
41738
41527
|
*/
|
|
41739
41528
|
|
|
41740
41529
|
|
|
41741
41530
|
_getStartRefLineNumber(referenceNumber) {
|
|
41742
|
-
var refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
|
|
41743
|
-
|
|
41531
|
+
var refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
|
|
41744
41532
|
var ref = this.refs[refRef];
|
|
41745
41533
|
|
|
41746
41534
|
if (!ref) {
|
|
@@ -41763,8 +41551,7 @@ class Passage extends React.Component {
|
|
|
41763
41551
|
}
|
|
41764
41552
|
|
|
41765
41553
|
_getEndRefLineNumber(referenceNumber) {
|
|
41766
|
-
var refRef = PassageMarkdown.END_REF_PREFIX + referenceNumber;
|
|
41767
|
-
|
|
41554
|
+
var refRef = PassageMarkdown.END_REF_PREFIX + referenceNumber;
|
|
41768
41555
|
var ref = this.refs[refRef];
|
|
41769
41556
|
|
|
41770
41557
|
if (!ref) {
|
|
@@ -41801,9 +41588,8 @@ class Passage extends React.Component {
|
|
|
41801
41588
|
}
|
|
41802
41589
|
|
|
41803
41590
|
_convertPosToLineNumber(absoluteVPos) {
|
|
41804
|
-
|
|
41805
|
-
var
|
|
41806
|
-
var relativeVPos = absoluteVPos - $content.offset().top;
|
|
41591
|
+
var content = ReactDOM__default.findDOMNode(this._contentRef);
|
|
41592
|
+
var relativeVPos = absoluteVPos - $(content).offset().top;
|
|
41807
41593
|
|
|
41808
41594
|
var lineHeight = this._getLineHeight();
|
|
41809
41595
|
|
|
@@ -41812,8 +41598,7 @@ class Passage extends React.Component {
|
|
|
41812
41598
|
}
|
|
41813
41599
|
|
|
41814
41600
|
_getRefContent(referenceNumber) {
|
|
41815
|
-
var refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
|
|
41816
|
-
|
|
41601
|
+
var refRef = PassageMarkdown.START_REF_PREFIX + referenceNumber;
|
|
41817
41602
|
var ref = this.refs[refRef];
|
|
41818
41603
|
|
|
41819
41604
|
if (!ref) {
|
|
@@ -41919,12 +41704,9 @@ class Passage extends React.Component {
|
|
|
41919
41704
|
onSerializedHighlightsUpdate: this._handleSerializedHighlightsUpdate,
|
|
41920
41705
|
serializedHighlights: this.props.highlights
|
|
41921
41706
|
}, /*#__PURE__*/React.createElement("div", {
|
|
41922
|
-
ref:
|
|
41923
|
-
}, /*#__PURE__*/React.createElement(LineHeightMeasurer
|
|
41924
|
-
|
|
41925
|
-
// $FlowFixMe[incompatible-type](0.52.0->0.53.0)
|
|
41926
|
-
, {
|
|
41927
|
-
ref: e => this._lineHeightMeasurer = e
|
|
41707
|
+
ref: _ref4 => this._contentRef = _ref4
|
|
41708
|
+
}, /*#__PURE__*/React.createElement(LineHeightMeasurer, {
|
|
41709
|
+
ref: _ref3 => this._lineHeightMeasurerRef = _ref3
|
|
41928
41710
|
}), PassageMarkdown.output(parsed)));
|
|
41929
41711
|
}
|
|
41930
41712
|
|
|
@@ -41967,10 +41749,7 @@ class Passage extends React.Component {
|
|
|
41967
41749
|
});
|
|
41968
41750
|
}
|
|
41969
41751
|
|
|
41970
|
-
var parseState =
|
|
41971
|
-
firstSentenceRef: null,
|
|
41972
|
-
firstQuestionRef: null
|
|
41973
|
-
}; // Replace the vertical double quote characters quoting text with
|
|
41752
|
+
var parseState = PassageMarkdown.getInitialParseState(); // Replace the vertical double quote characters quoting text with
|
|
41974
41753
|
// an unicode left and right double quote characters. This would
|
|
41975
41754
|
// avoid rendering right or left unicode double quotes on both
|
|
41976
41755
|
// ends of a sentence wrapped by double quotes.
|