@atlaskit/editor-plugin-synced-block 4.2.7 → 4.2.8
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/afm-cc/tsconfig.json +9 -0
- package/afm-jira/tsconfig.json +1 -1
- package/dist/cjs/nodeviews/bodiedSyncedBlock.js +27 -5
- package/dist/cjs/pm-plugins/main.js +83 -39
- package/dist/cjs/pm-plugins/utils/ignore-dom-event.js +30 -0
- package/dist/cjs/pm-plugins/utils/track-sync-blocks.js +49 -1
- package/dist/cjs/syncedBlockPlugin.js +16 -1
- package/dist/cjs/types/index.js +12 -0
- package/dist/cjs/ui/CreateSyncedBlockButton.js +10 -5
- package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +13 -11
- package/dist/cjs/ui/CreateSyncedBlockItem.js +17 -15
- package/dist/cjs/ui/DeleteConfirmationModal.js +12 -2
- package/dist/cjs/ui/Flag.js +67 -0
- package/dist/cjs/ui/floating-toolbar.js +3 -2
- package/dist/es2019/nodeviews/bodiedSyncedBlock.js +18 -0
- package/dist/es2019/pm-plugins/main.js +89 -40
- package/dist/es2019/pm-plugins/utils/ignore-dom-event.js +26 -0
- package/dist/es2019/pm-plugins/utils/track-sync-blocks.js +41 -0
- package/dist/es2019/syncedBlockPlugin.js +18 -2
- package/dist/es2019/types/index.js +6 -0
- package/dist/es2019/ui/CreateSyncedBlockButton.js +10 -4
- package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +13 -11
- package/dist/es2019/ui/CreateSyncedBlockItem.js +18 -14
- package/dist/es2019/ui/DeleteConfirmationModal.js +13 -2
- package/dist/es2019/ui/Flag.js +66 -0
- package/dist/es2019/ui/floating-toolbar.js +3 -2
- package/dist/esm/nodeviews/bodiedSyncedBlock.js +27 -5
- package/dist/esm/pm-plugins/main.js +85 -41
- package/dist/esm/pm-plugins/utils/ignore-dom-event.js +24 -0
- package/dist/esm/pm-plugins/utils/track-sync-blocks.js +48 -0
- package/dist/esm/syncedBlockPlugin.js +17 -2
- package/dist/esm/types/index.js +6 -0
- package/dist/esm/ui/CreateSyncedBlockButton.js +10 -5
- package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +13 -11
- package/dist/esm/ui/CreateSyncedBlockItem.js +17 -15
- package/dist/esm/ui/DeleteConfirmationModal.js +12 -2
- package/dist/esm/ui/Flag.js +58 -0
- package/dist/esm/ui/floating-toolbar.js +3 -2
- package/dist/types/nodeviews/bodiedSyncedBlock.d.ts +1 -1
- package/dist/types/pm-plugins/main.d.ts +4 -2
- package/dist/types/pm-plugins/utils/ignore-dom-event.d.ts +8 -0
- package/dist/types/pm-plugins/utils/track-sync-blocks.d.ts +5 -0
- package/dist/types/syncedBlockPluginType.d.ts +5 -1
- package/dist/types/types/index.d.ts +11 -0
- package/dist/types/ui/DeleteConfirmationModal.d.ts +4 -1
- package/dist/types/ui/Flag.d.ts +8 -0
- package/dist/types-ts4.5/nodeviews/bodiedSyncedBlock.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/main.d.ts +4 -2
- package/dist/types-ts4.5/pm-plugins/utils/ignore-dom-event.d.ts +8 -0
- package/dist/types-ts4.5/pm-plugins/utils/track-sync-blocks.d.ts +5 -0
- package/dist/types-ts4.5/syncedBlockPluginType.d.ts +5 -1
- package/dist/types-ts4.5/types/index.d.ts +11 -0
- package/dist/types-ts4.5/ui/DeleteConfirmationModal.d.ts +4 -1
- package/dist/types-ts4.5/ui/Flag.d.ts +8 -0
- package/package.json +6 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.Flag = void 0;
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
var _react = _interopRequireDefault(require("react"));
|
|
11
|
+
var _reactIntlNext = require("react-intl-next");
|
|
12
|
+
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
13
|
+
var _messages = require("@atlaskit/editor-common/messages");
|
|
14
|
+
var _flag = _interopRequireWildcard(require("@atlaskit/flag"));
|
|
15
|
+
var _statusError = _interopRequireDefault(require("@atlaskit/icon/core/status-error"));
|
|
16
|
+
var _main = require("../pm-plugins/main");
|
|
17
|
+
var _types = require("../types");
|
|
18
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
19
|
+
var flagMap = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, _types.FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE, {
|
|
20
|
+
title: _messages.syncBlockMessages.failToDeleteTitle,
|
|
21
|
+
description: _messages.syncBlockMessages.failToDeleteWhenOfflineDescription
|
|
22
|
+
}), _types.FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE, {
|
|
23
|
+
title: _messages.syncBlockMessages.failToEditTitle,
|
|
24
|
+
description: _messages.syncBlockMessages.failToEditWhenOfflineDescription
|
|
25
|
+
}), _types.FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE, {
|
|
26
|
+
title: _messages.syncBlockMessages.failToCreateTitle,
|
|
27
|
+
description: _messages.syncBlockMessages.failToCreateWhenOfflineDescription
|
|
28
|
+
});
|
|
29
|
+
var Flag = exports.Flag = function Flag(_ref) {
|
|
30
|
+
var api = _ref.api;
|
|
31
|
+
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['syncedBlock'], function (states) {
|
|
32
|
+
var _states$syncedBlockSt;
|
|
33
|
+
return {
|
|
34
|
+
showFlag: (_states$syncedBlockSt = states.syncedBlockState) === null || _states$syncedBlockSt === void 0 ? void 0 : _states$syncedBlockSt.showFlag
|
|
35
|
+
};
|
|
36
|
+
}),
|
|
37
|
+
showFlag = _useSharedPluginState.showFlag;
|
|
38
|
+
var _useIntl = (0, _reactIntlNext.useIntl)(),
|
|
39
|
+
formatMessage = _useIntl.formatMessage;
|
|
40
|
+
if (!showFlag) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
var _flagMap$showFlag = flagMap[showFlag],
|
|
44
|
+
title = _flagMap$showFlag.title,
|
|
45
|
+
description = _flagMap$showFlag.description;
|
|
46
|
+
var onDismissed = function onDismissed() {
|
|
47
|
+
api === null || api === void 0 || api.core.actions.execute(function (_ref2) {
|
|
48
|
+
var tr = _ref2.tr;
|
|
49
|
+
tr.setMeta(_main.syncedBlockPluginKey, {
|
|
50
|
+
showFlag: false
|
|
51
|
+
});
|
|
52
|
+
return tr;
|
|
53
|
+
});
|
|
54
|
+
api === null || api === void 0 || api.core.actions.focus();
|
|
55
|
+
};
|
|
56
|
+
return /*#__PURE__*/_react.default.createElement(_flag.FlagGroup, null, /*#__PURE__*/_react.default.createElement(_flag.default, {
|
|
57
|
+
onDismissed: onDismissed,
|
|
58
|
+
title: formatMessage(title),
|
|
59
|
+
description: formatMessage(description),
|
|
60
|
+
id: showFlag,
|
|
61
|
+
testId: showFlag,
|
|
62
|
+
icon: /*#__PURE__*/_react.default.createElement(_statusError.default, {
|
|
63
|
+
label: "",
|
|
64
|
+
color: "var(--ds-icon-danger, #C9372C)"
|
|
65
|
+
})
|
|
66
|
+
}));
|
|
67
|
+
};
|
|
@@ -20,7 +20,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
20
20
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
21
21
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
22
22
|
var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(state, intl, api, syncBlockStore) {
|
|
23
|
-
var _api$decorations;
|
|
23
|
+
var _api$decorations, _api$connectivity;
|
|
24
24
|
var syncBlockObject = (0, _utils2.findSyncBlockOrBodiedSyncBlock)(state.schema, state.selection);
|
|
25
25
|
if (!syncBlockObject) {
|
|
26
26
|
return;
|
|
@@ -92,6 +92,7 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(stat
|
|
|
92
92
|
nodeType: nodeType,
|
|
93
93
|
items: items,
|
|
94
94
|
scrollable: true,
|
|
95
|
-
groupLabel: formatMessage(_messages.syncBlockMessages.syncBlockGroup)
|
|
95
|
+
groupLabel: formatMessage(_messages.syncBlockMessages.syncBlockGroup),
|
|
96
|
+
visible: (api === null || api === void 0 || (_api$connectivity = api.connectivity) === null || _api$connectivity === void 0 || (_api$connectivity = _api$connectivity.sharedState.currentState()) === null || _api$connectivity === void 0 ? void 0 : _api$connectivity.mode) !== 'offline'
|
|
96
97
|
};
|
|
97
98
|
};
|
|
@@ -11,6 +11,19 @@ class BodiedSyncBlock extends ReactNodeView {
|
|
|
11
11
|
constructor(props) {
|
|
12
12
|
super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
|
|
13
13
|
this.syncBlockStore = props.syncBlockStore;
|
|
14
|
+
this.api = props.api;
|
|
15
|
+
this.handleConnectivityModeChange();
|
|
16
|
+
}
|
|
17
|
+
handleConnectivityModeChange() {
|
|
18
|
+
var _this$api;
|
|
19
|
+
if ((_this$api = this.api) !== null && _this$api !== void 0 && _this$api.connectivity) {
|
|
20
|
+
this.cleanupConnectivityModeListener = this.api.connectivity.sharedState.onChange(({
|
|
21
|
+
nextSharedState
|
|
22
|
+
}) => {
|
|
23
|
+
var _this$contentDOM;
|
|
24
|
+
(_this$contentDOM = this.contentDOM) === null || _this$contentDOM === void 0 ? void 0 : _this$contentDOM.setAttribute('contenteditable', nextSharedState.mode === 'online' ? 'true' : 'false');
|
|
25
|
+
});
|
|
26
|
+
}
|
|
14
27
|
}
|
|
15
28
|
createDomRef() {
|
|
16
29
|
const domRef = document.createElement('div');
|
|
@@ -37,6 +50,11 @@ class BodiedSyncBlock extends ReactNodeView {
|
|
|
37
50
|
}
|
|
38
51
|
return undefined;
|
|
39
52
|
}
|
|
53
|
+
destroy() {
|
|
54
|
+
if (this.cleanupConnectivityModeListener) {
|
|
55
|
+
this.cleanupConnectivityModeListener();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
40
58
|
}
|
|
41
59
|
export const bodiedSyncBlockNodeView = ({
|
|
42
60
|
pluginOptions,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
|
|
3
|
-
import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
|
|
3
|
+
import { BodiedSyncBlockSharedCssClassName, SyncBlockStateCssClassName } from '@atlaskit/editor-common/sync-block';
|
|
4
4
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { DecorationSet, Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
5
6
|
import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
|
|
6
7
|
import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
|
|
8
|
+
import { FLAG_ID } from '../types';
|
|
9
|
+
import { shouldIgnoreDomEvent } from './utils/ignore-dom-event';
|
|
7
10
|
import { calculateDecorations } from './utils/selection-decorations';
|
|
8
|
-
import { trackSyncBlocks } from './utils/track-sync-blocks';
|
|
11
|
+
import { hasEditInSyncBlock, trackSyncBlocks } from './utils/track-sync-blocks';
|
|
9
12
|
export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
10
13
|
export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api) => {
|
|
11
14
|
const {
|
|
@@ -18,27 +21,25 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
18
21
|
const syncBlockNodes = instance.doc.children.filter(node => node.type.name === 'syncBlock');
|
|
19
22
|
syncBlockStore.fetchSyncBlocksData(syncBlockNodes);
|
|
20
23
|
return {
|
|
21
|
-
|
|
24
|
+
selectionDecorationSet: calculateDecorations(instance.doc, instance.selection, instance.schema),
|
|
25
|
+
showFlag: false
|
|
22
26
|
};
|
|
23
27
|
},
|
|
24
28
|
apply: (tr, currentPluginState, oldEditorState) => {
|
|
29
|
+
var _meta$showFlag;
|
|
25
30
|
const meta = tr.getMeta(syncedBlockPluginKey);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
const {
|
|
32
|
+
showFlag,
|
|
33
|
+
selectionDecorationSet
|
|
34
|
+
} = currentPluginState;
|
|
35
|
+
let newDecorationSet = selectionDecorationSet.map(tr.mapping, tr.doc);
|
|
30
36
|
if (!tr.selection.eq(oldEditorState.selection)) {
|
|
31
|
-
|
|
32
|
-
...newState,
|
|
33
|
-
decorationSet: calculateDecorations(tr.doc, tr.selection, tr.doc.type.schema)
|
|
34
|
-
};
|
|
35
|
-
} else if (newState.decorationSet) {
|
|
36
|
-
newState = {
|
|
37
|
-
...newState,
|
|
38
|
-
decorationSet: newState.decorationSet.map(tr.mapping, tr.doc)
|
|
39
|
-
};
|
|
37
|
+
newDecorationSet = calculateDecorations(tr.doc, tr.selection, tr.doc.type.schema);
|
|
40
38
|
}
|
|
41
|
-
return
|
|
39
|
+
return {
|
|
40
|
+
showFlag: (_meta$showFlag = meta === null || meta === void 0 ? void 0 : meta.showFlag) !== null && _meta$showFlag !== void 0 ? _meta$showFlag : showFlag,
|
|
41
|
+
selectionDecorationSet: newDecorationSet
|
|
42
|
+
};
|
|
42
43
|
}
|
|
43
44
|
},
|
|
44
45
|
props: {
|
|
@@ -57,12 +58,34 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
57
58
|
})
|
|
58
59
|
},
|
|
59
60
|
decorations: state => {
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
var _syncedBlockPluginKey, _syncedBlockPluginKey2, _api$connectivity, _api$connectivity$sha;
|
|
62
|
+
const selectionDecorationSet = (_syncedBlockPluginKey = (_syncedBlockPluginKey2 = syncedBlockPluginKey.getState(state)) === null || _syncedBlockPluginKey2 === void 0 ? void 0 : _syncedBlockPluginKey2.selectionDecorationSet) !== null && _syncedBlockPluginKey !== void 0 ? _syncedBlockPluginKey : DecorationSet.empty;
|
|
63
|
+
const {
|
|
64
|
+
doc
|
|
65
|
+
} = state;
|
|
66
|
+
const decorations = [];
|
|
67
|
+
if ((api === null || api === void 0 ? void 0 : (_api$connectivity = api.connectivity) === null || _api$connectivity === void 0 ? void 0 : (_api$connectivity$sha = _api$connectivity.sharedState.currentState()) === null || _api$connectivity$sha === void 0 ? void 0 : _api$connectivity$sha.mode) === 'offline') {
|
|
68
|
+
state.doc.descendants((node, pos) => {
|
|
69
|
+
if (node.type.name === 'bodiedSyncBlock') {
|
|
70
|
+
decorations.push(Decoration.node(pos, pos + node.nodeSize, {
|
|
71
|
+
class: SyncBlockStateCssClassName.disabledClassName
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return selectionDecorationSet.add(doc, decorations);
|
|
62
77
|
},
|
|
63
78
|
handleClickOn: createSelectionClickHandler(['bodiedSyncBlock'], target => !!target.closest(`.${BodiedSyncBlockSharedCssClassName.prefix}`), {
|
|
64
79
|
useLongPressSelection
|
|
65
|
-
})
|
|
80
|
+
}),
|
|
81
|
+
handleDOMEvents: {
|
|
82
|
+
mouseover(view, event) {
|
|
83
|
+
return shouldIgnoreDomEvent(view, event, api);
|
|
84
|
+
},
|
|
85
|
+
mousedown(view, event) {
|
|
86
|
+
return shouldIgnoreDomEvent(view, event, api);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
66
89
|
},
|
|
67
90
|
view: editorView => {
|
|
68
91
|
syncBlockStore.setEditorView(editorView);
|
|
@@ -73,37 +96,63 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
|
|
|
73
96
|
};
|
|
74
97
|
},
|
|
75
98
|
filterTransaction: (tr, state) => {
|
|
99
|
+
var _api$connectivity2, _api$connectivity2$sh;
|
|
100
|
+
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';
|
|
101
|
+
const isConfirmedSyncBlockDeletion = Boolean(tr.getMeta('isConfirmedSyncBlockDeletion'));
|
|
76
102
|
// Ignore transactions that don't change the document
|
|
77
103
|
// or are from remote (collab) or already confirmed sync block deletion
|
|
78
104
|
// We only care about local changes that change the document
|
|
79
105
|
// and are not yet confirmed for sync block deletion
|
|
80
|
-
if (!tr.docChanged || !(syncBlockStore !== null && syncBlockStore !== void 0 && syncBlockStore.requireConfirmationBeforeDelete()) && !syncBlockStore.hasPendingCreation() || Boolean(tr.getMeta('isRemote')) || Boolean(tr.getMeta('
|
|
106
|
+
if (!tr.docChanged || !(syncBlockStore !== null && syncBlockStore !== void 0 && syncBlockStore.requireConfirmationBeforeDelete()) && !syncBlockStore.hasPendingCreation() || Boolean(tr.getMeta('isRemote')) || Boolean(tr.getMeta('isCommitSyncBlockCreation')) || !isOffline && isConfirmedSyncBlockDeletion) {
|
|
81
107
|
return true;
|
|
82
108
|
}
|
|
83
109
|
const {
|
|
84
110
|
removed,
|
|
85
111
|
added
|
|
86
112
|
} = trackSyncBlocks(syncBlockStore, tr, state);
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
if (!isOffline) {
|
|
114
|
+
if (removed.length > 0) {
|
|
115
|
+
// If there are source sync blocks being removed, and we need to confirm with user before deleting,
|
|
116
|
+
// we block the transaction here, and wait for user confirmation to proceed with deletion.
|
|
117
|
+
// See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
|
|
118
|
+
// proceed with deletion.
|
|
119
|
+
syncBlockStore.deleteSyncBlocksWithConfirmation(tr, removed);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (added.length > 0) {
|
|
123
|
+
// If there is bodiedSyncBlock node addition and it's waiting for the result of saving the node to backend (syncBlockStore.hasPendingCreation()),
|
|
124
|
+
// 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
|
|
125
|
+
// The callback will be evoked by in SourceSyncBlockStoreManager.commitPendingCreation
|
|
126
|
+
syncBlockStore.registerCreationCallback(() => {
|
|
127
|
+
var _api$core;
|
|
128
|
+
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(() => {
|
|
129
|
+
return tr.setMeta('isCommitSyncBlockCreation', true);
|
|
130
|
+
});
|
|
131
|
+
api === null || api === void 0 ? void 0 : api.core.actions.focus();
|
|
132
|
+
});
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
// Disable node deletion/creation/edition in offline mode and trigger an error flag instead
|
|
137
|
+
let errorFlag = false;
|
|
138
|
+
if (isConfirmedSyncBlockDeletion || removed.length > 0) {
|
|
139
|
+
errorFlag = FLAG_ID.CANNOT_DELETE_WHEN_OFFLINE;
|
|
140
|
+
} else if (added.length > 0) {
|
|
141
|
+
errorFlag = FLAG_ID.CANNOT_CREATE_WHEN_OFFLINE;
|
|
142
|
+
} else if (hasEditInSyncBlock(tr, state)) {
|
|
143
|
+
errorFlag = FLAG_ID.CANNOT_EDIT_WHEN_OFFLINE;
|
|
144
|
+
}
|
|
145
|
+
if (errorFlag) {
|
|
146
|
+
api === null || api === void 0 ? void 0 : api.core.actions.execute(({
|
|
147
|
+
tr
|
|
148
|
+
}) => {
|
|
149
|
+
tr.setMeta(syncedBlockPluginKey, {
|
|
150
|
+
showFlag: errorFlag
|
|
151
|
+
});
|
|
152
|
+
return tr;
|
|
103
153
|
});
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
return false;
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
107
156
|
}
|
|
108
157
|
return true;
|
|
109
158
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @returns true if should ignore event happens within bodiedSyncBlock node when offline
|
|
5
|
+
*/
|
|
6
|
+
export const shouldIgnoreDomEvent = (view, event, api) => {
|
|
7
|
+
var _api$connectivity, _api$connectivity$sha, _view$posAtCoords;
|
|
8
|
+
if ((api === null || api === void 0 ? void 0 : (_api$connectivity = api.connectivity) === null || _api$connectivity === void 0 ? void 0 : (_api$connectivity$sha = _api$connectivity.sharedState.currentState()) === null || _api$connectivity$sha === void 0 ? void 0 : _api$connectivity$sha.mode) !== 'offline') {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const {
|
|
12
|
+
bodiedSyncBlock
|
|
13
|
+
} = view.state.schema.nodes;
|
|
14
|
+
const pos = (_view$posAtCoords = view.posAtCoords({
|
|
15
|
+
left: event.clientX,
|
|
16
|
+
top: event.clientY
|
|
17
|
+
})) === null || _view$posAtCoords === void 0 ? void 0 : _view$posAtCoords.pos;
|
|
18
|
+
if (pos === undefined) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const $pos = view.state.doc.resolve(pos);
|
|
22
|
+
const maybeNode = findParentNodeOfTypeClosestToPos($pos, bodiedSyncBlock);
|
|
23
|
+
if (maybeNode) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
2
3
|
export const trackSyncBlocks = (storeManager, tr, state) => {
|
|
3
4
|
const sourceSyncBlockRemoved = {};
|
|
4
5
|
const sourceSyncBlockAdded = {};
|
|
@@ -55,4 +56,44 @@ export const trackSyncBlocks = (storeManager, tr, state) => {
|
|
|
55
56
|
removed: Object.values(sourceSyncBlockRemoved),
|
|
56
57
|
added: Object.values(sourceSyncBlockAdded)
|
|
57
58
|
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
*
|
|
63
|
+
* @returns true if steps modifies children node within bodiedSyncBlock
|
|
64
|
+
*/
|
|
65
|
+
export const hasEditInSyncBlock = (tr, state) => {
|
|
66
|
+
const {
|
|
67
|
+
bodiedSyncBlock
|
|
68
|
+
} = state.schema.nodes;
|
|
69
|
+
for (const step of tr.steps) {
|
|
70
|
+
const map = step.getMap();
|
|
71
|
+
const {
|
|
72
|
+
doc
|
|
73
|
+
} = tr;
|
|
74
|
+
const positions = [];
|
|
75
|
+
|
|
76
|
+
// Extract positions from steps dynamically based on applicable properties
|
|
77
|
+
if ('from' in step && typeof step.from === 'number' && 'to' in step && typeof step.to === 'number') {
|
|
78
|
+
const {
|
|
79
|
+
from,
|
|
80
|
+
to
|
|
81
|
+
} = step;
|
|
82
|
+
positions.push(from, to);
|
|
83
|
+
} else if ('pos' in step && typeof step.pos === 'number') {
|
|
84
|
+
const {
|
|
85
|
+
pos
|
|
86
|
+
} = step;
|
|
87
|
+
positions.push(pos);
|
|
88
|
+
}
|
|
89
|
+
for (const pos of positions) {
|
|
90
|
+
const newPos = map.map(pos);
|
|
91
|
+
if (newPos >= 0 && newPos <= doc.content.size) {
|
|
92
|
+
if (findParentNodeOfTypeClosestToPos(doc.resolve(newPos), bodiedSyncBlock)) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
58
99
|
};
|
|
@@ -6,9 +6,10 @@ import { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
|
|
|
6
6
|
import Lozenge from '@atlaskit/lozenge';
|
|
7
7
|
import { flushBodiedSyncBlocks } from './editor-actions';
|
|
8
8
|
import { copySyncedBlockReferenceToClipboardEditorCommand, createSyncedBlock } from './editor-commands';
|
|
9
|
-
import { createPlugin } from './pm-plugins/main';
|
|
9
|
+
import { createPlugin, syncedBlockPluginKey } from './pm-plugins/main';
|
|
10
10
|
import { getBlockMenuComponents } from './ui/block-menu-components';
|
|
11
11
|
import { DeleteConfirmationModal } from './ui/DeleteConfirmationModal';
|
|
12
|
+
import { Flag } from './ui/Flag';
|
|
12
13
|
import { getToolbarConfig } from './ui/floating-toolbar';
|
|
13
14
|
import { SyncBlockRefresher } from './ui/SyncBlockRefresher';
|
|
14
15
|
import { getToolbarComponents } from './ui/toolbar-components';
|
|
@@ -60,6 +61,7 @@ export const syncedBlockPlugin = ({
|
|
|
60
61
|
description: formatMessage(blockTypeMessages.syncedBlockDescription),
|
|
61
62
|
priority: 800,
|
|
62
63
|
keywords: ['synced', 'block', 'synced-block', 'sync', 'sync-block', 'auto', 'update', 'excerpt', 'connect'],
|
|
64
|
+
isDisabledOffline: true,
|
|
63
65
|
keyshortcut: '',
|
|
64
66
|
lozenge: /*#__PURE__*/React.createElement(Lozenge, {
|
|
65
67
|
appearance: "new"
|
|
@@ -81,8 +83,22 @@ export const syncedBlockPlugin = ({
|
|
|
81
83
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SyncBlockRefresher, {
|
|
82
84
|
syncBlockStoreManager: syncBlockStore
|
|
83
85
|
}), /*#__PURE__*/React.createElement(DeleteConfirmationModal, {
|
|
84
|
-
syncBlockStoreManager: syncBlockStore
|
|
86
|
+
syncBlockStoreManager: syncBlockStore,
|
|
87
|
+
api: api
|
|
88
|
+
}), /*#__PURE__*/React.createElement(Flag, {
|
|
89
|
+
api: api
|
|
85
90
|
}));
|
|
91
|
+
},
|
|
92
|
+
getSharedState: editorState => {
|
|
93
|
+
if (!editorState) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const {
|
|
97
|
+
showFlag
|
|
98
|
+
} = syncedBlockPluginKey.getState(editorState);
|
|
99
|
+
return {
|
|
100
|
+
showFlag
|
|
101
|
+
};
|
|
86
102
|
}
|
|
87
103
|
};
|
|
88
104
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export let FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
|
|
2
|
+
FLAG_ID["CANNOT_DELETE_WHEN_OFFLINE"] = "cannot-delete-when-offline";
|
|
3
|
+
FLAG_ID["CANNOT_EDIT_WHEN_OFFLINE"] = "cannot-edit-when-offline";
|
|
4
|
+
FLAG_ID["CANNOT_CREATE_WHEN_OFFLINE"] = "cannot-create-when-offline";
|
|
5
|
+
return FLAG_ID;
|
|
6
|
+
}({});
|
|
@@ -9,16 +9,22 @@ export const CreateSyncedBlockButton = ({
|
|
|
9
9
|
api
|
|
10
10
|
}) => {
|
|
11
11
|
const intl = useIntl();
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const {
|
|
13
|
+
selection,
|
|
14
|
+
mode
|
|
15
|
+
} = useSharedPluginStateWithSelector(api, ['selection', 'connectivity'], states => {
|
|
16
|
+
var _states$selectionStat, _states$connectivityS;
|
|
17
|
+
return {
|
|
18
|
+
selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection,
|
|
19
|
+
mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
|
|
20
|
+
};
|
|
15
21
|
});
|
|
16
22
|
|
|
17
23
|
// for toolbar button, we allow both creating a new synced block
|
|
18
24
|
// and converting existing block to synced block
|
|
19
25
|
const canBeConverted = Boolean(selection && canBeConvertedToSyncBlock(selection));
|
|
20
26
|
const canInsertEmptyBlock = Boolean(selection === null || selection === void 0 ? void 0 : selection.empty);
|
|
21
|
-
const isDisabled = Boolean(!canBeConverted && !canInsertEmptyBlock);
|
|
27
|
+
const isDisabled = Boolean(mode === 'offline' || !canBeConverted && !canInsertEmptyBlock);
|
|
22
28
|
const onClick = useCallback(() => {
|
|
23
29
|
var _api$core, _api$core2;
|
|
24
30
|
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
|
|
@@ -14,12 +14,14 @@ const CreateSyncedBlockDropdownItem = ({
|
|
|
14
14
|
} = useIntl();
|
|
15
15
|
const {
|
|
16
16
|
selection,
|
|
17
|
-
menuTriggerByNode
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
menuTriggerByNode,
|
|
18
|
+
mode
|
|
19
|
+
} = useSharedPluginStateWithSelector(api, ['selection', 'blockControls', 'connectivity'], states => {
|
|
20
|
+
var _states$selectionStat, _states$blockControls, _states$blockControls2, _states$connectivityS;
|
|
20
21
|
return {
|
|
21
22
|
selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection,
|
|
22
|
-
menuTriggerByNode: (_states$blockControls = (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.menuTriggerByNode) !== null && _states$blockControls !== void 0 ? _states$blockControls : undefined
|
|
23
|
+
menuTriggerByNode: (_states$blockControls = (_states$blockControls2 = states.blockControlsState) === null || _states$blockControls2 === void 0 ? void 0 : _states$blockControls2.menuTriggerByNode) !== null && _states$blockControls !== void 0 ? _states$blockControls : undefined,
|
|
24
|
+
mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
|
|
23
25
|
};
|
|
24
26
|
});
|
|
25
27
|
const isNested = menuTriggerByNode && menuTriggerByNode.rootPos !== menuTriggerByNode.pos;
|
|
@@ -34,17 +36,17 @@ const CreateSyncedBlockDropdownItem = ({
|
|
|
34
36
|
closeMenu: true
|
|
35
37
|
}));
|
|
36
38
|
};
|
|
39
|
+
const isOffline = mode === 'offline';
|
|
37
40
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
|
|
38
41
|
elemBefore: /*#__PURE__*/React.createElement(SyncBlocksIcon, {
|
|
39
42
|
label: ""
|
|
40
43
|
}),
|
|
41
|
-
onClick: onClick
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}, formatMessage(blockMenuMessages.newLozenge))));
|
|
44
|
+
onClick: onClick,
|
|
45
|
+
isDisabled: isOffline,
|
|
46
|
+
elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
|
|
47
|
+
appearance: "new"
|
|
48
|
+
}, formatMessage(blockMenuMessages.newLozenge))
|
|
49
|
+
}, formatMessage(blockMenuMessages.createSyncedBlock));
|
|
48
50
|
};
|
|
49
51
|
const CopySyncedBlockDropdownItem = ({
|
|
50
52
|
api
|
|
@@ -5,17 +5,24 @@ import { syncBlockMessages } from '@atlaskit/editor-common/messages';
|
|
|
5
5
|
import { ToolbarDropdownItem } from '@atlaskit/editor-toolbar';
|
|
6
6
|
import BlockSyncedIcon from '@atlaskit/icon-lab/core/block-synced';
|
|
7
7
|
import Lozenge from '@atlaskit/lozenge';
|
|
8
|
-
import { Flex } from '@atlaskit/primitives/compiled';
|
|
9
8
|
import { canBeConvertedToSyncBlock } from '../pm-plugins/utils/utils';
|
|
10
9
|
export const CreateSyncedBlockItem = ({
|
|
11
10
|
api
|
|
12
11
|
}) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
const {
|
|
13
|
+
formatMessage
|
|
14
|
+
} = useIntl();
|
|
15
|
+
const {
|
|
16
|
+
selection,
|
|
17
|
+
mode
|
|
18
|
+
} = useSharedPluginStateWithSelector(api, ['selection', 'connectivity'], states => {
|
|
19
|
+
var _states$selectionStat, _states$connectivityS;
|
|
20
|
+
return {
|
|
21
|
+
selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection,
|
|
22
|
+
mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
|
|
23
|
+
};
|
|
17
24
|
});
|
|
18
|
-
const isDisabled = Boolean(!selection || !canBeConvertedToSyncBlock(selection));
|
|
25
|
+
const isDisabled = Boolean(!selection || !canBeConvertedToSyncBlock(selection) || mode === 'offline');
|
|
19
26
|
const onClick = useCallback(() => {
|
|
20
27
|
var _api$core, _api$core2;
|
|
21
28
|
api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
|
|
@@ -25,18 +32,15 @@ export const CreateSyncedBlockItem = ({
|
|
|
25
32
|
}));
|
|
26
33
|
api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.focus();
|
|
27
34
|
}, [api]);
|
|
28
|
-
const message = intl.formatMessage(syncBlockMessages.createSyncBlockLabel);
|
|
29
35
|
return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
|
|
30
36
|
onClick: onClick,
|
|
31
37
|
isDisabled: isDisabled,
|
|
32
38
|
elemBefore: /*#__PURE__*/React.createElement(BlockSyncedIcon, {
|
|
33
39
|
size: "small",
|
|
34
40
|
label: ""
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
appearance: "new"
|
|
41
|
-
}, intl.formatMessage(syncBlockMessages.newLozenge))));
|
|
41
|
+
}),
|
|
42
|
+
elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
|
|
43
|
+
appearance: "new"
|
|
44
|
+
}, formatMessage(syncBlockMessages.newLozenge))
|
|
45
|
+
}, formatMessage(syncBlockMessages.createSyncBlockLabel));
|
|
42
46
|
};
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl-next';
|
|
3
3
|
import Button from '@atlaskit/button/new';
|
|
4
|
+
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
4
5
|
import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
5
6
|
import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
|
|
6
7
|
import { Text } from '@atlaskit/primitives/compiled';
|
|
7
8
|
export const DeleteConfirmationModal = ({
|
|
8
|
-
syncBlockStoreManager
|
|
9
|
+
syncBlockStoreManager,
|
|
10
|
+
api
|
|
9
11
|
}) => {
|
|
10
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
11
13
|
const [syncBlockCount, setSyncBlockCount] = useState(1);
|
|
14
|
+
const {
|
|
15
|
+
mode
|
|
16
|
+
} = useSharedPluginStateWithSelector(api, ['connectivity'], states => {
|
|
17
|
+
var _states$connectivityS;
|
|
18
|
+
return {
|
|
19
|
+
mode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode
|
|
20
|
+
};
|
|
21
|
+
});
|
|
12
22
|
const {
|
|
13
23
|
formatMessage
|
|
14
24
|
} = useIntl();
|
|
@@ -48,6 +58,7 @@ export const DeleteConfirmationModal = ({
|
|
|
48
58
|
}, formatMessage(messages.deleteConfirmationModalCancelButton)), /*#__PURE__*/React.createElement(Button, {
|
|
49
59
|
appearance: "warning",
|
|
50
60
|
onClick: handleClose(true),
|
|
51
|
-
autoFocus: true
|
|
61
|
+
autoFocus: true,
|
|
62
|
+
isDisabled: mode === 'offline'
|
|
52
63
|
}, formatMessage(messages.deleteConfirmationModalDeleteButton)))));
|
|
53
64
|
};
|