@khanacademy/perseus-editor 4.1.5 → 4.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.
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,188 +0,0 @@
1
- /**
2
- * Displays the given content in an iframe, isolating it from the parent page
3
- *
4
- * To simulate the environment of content rendered by itself, content previews
5
- * are rendered inside iframes, where components such as the math keypad work
6
- * because the body of the document is not the body of the editor. To make this
7
- * work, this component renders an iframe and can communicate objects to it
8
- * through postMessage. The recipient then needs to listen for these messages
9
- * and pull out the appropriate object stored in the parent's iframeDataStore
10
- * to get the data to render. When the iframe is loaded, it's javascript calls
11
- * its requestIframeData function in the parent, which triggers the parent to
12
- * send the current data.
13
- */
14
- import {Log} from "@khanacademy/perseus";
15
- import * as React from "react";
16
-
17
- let nextIframeID = 0;
18
- const requestIframeData: Record<string, any> = {};
19
- const updateIframeHeight: Record<string, any> = {};
20
- // @ts-expect-error - TS2339 - Property 'iframeDataStore' does not exist on type 'Window & typeof globalThis'.
21
- window.iframeDataStore = {};
22
-
23
- // This is called once after Perseus is loaded and the iframe
24
- // is ready to render content, then twice a second afterwards
25
- // to capture the result of animations.
26
- window.addEventListener("message", (event) => {
27
- if (typeof event.data === "string") {
28
- // In Perseus, we expect the callback to exist, as it is added by
29
- // `IframeContentRenderer.componentDidMount()`. Unfortunately, this
30
- // event listener also gets added in Manticore (since we include Perseus
31
- // from there), and Crowdin fires its own "message" events. So we'll
32
- // just have to ignore the event when we can't find the callback.
33
- const callback = requestIframeData[event.data];
34
- if (callback) {
35
- callback();
36
- }
37
- } else if (event.data.id) {
38
- if (event.data.height !== undefined) {
39
- updateIframeHeight[event.data.id](event.data.height);
40
- } else if (event.data.lintWarnings) {
41
- // This is a lint report being sent back from the linter.
42
- // TODO:
43
- // We'll want to display the number of warnings in the HUD.
44
- // But for now, we just log it to the console
45
- Log.log("LINTER REPORT", {
46
- lintWarnings: JSON.stringify(event.data.lintWarnings),
47
- });
48
- }
49
- }
50
- });
51
-
52
- type Props = {
53
- // The HTML content to render to the iframe
54
- // content?: string,
55
-
56
- // The URL that the iframe should load
57
- url: string;
58
- // The data-* suffix for passing information to the iframe's JS
59
- datasetKey: string;
60
- // The value of the data-* attribute
61
- datasetValue: any;
62
- // Whether to make the iframe's height match its content's height,
63
- // used to prevent scrolling inside the iframe.
64
- seamless: boolean;
65
- };
66
-
67
- class IframeContentRenderer extends React.Component<Props> {
68
- _frame: HTMLIFrameElement | null | undefined;
69
- container = React.createRef<HTMLDivElement>();
70
-
71
- // @ts-expect-error - TS2564 - Property '_isMounted' has no initializer and is not definitely assigned in the constructor.
72
- _isMounted: boolean;
73
- _lastData: any;
74
- // @ts-expect-error - TS2564 - Property '_lastHeight' has no initializer and is not definitely assigned in the constructor.
75
- _lastHeight: number;
76
- // @ts-expect-error - TS2564 - Property 'iframeID' has no initializer and is not definitely assigned in the constructor.
77
- iframeID: number;
78
-
79
- componentDidMount() {
80
- // TODO(scottgrant): This is a hack to remove the deprecated call to
81
- // this.isMounted() but is still considered an anti-pattern.
82
- this._isMounted = true;
83
-
84
- this.iframeID = nextIframeID;
85
- nextIframeID++;
86
-
87
- this._prepareFrame();
88
- requestIframeData[this.iframeID] = () => {
89
- this.sendNewData(this._lastData);
90
- };
91
-
92
- updateIframeHeight[this.iframeID] = (height: any) => {
93
- this._lastHeight = height;
94
- if (
95
- this._isMounted &&
96
- this.props.seamless &&
97
- this.container.current
98
- ) {
99
- this.container.current.style.height = height + "px";
100
- }
101
- };
102
- }
103
-
104
- shouldComponentUpdate(nextProps: Props): boolean {
105
- return (
106
- nextProps.datasetValue !== this.props.datasetValue ||
107
- nextProps.seamless !== this.props.seamless
108
- );
109
- }
110
-
111
- componentDidUpdate(prevProps: Props) {
112
- if (this.container.current) {
113
- if (!this.props.seamless) {
114
- this.container.current.style.height = "100%";
115
- } else {
116
- this.container.current.style.height = this._lastHeight + "px";
117
- }
118
- }
119
-
120
- if (prevProps.datasetValue !== this.props.datasetValue) {
121
- // Not just a change in seamless
122
- this._prepareFrame();
123
- }
124
- }
125
-
126
- componentWillUnmount() {
127
- requestIframeData[this.iframeID] = null;
128
- updateIframeHeight[this.iframeID] = null;
129
-
130
- this._isMounted = false;
131
- }
132
-
133
- _prepareFrame() {
134
- // Don't initialize the iframe until the page has loaded
135
- if (this._frame) {
136
- this.container.current?.removeChild(this._frame);
137
- }
138
-
139
- const frame = document.createElement("iframe");
140
- frame.style.width = "100%";
141
- frame.style.height = "100%";
142
- frame.src = this.props.url;
143
-
144
- if (this.props.datasetKey) {
145
- // If the user has specified a data-* attribute to place on the
146
- // iframe, we set it here. Right now, this is used to
147
- // communicate if the iframe should be enabling touch emulation.
148
- frame.dataset[this.props.datasetKey] = this.props.datasetValue;
149
- }
150
- frame.dataset.id = String(this.iframeID);
151
-
152
- if (this.props.seamless) {
153
- // The seamless prop is the same as the "nochrome" prop that
154
- // gets passed to DeviceFramer. If it is set, then we're going
155
- // to be displaying editor previews and want to leave some room
156
- // for lint indicators in the right margin. We use the dataset
157
- // as above to pass this information on to the perseus-frame
158
- // component inside the iframe
159
- frame.dataset.lintGutter = "true";
160
- }
161
-
162
- this.container.current?.appendChild(frame);
163
-
164
- this._frame = frame;
165
- }
166
-
167
- sendNewData(data: any) {
168
- const frame = this._frame;
169
- if (this._isMounted && data && frame?.contentWindow) {
170
- this._lastData = data;
171
-
172
- // We can't use JSON.stringify/parse for this because the apiOptions
173
- // includes the functions GroupMetadataEditor, groupAnnotator,
174
- // onFocusChange, and onInputError.
175
- // @ts-expect-error - TS2339 - Property 'iframeDataStore' does not exist on type 'Window & typeof globalThis'.
176
- window.iframeDataStore[this.iframeID] = data;
177
- frame.contentWindow.postMessage(this.iframeID, "*");
178
- }
179
- }
180
-
181
- render(): React.ReactNode {
182
- return (
183
- <div ref={this.container} style={{width: "100%", height: "100%"}} />
184
- );
185
- }
186
- }
187
-
188
- export default IframeContentRenderer;
package/src/index.ts DELETED
@@ -1,30 +0,0 @@
1
- export {libVersion} from "./version";
2
-
3
- export {default as ArticleEditor} from "./article-editor";
4
- export {default as DeviceFramer} from "./components/device-framer";
5
- export {default as ViewportResizer} from "./components/viewport-resizer";
6
- export {default as ArticleDiff} from "./diffs/article-diff";
7
- export {default as ItemDiff} from "./diffs/item-diff";
8
- export {default as StructuredItemDiff} from "./diffs/structured-item-diff";
9
- export {default as EditorPage} from "./editor-page";
10
- export {default as Editor} from "./editor";
11
- export {default as i18n} from "./i18n";
12
- export {default as IframeContentRenderer} from "./iframe-content-renderer";
13
- export {default as MultiRendererEditor} from "./multirenderer-editor";
14
- export {default as StatefulArticleEditor} from "./stateful-article-editor";
15
- export {default as StatefulEditorPage} from "./stateful-editor-page";
16
-
17
- import "./styles/perseus-editor.less";
18
-
19
- // eslint-disable-next-line import/order
20
- import {Widgets} from "@khanacademy/perseus";
21
- import AllEditors from "./all-editors";
22
- import AllWidgets from "./all-widgets";
23
-
24
- Widgets.registerEditors(AllEditors);
25
- Widgets.registerWidgets(AllWidgets);
26
-
27
- Widgets.replaceEditor("transformer", "deprecated-standin");
28
- Widgets.replaceWidget("transformer", "deprecated-standin");
29
-
30
- export {AllEditors, AllWidgets};
@@ -1,158 +0,0 @@
1
- import {itemDataVersion} from "@khanacademy/perseus";
2
- import * as React from "react";
3
- import _ from "underscore";
4
-
5
- import DeviceFramer from "./components/device-framer";
6
- import Editor from "./editor";
7
- import IframeContentRenderer from "./iframe-content-renderer";
8
- import ItemExtrasEditor from "./item-extras-editor";
9
-
10
- import type {
11
- APIOptions,
12
- ImageUploader,
13
- ChangeHandler,
14
- } from "@khanacademy/perseus";
15
-
16
- const ITEM_DATA_VERSION = itemDataVersion;
17
-
18
- type Props = {
19
- apiOptions?: APIOptions;
20
- deviceType?: string;
21
- gradeMessage?: string;
22
- imageUploader?: ImageUploader;
23
- wasAnswered?: boolean;
24
- question?: any;
25
- answerArea?: any;
26
- // URL of the route to show on initial load of the preview frames.
27
- previewURL: string;
28
- onChange: ChangeHandler;
29
- // The content ID of the AssessmentItem being edited. It may not be set
30
- // for non-content library exercise questions.
31
- itemId?: string;
32
- };
33
-
34
- class ItemEditor extends React.Component<Props> {
35
- static defaultProps: {
36
- answerArea: Record<any, any>;
37
- onChange: () => void;
38
- question: Record<any, any>;
39
- } = {
40
- onChange: () => {},
41
- question: {},
42
- answerArea: {},
43
- };
44
-
45
- frame = React.createRef<IframeContentRenderer>();
46
- questionEditor = React.createRef<Editor>();
47
- itemExtrasEditor = React.createRef<ItemExtrasEditor>();
48
-
49
- // Notify the parent that the question or answer area has been updated.
50
- updateProps: ChangeHandler = (newProps, cb, silent) => {
51
- const props = _(this.props).pick("question", "answerArea");
52
-
53
- this.props.onChange(_(props).extend(newProps), cb, silent);
54
- };
55
-
56
- triggerPreviewUpdate: (newData?: any) => void = (newData: any) => {
57
- this.frame.current?.sendNewData(newData);
58
- };
59
-
60
- handleEditorChange: ChangeHandler = (newProps, cb, silent) => {
61
- const question = _.extend({}, this.props.question, newProps);
62
- this.updateProps({question}, cb, silent);
63
- };
64
-
65
- handleItemExtrasChange: ChangeHandler = (newProps, cb, silent) => {
66
- const answerArea = _.extend({}, this.props.answerArea, newProps);
67
- this.updateProps({answerArea}, cb, silent);
68
- };
69
-
70
- getSaveWarnings: () => any = () => {
71
- return this.questionEditor.current?.getSaveWarnings();
72
- };
73
-
74
- serialize: (options?: any) => {
75
- answerArea: any;
76
- itemDataVersion: {
77
- major: number;
78
- minor: number;
79
- };
80
- question: any;
81
- } = (options: any) => {
82
- return {
83
- question: this.questionEditor.current?.serialize(options),
84
- answerArea: this.itemExtrasEditor.current?.serialize(),
85
- itemDataVersion: ITEM_DATA_VERSION,
86
- };
87
- };
88
-
89
- render(): React.ReactNode {
90
- const isMobile =
91
- this.props.deviceType === "phone" ||
92
- this.props.deviceType === "tablet";
93
- return (
94
- <div className="perseus-editor-table">
95
- <div className="perseus-editor-row perseus-question-container">
96
- <div className="perseus-editor-left-cell">
97
- <div className="pod-title">Question</div>
98
- <Editor
99
- ref={this.questionEditor}
100
- // Using the AssessmentItem content ID as the key
101
- // ensures that when the user navigates to another
102
- // item in the Sidebar, the question editor is
103
- // re-rendered by React.
104
- key={this.props.itemId}
105
- placeholder="Type your question here..."
106
- className="perseus-question-editor"
107
- imageUploader={this.props.imageUploader}
108
- onChange={this.handleEditorChange}
109
- apiOptions={this.props.apiOptions}
110
- showWordCount={true}
111
- {...this.props.question}
112
- />
113
- </div>
114
-
115
- <div className="perseus-editor-right-cell">
116
- <div id="problemarea">
117
- <DeviceFramer
118
- deviceType={this.props.deviceType}
119
- nochrome={true}
120
- >
121
- <IframeContentRenderer
122
- ref={this.frame}
123
- key={this.props.deviceType}
124
- datasetKey="mobile"
125
- datasetValue={isMobile}
126
- seamless={true}
127
- url={this.props.previewURL}
128
- />
129
- </DeviceFramer>
130
- <div
131
- id="hintsarea"
132
- className="hintsarea"
133
- style={{display: "none"}}
134
- />
135
- </div>
136
- </div>
137
- </div>
138
-
139
- <div className="perseus-editor-row perseus-answer-container">
140
- <div className="perseus-editor-left-cell">
141
- <div className="pod-title">Question extras</div>
142
- <ItemExtrasEditor
143
- ref={this.itemExtrasEditor}
144
- onChange={this.handleItemExtrasChange}
145
- {...this.props.answerArea}
146
- />
147
- </div>
148
-
149
- <div className="perseus-editor-right-cell">
150
- <div id="answer_area" />
151
- </div>
152
- </div>
153
- </div>
154
- );
155
- }
156
- }
157
-
158
- export default ItemEditor;
@@ -1,230 +0,0 @@
1
- import {components, ItemExtras} from "@khanacademy/perseus";
2
- import * as React from "react";
3
-
4
- import type {PerseusAnswerArea} from "@khanacademy/perseus";
5
-
6
- const {InfoTip} = components;
7
-
8
- type Props = PerseusAnswerArea & {
9
- onChange: (props: Partial<PerseusAnswerArea>) => void;
10
- };
11
-
12
- type State = {
13
- financialCalculatorOptionsExpanded: boolean;
14
- };
15
-
16
- class ItemExtrasEditor extends React.Component<Props, State> {
17
- static defaultProps: PerseusAnswerArea = {
18
- calculator: false,
19
- chi2Table: false,
20
- financialCalculatorMonthlyPayment: false,
21
- financialCalculatorTotalAmount: false,
22
- financialCalculatorTimeToPayOff: false,
23
- periodicTable: false,
24
- periodicTableWithKey: false,
25
- tTable: false,
26
- zTable: false,
27
- };
28
-
29
- state = {
30
- financialCalculatorOptionsExpanded: false,
31
- };
32
-
33
- componentDidUpdate(prevProps: Readonly<Props>): void {
34
- // If no financial calculator options are checked, uncheck the
35
- // financial calculator option.
36
- if (
37
- this.state.financialCalculatorOptionsExpanded &&
38
- !this.props.financialCalculatorMonthlyPayment &&
39
- !this.props.financialCalculatorTotalAmount &&
40
- !this.props.financialCalculatorTimeToPayOff
41
- ) {
42
- this.setState({financialCalculatorOptionsExpanded: false});
43
- }
44
- }
45
-
46
- serialize: () => PerseusAnswerArea = () => {
47
- const data = {...ItemExtrasEditor.defaultProps};
48
- for (const key of ItemExtras) {
49
- data[key] = !!this.props[key];
50
- }
51
- return data;
52
- };
53
-
54
- render(): React.ReactNode {
55
- return (
56
- <div className="perseus-answer-editor">
57
- <div className="perseus-answer-options">
58
- <ItemExtraCheckbox
59
- label="Show calculator:"
60
- infoTip="Use the calculator when completing difficult calculations is NOT the intent of the question. DON’T use the calculator when testing the student’s ability to complete different types of computations."
61
- checked={this.props.calculator}
62
- onChange={(e) => {
63
- this.props.onChange({
64
- calculator: e.target.checked,
65
- });
66
- }}
67
- />
68
-
69
- <ItemExtraCheckbox
70
- label="Show financial calculator:"
71
- infoTip="This provides the student with the ability to view a financial calculator, e.g., for answering financial questions. Once checked, requires at least one of the three options below to be checked."
72
- checked={this.state.financialCalculatorOptionsExpanded}
73
- onChange={(e) => {
74
- this.setState({
75
- financialCalculatorOptionsExpanded:
76
- e.target.checked,
77
- });
78
- // If the financial calculator is unchecked,
79
- // this needs to be reset. All checked by
80
- // default.
81
- this.props.onChange({
82
- financialCalculatorMonthlyPayment:
83
- e.target.checked,
84
- financialCalculatorTotalAmount:
85
- e.target.checked,
86
- financialCalculatorTimeToPayOff:
87
- e.target.checked,
88
- });
89
- }}
90
- />
91
-
92
- {this.state.financialCalculatorOptionsExpanded && (
93
- <>
94
- <ItemExtraCheckbox
95
- label="Include monthly payment:"
96
- infoTip="This provides the student with the ability to view a monthly payment calculator; e.g., given a loan amount, interest rate, and term, what is the monthly payment?"
97
- checked={
98
- this.props.financialCalculatorMonthlyPayment
99
- }
100
- onChange={(e) => {
101
- this.props.onChange({
102
- financialCalculatorMonthlyPayment:
103
- e.target.checked,
104
- });
105
- }}
106
- indent
107
- />
108
- <ItemExtraCheckbox
109
- label="Include total amount:"
110
- infoTip="This provides the student with the ability to view a total amount calculator; e.g., given a monthly payment, interest rate, and term, what is the total amount to be paid?"
111
- checked={
112
- this.props.financialCalculatorTotalAmount
113
- }
114
- onChange={(e) => {
115
- this.props.onChange({
116
- financialCalculatorTotalAmount:
117
- e.target.checked,
118
- });
119
- }}
120
- indent
121
- />
122
- <ItemExtraCheckbox
123
- label="Include time-to-pay-off:"
124
- infoTip="This provides the student with the ability to view a time to pay off calculator; e.g., given a loan amount, interest rate, and monthly payment, how long will it take to pay off the loan?"
125
- checked={
126
- this.props.financialCalculatorTimeToPayOff
127
- }
128
- onChange={(e) => {
129
- this.props.onChange({
130
- financialCalculatorTimeToPayOff:
131
- e.target.checked,
132
- });
133
- }}
134
- indent
135
- />
136
- </>
137
- )}
138
-
139
- <ItemExtraCheckbox
140
- label="Show periodic table:"
141
- infoTip="This provides the student with the ability to view a periodic table of the elements, e.g., for answering chemistry questions."
142
- checked={this.props.periodicTable}
143
- onChange={(e) => {
144
- this.props.onChange({
145
- periodicTable: e.target.checked,
146
- // If the periodic table is unchecked,
147
- // this needs to be reset. If table is
148
- // checked, it should already be false.
149
- periodicTableWithKey: false,
150
- });
151
- }}
152
- />
153
-
154
- {this.props.periodicTable && (
155
- <ItemExtraCheckbox
156
- label="Include key/legend with periodic table:"
157
- infoTip="Include a key for HS courses; omit for AP chemistry."
158
- checked={this.props.periodicTableWithKey}
159
- onChange={(e) => {
160
- this.props.onChange({
161
- periodicTableWithKey: e.target.checked,
162
- });
163
- }}
164
- indent
165
- />
166
- )}
167
-
168
- <ItemExtraCheckbox
169
- label="Show z table (statistics):"
170
- infoTip="This provides the student with the ability to view a table of critical values for the z distribution, e.g. for answering statistics questions."
171
- checked={this.props.zTable}
172
- onChange={(e) => {
173
- this.props.onChange({
174
- zTable: e.target.checked,
175
- });
176
- }}
177
- />
178
-
179
- <ItemExtraCheckbox
180
- label="Show t table (statistics):"
181
- infoTip="This provides the student with the ability to view a table of critical values for the Student's t distribution, e.g. for answering statistics questions."
182
- checked={this.props.tTable}
183
- onChange={(e) => {
184
- this.props.onChange({
185
- tTable: e.target.checked,
186
- });
187
- }}
188
- />
189
-
190
- <ItemExtraCheckbox
191
- label="Show chi-squared table (statistics):"
192
- infoTip="This provides the student with the ability to view a table of critical values for the chi-squared distribution, e.g. for answering statistics questions."
193
- checked={this.props.chi2Table}
194
- onChange={(e) => {
195
- this.props.onChange({
196
- chi2Table: e.target.checked,
197
- });
198
- }}
199
- />
200
- </div>
201
- </div>
202
- );
203
- }
204
- }
205
-
206
- const ItemExtraCheckbox = (props: {
207
- label: string;
208
- infoTip: string;
209
- checked: boolean;
210
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
211
- indent?: boolean;
212
- }) => (
213
- <div
214
- style={{
215
- marginLeft: props.indent ? "10px" : "0px",
216
- }}
217
- >
218
- <label>
219
- {props.label}
220
- <input
221
- type="checkbox"
222
- checked={props.checked}
223
- onChange={props.onChange}
224
- />
225
- </label>
226
- <InfoTip>{props.infoTip}</InfoTip>
227
- </div>
228
- );
229
-
230
- export default ItemExtrasEditor;
@@ -1,73 +0,0 @@
1
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
2
- /* vim: set ts=2 et sw=2 tw=80: */
3
-
4
- /*************************************************************
5
- *
6
- * KaTeX mhchem.js
7
- *
8
- * This file implements a KaTeX version of mhchem version 3.3.0.
9
- * It is adapted from MathJax/extensions/TeX/mhchem.js
10
- * It differs from the MathJax version as follows:
11
- * 1. The interface is changed so that it can be called from KaTeX, not MathJax.
12
- * 2. \rlap and \llap are replaced with \mathrlap and \mathllap.
13
- * 3. Four lines of code are edited in order to use \raisebox instead of \raise.
14
- * 4. The reaction arrow code is simplified. All reaction arrows are rendered
15
- * using KaTeX extensible arrows instead of building non-extensible arrows.
16
- * 5. \tripledash vertical alignment is slightly adjusted.
17
- *
18
- * This code, as other KaTeX code, is released under the MIT license.
19
- *
20
- * /*************************************************************
21
- *
22
- * MathJax/extensions/TeX/mhchem.js
23
- *
24
- * Implements the \ce command for handling chemical formulas
25
- * from the mhchem LaTeX package.
26
- *
27
- * ---------------------------------------------------------------------
28
- *
29
- * Copyright (c) 2011-2015 The MathJax Consortium
30
- * Copyright (c) 2015-2018 Martin Hensel
31
- *
32
- * Licensed under the Apache License, Version 2.0 (the "License");
33
- * you may not use this file except in compliance with the License.
34
- * You may obtain a copy of the License at
35
- *
36
- * http://www.apache.org/licenses/LICENSE-2.0
37
- *
38
- * Unless required by applicable law or agreed to in writing, software
39
- * distributed under the License is distributed on an "AS IS" BASIS,
40
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41
- * See the License for the specific language governing permissions and
42
- * limitations under the License.
43
- */
44
-
45
- //
46
- // Coding Style
47
- // - use '' for identifiers that can by minified/uglified
48
- // - use "" for strings that need to stay untouched
49
-
50
- // version: "3.3.0" for MathJax and KaTeX
51
-
52
- import katex from "katex";
53
-
54
- import {chemParse} from "./parser";
55
-
56
- // Add \ce, \pu, and \tripledash to the KaTeX macros.
57
-
58
- katex.__defineMacro("\\ce", function (context) {
59
- return chemParse(context.consumeArgs(1)[0], "ce");
60
- });
61
-
62
- katex.__defineMacro("\\pu", function (context) {
63
- return chemParse(context.consumeArgs(1)[0], "pu");
64
- });
65
-
66
- // Needed for \bond for the ~ forms
67
- // Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not
68
- // a mathematical minus, U+2212. So we need that extra 0.56.
69
- katex.__defineMacro(
70
- "\\tripledash",
71
- "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" +
72
- "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}",
73
- );