@khanacademy/perseus 19.1.5 → 19.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/graph.d.ts +0 -1
- package/dist/components/graphie.d.ts +0 -1
- package/dist/es/index.js +319 -212
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +338 -222
- package/dist/index.js.map +1 -1
- package/dist/interactive2/movable-point.d.ts +195 -1
- package/dist/interactive2/movable.d.ts +1 -1
- package/dist/interactive2/types.d.ts +4 -2
- package/dist/interactive2.d.ts +2 -1
- package/dist/server-item-renderer.d.ts +2 -2
- package/dist/util/graphie.d.ts +12 -2
- package/dist/widgets/expression.d.ts +6 -6
- package/package.json +11 -8
- package/.babelrc.js +0 -8
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -1432
- package/src/__stories__/article-renderer.stories.tsx +0 -100
- package/src/__stories__/hints-renderer.stories.tsx +0 -55
- package/src/__stories__/server-item-renderer.stories.tsx +0 -44
- package/src/__testdata__/article-renderer.testdata.ts +0 -212
- package/src/__testdata__/graphie.testdata.ts +0 -51
- package/src/__testdata__/renderer.testdata.ts +0 -274
- package/src/__testdata__/server-item-renderer.testdata.ts +0 -171
- package/src/__tests__/__snapshots__/perseus-markdown.test.ts.snap +0 -507
- package/src/__tests__/__snapshots__/renderer.test.tsx.snap +0 -525
- package/src/__tests__/__snapshots__/server-item-renderer.test.tsx.snap +0 -285
- package/src/__tests__/a11y.test.ts +0 -303
- package/src/__tests__/article-renderer.test.tsx +0 -130
- package/src/__tests__/error-boundary.test.tsx +0 -76
- package/src/__tests__/extract-perseus-data.test.ts +0 -1027
- package/src/__tests__/init.test.ts +0 -10
- package/src/__tests__/jipt-paragraphs.test.ts +0 -32
- package/src/__tests__/mock-asset-loading-widget.tsx +0 -53
- package/src/__tests__/mock-widget.tsx +0 -33
- package/src/__tests__/perseus-markdown.test.ts +0 -764
- package/src/__tests__/renderability.test.ts +0 -480
- package/src/__tests__/renderer-api.test.tsx +0 -302
- package/src/__tests__/renderer.test.tsx +0 -1816
- package/src/__tests__/server-item-renderer.test.tsx +0 -582
- package/src/__tests__/test-items/image-item.ts +0 -24
- package/src/__tests__/test-items/input-number-1-item.ts +0 -26
- package/src/__tests__/test-items/input-number-2-item.ts +0 -38
- package/src/__tests__/test-items/table-item.ts +0 -29
- package/src/__tests__/tex-wrangler.test.ts +0 -82
- package/src/__tests__/util.test.ts +0 -40
- package/src/__tests__/widget-container.test.tsx +0 -126
- package/src/__tests__/widgets.test.ts +0 -91
- package/src/a11y.ts +0 -45
- package/src/all-widgets.ts +0 -9
- package/src/article-renderer.tsx +0 -237
- package/src/asset-context.ts +0 -30
- package/src/basic-widgets.ts +0 -16
- package/src/components/__stories__/button-group.stories.tsx +0 -55
- package/src/components/__stories__/fixed-to-responsive.stories.tsx +0 -141
- package/src/components/__stories__/graph.stories.tsx +0 -28
- package/src/components/__stories__/graphie.stories.tsx +0 -33
- package/src/components/__stories__/hud.stories.tsx +0 -35
- package/src/components/__stories__/icon.stories.tsx +0 -63
- package/src/components/__stories__/image-loader.stories.tsx +0 -63
- package/src/components/__stories__/info-tip.stories.tsx +0 -31
- package/src/components/__stories__/inline-icon.stories.tsx +0 -40
- package/src/components/__stories__/input-with-examples.stories.tsx +0 -53
- package/src/components/__stories__/lint.stories.tsx +0 -86
- package/src/components/__stories__/math-input.stories.tsx +0 -43
- package/src/components/__stories__/math-output.stories.tsx +0 -23
- package/src/components/__stories__/multi-button-group.stories.tsx +0 -66
- package/src/components/__stories__/number-input.stories.tsx +0 -41
- package/src/components/__stories__/prop-check-box.stories.tsx +0 -65
- package/src/components/__stories__/range-input.stories.tsx +0 -29
- package/src/components/__stories__/simple-keypad-input.stories.tsx +0 -27
- package/src/components/__stories__/sortable.stories.tsx +0 -77
- package/src/components/__stories__/stub-tag-editor.stories.tsx +0 -45
- package/src/components/__stories__/svg-image.stories.tsx +0 -74
- package/src/components/__stories__/tex.stories.tsx +0 -23
- package/src/components/__stories__/text-input.stories.tsx +0 -33
- package/src/components/__stories__/text-list-editor.stories.tsx +0 -32
- package/src/components/__stories__/tooltip.stories.tsx +0 -52
- package/src/components/__stories__/zoomable-tex.stories.tsx +0 -41
- package/src/components/__stories__/zoomable.stories.tsx +0 -49
- package/src/components/__testdata__/sorter.testdata.ts +0 -19
- package/src/components/__tests__/__snapshots__/sortable.test.tsx.snap +0 -163
- package/src/components/__tests__/__snapshots__/sorter.test.tsx.snap +0 -265
- package/src/components/__tests__/math-input.test.tsx +0 -147
- package/src/components/__tests__/number-input.test.tsx +0 -128
- package/src/components/__tests__/sortable.test.tsx +0 -269
- package/src/components/__tests__/sorter.test.tsx +0 -114
- package/src/components/__tests__/zoomable.test.tsx +0 -399
- package/src/components/button-group.tsx +0 -130
- package/src/components/constants.ts +0 -14
- package/src/components/fixed-to-responsive.tsx +0 -169
- package/src/components/graph.tsx +0 -444
- package/src/components/graphie-classes.ts +0 -153
- package/src/components/graphie-movables.ts +0 -338
- package/src/components/graphie.tsx +0 -400
- package/src/components/highlighting/highlightable-content.tsx +0 -240
- package/src/components/highlighting/highlights.ts +0 -207
- package/src/components/highlighting/ranges.ts +0 -304
- package/src/components/highlighting/types.ts +0 -73
- package/src/components/highlighting/ui/highlight-renderer.tsx +0 -172
- package/src/components/highlighting/ui/highlight-set-renderer.tsx +0 -185
- package/src/components/highlighting/ui/highlight-tooltip.tsx +0 -141
- package/src/components/highlighting/ui/highlighting-ui.tsx +0 -143
- package/src/components/highlighting/ui/selection-tracker.tsx +0 -186
- package/src/components/highlighting/ui/types.ts +0 -21
- package/src/components/highlighting/ui/util.ts +0 -165
- package/src/components/highlighting/word-indexer.tsx +0 -152
- package/src/components/hud.tsx +0 -167
- package/src/components/icon.tsx +0 -141
- package/src/components/image-loader.tsx +0 -177
- package/src/components/info-tip/info-tip.tsx +0 -144
- package/src/components/info-tip.tsx +0 -39
- package/src/components/inline-icon.tsx +0 -60
- package/src/components/input-with-examples.tsx +0 -249
- package/src/components/lint.tsx +0 -459
- package/src/components/math-input.tsx +0 -474
- package/src/components/math-output.tsx +0 -134
- package/src/components/multi-button-group.tsx +0 -135
- package/src/components/number-input.tsx +0 -249
- package/src/components/prop-check-box.tsx +0 -79
- package/src/components/range-input.tsx +0 -60
- package/src/components/simple-keypad-input.tsx +0 -88
- package/src/components/sortable.tsx +0 -958
- package/src/components/stub-tag-editor.tsx +0 -53
- package/src/components/svg-image.tsx +0 -779
- package/src/components/tex.tsx +0 -67
- package/src/components/text-input.tsx +0 -129
- package/src/components/text-list-editor.tsx +0 -166
- package/src/components/tooltip.tsx +0 -410
- package/src/components/visibility-observer/__stories__/visibility-observer.stories.tsx +0 -141
- package/src/components/visibility-observer/create-visibility-observer.ts +0 -108
- package/src/components/visibility-observer/get-scroll-parent.ts +0 -46
- package/src/components/visibility-observer/visibility-observer.tsx +0 -124
- package/src/components/zoomable-tex.tsx +0 -78
- package/src/components/zoomable.tsx +0 -304
- package/src/components.ts +0 -15
- package/src/definition-context.tsx +0 -59
- package/src/dependencies.ts +0 -40
- package/src/error-boundary.tsx +0 -70
- package/src/extra-widgets.ts +0 -75
- package/src/hint-renderer.tsx +0 -151
- package/src/hints-renderer.tsx +0 -372
- package/src/icon-paths.ts +0 -119
- package/src/index.ts +0 -171
- package/src/init.ts +0 -56
- package/src/interaction-tracker.ts +0 -62
- package/src/interactive2/__tests__/movable-mock.ts +0 -55
- package/src/interactive2/__tests__/movable-point.test.ts +0 -144
- package/src/interactive2/interactive-util.test.ts +0 -93
- package/src/interactive2/interactive-util.ts +0 -159
- package/src/interactive2/movable-helper-methods.ts +0 -166
- package/src/interactive2/movable-line-options.ts +0 -419
- package/src/interactive2/movable-line.ts +0 -307
- package/src/interactive2/movable-point-options.ts +0 -224
- package/src/interactive2/movable-point.tsx +0 -585
- package/src/interactive2/movable-polygon-options.ts +0 -389
- package/src/interactive2/movable-polygon.ts +0 -360
- package/src/interactive2/movable.test.ts +0 -249
- package/src/interactive2/movable.ts +0 -437
- package/src/interactive2/objective_.ts +0 -79
- package/src/interactive2/types.ts +0 -17
- package/src/interactive2/wrapped-defaults.ts +0 -87
- package/src/interactive2/wrapped-ellipse.ts +0 -94
- package/src/interactive2/wrapped-line.ts +0 -116
- package/src/interactive2/wrapped-path.ts +0 -51
- package/src/interactive2.ts +0 -70
- package/src/item-version.ts +0 -10
- package/src/jipt-paragraphs.ts +0 -49
- package/src/jquery.mobile.vmouse.js +0 -545
- package/src/loading-context.ts +0 -21
- package/src/logging/log.test.ts +0 -39
- package/src/logging/log.ts +0 -97
- package/src/mixins/__tests__/widget-prop-denylist.test.ts +0 -21
- package/src/mixins/changeable.ts +0 -133
- package/src/mixins/editor-jsonify.ts +0 -13
- package/src/mixins/widget-jsonify-deprecated.ts +0 -23
- package/src/mixins/widget-prop-denylist.ts +0 -48
- package/src/multi-items/__stories__/multi-renderer.stories.tsx +0 -83
- package/src/multi-items/__testdata__/multi-renderer.testdata.ts +0 -172
- package/src/multi-items/__tests__/__snapshots__/multi-renderer.test.tsx.snap +0 -1164
- package/src/multi-items/__tests__/items.test.ts +0 -240
- package/src/multi-items/__tests__/multi-renderer.test.tsx +0 -914
- package/src/multi-items/__tests__/prop-type-builders.test.ts +0 -133
- package/src/multi-items/__tests__/shapes.test.ts +0 -43
- package/src/multi-items/__tests__/trees.test.ts +0 -317
- package/src/multi-items/item-types.ts +0 -56
- package/src/multi-items/items.ts +0 -176
- package/src/multi-items/multi-renderer.tsx +0 -569
- package/src/multi-items/prop-type-builders.ts +0 -106
- package/src/multi-items/shape-types.ts +0 -52
- package/src/multi-items/shapes.ts +0 -52
- package/src/multi-items/tree-types.ts +0 -47
- package/src/multi-items/trees.ts +0 -360
- package/src/multi-items.ts +0 -75
- package/src/perseus-api.tsx +0 -188
- package/src/perseus-env.ts +0 -27
- package/src/perseus-error.ts +0 -17
- package/src/perseus-markdown.tsx +0 -405
- package/src/perseus-types.ts +0 -1366
- package/src/perseus-version.ts +0 -9
- package/src/question-paragraph.tsx +0 -34
- package/src/renderability.ts +0 -109
- package/src/renderer.tsx +0 -2000
- package/src/server-item-renderer.tsx +0 -495
- package/src/sigfigs.ts +0 -490
- package/src/styles/articles.less +0 -749
- package/src/styles/constants.ts +0 -94
- package/src/styles/global-constants.ts +0 -343
- package/src/styles/global-styles.ts +0 -306
- package/src/styles/khan-exercise.css +0 -1468
- package/src/styles/media-queries.ts +0 -47
- package/src/styles/perseus-renderer.less +0 -732
- package/src/styles/shared.ts +0 -130
- package/src/styles/util.less +0 -47
- package/src/styles/variables.boostrap.less +0 -277
- package/src/styles/variables.less +0 -56
- package/src/styles/variables.shared.less +0 -340
- package/src/styles/widgets/categorizer.less +0 -38
- package/src/styles/widgets/dropdown.less +0 -3
- package/src/styles/widgets/expression.less +0 -65
- package/src/styles/widgets/graded-group.less +0 -36
- package/src/styles/widgets/grapher.less +0 -12
- package/src/styles/widgets/group.less +0 -19
- package/src/styles/widgets/image.less +0 -54
- package/src/styles/widgets/interactive-graph.less +0 -64
- package/src/styles/widgets/label-image.less +0 -57
- package/src/styles/widgets/matcher.less +0 -8
- package/src/styles/widgets/matrix.less +0 -126
- package/src/styles/widgets/measurer.less +0 -20
- package/src/styles/widgets/orderer.less +0 -98
- package/src/styles/widgets/passage.less +0 -154
- package/src/styles/widgets/plotter.less +0 -31
- package/src/styles/widgets/radio.less +0 -58
- package/src/styles/widgets/reaction-diagram.less +0 -35
- package/src/styles/widgets/sequence.less +0 -5
- package/src/styles/widgets/sortable.less +0 -113
- package/src/styles/widgets/table.less +0 -57
- package/src/styles/widgets/unit.less +0 -15
- package/src/tex-wrangler.ts +0 -182
- package/src/translation-linter.ts +0 -126
- package/src/traversal.ts +0 -138
- package/src/types.ts +0 -513
- package/src/util/a11y.ts +0 -23
- package/src/util/answer-types.test.ts +0 -114
- package/src/util/answer-types.ts +0 -876
- package/src/util/colors.ts +0 -93
- package/src/util/drawing-transform.test.ts +0 -67
- package/src/util/drawing-transform.ts +0 -102
- package/src/util/extract-perseus-data.ts +0 -539
- package/src/util/fix-passage-refs.ts +0 -121
- package/src/util/geometry.test.ts +0 -75
- package/src/util/geometry.ts +0 -312
- package/src/util/graph-bounds.ts +0 -23
- package/src/util/graph-utils.ts +0 -15
- package/src/util/graphie.test.ts +0 -1277
- package/src/util/graphie.ts +0 -1576
- package/src/util/interactive.ts +0 -4174
- package/src/util/interval.ts +0 -4
- package/src/util/katex-preprocess.ts +0 -14
- package/src/util/math.test.ts +0 -11
- package/src/util/math.ts +0 -294
- package/src/util/mobile-native-utils.test.ts +0 -22
- package/src/util/mobile-native-utils.ts +0 -12
- package/src/util/parse-perseus-json.test.ts +0 -10
- package/src/util/parse-perseus-json.ts +0 -13
- package/src/util/react-render.tsx +0 -27
- package/src/util/register-all-widgets-for-testing.ts +0 -13
- package/src/util/scroll-utils.ts +0 -155
- package/src/util/sizing-utils.ts +0 -46
- package/src/util/tex.ts +0 -73
- package/src/util/url-utils.ts +0 -34
- package/src/util.graphie.test.ts +0 -45
- package/src/util.graphie.ts +0 -59
- package/src/util.ts +0 -966
- package/src/version.ts +0 -10
- package/src/widget-container.tsx +0 -199
- package/src/widgets/__stories__/categorizer.stories.tsx +0 -14
- package/src/widgets/__stories__/cs-program.stories.tsx +0 -14
- package/src/widgets/__stories__/definition.stories.tsx +0 -114
- package/src/widgets/__stories__/dropdown.stories.tsx +0 -14
- package/src/widgets/__stories__/explanation.stories.tsx +0 -18
- package/src/widgets/__stories__/expression.stories.tsx +0 -145
- package/src/widgets/__stories__/graded-group-set.stories.tsx +0 -31
- package/src/widgets/__stories__/graded-group.stories.tsx +0 -31
- package/src/widgets/__stories__/grapher.stories.tsx +0 -46
- package/src/widgets/__stories__/group.stories.tsx +0 -14
- package/src/widgets/__stories__/iframe.stories.tsx +0 -14
- package/src/widgets/__stories__/image.stories.tsx +0 -85
- package/src/widgets/__stories__/input-number.stories.tsx +0 -101
- package/src/widgets/__stories__/interaction.stories.tsx +0 -14
- package/src/widgets/__stories__/interactive-graph.stories.tsx +0 -60
- package/src/widgets/__stories__/label-image.stories.tsx +0 -130
- package/src/widgets/__stories__/matcher.stories.tsx +0 -14
- package/src/widgets/__stories__/matrix.stories.tsx +0 -14
- package/src/widgets/__stories__/number-line.stories.tsx +0 -14
- package/src/widgets/__stories__/numeric-input.stories.tsx +0 -105
- package/src/widgets/__stories__/orderer.stories.tsx +0 -18
- package/src/widgets/__stories__/passage-ref.stories.tsx +0 -33
- package/src/widgets/__stories__/passage.stories.tsx +0 -39
- package/src/widgets/__stories__/plotter.stories.tsx +0 -27
- package/src/widgets/__stories__/radio.stories.tsx +0 -86
- package/src/widgets/__stories__/random-widgets.stories.tsx +0 -59
- package/src/widgets/__stories__/sorter.stories.tsx +0 -14
- package/src/widgets/__stories__/test-keypad-context-wrapper.tsx +0 -66
- package/src/widgets/__stories__/unit.stories.tsx +0 -28
- package/src/widgets/__stories__/video-transcript-link.stories.tsx +0 -23
- package/src/widgets/__stories__/video.stories.tsx +0 -22
- package/src/widgets/__testdata__/base-radio.testdata.ts +0 -21
- package/src/widgets/__testdata__/categorizer.testdata.ts +0 -89
- package/src/widgets/__testdata__/cs-program.testdata.ts +0 -27
- package/src/widgets/__testdata__/dropdown.testdata.ts +0 -71
- package/src/widgets/__testdata__/explanation.testdata.ts +0 -85
- package/src/widgets/__testdata__/expression.testdata.ts +0 -198
- package/src/widgets/__testdata__/graded-group-set.testdata.ts +0 -356
- package/src/widgets/__testdata__/graded-group.testdata.ts +0 -77
- package/src/widgets/__testdata__/grapher.testdata.ts +0 -374
- package/src/widgets/__testdata__/group.testdata.ts +0 -153
- package/src/widgets/__testdata__/iframe.testdata.ts +0 -35
- package/src/widgets/__testdata__/image.testdata.ts +0 -36
- package/src/widgets/__testdata__/input-number.testdata.ts +0 -72
- package/src/widgets/__testdata__/interaction.testdata.ts +0 -262
- package/src/widgets/__testdata__/interactive-graph-random.testdata.ts +0 -269
- package/src/widgets/__testdata__/interactive-graph.testdata.ts +0 -644
- package/src/widgets/__testdata__/label-image.testdata.ts +0 -308
- package/src/widgets/__testdata__/matcher.testdata.ts +0 -33
- package/src/widgets/__testdata__/matrix.testdata.ts +0 -28
- package/src/widgets/__testdata__/number-line.testdata.ts +0 -30
- package/src/widgets/__testdata__/numeric-input.testdata.ts +0 -265
- package/src/widgets/__testdata__/orderer.testdata.ts +0 -123
- package/src/widgets/__testdata__/passage-ref.testdata.ts +0 -101
- package/src/widgets/__testdata__/passage.testdata.ts +0 -95
- package/src/widgets/__testdata__/plotter.testdata.ts +0 -36
- package/src/widgets/__testdata__/radio.testdata.ts +0 -324
- package/src/widgets/__testdata__/randomizers.ts +0 -51
- package/src/widgets/__testdata__/sorter.testdata.ts +0 -19
- package/src/widgets/__testdata__/video.testdata.ts +0 -61
- package/src/widgets/__tests__/__snapshots__/categorizer.test.ts.snap +0 -940
- package/src/widgets/__tests__/__snapshots__/cs-program.test.ts.snap +0 -67
- package/src/widgets/__tests__/__snapshots__/definition.test.ts.snap +0 -97
- package/src/widgets/__tests__/__snapshots__/dropdown.test.ts.snap +0 -133
- package/src/widgets/__tests__/__snapshots__/explanation.test.ts.snap +0 -425
- package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt.test.ts.snap +0 -729
- package/src/widgets/__tests__/__snapshots__/graded-group-set.test.ts.snap +0 -339
- package/src/widgets/__tests__/__snapshots__/graded-group.test.ts.snap +0 -801
- package/src/widgets/__tests__/__snapshots__/grapher.test.ts.snap +0 -2673
- package/src/widgets/__tests__/__snapshots__/group.test.tsx.snap +0 -1211
- package/src/widgets/__tests__/__snapshots__/iframe.test.ts.snap +0 -61
- package/src/widgets/__tests__/__snapshots__/image.test.ts.snap +0 -378
- package/src/widgets/__tests__/__snapshots__/input-number.test.ts.snap +0 -495
- package/src/widgets/__tests__/__snapshots__/interaction.test.ts.snap +0 -292
- package/src/widgets/__tests__/__snapshots__/interactive-graph.test.ts.snap +0 -2889
- package/src/widgets/__tests__/__snapshots__/matcher.test.tsx.snap +0 -883
- package/src/widgets/__tests__/__snapshots__/matrix.test.ts.snap +0 -514
- package/src/widgets/__tests__/__snapshots__/number-line.test.ts.snap +0 -814
- package/src/widgets/__tests__/__snapshots__/numeric-input.test.ts.snap +0 -470
- package/src/widgets/__tests__/__snapshots__/orderer.test.ts.snap +0 -243
- package/src/widgets/__tests__/__snapshots__/passage-ref.test.ts.snap +0 -434
- package/src/widgets/__tests__/__snapshots__/passage.test.tsx.snap +0 -1956
- package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +0 -827
- package/src/widgets/__tests__/__snapshots__/radio.test.ts.snap +0 -4237
- package/src/widgets/__tests__/__snapshots__/unit.test.tsx.snap +0 -20
- package/src/widgets/__tests__/__snapshots__/video.test.ts.snap +0 -153
- package/src/widgets/__tests__/categorizer.test.ts +0 -203
- package/src/widgets/__tests__/cs-program.test.ts +0 -43
- package/src/widgets/__tests__/definition.test.ts +0 -136
- package/src/widgets/__tests__/dropdown.test.ts +0 -105
- package/src/widgets/__tests__/explanation.test.ts +0 -198
- package/src/widgets/__tests__/expression-mobile.test.tsx +0 -363
- package/src/widgets/__tests__/expression.test.tsx +0 -484
- package/src/widgets/__tests__/graded-group-set-jipt.test.ts +0 -30
- package/src/widgets/__tests__/graded-group-set.test.ts +0 -288
- package/src/widgets/__tests__/graded-group.test.ts +0 -232
- package/src/widgets/__tests__/grapher.cypress.ts +0 -576
- package/src/widgets/__tests__/grapher.test.ts +0 -33
- package/src/widgets/__tests__/group.test.tsx +0 -510
- package/src/widgets/__tests__/iframe.test.ts +0 -45
- package/src/widgets/__tests__/image.test.ts +0 -62
- package/src/widgets/__tests__/input-number.test.ts +0 -354
- package/src/widgets/__tests__/interaction.test.ts +0 -31
- package/src/widgets/__tests__/interactive-graph.cypress.ts +0 -815
- package/src/widgets/__tests__/interactive-graph.test.ts +0 -106
- package/src/widgets/__tests__/matcher.test.tsx +0 -176
- package/src/widgets/__tests__/matrix.test.ts +0 -82
- package/src/widgets/__tests__/number-line.test.ts +0 -79
- package/src/widgets/__tests__/numeric-input.test.ts +0 -575
- package/src/widgets/__tests__/orderer.test.ts +0 -73
- package/src/widgets/__tests__/passage-ref.test.ts +0 -168
- package/src/widgets/__tests__/passage.test.tsx +0 -224
- package/src/widgets/__tests__/plotter.test.tsx +0 -69
- package/src/widgets/__tests__/radio/base-radio.test.tsx +0 -470
- package/src/widgets/__tests__/radio/choice-icon.test.tsx +0 -90
- package/src/widgets/__tests__/radio/choice.test.tsx +0 -310
- package/src/widgets/__tests__/radio/focus-ring.test.tsx +0 -22
- package/src/widgets/__tests__/radio/option-status.test.tsx +0 -77
- package/src/widgets/__tests__/radio.test.ts +0 -807
- package/src/widgets/__tests__/randomizers.test.ts +0 -53
- package/src/widgets/__tests__/renderQuestion.tsx +0 -101
- package/src/widgets/__tests__/unit.test.tsx +0 -168
- package/src/widgets/__tests__/video.test.ts +0 -69
- package/src/widgets/categorizer.tsx +0 -344
- package/src/widgets/cs-program.tsx +0 -227
- package/src/widgets/definition.tsx +0 -121
- package/src/widgets/deprecated-standin/__stories__/deprecated-standin.stories.tsx +0 -30
- package/src/widgets/deprecated-standin/__tests__/__snapshots__/deprecated-standin.test.ts.snap +0 -70
- package/src/widgets/deprecated-standin/__tests__/deprecated-standin.test.ts +0 -93
- package/src/widgets/deprecated-standin/index.tsx +0 -58
- package/src/widgets/dropdown.tsx +0 -142
- package/src/widgets/explanation.tsx +0 -317
- package/src/widgets/expression.tsx +0 -707
- package/src/widgets/graded-group-answer-bar.tsx +0 -142
- package/src/widgets/graded-group-set.tsx +0 -338
- package/src/widgets/graded-group.tsx +0 -471
- package/src/widgets/grapher/util.tsx +0 -799
- package/src/widgets/grapher.tsx +0 -660
- package/src/widgets/group.tsx +0 -195
- package/src/widgets/iframe.tsx +0 -195
- package/src/widgets/image.tsx +0 -312
- package/src/widgets/input-number.tsx +0 -412
- package/src/widgets/interaction/arrow-picker.tsx +0 -38
- package/src/widgets/interaction/color-picker.tsx +0 -69
- package/src/widgets/interaction/dash-picker.tsx +0 -45
- package/src/widgets/interaction/element-container.tsx +0 -100
- package/src/widgets/interaction.tsx +0 -826
- package/src/widgets/interactive-graph.tsx +0 -2597
- package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -91
- package/src/widgets/label-image/__stories__/answer-pill.stories.tsx +0 -62
- package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -171
- package/src/widgets/label-image/__tests__/answer-pill.test.tsx +0 -75
- package/src/widgets/label-image/__tests__/hide-answers-toggle.test.tsx +0 -39
- package/src/widgets/label-image/answer-choices.tsx +0 -88
- package/src/widgets/label-image/answer-pill.tsx +0 -103
- package/src/widgets/label-image/hide-answers-toggle.tsx +0 -40
- package/src/widgets/label-image/marker.tsx +0 -268
- package/src/widgets/label-image/strings.ts +0 -5
- package/src/widgets/label-image/types.ts +0 -27
- package/src/widgets/label-image.test.ts +0 -928
- package/src/widgets/label-image.tsx +0 -819
- package/src/widgets/lights-puzzle.tsx +0 -359
- package/src/widgets/matcher.tsx +0 -298
- package/src/widgets/matrix.tsx +0 -634
- package/src/widgets/measurer.tsx +0 -222
- package/src/widgets/molecule/__tests__/layout.test.ts +0 -162
- package/src/widgets/molecule/__tests__/parser.test.ts +0 -155
- package/src/widgets/molecule/molecule-drawing.ts +0 -173
- package/src/widgets/molecule/molecule-layout.ts +0 -362
- package/src/widgets/molecule/smiles-parser.ts +0 -296
- package/src/widgets/molecule.tsx +0 -172
- package/src/widgets/number-line.tsx +0 -862
- package/src/widgets/numeric-input.tsx +0 -576
- package/src/widgets/orderer.tsx +0 -786
- package/src/widgets/passage/__tests__/passage-markdown.test.ts +0 -376
- package/src/widgets/passage/passage-markdown.tsx +0 -475
- package/src/widgets/passage-ref-target.tsx +0 -76
- package/src/widgets/passage-ref.tsx +0 -213
- package/src/widgets/passage.tsx +0 -582
- package/src/widgets/plotter.tsx +0 -1194
- package/src/widgets/radio/__stories__/base-radio.stories.tsx +0 -196
- package/src/widgets/radio/__stories__/choice-icon.stories.tsx +0 -166
- package/src/widgets/radio/__stories__/choice-none-above.stories.tsx +0 -40
- package/src/widgets/radio/__stories__/choice.stories.tsx +0 -137
- package/src/widgets/radio/__stories__/focus-ring.stories.tsx +0 -43
- package/src/widgets/radio/__stories__/option-status.stories.tsx +0 -103
- package/src/widgets/radio/base-radio.tsx +0 -511
- package/src/widgets/radio/choice-a11y-text.ts +0 -61
- package/src/widgets/radio/choice-icon/choice-icon.tsx +0 -218
- package/src/widgets/radio/choice-icon/cross-out-line.tsx +0 -51
- package/src/widgets/radio/choice-icon/shared-styles.ts +0 -15
- package/src/widgets/radio/choice-none-above.tsx +0 -56
- package/src/widgets/radio/choice.jsx.fixture.ts +0 -45
- package/src/widgets/radio/choice.tsx +0 -359
- package/src/widgets/radio/focus-ring.tsx +0 -57
- package/src/widgets/radio/option-status.tsx +0 -98
- package/src/widgets/radio/util.test.ts +0 -18
- package/src/widgets/radio/util.ts +0 -31
- package/src/widgets/radio/widget.tsx +0 -520
- package/src/widgets/radio.ts +0 -157
- package/src/widgets/reaction-diagram.tsx +0 -144
- package/src/widgets/sequence.tsx +0 -142
- package/src/widgets/simulator.tsx +0 -829
- package/src/widgets/sorter.tsx +0 -155
- package/src/widgets/table.tsx +0 -393
- package/src/widgets/unit.tsx +0 -374
- package/src/widgets/video-transcript-link.test.tsx +0 -213
- package/src/widgets/video-transcript-link.tsx +0 -84
- package/src/widgets/video.tsx +0 -135
- package/src/widgets.ts +0 -489
- package/src/zoom.ts +0 -555
- package/tsconfig-build.json +0 -26
- package/tsconfig-build.tsbuildinfo +0 -1
package/src/util.ts
DELETED
|
@@ -1,966 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @babel/no-invalid-this, getter-return, one-var */
|
|
2
|
-
import _ from "underscore";
|
|
3
|
-
|
|
4
|
-
import {Errors} from "./logging/log";
|
|
5
|
-
import {PerseusError} from "./perseus-error";
|
|
6
|
-
import KhanAnswerTypes from "./util/answer-types";
|
|
7
|
-
import * as GraphieUtil from "./util.graphie";
|
|
8
|
-
|
|
9
|
-
import type {Range} from "./perseus-types";
|
|
10
|
-
import type {Widget, PerseusScore} from "./types";
|
|
11
|
-
import type {KEScore} from "@khanacademy/perseus-core";
|
|
12
|
-
|
|
13
|
-
type WordPosition = {
|
|
14
|
-
start: number;
|
|
15
|
-
end: number;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type WordAndPosition = {
|
|
19
|
-
string: string;
|
|
20
|
-
pos: WordPosition;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
type RNG = () => number;
|
|
24
|
-
|
|
25
|
-
export type ParsedValue = {
|
|
26
|
-
value: number;
|
|
27
|
-
exact: boolean;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// TODO: dedupe this with Coord in interactive2/types.js
|
|
31
|
-
type Coordinates = [number, number];
|
|
32
|
-
|
|
33
|
-
export type GridDimensions = {
|
|
34
|
-
scale: number;
|
|
35
|
-
tickStep: number;
|
|
36
|
-
unityLabel: boolean;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type QueryParams = {
|
|
40
|
-
[param: string]: string;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export type Position = {
|
|
44
|
-
top: number;
|
|
45
|
-
left: number;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
type TouchHandlers = {
|
|
49
|
-
pointerDown: boolean;
|
|
50
|
-
currentTouchIdentifier: string | null | undefined;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
let supportsPassive = false;
|
|
54
|
-
|
|
55
|
-
const nestedMap = function <T, M>(
|
|
56
|
-
children: T | ReadonlyArray<T>,
|
|
57
|
-
func: (arg1: T) => M,
|
|
58
|
-
context: unknown,
|
|
59
|
-
): M | ReadonlyArray<M> {
|
|
60
|
-
if (Array.isArray(children)) {
|
|
61
|
-
// @ts-expect-error - TS2322 - Type '(M | readonly M[])[]' is not assignable to type 'M | readonly M[]'.
|
|
62
|
-
return _.map(children, function (child) {
|
|
63
|
-
// @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
|
|
64
|
-
return nestedMap(child, func);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
return func.call(context, children);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Used to compare equality of two input paths, which are represented as
|
|
72
|
-
* arrays of strings.
|
|
73
|
-
*/
|
|
74
|
-
function inputPathsEqual(
|
|
75
|
-
a?: ReadonlyArray<string> | null,
|
|
76
|
-
b?: ReadonlyArray<string> | null,
|
|
77
|
-
): boolean {
|
|
78
|
-
if (a == null || b == null) {
|
|
79
|
-
return (a == null) === (b == null);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
a.length === b.length &&
|
|
84
|
-
a.every((item, index) => {
|
|
85
|
-
return b[index] === item;
|
|
86
|
-
})
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
|
|
91
|
-
const rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
|
|
92
|
-
|
|
93
|
-
const rWidgetParts = new RegExp(rWidgetRule.source + "$");
|
|
94
|
-
const snowman = "\u2603";
|
|
95
|
-
const noScore: PerseusScore = {
|
|
96
|
-
type: "points",
|
|
97
|
-
earned: 0,
|
|
98
|
-
total: 0,
|
|
99
|
-
message: null,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const seededRNG: (seed: number) => RNG = function (seed: number): RNG {
|
|
103
|
-
let randomSeed = seed;
|
|
104
|
-
|
|
105
|
-
return function () {
|
|
106
|
-
// Robert Jenkins' 32 bit integer hash function.
|
|
107
|
-
let seed = randomSeed;
|
|
108
|
-
seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff;
|
|
109
|
-
seed = (seed ^ 0xc761c23c ^ (seed >>> 19)) & 0xffffffff;
|
|
110
|
-
seed = (seed + 0x165667b1 + (seed << 5)) & 0xffffffff;
|
|
111
|
-
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
|
|
112
|
-
seed = (seed + 0xfd7046c5 + (seed << 3)) & 0xffffffff;
|
|
113
|
-
seed = (seed ^ 0xb55a4f09 ^ (seed >>> 16)) & 0xffffffff;
|
|
114
|
-
return (randomSeed = seed & 0xfffffff) / 0x10000000;
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// Shuffle an array using a given random seed or function.
|
|
119
|
-
// If `ensurePermuted` is true, the input and ouput are guaranteed to be
|
|
120
|
-
// distinct permutations.
|
|
121
|
-
function shuffle<T>(
|
|
122
|
-
array: ReadonlyArray<T>,
|
|
123
|
-
randomSeed: number | RNG,
|
|
124
|
-
ensurePermuted = false,
|
|
125
|
-
): ReadonlyArray<T> {
|
|
126
|
-
// Always return a copy of the input array
|
|
127
|
-
const shuffled = _.clone(array);
|
|
128
|
-
|
|
129
|
-
// Handle edge cases (input array is empty or uniform)
|
|
130
|
-
if (
|
|
131
|
-
!shuffled.length ||
|
|
132
|
-
_.all(shuffled, function (value) {
|
|
133
|
-
return _.isEqual(value, shuffled[0]);
|
|
134
|
-
})
|
|
135
|
-
) {
|
|
136
|
-
return shuffled;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
let random;
|
|
140
|
-
if (typeof randomSeed === "function") {
|
|
141
|
-
random = randomSeed;
|
|
142
|
-
} else {
|
|
143
|
-
random = seededRNG(randomSeed);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
do {
|
|
147
|
-
// Fischer-Yates shuffle
|
|
148
|
-
for (let top = shuffled.length; top > 0; top--) {
|
|
149
|
-
const newEnd = Math.floor(random() * top),
|
|
150
|
-
temp = shuffled[newEnd];
|
|
151
|
-
|
|
152
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
153
|
-
shuffled[newEnd] = shuffled[top - 1];
|
|
154
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
155
|
-
shuffled[top - 1] = temp;
|
|
156
|
-
}
|
|
157
|
-
} while (ensurePermuted && _.isEqual(array, shuffled));
|
|
158
|
-
|
|
159
|
-
return shuffled;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* TODO(somewhatabstract, FEI-3463):
|
|
164
|
-
* Drop this custom split thing.
|
|
165
|
-
*/
|
|
166
|
-
// In IE8, split doesn't work right. Implement it ourselves.
|
|
167
|
-
const split: (str: string, r: RegExp) => ReadonlyArray<string> = "x".split(
|
|
168
|
-
/(.)/g,
|
|
169
|
-
).length
|
|
170
|
-
? function (str: string, r) {
|
|
171
|
-
return str.split(r);
|
|
172
|
-
}
|
|
173
|
-
: function (str: string, r: RegExp) {
|
|
174
|
-
// Based on Steven Levithan's MIT-licensed split, available at
|
|
175
|
-
// http://blog.stevenlevithan.com/archives/cross-browser-split
|
|
176
|
-
const output = [];
|
|
177
|
-
let lastIndex = (r.lastIndex = 0);
|
|
178
|
-
let match;
|
|
179
|
-
|
|
180
|
-
while ((match = r.exec(str))) {
|
|
181
|
-
const m = match;
|
|
182
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
|
|
183
|
-
output.push(str.slice(lastIndex, m.index));
|
|
184
|
-
// @ts-expect-error - TS2345 - Argument of type 'any' is not assignable to parameter of type 'never'.
|
|
185
|
-
output.push(...m.slice(1));
|
|
186
|
-
lastIndex = m.index + m[0].length;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
|
|
190
|
-
output.push(str.slice(lastIndex));
|
|
191
|
-
return output;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Combine two score objects.
|
|
196
|
-
*
|
|
197
|
-
* Given two score objects for two different widgets, combine them so that
|
|
198
|
-
* if one is wrong, the total score is wrong, etc.
|
|
199
|
-
*/
|
|
200
|
-
function combineScores(
|
|
201
|
-
scoreA: PerseusScore,
|
|
202
|
-
scoreB: PerseusScore,
|
|
203
|
-
): PerseusScore {
|
|
204
|
-
let message;
|
|
205
|
-
|
|
206
|
-
if (scoreA.type === "points" && scoreB.type === "points") {
|
|
207
|
-
if (
|
|
208
|
-
scoreA.message &&
|
|
209
|
-
scoreB.message &&
|
|
210
|
-
scoreA.message !== scoreB.message
|
|
211
|
-
) {
|
|
212
|
-
// TODO(alpert): Figure out how to combine messages usefully
|
|
213
|
-
message = null;
|
|
214
|
-
} else {
|
|
215
|
-
message = scoreA.message || scoreB.message;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
type: "points",
|
|
220
|
-
earned: scoreA.earned + scoreB.earned,
|
|
221
|
-
total: scoreA.total + scoreB.total,
|
|
222
|
-
message: message,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
if (scoreA.type === "points" && scoreB.type === "invalid") {
|
|
226
|
-
return scoreB;
|
|
227
|
-
}
|
|
228
|
-
if (scoreA.type === "invalid" && scoreB.type === "points") {
|
|
229
|
-
return scoreA;
|
|
230
|
-
}
|
|
231
|
-
if (scoreA.type === "invalid" && scoreB.type === "invalid") {
|
|
232
|
-
if (
|
|
233
|
-
scoreA.message &&
|
|
234
|
-
scoreB.message &&
|
|
235
|
-
scoreA.message !== scoreB.message
|
|
236
|
-
) {
|
|
237
|
-
// TODO(alpert): Figure out how to combine messages usefully
|
|
238
|
-
message = null;
|
|
239
|
-
} else {
|
|
240
|
-
message = scoreA.message || scoreB.message;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
type: "invalid",
|
|
245
|
-
message: message,
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* The above checks cover all combinations of score type, so if we get here
|
|
251
|
-
* then something is amiss with our inputs.
|
|
252
|
-
*/
|
|
253
|
-
throw new PerseusError(
|
|
254
|
-
"PerseusScore with unknown type encountered",
|
|
255
|
-
Errors.InvalidInput,
|
|
256
|
-
{
|
|
257
|
-
metadata: {
|
|
258
|
-
scoreA: JSON.stringify(scoreA),
|
|
259
|
-
scoreB: JSON.stringify(scoreB),
|
|
260
|
-
},
|
|
261
|
-
},
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function keScoreFromPerseusScore(
|
|
266
|
-
score: PerseusScore,
|
|
267
|
-
guess: any,
|
|
268
|
-
state: any,
|
|
269
|
-
): KEScore {
|
|
270
|
-
if (score.type === "points") {
|
|
271
|
-
return {
|
|
272
|
-
empty: false,
|
|
273
|
-
correct: score.earned >= score.total,
|
|
274
|
-
message: score.message,
|
|
275
|
-
guess: guess,
|
|
276
|
-
state: state,
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
if (score.type === "invalid") {
|
|
280
|
-
return {
|
|
281
|
-
empty: true,
|
|
282
|
-
correct: false,
|
|
283
|
-
message: score.message,
|
|
284
|
-
suppressAlmostThere: score.suppressAlmostThere,
|
|
285
|
-
guess: guess,
|
|
286
|
-
state: state,
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
throw new PerseusError(
|
|
290
|
-
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
291
|
-
"Invalid score type: " + score.type,
|
|
292
|
-
Errors.InvalidInput,
|
|
293
|
-
{
|
|
294
|
-
metadata: {
|
|
295
|
-
score: JSON.stringify(score),
|
|
296
|
-
guess: JSON.stringify(guess),
|
|
297
|
-
state: JSON.stringify(state),
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Return the first valid interpretation of 'text' as a number, in the form
|
|
305
|
-
* {value: 2.3, exact: true}.
|
|
306
|
-
*/
|
|
307
|
-
function firstNumericalParse(text: string): ParsedValue | null | undefined {
|
|
308
|
-
// TODO(alpert): This is sort of hacky...
|
|
309
|
-
let first;
|
|
310
|
-
const val = KhanAnswerTypes.predicate.createValidatorFunctional(
|
|
311
|
-
function (ans) {
|
|
312
|
-
first = ans;
|
|
313
|
-
return true; /* break */
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
simplify: "optional",
|
|
317
|
-
inexact: true,
|
|
318
|
-
forms: "integer, proper, improper, pi, log, mixed, decimal",
|
|
319
|
-
},
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
val(text);
|
|
323
|
-
return first;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function stringArrayOfSize(size: number): ReadonlyArray<string> {
|
|
327
|
-
return _(size).times(function () {
|
|
328
|
-
return "";
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* For a graph's x or y dimension, given the tick step,
|
|
334
|
-
* the ranges extent (e.g. [-10, 10]), the pixel dimension constraint,
|
|
335
|
-
* and the grid step, return a bunch of configurations for that dimension.
|
|
336
|
-
*
|
|
337
|
-
* Example:
|
|
338
|
-
* gridDimensionConfig(10, [-50, 50], 400, 5)
|
|
339
|
-
*
|
|
340
|
-
* Returns: {
|
|
341
|
-
* scale: 4,
|
|
342
|
-
* snap: 2.5,
|
|
343
|
-
* tickStep: 2,
|
|
344
|
-
* unityLabel: true
|
|
345
|
-
* };
|
|
346
|
-
*/
|
|
347
|
-
function gridDimensionConfig(
|
|
348
|
-
absTickStep: number,
|
|
349
|
-
extent: Coordinates,
|
|
350
|
-
dimensionConstraint: number,
|
|
351
|
-
gridStep: number,
|
|
352
|
-
): GridDimensions {
|
|
353
|
-
const scale = scaleFromExtent(extent, dimensionConstraint);
|
|
354
|
-
const stepPx = absTickStep * scale;
|
|
355
|
-
const unityLabel = stepPx > 30;
|
|
356
|
-
return {
|
|
357
|
-
scale: scale,
|
|
358
|
-
tickStep: absTickStep / gridStep,
|
|
359
|
-
unityLabel: unityLabel,
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Given the range, step, and boxSize, calculate the reasonable gridStep.
|
|
364
|
-
* Used for when one was not given explicitly.
|
|
365
|
-
*
|
|
366
|
-
* Example:
|
|
367
|
-
* getGridStep([[-10, 10], [-10, 10]], [1, 1], 340)
|
|
368
|
-
*
|
|
369
|
-
* Returns: [1, 1]
|
|
370
|
-
*
|
|
371
|
-
* TODO(somewhatabstract, FEI-3464): Consolidate query string parsing functions.
|
|
372
|
-
*/
|
|
373
|
-
function getGridStep(
|
|
374
|
-
range: [Coordinates, Coordinates],
|
|
375
|
-
step: Coordinates,
|
|
376
|
-
boxSize: number,
|
|
377
|
-
): Coordinates {
|
|
378
|
-
// @ts-expect-error - TS2322 - Type '(number | null | undefined)[]' is not assignable to type 'Coordinates'.
|
|
379
|
-
return _(2).times(function (i) {
|
|
380
|
-
const scale = scaleFromExtent(range[i], boxSize);
|
|
381
|
-
const gridStep = gridStepFromTickStep(step[i], scale);
|
|
382
|
-
return gridStep;
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function snapStepFromGridStep(gridStep: [number, number]): [number, number] {
|
|
387
|
-
return [gridStep[0] / 2, gridStep[1] / 2];
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Given the tickStep and the graph's scale, find a
|
|
392
|
-
* grid step.
|
|
393
|
-
* Example:
|
|
394
|
-
* gridStepFromTickStep(200, 0.2) // returns 100
|
|
395
|
-
*/
|
|
396
|
-
function gridStepFromTickStep(
|
|
397
|
-
tickStep: number,
|
|
398
|
-
scale: number,
|
|
399
|
-
): number | null | undefined {
|
|
400
|
-
const tickWidth = tickStep * scale;
|
|
401
|
-
const x = tickStep;
|
|
402
|
-
const y = Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
|
|
403
|
-
const leadingDigit = Math.floor(x / y);
|
|
404
|
-
if (tickWidth < 25) {
|
|
405
|
-
return tickStep;
|
|
406
|
-
}
|
|
407
|
-
if (tickWidth < 50) {
|
|
408
|
-
if (leadingDigit === 5) {
|
|
409
|
-
return tickStep;
|
|
410
|
-
}
|
|
411
|
-
return tickStep / 2;
|
|
412
|
-
}
|
|
413
|
-
if (leadingDigit === 1) {
|
|
414
|
-
return tickStep / 2;
|
|
415
|
-
}
|
|
416
|
-
if (leadingDigit === 2) {
|
|
417
|
-
return tickStep / 4;
|
|
418
|
-
}
|
|
419
|
-
if (leadingDigit === 5) {
|
|
420
|
-
return tickStep / 5;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Given the range and a dimension, come up with the appropriate
|
|
426
|
-
* scale.
|
|
427
|
-
* Example:
|
|
428
|
-
* scaleFromExtent([-25, 25], 500) // returns 10
|
|
429
|
-
*/
|
|
430
|
-
function scaleFromExtent(
|
|
431
|
-
extent: Coordinates,
|
|
432
|
-
dimensionConstraint: number,
|
|
433
|
-
): number {
|
|
434
|
-
const span = extent[1] - extent[0];
|
|
435
|
-
const scale = dimensionConstraint / span;
|
|
436
|
-
return scale;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Return a reasonable tick step given extent and dimension.
|
|
441
|
-
* (extent is [begin, end] of the domain.)
|
|
442
|
-
* Example:
|
|
443
|
-
* tickStepFromExtent([-10, 10], 300) // returns 2
|
|
444
|
-
*/
|
|
445
|
-
function tickStepFromExtent(
|
|
446
|
-
extent: Coordinates,
|
|
447
|
-
dimensionConstraint: number,
|
|
448
|
-
): number {
|
|
449
|
-
const span = extent[1] - extent[0];
|
|
450
|
-
|
|
451
|
-
let tickFactor;
|
|
452
|
-
// If single number digits
|
|
453
|
-
if (15 < span && span <= 20) {
|
|
454
|
-
tickFactor = 23;
|
|
455
|
-
|
|
456
|
-
// triple digit or decimal
|
|
457
|
-
} else if (span > 100 || span < 5) {
|
|
458
|
-
tickFactor = 10;
|
|
459
|
-
|
|
460
|
-
// double digit
|
|
461
|
-
} else {
|
|
462
|
-
tickFactor = 16;
|
|
463
|
-
}
|
|
464
|
-
const constraintFactor = dimensionConstraint / 500;
|
|
465
|
-
const desiredNumTicks = tickFactor * constraintFactor;
|
|
466
|
-
return tickStepFromNumTicks(span, desiredNumTicks);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Find a good tick step for the desired number of ticks in the range
|
|
471
|
-
* Modified from d3.scale.linear: d3_scale_linearTickRange.
|
|
472
|
-
* Thanks, mbostock!
|
|
473
|
-
* Example:
|
|
474
|
-
* tickStepFromNumTicks(50, 6) // returns 10
|
|
475
|
-
*/
|
|
476
|
-
function tickStepFromNumTicks(span: number, numTicks: number): number {
|
|
477
|
-
let step = Math.pow(10, Math.floor(Math.log(span / numTicks) / Math.LN10));
|
|
478
|
-
const err = (numTicks / span) * step;
|
|
479
|
-
|
|
480
|
-
// Filter ticks to get closer to the desired count.
|
|
481
|
-
if (err <= 0.15) {
|
|
482
|
-
step *= 10;
|
|
483
|
-
} else if (err <= 0.35) {
|
|
484
|
-
step *= 5;
|
|
485
|
-
} else if (err <= 0.75) {
|
|
486
|
-
step *= 2;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Round start and stop values to step interval.
|
|
490
|
-
return step;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
const constrainTickStep = (step: number, range: Range): number => {
|
|
494
|
-
const span = range[1] - range[0];
|
|
495
|
-
const numTicks = span / step;
|
|
496
|
-
if (numTicks <= 10) {
|
|
497
|
-
// Will displays fine on mobile
|
|
498
|
-
return step;
|
|
499
|
-
}
|
|
500
|
-
if (numTicks <= 20) {
|
|
501
|
-
// Will be crowded on mobile, so hide every other tick
|
|
502
|
-
return step * 2;
|
|
503
|
-
}
|
|
504
|
-
// Fallback in case we somehow have more than 20 ticks
|
|
505
|
-
// Note: This shouldn't happen due to GraphSettings.validStep
|
|
506
|
-
return tickStepFromNumTicks(span, 10);
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Constrain tick steps intended for desktop size graphs
|
|
511
|
-
* to something more suitable for mobile size graphs.
|
|
512
|
-
* Specifically, we aim for 10 or fewer ticks per graph axis.
|
|
513
|
-
*/
|
|
514
|
-
function constrainedTickStepsFromTickSteps(
|
|
515
|
-
tickSteps: [number, number],
|
|
516
|
-
ranges: [Range, Range],
|
|
517
|
-
): Coordinates {
|
|
518
|
-
return [
|
|
519
|
-
constrainTickStep(tickSteps[0], ranges[0]),
|
|
520
|
-
constrainTickStep(tickSteps[1], ranges[1]),
|
|
521
|
-
];
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Transparently update deprecated props so that the code to deal
|
|
526
|
-
* with them only lives in one place: (Widget).deprecatedProps
|
|
527
|
-
*
|
|
528
|
-
* For example, if a boolean `foo` was deprecated in favor of a
|
|
529
|
-
* number 'bar':
|
|
530
|
-
* deprecatedProps: {
|
|
531
|
-
* foo: function(props) {
|
|
532
|
-
* return {bar: props.foo ? 1 : 0};
|
|
533
|
-
* }
|
|
534
|
-
* }
|
|
535
|
-
*/
|
|
536
|
-
const DeprecationMixin: any = {
|
|
537
|
-
// This lifecycle stage is only called before first render
|
|
538
|
-
// TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
|
|
539
|
-
UNSAFE_componentWillMount: function () {
|
|
540
|
-
const newProps: Record<string, any> = {};
|
|
541
|
-
|
|
542
|
-
_.each(
|
|
543
|
-
this.deprecatedProps,
|
|
544
|
-
function (func, prop) {
|
|
545
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
546
|
-
if (_.has(this.props, prop)) {
|
|
547
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
548
|
-
_.extend(newProps, func(this.props));
|
|
549
|
-
}
|
|
550
|
-
},
|
|
551
|
-
this,
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
if (!_.isEmpty(newProps)) {
|
|
555
|
-
// Set new props directly so that widget renders correctly
|
|
556
|
-
// when it first mounts, even though these will be overwritten
|
|
557
|
-
// almost immediately afterwards...
|
|
558
|
-
_.extend(this.props, newProps);
|
|
559
|
-
|
|
560
|
-
// ...when we propagate the new props upwards and they come
|
|
561
|
-
// back down again.
|
|
562
|
-
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API
|
|
563
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
564
|
-
setTimeout(this.props.onChange, 0, newProps);
|
|
565
|
-
}
|
|
566
|
-
},
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* Approximate equality on numbers and primitives.
|
|
571
|
-
*/
|
|
572
|
-
function eq<T>(x: T, y: T): boolean {
|
|
573
|
-
if (typeof x === "number" && typeof y === "number") {
|
|
574
|
-
return Math.abs(x - y) < 1e-9;
|
|
575
|
-
}
|
|
576
|
-
return x === y;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Deep approximate equality on primitives, numbers, arrays, and objects.
|
|
581
|
-
* Recursive.
|
|
582
|
-
*/
|
|
583
|
-
function deepEq<T>(x: T, y: T): boolean {
|
|
584
|
-
if (Array.isArray(x) && Array.isArray(y)) {
|
|
585
|
-
if (x.length !== y.length) {
|
|
586
|
-
return false;
|
|
587
|
-
}
|
|
588
|
-
for (let i = 0; i < x.length; i++) {
|
|
589
|
-
if (!deepEq(x[i], y[i])) {
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
return true;
|
|
594
|
-
}
|
|
595
|
-
if (Array.isArray(x) || Array.isArray(y)) {
|
|
596
|
-
return false;
|
|
597
|
-
}
|
|
598
|
-
if (typeof x === "function" && typeof y === "function") {
|
|
599
|
-
return eq(x, y);
|
|
600
|
-
}
|
|
601
|
-
if (typeof x === "function" || typeof y === "function") {
|
|
602
|
-
return false;
|
|
603
|
-
}
|
|
604
|
-
if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
|
|
605
|
-
return (
|
|
606
|
-
x === y ||
|
|
607
|
-
(_.all(x, function (v, k) {
|
|
608
|
-
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
609
|
-
return deepEq(y[k], v);
|
|
610
|
-
}) &&
|
|
611
|
-
_.all(y, function (v, k) {
|
|
612
|
-
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
613
|
-
return deepEq(x[k], v);
|
|
614
|
-
}))
|
|
615
|
-
);
|
|
616
|
-
}
|
|
617
|
-
if ((typeof x === "object" && !!x) || (typeof y === "object" && !!y)) {
|
|
618
|
-
return false;
|
|
619
|
-
}
|
|
620
|
-
return eq(x, y);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* Query String Parser
|
|
625
|
-
*
|
|
626
|
-
* Original from:
|
|
627
|
-
* http://stackoverflow.com/questions/901115/get-querystring-values-in-javascript/2880929#2880929
|
|
628
|
-
*/
|
|
629
|
-
function parseQueryString(query: string): QueryParams {
|
|
630
|
-
// TODO(jangmi, CP-3340): Use withLocation to access SSR safe location.
|
|
631
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
632
|
-
query = query || window.location.search.substring(1);
|
|
633
|
-
const urlParams: Record<string, any> = {};
|
|
634
|
-
// Regex for replacing addition symbol with a space
|
|
635
|
-
const a = /\+/g;
|
|
636
|
-
const r = /([^&=]+)=?([^&]*)/g;
|
|
637
|
-
const d = function (s) {
|
|
638
|
-
return decodeURIComponent(s.replace(a, " "));
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
let e;
|
|
642
|
-
while ((e = r.exec(query))) {
|
|
643
|
-
const m = e;
|
|
644
|
-
urlParams[d(m[1])] = d(m[2]);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return urlParams;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* Query string adder
|
|
652
|
-
* Works for URLs without #.
|
|
653
|
-
* Original from:
|
|
654
|
-
* http://stackoverflow.com/questions/5999118/add-or-update-query-string-parameter
|
|
655
|
-
*/
|
|
656
|
-
function updateQueryString(uri: string, key: string, value: string): string {
|
|
657
|
-
value = encodeURIComponent(value);
|
|
658
|
-
const re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
|
|
659
|
-
const separator = uri.indexOf("?") !== -1 ? "&" : "?";
|
|
660
|
-
if (uri.match(re)) {
|
|
661
|
-
return uri.replace(re, "$1" + key + "=" + value + "$2");
|
|
662
|
-
}
|
|
663
|
-
return uri + separator + key + "=" + value;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
/**
|
|
667
|
-
* A more strict encodeURIComponent that escapes `()'!`s
|
|
668
|
-
* Especially useful for creating URLs that are embeddable in markdown
|
|
669
|
-
*
|
|
670
|
-
* Adapted from
|
|
671
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
|
|
672
|
-
* This function and the above original available under the
|
|
673
|
-
* CC-BY-SA 2.5 license.
|
|
674
|
-
*/
|
|
675
|
-
function strongEncodeURIComponent(str: string): string {
|
|
676
|
-
return (
|
|
677
|
-
encodeURIComponent(str)
|
|
678
|
-
// Note that although RFC3986 reserves "!", RFC5987 does not,
|
|
679
|
-
// so we do not need to escape it
|
|
680
|
-
.replace(/['()!]/g, window.escape) // i.e., %27 %28 %29
|
|
681
|
-
.replace(/\*/g, "%2A")
|
|
682
|
-
);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* TODO(somewhatabstract, JIRA-XXXX):
|
|
687
|
-
* This does not appear to be used within webapp. Could be dead code.
|
|
688
|
-
* Need to check with mobile.
|
|
689
|
-
*/
|
|
690
|
-
// There are certain widgets where we don't want to provide the "answered"
|
|
691
|
-
// highlight indicator.
|
|
692
|
-
// The issue with just using the `graded` flag on questions is that showing
|
|
693
|
-
// that a certain widget is ungraded can sometimes reveal the answer to a
|
|
694
|
-
// question ("is this transformation possible? if so, do it")
|
|
695
|
-
// This is kind of a hack to get around this.
|
|
696
|
-
function widgetShouldHighlight(widget: Widget): boolean {
|
|
697
|
-
if (!widget) {
|
|
698
|
-
return false;
|
|
699
|
-
}
|
|
700
|
-
switch (widget.type) {
|
|
701
|
-
/**
|
|
702
|
-
* Highlight bar denylist
|
|
703
|
-
*/
|
|
704
|
-
case "measurer":
|
|
705
|
-
case "protractor":
|
|
706
|
-
return true;
|
|
707
|
-
|
|
708
|
-
default:
|
|
709
|
-
return false;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* If a widget says that it is empty once it is graded.
|
|
715
|
-
* Trying to encapsulate references to the score format.
|
|
716
|
-
*/
|
|
717
|
-
function scoreIsEmpty(score: PerseusScore): boolean {
|
|
718
|
-
// HACK(benkomalo): ugh. this isn't great; the Perseus score objects
|
|
719
|
-
// overload the type "invalid" for what should probably be three
|
|
720
|
-
// distinct cases:
|
|
721
|
-
// - truly empty or not fully filled out
|
|
722
|
-
// - invalid or malformed inputs
|
|
723
|
-
// - "almost correct" like inputs where the widget wants to give
|
|
724
|
-
// feedback (e.g. a fraction needs to be reduced, or `pi` should
|
|
725
|
-
// be used instead of 3.14)
|
|
726
|
-
//
|
|
727
|
-
// Unfortunately the coercion happens all over the place, as these
|
|
728
|
-
// Perseus style score objects are created *everywhere* (basically
|
|
729
|
-
// in every widget), so it's hard to change now. We assume that
|
|
730
|
-
// anything with a "message" is not truly empty, and one of the
|
|
731
|
-
// latter two cases for now.
|
|
732
|
-
return (
|
|
733
|
-
score.type === "invalid" &&
|
|
734
|
-
(!score.message || score.message.length === 0)
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/*
|
|
739
|
-
* The touchHandlers are used to track the current state of the touch
|
|
740
|
-
* event, such as whether or not the user is currently pressed down (either
|
|
741
|
-
* through touch or mouse) on the screen.
|
|
742
|
-
*/
|
|
743
|
-
const touchHandlers: TouchHandlers = {
|
|
744
|
-
pointerDown: false,
|
|
745
|
-
currentTouchIdentifier: null,
|
|
746
|
-
};
|
|
747
|
-
|
|
748
|
-
function resetTouchHandlers() {
|
|
749
|
-
Object.assign(touchHandlers, {
|
|
750
|
-
pointerDown: false,
|
|
751
|
-
currentTouchIdentifier: null,
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Extracts the location of a touch or mouse event, allowing you to pass
|
|
757
|
-
* in a "mouseup", "mousedown", or "mousemove" event and receive the
|
|
758
|
-
* correct coordinates. Shouldn't be used with "vmouse" events.
|
|
759
|
-
*/
|
|
760
|
-
function extractPointerLocation(event: any): Position | null | undefined {
|
|
761
|
-
let touchOrEvent;
|
|
762
|
-
|
|
763
|
-
if (touchHandlers.pointerDown) {
|
|
764
|
-
// Look for the touch matching the one we're tracking; ignore others
|
|
765
|
-
if (touchHandlers.currentTouchIdentifier != null) {
|
|
766
|
-
const len = event.changedTouches ? event.changedTouches.length : 0;
|
|
767
|
-
for (let i = 0; i < len; i++) {
|
|
768
|
-
if (
|
|
769
|
-
event.changedTouches[i].identifier ===
|
|
770
|
-
touchHandlers.currentTouchIdentifier
|
|
771
|
-
) {
|
|
772
|
-
touchOrEvent = event.changedTouches[i];
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
} else {
|
|
776
|
-
touchOrEvent = event;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
const isEndish =
|
|
780
|
-
event.type === "touchend" || event.type === "touchcancel";
|
|
781
|
-
if (touchOrEvent && isEndish) {
|
|
782
|
-
touchHandlers.pointerDown = false;
|
|
783
|
-
touchHandlers.currentTouchIdentifier = null;
|
|
784
|
-
}
|
|
785
|
-
} else {
|
|
786
|
-
// touchstart or mousedown
|
|
787
|
-
touchHandlers.pointerDown = true;
|
|
788
|
-
if (event.changedTouches) {
|
|
789
|
-
touchOrEvent = event.changedTouches[0];
|
|
790
|
-
touchHandlers.currentTouchIdentifier = touchOrEvent.identifier;
|
|
791
|
-
} else {
|
|
792
|
-
touchOrEvent = event;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
if (touchOrEvent) {
|
|
797
|
-
return {
|
|
798
|
-
left: touchOrEvent.pageX,
|
|
799
|
-
top: touchOrEvent.pageY,
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// Older browsers don't support passive events and so we need to feature-
|
|
805
|
-
// detect them and do event subscription differently for them.
|
|
806
|
-
// See: orderer.jsx
|
|
807
|
-
const supportsPassiveEvents: () => boolean = () => {
|
|
808
|
-
// Test via a getter in the options object to see if the passive
|
|
809
|
-
// property is accessed
|
|
810
|
-
try {
|
|
811
|
-
const opts = Object.defineProperty({}, "passive", {
|
|
812
|
-
get: function () {
|
|
813
|
-
supportsPassive = true;
|
|
814
|
-
},
|
|
815
|
-
});
|
|
816
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
817
|
-
window.addEventListener("testPassive", null, opts);
|
|
818
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
819
|
-
window.removeEventListener("testPassive", null, opts);
|
|
820
|
-
} catch (e: any) {
|
|
821
|
-
// Intentionally left empty!
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
return supportsPassive;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* Pass this function as the touchstart for an element to
|
|
829
|
-
* avoid sending the touch to the mobile scratchpad
|
|
830
|
-
*/
|
|
831
|
-
function captureScratchpadTouchStart(e: TouchEvent) {
|
|
832
|
-
e.stopPropagation();
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
function getImageSize(
|
|
836
|
-
url: string,
|
|
837
|
-
callback: (width: number, height: number) => void,
|
|
838
|
-
): void {
|
|
839
|
-
const img = new Image();
|
|
840
|
-
img.onload = function () {
|
|
841
|
-
// IE 11 seems to have problems calculating the heights of svgs
|
|
842
|
-
// if they're not in the DOM. To solve this, we add the element to
|
|
843
|
-
// the dom, wait for a rerender, and use `.clientWidth` and
|
|
844
|
-
// `.clientHeight`. I think we could also solve the problem by
|
|
845
|
-
// adding the image to the document before setting the src, but then
|
|
846
|
-
// the experience would be worse for other browsers.
|
|
847
|
-
// TODO(scottgrant): This is correctly calculating the width of SVG
|
|
848
|
-
// images in browsers, but incorrectly saving the width of what may
|
|
849
|
-
// be a smaller viewport when using the editor, and reusing that
|
|
850
|
-
// width in a full-screen article.
|
|
851
|
-
if (img.width === 0 && img.height === 0) {
|
|
852
|
-
document.body?.appendChild(img);
|
|
853
|
-
// TODO(scottgrant): Remove this use of _.defer.
|
|
854
|
-
_.defer(function () {
|
|
855
|
-
callback(img.clientWidth, img.clientHeight);
|
|
856
|
-
document.body?.removeChild(img);
|
|
857
|
-
});
|
|
858
|
-
} else {
|
|
859
|
-
callback(img.width, img.height);
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
img.src = GraphieUtil.getRealImageUrl(url);
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
/**
|
|
867
|
-
* Gets the word right before where the textarea cursor is
|
|
868
|
-
*
|
|
869
|
-
* @param {Element} textarea - The textarea DOM element
|
|
870
|
-
* @return {JSON} - An object with the word and its starting and ending positions in the textarea
|
|
871
|
-
*/
|
|
872
|
-
function getWordBeforeCursor(textarea: HTMLTextAreaElement): WordAndPosition {
|
|
873
|
-
const text = textarea.value;
|
|
874
|
-
|
|
875
|
-
const endPos = textarea.selectionStart - 1;
|
|
876
|
-
const startPos =
|
|
877
|
-
Math.max(
|
|
878
|
-
text.lastIndexOf("\n", endPos),
|
|
879
|
-
text.lastIndexOf(" ", endPos),
|
|
880
|
-
) + 1;
|
|
881
|
-
|
|
882
|
-
return {
|
|
883
|
-
string: text.substring(startPos, endPos + 1),
|
|
884
|
-
pos: {
|
|
885
|
-
start: startPos,
|
|
886
|
-
end: endPos,
|
|
887
|
-
},
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
/**
|
|
892
|
-
* Moves the textarea cursor at the specified position
|
|
893
|
-
*
|
|
894
|
-
* @param {Element} textarea - The textarea DOM element
|
|
895
|
-
* @param {int} pos - The position where the cursor will be moved
|
|
896
|
-
*/
|
|
897
|
-
function moveCursor(textarea: HTMLTextAreaElement, pos: number): void {
|
|
898
|
-
textarea.selectionStart = pos;
|
|
899
|
-
textarea.selectionEnd = pos;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
const textarea = {
|
|
903
|
-
getWordBeforeCursor,
|
|
904
|
-
moveCursor,
|
|
905
|
-
} as const;
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* Many of our labels are automatically converted into math mode without
|
|
909
|
-
* the dollar signs. Unfortunately, this makes them untranslatable! This
|
|
910
|
-
* helper function removes the math mode symbols from a string if we want
|
|
911
|
-
* to translate it but don't need the extra dollar signs.
|
|
912
|
-
*/
|
|
913
|
-
const unescapeMathMode: (label: string) => string = (label) =>
|
|
914
|
-
label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
|
|
915
|
-
|
|
916
|
-
const random: RNG = seededRNG(new Date().getTime() & 0xffffffff);
|
|
917
|
-
|
|
918
|
-
const Util = {
|
|
919
|
-
inputPathsEqual,
|
|
920
|
-
nestedMap,
|
|
921
|
-
rWidgetRule,
|
|
922
|
-
rTypeFromWidgetId,
|
|
923
|
-
rWidgetParts,
|
|
924
|
-
snowman,
|
|
925
|
-
noScore,
|
|
926
|
-
seededRNG,
|
|
927
|
-
shuffle,
|
|
928
|
-
split,
|
|
929
|
-
combineScores,
|
|
930
|
-
keScoreFromPerseusScore,
|
|
931
|
-
firstNumericalParse,
|
|
932
|
-
stringArrayOfSize,
|
|
933
|
-
gridDimensionConfig,
|
|
934
|
-
getGridStep,
|
|
935
|
-
snapStepFromGridStep,
|
|
936
|
-
scaleFromExtent,
|
|
937
|
-
tickStepFromExtent,
|
|
938
|
-
gridStepFromTickStep,
|
|
939
|
-
tickStepFromNumTicks,
|
|
940
|
-
constrainedTickStepsFromTickSteps,
|
|
941
|
-
DeprecationMixin,
|
|
942
|
-
eq,
|
|
943
|
-
deepEq,
|
|
944
|
-
parseQueryString,
|
|
945
|
-
updateQueryString,
|
|
946
|
-
strongEncodeURIComponent,
|
|
947
|
-
widgetShouldHighlight,
|
|
948
|
-
scoreIsEmpty,
|
|
949
|
-
touchHandlers,
|
|
950
|
-
resetTouchHandlers,
|
|
951
|
-
extractPointerLocation,
|
|
952
|
-
supportsPassiveEvents,
|
|
953
|
-
captureScratchpadTouchStart,
|
|
954
|
-
getImageSize,
|
|
955
|
-
getImageSizeModern: GraphieUtil.getImageSizeModern,
|
|
956
|
-
getRealImageUrl: GraphieUtil.getRealImageUrl,
|
|
957
|
-
isLabeledSVG: GraphieUtil.isLabeledSVG,
|
|
958
|
-
getBaseUrl: GraphieUtil.getBaseUrl,
|
|
959
|
-
getSvgUrl: GraphieUtil.getSvgUrl,
|
|
960
|
-
getDataUrl: GraphieUtil.getDataUrl,
|
|
961
|
-
textarea,
|
|
962
|
-
unescapeMathMode,
|
|
963
|
-
random,
|
|
964
|
-
} as const;
|
|
965
|
-
|
|
966
|
-
export default Util;
|