@atlaskit/editor-plugin-synced-block 5.2.1 → 5.2.2
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 +9 -0
- package/afm-jira/tsconfig.json +1 -1
- package/dist/cjs/editor-commands/index.js +10 -4
- package/dist/cjs/pm-plugins/menu-and-toolbar-experiences.js +267 -0
- package/dist/cjs/syncedBlockPlugin.js +21 -12
- package/dist/cjs/types/index.js +6 -3
- package/dist/cjs/ui/CreateSyncedBlockButton.js +2 -1
- package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +2 -1
- package/dist/cjs/ui/floating-toolbar.js +2 -1
- package/dist/es2019/editor-commands/index.js +10 -4
- package/dist/es2019/pm-plugins/menu-and-toolbar-experiences.js +261 -0
- package/dist/es2019/syncedBlockPlugin.js +19 -12
- package/dist/es2019/types/index.js +5 -2
- package/dist/es2019/ui/CreateSyncedBlockButton.js +2 -1
- package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +2 -1
- package/dist/es2019/ui/floating-toolbar.js +2 -1
- package/dist/esm/editor-commands/index.js +10 -4
- package/dist/esm/pm-plugins/menu-and-toolbar-experiences.js +260 -0
- package/dist/esm/syncedBlockPlugin.js +21 -12
- package/dist/esm/types/index.js +5 -2
- package/dist/esm/ui/CreateSyncedBlockButton.js +2 -1
- package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +2 -1
- package/dist/esm/ui/floating-toolbar.js +2 -1
- package/dist/types/editor-commands/index.d.ts +3 -1
- package/dist/types/pm-plugins/menu-and-toolbar-experiences.d.ts +12 -0
- package/dist/types/types/index.d.ts +5 -14
- package/dist/types-ts4.5/editor-commands/index.d.ts +3 -1
- package/dist/types-ts4.5/pm-plugins/menu-and-toolbar-experiences.d.ts +12 -0
- package/dist/types-ts4.5/types/index.d.ts +5 -14
- package/package.json +3 -3
- package/dist/cjs/pm-plugins/experience-tracking/create-reference-experience.js +0 -113
- package/dist/cjs/pm-plugins/experience-tracking/create-source-experience.js +0 -169
- package/dist/cjs/pm-plugins/experience-tracking/delete-reference-experience.js +0 -175
- package/dist/cjs/pm-plugins/experience-tracking/delete-source-experience.js +0 -103
- package/dist/cjs/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -61
- package/dist/cjs/pm-plugins/experience-tracking/provider-only-experiences.js +0 -128
- package/dist/cjs/pm-plugins/utils/experience-tracking-utils.js +0 -85
- package/dist/es2019/pm-plugins/experience-tracking/create-reference-experience.js +0 -109
- package/dist/es2019/pm-plugins/experience-tracking/create-source-experience.js +0 -166
- package/dist/es2019/pm-plugins/experience-tracking/delete-reference-experience.js +0 -181
- package/dist/es2019/pm-plugins/experience-tracking/delete-source-experience.js +0 -98
- package/dist/es2019/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -46
- package/dist/es2019/pm-plugins/experience-tracking/provider-only-experiences.js +0 -127
- package/dist/es2019/pm-plugins/utils/experience-tracking-utils.js +0 -65
- package/dist/esm/pm-plugins/experience-tracking/create-reference-experience.js +0 -107
- package/dist/esm/pm-plugins/experience-tracking/create-source-experience.js +0 -163
- package/dist/esm/pm-plugins/experience-tracking/delete-reference-experience.js +0 -169
- package/dist/esm/pm-plugins/experience-tracking/delete-source-experience.js +0 -97
- package/dist/esm/pm-plugins/experience-tracking/get-experience-tracking-plugins.js +0 -55
- package/dist/esm/pm-plugins/experience-tracking/provider-only-experiences.js +0 -122
- package/dist/esm/pm-plugins/utils/experience-tracking-utils.js +0 -79
- package/dist/types/pm-plugins/experience-tracking/create-reference-experience.d.ts +0 -10
- package/dist/types/pm-plugins/experience-tracking/create-source-experience.d.ts +0 -10
- package/dist/types/pm-plugins/experience-tracking/delete-reference-experience.d.ts +0 -13
- package/dist/types/pm-plugins/experience-tracking/delete-source-experience.d.ts +0 -12
- package/dist/types/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +0 -5
- package/dist/types/pm-plugins/experience-tracking/provider-only-experiences.d.ts +0 -3
- package/dist/types/pm-plugins/utils/experience-tracking-utils.d.ts +0 -9
- package/dist/types-ts4.5/pm-plugins/experience-tracking/create-reference-experience.d.ts +0 -10
- package/dist/types-ts4.5/pm-plugins/experience-tracking/create-source-experience.d.ts +0 -10
- package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-reference-experience.d.ts +0 -13
- package/dist/types-ts4.5/pm-plugins/experience-tracking/delete-source-experience.d.ts +0 -12
- package/dist/types-ts4.5/pm-plugins/experience-tracking/get-experience-tracking-plugins.d.ts +0 -5
- package/dist/types-ts4.5/pm-plugins/experience-tracking/provider-only-experiences.d.ts +0 -3
- package/dist/types-ts4.5/pm-plugins/utils/experience-tracking-utils.d.ts +0 -9
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { bind } from 'bind-event-listener';
|
|
2
|
-
import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics';
|
|
3
|
-
import { Experience, ExperienceCheckDomMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView, popupWithNestedElement } 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 { getAddedResourceIds, getTarget } from '../utils/experience-tracking-utils';
|
|
8
|
-
const pluginKey = new PluginKey('createSourceSyncBlockExperience');
|
|
9
|
-
const START_METHOD = {
|
|
10
|
-
BLOCK_MENU: 'block-menu',
|
|
11
|
-
PINNED_TOOLBAR: 'pinned-toolbar',
|
|
12
|
-
QUICK_INSERT: 'quick-insert'
|
|
13
|
-
};
|
|
14
|
-
const SYNCED_BLOCK_CREATE_BUTTON_IDS = ['create-synced-block-toolbar-btn', 'create-synced-block-block-menu-btn', 'create-synced-block-quick-insert-btn'];
|
|
15
|
-
const syncedBlockCreateButtonIds = new Set(SYNCED_BLOCK_CREATE_BUTTON_IDS);
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* This experience tracks when a source sync block is inserted.
|
|
19
|
-
*
|
|
20
|
-
* Start: When user inserts a sync block via block menu, quick insert or pinned toolbar
|
|
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
|
|
23
|
-
*/
|
|
24
|
-
export const getCreateSourceExperiencePlugin = ({
|
|
25
|
-
refs,
|
|
26
|
-
dispatchAnalyticsEvent,
|
|
27
|
-
syncBlockStore
|
|
28
|
-
}) => {
|
|
29
|
-
let popupsTargetEl;
|
|
30
|
-
let editorViewEl;
|
|
31
|
-
const getPopupsTarget = () => {
|
|
32
|
-
if (!popupsTargetEl) {
|
|
33
|
-
popupsTargetEl = refs.popupsMountPoint || refs.wrapperElement || getPopupContainerFromEditorView(editorViewEl);
|
|
34
|
-
}
|
|
35
|
-
return popupsTargetEl;
|
|
36
|
-
};
|
|
37
|
-
const experience = getCreateSourceExperience({
|
|
38
|
-
refs,
|
|
39
|
-
dispatchAnalyticsEvent
|
|
40
|
-
});
|
|
41
|
-
syncBlockStore.sourceManager.setCreateExperience(experience);
|
|
42
|
-
const unbindClickListener = bind(document, {
|
|
43
|
-
type: 'click',
|
|
44
|
-
listener: event => {
|
|
45
|
-
const target = event.target;
|
|
46
|
-
if (!target) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const button = target.closest('button[data-testid]');
|
|
50
|
-
if (!button || !(button instanceof HTMLButtonElement)) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const testId = button.dataset.testid;
|
|
54
|
-
if (!isSyncedBlockCreateButtonId(testId)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
handleButtonClick(testId, experience);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
const unbindKeydownListener = bind(document, {
|
|
61
|
-
type: 'keydown',
|
|
62
|
-
listener: event => {
|
|
63
|
-
if (isEnterKey(event.key)) {
|
|
64
|
-
const typeaheadPopup = popupWithNestedElement(getPopupsTarget(), '.fabric-editor-typeahead');
|
|
65
|
-
if (!typeaheadPopup || !(typeaheadPopup instanceof HTMLElement)) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const firstItem = typeaheadPopup.querySelector('[role="option"]');
|
|
69
|
-
if (!firstItem || !(firstItem instanceof HTMLElement)) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const testId = firstItem.dataset.testid;
|
|
73
|
-
if (testId === 'create-synced-block-quick-insert-btn') {
|
|
74
|
-
experience.start({
|
|
75
|
-
method: START_METHOD.QUICK_INSERT
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
options: {
|
|
81
|
-
capture: true
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
return new SafePlugin({
|
|
85
|
-
key: pluginKey,
|
|
86
|
-
view: editorView => {
|
|
87
|
-
editorViewEl = editorView.dom;
|
|
88
|
-
return {
|
|
89
|
-
destroy: () => {
|
|
90
|
-
experience.abort({
|
|
91
|
-
reason: EXPERIENCE_ABORT_REASON.EDITOR_DESTROYED
|
|
92
|
-
});
|
|
93
|
-
unbindClickListener();
|
|
94
|
-
unbindKeydownListener();
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
const getCreateSourceExperience = ({
|
|
101
|
-
refs,
|
|
102
|
-
dispatchAnalyticsEvent
|
|
103
|
-
}) => {
|
|
104
|
-
return new Experience(ACTION_SUBJECT.SYNCED_BLOCK, {
|
|
105
|
-
actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
|
|
106
|
-
dispatchAnalyticsEvent,
|
|
107
|
-
checks: [new ExperienceCheckTimeout({
|
|
108
|
-
durationMs: 3000
|
|
109
|
-
}), new ExperienceCheckDomMutation({
|
|
110
|
-
onDomMutation: ({
|
|
111
|
-
mutations
|
|
112
|
-
}) => {
|
|
113
|
-
const createdResourceIds = getAddedResourceIds(mutations, '[data-prosemirror-node-name="bodiedSyncBlock"]');
|
|
114
|
-
if (createdResourceIds.length > 0) {
|
|
115
|
-
return {
|
|
116
|
-
status: 'success',
|
|
117
|
-
metadata: {
|
|
118
|
-
createdResourceIds
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
return undefined;
|
|
123
|
-
},
|
|
124
|
-
observeConfig: () => {
|
|
125
|
-
return {
|
|
126
|
-
target: getTarget(refs.containerElement),
|
|
127
|
-
options: {
|
|
128
|
-
childList: true
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
})]
|
|
133
|
-
});
|
|
134
|
-
};
|
|
135
|
-
const isSyncedBlockCreateButtonId = value => {
|
|
136
|
-
return !!value && syncedBlockCreateButtonIds.has(value);
|
|
137
|
-
};
|
|
138
|
-
const handleButtonClick = (testId, experience) => {
|
|
139
|
-
switch (testId) {
|
|
140
|
-
case 'create-synced-block-toolbar-btn':
|
|
141
|
-
experience.start({
|
|
142
|
-
method: START_METHOD.PINNED_TOOLBAR
|
|
143
|
-
});
|
|
144
|
-
break;
|
|
145
|
-
case 'create-synced-block-block-menu-btn':
|
|
146
|
-
experience.start({
|
|
147
|
-
method: START_METHOD.BLOCK_MENU
|
|
148
|
-
});
|
|
149
|
-
break;
|
|
150
|
-
case 'create-synced-block-quick-insert-btn':
|
|
151
|
-
experience.start({
|
|
152
|
-
method: START_METHOD.QUICK_INSERT
|
|
153
|
-
});
|
|
154
|
-
break;
|
|
155
|
-
default:
|
|
156
|
-
{
|
|
157
|
-
// Exhaustiveness check: if a new SyncedBlockToolbarButtonId is added
|
|
158
|
-
// but not handled above, TypeScript will error here.
|
|
159
|
-
const _exhaustiveCheck = testId;
|
|
160
|
-
return _exhaustiveCheck;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
const isEnterKey = key => {
|
|
165
|
-
return key === 'Enter';
|
|
166
|
-
};
|
|
@@ -1,181 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,98 +0,0 @@
|
|
|
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,46 +0,0 @@
|
|
|
1
|
-
import { getCreateReferenceExperiencePlugin } from "./create-reference-experience";
|
|
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";
|
|
6
|
-
export const getExperienceTrackingPlugins = ({
|
|
7
|
-
refs,
|
|
8
|
-
dispatchAnalyticsEvent,
|
|
9
|
-
syncBlockStore
|
|
10
|
-
}) => {
|
|
11
|
-
return [{
|
|
12
|
-
name: 'createReferenceSyncedBlockExperiencePlugin',
|
|
13
|
-
plugin: () => getCreateReferenceExperiencePlugin({
|
|
14
|
-
refs,
|
|
15
|
-
dispatchAnalyticsEvent
|
|
16
|
-
})
|
|
17
|
-
}, {
|
|
18
|
-
name: 'createSourceSyncedBlockExperiencePlugin',
|
|
19
|
-
plugin: () => getCreateSourceExperiencePlugin({
|
|
20
|
-
refs,
|
|
21
|
-
dispatchAnalyticsEvent,
|
|
22
|
-
syncBlockStore
|
|
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
|
-
})
|
|
45
|
-
}];
|
|
46
|
-
};
|
|
@@ -1,127 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
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
|
-
};
|