@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.
- package/dist/es/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -6
- package/.babelrc.js +0 -8
- package/.eslintrc.js +0 -12
- package/CHANGELOG.md +0 -1155
- package/src/README.md +0 -7
- package/src/__stories__/editor-page.stories.tsx +0 -65
- package/src/__stories__/editor.stories.tsx +0 -134
- package/src/__stories__/item-editor.stories.tsx +0 -41
- package/src/__stories__/tex-error-view.stories.tsx +0 -26
- package/src/__testdata__/input-number.testdata.ts +0 -27
- package/src/__tests__/editor.test.tsx +0 -142
- package/src/__tests__/hint-editor.test.tsx +0 -83
- package/src/__tests__/i18n.test.ts +0 -501
- package/src/__tests__/integration.test.ts +0 -5
- package/src/__tests__/item-extras-editor.test.tsx +0 -85
- package/src/__tests__/traversal.test.ts +0 -377
- package/src/all-editors.test.ts +0 -16
- package/src/all-editors.ts +0 -83
- package/src/all-widgets.ts +0 -7
- package/src/article-editor.tsx +0 -438
- package/src/components/__stories__/blur-input.stories.tsx +0 -22
- package/src/components/__stories__/section-control-button.stories.tsx +0 -26
- package/src/components/__tests__/blur-input.test.tsx +0 -67
- package/src/components/blur-input.tsx +0 -69
- package/src/components/checkbox.tsx +0 -194
- package/src/components/device-framer.tsx +0 -90
- package/src/components/drag-target.tsx +0 -87
- package/src/components/dropdown-option.tsx +0 -311
- package/src/components/form-wrapped-text-field.tsx +0 -245
- package/src/components/graph-points-count-selector.tsx +0 -31
- package/src/components/graph-settings.tsx +0 -627
- package/src/components/graph-type-selector.tsx +0 -31
- package/src/components/hover-behavior.ts +0 -177
- package/src/components/json-editor.tsx +0 -121
- package/src/components/link.ts +0 -173
- package/src/components/section-control-button.tsx +0 -53
- package/src/components/segment-count-selector.tsx +0 -27
- package/src/components/simple-button.tsx +0 -85
- package/src/components/sortable.tsx +0 -187
- package/src/components/util.ts +0 -38
- package/src/components/viewport-resizer.tsx +0 -72
- package/src/components/widget-editor.tsx +0 -222
- package/src/components/widget-select.tsx +0 -48
- package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
- package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
- package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
- package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
- package/src/diffs/__tests__/split-diff.test.ts +0 -33
- package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
- package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
- package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
- package/src/diffs/article-diff.tsx +0 -69
- package/src/diffs/item-diff.tsx +0 -76
- package/src/diffs/renderer-diff.tsx +0 -137
- package/src/diffs/split-diff.ts +0 -31
- package/src/diffs/string-array-diff.ts +0 -74
- package/src/diffs/structured-item-diff.tsx +0 -275
- package/src/diffs/tags-diff.tsx +0 -49
- package/src/diffs/text-diff.tsx +0 -193
- package/src/diffs/widget-diff-performer.ts +0 -69
- package/src/diffs/widget-diff.tsx +0 -290
- package/src/editor-page.tsx +0 -325
- package/src/editor.tsx +0 -1099
- package/src/hint-editor.tsx +0 -469
- package/src/i18n.ts +0 -140
- package/src/iframe-content-renderer.tsx +0 -188
- package/src/index.ts +0 -30
- package/src/item-editor.tsx +0 -158
- package/src/item-extras-editor.tsx +0 -230
- package/src/katex-mhchem/index.js +0 -73
- package/src/katex-mhchem/parser.js +0 -2659
- package/src/multirenderer-editor.tsx +0 -1061
- package/src/stateful-article-editor.tsx +0 -173
- package/src/stateful-editor-page.tsx +0 -88
- package/src/styles/perseus-editor.less +0 -1321
- package/src/testing-widgets.ts +0 -11
- package/src/tex-error-view.tsx +0 -90
- package/src/util/points.test.ts +0 -24
- package/src/util/points.ts +0 -13
- package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
- package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
- package/src/version.ts +0 -10
- package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
- package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
- package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
- package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
- package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
- package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
- package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
- package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
- package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
- package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
- package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
- package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
- package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
- package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
- package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
- package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
- package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
- package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
- package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
- package/src/widgets/categorizer-editor.tsx +0 -104
- package/src/widgets/cs-program-editor.tsx +0 -256
- package/src/widgets/definition-editor.tsx +0 -77
- package/src/widgets/deprecated-standin-editor.tsx +0 -29
- package/src/widgets/dropdown-editor.tsx +0 -211
- package/src/widgets/example-graphie-widget-editor.tsx +0 -70
- package/src/widgets/example-graphie-widget.tsx +0 -172
- package/src/widgets/example-widget-editor.tsx +0 -62
- package/src/widgets/example-widget.tsx +0 -154
- package/src/widgets/explanation-editor.tsx +0 -92
- package/src/widgets/expression-editor.tsx +0 -557
- package/src/widgets/graded-group-editor.tsx +0 -161
- package/src/widgets/graded-group-set-editor.tsx +0 -104
- package/src/widgets/grapher-editor.tsx +0 -155
- package/src/widgets/group-editor.tsx +0 -83
- package/src/widgets/iframe-editor.tsx +0 -202
- package/src/widgets/image-editor.tsx +0 -367
- package/src/widgets/input-number-editor.tsx +0 -288
- package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
- package/src/widgets/interaction-editor/function-editor.tsx +0 -108
- package/src/widgets/interaction-editor/index.ts +0 -3
- package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
- package/src/widgets/interaction-editor/label-editor.tsx +0 -87
- package/src/widgets/interaction-editor/line-editor.tsx +0 -125
- package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
- package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
- package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
- package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
- package/src/widgets/interaction-editor/point-editor.tsx +0 -72
- package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
- package/src/widgets/interactive-graph-editor.tsx +0 -571
- package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
- package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
- package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
- package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
- package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
- package/src/widgets/label-image/answer-choices.tsx +0 -231
- package/src/widgets/label-image/behavior.tsx +0 -122
- package/src/widgets/label-image/marker.tsx +0 -290
- package/src/widgets/label-image/question-markers.tsx +0 -176
- package/src/widgets/label-image/select-image.tsx +0 -81
- package/src/widgets/label-image-editor.tsx +0 -252
- package/src/widgets/lights-puzzle-editor.tsx +0 -278
- package/src/widgets/matcher-editor.tsx +0 -149
- package/src/widgets/matrix-editor.tsx +0 -156
- package/src/widgets/measurer-editor.tsx +0 -253
- package/src/widgets/molecule-editor.tsx +0 -64
- package/src/widgets/number-line-editor.tsx +0 -512
- package/src/widgets/numeric-input-editor.tsx +0 -536
- package/src/widgets/orderer-editor.tsx +0 -172
- package/src/widgets/passage-editor.tsx +0 -117
- package/src/widgets/passage-ref-editor.tsx +0 -80
- package/src/widgets/passage-ref-target-editor.tsx +0 -49
- package/src/widgets/plotter-editor.tsx +0 -542
- package/src/widgets/radio/editor.tsx +0 -398
- package/src/widgets/reaction-diagram-editor.tsx +0 -131
- package/src/widgets/sequence-editor.tsx +0 -205
- package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
- package/src/widgets/simple-markdown-tester.tsx +0 -92
- package/src/widgets/simulator-editor.tsx +0 -146
- package/src/widgets/sorter-editor.tsx +0 -103
- package/src/widgets/table-editor.tsx +0 -164
- package/src/widgets/unit-editor.tsx +0 -299
- package/src/widgets/video-editor.tsx +0 -73
- package/tsconfig-build.json +0 -22
- package/tsconfig-build.tsbuildinfo +0 -1
package/src/diffs/tags-diff.tsx
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A side by side diff view for general passage layout tags.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
|
|
7
|
-
import TextDiff from "./text-diff";
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
afterOnly: ReadonlyArray<string>;
|
|
11
|
-
beforeOnly: ReadonlyArray<string>;
|
|
12
|
-
intersection: ReadonlyArray<string>;
|
|
13
|
-
showSeparator: boolean;
|
|
14
|
-
title: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
class TagsDiff extends React.Component<Props> {
|
|
18
|
-
static defaultProps: {
|
|
19
|
-
afterOnly: ReadonlyArray<any>;
|
|
20
|
-
beforeOnly: ReadonlyArray<any>;
|
|
21
|
-
showSeparator: boolean;
|
|
22
|
-
title: string;
|
|
23
|
-
} = {
|
|
24
|
-
afterOnly: [],
|
|
25
|
-
beforeOnly: [],
|
|
26
|
-
showSeparator: false,
|
|
27
|
-
title: "Question tags",
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
render(): React.ReactNode {
|
|
31
|
-
const {afterOnly, beforeOnly, intersection, showSeparator} = this.props;
|
|
32
|
-
|
|
33
|
-
const beforeTags = intersection.concat(beforeOnly).join("\n") + "\n";
|
|
34
|
-
const afterTags = intersection.concat(afterOnly).join("\n") + "\n";
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div>
|
|
38
|
-
<TextDiff
|
|
39
|
-
before={beforeTags}
|
|
40
|
-
after={afterTags}
|
|
41
|
-
title={this.props.title}
|
|
42
|
-
/>
|
|
43
|
-
{showSeparator && <div className="diff-separator" />}
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export default TagsDiff;
|
package/src/diffs/text-diff.tsx
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/no-unsafe */
|
|
2
|
-
import {components} from "@khanacademy/perseus";
|
|
3
|
-
import classNames from "classnames";
|
|
4
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
5
|
-
import jsdiff from "jsdiff";
|
|
6
|
-
import PropTypes from "prop-types";
|
|
7
|
-
import * as React from "react";
|
|
8
|
-
import _ from "underscore";
|
|
9
|
-
|
|
10
|
-
import splitDiff from "./split-diff";
|
|
11
|
-
import stringArrayDiff from "./string-array-diff";
|
|
12
|
-
|
|
13
|
-
const {SvgImage} = components;
|
|
14
|
-
|
|
15
|
-
const BEFORE = "before";
|
|
16
|
-
const AFTER = "after";
|
|
17
|
-
|
|
18
|
-
const IMAGE_REGEX = /http.*?\.png|web\+graphie[^)]*/g;
|
|
19
|
-
|
|
20
|
-
const imagesInString = function (str: any) {
|
|
21
|
-
return str.match(IMAGE_REGEX) || [];
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const classFor = function (entry: any, ifAdded: string, ifRemoved: string) {
|
|
25
|
-
if (entry.added) {
|
|
26
|
-
return ifAdded;
|
|
27
|
-
}
|
|
28
|
-
if (entry.removed) {
|
|
29
|
-
return ifRemoved;
|
|
30
|
-
}
|
|
31
|
-
return "";
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
class ImageDiffSide extends React.Component<any> {
|
|
35
|
-
static propTypes = {
|
|
36
|
-
images: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
render(): React.ReactNode {
|
|
40
|
-
return (
|
|
41
|
-
<div>
|
|
42
|
-
{_.map(this.props.images, (entry, index) => {
|
|
43
|
-
const className = classNames({
|
|
44
|
-
image: true,
|
|
45
|
-
"image-unchanged": entry.status === "unchanged",
|
|
46
|
-
"image-added": entry.status === "added",
|
|
47
|
-
"image-removed": entry.status === "removed",
|
|
48
|
-
});
|
|
49
|
-
return (
|
|
50
|
-
<div key={index}>
|
|
51
|
-
<div className={className}>
|
|
52
|
-
{/* @ts-expect-error - TS2741 - Property 'alt' is missing in type '{ src: any; title: any; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'. */}
|
|
53
|
-
<SvgImage
|
|
54
|
-
src={entry.value}
|
|
55
|
-
title={entry.value}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
);
|
|
60
|
-
})}
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
class TextDiff extends React.Component<any, any> {
|
|
67
|
-
static propTypes = {
|
|
68
|
-
after: PropTypes.string,
|
|
69
|
-
before: PropTypes.string,
|
|
70
|
-
title: PropTypes.string.isRequired,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
static defaultProps: any = {
|
|
74
|
-
after: "",
|
|
75
|
-
before: "",
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
state: any = {
|
|
79
|
-
collapsed: this.props.before === this.props.after,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
UNSAFE_componentWillReceiveProps(nextProps: any) {
|
|
83
|
-
this.setState({
|
|
84
|
-
collapsed: nextProps.before === nextProps.after,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
handleExpand: () => void = () => {
|
|
89
|
-
this.setState({collapsed: false});
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
render(): React.ReactNode {
|
|
93
|
-
const diffed = jsdiff.diffWords(this.props.before, this.props.after);
|
|
94
|
-
|
|
95
|
-
const lines = splitDiff(diffed);
|
|
96
|
-
|
|
97
|
-
const beforeImages = imagesInString(this.props.before);
|
|
98
|
-
const afterImages = imagesInString(this.props.after);
|
|
99
|
-
const images = stringArrayDiff(beforeImages, afterImages);
|
|
100
|
-
|
|
101
|
-
const renderedLines = _.map(lines, (line) => {
|
|
102
|
-
const contents: Record<string, any> = {};
|
|
103
|
-
|
|
104
|
-
contents.before = _(line).map(function (entry, i) {
|
|
105
|
-
return (
|
|
106
|
-
<span
|
|
107
|
-
key={i}
|
|
108
|
-
className={classFor(
|
|
109
|
-
entry,
|
|
110
|
-
"not-present",
|
|
111
|
-
"removed dark",
|
|
112
|
-
)}
|
|
113
|
-
>
|
|
114
|
-
{entry.value}
|
|
115
|
-
</span>
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
contents.after = _(line).map(function (entry, i) {
|
|
120
|
-
return (
|
|
121
|
-
<span
|
|
122
|
-
key={i}
|
|
123
|
-
className={classFor(entry, "added dark", "not-present")}
|
|
124
|
-
>
|
|
125
|
-
{entry.value}
|
|
126
|
-
</span>
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return contents;
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const className = classNames({
|
|
134
|
-
"diff-row": true,
|
|
135
|
-
collapsed: this.state.collapsed,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div>
|
|
140
|
-
<div className="diff-header">{this.props.title}</div>
|
|
141
|
-
<div className="diff-header">{this.props.title}</div>
|
|
142
|
-
<div className="diff-body ui-helper-clearfix">
|
|
143
|
-
{_.map([BEFORE, AFTER], (side, index) => {
|
|
144
|
-
return (
|
|
145
|
-
<div className={"diff-row " + side} key={index}>
|
|
146
|
-
{!this.state.collapsed &&
|
|
147
|
-
_.map(renderedLines, (line, lineNum) => {
|
|
148
|
-
const changed = line[side].length > 1;
|
|
149
|
-
const lineClass = classNames({
|
|
150
|
-
"diff-line": true,
|
|
151
|
-
added: side === AFTER && changed,
|
|
152
|
-
removed: side === BEFORE && changed,
|
|
153
|
-
});
|
|
154
|
-
return (
|
|
155
|
-
<div
|
|
156
|
-
className={lineClass}
|
|
157
|
-
key={lineNum}
|
|
158
|
-
>
|
|
159
|
-
{line[side]}
|
|
160
|
-
</div>
|
|
161
|
-
);
|
|
162
|
-
})}
|
|
163
|
-
{!this.state.collapsed && (
|
|
164
|
-
<ImageDiffSide images={images[side]} />
|
|
165
|
-
)}
|
|
166
|
-
</div>
|
|
167
|
-
);
|
|
168
|
-
})}
|
|
169
|
-
</div>
|
|
170
|
-
{_.map([BEFORE, AFTER], (side, index) => {
|
|
171
|
-
return (
|
|
172
|
-
<div
|
|
173
|
-
className={className + " " + side}
|
|
174
|
-
key={index}
|
|
175
|
-
onClick={this.handleExpand}
|
|
176
|
-
>
|
|
177
|
-
{this.state.collapsed && (
|
|
178
|
-
<span>
|
|
179
|
-
<span className="expand-button">
|
|
180
|
-
{" "}
|
|
181
|
-
[ show unmodified ]{" "}
|
|
182
|
-
</span>
|
|
183
|
-
</span>
|
|
184
|
-
)}
|
|
185
|
-
</div>
|
|
186
|
-
);
|
|
187
|
-
})}
|
|
188
|
-
</div>
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export default TextDiff;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import _ from "underscore";
|
|
2
|
-
|
|
3
|
-
const UNCHANGED = "unchanged";
|
|
4
|
-
const CHANGED = "changed";
|
|
5
|
-
const ADDED = "added";
|
|
6
|
-
const REMOVED = "removed";
|
|
7
|
-
|
|
8
|
-
// For values which do not have further values nested within them (strings,
|
|
9
|
-
// numbers, and booleans)
|
|
10
|
-
const valueEntry = function (before: any, after: any, key) {
|
|
11
|
-
let status;
|
|
12
|
-
if (before === after) {
|
|
13
|
-
status = UNCHANGED;
|
|
14
|
-
} else if (before === undefined) {
|
|
15
|
-
status = ADDED;
|
|
16
|
-
} else if (after === undefined) {
|
|
17
|
-
status = REMOVED;
|
|
18
|
-
} else {
|
|
19
|
-
status = CHANGED;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
after: JSON.stringify(after),
|
|
24
|
-
before: JSON.stringify(before),
|
|
25
|
-
children: [],
|
|
26
|
-
key: key,
|
|
27
|
-
status: status,
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// For values which require a more granular diff (objects and arrays)
|
|
32
|
-
const objectEntry = function (before: any, after: any, key) {
|
|
33
|
-
const beforeKeys = _.isObject(before) ? _(before).keys() : [];
|
|
34
|
-
const afterKeys = _.isObject(after) ? _(after).keys() : [];
|
|
35
|
-
const keys = _.union(beforeKeys, afterKeys);
|
|
36
|
-
|
|
37
|
-
const children = _.map(keys, function (key) {
|
|
38
|
-
return performDiff((before || {})[key], (after || {})[key], key);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
let status;
|
|
42
|
-
if (before === undefined) {
|
|
43
|
-
status = ADDED;
|
|
44
|
-
} else if (after === undefined) {
|
|
45
|
-
status = REMOVED;
|
|
46
|
-
} else {
|
|
47
|
-
const changed = _.any(children, function (child) {
|
|
48
|
-
return child.status !== UNCHANGED;
|
|
49
|
-
});
|
|
50
|
-
status = changed ? CHANGED : UNCHANGED;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
after: "",
|
|
55
|
-
before: "",
|
|
56
|
-
children: children,
|
|
57
|
-
key: key,
|
|
58
|
-
status: status,
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const performDiff = function (before: any, after: any, key?: any): any {
|
|
63
|
-
if (typeof before === "object" || typeof after === "object") {
|
|
64
|
-
return objectEntry(before, after, key);
|
|
65
|
-
}
|
|
66
|
-
return valueEntry(before, after, key);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export default performDiff;
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
import {components} from "@khanacademy/perseus";
|
|
2
|
-
import classNames from "classnames";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import _ from "underscore";
|
|
6
|
-
|
|
7
|
-
import performDiff from "./widget-diff-performer";
|
|
8
|
-
|
|
9
|
-
const {SvgImage} = components;
|
|
10
|
-
|
|
11
|
-
const indentationFromDepth = function (depth: any) {
|
|
12
|
-
return (depth - 1) * 20;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const BEFORE = "before";
|
|
16
|
-
const AFTER = "after";
|
|
17
|
-
|
|
18
|
-
const UNCHANGED = "unchanged";
|
|
19
|
-
|
|
20
|
-
class DiffSide extends React.Component<any> {
|
|
21
|
-
static propTypes = {
|
|
22
|
-
className: PropTypes.string.isRequired,
|
|
23
|
-
depth: PropTypes.number.isRequired,
|
|
24
|
-
propKey: PropTypes.string.isRequired,
|
|
25
|
-
showKey: PropTypes.bool.isRequired,
|
|
26
|
-
side: PropTypes.oneOf([BEFORE, AFTER]).isRequired,
|
|
27
|
-
value: PropTypes.string,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
render(): React.ReactNode {
|
|
31
|
-
const className = classNames(this.props.className, {
|
|
32
|
-
"diff-row": true,
|
|
33
|
-
before: this.props.side === BEFORE,
|
|
34
|
-
after: this.props.side === AFTER,
|
|
35
|
-
});
|
|
36
|
-
return (
|
|
37
|
-
<div className={className}>
|
|
38
|
-
<div
|
|
39
|
-
style={{
|
|
40
|
-
paddingLeft: indentationFromDepth(this.props.depth),
|
|
41
|
-
}}
|
|
42
|
-
>
|
|
43
|
-
{this.props.showKey && this.props.propKey + ": "}
|
|
44
|
-
<span
|
|
45
|
-
className={"inner-value dark " + this.props.className}
|
|
46
|
-
>
|
|
47
|
-
{this.props.value}
|
|
48
|
-
</span>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
class CollapsedRow extends React.Component<any> {
|
|
56
|
-
static propTypes = {
|
|
57
|
-
depth: PropTypes.number,
|
|
58
|
-
onClick: PropTypes.func.isRequired,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
static defaultProps = {
|
|
62
|
-
depth: 0,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
render(): React.ReactNode {
|
|
66
|
-
const self = this;
|
|
67
|
-
return (
|
|
68
|
-
<div onClick={self.props.onClick} style={{clear: "both"}}>
|
|
69
|
-
{_.map([BEFORE, AFTER], function (side) {
|
|
70
|
-
return (
|
|
71
|
-
<div
|
|
72
|
-
className={"diff-row collapsed " + side}
|
|
73
|
-
key={side}
|
|
74
|
-
>
|
|
75
|
-
<div
|
|
76
|
-
style={{
|
|
77
|
-
paddingLeft: indentationFromDepth(
|
|
78
|
-
self.props.depth,
|
|
79
|
-
),
|
|
80
|
-
}}
|
|
81
|
-
>
|
|
82
|
-
<span> [ show unmodified ] </span>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
);
|
|
86
|
-
})}
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Component representing a single property that may be nested.
|
|
93
|
-
class DiffEntry extends React.Component<any, any> {
|
|
94
|
-
static propTypes = {
|
|
95
|
-
depth: PropTypes.number,
|
|
96
|
-
entry: PropTypes.shape({
|
|
97
|
-
after: PropTypes.string,
|
|
98
|
-
before: PropTypes.string,
|
|
99
|
-
children: PropTypes.arrayOf(PropTypes.any),
|
|
100
|
-
key: PropTypes.string,
|
|
101
|
-
}),
|
|
102
|
-
expanded: PropTypes.bool,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
static defaultProps = {
|
|
106
|
-
depth: 0,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
state = {
|
|
110
|
-
expanded: this.props.expanded,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
expand = () => {
|
|
114
|
-
this.setState({expanded: true});
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
render(): React.ReactNode {
|
|
118
|
-
const entry = this.props.entry;
|
|
119
|
-
const propertyDeleted = entry.status === "removed";
|
|
120
|
-
const propertyAdded = entry.status === "added";
|
|
121
|
-
const propertyChanged = entry.status === "changed";
|
|
122
|
-
|
|
123
|
-
const hasChildren = entry.children.length > 0;
|
|
124
|
-
|
|
125
|
-
const leftClass = classNames({
|
|
126
|
-
removed: propertyDeleted || (propertyChanged && !hasChildren),
|
|
127
|
-
dark: propertyDeleted,
|
|
128
|
-
"blank-space": propertyAdded,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const rightClass = classNames({
|
|
132
|
-
added: propertyAdded || (propertyChanged && !hasChildren),
|
|
133
|
-
dark: propertyAdded,
|
|
134
|
-
"blank-space": propertyDeleted,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
let shownChildren;
|
|
138
|
-
if (this.state.expanded) {
|
|
139
|
-
shownChildren = entry.children;
|
|
140
|
-
} else {
|
|
141
|
-
shownChildren = _(entry.children).select(function (child) {
|
|
142
|
-
return child.status !== UNCHANGED;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
let collapsed = shownChildren.length < entry.children.length;
|
|
147
|
-
|
|
148
|
-
// don't hide just one entry
|
|
149
|
-
if (entry.children.length === shownChildren.length + 1) {
|
|
150
|
-
shownChildren = entry.children;
|
|
151
|
-
collapsed = false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const self = this;
|
|
155
|
-
return (
|
|
156
|
-
<div>
|
|
157
|
-
{entry.key && (
|
|
158
|
-
<div style={{clear: "both"}}>
|
|
159
|
-
<DiffSide
|
|
160
|
-
side={BEFORE}
|
|
161
|
-
className={leftClass}
|
|
162
|
-
depth={this.props.depth}
|
|
163
|
-
propKey={entry.key}
|
|
164
|
-
showKey={!propertyAdded}
|
|
165
|
-
value={entry.before}
|
|
166
|
-
/>
|
|
167
|
-
<DiffSide
|
|
168
|
-
side={AFTER}
|
|
169
|
-
className={rightClass}
|
|
170
|
-
depth={this.props.depth}
|
|
171
|
-
propKey={entry.key}
|
|
172
|
-
showKey={!propertyDeleted}
|
|
173
|
-
value={entry.after}
|
|
174
|
-
/>
|
|
175
|
-
</div>
|
|
176
|
-
)}
|
|
177
|
-
{_.map(shownChildren, function (child) {
|
|
178
|
-
return (
|
|
179
|
-
<DiffEntry
|
|
180
|
-
key={child.key}
|
|
181
|
-
depth={self.props.depth + 1}
|
|
182
|
-
entry={child}
|
|
183
|
-
expanded={self.state.expanded}
|
|
184
|
-
/>
|
|
185
|
-
);
|
|
186
|
-
})}
|
|
187
|
-
{collapsed && (
|
|
188
|
-
<CollapsedRow
|
|
189
|
-
depth={this.props.depth + 1}
|
|
190
|
-
onClick={this.expand}
|
|
191
|
-
/>
|
|
192
|
-
)}
|
|
193
|
-
</div>
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// For image widgets, show the actual image
|
|
199
|
-
class ImageWidgetDiff extends React.Component<any> {
|
|
200
|
-
static propTypes = {
|
|
201
|
-
after: PropTypes.shape({
|
|
202
|
-
options: PropTypes.objectOf(PropTypes.any),
|
|
203
|
-
}).isRequired,
|
|
204
|
-
before: PropTypes.shape({
|
|
205
|
-
options: PropTypes.objectOf(PropTypes.any),
|
|
206
|
-
}).isRequired,
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
render(): React.ReactNode {
|
|
210
|
-
const {before, after} = this.props;
|
|
211
|
-
const beforeSrc =
|
|
212
|
-
before.options && before.options.backgroundImage
|
|
213
|
-
? before.options.backgroundImage.url
|
|
214
|
-
: "";
|
|
215
|
-
const afterSrc =
|
|
216
|
-
after.options && after.options.backgroundImage
|
|
217
|
-
? after.options.backgroundImage.url
|
|
218
|
-
: "";
|
|
219
|
-
return (
|
|
220
|
-
<div>
|
|
221
|
-
<div className="diff-row before">
|
|
222
|
-
{beforeSrc && (
|
|
223
|
-
<div
|
|
224
|
-
className={classNames({
|
|
225
|
-
image: true,
|
|
226
|
-
"image-unchanged": beforeSrc === afterSrc,
|
|
227
|
-
"image-removed": beforeSrc !== afterSrc,
|
|
228
|
-
})}
|
|
229
|
-
>
|
|
230
|
-
{/* @ts-expect-error - TS2741 - Property 'alt' is missing in type '{ src: any; title: any; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'. */}
|
|
231
|
-
<SvgImage src={beforeSrc} title={beforeSrc} />
|
|
232
|
-
</div>
|
|
233
|
-
)}
|
|
234
|
-
</div>
|
|
235
|
-
<div className="diff-row after">
|
|
236
|
-
{afterSrc && (
|
|
237
|
-
<div
|
|
238
|
-
className={classNames({
|
|
239
|
-
image: true,
|
|
240
|
-
"image-unchanged": beforeSrc === afterSrc,
|
|
241
|
-
"image-added": beforeSrc !== afterSrc,
|
|
242
|
-
})}
|
|
243
|
-
>
|
|
244
|
-
{/* @ts-expect-error - TS2741 - Property 'alt' is missing in type '{ src: any; title: any; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'. */}
|
|
245
|
-
<SvgImage src={afterSrc} title={afterSrc} />
|
|
246
|
-
</div>
|
|
247
|
-
)}
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
class WidgetDiff extends React.Component<any> {
|
|
255
|
-
static propTypes = {
|
|
256
|
-
after: PropTypes.shape({
|
|
257
|
-
options: PropTypes.objectOf(PropTypes.any),
|
|
258
|
-
}),
|
|
259
|
-
before: PropTypes.shape({
|
|
260
|
-
options: PropTypes.objectOf(PropTypes.any),
|
|
261
|
-
}),
|
|
262
|
-
title: PropTypes.string.isRequired,
|
|
263
|
-
type: PropTypes.string,
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
static defaultProps: any = {
|
|
267
|
-
after: {},
|
|
268
|
-
before: {},
|
|
269
|
-
type: "",
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
render(): React.ReactNode {
|
|
273
|
-
const {after, before, title, type} = this.props;
|
|
274
|
-
const diff = performDiff(before, after);
|
|
275
|
-
return (
|
|
276
|
-
<div>
|
|
277
|
-
<div className="diff-header">{title}</div>
|
|
278
|
-
<div className="diff-header">{title}</div>
|
|
279
|
-
<div className="diff-body ui-helper-clearfix">
|
|
280
|
-
{type === "image" && (
|
|
281
|
-
<ImageWidgetDiff before={before} after={after} />
|
|
282
|
-
)}
|
|
283
|
-
<DiffEntry entry={diff} />
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
export default WidgetDiff;
|