@atlaskit/editor-plugin-synced-block 4.3.9 → 4.3.11

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 4.3.11
4
+
5
+ ### Patch Changes
6
+
7
+ - [`55920a92e882a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/55920a92e882a) -
8
+ tsignores added for help-center local consumpton removed
9
+ - Updated dependencies
10
+
11
+ ## 4.3.10
12
+
13
+ ### Patch Changes
14
+
15
+ - [`99387f7d6303b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/99387f7d6303b) -
16
+ [ux] [EDITOR-2767] Implement bodiedSyncBlock creation/deletion undo/redo
17
+ - Updated dependencies
18
+
3
19
  ## 4.3.9
4
20
 
5
21
  ### Patch Changes
@@ -7,6 +7,7 @@ exports.syncedBlockPluginKey = exports.createPlugin = void 0;
7
7
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
8
8
  var _selection = require("@atlaskit/editor-common/selection");
9
9
  var _syncBlock = require("@atlaskit/editor-common/sync-block");
10
+ var _utils = require("@atlaskit/editor-common/utils");
10
11
  var _state = require("@atlaskit/editor-prosemirror/state");
11
12
  var _view = require("@atlaskit/editor-prosemirror/view");
12
13
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
@@ -15,7 +16,10 @@ var _lazySyncedBlock = require("../nodeviews/lazySyncedBlock");
15
16
  var _types = require("../types");
16
17
  var _ignoreDomEvent = require("./utils/ignore-dom-event");
17
18
  var _selectionDecorations = require("./utils/selection-decorations");
18
- var _trackSyncBlocks3 = require("./utils/track-sync-blocks");
19
+ var _trackSyncBlocks4 = require("./utils/track-sync-blocks");
20
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
21
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
22
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
19
23
  var syncedBlockPluginKey = exports.syncedBlockPluginKey = new _state.PluginKey('syncedBlockPlugin');
20
24
  var createPlugin = exports.createPlugin = function createPlugin(options, pmPluginFactoryParams, syncBlockStore, api) {
21
25
  var _ref = options || {},
@@ -24,7 +28,6 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
24
28
  return new _safePlugin.SafePlugin({
25
29
  key: syncedBlockPluginKey,
26
30
  state: {
27
- // @ts-ignore - Workaround for help-center local consumption
28
31
  init: function init(_, instance) {
29
32
  var syncBlockNodes = instance.doc.children.filter(function (node) {
30
33
  return node.type.name === 'syncBlock';
@@ -36,7 +39,6 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
36
39
  syncBlockStore: syncBlockStore
37
40
  };
38
41
  },
39
- // @ts-ignore - Workaround for help-center local consumption
40
42
  apply: function apply(tr, currentPluginState, oldEditorState) {
41
43
  var _meta$showFlag;
42
44
  var meta = tr.getMeta(syncedBlockPluginKey);
@@ -66,7 +68,6 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
66
68
  api: api
67
69
  })
68
70
  },
69
- // @ts-ignore - Workaround for help-center local consumption
70
71
  decorations: function decorations(state) {
71
72
  var _syncedBlockPluginKey, _syncedBlockPluginKey2, _api$connectivity, _api$editorViewMode;
72
73
  var selectionDecorationSet = (_syncedBlockPluginKey = (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(state)) === null || _syncedBlockPluginKey2 === void 0 ? void 0 : _syncedBlockPluginKey2.selectionDecorationSet) !== null && _syncedBlockPluginKey !== void 0 ? _syncedBlockPluginKey : _view.DecorationSet.empty;
@@ -75,8 +76,6 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
75
76
  var isViewMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view';
76
77
  var offlineDecorations = [];
77
78
  var viewModeDecorations = [];
78
-
79
- // @ts-ignore - Workaround for help-center local consumption
80
79
  state.doc.descendants(function (node, pos) {
81
80
  if (node.type.name === 'bodiedSyncBlock' && isOffline) {
82
81
  offlineDecorations.push(_view.Decoration.node(pos, pos + node.nodeSize, {
@@ -97,11 +96,9 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
97
96
  useLongPressSelection: useLongPressSelection
98
97
  }),
99
98
  handleDOMEvents: {
100
- // @ts-ignore - Workaround for help-center local consumption
101
99
  mouseover: function mouseover(view, event) {
102
100
  return (0, _ignoreDomEvent.shouldIgnoreDomEvent)(view, event, api);
103
101
  },
104
- // @ts-ignore - Workaround for help-center local consumption
105
102
  mousedown: function mousedown(view, event) {
106
103
  return (0, _ignoreDomEvent.shouldIgnoreDomEvent)(view, event, api);
107
104
  }
@@ -115,7 +112,6 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
115
112
  }
116
113
  };
117
114
  },
118
- // @ts-ignore - Workaround for help-center local consumption
119
115
  filterTransaction: function filterTransaction(tr, state) {
120
116
  var _api$connectivity2;
121
117
  var isOffline = (api === null || api === void 0 || (_api$connectivity2 = api.connectivity) === null || _api$connectivity2 === void 0 || (_api$connectivity2 = _api$connectivity2.sharedState.currentState()) === null || _api$connectivity2 === void 0 ? void 0 : _api$connectivity2.mode) === 'offline';
@@ -127,7 +123,7 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
127
123
  if (!tr.docChanged || !(syncBlockStore !== null && syncBlockStore !== void 0 && syncBlockStore.sourceManager.requireConfirmationBeforeDelete()) && !syncBlockStore.sourceManager.hasPendingCreation() || Boolean(tr.getMeta('isRemote')) || Boolean(tr.getMeta('isCommitSyncBlockCreation')) || !isOffline && isConfirmedSyncBlockDeletion) {
128
124
  return true;
129
125
  }
130
- var _trackSyncBlocks = (0, _trackSyncBlocks3.trackSyncBlocks)(syncBlockStore.sourceManager.isSourceBlock, tr, state),
126
+ var _trackSyncBlocks = (0, _trackSyncBlocks4.trackSyncBlocks)(syncBlockStore.sourceManager.isSourceBlock, tr, state),
131
127
  bodiedSyncBlockRemoved = _trackSyncBlocks.removed,
132
128
  bodiedSyncBlockAdded = _trackSyncBlocks.added;
133
129
  if (!isOffline) {
@@ -136,10 +132,19 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
136
132
  // we block the transaction here, and wait for user confirmation to proceed with deletion.
137
133
  // See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
138
134
  // proceed with deletion.
139
- syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved);
135
+ syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved.map(function (node) {
136
+ return node.attrs;
137
+ }));
140
138
  return false;
141
139
  }
142
140
  if (bodiedSyncBlockAdded.length > 0) {
141
+ if (Boolean(tr.getMeta(_utils.pmHistoryPluginKey))) {
142
+ // 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.
143
+ // 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.
144
+ // After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
145
+ return true;
146
+ }
147
+
143
148
  // If there is bodiedSyncBlock node addition and it's waiting for the result of saving the node to backend (syncBlockStore.hasPendingCreation()),
144
149
  // 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
145
150
  // The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
@@ -153,18 +158,19 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
153
158
  return false;
154
159
  }
155
160
  } else {
156
- // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
157
- var _trackSyncBlocks2 = (0, _trackSyncBlocks3.trackSyncBlocks)(function (node) {
161
+ var _trackSyncBlocks2 = (0, _trackSyncBlocks4.trackSyncBlocks)(function (node) {
158
162
  return node.type.name === 'syncBlock';
159
163
  }, tr, state),
160
164
  syncBlockRemoved = _trackSyncBlocks2.removed,
161
165
  syncBlockAdded = _trackSyncBlocks2.added;
162
166
  var errorFlag = false;
167
+
168
+ // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
163
169
  if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
164
170
  errorFlag = _types.FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
165
171
  } else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
166
172
  errorFlag = _types.FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
167
- } else if ((0, _trackSyncBlocks3.hasEditInSyncBlock)(tr, state)) {
173
+ } else if ((0, _trackSyncBlocks4.hasEditInSyncBlock)(tr, state)) {
168
174
  errorFlag = _types.FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
169
175
  }
170
176
  if (errorFlag) {
@@ -182,17 +188,47 @@ var createPlugin = exports.createPlugin = function createPlugin(options, pmPlugi
182
188
  }
183
189
  return true;
184
190
  },
185
- // @ts-ignore - Workaround for help-center local consumption
186
- appendTransaction: function appendTransaction(trs, _oldState, newState) {
187
- trs
188
- // @ts-ignore - Workaround for help-center local consumption
189
- .filter(function (tr) {
191
+ appendTransaction: function appendTransaction(trs, oldState, newState) {
192
+ trs.filter(function (tr) {
190
193
  return tr.docChanged;
191
- })
192
- // @ts-ignore - Workaround for help-center local consumption
193
- .forEach(function (tr) {
194
+ }).forEach(function (tr) {
194
195
  syncBlockStore === null || syncBlockStore === void 0 || syncBlockStore.sourceManager.rebaseTransaction(tr, newState);
195
196
  });
197
+ var _iterator = _createForOfIteratorHelper(trs),
198
+ _step;
199
+ try {
200
+ var _loop = function _loop() {
201
+ var tr = _step.value;
202
+ if (!tr.getMeta(_utils.pmHistoryPluginKey)) {
203
+ return 0; // continue
204
+ }
205
+ var _trackSyncBlocks3 = (0, _trackSyncBlocks4.trackSyncBlocks)(syncBlockStore.sourceManager.isSourceBlock, tr, oldState),
206
+ added = _trackSyncBlocks3.added;
207
+ if (added.length > 0) {
208
+ // Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
209
+ // See filterTransaction above for more details
210
+ var _tr = newState.tr;
211
+ added.forEach(function (node) {
212
+ if (node.from !== undefined && node.to !== undefined) {
213
+ _tr.delete(node.from, node.to);
214
+ }
215
+ });
216
+ return {
217
+ v: _tr
218
+ };
219
+ }
220
+ },
221
+ _ret;
222
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
223
+ _ret = _loop();
224
+ if (_ret === 0) continue;
225
+ if (_ret) return _ret.v;
226
+ }
227
+ } catch (err) {
228
+ _iterator.e(err);
229
+ } finally {
230
+ _iterator.f();
231
+ }
196
232
  return null;
197
233
  }
198
234
  });
@@ -33,7 +33,7 @@ var trackSyncBlocks = exports.trackSyncBlocks = function trackSyncBlocks(predica
33
33
  step.getMap().forEach(function (oldStart, oldEnd) {
34
34
  if (oldStart !== oldEnd && !hasChange) {
35
35
  var deletedSlice = state.doc.slice(Math.max(0, oldStart), Math.min(state.doc.content.size, oldEnd));
36
- deletedSlice.content.forEach(function (node, _, index) {
36
+ deletedSlice.content.forEach(function (node) {
37
37
  if (hasChange) {
38
38
  return;
39
39
  }
@@ -64,13 +64,19 @@ var trackSyncBlocks = exports.trackSyncBlocks = function trackSyncBlocks(predica
64
64
  oldDoc.content.forEach(function (node) {
65
65
  if (predicate(node)) {
66
66
  var syncBlockAttr = node.attrs;
67
- syncBlockMapOld[syncBlockAttr.localId] = syncBlockAttr;
67
+ syncBlockMapOld[syncBlockAttr.localId] = {
68
+ attrs: syncBlockAttr
69
+ };
68
70
  }
69
71
  });
70
- newDoc.content.forEach(function (node) {
72
+ newDoc.content.forEach(function (node, offset) {
71
73
  if (predicate(node)) {
72
74
  var syncBlockAttr = node.attrs;
73
- syncBlockMapNew[syncBlockAttr.localId] = syncBlockAttr;
75
+ syncBlockMapNew[syncBlockAttr.localId] = {
76
+ attrs: syncBlockAttr,
77
+ from: offset,
78
+ to: offset + node.nodeSize
79
+ };
74
80
  }
75
81
  });
76
82
 
@@ -60,7 +60,8 @@ var DeleteConfirmationModal = exports.DeleteConfirmationModal = function DeleteC
60
60
  };
61
61
  }, [syncBlockStoreManager, confirmationCallback]);
62
62
  return /*#__PURE__*/_react.default.createElement(_modalDialog.ModalTransition, null, isOpen && /*#__PURE__*/_react.default.createElement(_modalDialog.default, {
63
- onClose: handleClose(false)
63
+ onClose: handleClose(false),
64
+ testId: "sync-block-delete-confirmation"
64
65
  }, /*#__PURE__*/_react.default.createElement(_modalDialog.ModalHeader, {
65
66
  hasCloseButton: true
66
67
  }, /*#__PURE__*/_react.default.createElement(_modalDialog.ModalTitle, {
@@ -1,6 +1,7 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
3
3
  import { BodiedSyncBlockSharedCssClassName, SyncBlockStateCssClassName } from '@atlaskit/editor-common/sync-block';
4
+ import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
4
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
6
  import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
6
7
  import { convertPMNodesToSyncBlockNodes } from '@atlaskit/editor-synced-block-provider';
@@ -18,7 +19,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
18
19
  return new SafePlugin({
19
20
  key: syncedBlockPluginKey,
20
21
  state: {
21
- // @ts-ignore - Workaround for help-center local consumption
22
22
  init(_, instance) {
23
23
  const syncBlockNodes = instance.doc.children.filter(node => node.type.name === 'syncBlock');
24
24
  syncBlockStore.referenceManager.fetchSyncBlocksData(convertPMNodesToSyncBlockNodes(syncBlockNodes));
@@ -28,7 +28,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
28
28
  syncBlockStore: syncBlockStore
29
29
  };
30
30
  },
31
- // @ts-ignore - Workaround for help-center local consumption
32
31
  apply: (tr, currentPluginState, oldEditorState) => {
33
32
  var _meta$showFlag;
34
33
  const meta = tr.getMeta(syncedBlockPluginKey);
@@ -60,7 +59,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
60
59
  api
61
60
  })
62
61
  },
63
- // @ts-ignore - Workaround for help-center local consumption
64
62
  decorations: state => {
65
63
  var _syncedBlockPluginKey, _syncedBlockPluginKey2, _api$connectivity, _api$connectivity$sha, _api$editorViewMode, _api$editorViewMode$s;
66
64
  const selectionDecorationSet = (_syncedBlockPluginKey = (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(state)) === null || _syncedBlockPluginKey2 === void 0 ? void 0 : _syncedBlockPluginKey2.selectionDecorationSet) !== null && _syncedBlockPluginKey !== void 0 ? _syncedBlockPluginKey : DecorationSet.empty;
@@ -71,8 +69,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
71
69
  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';
72
70
  const offlineDecorations = [];
73
71
  const viewModeDecorations = [];
74
-
75
- // @ts-ignore - Workaround for help-center local consumption
76
72
  state.doc.descendants((node, pos) => {
77
73
  if (node.type.name === 'bodiedSyncBlock' && isOffline) {
78
74
  offlineDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
@@ -91,11 +87,9 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
91
87
  useLongPressSelection
92
88
  }),
93
89
  handleDOMEvents: {
94
- // @ts-ignore - Workaround for help-center local consumption
95
90
  mouseover(view, event) {
96
91
  return shouldIgnoreDomEvent(view, event, api);
97
92
  },
98
- // @ts-ignore - Workaround for help-center local consumption
99
93
  mousedown(view, event) {
100
94
  return shouldIgnoreDomEvent(view, event, api);
101
95
  }
@@ -109,7 +103,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
109
103
  }
110
104
  };
111
105
  },
112
- // @ts-ignore - Workaround for help-center local consumption
113
106
  filterTransaction: (tr, state) => {
114
107
  var _api$connectivity2, _api$connectivity2$sh;
115
108
  const isOffline = (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) === 'offline';
@@ -131,10 +124,17 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
131
124
  // we block the transaction here, and wait for user confirmation to proceed with deletion.
132
125
  // See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
133
126
  // proceed with deletion.
134
- syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved);
127
+ syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved.map(node => node.attrs));
135
128
  return false;
136
129
  }
137
130
  if (bodiedSyncBlockAdded.length > 0) {
131
+ if (Boolean(tr.getMeta(pmHistoryPluginKey))) {
132
+ // 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.
133
+ // 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.
134
+ // After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
135
+ return true;
136
+ }
137
+
138
138
  // If there is bodiedSyncBlock node addition and it's waiting for the result of saving the node to backend (syncBlockStore.hasPendingCreation()),
139
139
  // 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
140
140
  // The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
@@ -148,12 +148,13 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
148
148
  return false;
149
149
  }
150
150
  } else {
151
- // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
152
151
  const {
153
152
  removed: syncBlockRemoved,
154
153
  added: syncBlockAdded
155
154
  } = trackSyncBlocks(node => node.type.name === 'syncBlock', tr, state);
156
155
  let errorFlag = false;
156
+
157
+ // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
157
158
  if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
158
159
  errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
159
160
  } else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
@@ -177,15 +178,29 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
177
178
  }
178
179
  return true;
179
180
  },
180
- // @ts-ignore - Workaround for help-center local consumption
181
- appendTransaction: (trs, _oldState, newState) => {
182
- trs
183
- // @ts-ignore - Workaround for help-center local consumption
184
- .filter(tr => tr.docChanged)
185
- // @ts-ignore - Workaround for help-center local consumption
186
- .forEach(tr => {
181
+ appendTransaction: (trs, oldState, newState) => {
182
+ trs.filter(tr => tr.docChanged).forEach(tr => {
187
183
  syncBlockStore === null || syncBlockStore === void 0 ? void 0 : syncBlockStore.sourceManager.rebaseTransaction(tr, newState);
188
184
  });
185
+ for (const tr of trs) {
186
+ if (!tr.getMeta(pmHistoryPluginKey)) {
187
+ continue;
188
+ }
189
+ const {
190
+ added
191
+ } = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, oldState);
192
+ if (added.length > 0) {
193
+ // Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
194
+ // See filterTransaction above for more details
195
+ const tr = newState.tr;
196
+ added.forEach(node => {
197
+ if (node.from !== undefined && node.to !== undefined) {
198
+ tr.delete(node.from, node.to);
199
+ }
200
+ });
201
+ return tr;
202
+ }
203
+ }
189
204
  return null;
190
205
  }
191
206
  });
@@ -24,7 +24,7 @@ export const trackSyncBlocks = (predicate, tr, state) => {
24
24
  step.getMap().forEach((oldStart, oldEnd) => {
25
25
  if (oldStart !== oldEnd && !hasChange) {
26
26
  const deletedSlice = state.doc.slice(Math.max(0, oldStart), Math.min(state.doc.content.size, oldEnd));
27
- deletedSlice.content.forEach((node, _, index) => {
27
+ deletedSlice.content.forEach(node => {
28
28
  if (hasChange) {
29
29
  return;
30
30
  }
@@ -55,13 +55,19 @@ export const trackSyncBlocks = (predicate, tr, state) => {
55
55
  oldDoc.content.forEach(node => {
56
56
  if (predicate(node)) {
57
57
  const syncBlockAttr = node.attrs;
58
- syncBlockMapOld[syncBlockAttr.localId] = syncBlockAttr;
58
+ syncBlockMapOld[syncBlockAttr.localId] = {
59
+ attrs: syncBlockAttr
60
+ };
59
61
  }
60
62
  });
61
- newDoc.content.forEach(node => {
63
+ newDoc.content.forEach((node, offset) => {
62
64
  if (predicate(node)) {
63
65
  const syncBlockAttr = node.attrs;
64
- syncBlockMapNew[syncBlockAttr.localId] = syncBlockAttr;
66
+ syncBlockMapNew[syncBlockAttr.localId] = {
67
+ attrs: syncBlockAttr,
68
+ from: offset,
69
+ to: offset + node.nodeSize
70
+ };
65
71
  }
66
72
  });
67
73
 
@@ -45,7 +45,8 @@ export const DeleteConfirmationModal = ({
45
45
  };
46
46
  }, [syncBlockStoreManager, confirmationCallback]);
47
47
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
48
- onClose: handleClose(false)
48
+ onClose: handleClose(false),
49
+ testId: "sync-block-delete-confirmation"
49
50
  }, /*#__PURE__*/React.createElement(ModalHeader, {
50
51
  hasCloseButton: true
51
52
  }, /*#__PURE__*/React.createElement(ModalTitle, {
@@ -1,6 +1,10 @@
1
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1
4
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
5
  import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
3
6
  import { BodiedSyncBlockSharedCssClassName, SyncBlockStateCssClassName } from '@atlaskit/editor-common/sync-block';
7
+ import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
4
8
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
9
  import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
6
10
  import { convertPMNodesToSyncBlockNodes } from '@atlaskit/editor-synced-block-provider';
@@ -18,7 +22,6 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
18
22
  return new SafePlugin({
19
23
  key: syncedBlockPluginKey,
20
24
  state: {
21
- // @ts-ignore - Workaround for help-center local consumption
22
25
  init: function init(_, instance) {
23
26
  var syncBlockNodes = instance.doc.children.filter(function (node) {
24
27
  return node.type.name === 'syncBlock';
@@ -30,7 +33,6 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
30
33
  syncBlockStore: syncBlockStore
31
34
  };
32
35
  },
33
- // @ts-ignore - Workaround for help-center local consumption
34
36
  apply: function apply(tr, currentPluginState, oldEditorState) {
35
37
  var _meta$showFlag;
36
38
  var meta = tr.getMeta(syncedBlockPluginKey);
@@ -60,7 +62,6 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
60
62
  api: api
61
63
  })
62
64
  },
63
- // @ts-ignore - Workaround for help-center local consumption
64
65
  decorations: function decorations(state) {
65
66
  var _syncedBlockPluginKey, _syncedBlockPluginKey2, _api$connectivity, _api$editorViewMode;
66
67
  var selectionDecorationSet = (_syncedBlockPluginKey = (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(state)) === null || _syncedBlockPluginKey2 === void 0 ? void 0 : _syncedBlockPluginKey2.selectionDecorationSet) !== null && _syncedBlockPluginKey !== void 0 ? _syncedBlockPluginKey : DecorationSet.empty;
@@ -69,8 +70,6 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
69
70
  var isViewMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view';
70
71
  var offlineDecorations = [];
71
72
  var viewModeDecorations = [];
72
-
73
- // @ts-ignore - Workaround for help-center local consumption
74
73
  state.doc.descendants(function (node, pos) {
75
74
  if (node.type.name === 'bodiedSyncBlock' && isOffline) {
76
75
  offlineDecorations.push(Decoration.node(pos, pos + node.nodeSize, {
@@ -91,11 +90,9 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
91
90
  useLongPressSelection: useLongPressSelection
92
91
  }),
93
92
  handleDOMEvents: {
94
- // @ts-ignore - Workaround for help-center local consumption
95
93
  mouseover: function mouseover(view, event) {
96
94
  return shouldIgnoreDomEvent(view, event, api);
97
95
  },
98
- // @ts-ignore - Workaround for help-center local consumption
99
96
  mousedown: function mousedown(view, event) {
100
97
  return shouldIgnoreDomEvent(view, event, api);
101
98
  }
@@ -109,7 +106,6 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
109
106
  }
110
107
  };
111
108
  },
112
- // @ts-ignore - Workaround for help-center local consumption
113
109
  filterTransaction: function filterTransaction(tr, state) {
114
110
  var _api$connectivity2;
115
111
  var isOffline = (api === null || api === void 0 || (_api$connectivity2 = api.connectivity) === null || _api$connectivity2 === void 0 || (_api$connectivity2 = _api$connectivity2.sharedState.currentState()) === null || _api$connectivity2 === void 0 ? void 0 : _api$connectivity2.mode) === 'offline';
@@ -130,10 +126,19 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
130
126
  // we block the transaction here, and wait for user confirmation to proceed with deletion.
131
127
  // See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
132
128
  // proceed with deletion.
133
- syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved);
129
+ syncBlockStore.sourceManager.deleteSyncBlocksWithConfirmation(tr, bodiedSyncBlockRemoved.map(function (node) {
130
+ return node.attrs;
131
+ }));
134
132
  return false;
135
133
  }
136
134
  if (bodiedSyncBlockAdded.length > 0) {
135
+ if (Boolean(tr.getMeta(pmHistoryPluginKey))) {
136
+ // 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.
137
+ // 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.
138
+ // After true is returned here and the node is created, we delete the node in the filterTransaction immediately, which cancels out the creation
139
+ return true;
140
+ }
141
+
137
142
  // If there is bodiedSyncBlock node addition and it's waiting for the result of saving the node to backend (syncBlockStore.hasPendingCreation()),
138
143
  // 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
139
144
  // The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
@@ -147,13 +152,14 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
147
152
  return false;
148
153
  }
149
154
  } else {
150
- // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
151
155
  var _trackSyncBlocks2 = trackSyncBlocks(function (node) {
152
156
  return node.type.name === 'syncBlock';
153
157
  }, tr, state),
154
158
  syncBlockRemoved = _trackSyncBlocks2.removed,
155
159
  syncBlockAdded = _trackSyncBlocks2.added;
156
160
  var errorFlag = false;
161
+
162
+ // Disable (bodied)syncBlock node deletion/creation/edition in offline mode and trigger an error flag instead
157
163
  if (isConfirmedSyncBlockDeletion || bodiedSyncBlockRemoved.length > 0 || syncBlockRemoved.length > 0) {
158
164
  errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
159
165
  } else if (bodiedSyncBlockAdded.length > 0 || syncBlockAdded.length > 0) {
@@ -176,17 +182,47 @@ export var createPlugin = function createPlugin(options, pmPluginFactoryParams,
176
182
  }
177
183
  return true;
178
184
  },
179
- // @ts-ignore - Workaround for help-center local consumption
180
- appendTransaction: function appendTransaction(trs, _oldState, newState) {
181
- trs
182
- // @ts-ignore - Workaround for help-center local consumption
183
- .filter(function (tr) {
185
+ appendTransaction: function appendTransaction(trs, oldState, newState) {
186
+ trs.filter(function (tr) {
184
187
  return tr.docChanged;
185
- })
186
- // @ts-ignore - Workaround for help-center local consumption
187
- .forEach(function (tr) {
188
+ }).forEach(function (tr) {
188
189
  syncBlockStore === null || syncBlockStore === void 0 || syncBlockStore.sourceManager.rebaseTransaction(tr, newState);
189
190
  });
191
+ var _iterator = _createForOfIteratorHelper(trs),
192
+ _step;
193
+ try {
194
+ var _loop = function _loop() {
195
+ var tr = _step.value;
196
+ if (!tr.getMeta(pmHistoryPluginKey)) {
197
+ return 0; // continue
198
+ }
199
+ var _trackSyncBlocks3 = trackSyncBlocks(syncBlockStore.sourceManager.isSourceBlock, tr, oldState),
200
+ added = _trackSyncBlocks3.added;
201
+ if (added.length > 0) {
202
+ // Delete bodiedSyncBlock if it's originated from history, i.e. redo creation
203
+ // See filterTransaction above for more details
204
+ var _tr = newState.tr;
205
+ added.forEach(function (node) {
206
+ if (node.from !== undefined && node.to !== undefined) {
207
+ _tr.delete(node.from, node.to);
208
+ }
209
+ });
210
+ return {
211
+ v: _tr
212
+ };
213
+ }
214
+ },
215
+ _ret;
216
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
217
+ _ret = _loop();
218
+ if (_ret === 0) continue;
219
+ if (_ret) return _ret.v;
220
+ }
221
+ } catch (err) {
222
+ _iterator.e(err);
223
+ } finally {
224
+ _iterator.f();
225
+ }
190
226
  return null;
191
227
  }
192
228
  });
@@ -27,7 +27,7 @@ export var trackSyncBlocks = function trackSyncBlocks(predicate, tr, state) {
27
27
  step.getMap().forEach(function (oldStart, oldEnd) {
28
28
  if (oldStart !== oldEnd && !hasChange) {
29
29
  var deletedSlice = state.doc.slice(Math.max(0, oldStart), Math.min(state.doc.content.size, oldEnd));
30
- deletedSlice.content.forEach(function (node, _, index) {
30
+ deletedSlice.content.forEach(function (node) {
31
31
  if (hasChange) {
32
32
  return;
33
33
  }
@@ -58,13 +58,19 @@ export var trackSyncBlocks = function trackSyncBlocks(predicate, tr, state) {
58
58
  oldDoc.content.forEach(function (node) {
59
59
  if (predicate(node)) {
60
60
  var syncBlockAttr = node.attrs;
61
- syncBlockMapOld[syncBlockAttr.localId] = syncBlockAttr;
61
+ syncBlockMapOld[syncBlockAttr.localId] = {
62
+ attrs: syncBlockAttr
63
+ };
62
64
  }
63
65
  });
64
- newDoc.content.forEach(function (node) {
66
+ newDoc.content.forEach(function (node, offset) {
65
67
  if (predicate(node)) {
66
68
  var syncBlockAttr = node.attrs;
67
- syncBlockMapNew[syncBlockAttr.localId] = syncBlockAttr;
69
+ syncBlockMapNew[syncBlockAttr.localId] = {
70
+ attrs: syncBlockAttr,
71
+ from: offset,
72
+ to: offset + node.nodeSize
73
+ };
68
74
  }
69
75
  });
70
76
 
@@ -51,7 +51,8 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
51
51
  };
52
52
  }, [syncBlockStoreManager, confirmationCallback]);
53
53
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
54
- onClose: handleClose(false)
54
+ onClose: handleClose(false),
55
+ testId: "sync-block-delete-confirmation"
55
56
  }, /*#__PURE__*/React.createElement(ModalHeader, {
56
57
  hasCloseButton: true
57
58
  }, /*#__PURE__*/React.createElement(ModalTitle, {
@@ -2,8 +2,16 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
3
3
  import type { SyncBlockAttrs } from '../../syncedBlockPluginType';
4
4
  export declare const trackSyncBlocks: (predicate: (node: PMNode) => boolean, tr: Transaction, state: EditorState) => {
5
- removed: SyncBlockAttrs[];
6
- added: SyncBlockAttrs[];
5
+ removed: {
6
+ attrs: SyncBlockAttrs;
7
+ from?: number;
8
+ to?: number;
9
+ }[];
10
+ added: {
11
+ attrs: SyncBlockAttrs;
12
+ from?: number;
13
+ to?: number;
14
+ }[];
7
15
  };
8
16
  /**
9
17
  *
@@ -2,8 +2,16 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
2
  import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
3
3
  import type { SyncBlockAttrs } from '../../syncedBlockPluginType';
4
4
  export declare const trackSyncBlocks: (predicate: (node: PMNode) => boolean, tr: Transaction, state: EditorState) => {
5
- removed: SyncBlockAttrs[];
6
- added: SyncBlockAttrs[];
5
+ removed: {
6
+ attrs: SyncBlockAttrs;
7
+ from?: number;
8
+ to?: number;
9
+ }[];
10
+ added: {
11
+ attrs: SyncBlockAttrs;
12
+ from?: number;
13
+ to?: number;
14
+ }[];
7
15
  };
8
16
  /**
9
17
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "4.3.9",
3
+ "version": "4.3.11",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -32,7 +32,7 @@
32
32
  "@atlaskit/button": "23.6.3",
33
33
  "@atlaskit/editor-json-transformer": "^8.31.0",
34
34
  "@atlaskit/editor-plugin-analytics": "^6.2.0",
35
- "@atlaskit/editor-plugin-block-menu": "^5.0.0",
35
+ "@atlaskit/editor-plugin-block-menu": "^5.1.0",
36
36
  "@atlaskit/editor-plugin-connectivity": "6.0.0",
37
37
  "@atlaskit/editor-plugin-decorations": "^6.1.0",
38
38
  "@atlaskit/editor-plugin-floating-toolbar": "^8.2.0",