@atlaskit/editor-plugin-show-diff 6.2.18 → 6.3.0
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/CHANGELOG.md +18 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +19 -9
- package/dist/cjs/pm-plugins/calculateDiff/diffBySteps.js +126 -0
- package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +35 -13
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +30 -17
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +18 -8
- package/dist/es2019/pm-plugins/calculateDiff/diffBySteps.js +91 -0
- package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +37 -15
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +22 -7
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +19 -9
- package/dist/esm/pm-plugins/calculateDiff/diffBySteps.js +119 -0
- package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +37 -15
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +30 -17
- package/dist/types/pm-plugins/calculateDiff/diffBySteps.d.ts +4 -0
- package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +1 -1
- package/dist/types/showDiffPluginType.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/calculateDiff/diffBySteps.d.ts +4 -0
- package/dist/types-ts4.5/pm-plugins/decorations/createBlockChangedDecoration.d.ts +1 -1
- package/dist/types-ts4.5/showDiffPluginType.d.ts +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-show-diff
|
|
2
2
|
|
|
3
|
+
## 6.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`5d32941f15d07`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5d32941f15d07) -
|
|
8
|
+
EDITOR-5949: Change diffing logic to support closest block diffs + preliminary support for row
|
|
9
|
+
diffs.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
15
|
+
## 6.2.19
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
|
|
3
21
|
## 6.2.18
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.calculateDiffDecorations = void 0;
|
|
8
8
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
9
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
11
|
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
12
12
|
var _memoizeOne = _interopRequireDefault(require("memoize-one"));
|
|
13
13
|
var _prosemirrorChangeset = require("prosemirror-changeset");
|
|
@@ -21,6 +21,7 @@ var _createInlineChangedDecoration = require("../decorations/createInlineChanged
|
|
|
21
21
|
var _createNodeChangedDecorationWidget = require("../decorations/createNodeChangedDecorationWidget");
|
|
22
22
|
var _getAttrChangeRanges = require("../decorations/utils/getAttrChangeRanges");
|
|
23
23
|
var _getMarkChangeRanges = require("../decorations/utils/getMarkChangeRanges");
|
|
24
|
+
var _diffBySteps = require("./diffBySteps");
|
|
24
25
|
var _groupChangesByBlock = require("./groupChangesByBlock");
|
|
25
26
|
var _optimizeChanges = require("./optimizeChanges");
|
|
26
27
|
var _simplifySteps = require("./simplifySteps");
|
|
@@ -34,9 +35,16 @@ var getChanges = function getChanges(_ref) {
|
|
|
34
35
|
originalDoc = _ref.originalDoc,
|
|
35
36
|
steppedDoc = _ref.steppedDoc,
|
|
36
37
|
diffType = _ref.diffType,
|
|
37
|
-
tr = _ref.tr
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
tr = _ref.tr,
|
|
39
|
+
steps = _ref.steps;
|
|
40
|
+
if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
41
|
+
if (diffType === 'step') {
|
|
42
|
+
return (0, _diffBySteps.diffBySteps)(originalDoc, steps);
|
|
43
|
+
}
|
|
44
|
+
if (diffType === 'block') {
|
|
45
|
+
return (0, _groupChangesByBlock.groupChangesByBlock)(changeset.changes, originalDoc, steppedDoc);
|
|
46
|
+
}
|
|
47
|
+
return (0, _prosemirrorChangeset.simplifyChanges)(changeset.changes, tr.doc);
|
|
40
48
|
}
|
|
41
49
|
var changes = (0, _prosemirrorChangeset.simplifyChanges)(changeset.changes, tr.doc);
|
|
42
50
|
return (0, _optimizeChanges.optimizeChanges)(changes);
|
|
@@ -55,7 +63,7 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
55
63
|
if (node.isBlock && (!(0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) {
|
|
56
64
|
var nodeEnd = pos + node.nodeSize;
|
|
57
65
|
var isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
|
|
58
|
-
var
|
|
66
|
+
var blockChangedDecorations = (0, _createBlockChangedDecoration.createBlockChangedDecoration)({
|
|
59
67
|
change: {
|
|
60
68
|
from: pos,
|
|
61
69
|
to: nodeEnd,
|
|
@@ -65,8 +73,8 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
65
73
|
isInserted: isInserted,
|
|
66
74
|
isActive: isActive
|
|
67
75
|
});
|
|
68
|
-
if (
|
|
69
|
-
decorations.push(
|
|
76
|
+
if (blockChangedDecorations.length) {
|
|
77
|
+
decorations.push.apply(decorations, (0, _toConsumableArray2.default)(blockChangedDecorations));
|
|
70
78
|
}
|
|
71
79
|
}
|
|
72
80
|
});
|
|
@@ -145,7 +153,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3
|
|
|
145
153
|
originalDoc: originalDoc,
|
|
146
154
|
steppedDoc: steppedDoc,
|
|
147
155
|
diffType: diffType,
|
|
148
|
-
tr: tr
|
|
156
|
+
tr: tr,
|
|
157
|
+
steps: steps
|
|
149
158
|
});
|
|
150
159
|
var decorations = [];
|
|
151
160
|
changes.forEach(function (change) {
|
|
@@ -182,7 +191,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3
|
|
|
182
191
|
intl: intl,
|
|
183
192
|
activeIndexPos: activeIndexPos
|
|
184
193
|
}, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
|
|
185
|
-
isInserted: !isInserted
|
|
194
|
+
isInserted: !isInserted,
|
|
195
|
+
diffType: diffType
|
|
186
196
|
}));
|
|
187
197
|
if (decoration) {
|
|
188
198
|
decorations.push.apply(decorations, (0, _toConsumableArray2.default)(decoration));
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.diffBySteps = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
|
+
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
11
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
12
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
13
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
14
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
15
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
16
|
+
var mapPosition = function mapPosition(mapping, pos) {
|
|
17
|
+
return mapping.map(pos);
|
|
18
|
+
};
|
|
19
|
+
var createMapping = function createMapping(maps) {
|
|
20
|
+
var mapping = new _transform.Mapping();
|
|
21
|
+
var _iterator = _createForOfIteratorHelper(maps),
|
|
22
|
+
_step;
|
|
23
|
+
try {
|
|
24
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
25
|
+
var map = _step.value;
|
|
26
|
+
mapping.appendMap(map);
|
|
27
|
+
}
|
|
28
|
+
} catch (err) {
|
|
29
|
+
_iterator.e(err);
|
|
30
|
+
} finally {
|
|
31
|
+
_iterator.f();
|
|
32
|
+
}
|
|
33
|
+
return mapping;
|
|
34
|
+
};
|
|
35
|
+
var createSpans = function createSpans(length) {
|
|
36
|
+
return length > 0 ? [{
|
|
37
|
+
length: length,
|
|
38
|
+
data: null
|
|
39
|
+
}] : [];
|
|
40
|
+
};
|
|
41
|
+
var mergeOverlappingByNewDocRange = function mergeOverlappingByNewDocRange(changes) {
|
|
42
|
+
if (changes.length <= 1) {
|
|
43
|
+
return changes;
|
|
44
|
+
}
|
|
45
|
+
var sortedChanges = (0, _toConsumableArray2.default)(changes).sort(function (left, right) {
|
|
46
|
+
return left.fromB - right.fromB;
|
|
47
|
+
});
|
|
48
|
+
var merged = [];
|
|
49
|
+
var current = _objectSpread({}, sortedChanges[0]);
|
|
50
|
+
for (var i = 1; i < sortedChanges.length; i++) {
|
|
51
|
+
var next = sortedChanges[i];
|
|
52
|
+
var isOverlapping = next.fromB <= current.toB;
|
|
53
|
+
if (isOverlapping) {
|
|
54
|
+
current = {
|
|
55
|
+
fromA: Math.min(current.fromA, next.fromA),
|
|
56
|
+
toA: Math.max(current.toA, next.toA),
|
|
57
|
+
fromB: Math.min(current.fromB, next.fromB),
|
|
58
|
+
toB: Math.max(current.toB, next.toB),
|
|
59
|
+
deleted: [].concat((0, _toConsumableArray2.default)(current.deleted), (0, _toConsumableArray2.default)(next.deleted)),
|
|
60
|
+
inserted: [].concat((0, _toConsumableArray2.default)(current.inserted), (0, _toConsumableArray2.default)(next.inserted))
|
|
61
|
+
};
|
|
62
|
+
} else {
|
|
63
|
+
merged.push(current);
|
|
64
|
+
current = _objectSpread({}, next);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
merged.push(current);
|
|
68
|
+
return merged;
|
|
69
|
+
};
|
|
70
|
+
var diffBySteps = exports.diffBySteps = function diffBySteps(originalDoc, steps) {
|
|
71
|
+
var changes = [];
|
|
72
|
+
var currentDoc = originalDoc;
|
|
73
|
+
var successfulStepMaps = [];
|
|
74
|
+
var rangedSteps = [];
|
|
75
|
+
var _iterator2 = _createForOfIteratorHelper(steps),
|
|
76
|
+
_step2;
|
|
77
|
+
try {
|
|
78
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
79
|
+
var step = _step2.value;
|
|
80
|
+
var result = step.apply(currentDoc);
|
|
81
|
+
if (result.failed !== null || !result.doc) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
var stepMap = step.getMap();
|
|
85
|
+
var rangeStep = step;
|
|
86
|
+
if (typeof rangeStep.from === 'number' && typeof rangeStep.to === 'number') {
|
|
87
|
+
rangedSteps.push({
|
|
88
|
+
from: rangeStep.from,
|
|
89
|
+
to: rangeStep.to,
|
|
90
|
+
mapIndex: successfulStepMaps.length,
|
|
91
|
+
stepMap: stepMap
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
successfulStepMaps.push(stepMap);
|
|
95
|
+
currentDoc = result.doc;
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
_iterator2.e(err);
|
|
99
|
+
} finally {
|
|
100
|
+
_iterator2.f();
|
|
101
|
+
}
|
|
102
|
+
for (var _i = 0, _rangedSteps = rangedSteps; _i < _rangedSteps.length; _i++) {
|
|
103
|
+
var rangedStep = _rangedSteps[_i];
|
|
104
|
+
// Mapping from original -> doc before this step.
|
|
105
|
+
var originalToBeforeStep = createMapping(successfulStepMaps.slice(0, rangedStep.mapIndex));
|
|
106
|
+
var beforeStepToOriginal = originalToBeforeStep.invert();
|
|
107
|
+
var fromA = mapPosition(beforeStepToOriginal, rangedStep.from);
|
|
108
|
+
var toA = mapPosition(beforeStepToOriginal, rangedStep.to);
|
|
109
|
+
|
|
110
|
+
// Map the step range into final steppedDoc coordinates.
|
|
111
|
+
var fromAfterStep = rangedStep.stepMap.map(rangedStep.from, -1);
|
|
112
|
+
var toAfterStep = rangedStep.stepMap.map(rangedStep.to, 1);
|
|
113
|
+
var afterStepToFinal = createMapping(successfulStepMaps.slice(rangedStep.mapIndex + 1));
|
|
114
|
+
var fromB = mapPosition(afterStepToFinal, fromAfterStep);
|
|
115
|
+
var toB = mapPosition(afterStepToFinal, toAfterStep);
|
|
116
|
+
changes.push({
|
|
117
|
+
fromA: fromA,
|
|
118
|
+
toA: toA,
|
|
119
|
+
fromB: fromB,
|
|
120
|
+
toB: toB,
|
|
121
|
+
deleted: createSpans(Math.max(0, toA - fromA)),
|
|
122
|
+
inserted: createSpans(Math.max(0, toB - fromB))
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return mergeOverlappingByNewDocRange(changes);
|
|
126
|
+
};
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.createBlockChangedDecoration = void 0;
|
|
7
|
+
var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
|
|
7
8
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
8
9
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
9
10
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
@@ -27,12 +28,22 @@ var getBlockNodeStyle = function getBlockNodeStyle(_ref) {
|
|
|
27
28
|
var isTraditional = colorScheme === 'traditional';
|
|
28
29
|
if (['mediaSingle', 'mediaGroup', 'table',
|
|
29
30
|
// Handle table separately to avoid border issues
|
|
30
|
-
'tableRow', '
|
|
31
|
+
'tableRow', 'paragraph',
|
|
31
32
|
// Paragraph and heading nodes do not need special styling
|
|
32
33
|
'heading', 'hardBreak', 'decisionList', 'taskList', 'taskItem', 'bulletList', 'orderedList', 'layoutSection'].includes(nodeName)) {
|
|
33
34
|
// Layout nodes do not need special styling
|
|
34
35
|
return undefined;
|
|
35
36
|
}
|
|
37
|
+
if (['tableCell', 'tableHeader'].includes(nodeName)) {
|
|
38
|
+
if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
39
|
+
// This is used for positioning the cell overlay widget decorations
|
|
40
|
+
return (0, _lazyNodeView.convertToInlineCss)({
|
|
41
|
+
position: 'relative'
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// When gate is off, it should return undefined as above
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
36
47
|
if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
|
|
37
48
|
if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
38
49
|
if (isInserted) {
|
|
@@ -98,6 +109,17 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
|
|
|
98
109
|
isInserted = _ref2$isInserted === void 0 ? true : _ref2$isInserted,
|
|
99
110
|
_ref2$isActive = _ref2.isActive,
|
|
100
111
|
isActive = _ref2$isActive === void 0 ? false : _ref2$isActive;
|
|
112
|
+
var decorations = [];
|
|
113
|
+
if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && ['tableCell', 'tableHeader'].includes(change.name)) {
|
|
114
|
+
var cellOverlay = document.createElement('div');
|
|
115
|
+
var cellOverlayStyle = isInserted ? colorScheme === 'traditional' ? _traditional.traditionalAddedCellOverlayStyle : _standard.addedCellOverlayStyle : colorScheme === 'traditional' ? _traditional.deletedTraditionalCellOverlayStyle : _standard.deletedCellOverlayStyle;
|
|
116
|
+
cellOverlay.setAttribute('style', cellOverlayStyle);
|
|
117
|
+
decorations.push(
|
|
118
|
+
// change.to - 1 to position the overlay inside the end of the cell
|
|
119
|
+
_view.Decoration.widget(change.to - 1, cellOverlay, {
|
|
120
|
+
key: "diff-widget-cell-overlay-".concat(change.to)
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
101
123
|
var style = getBlockNodeStyle({
|
|
102
124
|
nodeName: change.name,
|
|
103
125
|
colorScheme: colorScheme,
|
|
@@ -114,24 +136,24 @@ var createBlockChangedDecoration = exports.createBlockChangedDecoration = functi
|
|
|
114
136
|
var className = getNodeClass(change.name);
|
|
115
137
|
if ((0, _platformFeatureFlags.fg)('platform_editor_show_diff_scroll_navigation')) {
|
|
116
138
|
if (style || className) {
|
|
117
|
-
|
|
139
|
+
decorations.push(_view.Decoration.node(change.from, change.to, {
|
|
118
140
|
style: style,
|
|
119
141
|
'data-testid': 'show-diff-changed-decoration-node',
|
|
120
142
|
class: className
|
|
121
143
|
}, {
|
|
122
144
|
key: 'diff-block',
|
|
123
145
|
nodeName: change.name
|
|
124
|
-
});
|
|
125
|
-
} else {
|
|
126
|
-
return undefined;
|
|
146
|
+
}));
|
|
127
147
|
}
|
|
148
|
+
} else {
|
|
149
|
+
decorations.push(_view.Decoration.node(change.from, change.to, {
|
|
150
|
+
style: style,
|
|
151
|
+
'data-testid': 'show-diff-changed-decoration-node',
|
|
152
|
+
class: className
|
|
153
|
+
}, {
|
|
154
|
+
key: 'diff-block',
|
|
155
|
+
nodeName: change.name
|
|
156
|
+
}));
|
|
128
157
|
}
|
|
129
|
-
return
|
|
130
|
-
style: style,
|
|
131
|
-
'data-testid': 'show-diff-changed-decoration-node',
|
|
132
|
-
class: className
|
|
133
|
-
}, {
|
|
134
|
-
key: 'diff-block',
|
|
135
|
-
nodeName: change.name
|
|
136
|
-
});
|
|
158
|
+
return decorations;
|
|
137
159
|
};
|
|
@@ -20,7 +20,10 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
20
20
|
/**
|
|
21
21
|
* Extracts information about deleted table rows from a change
|
|
22
22
|
*/
|
|
23
|
-
var extractChangedRows = function extractChangedRows(
|
|
23
|
+
var extractChangedRows = function extractChangedRows(_ref) {
|
|
24
|
+
var change = _ref.change,
|
|
25
|
+
originalDoc = _ref.originalDoc,
|
|
26
|
+
newDoc = _ref.newDoc;
|
|
24
27
|
var changedRows = [];
|
|
25
28
|
|
|
26
29
|
// Find the table in the original document
|
|
@@ -42,7 +45,6 @@ var extractChangedRows = function extractChangedRows(change, originalDoc, newDoc
|
|
|
42
45
|
return changedRows;
|
|
43
46
|
}
|
|
44
47
|
var newTableMap = _tableMap.TableMap.get(tableNew.node);
|
|
45
|
-
|
|
46
48
|
// If no rows were changed, return empty
|
|
47
49
|
if (oldTableMap.height <= newTableMap.height ||
|
|
48
50
|
// For now ignore if there are column deletions as well
|
|
@@ -61,7 +63,7 @@ var extractChangedRows = function extractChangedRows(change, originalDoc, newDoc
|
|
|
61
63
|
|
|
62
64
|
// Check if this row overlaps with the deletion range
|
|
63
65
|
var rowOverlapsChange = rowStart >= changeStartInTable && rowStart < changeEndInTable || rowEnd > changeStartInTable && rowEnd <= changeEndInTable || rowStart < changeStartInTable && rowEnd > changeEndInTable;
|
|
64
|
-
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && !isEmptyRow(rowNode)) {
|
|
66
|
+
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) || !isEmptyRow(rowNode))) {
|
|
65
67
|
var startOfRow = newTableMap.mapByRow.slice().reverse().find(function (row) {
|
|
66
68
|
return row[0] + tableNew.pos < change.fromB && change.fromB < row[row.length - 1] + tableNew.pos;
|
|
67
69
|
});
|
|
@@ -132,7 +134,7 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
132
134
|
if (cellNode.type.name === 'tableCell' || cellNode.type.name === 'tableHeader') {
|
|
133
135
|
var nodeView = nodeViewSerializer.tryCreateNodeView(cellNode);
|
|
134
136
|
if (nodeView) {
|
|
135
|
-
if (
|
|
137
|
+
if (nodeView instanceof HTMLElement && (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
136
138
|
var overlay = document.createElement('span');
|
|
137
139
|
var overlayStyle = colorScheme === 'traditional' ? isInserted ? _traditional.traditionalAddedCellOverlayStyle : _traditional.deletedTraditionalCellOverlayStyle : isInserted ? _standard.addedCellOverlayStyle : _standard.deletedCellOverlayStyle;
|
|
138
140
|
overlay.setAttribute('style', overlayStyle);
|
|
@@ -154,7 +156,10 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
154
156
|
/**
|
|
155
157
|
* Expands a diff to include whole changed rows when table rows are affected
|
|
156
158
|
*/
|
|
157
|
-
var expandDiffForChangedRows = function expandDiffForChangedRows(
|
|
159
|
+
var expandDiffForChangedRows = function expandDiffForChangedRows(_ref2) {
|
|
160
|
+
var changes = _ref2.changes,
|
|
161
|
+
originalDoc = _ref2.originalDoc,
|
|
162
|
+
newDoc = _ref2.newDoc;
|
|
158
163
|
var rowInfo = [];
|
|
159
164
|
var _iterator = _createForOfIteratorHelper(changes),
|
|
160
165
|
_step;
|
|
@@ -162,7 +167,11 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(changes, origin
|
|
|
162
167
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
163
168
|
var change = _step.value;
|
|
164
169
|
// Check if this change affects table content
|
|
165
|
-
var changedRows = extractChangedRows(
|
|
170
|
+
var changedRows = extractChangedRows({
|
|
171
|
+
change: change,
|
|
172
|
+
originalDoc: originalDoc,
|
|
173
|
+
newDoc: newDoc
|
|
174
|
+
});
|
|
166
175
|
if (changedRows.length > 0) {
|
|
167
176
|
rowInfo.push.apply(rowInfo, (0, _toConsumableArray2.default)(changedRows));
|
|
168
177
|
}
|
|
@@ -178,18 +187,22 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(changes, origin
|
|
|
178
187
|
/**
|
|
179
188
|
* Main function to handle deleted rows - computes diff and creates decorations
|
|
180
189
|
*/
|
|
181
|
-
var createChangedRowDecorationWidgets = exports.createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(
|
|
182
|
-
var changes =
|
|
183
|
-
originalDoc =
|
|
184
|
-
newDoc =
|
|
185
|
-
nodeViewSerializer =
|
|
186
|
-
colorScheme =
|
|
187
|
-
|
|
188
|
-
isInserted =
|
|
190
|
+
var createChangedRowDecorationWidgets = exports.createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref3) {
|
|
191
|
+
var changes = _ref3.changes,
|
|
192
|
+
originalDoc = _ref3.originalDoc,
|
|
193
|
+
newDoc = _ref3.newDoc,
|
|
194
|
+
nodeViewSerializer = _ref3.nodeViewSerializer,
|
|
195
|
+
colorScheme = _ref3.colorScheme,
|
|
196
|
+
_ref3$isInserted = _ref3.isInserted,
|
|
197
|
+
isInserted = _ref3$isInserted === void 0 ? false : _ref3$isInserted;
|
|
189
198
|
// First, expand the changes to include complete deleted rows
|
|
190
|
-
var changedRows = expandDiffForChangedRows(
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
var changedRows = expandDiffForChangedRows({
|
|
200
|
+
changes: changes.filter(function (change) {
|
|
201
|
+
return change.deleted.length > 0;
|
|
202
|
+
}),
|
|
203
|
+
originalDoc: originalDoc,
|
|
204
|
+
newDoc: newDoc
|
|
205
|
+
});
|
|
193
206
|
return changedRows.map(function (changedRow) {
|
|
194
207
|
var rowDOM = createChangedRowDOM(changedRow.rowNode, nodeViewSerializer, colorScheme, isInserted);
|
|
195
208
|
|
|
@@ -12,6 +12,7 @@ import { createInlineChangedDecoration } from '../decorations/createInlineChange
|
|
|
12
12
|
import { createNodeChangedDecorationWidget } from '../decorations/createNodeChangedDecorationWidget';
|
|
13
13
|
import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
|
|
14
14
|
import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
|
|
15
|
+
import { diffBySteps } from './diffBySteps';
|
|
15
16
|
import { groupChangesByBlock } from './groupChangesByBlock';
|
|
16
17
|
import { optimizeChanges } from './optimizeChanges';
|
|
17
18
|
import { simplifySteps } from './simplifySteps';
|
|
@@ -20,10 +21,17 @@ const getChanges = ({
|
|
|
20
21
|
originalDoc,
|
|
21
22
|
steppedDoc,
|
|
22
23
|
diffType,
|
|
23
|
-
tr
|
|
24
|
+
tr,
|
|
25
|
+
steps
|
|
24
26
|
}) => {
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
28
|
+
if (diffType === 'step') {
|
|
29
|
+
return diffBySteps(originalDoc, steps);
|
|
30
|
+
}
|
|
31
|
+
if (diffType === 'block') {
|
|
32
|
+
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
33
|
+
}
|
|
34
|
+
return simplifyChanges(changeset.changes, tr.doc);
|
|
27
35
|
}
|
|
28
36
|
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
29
37
|
return optimizeChanges(changes);
|
|
@@ -42,7 +50,7 @@ const calculateNodesForBlockDecoration = ({
|
|
|
42
50
|
if (node.isBlock && (!expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) {
|
|
43
51
|
const nodeEnd = pos + node.nodeSize;
|
|
44
52
|
const isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
|
|
45
|
-
const
|
|
53
|
+
const blockChangedDecorations = createBlockChangedDecoration({
|
|
46
54
|
change: {
|
|
47
55
|
from: pos,
|
|
48
56
|
to: nodeEnd,
|
|
@@ -52,8 +60,8 @@ const calculateNodesForBlockDecoration = ({
|
|
|
52
60
|
isInserted,
|
|
53
61
|
isActive
|
|
54
62
|
});
|
|
55
|
-
if (
|
|
56
|
-
decorations.push(
|
|
63
|
+
if (blockChangedDecorations.length) {
|
|
64
|
+
decorations.push(...blockChangedDecorations);
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
});
|
|
@@ -126,7 +134,8 @@ const calculateDiffDecorationsInner = ({
|
|
|
126
134
|
originalDoc,
|
|
127
135
|
steppedDoc,
|
|
128
136
|
diffType,
|
|
129
|
-
tr
|
|
137
|
+
tr,
|
|
138
|
+
steps
|
|
130
139
|
});
|
|
131
140
|
const decorations = [];
|
|
132
141
|
changes.forEach(change => {
|
|
@@ -164,7 +173,8 @@ const calculateDiffDecorationsInner = ({
|
|
|
164
173
|
intl,
|
|
165
174
|
activeIndexPos,
|
|
166
175
|
...(expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
|
|
167
|
-
isInserted: !isInserted
|
|
176
|
+
isInserted: !isInserted,
|
|
177
|
+
diffType
|
|
168
178
|
})
|
|
169
179
|
});
|
|
170
180
|
if (decoration) {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Mapping } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
const mapPosition = (mapping, pos) => mapping.map(pos);
|
|
3
|
+
const createMapping = maps => {
|
|
4
|
+
const mapping = new Mapping();
|
|
5
|
+
for (const map of maps) {
|
|
6
|
+
mapping.appendMap(map);
|
|
7
|
+
}
|
|
8
|
+
return mapping;
|
|
9
|
+
};
|
|
10
|
+
const createSpans = length => length > 0 ? [{
|
|
11
|
+
length,
|
|
12
|
+
data: null
|
|
13
|
+
}] : [];
|
|
14
|
+
const mergeOverlappingByNewDocRange = changes => {
|
|
15
|
+
if (changes.length <= 1) {
|
|
16
|
+
return changes;
|
|
17
|
+
}
|
|
18
|
+
const sortedChanges = [...changes].sort((left, right) => left.fromB - right.fromB);
|
|
19
|
+
const merged = [];
|
|
20
|
+
let current = {
|
|
21
|
+
...sortedChanges[0]
|
|
22
|
+
};
|
|
23
|
+
for (let i = 1; i < sortedChanges.length; i++) {
|
|
24
|
+
const next = sortedChanges[i];
|
|
25
|
+
const isOverlapping = next.fromB <= current.toB;
|
|
26
|
+
if (isOverlapping) {
|
|
27
|
+
current = {
|
|
28
|
+
fromA: Math.min(current.fromA, next.fromA),
|
|
29
|
+
toA: Math.max(current.toA, next.toA),
|
|
30
|
+
fromB: Math.min(current.fromB, next.fromB),
|
|
31
|
+
toB: Math.max(current.toB, next.toB),
|
|
32
|
+
deleted: [...current.deleted, ...next.deleted],
|
|
33
|
+
inserted: [...current.inserted, ...next.inserted]
|
|
34
|
+
};
|
|
35
|
+
} else {
|
|
36
|
+
merged.push(current);
|
|
37
|
+
current = {
|
|
38
|
+
...next
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
merged.push(current);
|
|
43
|
+
return merged;
|
|
44
|
+
};
|
|
45
|
+
export const diffBySteps = (originalDoc, steps) => {
|
|
46
|
+
const changes = [];
|
|
47
|
+
let currentDoc = originalDoc;
|
|
48
|
+
const successfulStepMaps = [];
|
|
49
|
+
const rangedSteps = [];
|
|
50
|
+
for (const step of steps) {
|
|
51
|
+
const result = step.apply(currentDoc);
|
|
52
|
+
if (result.failed !== null || !result.doc) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const stepMap = step.getMap();
|
|
56
|
+
const rangeStep = step;
|
|
57
|
+
if (typeof rangeStep.from === 'number' && typeof rangeStep.to === 'number') {
|
|
58
|
+
rangedSteps.push({
|
|
59
|
+
from: rangeStep.from,
|
|
60
|
+
to: rangeStep.to,
|
|
61
|
+
mapIndex: successfulStepMaps.length,
|
|
62
|
+
stepMap
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
successfulStepMaps.push(stepMap);
|
|
66
|
+
currentDoc = result.doc;
|
|
67
|
+
}
|
|
68
|
+
for (const rangedStep of rangedSteps) {
|
|
69
|
+
// Mapping from original -> doc before this step.
|
|
70
|
+
const originalToBeforeStep = createMapping(successfulStepMaps.slice(0, rangedStep.mapIndex));
|
|
71
|
+
const beforeStepToOriginal = originalToBeforeStep.invert();
|
|
72
|
+
const fromA = mapPosition(beforeStepToOriginal, rangedStep.from);
|
|
73
|
+
const toA = mapPosition(beforeStepToOriginal, rangedStep.to);
|
|
74
|
+
|
|
75
|
+
// Map the step range into final steppedDoc coordinates.
|
|
76
|
+
const fromAfterStep = rangedStep.stepMap.map(rangedStep.from, -1);
|
|
77
|
+
const toAfterStep = rangedStep.stepMap.map(rangedStep.to, 1);
|
|
78
|
+
const afterStepToFinal = createMapping(successfulStepMaps.slice(rangedStep.mapIndex + 1));
|
|
79
|
+
const fromB = mapPosition(afterStepToFinal, fromAfterStep);
|
|
80
|
+
const toB = mapPosition(afterStepToFinal, toAfterStep);
|
|
81
|
+
changes.push({
|
|
82
|
+
fromA,
|
|
83
|
+
toA,
|
|
84
|
+
fromB,
|
|
85
|
+
toB,
|
|
86
|
+
deleted: createSpans(Math.max(0, toA - fromA)),
|
|
87
|
+
inserted: createSpans(Math.max(0, toB - fromB))
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return mergeOverlappingByNewDocRange(changes);
|
|
91
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
1
2
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
2
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
4
|
-
import { standardDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, deletedContentStyleNew, deletedStyleQuoteNode } from './colorSchemes/standard';
|
|
5
|
-
import { traditionalDecorationMarkerVariable, traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariable, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNode, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNode, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNode, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNode, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode } from './colorSchemes/traditional';
|
|
5
|
+
import { standardDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, deletedContentStyleNew, deletedStyleQuoteNode, addedCellOverlayStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
6
|
+
import { traditionalDecorationMarkerVariable, traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariable, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNode, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNode, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNode, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNode, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode, traditionalAddedCellOverlayStyle, deletedTraditionalCellOverlayStyle } from './colorSchemes/traditional';
|
|
6
7
|
const getNodeClass = name => {
|
|
7
8
|
switch (name) {
|
|
8
9
|
case 'extension':
|
|
@@ -20,12 +21,22 @@ const getBlockNodeStyle = ({
|
|
|
20
21
|
const isTraditional = colorScheme === 'traditional';
|
|
21
22
|
if (['mediaSingle', 'mediaGroup', 'table',
|
|
22
23
|
// Handle table separately to avoid border issues
|
|
23
|
-
'tableRow', '
|
|
24
|
+
'tableRow', 'paragraph',
|
|
24
25
|
// Paragraph and heading nodes do not need special styling
|
|
25
26
|
'heading', 'hardBreak', 'decisionList', 'taskList', 'taskItem', 'bulletList', 'orderedList', 'layoutSection'].includes(nodeName)) {
|
|
26
27
|
// Layout nodes do not need special styling
|
|
27
28
|
return undefined;
|
|
28
29
|
}
|
|
30
|
+
if (['tableCell', 'tableHeader'].includes(nodeName)) {
|
|
31
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
32
|
+
// This is used for positioning the cell overlay widget decorations
|
|
33
|
+
return convertToInlineCss({
|
|
34
|
+
position: 'relative'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// When gate is off, it should return undefined as above
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
29
40
|
if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
|
|
30
41
|
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
31
42
|
if (isInserted) {
|
|
@@ -90,6 +101,17 @@ export const createBlockChangedDecoration = ({
|
|
|
90
101
|
isInserted = true,
|
|
91
102
|
isActive = false
|
|
92
103
|
}) => {
|
|
104
|
+
const decorations = [];
|
|
105
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) && ['tableCell', 'tableHeader'].includes(change.name)) {
|
|
106
|
+
const cellOverlay = document.createElement('div');
|
|
107
|
+
const cellOverlayStyle = isInserted ? colorScheme === 'traditional' ? traditionalAddedCellOverlayStyle : addedCellOverlayStyle : colorScheme === 'traditional' ? deletedTraditionalCellOverlayStyle : deletedCellOverlayStyle;
|
|
108
|
+
cellOverlay.setAttribute('style', cellOverlayStyle);
|
|
109
|
+
decorations.push(
|
|
110
|
+
// change.to - 1 to position the overlay inside the end of the cell
|
|
111
|
+
Decoration.widget(change.to - 1, cellOverlay, {
|
|
112
|
+
key: `diff-widget-cell-overlay-${change.to}`
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
93
115
|
let style = getBlockNodeStyle({
|
|
94
116
|
nodeName: change.name,
|
|
95
117
|
colorScheme,
|
|
@@ -106,24 +128,24 @@ export const createBlockChangedDecoration = ({
|
|
|
106
128
|
const className = getNodeClass(change.name);
|
|
107
129
|
if (fg('platform_editor_show_diff_scroll_navigation')) {
|
|
108
130
|
if (style || className) {
|
|
109
|
-
|
|
131
|
+
decorations.push(Decoration.node(change.from, change.to, {
|
|
110
132
|
style: style,
|
|
111
133
|
'data-testid': 'show-diff-changed-decoration-node',
|
|
112
134
|
class: className
|
|
113
135
|
}, {
|
|
114
136
|
key: 'diff-block',
|
|
115
137
|
nodeName: change.name
|
|
116
|
-
});
|
|
117
|
-
} else {
|
|
118
|
-
return undefined;
|
|
138
|
+
}));
|
|
119
139
|
}
|
|
140
|
+
} else {
|
|
141
|
+
decorations.push(Decoration.node(change.from, change.to, {
|
|
142
|
+
style,
|
|
143
|
+
'data-testid': 'show-diff-changed-decoration-node',
|
|
144
|
+
class: className
|
|
145
|
+
}, {
|
|
146
|
+
key: 'diff-block',
|
|
147
|
+
nodeName: change.name
|
|
148
|
+
}));
|
|
120
149
|
}
|
|
121
|
-
return
|
|
122
|
-
style,
|
|
123
|
-
'data-testid': 'show-diff-changed-decoration-node',
|
|
124
|
-
class: className
|
|
125
|
-
}, {
|
|
126
|
-
key: 'diff-block',
|
|
127
|
-
nodeName: change.name
|
|
128
|
-
});
|
|
150
|
+
return decorations;
|
|
129
151
|
};
|
|
@@ -9,7 +9,11 @@ import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
|
9
9
|
/**
|
|
10
10
|
* Extracts information about deleted table rows from a change
|
|
11
11
|
*/
|
|
12
|
-
const extractChangedRows = (
|
|
12
|
+
const extractChangedRows = ({
|
|
13
|
+
change,
|
|
14
|
+
originalDoc,
|
|
15
|
+
newDoc
|
|
16
|
+
}) => {
|
|
13
17
|
const changedRows = [];
|
|
14
18
|
|
|
15
19
|
// Find the table in the original document
|
|
@@ -27,7 +31,6 @@ const extractChangedRows = (change, originalDoc, newDoc) => {
|
|
|
27
31
|
return changedRows;
|
|
28
32
|
}
|
|
29
33
|
const newTableMap = TableMap.get(tableNew.node);
|
|
30
|
-
|
|
31
34
|
// If no rows were changed, return empty
|
|
32
35
|
if (oldTableMap.height <= newTableMap.height ||
|
|
33
36
|
// For now ignore if there are column deletions as well
|
|
@@ -46,7 +49,7 @@ const extractChangedRows = (change, originalDoc, newDoc) => {
|
|
|
46
49
|
|
|
47
50
|
// Check if this row overlaps with the deletion range
|
|
48
51
|
const rowOverlapsChange = rowStart >= changeStartInTable && rowStart < changeEndInTable || rowEnd > changeStartInTable && rowEnd <= changeEndInTable || rowStart < changeStartInTable && rowEnd > changeEndInTable;
|
|
49
|
-
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && !isEmptyRow(rowNode)) {
|
|
52
|
+
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) || !isEmptyRow(rowNode))) {
|
|
50
53
|
const startOfRow = newTableMap.mapByRow.slice().reverse().find(row => row[0] + tableNew.pos < change.fromB && change.fromB < row[row.length - 1] + tableNew.pos);
|
|
51
54
|
changedRows.push({
|
|
52
55
|
rowIndex,
|
|
@@ -113,7 +116,7 @@ const createChangedRowDOM = (rowNode, nodeViewSerializer, colorScheme, isInserte
|
|
|
113
116
|
if (cellNode.type.name === 'tableCell' || cellNode.type.name === 'tableHeader') {
|
|
114
117
|
const nodeView = nodeViewSerializer.tryCreateNodeView(cellNode);
|
|
115
118
|
if (nodeView) {
|
|
116
|
-
if (
|
|
119
|
+
if (nodeView instanceof HTMLElement && expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
117
120
|
const overlay = document.createElement('span');
|
|
118
121
|
const overlayStyle = colorScheme === 'traditional' ? isInserted ? traditionalAddedCellOverlayStyle : deletedTraditionalCellOverlayStyle : isInserted ? addedCellOverlayStyle : deletedCellOverlayStyle;
|
|
119
122
|
overlay.setAttribute('style', overlayStyle);
|
|
@@ -135,11 +138,19 @@ const createChangedRowDOM = (rowNode, nodeViewSerializer, colorScheme, isInserte
|
|
|
135
138
|
/**
|
|
136
139
|
* Expands a diff to include whole changed rows when table rows are affected
|
|
137
140
|
*/
|
|
138
|
-
const expandDiffForChangedRows = (
|
|
141
|
+
const expandDiffForChangedRows = ({
|
|
142
|
+
changes,
|
|
143
|
+
originalDoc,
|
|
144
|
+
newDoc
|
|
145
|
+
}) => {
|
|
139
146
|
const rowInfo = [];
|
|
140
147
|
for (const change of changes) {
|
|
141
148
|
// Check if this change affects table content
|
|
142
|
-
const changedRows = extractChangedRows(
|
|
149
|
+
const changedRows = extractChangedRows({
|
|
150
|
+
change,
|
|
151
|
+
originalDoc,
|
|
152
|
+
newDoc
|
|
153
|
+
});
|
|
143
154
|
if (changedRows.length > 0) {
|
|
144
155
|
rowInfo.push(...changedRows);
|
|
145
156
|
}
|
|
@@ -159,7 +170,11 @@ export const createChangedRowDecorationWidgets = ({
|
|
|
159
170
|
isInserted = false
|
|
160
171
|
}) => {
|
|
161
172
|
// First, expand the changes to include complete deleted rows
|
|
162
|
-
const changedRows = expandDiffForChangedRows(
|
|
173
|
+
const changedRows = expandDiffForChangedRows({
|
|
174
|
+
changes: changes.filter(change => change.deleted.length > 0),
|
|
175
|
+
originalDoc,
|
|
176
|
+
newDoc
|
|
177
|
+
});
|
|
163
178
|
return changedRows.map(changedRow => {
|
|
164
179
|
const rowDOM = createChangedRowDOM(changedRow.rowNode, nodeViewSerializer, colorScheme, isInserted);
|
|
165
180
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
4
4
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
5
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
6
6
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
@@ -20,6 +20,7 @@ import { createInlineChangedDecoration } from '../decorations/createInlineChange
|
|
|
20
20
|
import { createNodeChangedDecorationWidget } from '../decorations/createNodeChangedDecorationWidget';
|
|
21
21
|
import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
|
|
22
22
|
import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
|
|
23
|
+
import { diffBySteps } from './diffBySteps';
|
|
23
24
|
import { groupChangesByBlock } from './groupChangesByBlock';
|
|
24
25
|
import { optimizeChanges } from './optimizeChanges';
|
|
25
26
|
import { simplifySteps } from './simplifySteps';
|
|
@@ -28,9 +29,16 @@ var getChanges = function getChanges(_ref) {
|
|
|
28
29
|
originalDoc = _ref.originalDoc,
|
|
29
30
|
steppedDoc = _ref.steppedDoc,
|
|
30
31
|
diffType = _ref.diffType,
|
|
31
|
-
tr = _ref.tr
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
tr = _ref.tr,
|
|
33
|
+
steps = _ref.steps;
|
|
34
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
35
|
+
if (diffType === 'step') {
|
|
36
|
+
return diffBySteps(originalDoc, steps);
|
|
37
|
+
}
|
|
38
|
+
if (diffType === 'block') {
|
|
39
|
+
return groupChangesByBlock(changeset.changes, originalDoc, steppedDoc);
|
|
40
|
+
}
|
|
41
|
+
return simplifyChanges(changeset.changes, tr.doc);
|
|
34
42
|
}
|
|
35
43
|
var changes = simplifyChanges(changeset.changes, tr.doc);
|
|
36
44
|
return optimizeChanges(changes);
|
|
@@ -49,7 +57,7 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
49
57
|
if (node.isBlock && (!expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) {
|
|
50
58
|
var nodeEnd = pos + node.nodeSize;
|
|
51
59
|
var isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
|
|
52
|
-
var
|
|
60
|
+
var blockChangedDecorations = createBlockChangedDecoration({
|
|
53
61
|
change: {
|
|
54
62
|
from: pos,
|
|
55
63
|
to: nodeEnd,
|
|
@@ -59,8 +67,8 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
59
67
|
isInserted: isInserted,
|
|
60
68
|
isActive: isActive
|
|
61
69
|
});
|
|
62
|
-
if (
|
|
63
|
-
decorations.push(
|
|
70
|
+
if (blockChangedDecorations.length) {
|
|
71
|
+
decorations.push.apply(decorations, _toConsumableArray(blockChangedDecorations));
|
|
64
72
|
}
|
|
65
73
|
}
|
|
66
74
|
});
|
|
@@ -139,7 +147,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3
|
|
|
139
147
|
originalDoc: originalDoc,
|
|
140
148
|
steppedDoc: steppedDoc,
|
|
141
149
|
diffType: diffType,
|
|
142
|
-
tr: tr
|
|
150
|
+
tr: tr,
|
|
151
|
+
steps: steps
|
|
143
152
|
});
|
|
144
153
|
var decorations = [];
|
|
145
154
|
changes.forEach(function (change) {
|
|
@@ -176,7 +185,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3
|
|
|
176
185
|
intl: intl,
|
|
177
186
|
activeIndexPos: activeIndexPos
|
|
178
187
|
}, expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) && {
|
|
179
|
-
isInserted: !isInserted
|
|
188
|
+
isInserted: !isInserted,
|
|
189
|
+
diffType: diffType
|
|
180
190
|
}));
|
|
181
191
|
if (decoration) {
|
|
182
192
|
decorations.push.apply(decorations, _toConsumableArray(decoration));
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
6
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
7
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
8
|
+
import { Mapping } from '@atlaskit/editor-prosemirror/transform';
|
|
9
|
+
var mapPosition = function mapPosition(mapping, pos) {
|
|
10
|
+
return mapping.map(pos);
|
|
11
|
+
};
|
|
12
|
+
var createMapping = function createMapping(maps) {
|
|
13
|
+
var mapping = new Mapping();
|
|
14
|
+
var _iterator = _createForOfIteratorHelper(maps),
|
|
15
|
+
_step;
|
|
16
|
+
try {
|
|
17
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
18
|
+
var map = _step.value;
|
|
19
|
+
mapping.appendMap(map);
|
|
20
|
+
}
|
|
21
|
+
} catch (err) {
|
|
22
|
+
_iterator.e(err);
|
|
23
|
+
} finally {
|
|
24
|
+
_iterator.f();
|
|
25
|
+
}
|
|
26
|
+
return mapping;
|
|
27
|
+
};
|
|
28
|
+
var createSpans = function createSpans(length) {
|
|
29
|
+
return length > 0 ? [{
|
|
30
|
+
length: length,
|
|
31
|
+
data: null
|
|
32
|
+
}] : [];
|
|
33
|
+
};
|
|
34
|
+
var mergeOverlappingByNewDocRange = function mergeOverlappingByNewDocRange(changes) {
|
|
35
|
+
if (changes.length <= 1) {
|
|
36
|
+
return changes;
|
|
37
|
+
}
|
|
38
|
+
var sortedChanges = _toConsumableArray(changes).sort(function (left, right) {
|
|
39
|
+
return left.fromB - right.fromB;
|
|
40
|
+
});
|
|
41
|
+
var merged = [];
|
|
42
|
+
var current = _objectSpread({}, sortedChanges[0]);
|
|
43
|
+
for (var i = 1; i < sortedChanges.length; i++) {
|
|
44
|
+
var next = sortedChanges[i];
|
|
45
|
+
var isOverlapping = next.fromB <= current.toB;
|
|
46
|
+
if (isOverlapping) {
|
|
47
|
+
current = {
|
|
48
|
+
fromA: Math.min(current.fromA, next.fromA),
|
|
49
|
+
toA: Math.max(current.toA, next.toA),
|
|
50
|
+
fromB: Math.min(current.fromB, next.fromB),
|
|
51
|
+
toB: Math.max(current.toB, next.toB),
|
|
52
|
+
deleted: [].concat(_toConsumableArray(current.deleted), _toConsumableArray(next.deleted)),
|
|
53
|
+
inserted: [].concat(_toConsumableArray(current.inserted), _toConsumableArray(next.inserted))
|
|
54
|
+
};
|
|
55
|
+
} else {
|
|
56
|
+
merged.push(current);
|
|
57
|
+
current = _objectSpread({}, next);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
merged.push(current);
|
|
61
|
+
return merged;
|
|
62
|
+
};
|
|
63
|
+
export var diffBySteps = function diffBySteps(originalDoc, steps) {
|
|
64
|
+
var changes = [];
|
|
65
|
+
var currentDoc = originalDoc;
|
|
66
|
+
var successfulStepMaps = [];
|
|
67
|
+
var rangedSteps = [];
|
|
68
|
+
var _iterator2 = _createForOfIteratorHelper(steps),
|
|
69
|
+
_step2;
|
|
70
|
+
try {
|
|
71
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
72
|
+
var step = _step2.value;
|
|
73
|
+
var result = step.apply(currentDoc);
|
|
74
|
+
if (result.failed !== null || !result.doc) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
var stepMap = step.getMap();
|
|
78
|
+
var rangeStep = step;
|
|
79
|
+
if (typeof rangeStep.from === 'number' && typeof rangeStep.to === 'number') {
|
|
80
|
+
rangedSteps.push({
|
|
81
|
+
from: rangeStep.from,
|
|
82
|
+
to: rangeStep.to,
|
|
83
|
+
mapIndex: successfulStepMaps.length,
|
|
84
|
+
stepMap: stepMap
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
successfulStepMaps.push(stepMap);
|
|
88
|
+
currentDoc = result.doc;
|
|
89
|
+
}
|
|
90
|
+
} catch (err) {
|
|
91
|
+
_iterator2.e(err);
|
|
92
|
+
} finally {
|
|
93
|
+
_iterator2.f();
|
|
94
|
+
}
|
|
95
|
+
for (var _i = 0, _rangedSteps = rangedSteps; _i < _rangedSteps.length; _i++) {
|
|
96
|
+
var rangedStep = _rangedSteps[_i];
|
|
97
|
+
// Mapping from original -> doc before this step.
|
|
98
|
+
var originalToBeforeStep = createMapping(successfulStepMaps.slice(0, rangedStep.mapIndex));
|
|
99
|
+
var beforeStepToOriginal = originalToBeforeStep.invert();
|
|
100
|
+
var fromA = mapPosition(beforeStepToOriginal, rangedStep.from);
|
|
101
|
+
var toA = mapPosition(beforeStepToOriginal, rangedStep.to);
|
|
102
|
+
|
|
103
|
+
// Map the step range into final steppedDoc coordinates.
|
|
104
|
+
var fromAfterStep = rangedStep.stepMap.map(rangedStep.from, -1);
|
|
105
|
+
var toAfterStep = rangedStep.stepMap.map(rangedStep.to, 1);
|
|
106
|
+
var afterStepToFinal = createMapping(successfulStepMaps.slice(rangedStep.mapIndex + 1));
|
|
107
|
+
var fromB = mapPosition(afterStepToFinal, fromAfterStep);
|
|
108
|
+
var toB = mapPosition(afterStepToFinal, toAfterStep);
|
|
109
|
+
changes.push({
|
|
110
|
+
fromA: fromA,
|
|
111
|
+
toA: toA,
|
|
112
|
+
fromB: fromB,
|
|
113
|
+
toB: toB,
|
|
114
|
+
deleted: createSpans(Math.max(0, toA - fromA)),
|
|
115
|
+
inserted: createSpans(Math.max(0, toB - fromB))
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return mergeOverlappingByNewDocRange(changes);
|
|
119
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { convertToInlineCss } from '@atlaskit/editor-common/lazy-node-view';
|
|
1
2
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
2
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
4
|
-
import { standardDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, deletedContentStyleNew, deletedStyleQuoteNode } from './colorSchemes/standard';
|
|
5
|
-
import { traditionalDecorationMarkerVariable, traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariable, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNode, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNode, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNode, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNode, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode } from './colorSchemes/traditional';
|
|
5
|
+
import { standardDecorationMarkerVariable, editingStyleQuoteNode, editingStyleRuleNode, editingStyleCardBlockNode, editingStyleNode, deletedContentStyleNew, deletedStyleQuoteNode, addedCellOverlayStyle, deletedCellOverlayStyle } from './colorSchemes/standard';
|
|
6
|
+
import { traditionalDecorationMarkerVariable, traditionalDecorationMarkerVariableActive, traditionalDecorationMarkerVariableNew, traditionalDeletedDecorationMarkerVariable, traditionalDeletedDecorationMarkerVariableActive, traditionalDeletedDecorationMarkerVariableNew, traditionalStyleQuoteNode, traditionalStyleQuoteNodeActive, traditionalStyleQuoteNodeNew, traditionalStyleRuleNode, traditionalStyleRuleNodeActive, traditionalStyleRuleNodeNew, traditionalStyleCardBlockNode, traditionalStyleCardBlockNodeActive, traditionalStyleCardBlockNodeNew, traditionalStyleNode, traditionalStyleNodeActive, traditionalStyleNodeNew, getDeletedTraditionalInlineStyle, deletedTraditionalStyleQuoteNode, traditionalAddedCellOverlayStyle, deletedTraditionalCellOverlayStyle } from './colorSchemes/traditional';
|
|
6
7
|
var getNodeClass = function getNodeClass(name) {
|
|
7
8
|
switch (name) {
|
|
8
9
|
case 'extension':
|
|
@@ -21,12 +22,22 @@ var getBlockNodeStyle = function getBlockNodeStyle(_ref) {
|
|
|
21
22
|
var isTraditional = colorScheme === 'traditional';
|
|
22
23
|
if (['mediaSingle', 'mediaGroup', 'table',
|
|
23
24
|
// Handle table separately to avoid border issues
|
|
24
|
-
'tableRow', '
|
|
25
|
+
'tableRow', 'paragraph',
|
|
25
26
|
// Paragraph and heading nodes do not need special styling
|
|
26
27
|
'heading', 'hardBreak', 'decisionList', 'taskList', 'taskItem', 'bulletList', 'orderedList', 'layoutSection'].includes(nodeName)) {
|
|
27
28
|
// Layout nodes do not need special styling
|
|
28
29
|
return undefined;
|
|
29
30
|
}
|
|
31
|
+
if (['tableCell', 'tableHeader'].includes(nodeName)) {
|
|
32
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
33
|
+
// This is used for positioning the cell overlay widget decorations
|
|
34
|
+
return convertToInlineCss({
|
|
35
|
+
position: 'relative'
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// When gate is off, it should return undefined as above
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
30
41
|
if (['extension', 'embedCard', 'listItem'].includes(nodeName)) {
|
|
31
42
|
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
32
43
|
if (isInserted) {
|
|
@@ -92,6 +103,17 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
|
|
|
92
103
|
isInserted = _ref2$isInserted === void 0 ? true : _ref2$isInserted,
|
|
93
104
|
_ref2$isActive = _ref2.isActive,
|
|
94
105
|
isActive = _ref2$isActive === void 0 ? false : _ref2$isActive;
|
|
106
|
+
var decorations = [];
|
|
107
|
+
if (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) && ['tableCell', 'tableHeader'].includes(change.name)) {
|
|
108
|
+
var cellOverlay = document.createElement('div');
|
|
109
|
+
var cellOverlayStyle = isInserted ? colorScheme === 'traditional' ? traditionalAddedCellOverlayStyle : addedCellOverlayStyle : colorScheme === 'traditional' ? deletedTraditionalCellOverlayStyle : deletedCellOverlayStyle;
|
|
110
|
+
cellOverlay.setAttribute('style', cellOverlayStyle);
|
|
111
|
+
decorations.push(
|
|
112
|
+
// change.to - 1 to position the overlay inside the end of the cell
|
|
113
|
+
Decoration.widget(change.to - 1, cellOverlay, {
|
|
114
|
+
key: "diff-widget-cell-overlay-".concat(change.to)
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
95
117
|
var style = getBlockNodeStyle({
|
|
96
118
|
nodeName: change.name,
|
|
97
119
|
colorScheme: colorScheme,
|
|
@@ -108,24 +130,24 @@ export var createBlockChangedDecoration = function createBlockChangedDecoration(
|
|
|
108
130
|
var className = getNodeClass(change.name);
|
|
109
131
|
if (fg('platform_editor_show_diff_scroll_navigation')) {
|
|
110
132
|
if (style || className) {
|
|
111
|
-
|
|
133
|
+
decorations.push(Decoration.node(change.from, change.to, {
|
|
112
134
|
style: style,
|
|
113
135
|
'data-testid': 'show-diff-changed-decoration-node',
|
|
114
136
|
class: className
|
|
115
137
|
}, {
|
|
116
138
|
key: 'diff-block',
|
|
117
139
|
nodeName: change.name
|
|
118
|
-
});
|
|
119
|
-
} else {
|
|
120
|
-
return undefined;
|
|
140
|
+
}));
|
|
121
141
|
}
|
|
142
|
+
} else {
|
|
143
|
+
decorations.push(Decoration.node(change.from, change.to, {
|
|
144
|
+
style: style,
|
|
145
|
+
'data-testid': 'show-diff-changed-decoration-node',
|
|
146
|
+
class: className
|
|
147
|
+
}, {
|
|
148
|
+
key: 'diff-block',
|
|
149
|
+
nodeName: change.name
|
|
150
|
+
}));
|
|
122
151
|
}
|
|
123
|
-
return
|
|
124
|
-
style: style,
|
|
125
|
-
'data-testid': 'show-diff-changed-decoration-node',
|
|
126
|
-
class: className
|
|
127
|
-
}, {
|
|
128
|
-
key: 'diff-block',
|
|
129
|
-
nodeName: change.name
|
|
130
|
-
});
|
|
152
|
+
return decorations;
|
|
131
153
|
};
|
|
@@ -13,7 +13,10 @@ import { findSafeInsertPos } from './utils/findSafeInsertPos';
|
|
|
13
13
|
/**
|
|
14
14
|
* Extracts information about deleted table rows from a change
|
|
15
15
|
*/
|
|
16
|
-
var extractChangedRows = function extractChangedRows(
|
|
16
|
+
var extractChangedRows = function extractChangedRows(_ref) {
|
|
17
|
+
var change = _ref.change,
|
|
18
|
+
originalDoc = _ref.originalDoc,
|
|
19
|
+
newDoc = _ref.newDoc;
|
|
17
20
|
var changedRows = [];
|
|
18
21
|
|
|
19
22
|
// Find the table in the original document
|
|
@@ -35,7 +38,6 @@ var extractChangedRows = function extractChangedRows(change, originalDoc, newDoc
|
|
|
35
38
|
return changedRows;
|
|
36
39
|
}
|
|
37
40
|
var newTableMap = TableMap.get(tableNew.node);
|
|
38
|
-
|
|
39
41
|
// If no rows were changed, return empty
|
|
40
42
|
if (oldTableMap.height <= newTableMap.height ||
|
|
41
43
|
// For now ignore if there are column deletions as well
|
|
@@ -54,7 +56,7 @@ var extractChangedRows = function extractChangedRows(change, originalDoc, newDoc
|
|
|
54
56
|
|
|
55
57
|
// Check if this row overlaps with the deletion range
|
|
56
58
|
var rowOverlapsChange = rowStart >= changeStartInTable && rowStart < changeEndInTable || rowEnd > changeStartInTable && rowEnd <= changeEndInTable || rowStart < changeStartInTable && rowEnd > changeEndInTable;
|
|
57
|
-
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && !isEmptyRow(rowNode)) {
|
|
59
|
+
if (rowOverlapsChange && rowNode.type.name === 'tableRow' && (expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true) || !isEmptyRow(rowNode))) {
|
|
58
60
|
var startOfRow = newTableMap.mapByRow.slice().reverse().find(function (row) {
|
|
59
61
|
return row[0] + tableNew.pos < change.fromB && change.fromB < row[row.length - 1] + tableNew.pos;
|
|
60
62
|
});
|
|
@@ -125,7 +127,7 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
125
127
|
if (cellNode.type.name === 'tableCell' || cellNode.type.name === 'tableHeader') {
|
|
126
128
|
var nodeView = nodeViewSerializer.tryCreateNodeView(cellNode);
|
|
127
129
|
if (nodeView) {
|
|
128
|
-
if (
|
|
130
|
+
if (nodeView instanceof HTMLElement && expValEquals('platform_editor_diff_plugin_extended', 'isEnabled', true)) {
|
|
129
131
|
var overlay = document.createElement('span');
|
|
130
132
|
var overlayStyle = colorScheme === 'traditional' ? isInserted ? traditionalAddedCellOverlayStyle : deletedTraditionalCellOverlayStyle : isInserted ? addedCellOverlayStyle : deletedCellOverlayStyle;
|
|
131
133
|
overlay.setAttribute('style', overlayStyle);
|
|
@@ -147,7 +149,10 @@ var createChangedRowDOM = function createChangedRowDOM(rowNode, nodeViewSerializ
|
|
|
147
149
|
/**
|
|
148
150
|
* Expands a diff to include whole changed rows when table rows are affected
|
|
149
151
|
*/
|
|
150
|
-
var expandDiffForChangedRows = function expandDiffForChangedRows(
|
|
152
|
+
var expandDiffForChangedRows = function expandDiffForChangedRows(_ref2) {
|
|
153
|
+
var changes = _ref2.changes,
|
|
154
|
+
originalDoc = _ref2.originalDoc,
|
|
155
|
+
newDoc = _ref2.newDoc;
|
|
151
156
|
var rowInfo = [];
|
|
152
157
|
var _iterator = _createForOfIteratorHelper(changes),
|
|
153
158
|
_step;
|
|
@@ -155,7 +160,11 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(changes, origin
|
|
|
155
160
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
156
161
|
var change = _step.value;
|
|
157
162
|
// Check if this change affects table content
|
|
158
|
-
var changedRows = extractChangedRows(
|
|
163
|
+
var changedRows = extractChangedRows({
|
|
164
|
+
change: change,
|
|
165
|
+
originalDoc: originalDoc,
|
|
166
|
+
newDoc: newDoc
|
|
167
|
+
});
|
|
159
168
|
if (changedRows.length > 0) {
|
|
160
169
|
rowInfo.push.apply(rowInfo, _toConsumableArray(changedRows));
|
|
161
170
|
}
|
|
@@ -171,18 +180,22 @@ var expandDiffForChangedRows = function expandDiffForChangedRows(changes, origin
|
|
|
171
180
|
/**
|
|
172
181
|
* Main function to handle deleted rows - computes diff and creates decorations
|
|
173
182
|
*/
|
|
174
|
-
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(
|
|
175
|
-
var changes =
|
|
176
|
-
originalDoc =
|
|
177
|
-
newDoc =
|
|
178
|
-
nodeViewSerializer =
|
|
179
|
-
colorScheme =
|
|
180
|
-
|
|
181
|
-
isInserted =
|
|
183
|
+
export var createChangedRowDecorationWidgets = function createChangedRowDecorationWidgets(_ref3) {
|
|
184
|
+
var changes = _ref3.changes,
|
|
185
|
+
originalDoc = _ref3.originalDoc,
|
|
186
|
+
newDoc = _ref3.newDoc,
|
|
187
|
+
nodeViewSerializer = _ref3.nodeViewSerializer,
|
|
188
|
+
colorScheme = _ref3.colorScheme,
|
|
189
|
+
_ref3$isInserted = _ref3.isInserted,
|
|
190
|
+
isInserted = _ref3$isInserted === void 0 ? false : _ref3$isInserted;
|
|
182
191
|
// First, expand the changes to include complete deleted rows
|
|
183
|
-
var changedRows = expandDiffForChangedRows(
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
var changedRows = expandDiffForChangedRows({
|
|
193
|
+
changes: changes.filter(function (change) {
|
|
194
|
+
return change.deleted.length > 0;
|
|
195
|
+
}),
|
|
196
|
+
originalDoc: originalDoc,
|
|
197
|
+
newDoc: newDoc
|
|
198
|
+
});
|
|
186
199
|
return changedRows.map(function (changedRow) {
|
|
187
200
|
var rowDOM = createChangedRowDOM(changedRow.rowNode, nodeViewSerializer, colorScheme, isInserted);
|
|
188
201
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Change } from 'prosemirror-changeset';
|
|
2
|
+
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
export declare const diffBySteps: (originalDoc: PMNode, steps: Step[]) => Change[];
|
|
@@ -5,7 +5,7 @@ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
|
|
|
5
5
|
import type { Node } from '@atlaskit/editor-prosemirror/model';
|
|
6
6
|
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
7
7
|
export type ColorScheme = 'standard' | 'traditional';
|
|
8
|
-
export type DiffType = 'inline' | 'block';
|
|
8
|
+
export type DiffType = 'inline' | 'block' | 'step';
|
|
9
9
|
export type DiffParams = {
|
|
10
10
|
/**
|
|
11
11
|
* Color scheme to use for displaying diffs.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Change } from 'prosemirror-changeset';
|
|
2
|
+
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
export declare const diffBySteps: (originalDoc: PMNode, steps: Step[]) => Change[];
|
|
@@ -5,7 +5,7 @@ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
|
|
|
5
5
|
import type { Node } from '@atlaskit/editor-prosemirror/model';
|
|
6
6
|
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
7
7
|
export type ColorScheme = 'standard' | 'traditional';
|
|
8
|
-
export type DiffType = 'inline' | 'block';
|
|
8
|
+
export type DiffType = 'inline' | 'block' | 'step';
|
|
9
9
|
export type DiffParams = {
|
|
10
10
|
/**
|
|
11
11
|
* Color scheme to use for displaying diffs.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-show-diff",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "ShowDiff plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
35
35
|
"@atlaskit/editor-tables": "^2.9.0",
|
|
36
36
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
37
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
38
|
-
"@atlaskit/tokens": "^
|
|
37
|
+
"@atlaskit/tmp-editor-statsig": "^60.2.0",
|
|
38
|
+
"@atlaskit/tokens": "^13.0.0",
|
|
39
39
|
"@babel/runtime": "^7.0.0",
|
|
40
40
|
"lodash": "^4.17.21",
|
|
41
41
|
"memoize-one": "^6.0.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@atlaskit/editor-core": "^217.12.0",
|
|
49
49
|
"@atlaskit/editor-json-transformer": "^8.31.0",
|
|
50
50
|
"@atlaskit/form": "^15.5.0",
|
|
51
|
-
"@atlaskit/primitives": "^
|
|
51
|
+
"@atlaskit/primitives": "^19.0.0",
|
|
52
52
|
"@atlaskit/section-message": "^8.12.0",
|
|
53
53
|
"@atlaskit/textarea": "^8.2.0",
|
|
54
54
|
"@atlassian/confluence-presets": "workspace:^",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@atlaskit/editor-common": "^112.
|
|
59
|
+
"@atlaskit/editor-common": "^112.20.0",
|
|
60
60
|
"react": "^18.2.0"
|
|
61
61
|
},
|
|
62
62
|
"techstack": {
|