@atlaskit/editor-plugin-synced-block 5.3.12 → 5.3.14
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 +16 -0
- package/afm-cc/tsconfig.json +0 -3
- package/afm-jira/tsconfig.json +0 -3
- package/afm-products/tsconfig.json +0 -3
- package/dist/cjs/editor-commands/index.js +34 -38
- package/dist/cjs/nodeviews/bodiedSyncedBlock.js +2 -7
- package/dist/cjs/nodeviews/syncedBlock.js +4 -18
- package/dist/cjs/pm-plugins/main.js +120 -67
- package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-creation.js +141 -0
- package/dist/cjs/pm-plugins/utils/track-sync-blocks.js +2 -2
- package/dist/cjs/pm-plugins/utils/utils.js +1 -46
- package/dist/cjs/syncedBlockPlugin.js +7 -7
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/ui/DeleteConfirmationModal.js +4 -20
- package/dist/cjs/ui/Flag.js +5 -1
- package/dist/cjs/ui/SyncBlockLabel.js +4 -10
- package/dist/cjs/ui/SyncBlockRefresher.js +7 -9
- package/dist/cjs/ui/floating-toolbar.js +6 -3
- package/dist/es2019/editor-commands/index.js +34 -38
- package/dist/es2019/nodeviews/bodiedSyncedBlock.js +2 -7
- package/dist/es2019/nodeviews/syncedBlock.js +4 -15
- package/dist/es2019/pm-plugins/main.js +99 -58
- package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-creation.js +134 -0
- package/dist/es2019/pm-plugins/utils/track-sync-blocks.js +2 -2
- package/dist/es2019/pm-plugins/utils/utils.js +0 -47
- package/dist/es2019/syncedBlockPlugin.js +7 -6
- package/dist/es2019/types/index.js +1 -0
- package/dist/es2019/ui/DeleteConfirmationModal.js +4 -20
- package/dist/es2019/ui/Flag.js +5 -0
- package/dist/es2019/ui/SyncBlockLabel.js +4 -10
- package/dist/es2019/ui/SyncBlockRefresher.js +7 -9
- package/dist/es2019/ui/floating-toolbar.js +6 -3
- package/dist/esm/editor-commands/index.js +34 -38
- package/dist/esm/nodeviews/bodiedSyncedBlock.js +2 -7
- package/dist/esm/nodeviews/syncedBlock.js +4 -18
- package/dist/esm/pm-plugins/main.js +120 -67
- package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-creation.js +134 -0
- package/dist/esm/pm-plugins/utils/track-sync-blocks.js +2 -2
- package/dist/esm/pm-plugins/utils/utils.js +0 -45
- package/dist/esm/syncedBlockPlugin.js +7 -7
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/ui/DeleteConfirmationModal.js +4 -20
- package/dist/esm/ui/Flag.js +5 -1
- package/dist/esm/ui/SyncBlockLabel.js +4 -10
- package/dist/esm/ui/SyncBlockRefresher.js +7 -9
- package/dist/esm/ui/floating-toolbar.js +6 -3
- package/dist/types/pm-plugins/main.d.ts +2 -1
- package/dist/types/pm-plugins/utils/handle-bodied-sync-block-creation.d.ts +9 -0
- package/dist/types/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +2 -2
- package/dist/types/pm-plugins/utils/utils.d.ts +1 -3
- package/dist/types/types/index.d.ts +19 -1
- package/dist/types-ts4.5/pm-plugins/main.d.ts +2 -1
- package/dist/types-ts4.5/pm-plugins/utils/handle-bodied-sync-block-creation.d.ts +9 -0
- package/dist/types-ts4.5/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +2 -2
- package/dist/types-ts4.5/pm-plugins/utils/utils.d.ts +1 -3
- package/dist/types-ts4.5/types/index.d.ts +19 -1
- package/package.json +1 -5
|
@@ -4,7 +4,6 @@ import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
|
|
|
4
4
|
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
5
5
|
import { SyncBlockSharedCssClassName, SyncBlockActionsProvider } from '@atlaskit/editor-common/sync-block';
|
|
6
6
|
import { useFetchSyncBlockData, useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
|
|
7
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
7
|
import { removeSyncedBlockAtPos } from '../editor-commands';
|
|
9
8
|
import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
|
|
10
9
|
export class SyncBlock extends ReactNodeView {
|
|
@@ -22,7 +21,7 @@ export class SyncBlock extends ReactNodeView {
|
|
|
22
21
|
render({
|
|
23
22
|
getPos
|
|
24
23
|
}) {
|
|
25
|
-
var _this$options, _this$api$syncedBlock, _this$api, _this$api$syncedBlock2, _this$api$syncedBlock3, _this$api2, _this$api2$analytics, _this$options2
|
|
24
|
+
var _this$options, _this$api$syncedBlock, _this$api, _this$api$syncedBlock2, _this$api$syncedBlock3, _this$api2, _this$api2$analytics, _this$options2;
|
|
26
25
|
if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.syncedBlockRenderer)) {
|
|
27
26
|
return null;
|
|
28
27
|
}
|
|
@@ -33,14 +32,13 @@ export class SyncBlock extends ReactNodeView {
|
|
|
33
32
|
if (!resourceId || !localId) {
|
|
34
33
|
return null;
|
|
35
34
|
}
|
|
36
|
-
const
|
|
37
|
-
const syncBlockStore = (_this$api$syncedBlock = (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$syncedBlock2 = _this$api.syncedBlock) === null || _this$api$syncedBlock2 === void 0 ? void 0 : (_this$api$syncedBlock3 = _this$api$syncedBlock2.sharedState.currentState()) === null || _this$api$syncedBlock3 === void 0 ? void 0 : _this$api$syncedBlock3.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : initialSyncBlockStore;
|
|
35
|
+
const syncBlockStore = (_this$api$syncedBlock = (_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$syncedBlock2 = _this$api.syncedBlock) === null || _this$api$syncedBlock2 === void 0 ? void 0 : (_this$api$syncedBlock3 = _this$api$syncedBlock2.sharedState.currentState()) === null || _this$api$syncedBlock3 === void 0 ? void 0 : _this$api$syncedBlock3.syncBlockStore) !== null && _this$api$syncedBlock !== void 0 ? _this$api$syncedBlock : this.syncBlockStore;
|
|
38
36
|
if (!syncBlockStore) {
|
|
39
37
|
return null;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
// get document node from data provider
|
|
43
|
-
return
|
|
41
|
+
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
44
42
|
component: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
45
43
|
dispatchAnalyticsEvent: (_this$api2 = this.api) === null || _this$api2 === void 0 ? void 0 : (_this$api2$analytics = _this$api2.analytics) === null || _this$api2$analytics === void 0 ? void 0 : _this$api2$analytics.actions.fireAnalyticsEvent,
|
|
46
44
|
fallbackComponent: null
|
|
@@ -61,16 +59,7 @@ export class SyncBlock extends ReactNodeView {
|
|
|
61
59
|
return useFetchSyncBlockData(syncBlockStore, resourceId, localId, (_this$api3 = this.api) === null || _this$api3 === void 0 ? void 0 : (_this$api3$analytics = _this$api3.analytics) === null || _this$api3$analytics === void 0 ? void 0 : (_this$api3$analytics$ = _this$api3$analytics.actions) === null || _this$api3$analytics$ === void 0 ? void 0 : _this$api3$analytics$.fireAnalyticsEvent);
|
|
62
60
|
},
|
|
63
61
|
api: this.api
|
|
64
|
-
})))
|
|
65
|
-
localId: this.node.attrs.localId,
|
|
66
|
-
syncedBlockRenderer: (_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.syncedBlockRenderer,
|
|
67
|
-
useFetchSyncBlockTitle: () => useFetchSyncBlockTitle(syncBlockStore, this.node),
|
|
68
|
-
useFetchSyncBlockData: () => {
|
|
69
|
-
var _this$api4, _this$api4$analytics, _this$api4$analytics$;
|
|
70
|
-
return useFetchSyncBlockData(syncBlockStore, resourceId, localId, (_this$api4 = this.api) === null || _this$api4 === void 0 ? void 0 : (_this$api4$analytics = _this$api4.analytics) === null || _this$api4$analytics === void 0 ? void 0 : (_this$api4$analytics$ = _this$api4$analytics.actions) === null || _this$api4$analytics$ === void 0 ? void 0 : _this$api4$analytics$.fireAnalyticsEvent);
|
|
71
|
-
},
|
|
72
|
-
api: this.api
|
|
73
|
-
});
|
|
62
|
+
})));
|
|
74
63
|
}
|
|
75
64
|
destroy() {
|
|
76
65
|
var _this$unsubscribe;
|
|
@@ -9,15 +9,37 @@ import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
|
9
9
|
import { convertPMNodesToSyncBlockNodes, rebaseTransaction } from '@atlaskit/editor-synced-block-provider';
|
|
10
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
11
|
import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
|
|
12
|
-
import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
|
|
13
12
|
import { SyncBlock as SyncBlockView } from '../nodeviews/syncedBlock';
|
|
14
13
|
import { FLAG_ID } from '../types';
|
|
14
|
+
import { handleBodiedSyncBlockCreation } from './utils/handle-bodied-sync-block-creation';
|
|
15
15
|
import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-removal';
|
|
16
16
|
import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
|
|
17
17
|
import { calculateDecorations } from './utils/selection-decorations';
|
|
18
18
|
import { hasEditInSyncBlock, trackSyncBlocks } from './utils/track-sync-blocks';
|
|
19
19
|
import { sliceFullyContainsNode } from './utils/utils';
|
|
20
20
|
export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
21
|
+
const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos) => {
|
|
22
|
+
const resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
|
|
23
|
+
const newMap = new Map(oldMap);
|
|
24
|
+
if (resourceId) {
|
|
25
|
+
const pos = newRetryCreationPos.pos;
|
|
26
|
+
if (!pos) {
|
|
27
|
+
newMap.delete(resourceId);
|
|
28
|
+
} else {
|
|
29
|
+
newMap.set(resourceId, pos);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (newMap.size === 0) {
|
|
33
|
+
return newMap;
|
|
34
|
+
}
|
|
35
|
+
for (const [id, pos] of newMap.entries()) {
|
|
36
|
+
newMap.set(id, {
|
|
37
|
+
from: mapPos(pos.from),
|
|
38
|
+
to: mapPos(pos.to)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return newMap;
|
|
42
|
+
};
|
|
21
43
|
const showCopiedFlag = api => {
|
|
22
44
|
// Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
|
|
23
45
|
setTimeout(() => {
|
|
@@ -52,7 +74,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
52
74
|
const unpublishedFlagShown = new Set();
|
|
53
75
|
|
|
54
76
|
// Set up callback to detect unpublished sync blocks when they're fetched
|
|
55
|
-
|
|
77
|
+
syncBlockStore.referenceManager.setOnUnpublishedSyncBlockDetected(resourceId => {
|
|
56
78
|
// Only show the flag once per sync block
|
|
57
79
|
if (!unpublishedFlagShown.has(resourceId)) {
|
|
58
80
|
unpublishedFlagShown.add(resourceId);
|
|
@@ -79,7 +101,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
79
101
|
return {
|
|
80
102
|
selectionDecorationSet: calculateDecorations(instance.doc, instance.selection, instance.schema),
|
|
81
103
|
activeFlag: false,
|
|
82
|
-
syncBlockStore: syncBlockStore
|
|
104
|
+
syncBlockStore: syncBlockStore,
|
|
105
|
+
retryCreationPosMap: new Map()
|
|
83
106
|
};
|
|
84
107
|
},
|
|
85
108
|
apply: (tr, currentPluginState, oldEditorState) => {
|
|
@@ -88,23 +111,30 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
88
111
|
const {
|
|
89
112
|
activeFlag,
|
|
90
113
|
selectionDecorationSet,
|
|
91
|
-
bodiedSyncBlockDeletionStatus
|
|
114
|
+
bodiedSyncBlockDeletionStatus,
|
|
115
|
+
retryCreationPosMap
|
|
92
116
|
} = currentPluginState;
|
|
93
117
|
let newDecorationSet = selectionDecorationSet.map(tr.mapping, tr.doc);
|
|
94
118
|
if (!tr.selection.eq(oldEditorState.selection)) {
|
|
95
119
|
newDecorationSet = calculateDecorations(tr.doc, tr.selection, tr.doc.type.schema);
|
|
96
120
|
}
|
|
121
|
+
let newRetryCreationPosMap = retryCreationPosMap;
|
|
122
|
+
if (fg('platform_synced_block_patch_1')) {
|
|
123
|
+
const newPosEntry = meta === null || meta === void 0 ? void 0 : meta.retryCreationPos;
|
|
124
|
+
newRetryCreationPosMap = mapRetryCreationPosMap(retryCreationPosMap, newPosEntry, tr.mapping.map.bind(tr.mapping));
|
|
125
|
+
}
|
|
97
126
|
return {
|
|
98
127
|
activeFlag: (_meta$activeFlag = meta === null || meta === void 0 ? void 0 : meta.activeFlag) !== null && _meta$activeFlag !== void 0 ? _meta$activeFlag : activeFlag,
|
|
99
128
|
selectionDecorationSet: newDecorationSet,
|
|
100
129
|
syncBlockStore: syncBlockStore,
|
|
130
|
+
retryCreationPosMap: newRetryCreationPosMap,
|
|
101
131
|
bodiedSyncBlockDeletionStatus: (_meta$bodiedSyncBlock = meta === null || meta === void 0 ? void 0 : meta.bodiedSyncBlockDeletionStatus) !== null && _meta$bodiedSyncBlock !== void 0 ? _meta$bodiedSyncBlock : bodiedSyncBlockDeletionStatus
|
|
102
132
|
};
|
|
103
133
|
}
|
|
104
134
|
},
|
|
105
135
|
props: {
|
|
106
136
|
nodeViews: {
|
|
107
|
-
syncBlock:
|
|
137
|
+
syncBlock: (node, view, getPos, _decorations) => {
|
|
108
138
|
// To support SSR, pass `syncBlockStore` here
|
|
109
139
|
// and do not use lazy loading.
|
|
110
140
|
// We cannot start rendering and then load `syncBlockStore` asynchronously,
|
|
@@ -119,11 +149,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
119
149
|
eventDispatcher: pmPluginFactoryParams.eventDispatcher,
|
|
120
150
|
syncBlockStore: syncBlockStore
|
|
121
151
|
}).init();
|
|
122
|
-
}
|
|
123
|
-
options,
|
|
124
|
-
pmPluginFactoryParams,
|
|
125
|
-
api
|
|
126
|
-
}),
|
|
152
|
+
},
|
|
127
153
|
bodiedSyncBlock: lazyBodiedSyncBlockView({
|
|
128
154
|
pluginOptions: options,
|
|
129
155
|
pmPluginFactoryParams,
|
|
@@ -131,8 +157,10 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
131
157
|
})
|
|
132
158
|
},
|
|
133
159
|
decorations: state => {
|
|
134
|
-
var
|
|
135
|
-
const
|
|
160
|
+
var _currentPluginState$s, _api$connectivity, _api$connectivity$sha, _api$editorViewMode, _api$editorViewMode$s;
|
|
161
|
+
const currentPluginState = syncedBlockPluginKey.getState(state);
|
|
162
|
+
const selectionDecorationSet = (_currentPluginState$s = currentPluginState === null || currentPluginState === void 0 ? void 0 : currentPluginState.selectionDecorationSet) !== null && _currentPluginState$s !== void 0 ? _currentPluginState$s : DecorationSet.empty;
|
|
163
|
+
const syncBlockStore = currentPluginState === null || currentPluginState === void 0 ? void 0 : currentPluginState.syncBlockStore;
|
|
136
164
|
const {
|
|
137
165
|
doc
|
|
138
166
|
} = state;
|
|
@@ -140,6 +168,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
140
168
|
const isViewMode = (api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode) === 'view';
|
|
141
169
|
const offlineDecorations = [];
|
|
142
170
|
const viewModeDecorations = [];
|
|
171
|
+
const loadingDecorations = [];
|
|
143
172
|
state.doc.descendants((node, pos) => {
|
|
144
173
|
if (node.type.name === 'bodiedSyncBlock' && isOffline) {
|
|
145
174
|
offlineDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
|
|
@@ -151,8 +180,13 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
151
180
|
class: SyncBlockStateCssClassName.viewModeClassName
|
|
152
181
|
}));
|
|
153
182
|
}
|
|
183
|
+
if (node.type.name === 'bodiedSyncBlock' && syncBlockStore.sourceManager.isPendingCreation(node.attrs.resourceId) && fg('platform_synced_block_patch_1')) {
|
|
184
|
+
loadingDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
|
|
185
|
+
class: SyncBlockStateCssClassName.creationLoadingClassName
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
154
188
|
});
|
|
155
|
-
return selectionDecorationSet.add(doc, offlineDecorations).add(doc, viewModeDecorations);
|
|
189
|
+
return selectionDecorationSet.add(doc, offlineDecorations).add(doc, viewModeDecorations).add(doc, loadingDecorations);
|
|
156
190
|
},
|
|
157
191
|
handleClickOn: createSelectionClickHandler(['bodiedSyncBlock'], target => !!target.closest(`.${BodiedSyncBlockSharedCssClassName.prefix}`), {
|
|
158
192
|
useLongPressSelection
|
|
@@ -215,9 +249,15 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
215
249
|
var _api$connectivity2, _api$connectivity2$sh;
|
|
216
250
|
const isOffline = isOfflineMode(api === null || api === void 0 ? void 0 : (_api$connectivity2 = api.connectivity) === null || _api$connectivity2 === void 0 ? void 0 : (_api$connectivity2$sh = _api$connectivity2.sharedState.currentState()) === null || _api$connectivity2$sh === void 0 ? void 0 : _api$connectivity2$sh.mode);
|
|
217
251
|
const isConfirmedSyncBlockDeletion = Boolean(tr.getMeta('isConfirmedSyncBlockDeletion'));
|
|
252
|
+
const hasNoPendingRequest = fg('platform_synced_block_patch_1') ? false :
|
|
253
|
+
// requireConfirmationBeforeDelete is always true, so this evaluates to false and hence redundant
|
|
254
|
+
!(syncBlockStore !== null && syncBlockStore !== void 0 && syncBlockStore.sourceManager.requireConfirmationBeforeDelete()) && !syncBlockStore.sourceManager.hasPendingCreation();
|
|
255
|
+
const isCommitsCreation = fg('platform_synced_block_patch_1') ? false :
|
|
256
|
+
// For patch 1, we don't intercept the insert transaction, hence it's redundant
|
|
257
|
+
Boolean(tr.getMeta('isCommitSyncBlockCreation'));
|
|
218
258
|
|
|
219
259
|
// Track newly added reference sync blocks before processing the transaction
|
|
220
|
-
if (tr.docChanged && !tr.getMeta('isRemote')
|
|
260
|
+
if (tr.docChanged && !tr.getMeta('isRemote')) {
|
|
221
261
|
const {
|
|
222
262
|
added
|
|
223
263
|
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
@@ -234,7 +274,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
234
274
|
// or are from remote (collab) or already confirmed sync block deletion
|
|
235
275
|
// We only care about local changes that change the document
|
|
236
276
|
// and are not yet confirmed for sync block deletion
|
|
237
|
-
if (!tr.docChanged ||
|
|
277
|
+
if (!tr.docChanged || hasNoPendingRequest || Boolean(tr.getMeta('isRemote')) || isCommitsCreation || !isOffline && isConfirmedSyncBlockDeletion) {
|
|
238
278
|
return true;
|
|
239
279
|
}
|
|
240
280
|
const {
|
|
@@ -242,42 +282,39 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
242
282
|
added: bodiedSyncBlockAdded
|
|
243
283
|
} = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, state);
|
|
244
284
|
if (!isOffline) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
eventType: EVENT_TYPE.OPERATIONAL
|
|
261
|
-
});
|
|
285
|
+
const {
|
|
286
|
+
removed: syncBlockRemoved,
|
|
287
|
+
added: syncBlockAdded
|
|
288
|
+
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
289
|
+
syncBlockRemoved.forEach(syncBlock => {
|
|
290
|
+
var _api$analytics, _api$analytics$action;
|
|
291
|
+
api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : (_api$analytics$action = _api$analytics.actions) === null || _api$analytics$action === void 0 ? void 0 : _api$analytics$action.fireAnalyticsEvent({
|
|
292
|
+
action: ACTION.DELETED,
|
|
293
|
+
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
294
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
|
|
295
|
+
attributes: {
|
|
296
|
+
resourceId: syncBlock.attrs.resourceId,
|
|
297
|
+
blockInstanceId: syncBlock.attrs.localId
|
|
298
|
+
},
|
|
299
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
262
300
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
301
|
+
});
|
|
302
|
+
syncBlockAdded.forEach(syncBlock => {
|
|
303
|
+
var _api$analytics2, _api$analytics2$actio;
|
|
304
|
+
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.fireAnalyticsEvent({
|
|
305
|
+
action: ACTION.INSERTED,
|
|
306
|
+
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
307
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
|
|
308
|
+
attributes: {
|
|
309
|
+
resourceId: syncBlock.attrs.resourceId,
|
|
310
|
+
blockInstanceId: syncBlock.attrs.localId
|
|
311
|
+
},
|
|
312
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
275
313
|
});
|
|
276
|
-
}
|
|
277
|
-
;
|
|
314
|
+
});
|
|
278
315
|
if (bodiedSyncBlockRemoved.length > 0) {
|
|
279
316
|
confirmationTransactionRef.current = tr;
|
|
280
|
-
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef,
|
|
317
|
+
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr));
|
|
281
318
|
}
|
|
282
319
|
if (bodiedSyncBlockAdded.length > 0) {
|
|
283
320
|
if (Boolean(tr.getMeta(pmHistoryPluginKey))) {
|
|
@@ -286,18 +323,22 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
286
323
|
// After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
|
|
287
324
|
return true;
|
|
288
325
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
326
|
+
if (fg('platform_synced_block_patch_1')) {
|
|
327
|
+
handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, state, api);
|
|
328
|
+
return true;
|
|
329
|
+
} else {
|
|
330
|
+
// If there is bodiedSyncBlock node addition and it's waiting for the result of saving the node to backend (syncBlockStore.hasPendingCreation()),
|
|
331
|
+
// we need to intercept the transaction and save it in insert callback so that we only insert it to the document when backend call if backend call is successful
|
|
332
|
+
// The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
|
|
333
|
+
syncBlockStore.sourceManager.registerCreationCallback(() => {
|
|
334
|
+
var _api$core;
|
|
335
|
+
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(() => {
|
|
336
|
+
return tr.setMeta('isCommitSyncBlockCreation', true);
|
|
337
|
+
});
|
|
338
|
+
api === null || api === void 0 ? void 0 : api.core.actions.focus();
|
|
297
339
|
});
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
return false;
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
301
342
|
}
|
|
302
343
|
} else {
|
|
303
344
|
const {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import { FLAG_ID } from '../../types';
|
|
3
|
+
import { syncedBlockPluginKey } from '../main';
|
|
4
|
+
const onRetry = (api, resourceId) => {
|
|
5
|
+
return () => {
|
|
6
|
+
var _api$core, _api$core2;
|
|
7
|
+
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.focus();
|
|
8
|
+
api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(({
|
|
9
|
+
tr
|
|
10
|
+
}) => {
|
|
11
|
+
var _api$syncedBlock, _api$syncedBlock$shar, _api$syncedBlock$shar2, _api$syncedBlock2;
|
|
12
|
+
const pos = api === null || api === void 0 ? void 0 : (_api$syncedBlock = api.syncedBlock) === null || _api$syncedBlock === void 0 ? void 0 : (_api$syncedBlock$shar = _api$syncedBlock.sharedState.currentState()) === null || _api$syncedBlock$shar === void 0 ? void 0 : (_api$syncedBlock$shar2 = _api$syncedBlock$shar.retryCreationPosMap) === null || _api$syncedBlock$shar2 === void 0 ? void 0 : _api$syncedBlock$shar2.get(resourceId);
|
|
13
|
+
const from = pos === null || pos === void 0 ? void 0 : pos.from;
|
|
14
|
+
const to = pos === null || pos === void 0 ? void 0 : pos.to;
|
|
15
|
+
if (from === undefined || to === undefined) {
|
|
16
|
+
return tr;
|
|
17
|
+
}
|
|
18
|
+
tr.setSelection(TextSelection.create(tr.doc, from, to)).setMeta(syncedBlockPluginKey, {
|
|
19
|
+
activeFlag: false
|
|
20
|
+
});
|
|
21
|
+
api === null || api === void 0 ? void 0 : (_api$syncedBlock2 = api.syncedBlock) === null || _api$syncedBlock2 === void 0 ? void 0 : _api$syncedBlock2.commands.insertSyncedBlock()({
|
|
22
|
+
tr
|
|
23
|
+
});
|
|
24
|
+
return tr;
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const getRevertCreationPos = (api, doc, resourceId) => {
|
|
29
|
+
var _api$syncedBlock3, _api$syncedBlock3$sha, _api$syncedBlock3$sha2;
|
|
30
|
+
const retryCreationPos = api === null || api === void 0 ? void 0 : (_api$syncedBlock3 = api.syncedBlock) === null || _api$syncedBlock3 === void 0 ? void 0 : (_api$syncedBlock3$sha = _api$syncedBlock3.sharedState.currentState()) === null || _api$syncedBlock3$sha === void 0 ? void 0 : (_api$syncedBlock3$sha2 = _api$syncedBlock3$sha.retryCreationPosMap) === null || _api$syncedBlock3$sha2 === void 0 ? void 0 : _api$syncedBlock3$sha2.get(resourceId);
|
|
31
|
+
if (retryCreationPos) {
|
|
32
|
+
return retryCreationPos;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fallback to find the positions in case BE call returns before plugin state becomes available
|
|
36
|
+
// which is highly unlikely
|
|
37
|
+
let currentPos;
|
|
38
|
+
doc.descendants((node, pos) => {
|
|
39
|
+
if (currentPos) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (node.type.name === 'bodiedSyncBlock' && resourceId === node.attrs.resourceId) {
|
|
43
|
+
currentPos = {
|
|
44
|
+
from: pos,
|
|
45
|
+
to: pos + node.nodeSize
|
|
46
|
+
};
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return currentPos;
|
|
51
|
+
};
|
|
52
|
+
const buildRevertCreationTr = (tr, pos) => {
|
|
53
|
+
var _tr$doc$nodeAt;
|
|
54
|
+
const content = (_tr$doc$nodeAt = tr.doc.nodeAt(pos.from)) === null || _tr$doc$nodeAt === void 0 ? void 0 : _tr$doc$nodeAt.content;
|
|
55
|
+
if (content) {
|
|
56
|
+
tr.replaceWith(pos.from, pos.to, content);
|
|
57
|
+
const contentFrom = tr.mapping.map(pos.from);
|
|
58
|
+
tr.setSelection(TextSelection.create(tr.doc, contentFrom, contentFrom + content.size));
|
|
59
|
+
} else {
|
|
60
|
+
tr.delete(pos.from, pos.to);
|
|
61
|
+
}
|
|
62
|
+
return tr;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* Save the new bodiedSyncBlock to backend with empty content and handles revert (if failed) and retry flow
|
|
68
|
+
*/
|
|
69
|
+
export const handleBodiedSyncBlockCreation = (bodiedSyncBlockAdded, editorState, api) => {
|
|
70
|
+
const syncBlockStore = syncedBlockPluginKey.getState(editorState).syncBlockStore;
|
|
71
|
+
bodiedSyncBlockAdded.forEach(node => {
|
|
72
|
+
if (node.from === undefined || node.to === undefined) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const retryCreationPos = {
|
|
76
|
+
from: node.from,
|
|
77
|
+
to: node.to
|
|
78
|
+
};
|
|
79
|
+
const resourceId = node.attrs.resourceId;
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
var _api$core3;
|
|
82
|
+
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
|
|
83
|
+
tr
|
|
84
|
+
}) => {
|
|
85
|
+
return tr.setMeta(syncedBlockPluginKey, {
|
|
86
|
+
retryCreationPos: {
|
|
87
|
+
resourceId,
|
|
88
|
+
pos: retryCreationPos
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
syncBlockStore.sourceManager.createBodiedSyncBlockNode(node.attrs, success => {
|
|
94
|
+
if (success) {
|
|
95
|
+
var _api$core4, _api$core5;
|
|
96
|
+
api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(({
|
|
97
|
+
tr
|
|
98
|
+
}) => {
|
|
99
|
+
return tr.setMeta(syncedBlockPluginKey, {
|
|
100
|
+
retryCreationPos: {
|
|
101
|
+
resourceId,
|
|
102
|
+
pos: undefined
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
api === null || api === void 0 ? void 0 : (_api$core5 = api.core) === null || _api$core5 === void 0 ? void 0 : _api$core5.actions.focus();
|
|
107
|
+
} else {
|
|
108
|
+
var _api$core6;
|
|
109
|
+
api === null || api === void 0 ? void 0 : (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions.execute(({
|
|
110
|
+
tr
|
|
111
|
+
}) => {
|
|
112
|
+
const revertCreationPos = getRevertCreationPos(api, tr.doc, resourceId);
|
|
113
|
+
if (!revertCreationPos) {
|
|
114
|
+
return tr;
|
|
115
|
+
}
|
|
116
|
+
const revertTr = buildRevertCreationTr(tr, revertCreationPos);
|
|
117
|
+
return revertTr.setMeta('isConfirmedSyncBlockDeletion', true).setMeta('addToHistory', false).setMeta(syncedBlockPluginKey, {
|
|
118
|
+
activeFlag: {
|
|
119
|
+
id: FLAG_ID.CANNOT_CREATE_SYNC_BLOCK,
|
|
120
|
+
onRetry: onRetry(api, resourceId),
|
|
121
|
+
onDismissed: tr => tr.setMeta(syncedBlockPluginKey, {
|
|
122
|
+
...tr.getMeta(syncedBlockPluginKey),
|
|
123
|
+
retryCreationPos: {
|
|
124
|
+
resourceId,
|
|
125
|
+
pos: undefined
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}, node.node);
|
|
133
|
+
});
|
|
134
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
2
|
import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
3
|
export const trackSyncBlocks = (predicate, tr, state) => {
|
|
5
4
|
const removed = {};
|
|
6
5
|
const added = {};
|
|
@@ -20,7 +19,7 @@ export const trackSyncBlocks = (predicate, tr, state) => {
|
|
|
20
19
|
from,
|
|
21
20
|
to
|
|
22
21
|
} = step;
|
|
23
|
-
const docAtStep =
|
|
22
|
+
const docAtStep = tr.docs[idx];
|
|
24
23
|
let hasChange = false;
|
|
25
24
|
if (from !== to) {
|
|
26
25
|
step.getMap().forEach((oldStart, oldEnd) => {
|
|
@@ -67,6 +66,7 @@ export const trackSyncBlocks = (predicate, tr, state) => {
|
|
|
67
66
|
const syncBlockAttr = node.attrs;
|
|
68
67
|
syncBlockMapNew[syncBlockAttr.localId] = {
|
|
69
68
|
attrs: syncBlockAttr,
|
|
69
|
+
node: node,
|
|
70
70
|
from: offset,
|
|
71
71
|
to: offset + node.nodeSize
|
|
72
72
|
};
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
-
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
3
|
import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
-
import { CellSelection, findTable } from '@atlaskit/editor-tables';
|
|
6
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
4
|
export const findSyncBlock = (schema, selection) => {
|
|
8
5
|
const {
|
|
9
6
|
syncBlock
|
|
@@ -28,50 +25,6 @@ const UNSUPPORTED_NODE_TYPES = new Set(['inlineExtension', 'extension', 'bodiedE
|
|
|
28
25
|
* or false if conversion is not possible
|
|
29
26
|
*/
|
|
30
27
|
export const canBeConvertedToSyncBlock = selection => {
|
|
31
|
-
return fg('platform_synced_block_dogfooding') ? canBeConvertedToSyncBlockNew(selection) : canBeConvertedToSyncBlockOld(selection);
|
|
32
|
-
};
|
|
33
|
-
export const canBeConvertedToSyncBlockOld = selection => {
|
|
34
|
-
const schema = selection.$from.doc.type.schema;
|
|
35
|
-
const {
|
|
36
|
-
nodes
|
|
37
|
-
} = schema;
|
|
38
|
-
let from = selection.from;
|
|
39
|
-
let to = selection.to;
|
|
40
|
-
let contentToInclude = selection.content().content;
|
|
41
|
-
if (selection instanceof CellSelection) {
|
|
42
|
-
const table = findTable(selection);
|
|
43
|
-
if (!table) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
contentToInclude = Fragment.from([table.node]);
|
|
47
|
-
from = table.pos;
|
|
48
|
-
to = table.pos + table.node.nodeSize;
|
|
49
|
-
} else if (selection instanceof TextSelection) {
|
|
50
|
-
const trueParent = findParentNodeOfType([nodes.bulletList, nodes.orderedList, nodes.taskList, nodes.blockquote])(selection);
|
|
51
|
-
if (trueParent) {
|
|
52
|
-
contentToInclude = Fragment.from([trueParent.node]);
|
|
53
|
-
from = trueParent.pos;
|
|
54
|
-
to = trueParent.pos + trueParent.node.nodeSize;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
let canBeConverted = true;
|
|
58
|
-
selection.$from.doc.nodesBetween(from, to, node => {
|
|
59
|
-
if (UNSUPPORTED_NODE_TYPES.has(node.type.name)) {
|
|
60
|
-
canBeConverted = false;
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
if (!canBeConverted) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
contentToInclude = removeBreakoutMarks(contentToInclude);
|
|
68
|
-
return {
|
|
69
|
-
contentToInclude,
|
|
70
|
-
from,
|
|
71
|
-
to
|
|
72
|
-
};
|
|
73
|
-
};
|
|
74
|
-
export const canBeConvertedToSyncBlockNew = selection => {
|
|
75
28
|
const {
|
|
76
29
|
$from,
|
|
77
30
|
range
|
|
@@ -4,7 +4,6 @@ import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
|
4
4
|
import { IconSyncBlock } from '@atlaskit/editor-common/quick-insert';
|
|
5
5
|
import { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
|
|
6
6
|
import Lozenge from '@atlaskit/lozenge';
|
|
7
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
7
|
import { flushBodiedSyncBlocks, flushSyncBlocks } from './editor-actions';
|
|
9
8
|
import { copySyncedBlockReferenceToClipboardEditorCommand, createSyncedBlock } from './editor-commands';
|
|
10
9
|
import { createPlugin, syncedBlockPluginKey } from './pm-plugins/main';
|
|
@@ -41,7 +40,7 @@ export const syncedBlockPlugin = ({
|
|
|
41
40
|
return [{
|
|
42
41
|
name: 'syncedBlockPlugin',
|
|
43
42
|
plugin: params => createPlugin(config, params, syncBlockStore, api)
|
|
44
|
-
},
|
|
43
|
+
}, {
|
|
45
44
|
name: 'menuAndToolbarExperiencesPlugin',
|
|
46
45
|
plugin: () => getMenuAndToolbarExperiencesPlugin({
|
|
47
46
|
refs,
|
|
@@ -50,7 +49,7 @@ export const syncedBlockPlugin = ({
|
|
|
50
49
|
return api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.fireAnalyticsEvent(payload);
|
|
51
50
|
}
|
|
52
51
|
})
|
|
53
|
-
}]
|
|
52
|
+
}];
|
|
54
53
|
},
|
|
55
54
|
commands: {
|
|
56
55
|
copySyncedBlockReferenceToClipboard: inputMethod => copySyncedBlockReferenceToClipboardEditorCommand(syncBlockStore, inputMethod, api),
|
|
@@ -106,7 +105,7 @@ export const syncedBlockPlugin = ({
|
|
|
106
105
|
fireAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : _api$analytics4.actions.fireAnalyticsEvent
|
|
107
106
|
});
|
|
108
107
|
},
|
|
109
|
-
testId:
|
|
108
|
+
testId: SYNCED_BLOCK_BUTTON_TEST_ID.quickInsertCreate
|
|
110
109
|
}];
|
|
111
110
|
},
|
|
112
111
|
floatingToolbar: (state, intl) => getToolbarConfig(state, intl, api, syncBlockStore)
|
|
@@ -136,12 +135,14 @@ export const syncedBlockPlugin = ({
|
|
|
136
135
|
const {
|
|
137
136
|
activeFlag,
|
|
138
137
|
syncBlockStore: currentSyncBlockStore,
|
|
139
|
-
bodiedSyncBlockDeletionStatus
|
|
138
|
+
bodiedSyncBlockDeletionStatus,
|
|
139
|
+
retryCreationPosMap
|
|
140
140
|
} = syncedBlockPluginKey.getState(editorState);
|
|
141
141
|
return {
|
|
142
142
|
activeFlag,
|
|
143
143
|
syncBlockStore: currentSyncBlockStore,
|
|
144
|
-
bodiedSyncBlockDeletionStatus
|
|
144
|
+
bodiedSyncBlockDeletionStatus,
|
|
145
|
+
retryCreationPosMap
|
|
145
146
|
};
|
|
146
147
|
}
|
|
147
148
|
};
|
|
@@ -5,6 +5,7 @@ export let FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
|
|
|
5
5
|
FLAG_ID["FAIL_TO_DELETE"] = "fail-to-delete";
|
|
6
6
|
FLAG_ID["SYNC_BLOCK_COPIED"] = "sync-block-copied";
|
|
7
7
|
FLAG_ID["UNPUBLISHED_SYNC_BLOCK_PASTED"] = "unpublished-sync-block-pasted";
|
|
8
|
+
FLAG_ID["CANNOT_CREATE_SYNC_BLOCK"] = "cannot-create-sync-block";
|
|
8
9
|
return FLAG_ID;
|
|
9
10
|
}({});
|
|
10
11
|
export const SYNCED_BLOCK_BUTTON_TEST_ID = {
|