@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,98 @@
|
|
|
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 } from '../utils/experience-tracking-utils';
|
|
8
|
+
const pluginKey = new PluginKey('deleteSourceSyncBlockExperience');
|
|
9
|
+
const START_METHOD = {
|
|
10
|
+
DELETE_CONFIRM_BUTTON: 'delete-confirm-button'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This experience tracks when a source sync block is deleted.
|
|
15
|
+
*
|
|
16
|
+
* Start: When user clicks the delete button in the delete modal
|
|
17
|
+
* Success: When the sync block is removed from the DOM within 2000ms of start
|
|
18
|
+
* Failure: When 2000ms passes without the source sync block being removed from the DOM
|
|
19
|
+
*/
|
|
20
|
+
export const getDeleteSourceExperiencePlugin = ({
|
|
21
|
+
refs,
|
|
22
|
+
dispatchAnalyticsEvent,
|
|
23
|
+
syncBlockStore
|
|
24
|
+
}) => {
|
|
25
|
+
const experience = getDeleteSourceExperience({
|
|
26
|
+
refs,
|
|
27
|
+
dispatchAnalyticsEvent
|
|
28
|
+
});
|
|
29
|
+
syncBlockStore.sourceManager.setDeleteExperience(experience);
|
|
30
|
+
const unbindClickListener = bind(document, {
|
|
31
|
+
type: 'click',
|
|
32
|
+
listener: event => {
|
|
33
|
+
const target = event.target;
|
|
34
|
+
if (!target) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const button = target.closest('button[data-testid]');
|
|
38
|
+
if (!button || !(button instanceof HTMLButtonElement)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const testId = button.dataset.testid;
|
|
42
|
+
if (isSyncedBlockDeleteButtonId(testId)) {
|
|
43
|
+
experience.start({
|
|
44
|
+
method: START_METHOD.DELETE_CONFIRM_BUTTON
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return new SafePlugin({
|
|
50
|
+
key: pluginKey,
|
|
51
|
+
view: () => {
|
|
52
|
+
return {
|
|
53
|
+
destroy: () => {
|
|
54
|
+
experience.abort({
|
|
55
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
56
|
+
});
|
|
57
|
+
unbindClickListener();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
export const getDeleteSourceExperience = ({
|
|
64
|
+
refs,
|
|
65
|
+
dispatchAnalyticsEvent
|
|
66
|
+
}) => {
|
|
67
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
68
|
+
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE,
|
|
69
|
+
dispatchAnalyticsEvent,
|
|
70
|
+
checks: [new ExperienceCheckTimeout({
|
|
71
|
+
durationMs: 2000
|
|
72
|
+
}), new ExperienceCheckDomMutation({
|
|
73
|
+
onDomMutation: ({
|
|
74
|
+
mutations
|
|
75
|
+
}) => {
|
|
76
|
+
const deletedResourceIds = getRemovedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
77
|
+
if (deletedResourceIds.length > 0) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'success',
|
|
80
|
+
metadata: {
|
|
81
|
+
deletedResourceIds
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
},
|
|
87
|
+
observeConfig: () => {
|
|
88
|
+
return {
|
|
89
|
+
target: getTarget(refs.containerElement),
|
|
90
|
+
options: {
|
|
91
|
+
childList: true
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
})]
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const isSyncedBlockDeleteButtonId = testId => testId === 'synced-block-delete-confirmation-modal-delete-button';
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { getCreateReferenceExperiencePlugin } from "./create-reference-experience";
|
|
2
2
|
import { getCreateSourceExperiencePlugin } from "./create-source-experience";
|
|
3
|
+
import { getDeleteReferenceExperiencePlugin } from "./delete-reference-experience";
|
|
4
|
+
import { getDeleteSourceExperiencePlugin } from "./delete-source-experience";
|
|
5
|
+
import { getProviderOnlyExperiencesPlugin } from "./provider-only-experiences";
|
|
3
6
|
export const getExperienceTrackingPlugins = ({
|
|
4
7
|
refs,
|
|
5
8
|
dispatchAnalyticsEvent,
|
|
@@ -18,5 +21,26 @@ export const getExperienceTrackingPlugins = ({
|
|
|
18
21
|
dispatchAnalyticsEvent,
|
|
19
22
|
syncBlockStore
|
|
20
23
|
})
|
|
24
|
+
}, {
|
|
25
|
+
name: 'deleteSourceExperiencePlugin',
|
|
26
|
+
plugin: () => getDeleteSourceExperiencePlugin({
|
|
27
|
+
refs,
|
|
28
|
+
dispatchAnalyticsEvent,
|
|
29
|
+
syncBlockStore
|
|
30
|
+
})
|
|
31
|
+
}, {
|
|
32
|
+
name: 'deleteReferenceExperiencePlugin',
|
|
33
|
+
plugin: () => getDeleteReferenceExperiencePlugin({
|
|
34
|
+
refs,
|
|
35
|
+
dispatchAnalyticsEvent,
|
|
36
|
+
syncBlockStore
|
|
37
|
+
})
|
|
38
|
+
}, {
|
|
39
|
+
name: 'providerOnlySyncedBlockExperiencesPlugin',
|
|
40
|
+
plugin: () => getProviderOnlyExperiencesPlugin({
|
|
41
|
+
refs,
|
|
42
|
+
dispatchAnalyticsEvent,
|
|
43
|
+
syncBlockStore
|
|
44
|
+
})
|
|
21
45
|
}];
|
|
22
46
|
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { Experience, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
|
|
3
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
4
|
+
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { EXPERIENCE_ABORT_REASON } from '../../types';
|
|
6
|
+
const pluginKey = new PluginKey('providerOnlySyncBlockExperiences');
|
|
7
|
+
export const getProviderOnlyExperiencesPlugin = ({
|
|
8
|
+
refs,
|
|
9
|
+
dispatchAnalyticsEvent,
|
|
10
|
+
syncBlockStore
|
|
11
|
+
}) => {
|
|
12
|
+
const saveSourceExperience = getSaveSourceExperience({
|
|
13
|
+
refs,
|
|
14
|
+
dispatchAnalyticsEvent
|
|
15
|
+
});
|
|
16
|
+
syncBlockStore.sourceManager.setSaveExperience(saveSourceExperience);
|
|
17
|
+
const saveReferenceExperience = getSaveReferenceExperience({
|
|
18
|
+
refs,
|
|
19
|
+
dispatchAnalyticsEvent
|
|
20
|
+
});
|
|
21
|
+
const fetchExperience = getFetchExperience({
|
|
22
|
+
refs,
|
|
23
|
+
dispatchAnalyticsEvent
|
|
24
|
+
});
|
|
25
|
+
const fetchSourceInfoExperience = getFetchSourceInfoExperience({
|
|
26
|
+
refs,
|
|
27
|
+
dispatchAnalyticsEvent
|
|
28
|
+
});
|
|
29
|
+
syncBlockStore.referenceManager.setExperiences(fetchExperience, fetchSourceInfoExperience, saveReferenceExperience);
|
|
30
|
+
return new SafePlugin({
|
|
31
|
+
key: pluginKey,
|
|
32
|
+
view: () => {
|
|
33
|
+
return {
|
|
34
|
+
destroy: () => {
|
|
35
|
+
saveSourceExperience.abort({
|
|
36
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
37
|
+
});
|
|
38
|
+
saveReferenceExperience.abort({
|
|
39
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
40
|
+
});
|
|
41
|
+
fetchExperience.abort({
|
|
42
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
43
|
+
});
|
|
44
|
+
fetchSourceInfoExperience.abort({
|
|
45
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* This experience tracks when a source sync block is saved to the BE.
|
|
55
|
+
*
|
|
56
|
+
* Start: When the flush source sync block function is called.
|
|
57
|
+
* Success: When the sync block save is successful within 1500ms of start.
|
|
58
|
+
* Failure: When 1500ms passes without the sync block being successfully saved
|
|
59
|
+
*/
|
|
60
|
+
const getSaveSourceExperience = ({
|
|
61
|
+
dispatchAnalyticsEvent
|
|
62
|
+
}) => {
|
|
63
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
64
|
+
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE,
|
|
65
|
+
dispatchAnalyticsEvent,
|
|
66
|
+
checks: [new ExperienceCheckTimeout({
|
|
67
|
+
durationMs: 1500
|
|
68
|
+
})]
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* This experience tracks when a reference sync block is saved to the BE.
|
|
74
|
+
*
|
|
75
|
+
* Start: When the flush sync block function is called.
|
|
76
|
+
* Success: When the sync block save is successful within 1500ms of start.
|
|
77
|
+
* Failure: When 1500ms passes without the sync block being successfully saved
|
|
78
|
+
*/
|
|
79
|
+
const getSaveReferenceExperience = ({
|
|
80
|
+
dispatchAnalyticsEvent
|
|
81
|
+
}) => {
|
|
82
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
83
|
+
actionSubjectId: ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE,
|
|
84
|
+
dispatchAnalyticsEvent,
|
|
85
|
+
checks: [new ExperienceCheckTimeout({
|
|
86
|
+
durationMs: 1500
|
|
87
|
+
})]
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* This experience tracks when a reference sync block data is fetched from the BE.
|
|
93
|
+
*
|
|
94
|
+
* Start: When the fetchNodesData function is called.
|
|
95
|
+
* Success: When the fetching the data is successful within 1500ms of start.
|
|
96
|
+
* Failure: When 1500ms passes without the data being successfully fetched, or the fetch fails
|
|
97
|
+
*/
|
|
98
|
+
const getFetchExperience = ({
|
|
99
|
+
dispatchAnalyticsEvent
|
|
100
|
+
}) => {
|
|
101
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
102
|
+
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH,
|
|
103
|
+
dispatchAnalyticsEvent,
|
|
104
|
+
checks: [new ExperienceCheckTimeout({
|
|
105
|
+
durationMs: 1500
|
|
106
|
+
})]
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* This experience tracks when a reference sync block source info data (title, url) is fetched from the BE.
|
|
112
|
+
*
|
|
113
|
+
* Start: When the fetchSourceInfo function is called.
|
|
114
|
+
* Success: When the fetching the data is successful within 2500ms of start.
|
|
115
|
+
* Failure: When 2500ms passes without the data being successfully fetched, or the fetch fails
|
|
116
|
+
*/
|
|
117
|
+
const getFetchSourceInfoExperience = ({
|
|
118
|
+
dispatchAnalyticsEvent
|
|
119
|
+
}) => {
|
|
120
|
+
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
121
|
+
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO,
|
|
122
|
+
dispatchAnalyticsEvent,
|
|
123
|
+
checks: [new ExperienceCheckTimeout({
|
|
124
|
+
durationMs: 2500
|
|
125
|
+
})]
|
|
126
|
+
});
|
|
127
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { pmHistoryPluginKey } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { findChildren } from '@atlaskit/editor-prosemirror/utils';
|
|
3
|
+
let targetEl;
|
|
4
|
+
export const getTarget = containerElement => {
|
|
5
|
+
if (!targetEl) {
|
|
6
|
+
const element = containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelector('.ProseMirror');
|
|
7
|
+
if (!element || !(element instanceof HTMLElement)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
targetEl = element;
|
|
11
|
+
}
|
|
12
|
+
return targetEl;
|
|
13
|
+
};
|
|
14
|
+
export const wasSyncBlockDeletedOrAddedByHistory = (tr, oldState, newState) => {
|
|
15
|
+
const historyMeta = tr.getMeta(pmHistoryPluginKey);
|
|
16
|
+
if (!Boolean(historyMeta)) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
const {
|
|
20
|
+
syncBlock
|
|
21
|
+
} = newState.schema.nodes;
|
|
22
|
+
const oldSyncBlockNodes = findChildren(oldState.doc, node => node.type === syncBlock);
|
|
23
|
+
const newSyncBlockNodes = findChildren(newState.doc, node => node.type === syncBlock);
|
|
24
|
+
const oldSyncBlockIds = new Set(oldSyncBlockNodes.map(nodeWithPos => nodeWithPos.node.attrs.localId).filter(localId => Boolean(localId)));
|
|
25
|
+
const newSyncBlockIds = new Set(newSyncBlockNodes.map(nodeWithPos => nodeWithPos.node.attrs.localId).filter(localId => Boolean(localId)));
|
|
26
|
+
const hasDeletedSyncBlock = Array.from(oldSyncBlockIds).some(localId => !newSyncBlockIds.has(localId));
|
|
27
|
+
const hasAddedSyncBlock = Array.from(newSyncBlockIds).some(localId => !oldSyncBlockIds.has(localId));
|
|
28
|
+
return {
|
|
29
|
+
hasDeletedSyncBlock,
|
|
30
|
+
hasAddedSyncBlock,
|
|
31
|
+
isUndo: historyMeta.redo === false
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const getResourceIds = (nodes, resourceIds, query) => {
|
|
35
|
+
nodes.forEach(node => {
|
|
36
|
+
if (!(node instanceof HTMLElement)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const syncBlockElements = node.querySelectorAll(query);
|
|
40
|
+
syncBlockElements.forEach(element => {
|
|
41
|
+
const resourceId = element.getAttribute('resourceid');
|
|
42
|
+
if (resourceId) {
|
|
43
|
+
resourceIds.push(resourceId);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export const getAddedResourceIds = (mutations, query) => {
|
|
49
|
+
const resourceIds = [];
|
|
50
|
+
mutations.forEach(mutation => {
|
|
51
|
+
if (mutation.type === 'childList') {
|
|
52
|
+
getResourceIds(mutation.addedNodes, resourceIds, query);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return resourceIds;
|
|
56
|
+
};
|
|
57
|
+
export const getRemovedResourceIds = (mutations, query) => {
|
|
58
|
+
const resourceIds = [];
|
|
59
|
+
mutations.forEach(mutation => {
|
|
60
|
+
if (mutation.type === 'childList') {
|
|
61
|
+
getResourceIds(mutation.removedNodes, resourceIds, query);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return resourceIds;
|
|
65
|
+
};
|
|
@@ -5,4 +5,7 @@ export let FLAG_ID = /*#__PURE__*/function (FLAG_ID) {
|
|
|
5
5
|
FLAG_ID["FAIL_TO_DELETE"] = "fail-to-delete";
|
|
6
6
|
FLAG_ID["SYNC_BLOCK_COPIED"] = "sync-block-copied";
|
|
7
7
|
return FLAG_ID;
|
|
8
|
-
}({});
|
|
8
|
+
}({});
|
|
9
|
+
export const EXPERIENCE_ABORT_REASON = {
|
|
10
|
+
EDITOR_DESTROYED: 'editor-destroyed'
|
|
11
|
+
};
|
|
@@ -43,17 +43,48 @@ const CreateSyncedBlockDropdownItem = ({
|
|
|
43
43
|
}),
|
|
44
44
|
onClick: onClick,
|
|
45
45
|
isDisabled: isOffline,
|
|
46
|
-
testId:
|
|
46
|
+
testId: "create-synced-block-block-menu-btn",
|
|
47
47
|
elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
|
|
48
48
|
appearance: "new"
|
|
49
49
|
}, formatMessage(blockMenuMessages.newLozenge))
|
|
50
50
|
}, formatMessage(blockMenuMessages.createSyncedBlock));
|
|
51
51
|
};
|
|
52
|
+
const CopySyncedBlockDropdownItem = ({
|
|
53
|
+
api
|
|
54
|
+
}) => {
|
|
55
|
+
const {
|
|
56
|
+
formatMessage
|
|
57
|
+
} = useIntl();
|
|
58
|
+
const {
|
|
59
|
+
mode
|
|
60
|
+
} = useSharedPluginStateWithSelector(api, ['connectivity'], states => {
|
|
61
|
+
var _states$connectivityS2;
|
|
62
|
+
return {
|
|
63
|
+
mode: (_states$connectivityS2 = states.connectivityState) === null || _states$connectivityS2 === void 0 ? void 0 : _states$connectivityS2.mode
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
const onClick = () => {
|
|
67
|
+
var _api$core3, _api$core4, _api$blockControls2, _api$blockControls2$c;
|
|
68
|
+
api === null || api === void 0 ? void 0 : (_api$core3 = api.core) === null || _api$core3 === void 0 ? void 0 : _api$core3.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.copySyncedBlockReferenceToClipboard());
|
|
69
|
+
api === null || api === void 0 ? void 0 : (_api$core4 = api.core) === null || _api$core4 === void 0 ? void 0 : _api$core4.actions.execute(api === null || api === void 0 ? void 0 : (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 ? void 0 : (_api$blockControls2$c = _api$blockControls2.commands) === null || _api$blockControls2$c === void 0 ? void 0 : _api$blockControls2$c.toggleBlockMenu({
|
|
70
|
+
closeMenu: true
|
|
71
|
+
}));
|
|
72
|
+
};
|
|
73
|
+
return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
|
|
74
|
+
elemBefore: /*#__PURE__*/React.createElement(SyncBlocksIcon, {
|
|
75
|
+
label: ""
|
|
76
|
+
}),
|
|
77
|
+
onClick: onClick,
|
|
78
|
+
isDisabled: isOfflineMode(mode),
|
|
79
|
+
elemAfter: /*#__PURE__*/React.createElement(Lozenge, {
|
|
80
|
+
appearance: "new"
|
|
81
|
+
}, formatMessage(blockMenuMessages.newLozenge))
|
|
82
|
+
}, formatMessage(blockMenuMessages.copySyncedBlock));
|
|
83
|
+
};
|
|
52
84
|
export const CreateOrCopySyncedBlockDropdownItem = ({
|
|
53
85
|
api,
|
|
54
86
|
enableSourceSyncedBlockCreation
|
|
55
87
|
}) => {
|
|
56
|
-
var _menuTriggerByNode$no;
|
|
57
88
|
const {
|
|
58
89
|
menuTriggerByNode
|
|
59
90
|
} = useSharedPluginStateWithSelector(api, ['blockControls'], states => {
|
|
@@ -62,7 +93,11 @@ export const CreateOrCopySyncedBlockDropdownItem = ({
|
|
|
62
93
|
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
|
|
63
94
|
};
|
|
64
95
|
});
|
|
65
|
-
if (
|
|
96
|
+
if ((menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'syncBlock' || (menuTriggerByNode === null || menuTriggerByNode === void 0 ? void 0 : menuTriggerByNode.nodeType) === 'bodiedSyncBlock') {
|
|
97
|
+
return /*#__PURE__*/React.createElement(CopySyncedBlockDropdownItem, {
|
|
98
|
+
api: api
|
|
99
|
+
});
|
|
100
|
+
} else if (enableSourceSyncedBlockCreation) {
|
|
66
101
|
return /*#__PURE__*/React.createElement(CreateSyncedBlockDropdownItem, {
|
|
67
102
|
api: api
|
|
68
103
|
});
|
|
@@ -5,6 +5,7 @@ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'
|
|
|
5
5
|
import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
6
6
|
import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
|
|
7
7
|
import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
|
|
8
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
9
|
import { Text } from '@atlaskit/primitives/compiled';
|
|
9
10
|
import { syncedBlockPluginKey } from '../pm-plugins/main';
|
|
10
11
|
export const DeleteConfirmationModal = ({
|
|
@@ -105,6 +106,7 @@ export const DeleteConfirmationModal = ({
|
|
|
105
106
|
onClick: handleClick(true),
|
|
106
107
|
autoFocus: true,
|
|
107
108
|
isDisabled: isOfflineMode(mode),
|
|
108
|
-
isLoading: bodiedSyncBlockDeletionStatus === 'processing'
|
|
109
|
+
isLoading: bodiedSyncBlockDeletionStatus === 'processing',
|
|
110
|
+
testId: fg('platform_synced_block_dogfooding') ? 'synced-block-delete-confirmation-modal-delete-button' : undefined
|
|
109
111
|
}, formatMessage(messages.deleteConfirmationModalDeleteButton)))));
|
|
110
112
|
};
|
|
@@ -6,6 +6,7 @@ import { SyncBlockError } from '@atlaskit/editor-synced-block-provider';
|
|
|
6
6
|
import CopyIcon from '@atlaskit/icon/core/copy';
|
|
7
7
|
import DeleteIcon from '@atlaskit/icon/core/delete';
|
|
8
8
|
import EditIcon from '@atlaskit/icon/core/edit';
|
|
9
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
10
|
import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../editor-commands';
|
|
10
11
|
import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
|
|
11
12
|
export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
|
|
@@ -42,6 +43,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
|
|
|
42
43
|
title: formatMessage(commonMessages.delete),
|
|
43
44
|
onClick: removeSyncedBlock(api),
|
|
44
45
|
icon: DeleteIcon,
|
|
46
|
+
testId: fg('platform_synced_block_dogfooding') ? 'reference-synced-block-delete-button' : undefined,
|
|
45
47
|
...hoverDecorationProps(nodeType, akEditorSelectedNodeClassName)
|
|
46
48
|
};
|
|
47
49
|
items.push(deleteButton);
|
|
@@ -53,7 +55,7 @@ export const getToolbarConfig = (state, intl, api, syncBlockStore) => {
|
|
|
53
55
|
icon: CopyIcon,
|
|
54
56
|
title: formatMessage(messages.copySyncBlockLabel),
|
|
55
57
|
showTitle: false,
|
|
56
|
-
tooltipContent: formatMessage(messages.
|
|
58
|
+
tooltipContent: formatMessage(messages.copySyncedBlockTooltip),
|
|
57
59
|
onClick: copySyncedBlockReferenceToClipboard(syncBlockStore, api),
|
|
58
60
|
...hoverDecorationProps(nodeType, akEditorSelectedNodeClassName)
|
|
59
61
|
};
|
|
@@ -53,8 +53,8 @@ export var createSyncedBlock = function createSyncedBlock(_ref) {
|
|
|
53
53
|
syncBlockStore.sourceManager.createBodiedSyncBlockNode(_attrs);
|
|
54
54
|
tr.replaceWith(conversionInfo.from > 0 ? conversionInfo.from - 1 : 0, conversionInfo.to, _newBodiedSyncBlockNode).scrollIntoView();
|
|
55
55
|
|
|
56
|
-
// set selection to the
|
|
57
|
-
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.
|
|
56
|
+
// set selection to the start of the previous selection for the position taken up by the start of the new synced block
|
|
57
|
+
tr.setSelection(TextSelection.create(tr.doc, conversionInfo.from));
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// This transaction will be intercepted in filterTransaction and dispatched when saving to backend succeeds
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
1
|
import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
3
2
|
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout } from '@atlaskit/editor-common/experiences';
|
|
4
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
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';
|
|
6
7
|
var isPastedFromFabricEditor = function isPastedFromFabricEditor(html) {
|
|
7
8
|
return !!html && html.indexOf('data-pm-slice="') >= 0;
|
|
8
9
|
};
|
|
9
10
|
var pluginKey = new PluginKey('createReferenceSyncBlockExperience');
|
|
10
11
|
var START_METHOD = {
|
|
11
|
-
PASTE: 'paste'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
EDITOR_DESTROYED: 'editor-destroyed'
|
|
12
|
+
PASTE: 'paste',
|
|
13
|
+
UNDO: 'undo',
|
|
14
|
+
REDO: 'redo'
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -34,7 +34,7 @@ export var getCreateReferenceExperiencePlugin = function getCreateReferenceExper
|
|
|
34
34
|
return {
|
|
35
35
|
destroy: function destroy() {
|
|
36
36
|
experience.abort({
|
|
37
|
-
reason:
|
|
37
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
};
|
|
@@ -56,6 +56,19 @@ export var getCreateReferenceExperiencePlugin = function getCreateReferenceExper
|
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
},
|
|
60
|
+
appendTransaction: function appendTransaction(transactions, oldState, newState) {
|
|
61
|
+
transactions.forEach(function (tr) {
|
|
62
|
+
var _wasSyncBlockDeletedO = wasSyncBlockDeletedOrAddedByHistory(tr, oldState, newState),
|
|
63
|
+
hasAddedSyncBlock = _wasSyncBlockDeletedO.hasAddedSyncBlock,
|
|
64
|
+
isUndo = _wasSyncBlockDeletedO.isUndo;
|
|
65
|
+
if (hasAddedSyncBlock) {
|
|
66
|
+
experience.start({
|
|
67
|
+
method: isUndo ? START_METHOD.UNDO : START_METHOD.REDO
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return null;
|
|
59
72
|
}
|
|
60
73
|
});
|
|
61
74
|
};
|
|
@@ -70,21 +83,20 @@ var getCreateReferenceExperience = function getCreateReferenceExperience(_ref2)
|
|
|
70
83
|
}), new ExperienceCheckDomMutation({
|
|
71
84
|
onDomMutation: function onDomMutation(_ref3) {
|
|
72
85
|
var mutations = _ref3.mutations;
|
|
73
|
-
|
|
86
|
+
var insertedResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="syncBlock"]');
|
|
87
|
+
if (insertedResourceIds.length > 0) {
|
|
74
88
|
return {
|
|
75
|
-
status: 'success'
|
|
89
|
+
status: 'success',
|
|
90
|
+
metadata: {
|
|
91
|
+
insertedResourceIds: insertedResourceIds
|
|
92
|
+
}
|
|
76
93
|
};
|
|
77
94
|
}
|
|
78
95
|
return undefined;
|
|
79
96
|
},
|
|
80
97
|
observeConfig: function observeConfig() {
|
|
81
|
-
var _refs$containerElemen;
|
|
82
|
-
var 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
98
|
return {
|
|
87
|
-
target:
|
|
99
|
+
target: getTarget(refs.containerElement),
|
|
88
100
|
options: {
|
|
89
101
|
childList: true
|
|
90
102
|
}
|
|
@@ -92,15 +104,4 @@ var getCreateReferenceExperience = function getCreateReferenceExperience(_ref2)
|
|
|
92
104
|
}
|
|
93
105
|
})]
|
|
94
106
|
});
|
|
95
|
-
};
|
|
96
|
-
var isReferenceSyncBlockAddedInMutation = function isReferenceSyncBlockAddedInMutation(_ref4) {
|
|
97
|
-
var type = _ref4.type,
|
|
98
|
-
addedNodes = _ref4.addedNodes;
|
|
99
|
-
return type === 'childList' && _toConsumableArray(addedNodes).some(isReferenceSyncBlockNode);
|
|
100
|
-
};
|
|
101
|
-
var isReferenceSyncBlockNode = function isReferenceSyncBlockNode(node) {
|
|
102
|
-
if (!(node instanceof HTMLElement)) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
return !!node.querySelector('[data-prosemirror-node-name="syncBlock"]');
|
|
106
107
|
};
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
1
|
import { bind } from 'bind-event-listener';
|
|
3
2
|
import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
4
3
|
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView, popupWithNestedElement } from '@atlaskit/editor-common/experiences';
|
|
5
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
6
5
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
|
+
import { EXPERIENCE_ABORT_REASON } from '../../types';
|
|
7
|
+
import { getAddedResourceIds, getTarget } from '../utils/experience-tracking-utils';
|
|
7
8
|
var pluginKey = new PluginKey('createSourceSyncBlockExperience');
|
|
8
|
-
var ABORT_REASON = {
|
|
9
|
-
EDITOR_DESTROYED: 'editor-destroyed'
|
|
10
|
-
};
|
|
11
9
|
var START_METHOD = {
|
|
12
10
|
BLOCK_MENU: 'block-menu',
|
|
13
11
|
PINNED_TOOLBAR: 'pinned-toolbar',
|
|
@@ -20,8 +18,8 @@ var syncedBlockCreateButtonIds = new Set(SYNCED_BLOCK_CREATE_BUTTON_IDS);
|
|
|
20
18
|
* This experience tracks when a source sync block is inserted.
|
|
21
19
|
*
|
|
22
20
|
* Start: When user inserts a sync block via block menu, quick insert or pinned toolbar
|
|
23
|
-
* Success: When the sync block is added to the DOM within
|
|
24
|
-
* 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
|
|
25
23
|
*/
|
|
26
24
|
export var getCreateSourceExperiencePlugin = function getCreateSourceExperiencePlugin(_ref) {
|
|
27
25
|
var refs = _ref.refs,
|
|
@@ -37,8 +35,7 @@ export var getCreateSourceExperiencePlugin = function getCreateSourceExperienceP
|
|
|
37
35
|
};
|
|
38
36
|
var experience = getCreateSourceExperience({
|
|
39
37
|
refs: refs,
|
|
40
|
-
dispatchAnalyticsEvent: dispatchAnalyticsEvent
|
|
41
|
-
syncBlockStore: syncBlockStore
|
|
38
|
+
dispatchAnalyticsEvent: dispatchAnalyticsEvent
|
|
42
39
|
});
|
|
43
40
|
syncBlockStore.sourceManager.setCreateExperience(experience);
|
|
44
41
|
var unbindClickListener = bind(document, {
|
|
@@ -90,7 +87,7 @@ export var getCreateSourceExperiencePlugin = function getCreateSourceExperienceP
|
|
|
90
87
|
return {
|
|
91
88
|
destroy: function destroy() {
|
|
92
89
|
experience.abort({
|
|
93
|
-
reason:
|
|
90
|
+
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
94
91
|
});
|
|
95
92
|
unbindClickListener();
|
|
96
93
|
unbindKeydownListener();
|
|
@@ -106,25 +103,24 @@ var getCreateSourceExperience = function getCreateSourceExperience(_ref2) {
|
|
|
106
103
|
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
|
|
107
104
|
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
108
105
|
checks: [new ExperienceCheckTimeout({
|
|
109
|
-
durationMs:
|
|
106
|
+
durationMs: 3000
|
|
110
107
|
}), new ExperienceCheckDomMutation({
|
|
111
108
|
onDomMutation: function onDomMutation(_ref3) {
|
|
112
109
|
var mutations = _ref3.mutations;
|
|
113
|
-
|
|
110
|
+
var createdResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
111
|
+
if (createdResourceIds.length > 0) {
|
|
114
112
|
return {
|
|
115
|
-
status: 'success'
|
|
113
|
+
status: 'success',
|
|
114
|
+
metadata: {
|
|
115
|
+
createdResourceIds: createdResourceIds
|
|
116
|
+
}
|
|
116
117
|
};
|
|
117
118
|
}
|
|
118
119
|
return undefined;
|
|
119
120
|
},
|
|
120
121
|
observeConfig: function observeConfig() {
|
|
121
|
-
var _refs$containerElemen;
|
|
122
|
-
var proseMirrorElement = (_refs$containerElemen = refs.containerElement) === null || _refs$containerElemen === void 0 ? void 0 : _refs$containerElemen.querySelector('.ProseMirror');
|
|
123
|
-
if (!proseMirrorElement || !(proseMirrorElement instanceof HTMLElement)) {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
122
|
return {
|
|
127
|
-
target:
|
|
123
|
+
target: getTarget(refs.containerElement),
|
|
128
124
|
options: {
|
|
129
125
|
childList: true
|
|
130
126
|
}
|
|
@@ -164,15 +160,4 @@ var handleButtonClick = function handleButtonClick(testId, experience) {
|
|
|
164
160
|
};
|
|
165
161
|
var isEnterKey = function isEnterKey(key) {
|
|
166
162
|
return key === 'Enter';
|
|
167
|
-
};
|
|
168
|
-
var isSourceSyncBlockAddedInMutation = function isSourceSyncBlockAddedInMutation(_ref4) {
|
|
169
|
-
var type = _ref4.type,
|
|
170
|
-
addedNodes = _ref4.addedNodes;
|
|
171
|
-
return type === 'childList' && _toConsumableArray(addedNodes).some(isSourceSyncBlockNode);
|
|
172
|
-
};
|
|
173
|
-
var isSourceSyncBlockNode = function isSourceSyncBlockNode(node) {
|
|
174
|
-
if (!(node instanceof HTMLElement)) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
return !!node.querySelector('[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
178
163
|
};
|