@atlaskit/editor-plugin-annotation 29.0.5 → 29.1.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 +19 -0
- package/dist/cjs/pm-plugins/inline-comment.js +7 -0
- package/dist/cjs/pm-plugins/plugin-factory.js +67 -49
- package/dist/cjs/pm-plugins/utils.js +148 -29
- package/dist/es2019/pm-plugins/inline-comment.js +7 -0
- package/dist/es2019/pm-plugins/plugin-factory.js +33 -20
- package/dist/es2019/pm-plugins/utils.js +138 -25
- package/dist/esm/pm-plugins/inline-comment.js +7 -0
- package/dist/esm/pm-plugins/plugin-factory.js +68 -50
- package/dist/esm/pm-plugins/utils.js +147 -28
- package/dist/types/pm-plugins/utils.d.ts +8 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-annotation
|
|
2
2
|
|
|
3
|
+
## 29.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`afd887e901de1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/afd887e901de1) -
|
|
8
|
+
Discover annotations in legacy content macros and refresh their state when nested annotations are
|
|
9
|
+
added while platform_editor_fix_lcm_editor_annotations is enabled. Editor-scoped renderers can
|
|
10
|
+
load nested LCM annotations independently of the renderer experiment.
|
|
11
|
+
|
|
12
|
+
Allow the ProseMirror test editor helper to be checked with unused declaration checks enabled.
|
|
13
|
+
|
|
14
|
+
## 29.0.6
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- [`de0b3e0a118bc`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/de0b3e0a118bc) -
|
|
19
|
+
Add comment target attribution to inline comment draft-open analytics.
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
|
|
3
22
|
## 29.0.5
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -14,6 +14,7 @@ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
|
14
14
|
var _annotation2 = require("@atlaskit/editor-common/utils/annotation");
|
|
15
15
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
16
16
|
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
17
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
17
18
|
var _editorCommands = require("../editor-commands");
|
|
18
19
|
var _utils = require("../editor-commands/utils");
|
|
19
20
|
var _nodeviews = require("../nodeviews");
|
|
@@ -409,6 +410,12 @@ var inlineCommentPlugin = exports.inlineCommentPlugin = function inlineCommentPl
|
|
|
409
410
|
if (!(event.target instanceof HTMLElement)) {
|
|
410
411
|
return false;
|
|
411
412
|
}
|
|
413
|
+
if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_fix_lcm_editor_annotations')) {
|
|
414
|
+
// The LCM renderer bridge owns selection so its draft-close guard runs first.
|
|
415
|
+
if (event.target.closest('[data-lcm-annotation-renderer]')) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
412
419
|
|
|
413
420
|
// Find the nearest ancestor (or self) with the data-id attribute
|
|
414
421
|
var annotationId = (_event$target$closest = event.target.closest('[data-id]')) === null || _event$target$closest === void 0 ? void 0 : _event$target$closest.getAttribute('data-id');
|
|
@@ -5,8 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.shouldClearBookMarkCheck = exports.createPluginState = exports.createCommand = void 0;
|
|
8
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
8
9
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
10
|
var _pluginStateFactory = require("@atlaskit/editor-common/utils/plugin-state-factory");
|
|
11
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
10
12
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
11
13
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
12
14
|
var _reducer = _interopRequireDefault(require("./reducer"));
|
|
@@ -14,12 +16,11 @@ var _utils = require("./utils");
|
|
|
14
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; }
|
|
15
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; }
|
|
16
18
|
/**
|
|
17
|
-
* Creates a
|
|
18
|
-
* This ensures each editor instance has its own cache, avoiding cross-contamination.
|
|
19
|
+
* Creates a document-sync handler with a deleted annotations cache in its closure.
|
|
19
20
|
*/
|
|
20
21
|
var createHandleDocChanged = function createHandleDocChanged() {
|
|
21
22
|
// Cache for preserving deleted annotation resolved states through delete/undo cycles
|
|
22
|
-
// This
|
|
23
|
+
// This stays outside plugin state so the undo cache is not serialized.
|
|
23
24
|
var deletedAnnotationsCache = {};
|
|
24
25
|
return function (tr, prevPluginState) {
|
|
25
26
|
if (tr.getMeta('replaceDocument')) {
|
|
@@ -28,16 +29,24 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
var updatedState = getSelectionChangedHandler(false)(tr, prevPluginState);
|
|
32
|
+
var legacyContentExperimentEnabled = (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_fix_lcm_editor_annotations');
|
|
33
|
+
var currentDiscovery = legacyContentExperimentEnabled ? (0, _utils.getAnnotationDiscovery)(tr.doc) : undefined;
|
|
34
|
+
var previousAnnotationIds = currentDiscovery ? new Set((0, _utils.getAnnotationDiscovery)(tr.before).annotationIds) : undefined;
|
|
35
|
+
var newNestedAnnotationIds = currentDiscovery ? currentDiscovery.nestedAnnotationIds.filter(function (id) {
|
|
36
|
+
return !(previousAnnotationIds !== null && previousAnnotationIds !== void 0 && previousAnnotationIds.has(id)) && prevPluginState.annotations[id] === undefined && deletedAnnotationsCache[id] === undefined;
|
|
37
|
+
}) : [];
|
|
31
38
|
|
|
32
39
|
// Collect annotation IDs currently in the document
|
|
33
|
-
var annotationIdsInDocument = new Set();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
var annotationIdsInDocument = currentDiscovery ? new Set([].concat((0, _toConsumableArray2.default)(currentDiscovery.rootAnnotationIds), (0, _toConsumableArray2.default)(currentDiscovery.nestedAnnotationIds))) : new Set();
|
|
41
|
+
if (!currentDiscovery) {
|
|
42
|
+
tr.doc.descendants(function (node) {
|
|
43
|
+
node.marks.forEach(function (mark) {
|
|
44
|
+
if (mark.type.name === 'annotation') {
|
|
45
|
+
annotationIdsInDocument.add(mark.attrs.id);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
39
48
|
});
|
|
40
|
-
}
|
|
49
|
+
}
|
|
41
50
|
var annotationIdsInState = Object.keys(prevPluginState.annotations);
|
|
42
51
|
|
|
43
52
|
// Early return if annotations haven't changed
|
|
@@ -45,7 +54,9 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
45
54
|
return !annotationIdsInDocument.has(id);
|
|
46
55
|
});
|
|
47
56
|
if (!annotationsHaveChanged) {
|
|
48
|
-
return updatedState
|
|
57
|
+
return newNestedAnnotationIds.length > 0 ? _objectSpread(_objectSpread({}, updatedState), {}, {
|
|
58
|
+
dirtyAnnotations: true
|
|
59
|
+
}) : updatedState;
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
// Cache deleted annotations to be able to restore their resolved states on undo
|
|
@@ -68,6 +79,8 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
68
79
|
});
|
|
69
80
|
return _objectSpread(_objectSpread({}, updatedState), {}, {
|
|
70
81
|
annotations: updatedAnnotations
|
|
82
|
+
}, newNestedAnnotationIds.length > 0 && {
|
|
83
|
+
dirtyAnnotations: true
|
|
71
84
|
});
|
|
72
85
|
};
|
|
73
86
|
};
|
|
@@ -195,47 +208,52 @@ var getSelectionChangedHandler = function getSelectionChangedHandler(reopenComme
|
|
|
195
208
|
getSelectionChangeHandlerOld(reopenCommentView)(tr, pluginState);
|
|
196
209
|
};
|
|
197
210
|
};
|
|
211
|
+
var createAnnotationPluginFactory = function createAnnotationPluginFactory(onDocChanged) {
|
|
212
|
+
return (0, _pluginStateFactory.pluginFactory)(_utils.inlineCommentPluginKey, _reducer.default, {
|
|
213
|
+
onSelectionChanged: getSelectionChangedHandler(true),
|
|
214
|
+
onDocChanged: onDocChanged,
|
|
215
|
+
mapping: function mapping(tr, pluginState, editorState) {
|
|
216
|
+
var draftDecorationSet = pluginState.draftDecorationSet,
|
|
217
|
+
bookmark = pluginState.bookmark;
|
|
218
|
+
var mappedDecorationSet = _view.DecorationSet.empty,
|
|
219
|
+
mappedBookmark;
|
|
220
|
+
var hasMappedDecorations = false;
|
|
221
|
+
if (draftDecorationSet) {
|
|
222
|
+
mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
|
|
223
|
+
}
|
|
224
|
+
hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, function (spec) {
|
|
225
|
+
return Object.values(_utils.decorationKey).includes(spec.key);
|
|
226
|
+
}).length > 0;
|
|
198
227
|
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
|
|
212
|
-
}
|
|
213
|
-
hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, function (spec) {
|
|
214
|
-
return Object.values(_utils.decorationKey).includes(spec.key);
|
|
215
|
-
}).length > 0;
|
|
228
|
+
// When changes to decoration target make decoration invalid (e.g. delete text, add mark to node),
|
|
229
|
+
// we need to reset bookmark to hide create component and to avoid invalid draft being published
|
|
230
|
+
// We only perform this change when document selection has changed.
|
|
231
|
+
if (!hasMappedDecorations && shouldClearBookMarkCheck(tr, editorState, bookmark)) {
|
|
232
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
233
|
+
draftDecorationSet: mappedDecorationSet,
|
|
234
|
+
bookmark: undefined
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (bookmark) {
|
|
238
|
+
mappedBookmark = bookmark.map(tr.mapping);
|
|
239
|
+
}
|
|
216
240
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
241
|
+
// return same pluginState if mappings did not change
|
|
242
|
+
if (mappedBookmark === bookmark && mappedDecorationSet === draftDecorationSet) {
|
|
243
|
+
return pluginState;
|
|
244
|
+
}
|
|
221
245
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
222
246
|
draftDecorationSet: mappedDecorationSet,
|
|
223
|
-
bookmark:
|
|
247
|
+
bookmark: mappedBookmark
|
|
224
248
|
});
|
|
225
249
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
bookmark: mappedBookmark
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
var createPluginState = exports.createPluginState = dest.createPluginState;
|
|
241
|
-
var createCommand = exports.createCommand = dest.createCommand;
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
var handleDocChangedWithSync = createHandleDocChanged();
|
|
253
|
+
// Keep the control cohort's existing module-level cache lifetime unchanged.
|
|
254
|
+
var legacyDest = createAnnotationPluginFactory(handleDocChangedWithSync);
|
|
255
|
+
var commandFactory = (0, _pluginStateFactory.pluginFactory)(_utils.inlineCommentPluginKey, _reducer.default);
|
|
256
|
+
var createPluginState = exports.createPluginState = function createPluginState(dispatch, initialState) {
|
|
257
|
+
return ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_fix_lcm_editor_annotations') ? createAnnotationPluginFactory(createHandleDocChanged()) : legacyDest).createPluginState(dispatch, initialState);
|
|
258
|
+
};
|
|
259
|
+
var createCommand = exports.createCommand = commandFactory.createCommand;
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.addDraftDecoration = void 0;
|
|
8
8
|
exports.annotationExists = annotationExists;
|
|
9
|
-
exports.getPluginState = exports.getDraftCommandAnalyticsPayload = exports.getAnnotationViewKey = exports.getAllAnnotations = exports.findAnnotationsInSelection = exports.decorationKey = void 0;
|
|
9
|
+
exports.getPluginState = exports.getDraftCommandAnalyticsPayload = exports.getAnnotationViewKey = exports.getAnnotationDiscovery = exports.getAllAnnotations = exports.findAnnotationsInSelection = exports.decorationKey = void 0;
|
|
10
10
|
exports.getSelectionPositions = getSelectionPositions;
|
|
11
11
|
exports.hasInvalidNodes = exports.hasAnyUnResolvedAnnotationInPage = void 0;
|
|
12
12
|
exports.hasInvalidWhitespaceNode = hasInvalidWhitespaceNode;
|
|
@@ -16,12 +16,14 @@ exports.shouldHideRemixAnnotation = exports.resolveDraftBookmark = exports.isSup
|
|
|
16
16
|
exports.stripNonExistingAnnotations = stripNonExistingAnnotations;
|
|
17
17
|
exports.surroundingMarks = void 0;
|
|
18
18
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
19
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
19
20
|
var _annotation = require("@atlaskit/adf-schema/annotation");
|
|
20
21
|
var _enums = require("@atlaskit/editor-common/analytics/types/enums");
|
|
21
22
|
var _mediaSingle = require("@atlaskit/editor-common/media-single");
|
|
22
23
|
var _annotation2 = require("@atlaskit/editor-common/styles/annotation");
|
|
23
24
|
var _annotation3 = require("@atlaskit/editor-common/utils/annotation");
|
|
24
25
|
var _nodes = require("@atlaskit/editor-common/utils/nodes");
|
|
26
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
25
27
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
26
28
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
27
29
|
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
@@ -79,7 +81,111 @@ var reorderAnnotations = function reorderAnnotations(annotations, $from) {
|
|
|
79
81
|
});
|
|
80
82
|
});
|
|
81
83
|
};
|
|
84
|
+
var legacyContentAnnotationsByDoc = new WeakMap();
|
|
85
|
+
var legacyContentAnnotationIdsByExtension = new WeakMap();
|
|
86
|
+
var readNestedContentNodes = function readNestedContentNodes(parameters) {
|
|
87
|
+
if (!parameters || (0, _typeof2.default)(parameters) !== 'object') {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
var nestedContent = parameters.nestedContent;
|
|
91
|
+
if (!nestedContent || (0, _typeof2.default)(nestedContent) !== 'object') {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
var nestedDocument = nestedContent;
|
|
95
|
+
return nestedDocument.type === 'doc' && Array.isArray(nestedDocument.content) ? nestedDocument.content : undefined;
|
|
96
|
+
};
|
|
97
|
+
var getNestedContentAnnotationIds = function getNestedContentAnnotationIds(extension) {
|
|
98
|
+
var cachedIds = legacyContentAnnotationIdsByExtension.get(extension);
|
|
99
|
+
if (cachedIds) {
|
|
100
|
+
return cachedIds;
|
|
101
|
+
}
|
|
102
|
+
var nestedNodes = readNestedContentNodes(extension.attrs.parameters);
|
|
103
|
+
if (!nestedNodes) {
|
|
104
|
+
var noIds = Object.freeze([]);
|
|
105
|
+
legacyContentAnnotationIdsByExtension.set(extension, noIds);
|
|
106
|
+
return noIds;
|
|
107
|
+
}
|
|
108
|
+
var annotationIds = new Set();
|
|
109
|
+
var visitedAdfNodes = new WeakSet();
|
|
110
|
+
var pending = (0, _toConsumableArray2.default)(nestedNodes).reverse();
|
|
111
|
+
while (pending.length > 0) {
|
|
112
|
+
var _adfNode$attrs;
|
|
113
|
+
var value = pending.pop();
|
|
114
|
+
if (!value || (0, _typeof2.default)(value) !== 'object' || visitedAdfNodes.has(value)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
visitedAdfNodes.add(value);
|
|
118
|
+
var adfNode = value;
|
|
119
|
+
if (Array.isArray(adfNode.marks)) {
|
|
120
|
+
adfNode.marks.forEach(function (rawMark) {
|
|
121
|
+
if (!rawMark || (0, _typeof2.default)(rawMark) !== 'object') {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
var annotationMark = rawMark;
|
|
125
|
+
var attrs = annotationMark.attrs;
|
|
126
|
+
if (annotationMark.type !== 'annotation' || !validateAnnotationAttributes(attrs)) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
annotationIds.add(attrs.id);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (adfNode.type === 'extension' && ((_adfNode$attrs = adfNode.attrs) === null || _adfNode$attrs === void 0 ? void 0 : _adfNode$attrs.extensionType) === 'com.atlassian.confluence.migration' && adfNode.attrs.extensionKey === 'legacy-content') {
|
|
133
|
+
var _nestedNodes = readNestedContentNodes(adfNode.attrs.parameters);
|
|
134
|
+
if (_nestedNodes) {
|
|
135
|
+
for (var i = _nestedNodes.length - 1; i >= 0; i--) {
|
|
136
|
+
pending.push(_nestedNodes[i]);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (Array.isArray(adfNode.content)) {
|
|
141
|
+
for (var _i = adfNode.content.length - 1; _i >= 0; _i--) {
|
|
142
|
+
pending.push(adfNode.content[_i]);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
var ids = Object.freeze((0, _toConsumableArray2.default)(annotationIds));
|
|
147
|
+
legacyContentAnnotationIdsByExtension.set(extension, ids);
|
|
148
|
+
return ids;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/** Discover annotation IDs from immutable legacy-content ADF without repeatedly scanning it. */
|
|
152
|
+
var getAnnotationDiscovery = exports.getAnnotationDiscovery = function getAnnotationDiscovery(doc) {
|
|
153
|
+
var cachedDiscovery = legacyContentAnnotationsByDoc.get(doc);
|
|
154
|
+
if (cachedDiscovery) {
|
|
155
|
+
return cachedDiscovery;
|
|
156
|
+
}
|
|
157
|
+
var allAnnotationIds = new Set();
|
|
158
|
+
var rootAnnotationIds = new Set();
|
|
159
|
+
var nestedAnnotationIds = new Set();
|
|
160
|
+
doc.descendants(function (node) {
|
|
161
|
+
node.marks.filter(function (mark) {
|
|
162
|
+
return mark.type.name === 'annotation';
|
|
163
|
+
}).forEach(function (mark) {
|
|
164
|
+
if (validateAnnotationMark(mark)) {
|
|
165
|
+
rootAnnotationIds.add(mark.attrs.id);
|
|
166
|
+
allAnnotationIds.add(mark.attrs.id);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
if (node.type.name === 'extension' && node.attrs.extensionType === 'com.atlassian.confluence.migration' && node.attrs.extensionKey === 'legacy-content') {
|
|
170
|
+
getNestedContentAnnotationIds(node).forEach(function (id) {
|
|
171
|
+
nestedAnnotationIds.add(id);
|
|
172
|
+
allAnnotationIds.add(id);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
var discovery = {
|
|
178
|
+
annotationIds: Object.freeze((0, _toConsumableArray2.default)(allAnnotationIds)),
|
|
179
|
+
rootAnnotationIds: Object.freeze((0, _toConsumableArray2.default)(rootAnnotationIds)),
|
|
180
|
+
nestedAnnotationIds: Object.freeze((0, _toConsumableArray2.default)(nestedAnnotationIds))
|
|
181
|
+
};
|
|
182
|
+
legacyContentAnnotationsByDoc.set(doc, discovery);
|
|
183
|
+
return discovery;
|
|
184
|
+
};
|
|
82
185
|
var getAllAnnotations = exports.getAllAnnotations = function getAllAnnotations(doc) {
|
|
186
|
+
if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_fix_lcm_editor_annotations')) {
|
|
187
|
+
return (0, _toConsumableArray2.default)(getAnnotationDiscovery(doc).annotationIds);
|
|
188
|
+
}
|
|
83
189
|
var allAnnotationIds = new Set();
|
|
84
190
|
doc.descendants(function (node) {
|
|
85
191
|
node.marks.filter(function (mark) {
|
|
@@ -93,29 +199,30 @@ var getAllAnnotations = exports.getAllAnnotations = function getAllAnnotations(d
|
|
|
93
199
|
});
|
|
94
200
|
return Array.from(allAnnotationIds);
|
|
95
201
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
*/
|
|
100
|
-
var validateAnnotationMark = function validateAnnotationMark(annotationMark) {
|
|
101
|
-
var _ref = annotationMark.attrs,
|
|
102
|
-
id = _ref.id,
|
|
103
|
-
annotationType = _ref.annotationType;
|
|
104
|
-
return validateAnnotationId(id) && validateAnnotationType(annotationType);
|
|
105
|
-
function validateAnnotationId(id) {
|
|
106
|
-
if (!id || typeof id !== 'string') {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
var invalidIds = ['null', 'undefined'];
|
|
110
|
-
return !invalidIds.includes(id.toLowerCase());
|
|
202
|
+
var validateAnnotationId = function validateAnnotationId(id) {
|
|
203
|
+
if (!id || typeof id !== 'string') {
|
|
204
|
+
return false;
|
|
111
205
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return
|
|
206
|
+
var invalidIds = ['null', 'undefined'];
|
|
207
|
+
return !invalidIds.includes(id.toLowerCase());
|
|
208
|
+
};
|
|
209
|
+
var validateAnnotationType = function validateAnnotationType(type) {
|
|
210
|
+
if (!type || typeof type !== 'string') {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
var allowedTypes = Object.values(_annotation.AnnotationTypes);
|
|
214
|
+
return allowedTypes.some(function (allowedType) {
|
|
215
|
+
return allowedType === type;
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
var validateAnnotationAttributes = function validateAnnotationAttributes(attrs) {
|
|
219
|
+
if (!attrs || (0, _typeof2.default)(attrs) !== 'object') {
|
|
220
|
+
return false;
|
|
118
221
|
}
|
|
222
|
+
return 'id' in attrs && 'annotationType' in attrs && validateAnnotationId(attrs.id) && validateAnnotationType(attrs.annotationType);
|
|
223
|
+
};
|
|
224
|
+
var validateAnnotationMark = function validateAnnotationMark(annotationMark) {
|
|
225
|
+
return validateAnnotationAttributes(annotationMark.attrs);
|
|
119
226
|
};
|
|
120
227
|
var decorationKey = exports.decorationKey = {
|
|
121
228
|
block: 'blockCommentDecoration',
|
|
@@ -288,14 +395,26 @@ var getDraftCommandAnalyticsPayload = exports.getDraftCommandAnalyticsPayload =
|
|
|
288
395
|
var payload = function payload(state) {
|
|
289
396
|
var attributes = {};
|
|
290
397
|
if (drafting) {
|
|
398
|
+
var _currentMediaNodeWith;
|
|
399
|
+
var selection = state.selection;
|
|
400
|
+
var targetNode = selection instanceof _state.NodeSelection ? selection.node : (_currentMediaNodeWith = (0, _mediaSingle.currentMediaNodeWithPos)(state)) === null || _currentMediaNodeWith === void 0 ? void 0 : _currentMediaNodeWith.node;
|
|
401
|
+
var commentTargetType = 'other';
|
|
402
|
+
if ((targetNode === null || targetNode === void 0 ? void 0 : targetNode.type.name) === 'extension') {
|
|
403
|
+
commentTargetType = targetNode.attrs.extensionKey === 'native-embed:maui' ? 'remixEmbed' : 'other';
|
|
404
|
+
} else if (targetNode && ['media', 'mediaSingle', 'mediaInline'].includes(targetNode.type.name)) {
|
|
405
|
+
commentTargetType = 'media';
|
|
406
|
+
} else if (selection instanceof _state.TextSelection || selection instanceof _state.AllSelection) {
|
|
407
|
+
commentTargetType = 'text';
|
|
408
|
+
}
|
|
291
409
|
attributes = {
|
|
292
410
|
inputMethod: inputMethod,
|
|
293
|
-
overlap: getAnnotationsInSelectionCount(state)
|
|
411
|
+
overlap: getAnnotationsInSelectionCount(state),
|
|
412
|
+
commentTargetType: commentTargetType
|
|
294
413
|
};
|
|
295
414
|
}
|
|
296
415
|
if ((0, _fg.fg)('editor_inline_comments_on_inline_nodes')) {
|
|
297
|
-
var
|
|
298
|
-
bookmark =
|
|
416
|
+
var _ref = getPluginState(state) || {},
|
|
417
|
+
bookmark = _ref.bookmark;
|
|
299
418
|
attributes.inlineNodeNames = (0, _annotation3.getRangeInlineNodeNames)({
|
|
300
419
|
doc: state.doc,
|
|
301
420
|
pos: resolveDraftBookmark(state, bookmark)
|
|
@@ -312,12 +431,12 @@ var getDraftCommandAnalyticsPayload = exports.getDraftCommandAnalyticsPayload =
|
|
|
312
431
|
return payload;
|
|
313
432
|
};
|
|
314
433
|
var isSelectionValid = exports.isSelectionValid = function isSelectionValid(state) {
|
|
315
|
-
var
|
|
434
|
+
var _currentMediaNodeWith2;
|
|
316
435
|
var supportedBlockNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
317
436
|
var isBlockNodeSupported = arguments.length > 2 ? arguments[2] : undefined;
|
|
318
437
|
var selection = state.selection;
|
|
319
|
-
var
|
|
320
|
-
disallowOnWhitespace =
|
|
438
|
+
var _ref2 = getPluginState(state) || {},
|
|
439
|
+
disallowOnWhitespace = _ref2.disallowOnWhitespace;
|
|
321
440
|
var allowedInlineNodes = ['emoji', 'status', 'date', 'mention', 'inlineCard'];
|
|
322
441
|
var isSelectionEmpty = selection.empty;
|
|
323
442
|
var isTextOrAllSelection = selection instanceof _state.TextSelection || selection instanceof _state.AllSelection;
|
|
@@ -326,7 +445,7 @@ var isSelectionValid = exports.isSelectionValid = function isSelectionValid(stat
|
|
|
326
445
|
var isValidSelection = isTextOrAllSelection || isValidNodeSelection;
|
|
327
446
|
|
|
328
447
|
// Allow media so that it can enter draft mode
|
|
329
|
-
if ((
|
|
448
|
+
if ((_currentMediaNodeWith2 = (0, _mediaSingle.currentMediaNodeWithPos)(state)) !== null && _currentMediaNodeWith2 !== void 0 && _currentMediaNodeWith2.node) {
|
|
330
449
|
return _types.AnnotationSelectionType.VALID;
|
|
331
450
|
}
|
|
332
451
|
if (isSelectionEmpty || !isValidSelection) {
|
|
@@ -4,6 +4,7 @@ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
|
4
4
|
import { getAnnotationInlineNodeTypes } from '@atlaskit/editor-common/utils/annotation';
|
|
5
5
|
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
6
6
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
7
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
7
8
|
import { clearDirtyMark, closeComponent, setHoveredAnnotation, setInlineCommentsVisibility, setSelectedAnnotation, flushPendingSelections, updateInlineCommentResolvedState, updateMouseState, setPendingSelectedAnnotation, setInlineCommentDraftState, setInlineCommentsFetched } from '../editor-commands';
|
|
8
9
|
import { resetUserIntent, setUserIntent } from '../editor-commands/utils';
|
|
9
10
|
import { getAnnotationViewClassname, getBlockAnnotationViewClassname } from '../nodeviews';
|
|
@@ -353,6 +354,12 @@ export const inlineCommentPlugin = options => {
|
|
|
353
354
|
if (!(event.target instanceof HTMLElement)) {
|
|
354
355
|
return false;
|
|
355
356
|
}
|
|
357
|
+
if (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations')) {
|
|
358
|
+
// The LCM renderer bridge owns selection so its draft-close guard runs first.
|
|
359
|
+
if (event.target.closest('[data-lcm-annotation-renderer]')) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
356
363
|
|
|
357
364
|
// Find the nearest ancestor (or self) with the data-id attribute
|
|
358
365
|
const annotationId = (_event$target$closest = event.target.closest('[data-id]')) === null || _event$target$closest === void 0 ? void 0 : _event$target$closest.getAttribute('data-id');
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { pluginFactory } from '@atlaskit/editor-common/utils/plugin-state-factory';
|
|
2
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
2
3
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
4
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
4
5
|
import reducer from './reducer';
|
|
5
|
-
import { decorationKey, findAnnotationsInSelection, inlineCommentPluginKey, isBlockNodeAnnotationsSelected, isSelectedAnnotationsChanged } from './utils';
|
|
6
|
+
import { decorationKey, getAnnotationDiscovery, findAnnotationsInSelection, inlineCommentPluginKey, isBlockNodeAnnotationsSelected, isSelectedAnnotationsChanged } from './utils';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
* Creates a
|
|
9
|
-
* This ensures each editor instance has its own cache, avoiding cross-contamination.
|
|
9
|
+
* Creates a document-sync handler with a deleted annotations cache in its closure.
|
|
10
10
|
*/
|
|
11
11
|
const createHandleDocChanged = () => {
|
|
12
12
|
// Cache for preserving deleted annotation resolved states through delete/undo cycles
|
|
13
|
-
// This
|
|
13
|
+
// This stays outside plugin state so the undo cache is not serialized.
|
|
14
14
|
const deletedAnnotationsCache = {};
|
|
15
15
|
return (tr, prevPluginState) => {
|
|
16
16
|
if (tr.getMeta('replaceDocument')) {
|
|
@@ -20,22 +20,31 @@ const createHandleDocChanged = () => {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
const updatedState = getSelectionChangedHandler(false)(tr, prevPluginState);
|
|
23
|
+
const legacyContentExperimentEnabled = isExperimentEnabled('platform_editor_fix_lcm_editor_annotations');
|
|
24
|
+
const currentDiscovery = legacyContentExperimentEnabled ? getAnnotationDiscovery(tr.doc) : undefined;
|
|
25
|
+
const previousAnnotationIds = currentDiscovery ? new Set(getAnnotationDiscovery(tr.before).annotationIds) : undefined;
|
|
26
|
+
const newNestedAnnotationIds = currentDiscovery ? currentDiscovery.nestedAnnotationIds.filter(id => !(previousAnnotationIds !== null && previousAnnotationIds !== void 0 && previousAnnotationIds.has(id)) && prevPluginState.annotations[id] === undefined && deletedAnnotationsCache[id] === undefined) : [];
|
|
23
27
|
|
|
24
28
|
// Collect annotation IDs currently in the document
|
|
25
|
-
const annotationIdsInDocument = new Set();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const annotationIdsInDocument = currentDiscovery ? new Set([...currentDiscovery.rootAnnotationIds, ...currentDiscovery.nestedAnnotationIds]) : new Set();
|
|
30
|
+
if (!currentDiscovery) {
|
|
31
|
+
tr.doc.descendants(node => {
|
|
32
|
+
node.marks.forEach(mark => {
|
|
33
|
+
if (mark.type.name === 'annotation') {
|
|
34
|
+
annotationIdsInDocument.add(mark.attrs.id);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
31
37
|
});
|
|
32
|
-
}
|
|
38
|
+
}
|
|
33
39
|
const annotationIdsInState = Object.keys(prevPluginState.annotations);
|
|
34
40
|
|
|
35
41
|
// Early return if annotations haven't changed
|
|
36
42
|
const annotationsHaveChanged = annotationIdsInDocument.size !== annotationIdsInState.length || annotationIdsInState.some(id => !annotationIdsInDocument.has(id));
|
|
37
43
|
if (!annotationsHaveChanged) {
|
|
38
|
-
return
|
|
44
|
+
return newNestedAnnotationIds.length > 0 ? {
|
|
45
|
+
...updatedState,
|
|
46
|
+
dirtyAnnotations: true
|
|
47
|
+
} : updatedState;
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
// Cache deleted annotations to be able to restore their resolved states on undo
|
|
@@ -58,7 +67,10 @@ const createHandleDocChanged = () => {
|
|
|
58
67
|
});
|
|
59
68
|
return {
|
|
60
69
|
...updatedState,
|
|
61
|
-
annotations: updatedAnnotations
|
|
70
|
+
annotations: updatedAnnotations,
|
|
71
|
+
...(newNestedAnnotationIds.length > 0 && {
|
|
72
|
+
dirtyAnnotations: true
|
|
73
|
+
})
|
|
62
74
|
};
|
|
63
75
|
};
|
|
64
76
|
};
|
|
@@ -194,12 +206,9 @@ const getSelectionChangedHandler = reopenCommentView => (tr, pluginState) => plu
|
|
|
194
206
|
getSelectionChangeHandlerNew(reopenCommentView)(tr, pluginState) :
|
|
195
207
|
// else if platform_editor_comments_api_manager == false
|
|
196
208
|
getSelectionChangeHandlerOld(reopenCommentView)(tr, pluginState);
|
|
197
|
-
|
|
198
|
-
// Create the handler with cache once at module level
|
|
199
|
-
const handleDocChangedWithSync = createHandleDocChanged();
|
|
200
|
-
const dest = pluginFactory(inlineCommentPluginKey, reducer, {
|
|
209
|
+
const createAnnotationPluginFactory = onDocChanged => pluginFactory(inlineCommentPluginKey, reducer, {
|
|
201
210
|
onSelectionChanged: getSelectionChangedHandler(true),
|
|
202
|
-
onDocChanged
|
|
211
|
+
onDocChanged,
|
|
203
212
|
mapping: (tr, pluginState, editorState) => {
|
|
204
213
|
const {
|
|
205
214
|
draftDecorationSet,
|
|
@@ -238,5 +247,9 @@ const dest = pluginFactory(inlineCommentPluginKey, reducer, {
|
|
|
238
247
|
};
|
|
239
248
|
}
|
|
240
249
|
});
|
|
241
|
-
|
|
242
|
-
|
|
250
|
+
const handleDocChangedWithSync = createHandleDocChanged();
|
|
251
|
+
// Keep the control cohort's existing module-level cache lifetime unchanged.
|
|
252
|
+
const legacyDest = createAnnotationPluginFactory(handleDocChangedWithSync);
|
|
253
|
+
const commandFactory = pluginFactory(inlineCommentPluginKey, reducer);
|
|
254
|
+
export const createPluginState = (dispatch, initialState) => (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations') ? createAnnotationPluginFactory(createHandleDocChanged()) : legacyDest).createPluginState(dispatch, initialState);
|
|
255
|
+
export const createCommand = commandFactory.createCommand;
|
|
@@ -4,6 +4,7 @@ import { currentMediaNodeWithPos } from '@atlaskit/editor-common/media-single';
|
|
|
4
4
|
import { AnnotationSharedClassNames, BlockAnnotationSharedClassNames } from '@atlaskit/editor-common/styles/annotation';
|
|
5
5
|
import { canApplyAnnotationOnRange, getAnnotationIdsFromRange, getRangeInlineNodeNames, hasAnnotationMark, isEmptyTextSelection } from '@atlaskit/editor-common/utils/annotation';
|
|
6
6
|
import { isParagraph, isText } from '@atlaskit/editor-common/utils/nodes';
|
|
7
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
7
8
|
import { AllSelection, NodeSelection, PluginKey, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
8
9
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
9
10
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
@@ -53,7 +54,109 @@ const reorderAnnotations = (annotations, $from) => {
|
|
|
53
54
|
const idSet = surroundingMarks($from).map(filterAnnotationIds);
|
|
54
55
|
annotations.sort((a, b) => sum(idSet, ids => ids.indexOf(a.id)) - sum(idSet, ids => ids.indexOf(b.id)));
|
|
55
56
|
};
|
|
57
|
+
const legacyContentAnnotationsByDoc = new WeakMap();
|
|
58
|
+
const legacyContentAnnotationIdsByExtension = new WeakMap();
|
|
59
|
+
const readNestedContentNodes = parameters => {
|
|
60
|
+
if (!parameters || typeof parameters !== 'object') {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const nestedContent = parameters.nestedContent;
|
|
64
|
+
if (!nestedContent || typeof nestedContent !== 'object') {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const nestedDocument = nestedContent;
|
|
68
|
+
return nestedDocument.type === 'doc' && Array.isArray(nestedDocument.content) ? nestedDocument.content : undefined;
|
|
69
|
+
};
|
|
70
|
+
const getNestedContentAnnotationIds = extension => {
|
|
71
|
+
const cachedIds = legacyContentAnnotationIdsByExtension.get(extension);
|
|
72
|
+
if (cachedIds) {
|
|
73
|
+
return cachedIds;
|
|
74
|
+
}
|
|
75
|
+
const nestedNodes = readNestedContentNodes(extension.attrs.parameters);
|
|
76
|
+
if (!nestedNodes) {
|
|
77
|
+
const noIds = Object.freeze([]);
|
|
78
|
+
legacyContentAnnotationIdsByExtension.set(extension, noIds);
|
|
79
|
+
return noIds;
|
|
80
|
+
}
|
|
81
|
+
const annotationIds = new Set();
|
|
82
|
+
const visitedAdfNodes = new WeakSet();
|
|
83
|
+
const pending = [...nestedNodes].reverse();
|
|
84
|
+
while (pending.length > 0) {
|
|
85
|
+
var _adfNode$attrs;
|
|
86
|
+
const value = pending.pop();
|
|
87
|
+
if (!value || typeof value !== 'object' || visitedAdfNodes.has(value)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
visitedAdfNodes.add(value);
|
|
91
|
+
const adfNode = value;
|
|
92
|
+
if (Array.isArray(adfNode.marks)) {
|
|
93
|
+
adfNode.marks.forEach(rawMark => {
|
|
94
|
+
if (!rawMark || typeof rawMark !== 'object') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const annotationMark = rawMark;
|
|
98
|
+
const attrs = annotationMark.attrs;
|
|
99
|
+
if (annotationMark.type !== 'annotation' || !validateAnnotationAttributes(attrs)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
annotationIds.add(attrs.id);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (adfNode.type === 'extension' && ((_adfNode$attrs = adfNode.attrs) === null || _adfNode$attrs === void 0 ? void 0 : _adfNode$attrs.extensionType) === 'com.atlassian.confluence.migration' && adfNode.attrs.extensionKey === 'legacy-content') {
|
|
106
|
+
const nestedNodes = readNestedContentNodes(adfNode.attrs.parameters);
|
|
107
|
+
if (nestedNodes) {
|
|
108
|
+
for (let i = nestedNodes.length - 1; i >= 0; i--) {
|
|
109
|
+
pending.push(nestedNodes[i]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(adfNode.content)) {
|
|
114
|
+
for (let i = adfNode.content.length - 1; i >= 0; i--) {
|
|
115
|
+
pending.push(adfNode.content[i]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const ids = Object.freeze([...annotationIds]);
|
|
120
|
+
legacyContentAnnotationIdsByExtension.set(extension, ids);
|
|
121
|
+
return ids;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** Discover annotation IDs from immutable legacy-content ADF without repeatedly scanning it. */
|
|
125
|
+
export const getAnnotationDiscovery = doc => {
|
|
126
|
+
const cachedDiscovery = legacyContentAnnotationsByDoc.get(doc);
|
|
127
|
+
if (cachedDiscovery) {
|
|
128
|
+
return cachedDiscovery;
|
|
129
|
+
}
|
|
130
|
+
const allAnnotationIds = new Set();
|
|
131
|
+
const rootAnnotationIds = new Set();
|
|
132
|
+
const nestedAnnotationIds = new Set();
|
|
133
|
+
doc.descendants(node => {
|
|
134
|
+
node.marks.filter(mark => mark.type.name === 'annotation').forEach(mark => {
|
|
135
|
+
if (validateAnnotationMark(mark)) {
|
|
136
|
+
rootAnnotationIds.add(mark.attrs.id);
|
|
137
|
+
allAnnotationIds.add(mark.attrs.id);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (node.type.name === 'extension' && node.attrs.extensionType === 'com.atlassian.confluence.migration' && node.attrs.extensionKey === 'legacy-content') {
|
|
141
|
+
getNestedContentAnnotationIds(node).forEach(id => {
|
|
142
|
+
nestedAnnotationIds.add(id);
|
|
143
|
+
allAnnotationIds.add(id);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
});
|
|
148
|
+
const discovery = {
|
|
149
|
+
annotationIds: Object.freeze([...allAnnotationIds]),
|
|
150
|
+
rootAnnotationIds: Object.freeze([...rootAnnotationIds]),
|
|
151
|
+
nestedAnnotationIds: Object.freeze([...nestedAnnotationIds])
|
|
152
|
+
};
|
|
153
|
+
legacyContentAnnotationsByDoc.set(doc, discovery);
|
|
154
|
+
return discovery;
|
|
155
|
+
};
|
|
56
156
|
export const getAllAnnotations = doc => {
|
|
157
|
+
if (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations')) {
|
|
158
|
+
return [...getAnnotationDiscovery(doc).annotationIds];
|
|
159
|
+
}
|
|
57
160
|
const allAnnotationIds = new Set();
|
|
58
161
|
doc.descendants(node => {
|
|
59
162
|
node.marks.filter(mark => mark.type.name === 'annotation')
|
|
@@ -63,31 +166,27 @@ export const getAllAnnotations = doc => {
|
|
|
63
166
|
});
|
|
64
167
|
return Array.from(allAnnotationIds);
|
|
65
168
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
*/
|
|
70
|
-
const validateAnnotationMark = annotationMark => {
|
|
71
|
-
const {
|
|
72
|
-
id,
|
|
73
|
-
annotationType
|
|
74
|
-
} = annotationMark.attrs;
|
|
75
|
-
return validateAnnotationId(id) && validateAnnotationType(annotationType);
|
|
76
|
-
function validateAnnotationId(id) {
|
|
77
|
-
if (!id || typeof id !== 'string') {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
const invalidIds = ['null', 'undefined'];
|
|
81
|
-
return !invalidIds.includes(id.toLowerCase());
|
|
169
|
+
const validateAnnotationId = id => {
|
|
170
|
+
if (!id || typeof id !== 'string') {
|
|
171
|
+
return false;
|
|
82
172
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
173
|
+
const invalidIds = ['null', 'undefined'];
|
|
174
|
+
return !invalidIds.includes(id.toLowerCase());
|
|
175
|
+
};
|
|
176
|
+
const validateAnnotationType = type => {
|
|
177
|
+
if (!type || typeof type !== 'string') {
|
|
178
|
+
return false;
|
|
89
179
|
}
|
|
180
|
+
const allowedTypes = Object.values(AnnotationTypes);
|
|
181
|
+
return allowedTypes.some(allowedType => allowedType === type);
|
|
90
182
|
};
|
|
183
|
+
const validateAnnotationAttributes = attrs => {
|
|
184
|
+
if (!attrs || typeof attrs !== 'object') {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return 'id' in attrs && 'annotationType' in attrs && validateAnnotationId(attrs.id) && validateAnnotationType(attrs.annotationType);
|
|
188
|
+
};
|
|
189
|
+
const validateAnnotationMark = annotationMark => validateAnnotationAttributes(annotationMark.attrs);
|
|
91
190
|
export const decorationKey = {
|
|
92
191
|
block: 'blockCommentDecoration',
|
|
93
192
|
inline: 'inlineCommentDecoration'
|
|
@@ -246,9 +345,23 @@ export const getDraftCommandAnalyticsPayload = (drafting, inputMethod) => {
|
|
|
246
345
|
const payload = state => {
|
|
247
346
|
let attributes = {};
|
|
248
347
|
if (drafting) {
|
|
348
|
+
var _currentMediaNodeWith;
|
|
349
|
+
const {
|
|
350
|
+
selection
|
|
351
|
+
} = state;
|
|
352
|
+
const targetNode = selection instanceof NodeSelection ? selection.node : (_currentMediaNodeWith = currentMediaNodeWithPos(state)) === null || _currentMediaNodeWith === void 0 ? void 0 : _currentMediaNodeWith.node;
|
|
353
|
+
let commentTargetType = 'other';
|
|
354
|
+
if ((targetNode === null || targetNode === void 0 ? void 0 : targetNode.type.name) === 'extension') {
|
|
355
|
+
commentTargetType = targetNode.attrs.extensionKey === 'native-embed:maui' ? 'remixEmbed' : 'other';
|
|
356
|
+
} else if (targetNode && ['media', 'mediaSingle', 'mediaInline'].includes(targetNode.type.name)) {
|
|
357
|
+
commentTargetType = 'media';
|
|
358
|
+
} else if (selection instanceof TextSelection || selection instanceof AllSelection) {
|
|
359
|
+
commentTargetType = 'text';
|
|
360
|
+
}
|
|
249
361
|
attributes = {
|
|
250
362
|
inputMethod,
|
|
251
|
-
overlap: getAnnotationsInSelectionCount(state)
|
|
363
|
+
overlap: getAnnotationsInSelectionCount(state),
|
|
364
|
+
commentTargetType
|
|
252
365
|
};
|
|
253
366
|
}
|
|
254
367
|
if (fg('editor_inline_comments_on_inline_nodes')) {
|
|
@@ -271,7 +384,7 @@ export const getDraftCommandAnalyticsPayload = (drafting, inputMethod) => {
|
|
|
271
384
|
return payload;
|
|
272
385
|
};
|
|
273
386
|
export const isSelectionValid = (state, supportedBlockNodes = [], isBlockNodeSupported) => {
|
|
274
|
-
var
|
|
387
|
+
var _currentMediaNodeWith2;
|
|
275
388
|
const {
|
|
276
389
|
selection
|
|
277
390
|
} = state;
|
|
@@ -286,7 +399,7 @@ export const isSelectionValid = (state, supportedBlockNodes = [], isBlockNodeSup
|
|
|
286
399
|
const isValidSelection = isTextOrAllSelection || isValidNodeSelection;
|
|
287
400
|
|
|
288
401
|
// Allow media so that it can enter draft mode
|
|
289
|
-
if ((
|
|
402
|
+
if ((_currentMediaNodeWith2 = currentMediaNodeWithPos(state)) !== null && _currentMediaNodeWith2 !== void 0 && _currentMediaNodeWith2.node) {
|
|
290
403
|
return AnnotationSelectionType.VALID;
|
|
291
404
|
}
|
|
292
405
|
if (isSelectionEmpty || !isValidSelection) {
|
|
@@ -7,6 +7,7 @@ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
|
7
7
|
import { getAnnotationInlineNodeTypes } from '@atlaskit/editor-common/utils/annotation';
|
|
8
8
|
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
9
9
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
10
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
10
11
|
import { clearDirtyMark, closeComponent, setHoveredAnnotation, setInlineCommentsVisibility, setSelectedAnnotation, flushPendingSelections, updateInlineCommentResolvedState, updateMouseState, setPendingSelectedAnnotation, setInlineCommentDraftState, setInlineCommentsFetched } from '../editor-commands';
|
|
11
12
|
import { resetUserIntent, setUserIntent } from '../editor-commands/utils';
|
|
12
13
|
import { getAnnotationViewClassname, getBlockAnnotationViewClassname } from '../nodeviews';
|
|
@@ -402,6 +403,12 @@ export var inlineCommentPlugin = function inlineCommentPlugin(options) {
|
|
|
402
403
|
if (!(event.target instanceof HTMLElement)) {
|
|
403
404
|
return false;
|
|
404
405
|
}
|
|
406
|
+
if (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations')) {
|
|
407
|
+
// The LCM renderer bridge owns selection so its draft-close guard runs first.
|
|
408
|
+
if (event.target.closest('[data-lcm-annotation-renderer]')) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
405
412
|
|
|
406
413
|
// Find the nearest ancestor (or self) with the data-id attribute
|
|
407
414
|
var annotationId = (_event$target$closest = event.target.closest('[data-id]')) === null || _event$target$closest === void 0 ? void 0 : _event$target$closest.getAttribute('data-id');
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
1
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
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; }
|
|
3
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; }
|
|
4
5
|
import { pluginFactory } from '@atlaskit/editor-common/utils/plugin-state-factory';
|
|
6
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
5
7
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
8
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
7
9
|
import reducer from './reducer';
|
|
8
|
-
import { decorationKey, findAnnotationsInSelection, inlineCommentPluginKey, isBlockNodeAnnotationsSelected, isSelectedAnnotationsChanged } from './utils';
|
|
10
|
+
import { decorationKey, getAnnotationDiscovery, findAnnotationsInSelection, inlineCommentPluginKey, isBlockNodeAnnotationsSelected, isSelectedAnnotationsChanged } from './utils';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
|
-
* Creates a
|
|
12
|
-
* This ensures each editor instance has its own cache, avoiding cross-contamination.
|
|
13
|
+
* Creates a document-sync handler with a deleted annotations cache in its closure.
|
|
13
14
|
*/
|
|
14
15
|
var createHandleDocChanged = function createHandleDocChanged() {
|
|
15
16
|
// Cache for preserving deleted annotation resolved states through delete/undo cycles
|
|
16
|
-
// This
|
|
17
|
+
// This stays outside plugin state so the undo cache is not serialized.
|
|
17
18
|
var deletedAnnotationsCache = {};
|
|
18
19
|
return function (tr, prevPluginState) {
|
|
19
20
|
if (tr.getMeta('replaceDocument')) {
|
|
@@ -22,16 +23,24 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
var updatedState = getSelectionChangedHandler(false)(tr, prevPluginState);
|
|
26
|
+
var legacyContentExperimentEnabled = isExperimentEnabled('platform_editor_fix_lcm_editor_annotations');
|
|
27
|
+
var currentDiscovery = legacyContentExperimentEnabled ? getAnnotationDiscovery(tr.doc) : undefined;
|
|
28
|
+
var previousAnnotationIds = currentDiscovery ? new Set(getAnnotationDiscovery(tr.before).annotationIds) : undefined;
|
|
29
|
+
var newNestedAnnotationIds = currentDiscovery ? currentDiscovery.nestedAnnotationIds.filter(function (id) {
|
|
30
|
+
return !(previousAnnotationIds !== null && previousAnnotationIds !== void 0 && previousAnnotationIds.has(id)) && prevPluginState.annotations[id] === undefined && deletedAnnotationsCache[id] === undefined;
|
|
31
|
+
}) : [];
|
|
25
32
|
|
|
26
33
|
// Collect annotation IDs currently in the document
|
|
27
|
-
var annotationIdsInDocument = new Set();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
var annotationIdsInDocument = currentDiscovery ? new Set([].concat(_toConsumableArray(currentDiscovery.rootAnnotationIds), _toConsumableArray(currentDiscovery.nestedAnnotationIds))) : new Set();
|
|
35
|
+
if (!currentDiscovery) {
|
|
36
|
+
tr.doc.descendants(function (node) {
|
|
37
|
+
node.marks.forEach(function (mark) {
|
|
38
|
+
if (mark.type.name === 'annotation') {
|
|
39
|
+
annotationIdsInDocument.add(mark.attrs.id);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
33
42
|
});
|
|
34
|
-
}
|
|
43
|
+
}
|
|
35
44
|
var annotationIdsInState = Object.keys(prevPluginState.annotations);
|
|
36
45
|
|
|
37
46
|
// Early return if annotations haven't changed
|
|
@@ -39,7 +48,9 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
39
48
|
return !annotationIdsInDocument.has(id);
|
|
40
49
|
});
|
|
41
50
|
if (!annotationsHaveChanged) {
|
|
42
|
-
return updatedState
|
|
51
|
+
return newNestedAnnotationIds.length > 0 ? _objectSpread(_objectSpread({}, updatedState), {}, {
|
|
52
|
+
dirtyAnnotations: true
|
|
53
|
+
}) : updatedState;
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
// Cache deleted annotations to be able to restore their resolved states on undo
|
|
@@ -62,6 +73,8 @@ var createHandleDocChanged = function createHandleDocChanged() {
|
|
|
62
73
|
});
|
|
63
74
|
return _objectSpread(_objectSpread({}, updatedState), {}, {
|
|
64
75
|
annotations: updatedAnnotations
|
|
76
|
+
}, newNestedAnnotationIds.length > 0 && {
|
|
77
|
+
dirtyAnnotations: true
|
|
65
78
|
});
|
|
66
79
|
};
|
|
67
80
|
};
|
|
@@ -189,47 +202,52 @@ var getSelectionChangedHandler = function getSelectionChangedHandler(reopenComme
|
|
|
189
202
|
getSelectionChangeHandlerOld(reopenCommentView)(tr, pluginState);
|
|
190
203
|
};
|
|
191
204
|
};
|
|
205
|
+
var createAnnotationPluginFactory = function createAnnotationPluginFactory(onDocChanged) {
|
|
206
|
+
return pluginFactory(inlineCommentPluginKey, reducer, {
|
|
207
|
+
onSelectionChanged: getSelectionChangedHandler(true),
|
|
208
|
+
onDocChanged: onDocChanged,
|
|
209
|
+
mapping: function mapping(tr, pluginState, editorState) {
|
|
210
|
+
var draftDecorationSet = pluginState.draftDecorationSet,
|
|
211
|
+
bookmark = pluginState.bookmark;
|
|
212
|
+
var mappedDecorationSet = DecorationSet.empty,
|
|
213
|
+
mappedBookmark;
|
|
214
|
+
var hasMappedDecorations = false;
|
|
215
|
+
if (draftDecorationSet) {
|
|
216
|
+
mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
|
|
217
|
+
}
|
|
218
|
+
hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, function (spec) {
|
|
219
|
+
return Object.values(decorationKey).includes(spec.key);
|
|
220
|
+
}).length > 0;
|
|
192
221
|
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
mappedDecorationSet = draftDecorationSet.map(tr.mapping, tr.doc);
|
|
206
|
-
}
|
|
207
|
-
hasMappedDecorations = mappedDecorationSet.find(undefined, undefined, function (spec) {
|
|
208
|
-
return Object.values(decorationKey).includes(spec.key);
|
|
209
|
-
}).length > 0;
|
|
222
|
+
// When changes to decoration target make decoration invalid (e.g. delete text, add mark to node),
|
|
223
|
+
// we need to reset bookmark to hide create component and to avoid invalid draft being published
|
|
224
|
+
// We only perform this change when document selection has changed.
|
|
225
|
+
if (!hasMappedDecorations && shouldClearBookMarkCheck(tr, editorState, bookmark)) {
|
|
226
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
227
|
+
draftDecorationSet: mappedDecorationSet,
|
|
228
|
+
bookmark: undefined
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (bookmark) {
|
|
232
|
+
mappedBookmark = bookmark.map(tr.mapping);
|
|
233
|
+
}
|
|
210
234
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
235
|
+
// return same pluginState if mappings did not change
|
|
236
|
+
if (mappedBookmark === bookmark && mappedDecorationSet === draftDecorationSet) {
|
|
237
|
+
return pluginState;
|
|
238
|
+
}
|
|
215
239
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
216
240
|
draftDecorationSet: mappedDecorationSet,
|
|
217
|
-
bookmark:
|
|
241
|
+
bookmark: mappedBookmark
|
|
218
242
|
});
|
|
219
243
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
bookmark: mappedBookmark
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
export var createPluginState = dest.createPluginState;
|
|
235
|
-
export var createCommand = dest.createCommand;
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
var handleDocChangedWithSync = createHandleDocChanged();
|
|
247
|
+
// Keep the control cohort's existing module-level cache lifetime unchanged.
|
|
248
|
+
var legacyDest = createAnnotationPluginFactory(handleDocChangedWithSync);
|
|
249
|
+
var commandFactory = pluginFactory(inlineCommentPluginKey, reducer);
|
|
250
|
+
export var createPluginState = function createPluginState(dispatch, initialState) {
|
|
251
|
+
return (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations') ? createAnnotationPluginFactory(createHandleDocChanged()) : legacyDest).createPluginState(dispatch, initialState);
|
|
252
|
+
};
|
|
253
|
+
export var createCommand = commandFactory.createCommand;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import _typeof from "@babel/runtime/helpers/typeof";
|
|
2
3
|
import { AnnotationTypes } from '@atlaskit/adf-schema/annotation';
|
|
3
4
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics/types/enums';
|
|
4
5
|
import { currentMediaNodeWithPos } from '@atlaskit/editor-common/media-single';
|
|
5
6
|
import { AnnotationSharedClassNames, BlockAnnotationSharedClassNames } from '@atlaskit/editor-common/styles/annotation';
|
|
6
7
|
import { canApplyAnnotationOnRange, getAnnotationIdsFromRange, getRangeInlineNodeNames, hasAnnotationMark, isEmptyTextSelection } from '@atlaskit/editor-common/utils/annotation';
|
|
7
8
|
import { isParagraph, isText } from '@atlaskit/editor-common/utils/nodes';
|
|
9
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
8
10
|
import { AllSelection, NodeSelection, PluginKey, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
9
11
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
10
12
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
@@ -62,7 +64,111 @@ var reorderAnnotations = function reorderAnnotations(annotations, $from) {
|
|
|
62
64
|
});
|
|
63
65
|
});
|
|
64
66
|
};
|
|
67
|
+
var legacyContentAnnotationsByDoc = new WeakMap();
|
|
68
|
+
var legacyContentAnnotationIdsByExtension = new WeakMap();
|
|
69
|
+
var readNestedContentNodes = function readNestedContentNodes(parameters) {
|
|
70
|
+
if (!parameters || _typeof(parameters) !== 'object') {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
var nestedContent = parameters.nestedContent;
|
|
74
|
+
if (!nestedContent || _typeof(nestedContent) !== 'object') {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
var nestedDocument = nestedContent;
|
|
78
|
+
return nestedDocument.type === 'doc' && Array.isArray(nestedDocument.content) ? nestedDocument.content : undefined;
|
|
79
|
+
};
|
|
80
|
+
var getNestedContentAnnotationIds = function getNestedContentAnnotationIds(extension) {
|
|
81
|
+
var cachedIds = legacyContentAnnotationIdsByExtension.get(extension);
|
|
82
|
+
if (cachedIds) {
|
|
83
|
+
return cachedIds;
|
|
84
|
+
}
|
|
85
|
+
var nestedNodes = readNestedContentNodes(extension.attrs.parameters);
|
|
86
|
+
if (!nestedNodes) {
|
|
87
|
+
var noIds = Object.freeze([]);
|
|
88
|
+
legacyContentAnnotationIdsByExtension.set(extension, noIds);
|
|
89
|
+
return noIds;
|
|
90
|
+
}
|
|
91
|
+
var annotationIds = new Set();
|
|
92
|
+
var visitedAdfNodes = new WeakSet();
|
|
93
|
+
var pending = _toConsumableArray(nestedNodes).reverse();
|
|
94
|
+
while (pending.length > 0) {
|
|
95
|
+
var _adfNode$attrs;
|
|
96
|
+
var value = pending.pop();
|
|
97
|
+
if (!value || _typeof(value) !== 'object' || visitedAdfNodes.has(value)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
visitedAdfNodes.add(value);
|
|
101
|
+
var adfNode = value;
|
|
102
|
+
if (Array.isArray(adfNode.marks)) {
|
|
103
|
+
adfNode.marks.forEach(function (rawMark) {
|
|
104
|
+
if (!rawMark || _typeof(rawMark) !== 'object') {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
var annotationMark = rawMark;
|
|
108
|
+
var attrs = annotationMark.attrs;
|
|
109
|
+
if (annotationMark.type !== 'annotation' || !validateAnnotationAttributes(attrs)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
annotationIds.add(attrs.id);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (adfNode.type === 'extension' && ((_adfNode$attrs = adfNode.attrs) === null || _adfNode$attrs === void 0 ? void 0 : _adfNode$attrs.extensionType) === 'com.atlassian.confluence.migration' && adfNode.attrs.extensionKey === 'legacy-content') {
|
|
116
|
+
var _nestedNodes = readNestedContentNodes(adfNode.attrs.parameters);
|
|
117
|
+
if (_nestedNodes) {
|
|
118
|
+
for (var i = _nestedNodes.length - 1; i >= 0; i--) {
|
|
119
|
+
pending.push(_nestedNodes[i]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(adfNode.content)) {
|
|
124
|
+
for (var _i = adfNode.content.length - 1; _i >= 0; _i--) {
|
|
125
|
+
pending.push(adfNode.content[_i]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
var ids = Object.freeze(_toConsumableArray(annotationIds));
|
|
130
|
+
legacyContentAnnotationIdsByExtension.set(extension, ids);
|
|
131
|
+
return ids;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/** Discover annotation IDs from immutable legacy-content ADF without repeatedly scanning it. */
|
|
135
|
+
export var getAnnotationDiscovery = function getAnnotationDiscovery(doc) {
|
|
136
|
+
var cachedDiscovery = legacyContentAnnotationsByDoc.get(doc);
|
|
137
|
+
if (cachedDiscovery) {
|
|
138
|
+
return cachedDiscovery;
|
|
139
|
+
}
|
|
140
|
+
var allAnnotationIds = new Set();
|
|
141
|
+
var rootAnnotationIds = new Set();
|
|
142
|
+
var nestedAnnotationIds = new Set();
|
|
143
|
+
doc.descendants(function (node) {
|
|
144
|
+
node.marks.filter(function (mark) {
|
|
145
|
+
return mark.type.name === 'annotation';
|
|
146
|
+
}).forEach(function (mark) {
|
|
147
|
+
if (validateAnnotationMark(mark)) {
|
|
148
|
+
rootAnnotationIds.add(mark.attrs.id);
|
|
149
|
+
allAnnotationIds.add(mark.attrs.id);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (node.type.name === 'extension' && node.attrs.extensionType === 'com.atlassian.confluence.migration' && node.attrs.extensionKey === 'legacy-content') {
|
|
153
|
+
getNestedContentAnnotationIds(node).forEach(function (id) {
|
|
154
|
+
nestedAnnotationIds.add(id);
|
|
155
|
+
allAnnotationIds.add(id);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
var discovery = {
|
|
161
|
+
annotationIds: Object.freeze(_toConsumableArray(allAnnotationIds)),
|
|
162
|
+
rootAnnotationIds: Object.freeze(_toConsumableArray(rootAnnotationIds)),
|
|
163
|
+
nestedAnnotationIds: Object.freeze(_toConsumableArray(nestedAnnotationIds))
|
|
164
|
+
};
|
|
165
|
+
legacyContentAnnotationsByDoc.set(doc, discovery);
|
|
166
|
+
return discovery;
|
|
167
|
+
};
|
|
65
168
|
export var getAllAnnotations = function getAllAnnotations(doc) {
|
|
169
|
+
if (isExperimentEnabled('platform_editor_fix_lcm_editor_annotations')) {
|
|
170
|
+
return _toConsumableArray(getAnnotationDiscovery(doc).annotationIds);
|
|
171
|
+
}
|
|
66
172
|
var allAnnotationIds = new Set();
|
|
67
173
|
doc.descendants(function (node) {
|
|
68
174
|
node.marks.filter(function (mark) {
|
|
@@ -76,29 +182,30 @@ export var getAllAnnotations = function getAllAnnotations(doc) {
|
|
|
76
182
|
});
|
|
77
183
|
return Array.from(allAnnotationIds);
|
|
78
184
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
var validateAnnotationMark = function validateAnnotationMark(annotationMark) {
|
|
84
|
-
var _ref = annotationMark.attrs,
|
|
85
|
-
id = _ref.id,
|
|
86
|
-
annotationType = _ref.annotationType;
|
|
87
|
-
return validateAnnotationId(id) && validateAnnotationType(annotationType);
|
|
88
|
-
function validateAnnotationId(id) {
|
|
89
|
-
if (!id || typeof id !== 'string') {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
var invalidIds = ['null', 'undefined'];
|
|
93
|
-
return !invalidIds.includes(id.toLowerCase());
|
|
185
|
+
var validateAnnotationId = function validateAnnotationId(id) {
|
|
186
|
+
if (!id || typeof id !== 'string') {
|
|
187
|
+
return false;
|
|
94
188
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return
|
|
189
|
+
var invalidIds = ['null', 'undefined'];
|
|
190
|
+
return !invalidIds.includes(id.toLowerCase());
|
|
191
|
+
};
|
|
192
|
+
var validateAnnotationType = function validateAnnotationType(type) {
|
|
193
|
+
if (!type || typeof type !== 'string') {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
var allowedTypes = Object.values(AnnotationTypes);
|
|
197
|
+
return allowedTypes.some(function (allowedType) {
|
|
198
|
+
return allowedType === type;
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
var validateAnnotationAttributes = function validateAnnotationAttributes(attrs) {
|
|
202
|
+
if (!attrs || _typeof(attrs) !== 'object') {
|
|
203
|
+
return false;
|
|
101
204
|
}
|
|
205
|
+
return 'id' in attrs && 'annotationType' in attrs && validateAnnotationId(attrs.id) && validateAnnotationType(attrs.annotationType);
|
|
206
|
+
};
|
|
207
|
+
var validateAnnotationMark = function validateAnnotationMark(annotationMark) {
|
|
208
|
+
return validateAnnotationAttributes(annotationMark.attrs);
|
|
102
209
|
};
|
|
103
210
|
export var decorationKey = {
|
|
104
211
|
block: 'blockCommentDecoration',
|
|
@@ -271,14 +378,26 @@ export var getDraftCommandAnalyticsPayload = function getDraftCommandAnalyticsPa
|
|
|
271
378
|
var payload = function payload(state) {
|
|
272
379
|
var attributes = {};
|
|
273
380
|
if (drafting) {
|
|
381
|
+
var _currentMediaNodeWith;
|
|
382
|
+
var selection = state.selection;
|
|
383
|
+
var targetNode = selection instanceof NodeSelection ? selection.node : (_currentMediaNodeWith = currentMediaNodeWithPos(state)) === null || _currentMediaNodeWith === void 0 ? void 0 : _currentMediaNodeWith.node;
|
|
384
|
+
var commentTargetType = 'other';
|
|
385
|
+
if ((targetNode === null || targetNode === void 0 ? void 0 : targetNode.type.name) === 'extension') {
|
|
386
|
+
commentTargetType = targetNode.attrs.extensionKey === 'native-embed:maui' ? 'remixEmbed' : 'other';
|
|
387
|
+
} else if (targetNode && ['media', 'mediaSingle', 'mediaInline'].includes(targetNode.type.name)) {
|
|
388
|
+
commentTargetType = 'media';
|
|
389
|
+
} else if (selection instanceof TextSelection || selection instanceof AllSelection) {
|
|
390
|
+
commentTargetType = 'text';
|
|
391
|
+
}
|
|
274
392
|
attributes = {
|
|
275
393
|
inputMethod: inputMethod,
|
|
276
|
-
overlap: getAnnotationsInSelectionCount(state)
|
|
394
|
+
overlap: getAnnotationsInSelectionCount(state),
|
|
395
|
+
commentTargetType: commentTargetType
|
|
277
396
|
};
|
|
278
397
|
}
|
|
279
398
|
if (fg('editor_inline_comments_on_inline_nodes')) {
|
|
280
|
-
var
|
|
281
|
-
bookmark =
|
|
399
|
+
var _ref = getPluginState(state) || {},
|
|
400
|
+
bookmark = _ref.bookmark;
|
|
282
401
|
attributes.inlineNodeNames = getRangeInlineNodeNames({
|
|
283
402
|
doc: state.doc,
|
|
284
403
|
pos: resolveDraftBookmark(state, bookmark)
|
|
@@ -295,12 +414,12 @@ export var getDraftCommandAnalyticsPayload = function getDraftCommandAnalyticsPa
|
|
|
295
414
|
return payload;
|
|
296
415
|
};
|
|
297
416
|
export var isSelectionValid = function isSelectionValid(state) {
|
|
298
|
-
var
|
|
417
|
+
var _currentMediaNodeWith2;
|
|
299
418
|
var supportedBlockNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
300
419
|
var isBlockNodeSupported = arguments.length > 2 ? arguments[2] : undefined;
|
|
301
420
|
var selection = state.selection;
|
|
302
|
-
var
|
|
303
|
-
disallowOnWhitespace =
|
|
421
|
+
var _ref2 = getPluginState(state) || {},
|
|
422
|
+
disallowOnWhitespace = _ref2.disallowOnWhitespace;
|
|
304
423
|
var allowedInlineNodes = ['emoji', 'status', 'date', 'mention', 'inlineCard'];
|
|
305
424
|
var isSelectionEmpty = selection.empty;
|
|
306
425
|
var isTextOrAllSelection = selection instanceof TextSelection || selection instanceof AllSelection;
|
|
@@ -309,7 +428,7 @@ export var isSelectionValid = function isSelectionValid(state) {
|
|
|
309
428
|
var isValidSelection = isTextOrAllSelection || isValidNodeSelection;
|
|
310
429
|
|
|
311
430
|
// Allow media so that it can enter draft mode
|
|
312
|
-
if ((
|
|
431
|
+
if ((_currentMediaNodeWith2 = currentMediaNodeWithPos(state)) !== null && _currentMediaNodeWith2 !== void 0 && _currentMediaNodeWith2.node) {
|
|
313
432
|
return AnnotationSelectionType.VALID;
|
|
314
433
|
}
|
|
315
434
|
if (isSelectionEmpty || !isValidSelection) {
|
|
@@ -11,6 +11,13 @@ import type { InlineCommentPluginState } from './types';
|
|
|
11
11
|
* @param $pos Position to center search around
|
|
12
12
|
*/
|
|
13
13
|
export declare const surroundingMarks: ($pos: ResolvedPos) => (readonly Mark[])[];
|
|
14
|
+
type AnnotationDiscovery = {
|
|
15
|
+
annotationIds: readonly string[];
|
|
16
|
+
nestedAnnotationIds: readonly string[];
|
|
17
|
+
rootAnnotationIds: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
/** Discover annotation IDs from immutable legacy-content ADF without repeatedly scanning it. */
|
|
20
|
+
export declare const getAnnotationDiscovery: (doc: Node) => AnnotationDiscovery;
|
|
14
21
|
export declare const getAllAnnotations: (doc: Node) => string[];
|
|
15
22
|
export declare const decorationKey: {
|
|
16
23
|
block: string;
|
|
@@ -52,3 +59,4 @@ export declare function isSelectedAnnotationsChanged(oldSelectedAnnotations: Ann
|
|
|
52
59
|
*/
|
|
53
60
|
export declare const isBlockNodeAnnotationsSelected: (selection: Selection, selectedAnnotations?: AnnotationInfo[]) => boolean;
|
|
54
61
|
export declare const hasAnyUnResolvedAnnotationInPage: (state: EditorState) => boolean;
|
|
62
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-annotation",
|
|
3
|
-
"version": "29.0
|
|
3
|
+
"version": "29.1.0",
|
|
4
4
|
"description": "Annotation plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,12 +30,13 @@
|
|
|
30
30
|
"@atlaskit/editor-toolbar": "^2.8.0",
|
|
31
31
|
"@atlaskit/editor-toolbar-model": "^1.2.0",
|
|
32
32
|
"@atlaskit/icon": "^38.0.0",
|
|
33
|
+
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
33
34
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
34
35
|
"@atlaskit/tmp-editor-statsig": "^246.0.0",
|
|
35
36
|
"@babel/runtime": "^7.0.0"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
|
-
"@atlaskit/editor-common": "^133.
|
|
39
|
+
"@atlaskit/editor-common": "^133.7.0",
|
|
39
40
|
"react": "^18.2.0 || ^19.2.0",
|
|
40
41
|
"react-dom": "^18.2.0 || ^19.2.0",
|
|
41
42
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|