@atlaskit/editor-plugin-synced-block 5.3.33 → 5.3.34
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 +8 -0
- package/dist/cjs/editor-commands/index.js +2 -4
- package/dist/cjs/pm-plugins/main.js +266 -109
- package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-creation.js +2 -1
- package/dist/cjs/pm-plugins/utils/utils.js +13 -1
- package/dist/es2019/editor-commands/index.js +10 -10
- package/dist/es2019/pm-plugins/main.js +256 -115
- package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-creation.js +2 -1
- package/dist/es2019/pm-plugins/utils/utils.js +13 -0
- package/dist/esm/editor-commands/index.js +3 -5
- package/dist/esm/pm-plugins/main.js +266 -109
- package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-creation.js +2 -1
- package/dist/esm/pm-plugins/utils/utils.js +13 -0
- package/dist/types/pm-plugins/utils/utils.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/utils/utils.d.ts +5 -0
- package/package.json +4 -1
|
@@ -5,7 +5,7 @@ import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
|
5
5
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
7
7
|
import { syncedBlockPluginKey } from '../pm-plugins/main';
|
|
8
|
-
import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
8
|
+
import { canBeConvertedToSyncBlock, deferDispatch, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
9
9
|
import { FLAG_ID } from '../types';
|
|
10
10
|
import { pasteSyncBlockHTMLContent } from './utils';
|
|
11
11
|
export const createSyncedBlock = ({
|
|
@@ -88,9 +88,7 @@ export const copySyncedBlockReferenceToClipboardEditorCommand = (syncBlockStore,
|
|
|
88
88
|
}
|
|
89
89
|
return null;
|
|
90
90
|
};
|
|
91
|
-
export const copySyncedBlockReferenceToClipboard = (syncBlockStore, inputMethod, api) => (state, _dispatch, _view) =>
|
|
92
|
-
return copySyncedBlockReferenceToClipboardInternal(state.tr.doc.type.schema, state.tr.selection, syncBlockStore, inputMethod, api);
|
|
93
|
-
};
|
|
91
|
+
export const copySyncedBlockReferenceToClipboard = (syncBlockStore, inputMethod, api) => (state, _dispatch, _view) => copySyncedBlockReferenceToClipboardInternal(state.tr.doc.type.schema, state.tr.selection, syncBlockStore, inputMethod, api);
|
|
94
92
|
const copySyncedBlockReferenceToClipboardInternal = (schema, selection, syncBlockStore, inputMethod, api) => {
|
|
95
93
|
const syncBlockFindResult = findSyncBlockOrBodiedSyncBlock(schema, selection);
|
|
96
94
|
if (!syncBlockFindResult) {
|
|
@@ -154,9 +152,7 @@ const copySyncedBlockReferenceToClipboardInternal = (schema, selection, syncBloc
|
|
|
154
152
|
}
|
|
155
153
|
const domNode = toDOM(referenceSyncBlockNode, schema);
|
|
156
154
|
copyDomNode(domNode, referenceSyncBlockNode.type, selection);
|
|
157
|
-
|
|
158
|
-
// Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
|
|
159
|
-
setTimeout(() => {
|
|
155
|
+
deferDispatch(() => {
|
|
160
156
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
161
157
|
tr
|
|
162
158
|
}) => {
|
|
@@ -177,7 +173,7 @@ const copySyncedBlockReferenceToClipboardInternal = (schema, selection, syncBloc
|
|
|
177
173
|
}
|
|
178
174
|
});
|
|
179
175
|
});
|
|
180
|
-
}
|
|
176
|
+
});
|
|
181
177
|
return true;
|
|
182
178
|
};
|
|
183
179
|
export const editSyncedBlockSource = (syncBlockStore, api) => (state, dispatch, _view) => {
|
|
@@ -202,7 +198,9 @@ export const editSyncedBlockSource = (syncBlockStore, api) => (state, dispatch,
|
|
|
202
198
|
window.open(syncBlockURL, '_blank');
|
|
203
199
|
} else {
|
|
204
200
|
var _api$analytics6, _api$analytics6$actio;
|
|
205
|
-
const
|
|
201
|
+
const {
|
|
202
|
+
tr
|
|
203
|
+
} = state;
|
|
206
204
|
api === null || api === void 0 ? void 0 : (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : (_api$analytics6$actio = _api$analytics6.actions) === null || _api$analytics6$actio === void 0 ? void 0 : _api$analytics6$actio.attachAnalyticsEvent({
|
|
207
205
|
eventType: EVENT_TYPE.OPERATIONAL,
|
|
208
206
|
action: ACTION.ERROR,
|
|
@@ -268,7 +266,9 @@ export const unsync = (storeManager, isBodiedSyncBlock, view) => {
|
|
|
268
266
|
}
|
|
269
267
|
if (isBodiedSyncBlock) {
|
|
270
268
|
const content = syncBlock === null || syncBlock === void 0 ? void 0 : syncBlock.node.content;
|
|
271
|
-
const
|
|
269
|
+
const {
|
|
270
|
+
tr
|
|
271
|
+
} = state;
|
|
272
272
|
tr.replaceWith(syncBlock.pos, syncBlock.pos + syncBlock.node.nodeSize, content).setMeta('deletionReason', 'source-block-unsynced');
|
|
273
273
|
view.dispatch(tr);
|
|
274
274
|
return true;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
1
2
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
3
4
|
import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
|
|
@@ -16,13 +17,15 @@ import { handleBodiedSyncBlockRemoval } from './utils/handle-bodied-sync-block-r
|
|
|
16
17
|
import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
|
|
17
18
|
import { calculateDecorations } from './utils/selection-decorations';
|
|
18
19
|
import { hasEditInSyncBlock, trackSyncBlocks } from './utils/track-sync-blocks';
|
|
19
|
-
import { wasInlineExtensionInsertedInBodiedSyncBlock, sliceFullyContainsNode } from './utils/utils';
|
|
20
|
+
import { deferDispatch, wasInlineExtensionInsertedInBodiedSyncBlock, sliceFullyContainsNode } from './utils/utils';
|
|
20
21
|
export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
21
22
|
const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos) => {
|
|
22
23
|
const resourceId = newRetryCreationPos === null || newRetryCreationPos === void 0 ? void 0 : newRetryCreationPos.resourceId;
|
|
23
24
|
const newMap = new Map(oldMap);
|
|
24
25
|
if (resourceId) {
|
|
25
|
-
const
|
|
26
|
+
const {
|
|
27
|
+
pos
|
|
28
|
+
} = newRetryCreationPos;
|
|
26
29
|
if (!pos) {
|
|
27
30
|
newMap.delete(resourceId);
|
|
28
31
|
} else {
|
|
@@ -41,18 +44,15 @@ const mapRetryCreationPosMap = (oldMap, newRetryCreationPos, mapPos) => {
|
|
|
41
44
|
return newMap;
|
|
42
45
|
};
|
|
43
46
|
const showCopiedFlag = api => {
|
|
44
|
-
|
|
45
|
-
setTimeout(() => {
|
|
47
|
+
deferDispatch(() => {
|
|
46
48
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
47
49
|
tr
|
|
48
|
-
}) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
-
}, 0);
|
|
50
|
+
}) => tr.setMeta(syncedBlockPluginKey, {
|
|
51
|
+
activeFlag: {
|
|
52
|
+
id: FLAG_ID.SYNC_BLOCK_COPIED
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
});
|
|
56
56
|
};
|
|
57
57
|
const showInlineExtensionInSyncBlockWarningIfNeeded = (tr, state, api, inlineExtensionFlagShown) => {
|
|
58
58
|
var _api$connectivity, _api$connectivity$sha;
|
|
@@ -66,18 +66,15 @@ const showInlineExtensionInSyncBlockWarningIfNeeded = (tr, state, api, inlineExt
|
|
|
66
66
|
// Only show the flag on the first instance per sync block (same as UNPUBLISHED_SYNC_BLOCK_PASTED)
|
|
67
67
|
if (resourceId && !inlineExtensionFlagShown.has(resourceId)) {
|
|
68
68
|
inlineExtensionFlagShown.add(resourceId);
|
|
69
|
-
|
|
70
|
-
setTimeout(() => {
|
|
69
|
+
deferDispatch(() => {
|
|
71
70
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
72
71
|
tr
|
|
73
|
-
}) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
}, 0);
|
|
72
|
+
}) => tr.setMeta(syncedBlockPluginKey, {
|
|
73
|
+
activeFlag: {
|
|
74
|
+
id: FLAG_ID.INLINE_EXTENSION_IN_SYNC_BLOCK
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
});
|
|
81
78
|
}
|
|
82
79
|
};
|
|
83
80
|
const getDeleteReason = tr => {
|
|
@@ -87,37 +84,166 @@ const getDeleteReason = tr => {
|
|
|
87
84
|
}
|
|
88
85
|
return reason;
|
|
89
86
|
};
|
|
87
|
+
const filterTransactionOnline = ({
|
|
88
|
+
tr,
|
|
89
|
+
state,
|
|
90
|
+
syncBlockStore,
|
|
91
|
+
api,
|
|
92
|
+
confirmationTransactionRef,
|
|
93
|
+
bodiedSyncBlockRemoved,
|
|
94
|
+
bodiedSyncBlockAdded,
|
|
95
|
+
inlineExtensionFlagShown
|
|
96
|
+
}) => {
|
|
97
|
+
const {
|
|
98
|
+
removed: syncBlockRemoved,
|
|
99
|
+
added: syncBlockAdded
|
|
100
|
+
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
101
|
+
syncBlockRemoved.forEach(syncBlock => {
|
|
102
|
+
var _api$analytics, _api$analytics$action;
|
|
103
|
+
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({
|
|
104
|
+
action: ACTION.DELETED,
|
|
105
|
+
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
106
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
|
|
107
|
+
attributes: {
|
|
108
|
+
resourceId: syncBlock.attrs.resourceId,
|
|
109
|
+
blockInstanceId: syncBlock.attrs.localId
|
|
110
|
+
},
|
|
111
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
syncBlockAdded.forEach(syncBlock => {
|
|
115
|
+
if (fg('platform_synced_block_patch_3')) {
|
|
116
|
+
var _api$analytics2, _api$analytics2$actio;
|
|
117
|
+
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({
|
|
118
|
+
action: ACTION.INSERTED,
|
|
119
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
120
|
+
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK,
|
|
121
|
+
attributes: {
|
|
122
|
+
resourceId: syncBlock.attrs.resourceId,
|
|
123
|
+
blockInstanceId: syncBlock.attrs.localId
|
|
124
|
+
},
|
|
125
|
+
eventType: EVENT_TYPE.TRACK
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
var _api$analytics3, _api$analytics3$actio;
|
|
129
|
+
api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : (_api$analytics3$actio = _api$analytics3.actions) === null || _api$analytics3$actio === void 0 ? void 0 : _api$analytics3$actio.fireAnalyticsEvent({
|
|
130
|
+
action: ACTION.INSERTED,
|
|
131
|
+
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
132
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
|
|
133
|
+
attributes: {
|
|
134
|
+
resourceId: syncBlock.attrs.resourceId,
|
|
135
|
+
blockInstanceId: syncBlock.attrs.localId
|
|
136
|
+
},
|
|
137
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
if (bodiedSyncBlockRemoved.length > 0) {
|
|
142
|
+
// eslint-disable-next-line no-param-reassign
|
|
143
|
+
confirmationTransactionRef.current = tr;
|
|
144
|
+
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr));
|
|
145
|
+
}
|
|
146
|
+
if (bodiedSyncBlockAdded.length > 0) {
|
|
147
|
+
if (tr.getMeta(pmHistoryPluginKey)) {
|
|
148
|
+
// We don't allow bodiedSyncBlock creation via redo, however, we need to return true here to let transaction through so history can be updated properly.
|
|
149
|
+
// If we simply returns false, creation from redo is blocked as desired, but this results in editor showing redo as possible even though it's not.
|
|
150
|
+
// After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
handleBodiedSyncBlockCreation(bodiedSyncBlockAdded, state, api);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
showInlineExtensionInSyncBlockWarningIfNeeded(tr, state, api, inlineExtensionFlagShown);
|
|
157
|
+
return true;
|
|
158
|
+
};
|
|
159
|
+
const filterTransactionOffline = ({
|
|
160
|
+
tr,
|
|
161
|
+
state,
|
|
162
|
+
api,
|
|
163
|
+
isConfirmedSyncBlockDeletion,
|
|
164
|
+
bodiedSyncBlockRemoved,
|
|
165
|
+
bodiedSyncBlockAdded
|
|
166
|
+
}) => {
|
|
167
|
+
const {
|
|
168
|
+
removed: syncBlockRemoved,
|
|
169
|
+
added: syncBlockAdded
|
|
170
|
+
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
171
|
+
let errorFlag = false;
|
|
172
|
+
if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
|
|
173
|
+
errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
|
|
174
|
+
} else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
|
|
175
|
+
errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
|
|
176
|
+
} else if (hasEditInSyncBlock(tr, state)) {
|
|
177
|
+
errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
|
|
178
|
+
}
|
|
179
|
+
if (errorFlag) {
|
|
180
|
+
deferDispatch(() => {
|
|
181
|
+
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
182
|
+
tr
|
|
183
|
+
}) => tr.setMeta(syncedBlockPluginKey, {
|
|
184
|
+
activeFlag: {
|
|
185
|
+
id: errorFlag
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
188
|
+
});
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
return true;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Encapsulates mutable state that persists across transactions in the
|
|
196
|
+
* synced block plugin. Replaces module-level closure variables so state
|
|
197
|
+
* is explicitly scoped to a single plugin instance.
|
|
198
|
+
*/
|
|
199
|
+
class SyncedBlockPluginContext {
|
|
200
|
+
constructor() {
|
|
201
|
+
_defineProperty(this, "confirmationTransactionRef", {
|
|
202
|
+
current: undefined
|
|
203
|
+
});
|
|
204
|
+
_defineProperty(this, "_isCopyEvent", false);
|
|
205
|
+
_defineProperty(this, "unpublishedFlagShown", new Set());
|
|
206
|
+
_defineProperty(this, "inlineExtensionFlagShown", new Set());
|
|
207
|
+
}
|
|
208
|
+
get isCopyEvent() {
|
|
209
|
+
return this._isCopyEvent;
|
|
210
|
+
}
|
|
211
|
+
markCopyEvent() {
|
|
212
|
+
this._isCopyEvent = true;
|
|
213
|
+
}
|
|
214
|
+
consumeCopyEvent() {
|
|
215
|
+
const was = this._isCopyEvent;
|
|
216
|
+
this._isCopyEvent = false;
|
|
217
|
+
return was;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
90
220
|
export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api) => {
|
|
221
|
+
var _ctx$confirmationTran, _ctx$unpublishedFlagS, _ctx$inlineExtensionF;
|
|
91
222
|
const {
|
|
92
223
|
useLongPressSelection = false
|
|
93
224
|
} = options || {};
|
|
94
|
-
const
|
|
225
|
+
const ctx = fg('platform_synced_block_patch_5') ? new SyncedBlockPluginContext() : undefined;
|
|
226
|
+
const confirmationTransactionRef = (_ctx$confirmationTran = ctx === null || ctx === void 0 ? void 0 : ctx.confirmationTransactionRef) !== null && _ctx$confirmationTran !== void 0 ? _ctx$confirmationTran : {
|
|
95
227
|
current: undefined
|
|
96
228
|
};
|
|
97
|
-
// Track if a copy event occurred to distinguish copy from drag and drop
|
|
98
229
|
let isCopyEvent = false;
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
// Track which sync blocks have already triggered the inline extension in sync block flag
|
|
102
|
-
const inlineExtensionFlagShown = new Set();
|
|
230
|
+
const unpublishedFlagShown = (_ctx$unpublishedFlagS = ctx === null || ctx === void 0 ? void 0 : ctx.unpublishedFlagShown) !== null && _ctx$unpublishedFlagS !== void 0 ? _ctx$unpublishedFlagS : new Set();
|
|
231
|
+
const inlineExtensionFlagShown = (_ctx$inlineExtensionF = ctx === null || ctx === void 0 ? void 0 : ctx.inlineExtensionFlagShown) !== null && _ctx$inlineExtensionF !== void 0 ? _ctx$inlineExtensionF : new Set();
|
|
103
232
|
|
|
104
233
|
// Set up callback to detect unpublished sync blocks when they're fetched
|
|
105
234
|
syncBlockStore.referenceManager.setOnUnpublishedSyncBlockDetected(resourceId => {
|
|
106
235
|
// Only show the flag once per sync block
|
|
107
236
|
if (!unpublishedFlagShown.has(resourceId)) {
|
|
108
237
|
unpublishedFlagShown.add(resourceId);
|
|
109
|
-
|
|
110
|
-
setTimeout(() => {
|
|
238
|
+
deferDispatch(() => {
|
|
111
239
|
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
112
240
|
tr
|
|
113
|
-
}) => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
});
|
|
120
|
-
}, 0);
|
|
241
|
+
}) => tr.setMeta(syncedBlockPluginKey, {
|
|
242
|
+
activeFlag: {
|
|
243
|
+
id: FLAG_ID.UNPUBLISHED_SYNC_BLOCK_PASTED
|
|
244
|
+
}
|
|
245
|
+
}));
|
|
246
|
+
});
|
|
121
247
|
}
|
|
122
248
|
});
|
|
123
249
|
return new SafePlugin({
|
|
@@ -159,22 +285,21 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
159
285
|
},
|
|
160
286
|
props: {
|
|
161
287
|
nodeViews: {
|
|
162
|
-
syncBlock: (node, view, getPos, _decorations) =>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
},
|
|
288
|
+
syncBlock: (node, view, getPos, _decorations) =>
|
|
289
|
+
// To support SSR, pass `syncBlockStore` here
|
|
290
|
+
// and do not use lazy loading.
|
|
291
|
+
// We cannot start rendering and then load `syncBlockStore` asynchronously,
|
|
292
|
+
// because obtaining it is asynchronous (sharedPluginState.currentState() is delayed).
|
|
293
|
+
new SyncBlockView({
|
|
294
|
+
api,
|
|
295
|
+
options,
|
|
296
|
+
node,
|
|
297
|
+
view,
|
|
298
|
+
getPos,
|
|
299
|
+
portalProviderAPI: pmPluginFactoryParams.portalProviderAPI,
|
|
300
|
+
eventDispatcher: pmPluginFactoryParams.eventDispatcher,
|
|
301
|
+
syncBlockStore: syncBlockStore
|
|
302
|
+
}).init(),
|
|
178
303
|
bodiedSyncBlock: lazyBodiedSyncBlockView({
|
|
179
304
|
pluginOptions: options,
|
|
180
305
|
pmPluginFactoryParams,
|
|
@@ -224,7 +349,11 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
224
349
|
return shouldIgnoreDomEvent(view, event, api);
|
|
225
350
|
},
|
|
226
351
|
copy: () => {
|
|
227
|
-
|
|
352
|
+
if (ctx) {
|
|
353
|
+
ctx.markCopyEvent();
|
|
354
|
+
} else {
|
|
355
|
+
isCopyEvent = true;
|
|
356
|
+
}
|
|
228
357
|
return false;
|
|
229
358
|
}
|
|
230
359
|
},
|
|
@@ -236,8 +365,10 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
236
365
|
const {
|
|
237
366
|
schema
|
|
238
367
|
} = state;
|
|
239
|
-
const isCopy = isCopyEvent;
|
|
240
|
-
|
|
368
|
+
const isCopy = ctx ? ctx.consumeCopyEvent() : isCopyEvent;
|
|
369
|
+
if (!ctx) {
|
|
370
|
+
isCopyEvent = false;
|
|
371
|
+
}
|
|
241
372
|
if (!syncBlockStore || !isCopy) {
|
|
242
373
|
return slice;
|
|
243
374
|
}
|
|
@@ -280,7 +411,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
280
411
|
const {
|
|
281
412
|
added
|
|
282
413
|
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
283
|
-
// Mark newly added sync blocks so we can detect unpublished status when data is fetched
|
|
284
414
|
added.forEach(nodeInfo => {
|
|
285
415
|
var _nodeInfo$attrs;
|
|
286
416
|
if ((_nodeInfo$attrs = nodeInfo.attrs) !== null && _nodeInfo$attrs !== void 0 && _nodeInfo$attrs.resourceId) {
|
|
@@ -288,11 +418,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
288
418
|
}
|
|
289
419
|
});
|
|
290
420
|
}
|
|
291
|
-
|
|
292
|
-
// Ignore transactions that don't change the document
|
|
293
|
-
// or are from remote (collab) or already confirmed sync block deletion
|
|
294
|
-
// We only care about local changes that change the document
|
|
295
|
-
// and are not yet confirmed for sync block deletion
|
|
296
421
|
if (!tr.docChanged || Boolean(tr.getMeta('isRemote')) || !isOffline && isConfirmedSyncBlockDeletion) {
|
|
297
422
|
return true;
|
|
298
423
|
}
|
|
@@ -300,14 +425,33 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
300
425
|
removed: bodiedSyncBlockRemoved,
|
|
301
426
|
added: bodiedSyncBlockAdded
|
|
302
427
|
} = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, state);
|
|
428
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
429
|
+
return isOffline ? filterTransactionOffline({
|
|
430
|
+
tr,
|
|
431
|
+
state,
|
|
432
|
+
api,
|
|
433
|
+
isConfirmedSyncBlockDeletion,
|
|
434
|
+
bodiedSyncBlockRemoved,
|
|
435
|
+
bodiedSyncBlockAdded
|
|
436
|
+
}) : filterTransactionOnline({
|
|
437
|
+
tr,
|
|
438
|
+
state,
|
|
439
|
+
syncBlockStore,
|
|
440
|
+
api,
|
|
441
|
+
confirmationTransactionRef,
|
|
442
|
+
bodiedSyncBlockRemoved,
|
|
443
|
+
bodiedSyncBlockAdded,
|
|
444
|
+
inlineExtensionFlagShown
|
|
445
|
+
});
|
|
446
|
+
}
|
|
303
447
|
if (!isOffline) {
|
|
304
448
|
const {
|
|
305
449
|
removed: syncBlockRemoved,
|
|
306
450
|
added: syncBlockAdded
|
|
307
451
|
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
308
452
|
syncBlockRemoved.forEach(syncBlock => {
|
|
309
|
-
var _api$
|
|
310
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
453
|
+
var _api$analytics4, _api$analytics4$actio;
|
|
454
|
+
api === null || api === void 0 ? void 0 : (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 ? void 0 : (_api$analytics4$actio = _api$analytics4.actions) === null || _api$analytics4$actio === void 0 ? void 0 : _api$analytics4$actio.fireAnalyticsEvent({
|
|
311
455
|
action: ACTION.DELETED,
|
|
312
456
|
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
313
457
|
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
|
|
@@ -320,8 +464,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
320
464
|
});
|
|
321
465
|
syncBlockAdded.forEach(syncBlock => {
|
|
322
466
|
if (fg('platform_synced_block_patch_3')) {
|
|
323
|
-
var _api$
|
|
324
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
467
|
+
var _api$analytics5, _api$analytics5$actio;
|
|
468
|
+
api === null || api === void 0 ? void 0 : (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 ? void 0 : (_api$analytics5$actio = _api$analytics5.actions) === null || _api$analytics5$actio === void 0 ? void 0 : _api$analytics5$actio.fireAnalyticsEvent({
|
|
325
469
|
action: ACTION.INSERTED,
|
|
326
470
|
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
327
471
|
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK,
|
|
@@ -332,8 +476,8 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
332
476
|
eventType: EVENT_TYPE.TRACK
|
|
333
477
|
});
|
|
334
478
|
} else {
|
|
335
|
-
var _api$
|
|
336
|
-
api === null || api === void 0 ? void 0 : (_api$
|
|
479
|
+
var _api$analytics6, _api$analytics6$actio;
|
|
480
|
+
api === null || api === void 0 ? void 0 : (_api$analytics6 = api.analytics) === null || _api$analytics6 === void 0 ? void 0 : (_api$analytics6$actio = _api$analytics6.actions) === null || _api$analytics6$actio === void 0 ? void 0 : _api$analytics6$actio.fireAnalyticsEvent({
|
|
337
481
|
action: ACTION.INSERTED,
|
|
338
482
|
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
339
483
|
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_CREATE,
|
|
@@ -350,7 +494,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
350
494
|
return handleBodiedSyncBlockRemoval(bodiedSyncBlockRemoved, syncBlockStore, api, confirmationTransactionRef, getDeleteReason(tr));
|
|
351
495
|
}
|
|
352
496
|
if (bodiedSyncBlockAdded.length > 0) {
|
|
353
|
-
if (
|
|
497
|
+
if (tr.getMeta(pmHistoryPluginKey)) {
|
|
354
498
|
// We don't allow bodiedSyncBlock creation via redo, however, we need to return true here to let transaction through so history can be updated properly.
|
|
355
499
|
// If we simply returns false, creation from redo is blocked as desired, but this results in editor showing redo as possible even though it's not.
|
|
356
500
|
// After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
|
|
@@ -361,36 +505,32 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
361
505
|
}
|
|
362
506
|
showInlineExtensionInSyncBlockWarningIfNeeded(tr, state, api, inlineExtensionFlagShown);
|
|
363
507
|
return true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
508
|
+
}
|
|
509
|
+
const {
|
|
510
|
+
removed: syncBlockRemoved,
|
|
511
|
+
added: syncBlockAdded
|
|
512
|
+
} = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
|
|
513
|
+
let errorFlag = false;
|
|
370
514
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
});
|
|
391
|
-
}, 0);
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
515
|
+
// Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
|
|
516
|
+
if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
|
|
517
|
+
errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
|
|
518
|
+
} else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
|
|
519
|
+
errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
|
|
520
|
+
} else if (hasEditInSyncBlock(tr, state)) {
|
|
521
|
+
errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
|
|
522
|
+
}
|
|
523
|
+
if (errorFlag) {
|
|
524
|
+
deferDispatch(() => {
|
|
525
|
+
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
526
|
+
tr
|
|
527
|
+
}) => tr.setMeta(syncedBlockPluginKey, {
|
|
528
|
+
activeFlag: {
|
|
529
|
+
id: errorFlag
|
|
530
|
+
}
|
|
531
|
+
}));
|
|
532
|
+
});
|
|
533
|
+
return false;
|
|
394
534
|
}
|
|
395
535
|
return true;
|
|
396
536
|
},
|
|
@@ -401,22 +541,23 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
401
541
|
}
|
|
402
542
|
});
|
|
403
543
|
for (const tr of trs) {
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
added
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
544
|
+
if (tr.getMeta(pmHistoryPluginKey)) {
|
|
545
|
+
const {
|
|
546
|
+
added
|
|
547
|
+
} = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, oldState);
|
|
548
|
+
if (added.length > 0) {
|
|
549
|
+
// Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
|
|
550
|
+
// See filterTransaction above for more details
|
|
551
|
+
const {
|
|
552
|
+
tr
|
|
553
|
+
} = newState;
|
|
554
|
+
added.forEach(node => {
|
|
555
|
+
if (node.from !== undefined && node.to !== undefined) {
|
|
556
|
+
tr.delete(node.from, node.to);
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
return tr;
|
|
560
|
+
}
|
|
420
561
|
}
|
|
421
562
|
}
|
|
422
563
|
return null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
2
|
import { FLAG_ID } from '../../types';
|
|
3
3
|
import { syncedBlockPluginKey } from '../main';
|
|
4
|
+
import { deferDispatch } from './utils';
|
|
4
5
|
const onRetry = (api, resourceId) => {
|
|
5
6
|
return () => {
|
|
6
7
|
var _api$core, _api$core2;
|
|
@@ -77,7 +78,7 @@ export const handleBodiedSyncBlockCreation = (bodiedSyncBlockAdded, editorState,
|
|
|
77
78
|
to: node.to
|
|
78
79
|
};
|
|
79
80
|
const resourceId = node.attrs.resourceId;
|
|
80
|
-
|
|
81
|
+
deferDispatch(() => {
|
|
81
82
|
var _api$core3;
|
|
82
83
|
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(({
|
|
83
84
|
tr
|
|
@@ -2,6 +2,19 @@ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
|
|
|
2
2
|
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
3
|
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
4
4
|
import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
|
|
9
|
+
* Used to avoid re-entrant ProseMirror dispatch cycles.
|
|
10
|
+
*/
|
|
11
|
+
export const deferDispatch = fn => {
|
|
12
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
13
|
+
queueMicrotask(fn);
|
|
14
|
+
} else {
|
|
15
|
+
setTimeout(fn, 0);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
5
18
|
export const findSyncBlock = (schema, selection) => {
|
|
6
19
|
const {
|
|
7
20
|
syncBlock
|
|
@@ -5,7 +5,7 @@ import { DOMSerializer, Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
|
5
5
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
import { findSelectedNodeOfType, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
7
7
|
import { syncedBlockPluginKey } from '../pm-plugins/main';
|
|
8
|
-
import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
8
|
+
import { canBeConvertedToSyncBlock, deferDispatch, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
9
9
|
import { FLAG_ID } from '../types';
|
|
10
10
|
import { pasteSyncBlockHTMLContent } from './utils';
|
|
11
11
|
export var createSyncedBlock = function createSyncedBlock(_ref) {
|
|
@@ -147,9 +147,7 @@ var copySyncedBlockReferenceToClipboardInternal = function copySyncedBlockRefere
|
|
|
147
147
|
}
|
|
148
148
|
var domNode = toDOM(referenceSyncBlockNode, schema);
|
|
149
149
|
copyDomNode(domNode, referenceSyncBlockNode.type, selection);
|
|
150
|
-
|
|
151
|
-
// Use setTimeout to dispatch transaction in next tick and avoid re-entrant dispatch
|
|
152
|
-
setTimeout(function () {
|
|
150
|
+
deferDispatch(function () {
|
|
153
151
|
api === null || api === void 0 || api.core.actions.execute(function (_ref3) {
|
|
154
152
|
var _api$analytics4;
|
|
155
153
|
var tr = _ref3.tr;
|
|
@@ -169,7 +167,7 @@ var copySyncedBlockReferenceToClipboardInternal = function copySyncedBlockRefere
|
|
|
169
167
|
}
|
|
170
168
|
});
|
|
171
169
|
});
|
|
172
|
-
}
|
|
170
|
+
});
|
|
173
171
|
return true;
|
|
174
172
|
};
|
|
175
173
|
export var editSyncedBlockSource = function editSyncedBlockSource(syncBlockStore, api) {
|