@khanacademy/perseus-editor 4.1.5 → 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 -1155
  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,469 +0,0 @@
1
- /* eslint-disable @khanacademy/ts-no-error-suppressions */
2
- /* eslint-disable @babel/no-invalid-this */
3
- /**
4
- * Collection of classes for rendering the hint editor area,
5
- * hint editor boxes, and hint previews
6
- */
7
- import {components, icons} from "@khanacademy/perseus";
8
- import * as React from "react";
9
- import _ from "underscore";
10
-
11
- import DeviceFramer from "./components/device-framer";
12
- import Editor from "./editor";
13
- import IframeContentRenderer from "./iframe-content-renderer";
14
-
15
- import type {
16
- APIOptions,
17
- WidgetDict,
18
- ImageDict,
19
- Hint,
20
- ChangeHandler,
21
- DeviceType,
22
- } from "@khanacademy/perseus";
23
-
24
- const {InfoTip, InlineIcon} = components;
25
- const {iconCircleArrowDown, iconCircleArrowUp, iconPlus, iconTrash} = icons;
26
-
27
- type ImageUploader = (
28
- file: string,
29
- callback: (url: string) => unknown,
30
- ) => unknown;
31
-
32
- type HintEditorProps = {
33
- itemId?: string;
34
- apiOptions?: APIOptions;
35
- className: string;
36
- imageUploader?: ImageUploader;
37
- showMoveButtons?: boolean;
38
- showRemoveButton?: boolean;
39
- showTitle?: boolean;
40
- content?: string | null | undefined;
41
- replace?: boolean | null | undefined;
42
- widgets?: WidgetDict | null | undefined;
43
- images?: ImageDict | null | undefined;
44
- isLast: boolean;
45
- isFirst: boolean;
46
- onMove: (direction: number) => unknown;
47
- onRemove: () => unknown;
48
- onChange: ChangeHandler;
49
- __type?: "hint";
50
- };
51
-
52
- /* Renders a hint editor box
53
- *
54
- * This includes:
55
- * ~ A "Hint" title
56
- * ~ the textarea for the hint
57
- * ~ the "remove this hint" box
58
- * ~ the move hint up/down arrows
59
- */
60
- export class HintEditor extends React.Component<HintEditorProps> {
61
- static defaultProps: {
62
- className: string;
63
- content: string;
64
- replace: boolean;
65
- showMoveButtons: boolean;
66
- showRemoveButton: boolean;
67
- showTitle: boolean;
68
- } = {
69
- className: "",
70
- content: "",
71
- replace: false,
72
- showMoveButtons: true,
73
- showTitle: true,
74
- showRemoveButton: true,
75
- };
76
-
77
- editor = React.createRef<Editor>();
78
-
79
- handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void = (
80
- e: React.ChangeEvent<HTMLInputElement>,
81
- ) => {
82
- this.props.onChange({replace: e.target.checked});
83
- };
84
-
85
- focus: () => void = () => {
86
- this.editor.current?.focus();
87
- };
88
-
89
- getSaveWarnings: () => any = () => {
90
- return this.editor.current?.getSaveWarnings();
91
- };
92
-
93
- serialize: (options?: any) => any = (options: any) => {
94
- return this.editor.current?.serialize(options);
95
- };
96
-
97
- render(): React.ReactNode {
98
- return (
99
- <div className={"perseus-hint-editor " + this.props.className}>
100
- {this.props.showTitle && <div className="pod-title">Hint</div>}
101
- <Editor
102
- ref={this.editor}
103
- // Using the AssessmentItem content ID as the key
104
- // ensures that when the user navigates to another
105
- // item in the Sidebar, the question editor is
106
- // re-rendered by React.
107
- key={this.props.itemId}
108
- apiOptions={this.props.apiOptions}
109
- widgets={this.props.widgets || undefined}
110
- content={this.props.content || undefined}
111
- images={this.props.images}
112
- replace={this.props.replace}
113
- placeholder="Type your hint here..."
114
- imageUploader={this.props.imageUploader}
115
- onChange={this.props.onChange}
116
- />
117
- <div className="hint-controls-container clearfix">
118
- {this.props.showMoveButtons && (
119
- <span className="reorder-hints">
120
- <button
121
- type="button"
122
- className={this.props.isLast ? "hidden" : ""}
123
- onClick={_.partial(this.props.onMove, 1)}
124
- >
125
- <InlineIcon {...iconCircleArrowDown} />
126
- </button>{" "}
127
- <button
128
- type="button"
129
- className={this.props.isFirst ? "hidden" : ""}
130
- onClick={_.partial(this.props.onMove, -1)}
131
- >
132
- <InlineIcon {...iconCircleArrowUp} />
133
- </button>{" "}
134
- {this.props.isLast && (
135
- <InfoTip>
136
- <p>
137
- The last hint is automatically bolded.
138
- </p>
139
- </InfoTip>
140
- )}
141
- </span>
142
- )}
143
- <input
144
- type="checkbox"
145
- // @ts-expect-error - TS2322 - Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'.
146
- checked={this.props.replace}
147
- onChange={this.handleChange}
148
- />
149
- Replace previous hint
150
- {this.props.showRemoveButton && (
151
- <button
152
- type="button"
153
- className="remove-hint simple-button orange"
154
- onClick={this.props.onRemove}
155
- >
156
- <InlineIcon {...iconTrash} />
157
- Remove this hint{" "}
158
- </button>
159
- )}
160
- </div>
161
- </div>
162
- );
163
- }
164
- }
165
-
166
- type CombinedHintEditorProps = {
167
- itemId?: string;
168
- apiOptions?: APIOptions;
169
- deviceType: DeviceType;
170
- imageUploader?: ImageUploader;
171
- highlightLint?: boolean;
172
- isLast: boolean;
173
- isFirst: boolean;
174
- hint: Hint;
175
- pos: number; // position,
176
- contentPaths: ReadonlyArray<string>;
177
- // URL of the route to show on initial load of the preview frames.
178
- previewURL: string;
179
- onMove: (direction: number) => unknown;
180
- onRemove: () => unknown;
181
- onChange: ChangeHandler;
182
- };
183
-
184
- /* A single hint-row containing a hint editor and preview */
185
- class CombinedHintEditor extends React.Component<CombinedHintEditorProps> {
186
- static defaultProps = {
187
- highlightLint: false,
188
- };
189
-
190
- editor = React.createRef<HintEditor>();
191
- frame = React.createRef<IframeContentRenderer>();
192
-
193
- componentDidMount() {
194
- this.updatePreview();
195
- }
196
-
197
- componentDidUpdate() {
198
- this.updatePreview();
199
- }
200
-
201
- updatePreview = () => {
202
- const shouldBold =
203
- this.props.isLast && !/\*\*/.test(this.props.hint.content);
204
-
205
- this.frame.current?.sendNewData({
206
- type: "hint",
207
- data: {
208
- hint: this.props.hint,
209
- bold: shouldBold,
210
- pos: this.props.pos,
211
- apiOptions: this.props.apiOptions,
212
- linterContext: {
213
- contentType: "hint",
214
- highlightLint: this.props.highlightLint,
215
- paths: this.props.contentPaths,
216
- },
217
- },
218
- });
219
- };
220
-
221
- getSaveWarnings = () => {
222
- return this.editor.current?.getSaveWarnings();
223
- };
224
-
225
- serialize = (options: any) => {
226
- return this.editor.current?.serialize(options);
227
- };
228
-
229
- focus = () => {
230
- this.editor.current?.focus();
231
- };
232
-
233
- render(): React.ReactNode {
234
- const isMobile =
235
- this.props.deviceType === "phone" ||
236
- this.props.deviceType === "tablet";
237
- return (
238
- <div
239
- className={
240
- "perseus-combined-hint-editor " + "perseus-editor-row"
241
- }
242
- >
243
- <div className="perseus-editor-left-cell">
244
- <HintEditor
245
- ref={this.editor}
246
- itemId={this.props.itemId}
247
- isFirst={this.props.isFirst}
248
- isLast={this.props.isLast}
249
- widgets={this.props.hint.widgets}
250
- content={this.props.hint.content}
251
- images={this.props.hint.images}
252
- replace={this.props.hint.replace}
253
- imageUploader={this.props.imageUploader}
254
- onChange={this.props.onChange}
255
- onRemove={this.props.onRemove}
256
- onMove={this.props.onMove}
257
- apiOptions={this.props.apiOptions}
258
- />
259
- </div>
260
- <div className="perseus-editor-right-cell">
261
- <DeviceFramer
262
- deviceType={this.props.deviceType}
263
- nochrome={true}
264
- >
265
- <IframeContentRenderer
266
- ref={this.frame}
267
- datasetKey="mobile"
268
- datasetValue={isMobile}
269
- seamless={true}
270
- url={this.props.previewURL}
271
- />
272
- </DeviceFramer>
273
- </div>
274
- </div>
275
- );
276
- }
277
- }
278
-
279
- type CombinedHintsEditorProps = {
280
- apiOptions?: APIOptions;
281
- deviceType: DeviceType;
282
- imageUploader?: ImageUploader;
283
- highlightLint?: boolean;
284
- hints: ReadonlyArray<Hint>;
285
- // URL of the route to show on initial load of the preview frames.
286
- previewURL: string;
287
- onChange: ChangeHandler;
288
- // The content ID of the AssessmentItem being edited. It may not be set
289
- // for non-content library exercise questions.
290
- itemId?: string;
291
- };
292
-
293
- /* The entire hints editing/preview area
294
- *
295
- * Includes:
296
- * ~ All the hint edit boxes, move and remove buttons
297
- * ~ All the hint previews
298
- * ~ The "add a hint" button
299
- */
300
- class CombinedHintsEditor extends React.Component<CombinedHintsEditorProps> {
301
- static HintEditor: typeof HintEditor = HintEditor;
302
-
303
- static defaultProps: {
304
- highlightLint: boolean;
305
- hints: ReadonlyArray<any>;
306
- onChange: () => void;
307
- } = {
308
- onChange: () => {},
309
- hints: [],
310
- highlightLint: false,
311
- };
312
-
313
- handleHintChange: (
314
- i: number,
315
- newProps: CombinedHintsEditorProps,
316
- cb: () => unknown,
317
- silent: boolean,
318
- ) => void = (
319
- i: number,
320
- newProps: CombinedHintsEditorProps,
321
- cb: () => unknown,
322
- silent: boolean,
323
- ) => {
324
- // TODO(joel) - lens
325
- const hints = _(this.props.hints).clone();
326
- hints[i] = _.extend(
327
- {},
328
- this.serializeHint(i, {keepDeletedWidgets: true}),
329
- newProps,
330
- );
331
-
332
- // @ts-expect-error - TS2740 - Type 'Hint' is missing the following properties from type 'readonly Hint[]': length, concat, join, slice, and 18 more.
333
- this.props.onChange({hints: hints}, cb, silent);
334
- };
335
-
336
- handleHintRemove: (i: number) => void = (i: number) => {
337
- // eslint-disable-next-line no-alert
338
- if (!confirm("Are you sure you want to delete this hint?")) {
339
- return;
340
- }
341
-
342
- const hints = _(this.props.hints).clone();
343
- // @ts-expect-error - TS2339 - Property 'splice' does not exist on type 'Hint'.
344
- hints.splice(i, 1);
345
- // @ts-expect-error - TS2322 - Type 'Hint' is not assignable to type 'readonly Hint[]'.
346
- this.props.onChange({hints: hints});
347
- };
348
-
349
- handleHintMove: (i: number, dir: number) => void = (
350
- i: number,
351
- dir: number,
352
- ) => {
353
- const hints = _(this.props.hints).clone();
354
- // @ts-expect-error - TS2339 - Property 'splice' does not exist on type 'Hint'.
355
- const hint = hints.splice(i, 1)[0];
356
- // @ts-expect-error - TS2339 - Property 'splice' does not exist on type 'Hint'.
357
- hints.splice(i + dir, 0, hint);
358
- // @ts-expect-error - TS2322 - Type 'Hint' is not assignable to type 'readonly Hint[]'.
359
- this.props.onChange({hints: hints}, () => {
360
- // eslint-disable-next-line react/no-string-refs
361
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
362
- this.refs["hintEditor" + (i + dir)].focus();
363
- });
364
- };
365
-
366
- addHint: () => void = () => {
367
- const hints = _(this.props.hints)
368
- .clone()
369
- // @ts-expect-error - TS2339 - Property 'concat' does not exist on type 'Hint'.
370
- .concat([{content: ""}]);
371
- this.props.onChange({hints: hints}, () => {
372
- const i = hints.length - 1;
373
- // eslint-disable-next-line react/no-string-refs
374
- // @ts-expect-error - TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
375
- this.refs["hintEditor" + i].focus();
376
- });
377
- };
378
-
379
- getSaveWarnings: () => any = () => {
380
- return _.chain(this.props.hints)
381
- .map((hint, i) => {
382
- return _.map(
383
- // eslint-disable-next-line react/no-string-refs
384
- // @ts-expect-error - TS2339 - Property 'getSaveWarnings' does not exist on type 'ReactInstance'.
385
- this.refs["hintEditor" + i].getSaveWarnings(),
386
- (issue) => "Hint " + (i + 1) + ": " + issue,
387
- );
388
- })
389
- .flatten(true)
390
- .value();
391
- };
392
-
393
- serialize: (options?: any) => ReadonlyArray<string> = (options: any) => {
394
- return this.props.hints.map((hint, i) => {
395
- return this.serializeHint(i, options);
396
- });
397
- };
398
-
399
- serializeHint: (index: number, options?: any) => string = (
400
- index: number,
401
- options: any,
402
- ): string => {
403
- // eslint-disable-next-line react/no-string-refs
404
- // @ts-expect-error - TS2339 - Property 'serialize' does not exist on type 'ReactInstance'.
405
- return this.refs["hintEditor" + index].serialize(options);
406
- };
407
-
408
- render(): React.ReactNode {
409
- const {itemId, hints} = this.props;
410
- const hintElems = _.map(
411
- hints,
412
- function (hint, i) {
413
- return (
414
- <CombinedHintEditor
415
- ref={"hintEditor" + i}
416
- key={"hintEditor" + i}
417
- isFirst={i === 0}
418
- isLast={i + 1 === hints.length}
419
- itemId={itemId}
420
- hint={hint}
421
- pos={i}
422
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
423
- imageUploader={this.props.imageUploader}
424
- // eslint-disable-next-line react/jsx-no-bind
425
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
426
- onChange={this.handleHintChange.bind(this, i)}
427
- // eslint-disable-next-line react/jsx-no-bind
428
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
429
- onRemove={this.handleHintRemove.bind(this, i)}
430
- // eslint-disable-next-line react/jsx-no-bind
431
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
432
- onMove={this.handleHintMove.bind(this, i)}
433
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
434
- deviceType={this.props.deviceType}
435
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
436
- apiOptions={this.props.apiOptions}
437
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
438
- highlightLint={this.props.highlightLint}
439
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
440
- previewURL={this.props.previewURL}
441
- // TODO(CP-4838): what should be passed here?
442
- contentPaths={[]}
443
- />
444
- );
445
- },
446
- this,
447
- );
448
-
449
- return (
450
- <div className="perseus-hints-editor perseus-editor-table">
451
- {hintElems}
452
- <div className="perseus-editor-row">
453
- <div className="add-hint-container perseus-editor-left-cell">
454
- <button
455
- type="button"
456
- className="add-hint simple-button orange"
457
- onClick={this.addHint}
458
- >
459
- <InlineIcon {...iconPlus} /> Add a hint
460
- </button>
461
- </div>
462
- </div>
463
- </div>
464
- );
465
- /* eslint-enable max-len */
466
- }
467
- }
468
-
469
- export default CombinedHintsEditor;
package/src/i18n.ts DELETED
@@ -1,140 +0,0 @@
1
- /**
2
- * Functions for extracting data from items for use in i18n.
3
- */
4
- import {traverse, MultiItems, PerseusMarkdown} from "@khanacademy/perseus";
5
- import _ from "underscore";
6
-
7
- const {findContentNodesInItem, findHintNodesInItem, inferItemShape} =
8
- MultiItems;
9
-
10
- // Takes a renderer content and parses the markdown for images
11
- function findImagesInContent(content: any, images: Array<any>) {
12
- // @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
13
- const parsed = PerseusMarkdown.parse(content);
14
-
15
- PerseusMarkdown.traverseContent(parsed, function (node) {
16
- if (node.type === "image") {
17
- images.push(node.target);
18
- }
19
- });
20
- }
21
-
22
- // Background images in some widgets are annoying to deal with because
23
- // sometimes the objects aren't full when there isn't an image. So, we do some
24
- // extra checking to make sure we don't cause an error or push an empty image.
25
- function handleBackgroundImage(graph, images: Array<any>) {
26
- if (graph && graph.backgroundImage && graph.backgroundImage.url) {
27
- images.push(graph.backgroundImage.url);
28
- }
29
- }
30
-
31
- // The callback called for each widget. We check each of the areas of each
32
- // widget where they contain a renderer for images by calling
33
- // findImagesInContent. We don't have to recurse through child widgets, because
34
- // traverseRendererDeep does that for us.
35
- function widgetCallback(widgetInfo: any, images: Array<any>) {
36
- if (!widgetInfo.options) {
37
- return;
38
- }
39
-
40
- // TODO(emily/aria): Move this into the widget files, so we don't have the
41
- // logic out here.
42
- if (widgetInfo.type === "categorizer") {
43
- _.each(widgetInfo.options.items, function (item) {
44
- findImagesInContent(item, images);
45
- });
46
- _.each(widgetInfo.options.categories, function (category) {
47
- findImagesInContent(category, images);
48
- });
49
- } else if (widgetInfo.type === "image") {
50
- findImagesInContent(widgetInfo.options.title, images);
51
- findImagesInContent(widgetInfo.options.caption, images);
52
- } else if (widgetInfo.type === "matcher") {
53
- _.each(widgetInfo.options.left, function (option) {
54
- findImagesInContent(option, images);
55
- });
56
- _.each(widgetInfo.options.right, function (option) {
57
- findImagesInContent(option, images);
58
- });
59
- _.each(widgetInfo.options.labels, function (label) {
60
- findImagesInContent(label, images);
61
- });
62
- } else if (widgetInfo.type === "matrix") {
63
- findImagesInContent(widgetInfo.options.prefix, images);
64
- findImagesInContent(widgetInfo.options.suffix, images);
65
- } else if (widgetInfo.type === "orderer") {
66
- _.each(widgetInfo.options.options, function (option) {
67
- findImagesInContent(option.content, images);
68
- });
69
- } else if (widgetInfo.type === "passage") {
70
- findImagesInContent(widgetInfo.options.passageTitle, images);
71
- } else if (widgetInfo.type === "radio") {
72
- _.each(widgetInfo.options.choices, function (choice) {
73
- findImagesInContent(choice.content, images);
74
- });
75
- } else if (widgetInfo.type === "sorter") {
76
- _.each(widgetInfo.options.correct, function (option) {
77
- findImagesInContent(option, images);
78
- });
79
- } else if (widgetInfo.type === "table") {
80
- _.each(widgetInfo.options.headers, function (header) {
81
- findImagesInContent(header, images);
82
- });
83
- }
84
-
85
- if (widgetInfo.type === "grapher") {
86
- handleBackgroundImage(widgetInfo.options.graph, images);
87
- } else if (widgetInfo.type === "image") {
88
- handleBackgroundImage(widgetInfo.options, images);
89
- } else if (widgetInfo.type === "interactive-graph") {
90
- handleBackgroundImage(widgetInfo.options, images);
91
- } else if (widgetInfo.type === "measurer" && widgetInfo.options.image) {
92
- images.push(widgetInfo.options.image.url);
93
- } else if (widgetInfo.type === "plotter") {
94
- images.push(widgetInfo.options.picUrl);
95
- }
96
- }
97
-
98
- function findImagesInRenderers(renderers) {
99
- const images = [];
100
-
101
- _.each(renderers, (renderer) => {
102
- traverse(
103
- renderer,
104
- (content) => {
105
- findImagesInContent(content, images);
106
- },
107
- (widget) => widgetCallback(widget, images),
108
- );
109
- });
110
-
111
- return images;
112
- }
113
-
114
- // Calls findImagesInContent on all of the different content areas for
115
- // assessment items
116
- function findImagesInItemData(itemData: any): any {
117
- let renderers = [];
118
- if (itemData._multi) {
119
- const shape = inferItemShape(itemData);
120
- // @ts-expect-error - TS2345 - Argument of type 'ContentNode' is not assignable to parameter of type 'never'.
121
- findContentNodesInItem(itemData, shape, (node) => renderers.push(node));
122
- // @ts-expect-error - TS2345 - Argument of type 'HintNode' is not assignable to parameter of type 'never'.
123
- findHintNodesInItem(itemData, shape, (node) => renderers.push(node));
124
- } else {
125
- // @ts-expect-error - TS2322 - Type 'any' is not assignable to type 'never'. | TS2322 - Type 'any' is not assignable to type 'never'.
126
- renderers = [itemData.question, ...itemData.hints];
127
- }
128
- return findImagesInRenderers(renderers);
129
- }
130
-
131
- // Calls findImagesInContent on all of the different content areas for
132
- // articles
133
- function findImagesInArticles(perseusContent: any): any {
134
- return findImagesInRenderers(perseusContent);
135
- }
136
-
137
- export default {
138
- findImagesInArticles: findImagesInArticles,
139
- findImagesInItemData: findImagesInItemData,
140
- };