@atlaskit/editor-plugin-paste 0.1.22 → 0.2.0

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.
Files changed (78) hide show
  1. package/.eslintrc.js +18 -0
  2. package/CHANGELOG.md +6 -0
  3. package/dist/cjs/actions.js +12 -0
  4. package/dist/cjs/commands.js +255 -0
  5. package/dist/cjs/edge-cases/index.js +88 -0
  6. package/dist/cjs/edge-cases/lists.js +107 -0
  7. package/dist/cjs/handlers.js +939 -0
  8. package/dist/cjs/index.js +8 -1
  9. package/dist/cjs/plugin.js +43 -0
  10. package/dist/cjs/plugins/media.js +207 -0
  11. package/dist/cjs/pm-plugins/analytics.js +376 -0
  12. package/dist/cjs/pm-plugins/clipboard-text-serializer.js +43 -0
  13. package/dist/cjs/pm-plugins/main.js +484 -0
  14. package/dist/cjs/pm-plugins/plugin-factory.js +42 -0
  15. package/dist/cjs/reducer.js +41 -0
  16. package/dist/cjs/util/index.js +214 -0
  17. package/dist/cjs/util/tinyMCE.js +183 -0
  18. package/dist/es2019/actions.js +6 -0
  19. package/dist/es2019/commands.js +236 -0
  20. package/dist/es2019/edge-cases/index.js +87 -0
  21. package/dist/es2019/edge-cases/lists.js +113 -0
  22. package/dist/es2019/handlers.js +919 -0
  23. package/dist/es2019/index.js +1 -1
  24. package/dist/es2019/plugin.js +38 -0
  25. package/dist/es2019/plugins/media.js +204 -0
  26. package/dist/es2019/pm-plugins/analytics.js +332 -0
  27. package/dist/es2019/pm-plugins/clipboard-text-serializer.js +37 -0
  28. package/dist/es2019/pm-plugins/main.js +453 -0
  29. package/dist/es2019/pm-plugins/plugin-factory.js +30 -0
  30. package/dist/es2019/reducer.js +32 -0
  31. package/dist/es2019/util/index.js +209 -0
  32. package/dist/es2019/util/tinyMCE.js +168 -0
  33. package/dist/esm/actions.js +6 -0
  34. package/dist/esm/commands.js +249 -0
  35. package/dist/esm/edge-cases/index.js +81 -0
  36. package/dist/esm/edge-cases/lists.js +98 -0
  37. package/dist/esm/handlers.js +918 -0
  38. package/dist/esm/index.js +1 -1
  39. package/dist/esm/plugin.js +37 -0
  40. package/dist/esm/plugins/media.js +199 -0
  41. package/dist/esm/pm-plugins/analytics.js +364 -0
  42. package/dist/esm/pm-plugins/clipboard-text-serializer.js +37 -0
  43. package/dist/esm/pm-plugins/main.js +471 -0
  44. package/dist/esm/pm-plugins/plugin-factory.js +36 -0
  45. package/dist/esm/reducer.js +34 -0
  46. package/dist/esm/util/index.js +194 -0
  47. package/dist/esm/util/tinyMCE.js +176 -0
  48. package/dist/types/actions.d.ts +21 -0
  49. package/dist/types/commands.d.ts +29 -0
  50. package/dist/types/edge-cases/index.d.ts +11 -0
  51. package/dist/types/edge-cases/lists.d.ts +18 -0
  52. package/dist/types/handlers.d.ts +55 -0
  53. package/dist/types/index.d.ts +1 -0
  54. package/dist/types/plugin.d.ts +2 -0
  55. package/dist/types/plugins/media.d.ts +23 -0
  56. package/dist/types/pm-plugins/analytics.d.ts +44 -0
  57. package/dist/types/pm-plugins/clipboard-text-serializer.d.ts +13 -0
  58. package/dist/types/pm-plugins/main.d.ts +12 -0
  59. package/dist/types/pm-plugins/plugin-factory.d.ts +3 -0
  60. package/dist/types/reducer.d.ts +3 -0
  61. package/dist/types/util/index.d.ts +21 -0
  62. package/dist/types/util/tinyMCE.d.ts +32 -0
  63. package/dist/types-ts4.5/actions.d.ts +21 -0
  64. package/dist/types-ts4.5/commands.d.ts +29 -0
  65. package/dist/types-ts4.5/edge-cases/index.d.ts +11 -0
  66. package/dist/types-ts4.5/edge-cases/lists.d.ts +18 -0
  67. package/dist/types-ts4.5/handlers.d.ts +55 -0
  68. package/dist/types-ts4.5/index.d.ts +1 -0
  69. package/dist/types-ts4.5/plugin.d.ts +2 -0
  70. package/dist/types-ts4.5/plugins/media.d.ts +23 -0
  71. package/dist/types-ts4.5/pm-plugins/analytics.d.ts +44 -0
  72. package/dist/types-ts4.5/pm-plugins/clipboard-text-serializer.d.ts +13 -0
  73. package/dist/types-ts4.5/pm-plugins/main.d.ts +12 -0
  74. package/dist/types-ts4.5/pm-plugins/plugin-factory.d.ts +3 -0
  75. package/dist/types-ts4.5/reducer.d.ts +3 -0
  76. package/dist/types-ts4.5/util/index.d.ts +21 -0
  77. package/dist/types-ts4.5/util/tinyMCE.d.ts +32 -0
  78. package/package.json +17 -5
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export { pastePlugin } from './plugin';
@@ -0,0 +1,37 @@
1
+ import { createPlugin } from './pm-plugins/main';
2
+ import { pluginKey } from './pm-plugins/plugin-factory';
3
+ export var pastePlugin = function pastePlugin(_ref) {
4
+ var _api$featureFlags;
5
+ var config = _ref.config,
6
+ api = _ref.api;
7
+ var _ref2 = config !== null && config !== void 0 ? config : {},
8
+ cardOptions = _ref2.cardOptions,
9
+ sanitizePrivateContent = _ref2.sanitizePrivateContent;
10
+ var featureFlags = (api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {};
11
+ return {
12
+ name: 'paste',
13
+ pmPlugins: function pmPlugins() {
14
+ return [{
15
+ name: 'paste',
16
+ plugin: function plugin(_ref3) {
17
+ var schema = _ref3.schema,
18
+ providerFactory = _ref3.providerFactory,
19
+ dispatchAnalyticsEvent = _ref3.dispatchAnalyticsEvent,
20
+ dispatch = _ref3.dispatch;
21
+ return createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, api, cardOptions, sanitizePrivateContent, providerFactory);
22
+ }
23
+ }];
24
+ },
25
+ getSharedState: function getSharedState(editorState) {
26
+ if (!editorState) {
27
+ return {
28
+ lastContentPasted: null
29
+ };
30
+ }
31
+ var pluginState = pluginKey.getState(editorState);
32
+ return {
33
+ lastContentPasted: pluginState.lastContentPasted
34
+ };
35
+ }
36
+ };
37
+ };
@@ -0,0 +1,199 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { DEFAULT_IMAGE_WIDTH } from '@atlaskit/editor-common/media-single';
5
+ import { mapSlice, removeNestedEmptyEls, unwrap, walkUpTreeUntil } from '@atlaskit/editor-common/utils';
6
+ import { hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
7
+ import { getRandomHex } from '@atlaskit/media-common';
8
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
9
+
10
+ /**
11
+ * Ensure correct layout in nested mode
12
+ *
13
+ * TODO: this func is only used in handlePaste, so layout update won't work for drop event
14
+ */
15
+ export function transformSliceForMedia(slice, schema) {
16
+ var _schema$nodes = schema.nodes,
17
+ mediaSingle = _schema$nodes.mediaSingle,
18
+ layoutSection = _schema$nodes.layoutSection,
19
+ table = _schema$nodes.table,
20
+ bulletList = _schema$nodes.bulletList,
21
+ orderedList = _schema$nodes.orderedList,
22
+ expand = _schema$nodes.expand,
23
+ nestedExpand = _schema$nodes.nestedExpand;
24
+ return function (selection) {
25
+ var newSlice = slice;
26
+ if (hasParentNodeOfType([layoutSection, table, bulletList, orderedList, expand, nestedExpand])(selection)) {
27
+ newSlice = mapSlice(newSlice, function (node) {
28
+ var extendedOrLegacyAttrs = getBooleanFF('platform.editor.media.extended-resize-experience') ? {
29
+ layout: node.attrs.layout,
30
+ widthType: node.attrs.widthType,
31
+ width: node.attrs.width
32
+ } : {
33
+ layout: node.attrs.layout
34
+ };
35
+ var attrs = {};
36
+ if (hasParentNodeOfType([layoutSection, table])(selection)) {
37
+ // Supports layouts
38
+ attrs = _objectSpread({}, extendedOrLegacyAttrs);
39
+ } else if (hasParentNodeOfType([bulletList, orderedList, expand, nestedExpand])(selection)) {
40
+ // does not support other layouts
41
+ attrs = _objectSpread(_objectSpread({}, extendedOrLegacyAttrs), {}, {
42
+ layout: 'center'
43
+ });
44
+ }
45
+ return node.type.name === 'mediaSingle' ? mediaSingle.createChecked(attrs, node.content, node.marks) : node;
46
+ });
47
+ }
48
+ return newSlice;
49
+ };
50
+ }
51
+
52
+ // TODO move this to editor-common
53
+ export var isImage = function isImage(fileType) {
54
+ return !!fileType && (fileType.indexOf('image/') > -1 || fileType.indexOf('video/') > -1);
55
+ };
56
+ export var transformSliceToCorrectMediaWrapper = function transformSliceToCorrectMediaWrapper(slice, schema) {
57
+ var _schema$nodes2 = schema.nodes,
58
+ mediaGroup = _schema$nodes2.mediaGroup,
59
+ mediaSingle = _schema$nodes2.mediaSingle,
60
+ media = _schema$nodes2.media;
61
+ return mapSlice(slice, function (node, parent) {
62
+ if (!parent && node.type === media) {
63
+ if (mediaSingle && (isImage(node.attrs.__fileMimeType) || node.attrs.type === 'external')) {
64
+ return mediaSingle.createChecked({}, node);
65
+ } else {
66
+ return mediaGroup.createChecked({}, [node]);
67
+ }
68
+ }
69
+ return node;
70
+ });
71
+ };
72
+
73
+ /**
74
+ * This func will be called when copy & paste, drag & drop external html with media, media files, and slices from editor
75
+ * Because width may not be available when transform, DEFAULT_IMAGE_WIDTH is used as a fallback
76
+ *
77
+ */
78
+ export var transformSliceToMediaSingleWithNewExperience = function transformSliceToMediaSingleWithNewExperience(slice, schema) {
79
+ var _schema$nodes3 = schema.nodes,
80
+ mediaInline = _schema$nodes3.mediaInline,
81
+ mediaSingle = _schema$nodes3.mediaSingle,
82
+ media = _schema$nodes3.media;
83
+ var newSlice = mapSlice(slice, function (node) {
84
+ // This logic is duplicated in editor-plugin-ai where external images can be inserted
85
+ // from external sources through the use of AI. The editor-plugin-ai package is avoiding
86
+ // sharing dependencies with editor-core to support products using it with various versions
87
+ // of editor packages.
88
+ // The duplication is in the following file:
89
+ // packages/editor/editor-plugin-ai/src/prebuilt/content-transformers/markdown-to-pm/markdown-transformer.ts
90
+ if (node.type === mediaSingle) {
91
+ return getBooleanFF('platform.editor.media.extended-resize-experience') ? mediaSingle.createChecked({
92
+ width: node.attrs.width || DEFAULT_IMAGE_WIDTH,
93
+ widthType: node.attrs.widthType || 'pixel',
94
+ layout: node.attrs.layout
95
+ }, node.content, node.marks) : node;
96
+ }
97
+ return node;
98
+ });
99
+ return mapSlice(newSlice, function (node) {
100
+ var __mediaTraceId = getRandomHex(8);
101
+ if (node.type === media) {
102
+ return media.createChecked(_objectSpread(_objectSpread({}, node.attrs), {}, {
103
+ __external: node.attrs.type === 'external',
104
+ __mediaTraceId: node.attrs.type === 'external' ? null : __mediaTraceId
105
+ }), node.content, node.marks);
106
+ }
107
+ if (node.type.name === 'mediaInline') {
108
+ return mediaInline.createChecked(_objectSpread(_objectSpread({}, node.attrs), {}, {
109
+ __mediaTraceId: __mediaTraceId
110
+ }), node.content, node.marks);
111
+ }
112
+ return node;
113
+ });
114
+ };
115
+
116
+ /**
117
+ * Check base styles to see if an element will be invisible when rendered in a document.
118
+ * @param element
119
+ */
120
+ var isElementInvisible = function isElementInvisible(element) {
121
+ return element.style.opacity === '0' || element.style.display === 'none' || element.style.visibility === 'hidden';
122
+ };
123
+ var VALID_TAGS_CONTAINER = ['DIV', 'TD'];
124
+ function canContainImage(element) {
125
+ if (!element) {
126
+ return false;
127
+ }
128
+ return VALID_TAGS_CONTAINER.indexOf(element.tagName) !== -1;
129
+ }
130
+
131
+ /**
132
+ * Given a html string, we attempt to hoist any nested `<img>` tags,
133
+ * not directly wrapped by a `<div>` as ProseMirror no-op's
134
+ * on those scenarios.
135
+ * @param html
136
+ */
137
+ export var unwrapNestedMediaElements = function unwrapNestedMediaElements(html) {
138
+ var parser = new DOMParser();
139
+ var doc = parser.parseFromString(html, 'text/html');
140
+ var wrapper = doc.body;
141
+
142
+ // Remove Google Doc's wrapper <b> el
143
+ var docsWrapper = wrapper.querySelector('b[id^="docs-internal-guid-"]');
144
+ if (docsWrapper) {
145
+ unwrap(wrapper, docsWrapper);
146
+ }
147
+ var imageTags = wrapper.querySelectorAll('img');
148
+ if (!imageTags.length) {
149
+ return html;
150
+ }
151
+ imageTags.forEach(function (imageTag) {
152
+ // Capture the immediate parent, we may remove the media from here later.
153
+ var mediaParent = imageTag.parentElement;
154
+ if (!mediaParent) {
155
+ return;
156
+ }
157
+
158
+ // If either the parent or the image itself contains styles that would make
159
+ // them invisible on copy, dont paste them.
160
+ if (isElementInvisible(mediaParent) || isElementInvisible(imageTag)) {
161
+ mediaParent.removeChild(imageTag);
162
+ return;
163
+ }
164
+
165
+ // If its wrapped by a valid container we assume its safe to bypass.
166
+ // ProseMirror should handle these cases properly.
167
+ if (canContainImage(mediaParent) || mediaParent instanceof HTMLSpanElement && mediaParent.closest('[class*="emoji-common"]')) {
168
+ return;
169
+ }
170
+
171
+ // Find the top most element that the parent has a valid container for the image.
172
+ // Stop just before found the wrapper
173
+ var insertBeforeElement = walkUpTreeUntil(mediaParent, function (element) {
174
+ // If is at the top just use this element as reference
175
+ if (element.parentElement === wrapper) {
176
+ return true;
177
+ }
178
+ return canContainImage(element.parentElement);
179
+ });
180
+
181
+ // Here we try to insert the media right after its top most valid parent element
182
+ // Unless its the last element in our structure then we will insert above it.
183
+ if (insertBeforeElement && insertBeforeElement.parentElement) {
184
+ // Insert as close as possible to the most closest valid element index in the tree.
185
+ insertBeforeElement.parentElement.insertBefore(imageTag, insertBeforeElement.nextElementSibling || insertBeforeElement);
186
+
187
+ // Attempt to clean up lines left behind by the image
188
+ mediaParent.innerText = mediaParent.innerText.trim();
189
+ // Walk up and delete empty elements left over after removing the image tag
190
+ removeNestedEmptyEls(mediaParent);
191
+ }
192
+ });
193
+
194
+ // If last child is a hardbreak we don't want it
195
+ if (wrapper.lastElementChild && wrapper.lastElementChild.tagName === 'BR') {
196
+ wrapper.removeChild(wrapper.lastElementChild);
197
+ }
198
+ return wrapper.innerHTML;
199
+ };
@@ -0,0 +1,364 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, PasteContents, PasteTypes } from '@atlaskit/editor-common/analytics';
6
+ import { getLinkDomain, mapSlice } from '@atlaskit/editor-common/utils';
7
+ import { findParentNode } from '@atlaskit/editor-prosemirror/utils';
8
+ import { handleCodeBlock, handleExpandPasteInTable, handleMarkdown, handleMediaSingle, handlePasteAsPlainText, handlePasteIntoCaption, handlePasteIntoTaskOrDecisionOrPanel, handlePasteLinkOnSelectedText, handlePasteNonNestableBlockNodesIntoList, handlePastePanelOrDecisionContentIntoList, handlePastePreservingMarks, handleRichText, handleSelectedTable } from '../handlers';
9
+ import { getPasteSource } from '../util';
10
+ var contentToPasteContent = {
11
+ url: PasteContents.url,
12
+ paragraph: PasteContents.text,
13
+ bulletList: PasteContents.bulletList,
14
+ orderedList: PasteContents.orderedList,
15
+ heading: PasteContents.heading,
16
+ blockquote: PasteContents.blockquote,
17
+ codeBlock: PasteContents.codeBlock,
18
+ panel: PasteContents.panel,
19
+ rule: PasteContents.rule,
20
+ mediaSingle: PasteContents.mediaSingle,
21
+ mediaCard: PasteContents.mediaCard,
22
+ mediaGroup: PasteContents.mediaGroup,
23
+ table: PasteContents.table,
24
+ tableCells: PasteContents.tableCells,
25
+ tableHeader: PasteContents.tableHeader,
26
+ tableRow: PasteContents.tableRow,
27
+ decisionList: PasteContents.decisionList,
28
+ decisionItem: PasteContents.decisionItem,
29
+ taskList: PasteContents.taskItem,
30
+ extension: PasteContents.extension,
31
+ bodiedExtension: PasteContents.bodiedExtension,
32
+ blockCard: PasteContents.blockCard,
33
+ layoutSection: PasteContents.layoutSection
34
+ };
35
+ var nodeToActionSubjectId = {
36
+ blockquote: ACTION_SUBJECT_ID.PASTE_BLOCKQUOTE,
37
+ blockCard: ACTION_SUBJECT_ID.PASTE_BLOCK_CARD,
38
+ bodiedExtension: ACTION_SUBJECT_ID.PASTE_BODIED_EXTENSION,
39
+ bulletList: ACTION_SUBJECT_ID.PASTE_BULLET_LIST,
40
+ codeBlock: ACTION_SUBJECT_ID.PASTE_CODE_BLOCK,
41
+ decisionList: ACTION_SUBJECT_ID.PASTE_DECISION_LIST,
42
+ extension: ACTION_SUBJECT_ID.PASTE_EXTENSION,
43
+ heading: ACTION_SUBJECT_ID.PASTE_HEADING,
44
+ mediaGroup: ACTION_SUBJECT_ID.PASTE_MEDIA_GROUP,
45
+ mediaSingle: ACTION_SUBJECT_ID.PASTE_MEDIA_SINGLE,
46
+ orderedList: ACTION_SUBJECT_ID.PASTE_ORDERED_LIST,
47
+ panel: ACTION_SUBJECT_ID.PASTE_PANEL,
48
+ rule: ACTION_SUBJECT_ID.PASTE_RULE,
49
+ table: ACTION_SUBJECT_ID.PASTE_TABLE,
50
+ tableCell: ACTION_SUBJECT_ID.PASTE_TABLE_CELL,
51
+ tableHeader: ACTION_SUBJECT_ID.PASTE_TABLE_HEADER,
52
+ tableRow: ACTION_SUBJECT_ID.PASTE_TABLE_ROW,
53
+ taskList: ACTION_SUBJECT_ID.PASTE_TASK_LIST
54
+ };
55
+ export function getContent(_ref) {
56
+ var schema = _ref.schema,
57
+ slice = _ref.slice;
58
+ var paragraph = schema.nodes.paragraph,
59
+ link = schema.marks.link;
60
+ var nodeOrMarkName = new Set();
61
+ slice.content.forEach(function (node) {
62
+ if (node.type === paragraph && node.content.size === 0) {
63
+ // Skip empty paragraph
64
+ return;
65
+ }
66
+ if (node.type.name === 'text' && link.isInSet(node.marks)) {
67
+ nodeOrMarkName.add('url');
68
+ return;
69
+ }
70
+
71
+ // Check node contain link
72
+ if (node.type === paragraph && node.rangeHasMark(0, node.nodeSize - 2, link)) {
73
+ nodeOrMarkName.add('url');
74
+ return;
75
+ }
76
+ nodeOrMarkName.add(node.type.name);
77
+ });
78
+ if (nodeOrMarkName.size > 1) {
79
+ return PasteContents.mixed;
80
+ }
81
+ if (nodeOrMarkName.size === 0) {
82
+ return PasteContents.uncategorized;
83
+ }
84
+ var type = nodeOrMarkName.values().next().value;
85
+ var pasteContent = contentToPasteContent[type];
86
+ return pasteContent ? pasteContent : PasteContents.uncategorized;
87
+ }
88
+ export function getMediaTraceId(slice) {
89
+ var traceId;
90
+ mapSlice(slice, function (node) {
91
+ if (node.type.name === 'media' || node.type.name === 'mediaInline') {
92
+ traceId = node.attrs.__mediaTraceId;
93
+ }
94
+ return node;
95
+ });
96
+ return traceId;
97
+ }
98
+ function getActionSubjectId(_ref2) {
99
+ var selection = _ref2.selection,
100
+ schema = _ref2.schema;
101
+ var _schema$nodes = schema.nodes,
102
+ paragraph = _schema$nodes.paragraph,
103
+ listItem = _schema$nodes.listItem,
104
+ taskItem = _schema$nodes.taskItem,
105
+ decisionItem = _schema$nodes.decisionItem;
106
+ var parent = findParentNode(function (node) {
107
+ if (node.type !== paragraph && node.type !== listItem && node.type !== taskItem && node.type !== decisionItem) {
108
+ return true;
109
+ }
110
+ return false;
111
+ })(selection);
112
+ if (!parent) {
113
+ return ACTION_SUBJECT_ID.PASTE_PARAGRAPH;
114
+ }
115
+ var parentType = parent.node.type;
116
+ var actionSubjectId = nodeToActionSubjectId[parentType.name];
117
+ return actionSubjectId ? actionSubjectId : ACTION_SUBJECT_ID.PASTE_PARAGRAPH;
118
+ }
119
+ function createPasteAsPlainPayload(actionSubjectId, text, linksInPasteCount) {
120
+ return {
121
+ action: ACTION.PASTED_AS_PLAIN,
122
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
123
+ actionSubjectId: actionSubjectId,
124
+ eventType: EVENT_TYPE.TRACK,
125
+ attributes: {
126
+ inputMethod: INPUT_METHOD.KEYBOARD,
127
+ pasteSize: text.length,
128
+ linksInPasteCount: linksInPasteCount
129
+ }
130
+ };
131
+ }
132
+ function createPastePayload(actionSubjectId, attributes, linkDomain) {
133
+ return _objectSpread({
134
+ action: ACTION.PASTED,
135
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
136
+ actionSubjectId: actionSubjectId,
137
+ eventType: EVENT_TYPE.TRACK,
138
+ attributes: _objectSpread({
139
+ inputMethod: INPUT_METHOD.KEYBOARD
140
+ }, attributes)
141
+ }, linkDomain && linkDomain.length > 0 ? {
142
+ nonPrivacySafeAttributes: {
143
+ linkDomain: linkDomain
144
+ }
145
+ } : {});
146
+ }
147
+ function createPasteAnalyticsPayloadBySelection(event, slice, pasteContext) {
148
+ return function (selection) {
149
+ var text = event.clipboardData ? event.clipboardData.getData('text/plain') || event.clipboardData.getData('text/uri-list') : '';
150
+ var actionSubjectId = getActionSubjectId({
151
+ selection: selection,
152
+ schema: selection.$from.doc.type.schema
153
+ });
154
+ var pasteSize = slice.size;
155
+ var content = getContent({
156
+ schema: selection.$from.doc.type.schema,
157
+ slice: slice
158
+ });
159
+ var linkUrls = [];
160
+ var mediaTraceId = getMediaTraceId(slice);
161
+
162
+ // If we have a link among the pasted content, grab the
163
+ // domain and send it up with the analytics event
164
+ if (content === PasteContents.url || content === PasteContents.mixed) {
165
+ mapSlice(slice, function (node) {
166
+ var linkMark = node.marks.find(function (mark) {
167
+ return mark.type.name === 'link';
168
+ });
169
+ if (linkMark) {
170
+ linkUrls.push(linkMark.attrs.href);
171
+ }
172
+ return node;
173
+ });
174
+ }
175
+ if (pasteContext.asPlain) {
176
+ return createPasteAsPlainPayload(actionSubjectId, text, linkUrls.length);
177
+ }
178
+ var source = getPasteSource(event);
179
+ if (pasteContext.type === PasteTypes.plain) {
180
+ return createPastePayload(actionSubjectId, {
181
+ pasteSize: text.length,
182
+ type: pasteContext.type,
183
+ content: PasteContents.text,
184
+ source: source,
185
+ hyperlinkPasteOnText: false,
186
+ linksInPasteCount: linkUrls.length,
187
+ pasteSplitList: pasteContext.pasteSplitList
188
+ });
189
+ }
190
+ var linkDomains = linkUrls.map(getLinkDomain);
191
+ return createPastePayload(actionSubjectId, {
192
+ type: pasteContext.type,
193
+ pasteSize: pasteSize,
194
+ content: content,
195
+ source: source,
196
+ hyperlinkPasteOnText: !!pasteContext.hyperlinkPasteOnText,
197
+ linksInPasteCount: linkUrls.length,
198
+ mediaTraceId: mediaTraceId,
199
+ pasteSplitList: pasteContext.pasteSplitList
200
+ }, linkDomains);
201
+ };
202
+ }
203
+ export function createPasteAnalyticsPayload(view, event, slice, pasteContext) {
204
+ return createPasteAnalyticsPayloadBySelection(event, slice, pasteContext)(view.state.selection);
205
+ }
206
+
207
+ // TODO: ED-6612 We should not dispatch only analytics, it's preferred to wrap each command with his own analytics.
208
+ // However, handlers like handleMacroAutoConvert dispatch multiple time,
209
+ // so pasteCommandWithAnalytics is useless in this case.
210
+ export var sendPasteAnalyticsEvent = function sendPasteAnalyticsEvent(editorAnalyticsAPI) {
211
+ return function (view, event, slice, pasteContext) {
212
+ var tr = view.state.tr;
213
+ var payload = createPasteAnalyticsPayload(view, event, slice, pasteContext);
214
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent(payload)(tr);
215
+ view.dispatch(tr);
216
+ };
217
+ };
218
+ export var handlePasteAsPlainTextWithAnalytics = function handlePasteAsPlainTextWithAnalytics(editorAnalyticsAPI) {
219
+ return function (view, event, slice) {
220
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
221
+ type: PasteTypes.plain,
222
+ asPlain: true
223
+ }))(handlePasteAsPlainText(slice, event, editorAnalyticsAPI));
224
+ };
225
+ };
226
+ export var handlePasteIntoTaskAndDecisionWithAnalytics = function handlePasteIntoTaskAndDecisionWithAnalytics(view, event, slice, type, pluginInjectionApi) {
227
+ var _pluginInjectionApi$a, _pluginInjectionApi$c;
228
+ return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions)(createPasteAnalyticsPayloadBySelection(event, slice, {
229
+ type: type
230
+ }))(handlePasteIntoTaskOrDecisionOrPanel(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.card) === null || _pluginInjectionApi$c === void 0 || (_pluginInjectionApi$c = _pluginInjectionApi$c.actions) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.queueCardsFromChangedTr));
231
+ };
232
+ export var handlePasteIntoCaptionWithAnalytics = function handlePasteIntoCaptionWithAnalytics(editorAnalyticsAPI) {
233
+ return function (view, event, slice, type) {
234
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
235
+ type: type
236
+ }))(handlePasteIntoCaption(slice));
237
+ };
238
+ };
239
+ export var handleCodeBlockWithAnalytics = function handleCodeBlockWithAnalytics(editorAnalyticsAPI) {
240
+ return function (view, event, slice, text) {
241
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
242
+ type: PasteTypes.plain
243
+ }))(handleCodeBlock(text));
244
+ };
245
+ };
246
+ export var handleMediaSingleWithAnalytics = function handleMediaSingleWithAnalytics(editorAnalyticsAPI) {
247
+ return function (view, event, slice, type, insertMediaAsMediaSingle) {
248
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
249
+ type: type
250
+ }))(handleMediaSingle(INPUT_METHOD.CLIPBOARD, insertMediaAsMediaSingle)(slice));
251
+ };
252
+ };
253
+ export var handlePastePreservingMarksWithAnalytics = function handlePastePreservingMarksWithAnalytics(view, event, slice, type, pluginInjectionApi) {
254
+ var _pluginInjectionApi$a2, _pluginInjectionApi$c2;
255
+ return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.actions)(createPasteAnalyticsPayloadBySelection(event, slice, {
256
+ type: type
257
+ }))(handlePastePreservingMarks(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c2 = pluginInjectionApi.card) === null || _pluginInjectionApi$c2 === void 0 || (_pluginInjectionApi$c2 = _pluginInjectionApi$c2.actions) === null || _pluginInjectionApi$c2 === void 0 ? void 0 : _pluginInjectionApi$c2.queueCardsFromChangedTr));
258
+ };
259
+ export var handleMarkdownWithAnalytics = function handleMarkdownWithAnalytics(view, event, slice, pluginInjectionApi) {
260
+ var _pluginInjectionApi$a3, _pluginInjectionApi$c3;
261
+ return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a3 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.actions)(createPasteAnalyticsPayloadBySelection(event, slice, {
262
+ type: PasteTypes.markdown
263
+ }))(handleMarkdown(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c3 = pluginInjectionApi.card) === null || _pluginInjectionApi$c3 === void 0 || (_pluginInjectionApi$c3 = _pluginInjectionApi$c3.actions) === null || _pluginInjectionApi$c3 === void 0 ? void 0 : _pluginInjectionApi$c3.queueCardsFromChangedTr));
264
+ };
265
+ export var handleRichTextWithAnalytics = function handleRichTextWithAnalytics(view, event, slice, pluginInjectionApi) {
266
+ var _pluginInjectionApi$a4, _pluginInjectionApi$c4;
267
+ return injectAnalyticsPayloadBeforeCommand(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a4 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions)(createPasteAnalyticsPayloadBySelection(event, slice, {
268
+ type: PasteTypes.richText
269
+ }))(handleRichText(slice, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c4 = pluginInjectionApi.card) === null || _pluginInjectionApi$c4 === void 0 || (_pluginInjectionApi$c4 = _pluginInjectionApi$c4.actions) === null || _pluginInjectionApi$c4 === void 0 ? void 0 : _pluginInjectionApi$c4.queueCardsFromChangedTr));
270
+ };
271
+ var injectAnalyticsPayloadBeforeCommand = function injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI) {
272
+ return function (createPayloadByTransaction) {
273
+ return function (mainCommand) {
274
+ return function (state, dispatch, view) {
275
+ var originalTransaction = state.tr;
276
+ var fakeDispatch = function fakeDispatch(tr) {
277
+ originalTransaction = tr;
278
+ };
279
+ var result = mainCommand(state, fakeDispatch, view);
280
+ if (!result) {
281
+ return false;
282
+ }
283
+ if (dispatch && originalTransaction.docChanged) {
284
+ // it needs to know the selection before the changes
285
+ var payload = createPayloadByTransaction(state.selection);
286
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent(payload)(originalTransaction);
287
+ dispatch(originalTransaction);
288
+ }
289
+ return true;
290
+ };
291
+ };
292
+ };
293
+ };
294
+ export var handlePastePanelOrDecisionIntoListWithAnalytics = function handlePastePanelOrDecisionIntoListWithAnalytics(editorAnalyticsAPI) {
295
+ return function (view, event, slice, findRootParentListNode) {
296
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
297
+ type: PasteTypes.richText
298
+ }))(handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode));
299
+ };
300
+ };
301
+ export var handlePasteNonNestableBlockNodesIntoListWithAnalytics = function handlePasteNonNestableBlockNodesIntoListWithAnalytics(editorAnalyticsAPI) {
302
+ return function (view, event, slice) {
303
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
304
+ type: PasteTypes.richText,
305
+ pasteSplitList: true
306
+ }))(handlePasteNonNestableBlockNodesIntoList(slice));
307
+ };
308
+ };
309
+ export var handleExpandWithAnalytics = function handleExpandWithAnalytics(editorAnalyticsAPI) {
310
+ return function (view, event, slice) {
311
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
312
+ type: PasteTypes.richText,
313
+ pasteSplitList: true
314
+ }))(handleExpandPasteInTable(slice));
315
+ };
316
+ };
317
+ export var handleSelectedTableWithAnalytics = function handleSelectedTableWithAnalytics(editorAnalyticsAPI) {
318
+ return function (view, event, slice) {
319
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
320
+ type: PasteTypes.richText
321
+ }))(handleSelectedTable(editorAnalyticsAPI)(slice));
322
+ };
323
+ };
324
+ export var handlePasteLinkOnSelectedTextWithAnalytics = function handlePasteLinkOnSelectedTextWithAnalytics(editorAnalyticsAPI) {
325
+ return function (view, event, slice, type) {
326
+ return injectAnalyticsPayloadBeforeCommand(editorAnalyticsAPI)(createPasteAnalyticsPayloadBySelection(event, slice, {
327
+ type: type,
328
+ hyperlinkPasteOnText: true
329
+ }))(handlePasteLinkOnSelectedText(slice));
330
+ };
331
+ };
332
+ export var createPasteMeasurePayload = function createPasteMeasurePayload(_ref3) {
333
+ var view = _ref3.view,
334
+ duration = _ref3.duration,
335
+ content = _ref3.content,
336
+ distortedDuration = _ref3.distortedDuration;
337
+ var pasteIntoNode = getActionSubjectId({
338
+ selection: view.state.selection,
339
+ schema: view.state.schema
340
+ });
341
+ return {
342
+ action: ACTION.PASTED_TIMED,
343
+ actionSubject: ACTION_SUBJECT.EDITOR,
344
+ eventType: EVENT_TYPE.OPERATIONAL,
345
+ attributes: {
346
+ pasteIntoNode: pasteIntoNode,
347
+ content: content,
348
+ time: duration,
349
+ distortedDuration: distortedDuration
350
+ }
351
+ };
352
+ };
353
+ export var getContentNodeTypes = function getContentNodeTypes(content) {
354
+ var nodeTypes = new Set();
355
+ if (content.size) {
356
+ content.forEach(function (node) {
357
+ if (node.content && node.content.size) {
358
+ nodeTypes = new Set([].concat(_toConsumableArray(nodeTypes), _toConsumableArray(getContentNodeTypes(node.content))));
359
+ }
360
+ nodeTypes.add(node.type.name);
361
+ });
362
+ }
363
+ return Array.from(nodeTypes);
364
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Returns a plain text serialization of a given slice. This is used for populating the plain text
3
+ * section of the clipboard on copy.
4
+ * The current implementation is bare bones - only inlineCards, blockCards and mentions are tested (they
5
+ * previously were empty on plain text copy).
6
+ * Unknown nodes are passed to node.textBetween().
7
+ *
8
+ * By default (without this function passed to the editor), the editor uses
9
+ * `slice.content.textBetween(0, slice.content.size, "\n\n")`
10
+ * (see https://prosemirror.net/docs/ref/#view.EditorProps.clipboardTextSerializer)
11
+ */
12
+ export function clipboardTextSerializer(slice) {
13
+ var text = '';
14
+ var blockSeparater = '\n\n';
15
+ slice.content.nodesBetween(0, slice.content.size, function (node) {
16
+ if (node.type.isBlock) {
17
+ text += blockSeparater;
18
+ }
19
+ if (node.type.name === 'paragraph') {
20
+ return true;
21
+ } else if (node.type.name === 'hardBreak') {
22
+ text += '\n';
23
+ } else if (node.type.name === 'text') {
24
+ text += node.text;
25
+ } else if (node.type.name === 'inlineCard') {
26
+ text += node.attrs.url;
27
+ } else if (node.type.name === 'blockCard') {
28
+ text += node.attrs.url;
29
+ } else if (node.type.name === 'mention') {
30
+ text += node.attrs.text;
31
+ } else {
32
+ text += node.textBetween(0, node.content.size, '\n\n');
33
+ }
34
+ return false;
35
+ });
36
+ return text.trim();
37
+ }