@atlaskit/editor-plugin-synced-block 5.1.9 → 5.1.10
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 +14 -0
- package/dist/cjs/editor-commands/index.js +2 -2
- package/dist/cjs/pm-plugins/experience-tracking/create-reference-experience.js +26 -26
- package/dist/cjs/pm-plugins/experience-tracking/create-source-experience.js +14 -30
- package/dist/cjs/pm-plugins/experience-tracking/delete-reference-experience.js +175 -0
- package/dist/cjs/pm-plugins/experience-tracking/delete-source-experience.js +103 -0
- package/dist/cjs/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +30 -0
- package/dist/cjs/pm-plugins/experience-tracking/provider-only-experiences.js +128 -0
- package/dist/cjs/pm-plugins/utils/experience-tracking-utils.js +85 -0
- package/dist/cjs/types/index.js +5 -2
- package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +40 -8
- package/dist/cjs/ui/DeleteConfirmationModal.js +3 -1
- package/dist/cjs/ui/floating-toolbar.js +4 -2
- package/dist/es2019/editor-commands/index.js +2 -2
- package/dist/es2019/pm-plugins/experience-tracking/create-reference-experience.js +27 -23
- package/dist/es2019/pm-plugins/experience-tracking/create-source-experience.js +14 -27
- package/dist/es2019/pm-plugins/experience-tracking/delete-reference-experience.js +181 -0
- package/dist/es2019/pm-plugins/experience-tracking/delete-source-experience.js +98 -0
- package/dist/es2019/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +24 -0
- package/dist/es2019/pm-plugins/experience-tracking/provider-only-experiences.js +127 -0
- package/dist/es2019/pm-plugins/utils/experience-tracking-utils.js +65 -0
- package/dist/es2019/types/index.js +4 -1
- package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +38 -3
- package/dist/es2019/ui/DeleteConfirmationModal.js +3 -1
- package/dist/es2019/ui/floating-toolbar.js +3 -1
- package/dist/esm/editor-commands/index.js +2 -2
- package/dist/esm/pm-plugins/experience-tracking/create-reference-experience.js +26 -25
- package/dist/esm/pm-plugins/experience-tracking/create-source-experience.js +14 -29
- package/dist/esm/pm-plugins/experience-tracking/delete-reference-experience.js +169 -0
- package/dist/esm/pm-plugins/experience-tracking/delete-source-experience.js +97 -0
- package/dist/esm/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +30 -0
- package/dist/esm/pm-plugins/experience-tracking/provider-only-experiences.js +122 -0
- package/dist/esm/pm-plugins/utils/experience-tracking-utils.js +79 -0
- package/dist/esm/types/index.js +4 -1
- package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +40 -8
- package/dist/esm/ui/DeleteConfirmationModal.js +3 -1
- package/dist/esm/ui/floating-toolbar.js +4 -2
- package/dist/types/pm-plugins/experience-tracking/create-reference-experience.d.ts +2 -9
- package/dist/types/pm-plugins/experience-tracking/create-source-experience.d.ts +4 -15
- package/dist/types/pm-plugins/experience-tracking/delete-reference-experience.d.ts +13 -0
- package/dist/types/pm-plugins/experience-tracking/delete-source-experience.d.ts +12 -0
- package/dist/types/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +2 -13
- package/dist/types/pm-plugins/experience-tracking/provider-only-experiences.d.ts +3 -0
- package/dist/types/pm-plugins/utils/experience-tracking-utils.d.ts +9 -0
- package/dist/types/types/index.d.ts +15 -0
- package/dist/types-ts4.5/pm-plugins/experience-tracking/create-reference-experience.d.ts +2 -9
- package/dist/types-ts4.5/pm-plugins/experience-tracking/create-source-experience.d.ts +4 -15
- package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-reference-experience.d.ts +13 -0
- package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-source-experience.d.ts +12 -0
- package/dist/types-ts4.5/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +2 -13
- package/dist/types-ts4.5/pm-plugins/experience-tracking/provider-only-experiences.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/utils/experience-tracking-utils.d.ts +9 -0
- package/dist/types-ts4.5/types/index.d.ts +15 -0
- package/package.json +5 -5
- package/build/tsconfig.json +0 -22
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wasSyncBlockDeletedOrAddedByHistory = exports.getTarget = exports.getRemovedResourceIds = exports.getAddedResourceIds = void 0;
|
|
7
|
+
var _utils = require("@atlaskit/editor-common/utils");
|
|
8
|
+
var _utils2 = require("@atlaskit/editor-prosemirror/utils");
|
|
9
|
+
var targetEl;
|
|
10
|
+
var getTarget = exports.getTarget = function getTarget(containerElement) {
|
|
11
|
+
if (!targetEl) {
|
|
12
|
+
var element = containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelector('.ProseMirror');
|
|
13
|
+
if (!element || !(element instanceof HTMLElement)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
targetEl = element;
|
|
17
|
+
}
|
|
18
|
+
return targetEl;
|
|
19
|
+
};
|
|
20
|
+
var wasSyncBlockDeletedOrAddedByHistory = exports.wasSyncBlockDeletedOrAddedByHistory = function wasSyncBlockDeletedOrAddedByHistory(tr, oldState, newState) {
|
|
21
|
+
var historyMeta = tr.getMeta(_utils.pmHistoryPluginKey);
|
|
22
|
+
if (!Boolean(historyMeta)) {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
var syncBlock = newState.schema.nodes.syncBlock;
|
|
26
|
+
var oldSyncBlockNodes = (0, _utils2.findChildren)(oldState.doc, function (node) {
|
|
27
|
+
return node.type === syncBlock;
|
|
28
|
+
});
|
|
29
|
+
var newSyncBlockNodes = (0, _utils2.findChildren)(newState.doc, function (node) {
|
|
30
|
+
return node.type === syncBlock;
|
|
31
|
+
});
|
|
32
|
+
var oldSyncBlockIds = new Set(oldSyncBlockNodes.map(function (nodeWithPos) {
|
|
33
|
+
return nodeWithPos.node.attrs.localId;
|
|
34
|
+
}).filter(function (localId) {
|
|
35
|
+
return Boolean(localId);
|
|
36
|
+
}));
|
|
37
|
+
var newSyncBlockIds = new Set(newSyncBlockNodes.map(function (nodeWithPos) {
|
|
38
|
+
return nodeWithPos.node.attrs.localId;
|
|
39
|
+
}).filter(function (localId) {
|
|
40
|
+
return Boolean(localId);
|
|
41
|
+
}));
|
|
42
|
+
var hasDeletedSyncBlock = Array.from(oldSyncBlockIds).some(function (localId) {
|
|
43
|
+
return !newSyncBlockIds.has(localId);
|
|
44
|
+
});
|
|
45
|
+
var hasAddedSyncBlock = Array.from(newSyncBlockIds).some(function (localId) {
|
|
46
|
+
return !oldSyncBlockIds.has(localId);
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
hasDeletedSyncBlock: hasDeletedSyncBlock,
|
|
50
|
+
hasAddedSyncBlock: hasAddedSyncBlock,
|
|
51
|
+
isUndo: historyMeta.redo === false
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
var getResourceIds = function getResourceIds(nodes, resourceIds, query) {
|
|
55
|
+
nodes.forEach(function (node) {
|
|
56
|
+
if (!(node instanceof HTMLElement)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
var syncBlockElements = node.querySelectorAll(query);
|
|
60
|
+
syncBlockElements.forEach(function (element) {
|
|
61
|
+
var resourceId = element.getAttribute('resourceid');
|
|
62
|
+
if (resourceId) {
|
|
63
|
+
resourceIds.push(resourceId);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
var getAddedResourceIds = exports.getAddedResourceIds = function getAddedResourceIds(mutations, query) {
|
|
69
|
+
var resourceIds = [];
|
|
70
|
+
mutations.forEach(function (mutation) {
|
|
71
|
+
if (mutation.type === 'childList') {
|
|
72
|
+
getResourceIds(mutation.addedNodes, resourceIds, query);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return resourceIds;
|
|
76
|
+
};
|
|
77
|
+
var getRemovedResourceIds = exports.getRemovedResourceIds = function getRemovedResourceIds(mutations, query) {
|
|
78
|
+
var resourceIds = [];
|
|
79
|
+
mutations.forEach(function (mutation) {
|
|
80
|
+
if (mutation.type === 'childList') {
|
|
81
|
+
getResourceIds(mutation.removedNodes, resourceIds, query);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return resourceIds;
|
|
85
|
+
};
|
package/dist/cjs/types/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.FLAG_ID = void 0;
|
|
6
|
+
exports.FLAG_ID = exports.EXPERIENCE_ABORT_REASON = void 0;
|
|
7
7
|
var FLAG_ID = exports.FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
|
|
8
8
|
FLAG_ID["CANNOT_DELETE_WHEN_OFFLINE"] = "cannot-delete-when-offline";
|
|
9
9
|
FLAG_ID["CANNOT_EDIT_WHEN_OFFLINE"] = "cannot-edit-when-offline";
|
|
@@ -11,4 +11,7 @@ var FLAG_ID = exports.FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
|
|
|
11
11
|
FLAG_ID["FAIL_TO_DELETE"] = "fail-to-delete";
|
|
12
12
|
FLAG_ID["SYNC_BLOCK_COPIED"] = "sync-block-copied";
|
|
13
13
|
return FLAG_ID;
|
|
14
|
-
}({});
|
|
14
|
+
}({});
|
|
15
|
+
var EXPERIENCE_ABORT_REASON = exports.EXPERIENCE_ABORT_REASON = {
|
|
16
|
+
EDITOR_DESTROYED: 'editor-destroyed'
|
|
17
|
+
};
|
|
@@ -51,24 +51,56 @@ var CreateSyncedBlockDropdownItem = function CreateSyncedBlockDropdownItem(_ref)
|
|
|
51
51
|
}),
|
|
52
52
|
onClick: onClick,
|
|
53
53
|
isDisabled: isOffline,
|
|
54
|
-
testId:
|
|
54
|
+
testId: "create-synced-block-block-menu-btn",
|
|
55
55
|
elemAfter: /*#__PURE__*/_react.default.createElement(_lozenge.default, {
|
|
56
56
|
appearance: "new"
|
|
57
57
|
}, formatMessage(_messages.blockMenuMessages.newLozenge))
|
|
58
58
|
}, formatMessage(_messages.blockMenuMessages.createSyncedBlock));
|
|
59
59
|
};
|
|
60
|
-
var
|
|
61
|
-
var
|
|
62
|
-
var
|
|
63
|
-
|
|
64
|
-
var _useSharedPluginState2 = (0, _hooks.useSharedPluginStateWithSelector)(api, ['
|
|
60
|
+
var CopySyncedBlockDropdownItem = function CopySyncedBlockDropdownItem(_ref2) {
|
|
61
|
+
var api = _ref2.api;
|
|
62
|
+
var _useIntl2 = (0, _reactIntlNext.useIntl)(),
|
|
63
|
+
formatMessage = _useIntl2.formatMessage;
|
|
64
|
+
var _useSharedPluginState2 = (0, _hooks.useSharedPluginStateWithSelector)(api, ['connectivity'], function (states) {
|
|
65
|
+
var _states$connectivityS2;
|
|
66
|
+
return {
|
|
67
|
+
mode: (_states$connectivityS2 = states.connectivityState) === null || _states$connectivityS2 === void 0 ? void 0 : _states$connectivityS2.mode
|
|
68
|
+
};
|
|
69
|
+
}),
|
|
70
|
+
mode = _useSharedPluginState2.mode;
|
|
71
|
+
var onClick = function onClick() {
|
|
72
|
+
var _api$core3, _api$core4, _api$blockControls2;
|
|
73
|
+
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.copySyncedBlockReferenceToClipboard());
|
|
74
|
+
api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.commands) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.toggleBlockMenu({
|
|
75
|
+
closeMenu: true
|
|
76
|
+
}));
|
|
77
|
+
};
|
|
78
|
+
return /*#__PURE__*/_react.default.createElement(_editorToolbar.ToolbarDropdownItem, {
|
|
79
|
+
elemBefore: /*#__PURE__*/_react.default.createElement(_editorToolbar.SyncBlocksIcon, {
|
|
80
|
+
label: ""
|
|
81
|
+
}),
|
|
82
|
+
onClick: onClick,
|
|
83
|
+
isDisabled: (0, _editorPluginConnectivity.isOfflineMode)(mode),
|
|
84
|
+
elemAfter: /*#__PURE__*/_react.default.createElement(_lozenge.default, {
|
|
85
|
+
appearance: "new"
|
|
86
|
+
}, formatMessage(_messages.blockMenuMessages.newLozenge))
|
|
87
|
+
}, formatMessage(_messages.blockMenuMessages.copySyncedBlock));
|
|
88
|
+
};
|
|
89
|
+
var CreateOrCopySyncedBlockDropdownItem = exports.CreateOrCopySyncedBlockDropdownItem = function CreateOrCopySyncedBlockDropdownItem(_ref3) {
|
|
90
|
+
var api = _ref3.api,
|
|
91
|
+
enableSourceSyncedBlockCreation = _ref3.enableSourceSyncedBlockCreation;
|
|
92
|
+
var _useSharedPluginState3 = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls'], function (states) {
|
|
65
93
|
var _states$blockControls3, _states$blockControls4;
|
|
66
94
|
return {
|
|
67
95
|
menuTriggerByNode: (_states$blockControls3 = (_states$blockControls4 = states.blockControlsState) === null || _states$blockControls4 === void 0 ? void 0 : _states$blockControls4.menuTriggerByNode) !== null && _states$blockControls3 !== void 0 ? _states$blockControls3 : undefined
|
|
68
96
|
};
|
|
69
97
|
}),
|
|
70
|
-
menuTriggerByNode =
|
|
71
|
-
if (
|
|
98
|
+
menuTriggerByNode = _useSharedPluginState3.menuTriggerByNode;
|
|
99
|
+
if ((menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'syncBlock' || (menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'bodiedSyncBlock') {
|
|
100
|
+
return /*#__PURE__*/_react.default.createElement(CopySyncedBlockDropdownItem, {
|
|
101
|
+
api: api
|
|
102
|
+
});
|
|
103
|
+
} else if (enableSourceSyncedBlockCreation) {
|
|
72
104
|
return /*#__PURE__*/_react.default.createElement(CreateSyncedBlockDropdownItem, {
|
|
73
105
|
api: api
|
|
74
106
|
});
|
|
@@ -14,6 +14,7 @@ var _hooks = require("@atlaskit/editor-common/hooks");
|
|
|
14
14
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
15
15
|
var _editorPluginConnectivity = require("@atlaskit/editor-plugin-connectivity");
|
|
16
16
|
var _modalDialog = _interopRequireWildcard(require("@atlaskit/modal-dialog"));
|
|
17
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
17
18
|
var _compiled = require("@atlaskit/primitives/compiled");
|
|
18
19
|
var _main = require("../pm-plugins/main");
|
|
19
20
|
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); }
|
|
@@ -117,6 +118,7 @@ var DeleteConfirmationModal = exports.DeleteConfirmationModal = function DeleteC
|
|
|
117
118
|
onClick: handleClick(true),
|
|
118
119
|
autoFocus: true,
|
|
119
120
|
isDisabled: (0, _editorPluginConnectivity.isOfflineMode)(mode),
|
|
120
|
-
isLoading: bodiedSyncBlockDeletionStatus === 'processing'
|
|
121
|
+
isLoading: bodiedSyncBlockDeletionStatus === 'processing',
|
|
122
|
+
testId: (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? 'synced-block-delete-confirmation-modal-delete-button' : undefined
|
|
121
123
|
}, formatMessage(_messages.syncBlockMessages.deleteConfirmationModalDeleteButton)))));
|
|
122
124
|
};
|
|
@@ -15,6 +15,7 @@ var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider
|
|
|
15
15
|
var _copy = _interopRequireDefault(require("@atlaskit/icon/core/copy"));
|
|
16
16
|
var _delete = _interopRequireDefault(require("@atlaskit/icon/core/delete"));
|
|
17
17
|
var _edit = _interopRequireDefault(require("@atlaskit/icon/core/edit"));
|
|
18
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
18
19
|
var _editorCommands = require("../editor-commands");
|
|
19
20
|
var _utils2 = require("../pm-plugins/utils/utils");
|
|
20
21
|
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); }
|
|
@@ -47,7 +48,8 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(stat
|
|
|
47
48
|
type: 'button',
|
|
48
49
|
title: formatMessage(_messages.default.delete),
|
|
49
50
|
onClick: (0, _editorCommands.removeSyncedBlock)(api),
|
|
50
|
-
icon: _delete.default
|
|
51
|
+
icon: _delete.default,
|
|
52
|
+
testId: (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? 'reference-synced-block-delete-button' : undefined
|
|
51
53
|
}, hoverDecorationProps(nodeType, _consts.akEditorSelectedNodeClassName));
|
|
52
54
|
items.push(deleteButton);
|
|
53
55
|
} else {
|
|
@@ -58,7 +60,7 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(stat
|
|
|
58
60
|
icon: _copy.default,
|
|
59
61
|
title: formatMessage(_messages.syncBlockMessages.copySyncBlockLabel),
|
|
60
62
|
showTitle: false,
|
|
61
|
-
tooltipContent: formatMessage(_messages.syncBlockMessages.
|
|
63
|
+
tooltipContent: formatMessage(_messages.syncBlockMessages.copySyncedBlockTooltip),
|
|
62
64
|
onClick: (0, _editorCommands.copySyncedBlockReferenceToClipboard)(syncBlockStore, api)
|
|
63
65
|
}, hoverDecorationProps(nodeType, _consts.akEditorSelectedNodeClassName));
|
|
64
66
|
items.push(copyButton);
|
|
@@ -59,8 +59,8 @@ export const createSyncedBlock = ({
|
|
|
59
59
|
syncBlockStore.sourceManager.createBodiedSyncBlockNode(attrs);
|
|
60
60
|
tr.replaceWith(conversionInfo.from > 0 ? conversionInfo.from - 1 : 0, conversionInfo.to, newBodiedSyncBlockNode).scrollIntoView();
|
|
61
61
|
|
|
62
|
-
// set selection to the
|
|
63
|
-
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.
|
|
62
|
+
// set selection to the start of the previous selection for the position taken up by the start of the new synced block
|
|
63
|
+
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.from));
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// This transaction will be intercepted in filterTransaction and dispatched when saving to backend succeeds
|
|
@@ -2,13 +2,14 @@ import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analy
|
|
|
2
2
|
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
|
|
3
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
4
4
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { EXPERIENCE_ABORT_REASON } from '../../types';
|
|
6
|
+
import { getAddedResourceIds, wasSyncBlockDeletedOrAddedByHistory, getTarget } from '../utils/experience-tracking-utils';
|
|
5
7
|
const isPastedFromFabricEditor = html => !!html && html.indexOf('data-pm-slice="') >= 0;
|
|
6
8
|
const pluginKey = new PluginKey('createReferenceSyncBlockExperience');
|
|
7
9
|
const START_METHOD = {
|
|
8
|
-
PASTE: 'paste'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
EDITOR_DESTROYED: 'editor-destroyed'
|
|
10
|
+
PASTE: 'paste',
|
|
11
|
+
UNDO: 'undo',
|
|
12
|
+
REDO: 'redo'
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -32,7 +33,7 @@ export const getCreateReferenceExperiencePlugin = ({
|
|
|
32
33
|
return {
|
|
33
34
|
destroy: () => {
|
|
34
35
|
experience.abort({
|
|
35
|
-
reason:
|
|
36
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
};
|
|
@@ -54,6 +55,20 @@ export const getCreateReferenceExperiencePlugin = ({
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
}
|
|
58
|
+
},
|
|
59
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
60
|
+
transactions.forEach(tr => {
|
|
61
|
+
const {
|
|
62
|
+
hasAddedSyncBlock,
|
|
63
|
+
isUndo
|
|
64
|
+
} = wasSyncBlockDeletedOrAddedByHistory(tr, oldState, newState);
|
|
65
|
+
if (hasAddedSyncBlock) {
|
|
66
|
+
experience.start({
|
|
67
|
+
method: isUndo ? START_METHOD.UNDO : START_METHOD.REDO
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return null;
|
|
57
72
|
}
|
|
58
73
|
});
|
|
59
74
|
};
|
|
@@ -70,21 +85,20 @@ const getCreateReferenceExperience = ({
|
|
|
70
85
|
onDomMutation: ({
|
|
71
86
|
mutations
|
|
72
87
|
}) => {
|
|
73
|
-
|
|
88
|
+
const insertedResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="syncBlock"]');
|
|
89
|
+
if (insertedResourceIds.length > 0) {
|
|
74
90
|
return {
|
|
75
|
-
status: 'success'
|
|
91
|
+
status: 'success',
|
|
92
|
+
metadata: {
|
|
93
|
+
insertedResourceIds
|
|
94
|
+
}
|
|
76
95
|
};
|
|
77
96
|
}
|
|
78
97
|
return undefined;
|
|
79
98
|
},
|
|
80
99
|
observeConfig: () => {
|
|
81
|
-
var _refs$containerElemen;
|
|
82
|
-
const proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
|
|
83
|
-
if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
100
|
return {
|
|
87
|
-
target:
|
|
101
|
+
target: getTarget(refs.containerElement),
|
|
88
102
|
options: {
|
|
89
103
|
childList: true
|
|
90
104
|
}
|
|
@@ -92,14 +106,4 @@ const getCreateReferenceExperience = ({
|
|
|
92
106
|
}
|
|
93
107
|
})]
|
|
94
108
|
});
|
|
95
|
-
};
|
|
96
|
-
const isReferenceSyncBlockAddedInMutation = ({
|
|
97
|
-
type,
|
|
98
|
-
addedNodes
|
|
99
|
-
}) => type === 'childList' && [...addedNodes].some(isReferenceSyncBlockNode);
|
|
100
|
-
const isReferenceSyncBlockNode = node => {
|
|
101
|
-
if (!(node instanceof HTMLElement)) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
return !!node.querySelector('[data-prosemirror-node-name="syncBlock"]');
|
|
105
109
|
};
|
|
@@ -3,10 +3,9 @@ import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analy
|
|
|
3
3
|
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView, popupWithNestedElement } from '@atlaskit/editor-common/experiences';
|
|
4
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
5
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
|
+
import { EXPERIENCE_ABORT_REASON } from '../../types';
|
|
7
|
+
import { getAddedResourceIds, getTarget } from '../utils/experience-tracking-utils';
|
|
6
8
|
const pluginKey = new PluginKey('createSourceSyncBlockExperience');
|
|
7
|
-
const ABORT_REASON = {
|
|
8
|
-
EDITOR_DESTROYED: 'editor-destroyed'
|
|
9
|
-
};
|
|
10
9
|
const START_METHOD = {
|
|
11
10
|
BLOCK_MENU: 'block-menu',
|
|
12
11
|
PINNED_TOOLBAR: 'pinned-toolbar',
|
|
@@ -19,8 +18,8 @@ const syncedBlockCreateButtonIds = new Set(SYNCED_BLOCK_CREATE_BUTTON_IDS);
|
|
|
19
18
|
* This experience tracks when a source sync block is inserted.
|
|
20
19
|
*
|
|
21
20
|
* Start: When user inserts a sync block via block menu, quick insert or pinned toolbar
|
|
22
|
-
* Success: When the sync block is added to the DOM within
|
|
23
|
-
* Failure: When
|
|
21
|
+
* Success: When the sync block is added to the DOM within 3000ms of start
|
|
22
|
+
* Failure: When 3000ms passes without the source sync block being added to the DOM
|
|
24
23
|
*/
|
|
25
24
|
export const getCreateSourceExperiencePlugin = ({
|
|
26
25
|
refs,
|
|
@@ -37,8 +36,7 @@ export const getCreateSourceExperiencePlugin = ({
|
|
|
37
36
|
};
|
|
38
37
|
const experience = getCreateSourceExperience({
|
|
39
38
|
refs,
|
|
40
|
-
dispatchAnalyticsEvent
|
|
41
|
-
syncBlockStore
|
|
39
|
+
dispatchAnalyticsEvent
|
|
42
40
|
});
|
|
43
41
|
syncBlockStore.sourceManager.setCreateExperience(experience);
|
|
44
42
|
const unbindClickListener = bind(document, {
|
|
@@ -90,7 +88,7 @@ export const getCreateSourceExperiencePlugin = ({
|
|
|
90
88
|
return {
|
|
91
89
|
destroy: () => {
|
|
92
90
|
experience.abort({
|
|
93
|
-
reason:
|
|
91
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
94
92
|
});
|
|
95
93
|
unbindClickListener();
|
|
96
94
|
unbindKeydownListener();
|
|
@@ -107,26 +105,25 @@ const getCreateSourceExperience = ({
|
|
|
107
105
|
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
|
|
108
106
|
dispatchAnalyticsEvent,
|
|
109
107
|
checks: [new ExperienceCheckTimeout({
|
|
110
|
-
durationMs:
|
|
108
|
+
durationMs: 3000
|
|
111
109
|
}), new ExperienceCheckDomMutation({
|
|
112
110
|
onDomMutation: ({
|
|
113
111
|
mutations
|
|
114
112
|
}) => {
|
|
115
|
-
|
|
113
|
+
const createdResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
114
|
+
if (createdResourceIds.length > 0) {
|
|
116
115
|
return {
|
|
117
|
-
status: 'success'
|
|
116
|
+
status: 'success',
|
|
117
|
+
metadata: {
|
|
118
|
+
createdResourceIds
|
|
119
|
+
}
|
|
118
120
|
};
|
|
119
121
|
}
|
|
120
122
|
return undefined;
|
|
121
123
|
},
|
|
122
124
|
observeConfig: () => {
|
|
123
|
-
var _refs$containerElemen;
|
|
124
|
-
const proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
|
|
125
|
-
if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
125
|
return {
|
|
129
|
-
target:
|
|
126
|
+
target: getTarget(refs.containerElement),
|
|
130
127
|
options: {
|
|
131
128
|
childList: true
|
|
132
129
|
}
|
|
@@ -166,14 +163,4 @@ const handleButtonClick = (testId, experience) => {
|
|
|
166
163
|
};
|
|
167
164
|
const isEnterKey = key => {
|
|
168
165
|
return key === 'Enter';
|
|
169
|
-
};
|
|
170
|
-
const isSourceSyncBlockAddedInMutation = ({
|
|
171
|
-
type,
|
|
172
|
-
addedNodes
|
|
173
|
-
}) => type === 'childList' && [...addedNodes].some(isSourceSyncBlockNode);
|
|
174
|
-
const isSourceSyncBlockNode = node => {
|
|
175
|
-
if (!(node instanceof HTMLElement)) {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
return !!node.querySelector('[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
179
166
|
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { bind } from 'bind-event-listener';
|
|
2
|
+
import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
3
|
+
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
|
|
4
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
|
+
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
|
+
import { EXPERIENCE_ABORT_REASON } from '../../types';
|
|
7
|
+
import { getRemovedResourceIds, getTarget, wasSyncBlockDeletedOrAddedByHistory } from '../utils/experience-tracking-utils';
|
|
8
|
+
const pluginKey = new PluginKey('deleteReferenceSyncBlockExperience');
|
|
9
|
+
const START_METHOD = {
|
|
10
|
+
ELEMENT_TOOLBAR: 'element-toolbar',
|
|
11
|
+
DELETE: 'delete',
|
|
12
|
+
TYPED_OVER: 'typed-over',
|
|
13
|
+
CUT: 'cut',
|
|
14
|
+
UNDO: 'undo',
|
|
15
|
+
REDO: 'redo'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* This experience tracks when a reference sync block is deleted.
|
|
20
|
+
*
|
|
21
|
+
* Start: When user deletes ref sync block from toolbar, presses delete when cursor is in front of ref sync block,
|
|
22
|
+
* presses any key with a ref sync block selected, cuts with a ref sync block selected, triggers undo/redo that deletes a ref sync block
|
|
23
|
+
* Success: When the sync block is removed from the DOM within 2000ms of start
|
|
24
|
+
* Failure: When 2000ms passes without the reference sync block being removed from the DOM
|
|
25
|
+
*/
|
|
26
|
+
export const getDeleteReferenceExperiencePlugin = ({
|
|
27
|
+
refs,
|
|
28
|
+
dispatchAnalyticsEvent,
|
|
29
|
+
syncBlockStore
|
|
30
|
+
}) => {
|
|
31
|
+
const experience = getDeleteReferenceExperience({
|
|
32
|
+
refs,
|
|
33
|
+
dispatchAnalyticsEvent
|
|
34
|
+
});
|
|
35
|
+
syncBlockStore.sourceManager.setDeleteExperience(experience);
|
|
36
|
+
const unbindClickListener = bind(document, {
|
|
37
|
+
type: 'click',
|
|
38
|
+
listener: event => {
|
|
39
|
+
const target = event.target;
|
|
40
|
+
if (!target) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const button = target.closest('button[data-testid]');
|
|
44
|
+
if (!button || !(button instanceof HTMLButtonElement)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const testId = button.dataset.testid;
|
|
48
|
+
if (isReferenceSyncedBlockDeleteButtonId(testId)) {
|
|
49
|
+
experience.start({
|
|
50
|
+
method: START_METHOD.ELEMENT_TOOLBAR
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return new SafePlugin({
|
|
56
|
+
key: pluginKey,
|
|
57
|
+
props: {
|
|
58
|
+
handleDOMEvents: {
|
|
59
|
+
cut: view => {
|
|
60
|
+
const {
|
|
61
|
+
state
|
|
62
|
+
} = view;
|
|
63
|
+
if (hasSyncBlockInSelection(state.selection)) {
|
|
64
|
+
experience.start({
|
|
65
|
+
method: START_METHOD.CUT
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
},
|
|
70
|
+
keydown: (view, event) => {
|
|
71
|
+
const {
|
|
72
|
+
state
|
|
73
|
+
} = view;
|
|
74
|
+
const hasSelection = hasSyncBlockInSelection(state.selection);
|
|
75
|
+
const hasAdjacent = hasSyncBlockBeforeCursor(state.selection);
|
|
76
|
+
if (hasSelection) {
|
|
77
|
+
experience.start({
|
|
78
|
+
method: START_METHOD.TYPED_OVER
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (isDeleteKey(event.key) && hasAdjacent) {
|
|
82
|
+
experience.start({
|
|
83
|
+
method: START_METHOD.DELETE
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
91
|
+
transactions.forEach(tr => {
|
|
92
|
+
const {
|
|
93
|
+
hasDeletedSyncBlock,
|
|
94
|
+
isUndo
|
|
95
|
+
} = wasSyncBlockDeletedOrAddedByHistory(tr, oldState, newState);
|
|
96
|
+
if (hasDeletedSyncBlock) {
|
|
97
|
+
experience.start({
|
|
98
|
+
method: isUndo ? START_METHOD.UNDO : START_METHOD.REDO
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return null;
|
|
103
|
+
},
|
|
104
|
+
view: () => {
|
|
105
|
+
return {
|
|
106
|
+
destroy: () => {
|
|
107
|
+
experience.abort({
|
|
108
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
109
|
+
});
|
|
110
|
+
unbindClickListener();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
export const getDeleteReferenceExperience = ({
|
|
117
|
+
refs,
|
|
118
|
+
dispatchAnalyticsEvent
|
|
119
|
+
}) => {
|
|
120
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
121
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_DELETE,
|
|
122
|
+
dispatchAnalyticsEvent,
|
|
123
|
+
checks: [new ExperienceCheckTimeout({
|
|
124
|
+
durationMs: 2000
|
|
125
|
+
}), new ExperienceCheckDomMutation({
|
|
126
|
+
onDomMutation: ({
|
|
127
|
+
mutations
|
|
128
|
+
}) => {
|
|
129
|
+
const deletedResourceIds = getRemovedResourceIds(mutations, '[data-prosemirror-node-name="syncBlock"]');
|
|
130
|
+
if (deletedResourceIds.length > 0) {
|
|
131
|
+
return {
|
|
132
|
+
status: 'success',
|
|
133
|
+
metadata: {
|
|
134
|
+
deletedResourceIds
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
},
|
|
140
|
+
observeConfig: () => {
|
|
141
|
+
return {
|
|
142
|
+
target: getTarget(refs.containerElement),
|
|
143
|
+
options: {
|
|
144
|
+
childList: true
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
})]
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
const isReferenceSyncedBlockDeleteButtonId = testId => testId === 'reference-synced-block-delete-button';
|
|
152
|
+
const isDeleteKey = key => {
|
|
153
|
+
return key === 'Delete' || key === 'Backspace';
|
|
154
|
+
};
|
|
155
|
+
const hasSyncBlockInSelection = selection => {
|
|
156
|
+
const {
|
|
157
|
+
syncBlock
|
|
158
|
+
} = selection.$from.doc.type.schema.nodes;
|
|
159
|
+
let found = false;
|
|
160
|
+
selection.$from.doc.nodesBetween(selection.from, selection.to, node => {
|
|
161
|
+
if (node.type === syncBlock) {
|
|
162
|
+
found = true;
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
// sync block nodes can only be found at the top level
|
|
166
|
+
return false;
|
|
167
|
+
});
|
|
168
|
+
return found;
|
|
169
|
+
};
|
|
170
|
+
const hasSyncBlockBeforeCursor = selection => {
|
|
171
|
+
if (!selection.empty) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const {
|
|
175
|
+
syncBlock
|
|
176
|
+
} = selection.$from.doc.type.schema.nodes;
|
|
177
|
+
const {
|
|
178
|
+
nodeBefore
|
|
179
|
+
} = selection.$from;
|
|
180
|
+
return (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.type) === syncBlock;
|
|
181
|
+
};
|