@khanacademy/perseus-editor 4.1.4 → 4.1.6

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.
Files changed (175) hide show
  1. package/dist/es/index.js +1 -1
  2. package/dist/index.js +1 -1
  3. package/package.json +9 -6
  4. package/.babelrc.js +0 -8
  5. package/.eslintrc.js +0 -12
  6. package/CHANGELOG.md +0 -1146
  7. package/src/README.md +0 -7
  8. package/src/__stories__/editor-page.stories.tsx +0 -65
  9. package/src/__stories__/editor.stories.tsx +0 -134
  10. package/src/__stories__/item-editor.stories.tsx +0 -41
  11. package/src/__stories__/tex-error-view.stories.tsx +0 -26
  12. package/src/__testdata__/input-number.testdata.ts +0 -27
  13. package/src/__tests__/editor.test.tsx +0 -142
  14. package/src/__tests__/hint-editor.test.tsx +0 -83
  15. package/src/__tests__/i18n.test.ts +0 -501
  16. package/src/__tests__/integration.test.ts +0 -5
  17. package/src/__tests__/item-extras-editor.test.tsx +0 -85
  18. package/src/__tests__/traversal.test.ts +0 -377
  19. package/src/all-editors.test.ts +0 -16
  20. package/src/all-editors.ts +0 -83
  21. package/src/all-widgets.ts +0 -7
  22. package/src/article-editor.tsx +0 -438
  23. package/src/components/__stories__/blur-input.stories.tsx +0 -22
  24. package/src/components/__stories__/section-control-button.stories.tsx +0 -26
  25. package/src/components/__tests__/blur-input.test.tsx +0 -67
  26. package/src/components/blur-input.tsx +0 -69
  27. package/src/components/checkbox.tsx +0 -194
  28. package/src/components/device-framer.tsx +0 -90
  29. package/src/components/drag-target.tsx +0 -87
  30. package/src/components/dropdown-option.tsx +0 -311
  31. package/src/components/form-wrapped-text-field.tsx +0 -245
  32. package/src/components/graph-points-count-selector.tsx +0 -31
  33. package/src/components/graph-settings.tsx +0 -627
  34. package/src/components/graph-type-selector.tsx +0 -31
  35. package/src/components/hover-behavior.ts +0 -177
  36. package/src/components/json-editor.tsx +0 -121
  37. package/src/components/link.ts +0 -173
  38. package/src/components/section-control-button.tsx +0 -53
  39. package/src/components/segment-count-selector.tsx +0 -27
  40. package/src/components/simple-button.tsx +0 -85
  41. package/src/components/sortable.tsx +0 -187
  42. package/src/components/util.ts +0 -38
  43. package/src/components/viewport-resizer.tsx +0 -72
  44. package/src/components/widget-editor.tsx +0 -222
  45. package/src/components/widget-select.tsx +0 -48
  46. package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
  47. package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
  48. package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
  49. package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
  50. package/src/diffs/__tests__/split-diff.test.ts +0 -33
  51. package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
  52. package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
  53. package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
  54. package/src/diffs/article-diff.tsx +0 -69
  55. package/src/diffs/item-diff.tsx +0 -76
  56. package/src/diffs/renderer-diff.tsx +0 -137
  57. package/src/diffs/split-diff.ts +0 -31
  58. package/src/diffs/string-array-diff.ts +0 -74
  59. package/src/diffs/structured-item-diff.tsx +0 -275
  60. package/src/diffs/tags-diff.tsx +0 -49
  61. package/src/diffs/text-diff.tsx +0 -193
  62. package/src/diffs/widget-diff-performer.ts +0 -69
  63. package/src/diffs/widget-diff.tsx +0 -290
  64. package/src/editor-page.tsx +0 -325
  65. package/src/editor.tsx +0 -1099
  66. package/src/hint-editor.tsx +0 -469
  67. package/src/i18n.ts +0 -140
  68. package/src/iframe-content-renderer.tsx +0 -188
  69. package/src/index.ts +0 -30
  70. package/src/item-editor.tsx +0 -158
  71. package/src/item-extras-editor.tsx +0 -230
  72. package/src/katex-mhchem/index.js +0 -73
  73. package/src/katex-mhchem/parser.js +0 -2659
  74. package/src/multirenderer-editor.tsx +0 -1061
  75. package/src/stateful-article-editor.tsx +0 -173
  76. package/src/stateful-editor-page.tsx +0 -88
  77. package/src/styles/perseus-editor.less +0 -1321
  78. package/src/testing-widgets.ts +0 -11
  79. package/src/tex-error-view.tsx +0 -90
  80. package/src/util/points.test.ts +0 -24
  81. package/src/util/points.ts +0 -13
  82. package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
  83. package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
  84. package/src/version.ts +0 -10
  85. package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
  86. package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
  87. package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
  88. package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
  89. package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
  90. package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
  91. package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
  92. package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
  93. package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
  94. package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
  95. package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
  96. package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
  97. package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
  98. package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
  99. package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
  100. package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
  101. package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
  102. package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
  103. package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
  104. package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
  105. package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
  106. package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
  107. package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
  108. package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
  109. package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
  110. package/src/widgets/categorizer-editor.tsx +0 -104
  111. package/src/widgets/cs-program-editor.tsx +0 -256
  112. package/src/widgets/definition-editor.tsx +0 -77
  113. package/src/widgets/deprecated-standin-editor.tsx +0 -29
  114. package/src/widgets/dropdown-editor.tsx +0 -211
  115. package/src/widgets/example-graphie-widget-editor.tsx +0 -70
  116. package/src/widgets/example-graphie-widget.tsx +0 -172
  117. package/src/widgets/example-widget-editor.tsx +0 -62
  118. package/src/widgets/example-widget.tsx +0 -154
  119. package/src/widgets/explanation-editor.tsx +0 -92
  120. package/src/widgets/expression-editor.tsx +0 -557
  121. package/src/widgets/graded-group-editor.tsx +0 -161
  122. package/src/widgets/graded-group-set-editor.tsx +0 -104
  123. package/src/widgets/grapher-editor.tsx +0 -155
  124. package/src/widgets/group-editor.tsx +0 -83
  125. package/src/widgets/iframe-editor.tsx +0 -202
  126. package/src/widgets/image-editor.tsx +0 -367
  127. package/src/widgets/input-number-editor.tsx +0 -288
  128. package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
  129. package/src/widgets/interaction-editor/function-editor.tsx +0 -108
  130. package/src/widgets/interaction-editor/index.ts +0 -3
  131. package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
  132. package/src/widgets/interaction-editor/label-editor.tsx +0 -87
  133. package/src/widgets/interaction-editor/line-editor.tsx +0 -125
  134. package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
  135. package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
  136. package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
  137. package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
  138. package/src/widgets/interaction-editor/point-editor.tsx +0 -72
  139. package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
  140. package/src/widgets/interactive-graph-editor.tsx +0 -571
  141. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
  142. package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
  143. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
  144. package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
  145. package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
  146. package/src/widgets/label-image/answer-choices.tsx +0 -231
  147. package/src/widgets/label-image/behavior.tsx +0 -122
  148. package/src/widgets/label-image/marker.tsx +0 -290
  149. package/src/widgets/label-image/question-markers.tsx +0 -176
  150. package/src/widgets/label-image/select-image.tsx +0 -81
  151. package/src/widgets/label-image-editor.tsx +0 -252
  152. package/src/widgets/lights-puzzle-editor.tsx +0 -278
  153. package/src/widgets/matcher-editor.tsx +0 -149
  154. package/src/widgets/matrix-editor.tsx +0 -156
  155. package/src/widgets/measurer-editor.tsx +0 -253
  156. package/src/widgets/molecule-editor.tsx +0 -64
  157. package/src/widgets/number-line-editor.tsx +0 -512
  158. package/src/widgets/numeric-input-editor.tsx +0 -536
  159. package/src/widgets/orderer-editor.tsx +0 -172
  160. package/src/widgets/passage-editor.tsx +0 -117
  161. package/src/widgets/passage-ref-editor.tsx +0 -80
  162. package/src/widgets/passage-ref-target-editor.tsx +0 -49
  163. package/src/widgets/plotter-editor.tsx +0 -542
  164. package/src/widgets/radio/editor.tsx +0 -398
  165. package/src/widgets/reaction-diagram-editor.tsx +0 -131
  166. package/src/widgets/sequence-editor.tsx +0 -205
  167. package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
  168. package/src/widgets/simple-markdown-tester.tsx +0 -92
  169. package/src/widgets/simulator-editor.tsx +0 -146
  170. package/src/widgets/sorter-editor.tsx +0 -103
  171. package/src/widgets/table-editor.tsx +0 -164
  172. package/src/widgets/unit-editor.tsx +0 -299
  173. package/src/widgets/video-editor.tsx +0 -73
  174. package/tsconfig-build.json +0 -22
  175. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,536 +0,0 @@
1
- /* eslint-disable jsx-a11y/anchor-is-valid, react/sort-comp */
2
- import {
3
- components,
4
- icons,
5
- Changeable,
6
- EditorJsonify,
7
- Util,
8
- } from "@khanacademy/perseus";
9
- import createReactClass from "create-react-class";
10
- import * as React from "react";
11
- import _ from "underscore";
12
-
13
- import Editor from "../editor";
14
-
15
- const {
16
- ButtonGroup,
17
- InfoTip,
18
- InlineIcon,
19
- MultiButtonGroup,
20
- NumberInput,
21
- PropCheckBox,
22
- TextInput,
23
- } = components;
24
- const {iconGear, iconTrash} = icons;
25
- const {firstNumericalParse} = Util;
26
-
27
- const answerFormButtons = [
28
- {title: "Integers", value: "integer", content: "6"},
29
- {title: "Decimals", value: "decimal", content: "0.75"},
30
- {title: "Proper fractions", value: "proper", content: "\u2157"},
31
- {
32
- title: "Improper fractions",
33
- value: "improper",
34
- content: "\u2077\u2044\u2084",
35
- },
36
- {title: "Mixed numbers", value: "mixed", content: "1\u00BE"},
37
- {title: "Numbers with \u03C0", value: "pi", content: "\u03C0"},
38
- ];
39
-
40
- const initAnswer = (status: string) => {
41
- return {
42
- value: null,
43
- status: status,
44
- message: "",
45
- simplify: "required",
46
- answerForms: [],
47
- strict: false,
48
- maxError: null,
49
- };
50
- };
51
-
52
- const NumericInputEditor: any = createReactClass({
53
- displayName: "NumericInputEditor",
54
-
55
- propTypes: {
56
- ...Changeable.propTypes,
57
- },
58
-
59
- statics: {
60
- widgetName: "numeric-input",
61
- },
62
-
63
- getDefaultProps: function () {
64
- return {
65
- answers: [initAnswer("correct")],
66
- size: "normal",
67
- coefficient: false,
68
- labelText: "",
69
- rightAlign: false,
70
- };
71
- },
72
-
73
- getInitialState: function () {
74
- return {
75
- lastStatus: "wrong",
76
- showOptions: _.map(this.props.answers, () => false),
77
- };
78
- },
79
-
80
- render: function () {
81
- const answers = this.props.answers;
82
-
83
- const unsimplifiedAnswers = (i: any) => (
84
- <div className="perseus-widget-row">
85
- <label>Unsimplified answers are</label>
86
- <ButtonGroup
87
- value={answers[i]["simplify"]}
88
- allowEmpty={false}
89
- buttons={[
90
- {value: "required", content: "ungraded"},
91
- {value: "optional", content: "accepted"},
92
- {value: "enforced", content: "wrong"},
93
- ]}
94
- onChange={this.updateAnswer(i, "simplify")}
95
- />
96
- <InfoTip>
97
- <p>
98
- Normally select "ungraded". This will give the user a
99
- message saying the answer is correct but not simplified.
100
- The user will then have to simplify it and re-enter, but
101
- will not be penalized. (5th grade and after)
102
- </p>
103
- <p>
104
- Select "accepted" only if the user is not expected to
105
- know how to simplify fractions yet. (Anything prior to
106
- 5th grade)
107
- </p>
108
- <p>
109
- Select "wrong" <em>only</em> if we are specifically
110
- assessing the ability to simplify.
111
- </p>
112
- </InfoTip>
113
- </div>
114
- );
115
-
116
- const suggestedAnswerTypes = (i: any) => (
117
- <div>
118
- <div className="perseus-widget-row">
119
- <label>Choose the suggested answer formats</label>
120
- <MultiButtonGroup
121
- buttons={answerFormButtons}
122
- values={answers[i]["answerForms"]}
123
- onChange={this.updateAnswer(i, "answerForms")}
124
- />
125
- <InfoTip>
126
- <p>
127
- Formats will be autoselected for you based on the
128
- given answer; to show no suggested formats and
129
- accept all types, simply have a decimal/integer be
130
- the answer. Values with &pi; will have format "pi",
131
- and values that are fractions will have some subset
132
- (mixed will be "mixed" and "proper"; improper/proper
133
- will both be "improper" and "proper"). If you would
134
- like to specify that it is only a proper fraction
135
- (or only a mixed/improper fraction), deselect the
136
- other format. Except for specific cases, you should
137
- not need to change the autoselected formats.
138
- </p>
139
- <p>
140
- To restrict the answer to <em>only</em> an improper
141
- fraction (i.e. 7/4), select the improper fraction
142
- and toggle "strict" to true. This <b>will not</b>{" "}
143
- accept 1.75 as an answer.{" "}
144
- </p>
145
- <p>
146
- Unless you are testing that specific skill, please
147
- do not restrict the answer format.
148
- </p>
149
- </InfoTip>
150
- </div>
151
- <div className="perseus-widget-row">
152
- <PropCheckBox
153
- label="Strictly match only these formats"
154
- strict={answers[i]["strict"]}
155
- // eslint-disable-next-line react/jsx-no-bind
156
- onChange={this.updateAnswer.bind(this, i)}
157
- />
158
- </div>
159
- </div>
160
- );
161
-
162
- const maxError = (i: any) => (
163
- <div className="perseus-widget-row">
164
- <label>
165
- Max error{" "}
166
- <NumberInput
167
- className="max-error"
168
- value={answers[i]["maxError"]}
169
- onChange={this.updateAnswer(i, "maxError")}
170
- placeholder="0"
171
- />
172
- </label>
173
- </div>
174
- );
175
-
176
- const inputSize = (
177
- <div className="perseus-widget-row">
178
- <label>Width: </label>
179
- <ButtonGroup
180
- value={this.props.size}
181
- allowEmpty={false}
182
- buttons={[
183
- {value: "normal", content: "Normal (80px)"},
184
- {value: "small", content: "Small (40px)"},
185
- ]}
186
- onChange={this.change("size")}
187
- />
188
- <InfoTip>
189
- <p>
190
- Use size "Normal" for all text boxes, unless there are
191
- multiple text boxes in one line and the answer area is
192
- too narrow to fit them.
193
- </p>
194
- </InfoTip>
195
- </div>
196
- );
197
-
198
- const rightAlign = (
199
- <div className="perseus-widget-row">
200
- <PropCheckBox
201
- label="Right alignment"
202
- rightAlign={this.props.rightAlign}
203
- onChange={this.props.onChange}
204
- />
205
- </div>
206
- );
207
-
208
- const labelText = (
209
- <div className="perseus-widget-row">
210
- <label>
211
- Label text:{" "}
212
- <TextInput
213
- value={this.props.labelText}
214
- onChange={this.change("labelText")}
215
- />
216
- </label>
217
- <InfoTip>
218
- <p>
219
- Text to describe this input. This will be shown to users
220
- using screenreaders.
221
- </p>
222
- </InfoTip>
223
- </div>
224
- );
225
-
226
- const coefficientCheck = (
227
- <div>
228
- <div className="perseus-widget-row">
229
- <PropCheckBox
230
- label="Coefficient"
231
- coefficient={this.props.coefficient}
232
- onChange={this.props.onChange}
233
- />
234
- <InfoTip>
235
- <p>
236
- A coefficient style number allows the student to use
237
- - for -1 and an empty string to mean 1.
238
- </p>
239
- </InfoTip>
240
- </div>
241
- </div>
242
- );
243
-
244
- const addAnswerButton = (
245
- <div>
246
- <a
247
- href="javascript:void(0)"
248
- className="simple-button orange"
249
- onClick={() => this.addAnswer()}
250
- onKeyDown={(e) => this.onSpace(e, this.addAnswer)}
251
- >
252
- <span>Add new answer</span>
253
- </a>
254
- </div>
255
- );
256
-
257
- const instructions = {
258
- wrong: "(address the mistake/misconception)",
259
- ungraded: "(explain in detail to avoid confusion)",
260
- correct: "(reinforce the user's understanding)",
261
- } as const;
262
-
263
- const generateInputAnswerEditors = () =>
264
- answers.map((answer, i) => {
265
- const editor = (
266
- <Editor
267
- apiOptions={this.props.apiOptions}
268
- content={answer.message || ""}
269
- placeholder={
270
- "Why is this answer " +
271
- answer.status +
272
- "?\t" +
273
- instructions[answer.status]
274
- }
275
- widgetEnabled={false}
276
- onChange={(newProps) => {
277
- if ("content" in newProps) {
278
- this.updateAnswer(i, {
279
- message: newProps.content,
280
- });
281
- }
282
- }}
283
- />
284
- );
285
- return (
286
- <div className="perseus-widget-row" key={i}>
287
- <div
288
- className={
289
- "input-answer-editor-value-container" +
290
- (answer.maxError ? " with-max-error" : "")
291
- }
292
- >
293
- <NumberInput
294
- value={answer.value}
295
- className="numeric-input-value"
296
- placeholder="answer"
297
- format={_.last(answer.answerForms)}
298
- onFormatChange={(newValue, format) => {
299
- // NOTE(charlie): The mobile web expression
300
- // editor relies on this automatic answer
301
- // form resolution for determining when to
302
- // show the Pi symbol. If we get rid of it,
303
- // we should also disable Pi for
304
- // NumericInput and require problems that
305
- // use Pi to build on Expression.
306
- // Alternatively, we could store answers
307
- // as plaintext and parse them to determine
308
- // whether or not to reveal Pi on the
309
- // keypad (right now, answers are stored as
310
- // resolved values, like '0.125' rather
311
- // than '1/8').
312
- let forms;
313
- if (format === "pi") {
314
- forms = ["pi"];
315
- } else if (format === "mixed") {
316
- forms = ["proper", "mixed"];
317
- } else if (
318
- format === "proper" ||
319
- format === "improper"
320
- ) {
321
- forms = ["proper", "improper"];
322
- }
323
- this.updateAnswer(i, {
324
- value: firstNumericalParse(newValue),
325
- answerForms: forms,
326
- });
327
- }}
328
- onChange={(newValue) => {
329
- this.updateAnswer(i, {
330
- value: firstNumericalParse(newValue),
331
- });
332
- }}
333
- />
334
- {answer.strict && (
335
- <div
336
- className="is-strict-indicator"
337
- title="strictly equivalent to"
338
- >
339
- &equiv;
340
- </div>
341
- )}
342
- {answer.simplify !== "required" &&
343
- answer.status === "correct" && (
344
- <div
345
- className={
346
- "simplify-indicator " +
347
- answer.simplify
348
- }
349
- title="accepts unsimplified answers"
350
- >
351
- &permil;
352
- </div>
353
- )}
354
- {answer.maxError ? (
355
- <div className="max-error-container">
356
- <div className="max-error-plusmn">
357
- &plusmn;
358
- </div>
359
- <NumberInput
360
- placeholder={0}
361
- value={answers[i]["maxError"]}
362
- format={_.last(answer.answerForms)}
363
- onChange={this.updateAnswer(
364
- i,
365
- "maxError",
366
- )}
367
- />
368
- </div>
369
- ) : null}
370
- <div className="value-divider" />
371
- <a
372
- href="javascript:void(0)"
373
- className={"answer-status " + answer.status}
374
- onClick={() => this.onStatusChange(i)}
375
- onKeyDown={(e) =>
376
- this.onSpace(e, this.onStatusChange, i)
377
- }
378
- >
379
- {answer.status}
380
- </a>
381
- <a
382
- href="javascript:void(0)"
383
- className="answer-trash"
384
- aria-label="Delete answer"
385
- onClick={() => this.onTrashAnswer(i)}
386
- onKeyDown={(e) =>
387
- this.onSpace(e, this.onTrashAnswer, i)
388
- }
389
- >
390
- <InlineIcon {...iconTrash} />
391
- </a>
392
- <a
393
- href="javascript:void(0)"
394
- className="options-toggle"
395
- aria-label="Toggle options"
396
- onClick={() => this.onToggleOptions(i)}
397
- onKeyDown={(e) =>
398
- this.onSpace(e, this.onToggleOptions, i)
399
- }
400
- >
401
- <InlineIcon {...iconGear} />
402
- </a>
403
- </div>
404
- <div className="input-answer-editor-message">
405
- {editor}
406
- </div>
407
- {this.state.showOptions[i] && (
408
- <div className="options-container">
409
- {maxError(i)}
410
- {answer.status === "correct" &&
411
- unsimplifiedAnswers(i)}
412
- {suggestedAnswerTypes(i)}
413
- </div>
414
- )}
415
- </div>
416
- );
417
- });
418
-
419
- return (
420
- <div className="perseus-input-number-editor">
421
- <div className="ui-title">User input</div>
422
- <div className="msg-title">
423
- Message shown to user on attempt
424
- </div>
425
- {generateInputAnswerEditors()}
426
- {addAnswerButton}
427
- {inputSize}
428
- {rightAlign}
429
- {coefficientCheck}
430
- {labelText}
431
- </div>
432
- );
433
- },
434
-
435
- change(...args) {
436
- return Changeable.change.apply(this, args);
437
- },
438
-
439
- onToggleOptions: function (choiceIndex) {
440
- const showOptions = this.state.showOptions.slice();
441
- showOptions[choiceIndex] = !showOptions[choiceIndex];
442
- this.setState({showOptions: showOptions});
443
- },
444
-
445
- onTrashAnswer: function (choiceIndex) {
446
- if (choiceIndex >= 0 && choiceIndex < this.props.answers.length) {
447
- const answers = this.props.answers.slice(0);
448
- answers.splice(choiceIndex, 1);
449
- this.props.onChange({answers: answers});
450
- }
451
- },
452
-
453
- onSpace: function (e, callback) {
454
- if (e.key === " ") {
455
- e.preventDefault(); // prevent page shifting
456
- // eslint-disable-next-line prefer-rest-params
457
- const args = _.toArray(arguments).slice(2);
458
- callback.apply(this, args);
459
- }
460
- },
461
-
462
- onStatusChange: function (choiceIndex) {
463
- const statuses = ["wrong", "ungraded", "correct"];
464
- const answers = this.props.answers;
465
- const i = _.indexOf(statuses, answers[choiceIndex].status);
466
- const newStatus = statuses[(i + 1) % statuses.length];
467
-
468
- this.updateAnswer(choiceIndex, {
469
- status: newStatus,
470
- simplify: newStatus === "correct" ? "required" : "accepted",
471
- });
472
- },
473
-
474
- updateAnswer: function (choiceIndex, update) {
475
- if (!_.isObject(update)) {
476
- return _.partial(
477
- (choiceIndex, key, value) => {
478
- const update: Record<string, any> = {};
479
- update[key] = value;
480
- this.updateAnswer(choiceIndex, update);
481
- },
482
- choiceIndex,
483
- update,
484
- );
485
- }
486
-
487
- let answers = _.clone(this.props.answers);
488
-
489
- // Don't bother to make a new answer box unless we are editing the last
490
- // one.
491
- // TODO(oliver): This might not be necessary anymore.
492
- if (choiceIndex === answers.length) {
493
- const lastAnswer = initAnswer(this.state.lastStatus);
494
- answers = answers.concat(lastAnswer);
495
- }
496
-
497
- answers[choiceIndex] = _.extend({}, answers[choiceIndex], update);
498
- this.props.onChange({answers: answers});
499
- },
500
-
501
- addAnswer: function () {
502
- const lastAnswer = initAnswer(this.state.lastStatus);
503
- const answers = this.props.answers.concat(lastAnswer);
504
- this.props.onChange({answers: answers});
505
- },
506
-
507
- getSaveWarnings: function () {
508
- // Filter out all the empty answers
509
- const warnings = [];
510
- // TODO(emily): This doesn't actually work, because the value is either
511
- // null or undefined when undefined, probably.
512
- if (_.contains(_.pluck(this.props.answers, "value"), "")) {
513
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
514
- warnings.push("One or more answers is empty");
515
- }
516
- this.props.answers.forEach((answer, i) => {
517
- const formatError =
518
- answer.strict &&
519
- (!answer.answerForms || answer.answerForms.length === 0);
520
- if (formatError) {
521
- warnings.push(
522
- // @ts-expect-error - TS2345 - Argument of type 'string' is not assignable to parameter of type 'never'.
523
- `Answer ${i + 1} is set to string format ` +
524
- "matching, but no format was selected",
525
- );
526
- }
527
- });
528
- return warnings;
529
- },
530
-
531
- serialize() {
532
- return EditorJsonify.serialize.call(this);
533
- },
534
- });
535
-
536
- export default NumericInputEditor;