@atlaskit/editor-plugin-show-diff 16.1.1 → 17.0.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 +23 -0
- package/afm-products/tsconfig.json +3 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +67 -22
- package/dist/cjs/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +242 -26
- package/dist/cjs/pm-plugins/decorations/colorSchemes/factory.js +71 -37
- package/dist/cjs/pm-plugins/decorations/colorSchemes/schemes.js +5 -1
- package/dist/cjs/pm-plugins/decorations/colorSchemes/types.js +0 -2
- package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +21 -14
- package/dist/cjs/pm-plugins/decorations/extractContributorTags.js +123 -43
- package/dist/cjs/pm-plugins/decorations/revealStyles.js +5 -1
- package/dist/cjs/pm-plugins/getScrollableDecorations.js +48 -19
- package/dist/cjs/pm-plugins/utils/baseNodeName.js +25 -0
- package/dist/cjs/pm-plugins/utils/taggableBlockNodes.js +37 -0
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +39 -2
- package/dist/es2019/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +196 -10
- package/dist/es2019/pm-plugins/decorations/colorSchemes/factory.js +51 -19
- package/dist/es2019/pm-plugins/decorations/colorSchemes/schemes.js +3 -0
- package/dist/es2019/pm-plugins/decorations/colorSchemes/types.js +0 -2
- package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +23 -14
- package/dist/es2019/pm-plugins/decorations/extractContributorTags.js +60 -7
- package/dist/es2019/pm-plugins/decorations/revealStyles.js +5 -1
- package/dist/es2019/pm-plugins/getScrollableDecorations.js +44 -19
- package/dist/es2019/pm-plugins/utils/baseNodeName.js +18 -0
- package/dist/es2019/pm-plugins/utils/taggableBlockNodes.js +28 -0
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +67 -22
- package/dist/esm/pm-plugins/calculateDiff/simplifyChangesWithAttribution.js +243 -26
- package/dist/esm/pm-plugins/decorations/colorSchemes/factory.js +71 -37
- package/dist/esm/pm-plugins/decorations/colorSchemes/schemes.js +5 -1
- package/dist/esm/pm-plugins/decorations/colorSchemes/types.js +0 -2
- package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +21 -14
- package/dist/esm/pm-plugins/decorations/extractContributorTags.js +123 -43
- package/dist/esm/pm-plugins/decorations/revealStyles.js +5 -1
- package/dist/esm/pm-plugins/getScrollableDecorations.js +48 -19
- package/dist/esm/pm-plugins/utils/baseNodeName.js +20 -0
- package/dist/esm/pm-plugins/utils/taggableBlockNodes.js +32 -0
- package/dist/types/pm-plugins/calculateDiff/simplifyChangesWithAttribution.d.ts +20 -1
- package/dist/types/pm-plugins/decorations/colorSchemes/factory.d.ts +4 -11
- package/dist/types/pm-plugins/decorations/colorSchemes/types.d.ts +9 -8
- package/dist/types/pm-plugins/getScrollableDecorations.d.ts +2 -2
- package/dist/types/pm-plugins/utils/baseNodeName.d.ts +16 -0
- package/dist/types/pm-plugins/utils/taggableBlockNodes.d.ts +14 -0
- package/package.json +12 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-show-diff
|
|
2
2
|
|
|
3
|
+
## 17.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 16.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`b2a2413928cac`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b2a2413928cac) -
|
|
14
|
+
Match agent highlights, cursors and review diffs to shared Studio and third-party brand colours
|
|
15
|
+
under the existing telepointer redesign. Use the existing purple attribution treatment for Rovo
|
|
16
|
+
review diffs and preserve square Rovo telepointer avatars.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [`8c53dda37401d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8c53dda37401d) -
|
|
21
|
+
Fix contributor tags on block nodes, behind `confluence_ncs_step_diffing_version_history`. Changes
|
|
22
|
+
are now split per contributor instead of being credited to whoever wrote last, so each
|
|
23
|
+
contributor's change hosts its own tag and is its own navigation stop.
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
|
|
3
26
|
## 16.1.1
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -197,8 +197,51 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
197
197
|
diffType = _ref5.diffType,
|
|
198
198
|
_ref5$coarseTableCell = _ref5.coarseTableCellsOnly,
|
|
199
199
|
coarseTableCellsOnly = _ref5$coarseTableCell === void 0 ? false : _ref5$coarseTableCell,
|
|
200
|
-
tagMountContext = _ref5.tagMountContext
|
|
200
|
+
tagMountContext = _ref5.tagMountContext,
|
|
201
|
+
nodeRanges = _ref5.nodeRanges;
|
|
201
202
|
var decorations = [];
|
|
203
|
+
|
|
204
|
+
// Exact-nodes path: only reached for a split change (EDITOR-8932), which names the nodes it
|
|
205
|
+
// owns. Deliberately kept separate from the walk below rather than sharing it.
|
|
206
|
+
if (nodeRanges) {
|
|
207
|
+
var _iterator = _createForOfIteratorHelper(nodeRanges),
|
|
208
|
+
_step;
|
|
209
|
+
try {
|
|
210
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
211
|
+
var _step$value = _step.value,
|
|
212
|
+
pos = _step$value.from,
|
|
213
|
+
nodeEnd = _step$value.to;
|
|
214
|
+
var node = doc.nodeAt(pos);
|
|
215
|
+
if (!(node !== null && node !== void 0 && node.isBlock)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
var isActive = isRangeActive(activeIndexPos, pos, nodeEnd);
|
|
219
|
+
decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createBlockChangedDecoration.createBlockChangedDecoration)({
|
|
220
|
+
attributionKey: attributionKey,
|
|
221
|
+
change: {
|
|
222
|
+
from: pos,
|
|
223
|
+
to: nodeEnd,
|
|
224
|
+
name: node.type.name
|
|
225
|
+
},
|
|
226
|
+
colorScheme: colorScheme,
|
|
227
|
+
isInserted: isInserted,
|
|
228
|
+
isActive: isActive,
|
|
229
|
+
shouldHideDeleted: shouldHideDeleted,
|
|
230
|
+
showContributorTags: showContributorTags,
|
|
231
|
+
showIndicators: showIndicators,
|
|
232
|
+
doc: doc,
|
|
233
|
+
diffType: diffType,
|
|
234
|
+
tagMountContext: tagMountContext
|
|
235
|
+
})));
|
|
236
|
+
}
|
|
237
|
+
} catch (err) {
|
|
238
|
+
_iterator.e(err);
|
|
239
|
+
} finally {
|
|
240
|
+
_iterator.f();
|
|
241
|
+
}
|
|
242
|
+
return decorations;
|
|
243
|
+
}
|
|
244
|
+
|
|
202
245
|
// Coarse path: inside the large table, only cell/header overlays are kept — the
|
|
203
246
|
// table/row/paragraph decorations there are redundant and cause expensive per-cell
|
|
204
247
|
// re-render. Blocks outside the table keep their normal decorations.
|
|
@@ -212,18 +255,18 @@ var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration
|
|
|
212
255
|
}
|
|
213
256
|
}
|
|
214
257
|
if (node.isBlock && (!(0, _isExtendedEnabled.isExtendedEnabled)(diffType) || pos + node.nodeSize <= to)) {
|
|
215
|
-
var
|
|
216
|
-
var
|
|
258
|
+
var _nodeEnd = pos + node.nodeSize;
|
|
259
|
+
var _isActive = isRangeActive(activeIndexPos, pos, _nodeEnd);
|
|
217
260
|
decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createBlockChangedDecoration.createBlockChangedDecoration)({
|
|
218
261
|
attributionKey: attributionKey,
|
|
219
262
|
change: {
|
|
220
263
|
from: pos,
|
|
221
|
-
to:
|
|
264
|
+
to: _nodeEnd,
|
|
222
265
|
name: node.type.name
|
|
223
266
|
},
|
|
224
267
|
colorScheme: colorScheme,
|
|
225
268
|
isInserted: isInserted,
|
|
226
|
-
isActive:
|
|
269
|
+
isActive: _isActive,
|
|
227
270
|
shouldHideDeleted: shouldHideDeleted,
|
|
228
271
|
showContributorTags: showContributorTags,
|
|
229
272
|
showIndicators: showIndicators,
|
|
@@ -346,13 +389,13 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
346
389
|
}
|
|
347
390
|
var pendingAttrSteps = [];
|
|
348
391
|
var stepMaps = [];
|
|
349
|
-
var
|
|
350
|
-
|
|
392
|
+
var _iterator2 = _createForOfIteratorHelper(simplifiedSteps.entries()),
|
|
393
|
+
_step2;
|
|
351
394
|
try {
|
|
352
|
-
for (
|
|
353
|
-
var
|
|
354
|
-
stepIndex =
|
|
355
|
-
step =
|
|
395
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
396
|
+
var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2),
|
|
397
|
+
stepIndex = _step2$value[0],
|
|
398
|
+
step = _step2$value[1];
|
|
356
399
|
var result = step.apply(steppedDoc);
|
|
357
400
|
if (result.failed === null && result.doc) {
|
|
358
401
|
if ((0, _getAttrChangeRanges.stepIsValidAttrChange)(step, steppedDoc, result.doc)) {
|
|
@@ -371,9 +414,9 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
371
414
|
// Gate the complete attribution fix: mapped positions and step-time nodes are used together.
|
|
372
415
|
// The fallback deliberately preserves the legacy raw-position lookups for rollout safety.
|
|
373
416
|
} catch (err) {
|
|
374
|
-
|
|
417
|
+
_iterator2.e(err);
|
|
375
418
|
} finally {
|
|
376
|
-
|
|
419
|
+
_iterator2.f();
|
|
377
420
|
}
|
|
378
421
|
var attrStepContexts = (0, _fg.fg)('platform_editor_reduce_diff_attr_sensitivity') ? pendingAttrSteps.flatMap(function (_ref1) {
|
|
379
422
|
var afterNode = _ref1.afterNode,
|
|
@@ -461,7 +504,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
461
504
|
tr: tr,
|
|
462
505
|
attributedChanges: attributedChanges
|
|
463
506
|
});
|
|
464
|
-
changes = (0, _simplifyChangesWithAttribution.collapseOverlappingChanges)(uncollapsedChanges);
|
|
507
|
+
changes = (0, _simplifyChangesWithAttribution.collapseOverlappingChanges)(uncollapsedChanges, tr.doc);
|
|
465
508
|
|
|
466
509
|
// Still colours-only: a tags-only diff keeps the plain colour scheme.
|
|
467
510
|
if (attributionColoringEnabled) {
|
|
@@ -558,13 +601,13 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
558
601
|
// table (the cell overlays added below provide the highlight without the
|
|
559
602
|
// expensive content re-render); leaf blocks outside the table still get theirs.
|
|
560
603
|
var coarseTables = useCoarseTableDecoration ? tableRanges(tr.doc, change.fromB, change.toB) : [];
|
|
561
|
-
var
|
|
562
|
-
|
|
604
|
+
var _iterator3 = _createForOfIteratorHelper(leafTextblockRanges(tr.doc, change.fromB, change.toB)),
|
|
605
|
+
_step3;
|
|
563
606
|
try {
|
|
564
|
-
for (
|
|
565
|
-
var
|
|
566
|
-
from =
|
|
567
|
-
to =
|
|
607
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
608
|
+
var _step3$value = (0, _slicedToArray2.default)(_step3.value, 2),
|
|
609
|
+
from = _step3$value[0],
|
|
610
|
+
to = _step3$value[1];
|
|
568
611
|
if (useCoarseTableDecoration && isInsideTable(coarseTables, from)) {
|
|
569
612
|
continue;
|
|
570
613
|
}
|
|
@@ -591,9 +634,9 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
591
634
|
}))));
|
|
592
635
|
}
|
|
593
636
|
} catch (err) {
|
|
594
|
-
|
|
637
|
+
_iterator3.e(err);
|
|
595
638
|
} finally {
|
|
596
|
-
|
|
639
|
+
_iterator3.f();
|
|
597
640
|
}
|
|
598
641
|
} else {
|
|
599
642
|
decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createInlineChangedDecoration.createInlineChangedDecoration)(_objectSpread({
|
|
@@ -620,6 +663,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref8
|
|
|
620
663
|
doc: tr.doc,
|
|
621
664
|
from: change.fromB,
|
|
622
665
|
to: change.toB,
|
|
666
|
+
// A split piece's own range no longer covers the container it opened (EDITOR-8932).
|
|
667
|
+
nodeRanges: change.blockNodeRangesB,
|
|
623
668
|
colorScheme: changeColorScheme
|
|
624
669
|
}, (0, _isExtendedEnabled.isExtendedEnabled)(diffType) && {
|
|
625
670
|
isInserted: isInserted,
|
|
@@ -10,11 +10,17 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
|
|
|
10
10
|
var _prosemirrorChangeset = require("prosemirror-changeset");
|
|
11
11
|
var _attributions = require("../decorations/colorSchemes/attributions");
|
|
12
12
|
var _optimizeChanges = require("./optimizeChanges");
|
|
13
|
-
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; }
|
|
14
|
-
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; }
|
|
15
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; } } }; }
|
|
16
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; } }
|
|
17
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
|
+
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; }
|
|
17
|
+
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; }
|
|
18
|
+
/**
|
|
19
|
+
* A change, plus the block nodes it owns when it is one piece of a split — a piece's own range no
|
|
20
|
+
* longer covers the container it opened. Absent on an unsplit change, which decorates the blocks
|
|
21
|
+
* inside its own range as before.
|
|
22
|
+
*/
|
|
23
|
+
|
|
18
24
|
var getAttributionIdentity = function getAttributionIdentity(change) {
|
|
19
25
|
var identities = new Set();
|
|
20
26
|
for (var _i = 0, _arr = [].concat((0, _toConsumableArray2.default)(change.deleted), (0, _toConsumableArray2.default)(change.inserted)); _i < _arr.length; _i++) {
|
|
@@ -36,55 +42,265 @@ var byNewDocRange = function byNewDocRange(left, right) {
|
|
|
36
42
|
return left.fromB - right.fromB || left.toB - right.toB;
|
|
37
43
|
};
|
|
38
44
|
|
|
45
|
+
/** Union of the given ranges, with overlapping and touching ones merged. */
|
|
46
|
+
var mergeRanges = function mergeRanges(ranges) {
|
|
47
|
+
return (0, _toConsumableArray2.default)(ranges).sort(function (left, right) {
|
|
48
|
+
return left.from - right.from;
|
|
49
|
+
}).reduce(function (merged, range) {
|
|
50
|
+
var last = merged[merged.length - 1];
|
|
51
|
+
if (last && range.from <= last.to) {
|
|
52
|
+
last.to = Math.max(last.to, range.to);
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
return [].concat((0, _toConsumableArray2.default)(merged), [_objectSpread({}, range)]);
|
|
56
|
+
}, []);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** Whether `inner` sits wholly inside `outer` and covers less of the document. */
|
|
60
|
+
var isContained = function isContained(outer, inner) {
|
|
61
|
+
return inner.toB > inner.fromB && outer.fromB <= inner.fromB && inner.toB <= outer.toB && inner.toB - inner.fromB < outer.toB - outer.fromB;
|
|
62
|
+
};
|
|
63
|
+
|
|
39
64
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* Merging keeps every span from both sides, so the latest-writer rule still decides whose tag is
|
|
45
|
-
* shown. Ranges that merely touch are left alone, so an unattributed edit next to an attributed one
|
|
46
|
-
* is not credited to it.
|
|
65
|
+
* The block nodes in `change` whose opening position `ownsPosition` claims. Ownership is by opening
|
|
66
|
+
* position so a block another contributor added inside a container is not claimed by whoever opened
|
|
67
|
+
* the container. `undefined` for a range this document cannot resolve, which falls the piece back
|
|
68
|
+
* to decorating its own range.
|
|
47
69
|
*/
|
|
48
|
-
var
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
70
|
+
var blockNodeRanges = function blockNodeRanges(doc, change, ownsPosition) {
|
|
71
|
+
if (!doc || change.from >= change.to || change.to > doc.content.size) {
|
|
72
|
+
return undefined;
|
|
51
73
|
}
|
|
74
|
+
var ranges = [];
|
|
75
|
+
doc.nodesBetween(change.from, change.to, function (node, pos) {
|
|
76
|
+
if (node.isBlock && ownsPosition(pos) && pos + node.nodeSize <= change.to) {
|
|
77
|
+
ranges.push({
|
|
78
|
+
from: pos,
|
|
79
|
+
to: pos + node.nodeSize
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
return ranges;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Splits a change whose spans name more than one contributor into one change per run of consecutive
|
|
89
|
+
* spans sharing a key.
|
|
90
|
+
*
|
|
91
|
+
* `prosemirror-changeset` merges contiguous inserted content into one change while keeping per-span
|
|
92
|
+
* data, so a panel inserted by one contributor and edited inside by another arrives as a single
|
|
93
|
+
* change holding every span — and the latest-writer rule credited all of it, panel included, to
|
|
94
|
+
* whoever wrote last (EDITOR-8932).
|
|
95
|
+
*/
|
|
96
|
+
var splitMixedIdentityChanges = function splitMixedIdentityChanges(changes, doc) {
|
|
97
|
+
return changes.flatMap(function (change) {
|
|
98
|
+
if (getAttributionIdentity(change).mergeable) {
|
|
99
|
+
return [change];
|
|
100
|
+
}
|
|
101
|
+
var runs = [];
|
|
102
|
+
var offset = change.fromB;
|
|
103
|
+
var _iterator = _createForOfIteratorHelper(change.inserted),
|
|
104
|
+
_step;
|
|
105
|
+
try {
|
|
106
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
107
|
+
var span = _step.value;
|
|
108
|
+
var key = (0, _attributions.getAttributionKey)(span.data);
|
|
109
|
+
var last = runs[runs.length - 1];
|
|
110
|
+
if (last && last.key === key) {
|
|
111
|
+
last.to = offset + span.length;
|
|
112
|
+
last.spans.push(span);
|
|
113
|
+
} else {
|
|
114
|
+
runs.push({
|
|
115
|
+
key: key,
|
|
116
|
+
from: offset,
|
|
117
|
+
to: offset + span.length,
|
|
118
|
+
spans: [span]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
offset += span.length;
|
|
122
|
+
}
|
|
52
123
|
|
|
124
|
+
// The offsets above are only positions if the spans partition the inserted range.
|
|
125
|
+
} catch (err) {
|
|
126
|
+
_iterator.e(err);
|
|
127
|
+
} finally {
|
|
128
|
+
_iterator.f();
|
|
129
|
+
}
|
|
130
|
+
if (runs.length < 2 || offset !== change.toB) {
|
|
131
|
+
return [change];
|
|
132
|
+
}
|
|
133
|
+
return runs.map(function (run, index) {
|
|
134
|
+
var owned = blockNodeRanges(doc, {
|
|
135
|
+
from: change.fromB,
|
|
136
|
+
to: change.toB
|
|
137
|
+
}, function (pos) {
|
|
138
|
+
return pos >= run.from && pos < run.to;
|
|
139
|
+
});
|
|
140
|
+
return _objectSpread(_objectSpread({}, change), {}, {
|
|
141
|
+
fromA: index === 0 ? change.fromA : change.toA,
|
|
142
|
+
fromB: run.from,
|
|
143
|
+
toB: run.to,
|
|
144
|
+
deleted: index === 0 ? change.deleted : [],
|
|
145
|
+
inserted: run.spans
|
|
146
|
+
}, owned ? {
|
|
147
|
+
blockNodeRangesB: owned
|
|
148
|
+
} : {});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Subtracts every other author's contained change from a change's range, so both contributions
|
|
155
|
+
* survive. Applies when the contributors arrive as separate changes rather than as spans of one —
|
|
156
|
+
* the `step` diff type. A contained change by the same author, and one that only partially
|
|
157
|
+
* overlaps, are left for the collapse below.
|
|
158
|
+
*
|
|
159
|
+
* The leading fragment keeps the deleted side, so one deletion is not drawn once per fragment.
|
|
160
|
+
*/
|
|
161
|
+
var splitContainedChanges = function splitContainedChanges(changes, doc) {
|
|
162
|
+
return changes.flatMap(function (change) {
|
|
163
|
+
var _getAttributionIdenti = getAttributionIdentity(change),
|
|
164
|
+
key = _getAttributionIdenti.key;
|
|
165
|
+
var inner = mergeRanges(changes.filter(function (other) {
|
|
166
|
+
var otherKey = getAttributionIdentity(other).key;
|
|
167
|
+
return other !== change && key !== undefined && otherKey !== undefined && otherKey !== key && isContained(change, other);
|
|
168
|
+
}).map(function (_ref) {
|
|
169
|
+
var fromB = _ref.fromB,
|
|
170
|
+
toB = _ref.toB;
|
|
171
|
+
return {
|
|
172
|
+
from: fromB,
|
|
173
|
+
to: toB
|
|
174
|
+
};
|
|
175
|
+
}));
|
|
176
|
+
if (inner.length === 0) {
|
|
177
|
+
return [change];
|
|
178
|
+
}
|
|
179
|
+
var gaps = [];
|
|
180
|
+
var cursor = change.fromB;
|
|
181
|
+
var _iterator2 = _createForOfIteratorHelper(inner),
|
|
182
|
+
_step2;
|
|
183
|
+
try {
|
|
184
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
185
|
+
var _step2$value = _step2.value,
|
|
186
|
+
from = _step2$value.from,
|
|
187
|
+
to = _step2$value.to;
|
|
188
|
+
if (from > cursor) {
|
|
189
|
+
gaps.push({
|
|
190
|
+
from: cursor,
|
|
191
|
+
to: from
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
cursor = Math.max(cursor, to);
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
_iterator2.e(err);
|
|
198
|
+
} finally {
|
|
199
|
+
_iterator2.f();
|
|
200
|
+
}
|
|
201
|
+
if (change.toB > cursor) {
|
|
202
|
+
gaps.push({
|
|
203
|
+
from: cursor,
|
|
204
|
+
to: change.toB
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Subtracted end to end, so nothing is left to highlight — but the blocks are still owned.
|
|
209
|
+
var fragments = gaps.length > 0 ? gaps : [{
|
|
210
|
+
from: change.toB,
|
|
211
|
+
to: change.toB
|
|
212
|
+
}];
|
|
213
|
+
// The outer author's: every block in their range that no inner change opened.
|
|
214
|
+
var owned = blockNodeRanges(doc, {
|
|
215
|
+
from: change.fromB,
|
|
216
|
+
to: change.toB
|
|
217
|
+
}, function (pos) {
|
|
218
|
+
return !inner.some(function (_ref2) {
|
|
219
|
+
var from = _ref2.from,
|
|
220
|
+
to = _ref2.to;
|
|
221
|
+
return pos >= from && pos < to;
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
return fragments.map(function (fragment, index) {
|
|
225
|
+
return _objectSpread(_objectSpread({}, change), {}, {
|
|
226
|
+
fromA: index === 0 ? change.fromA : change.toA,
|
|
227
|
+
fromB: fragment.from,
|
|
228
|
+
toB: fragment.to,
|
|
229
|
+
deleted: index === 0 ? change.deleted : []
|
|
230
|
+
}, owned ? {
|
|
231
|
+
blockNodeRangesB: index === 0 ? owned : []
|
|
232
|
+
} : {});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The blocks a merged change owns. Both sides must name theirs, or the merge falls back to its own
|
|
239
|
+
* range — narrowing it could drop a block altogether.
|
|
240
|
+
*/
|
|
241
|
+
var mergeBlockNodeRanges = function mergeBlockNodeRanges(left, right) {
|
|
242
|
+
return left.blockNodeRangesB && right.blockNodeRangesB ? [].concat((0, _toConsumableArray2.default)(left.blockNodeRangesB), (0, _toConsumableArray2.default)(right.blockNodeRangesB)) : undefined;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/** Unions the changes whose new-document ranges strictly overlap, leaving touching ones alone. */
|
|
246
|
+
var collapse = function collapse(changes) {
|
|
53
247
|
// A zero-length new-document range paints no inline decoration, so it is kept aside rather than
|
|
54
248
|
// folded into a neighbouring insertion.
|
|
55
249
|
var emptyRanges = changes.filter(function (change) {
|
|
56
250
|
return change.toB <= change.fromB;
|
|
57
251
|
});
|
|
58
252
|
var collapsed = [];
|
|
59
|
-
var
|
|
253
|
+
var _iterator3 = _createForOfIteratorHelper(changes.filter(function (change) {
|
|
60
254
|
return change.toB > change.fromB;
|
|
61
255
|
}).sort(byNewDocRange)),
|
|
62
|
-
|
|
256
|
+
_step3;
|
|
63
257
|
try {
|
|
64
|
-
for (
|
|
65
|
-
var change =
|
|
258
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
259
|
+
var change = _step3.value;
|
|
66
260
|
var current = collapsed[collapsed.length - 1];
|
|
67
261
|
if (current && change.fromB < current.toB) {
|
|
68
|
-
|
|
262
|
+
var blockNodeRangesB = mergeBlockNodeRanges(current, change);
|
|
263
|
+
collapsed[collapsed.length - 1] = _objectSpread({
|
|
69
264
|
fromA: Math.min(current.fromA, change.fromA),
|
|
70
265
|
toA: Math.max(current.toA, change.toA),
|
|
71
266
|
fromB: Math.min(current.fromB, change.fromB),
|
|
72
267
|
toB: Math.max(current.toB, change.toB),
|
|
73
268
|
deleted: [].concat((0, _toConsumableArray2.default)(current.deleted), (0, _toConsumableArray2.default)(change.deleted)),
|
|
74
269
|
inserted: [].concat((0, _toConsumableArray2.default)(current.inserted), (0, _toConsumableArray2.default)(change.inserted))
|
|
75
|
-
}
|
|
270
|
+
}, blockNodeRangesB ? {
|
|
271
|
+
blockNodeRangesB: blockNodeRangesB
|
|
272
|
+
} : {});
|
|
76
273
|
} else {
|
|
77
274
|
collapsed.push(_objectSpread({}, change));
|
|
78
275
|
}
|
|
79
276
|
}
|
|
80
277
|
} catch (err) {
|
|
81
|
-
|
|
278
|
+
_iterator3.e(err);
|
|
82
279
|
} finally {
|
|
83
|
-
|
|
280
|
+
_iterator3.f();
|
|
84
281
|
}
|
|
85
282
|
return [].concat(collapsed, (0, _toConsumableArray2.default)(emptyRanges)).sort(byNewDocRange);
|
|
86
283
|
};
|
|
87
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Collapses changes whose new-document ranges strictly overlap. Attribution runs are simplified
|
|
287
|
+
* independently, so runs either side of an unattributed step can come back covering the same
|
|
288
|
+
* characters — which stacks two inline decorations and renders one contributor tag per copy.
|
|
289
|
+
*
|
|
290
|
+
* Merging keeps every span from both sides, so the latest-writer rule still decides whose tag is
|
|
291
|
+
* shown. Ranges that merely touch are left alone, so an unattributed edit next to an attributed one
|
|
292
|
+
* is not credited to it.
|
|
293
|
+
*
|
|
294
|
+
* Contributors are separated first, by `splitMixedIdentityChanges` and `splitContainedChanges`.
|
|
295
|
+
* Both leave ranges that only touch, so they survive the collapse.
|
|
296
|
+
*
|
|
297
|
+
* Carries no gate of its own: the only caller reaches it through the attributed changeset, which
|
|
298
|
+
* already requires `confluence_ncs_step_diffing_version_history`.
|
|
299
|
+
*/
|
|
300
|
+
var collapseOverlappingChanges = exports.collapseOverlappingChanges = function collapseOverlappingChanges(changes, doc) {
|
|
301
|
+
return collapse(splitContainedChanges(splitMixedIdentityChanges(changes, doc), doc));
|
|
302
|
+
};
|
|
303
|
+
|
|
88
304
|
/**
|
|
89
305
|
* Simplifies and optimizes consecutive changes without crossing an attribution boundary.
|
|
90
306
|
* A change which already contains more than one identity is deliberately kept isolated.
|
|
@@ -114,12 +330,12 @@ var simplifyChangesWithAttribution = exports.simplifyChangesWithAttribution = fu
|
|
|
114
330
|
run = [];
|
|
115
331
|
runIdentity = undefined;
|
|
116
332
|
};
|
|
117
|
-
var
|
|
118
|
-
|
|
333
|
+
var _iterator4 = _createForOfIteratorHelper(changes),
|
|
334
|
+
_step4;
|
|
119
335
|
try {
|
|
120
|
-
for (
|
|
336
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
121
337
|
var _runIdentity;
|
|
122
|
-
var change =
|
|
338
|
+
var change = _step4.value;
|
|
123
339
|
var identity = getAttributionIdentity(change);
|
|
124
340
|
var canJoinRun = ((_runIdentity = runIdentity) === null || _runIdentity === void 0 ? void 0 : _runIdentity.mergeable) === true && identity.mergeable && runIdentity.key === identity.key;
|
|
125
341
|
if (run.length > 0 && !canJoinRun) {
|
|
@@ -132,9 +348,9 @@ var simplifyChangesWithAttribution = exports.simplifyChangesWithAttribution = fu
|
|
|
132
348
|
}
|
|
133
349
|
}
|
|
134
350
|
} catch (err) {
|
|
135
|
-
|
|
351
|
+
_iterator4.e(err);
|
|
136
352
|
} finally {
|
|
137
|
-
|
|
353
|
+
_iterator4.f();
|
|
138
354
|
}
|
|
139
355
|
flush();
|
|
140
356
|
return result;
|