@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
@@ -0,0 +1,918 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
4
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
5
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
7
+ 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; }
8
+ 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; }
9
+ import uuid from 'uuid/v4';
10
+ import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
11
+ import { insideTable } from '@atlaskit/editor-common/core-utils';
12
+ import { anyMarkActive } from '@atlaskit/editor-common/mark';
13
+ import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection';
14
+ import { canLinkBeCreatedInRange, insideTableCell, isInListItem, isLinkMark, isListItemNode, isListNode, isParagraph, isText, linkifyContent, mapSlice } from '@atlaskit/editor-common/utils';
15
+ import { closeHistory } from '@atlaskit/editor-prosemirror/history';
16
+ import { Fragment, Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model';
17
+ import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
18
+ import { canInsert, findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
19
+ import { replaceSelectedTable } from '@atlaskit/editor-tables/utils';
20
+ // TODO: ED-20519 Needs Macro extraction
21
+
22
+ import { startTrackingPastedMacroPositions, stopTrackingPastedMacroPositions } from './commands';
23
+ import { insertSliceForLists, insertSliceForListsInsideBlockquote } from './edge-cases';
24
+ import { getPluginState as getPastePluginState } from './pm-plugins/plugin-factory';
25
+ import { addReplaceSelectedTableAnalytics, applyTextMarksToSlice, hasOnlyNodesOfType } from './util';
26
+
27
+ /** Helper type for single arg function */
28
+
29
+ /* eslint-disable @typescript-eslint/no-explicit-any */
30
+ /**
31
+ * Compose 1 to n functions.
32
+ * @param func first function
33
+ * @param funcs additional functions
34
+ */
35
+ function compose(func) {
36
+ for (var _len = arguments.length, funcs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
37
+ funcs[_key - 1] = arguments[_key];
38
+ }
39
+ var allFuncs = [func].concat(funcs);
40
+ return function composed(raw) {
41
+ return allFuncs.reduceRight(function (memo, func) {
42
+ return func(memo);
43
+ }, raw);
44
+ };
45
+ }
46
+ /* eslint-enable @typescript-eslint/no-explicit-any */
47
+
48
+ // remove text attribute from mention for copy/paste (GDPR)
49
+ export function handleMention(slice, schema) {
50
+ return mapSlice(slice, function (node) {
51
+ if (node.type.name === schema.nodes.mention.name) {
52
+ var mention = node.attrs;
53
+ var newMention = _objectSpread(_objectSpread({}, mention), {}, {
54
+ text: ''
55
+ });
56
+ return schema.nodes.mention.create(newMention, node.content, node.marks);
57
+ }
58
+ return node;
59
+ });
60
+ }
61
+ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
62
+ return function (state, dispatch) {
63
+ var _slice$content$firstC, _transformedSlice$con;
64
+ var schema = state.schema,
65
+ selection = state.tr.selection;
66
+ var codeMark = schema.marks.code,
67
+ _schema$nodes = schema.nodes,
68
+ decisionItem = _schema$nodes.decisionItem,
69
+ emoji = _schema$nodes.emoji,
70
+ hardBreak = _schema$nodes.hardBreak,
71
+ mention = _schema$nodes.mention,
72
+ paragraph = _schema$nodes.paragraph,
73
+ taskItem = _schema$nodes.taskItem,
74
+ text = _schema$nodes.text,
75
+ panel = _schema$nodes.panel,
76
+ bulletList = _schema$nodes.bulletList,
77
+ orderedList = _schema$nodes.orderedList,
78
+ taskList = _schema$nodes.taskList,
79
+ listItem = _schema$nodes.listItem,
80
+ expand = _schema$nodes.expand,
81
+ heading = _schema$nodes.heading;
82
+ var selectionIsValidNode = state.selection instanceof NodeSelection && ['decisionList', 'decisionItem', 'taskList', 'taskItem'].includes(state.selection.node.type.name);
83
+ var selectionHasValidParentNode = hasParentNodeOfType([decisionItem, taskItem, panel])(state.selection);
84
+ var selectionIsPanel = hasParentNodeOfType([panel])(state.selection);
85
+
86
+ // Some types of content should be handled by the default handler, not this function.
87
+ // Check through slice content to see if it contains an invalid node.
88
+ var sliceIsInvalid = false;
89
+ slice.content.nodesBetween(0, slice.content.size, function (node) {
90
+ if (node.type === bulletList || node.type === orderedList || node.type === expand || node.type === heading || node.type === listItem) {
91
+ sliceIsInvalid = true;
92
+ }
93
+ if (selectionIsPanel && node.type === taskList) {
94
+ sliceIsInvalid = true;
95
+ }
96
+ });
97
+
98
+ // If the selection is a panel,
99
+ // and the slice's first node is a paragraph
100
+ // and it is not from a depth that would indicate it being from inside from another node (e.g. text from a decision)
101
+ // then we can rely on the default behaviour.
102
+ var sliceIsAPanelReceivingLowDepthText = selectionIsPanel && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === paragraph && slice.openEnd < 2;
103
+ if (sliceIsInvalid || sliceIsAPanelReceivingLowDepthText || !selectionIsValidNode && !selectionHasValidParentNode) {
104
+ return false;
105
+ }
106
+ var filters = [linkifyContent(schema)];
107
+ var selectionMarks = selection.$head.marks();
108
+ if (selection instanceof TextSelection && Array.isArray(selectionMarks) && selectionMarks.length > 0 && hasOnlyNodesOfType(paragraph, text, emoji, mention, hardBreak)(slice) && (!codeMark.isInSet(selectionMarks) || anyMarkActive(state, codeMark)) // check if there is a code mark anywhere in the selection
109
+ ) {
110
+ filters.push(applyTextMarksToSlice(schema, selection.$head.marks()));
111
+ }
112
+ var transformedSlice = compose.apply(null, filters)(slice);
113
+ var tr = closeHistory(state.tr);
114
+ var transformedSliceIsValidNode = transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskList', 'taskItem', 'panel'].includes(transformedSlice.content.firstChild.type.name) && !isInListItem(state);
115
+ // If the slice or the selection are valid nodes to handle,
116
+ // and the slice is not a whole node (i.e. openStart is 1 and openEnd is 0)
117
+ // or the slice's first node is a paragraph,
118
+ // then we can replace the selection with our slice.
119
+ if ((transformedSliceIsValidNode || selectionIsValidNode) && !(transformedSlice.openStart === 1 && transformedSlice.openEnd === 0 ||
120
+ // Whole codeblock node has reverse slice depths.
121
+ transformedSlice.openStart === 0 && transformedSlice.openEnd === 1) || ((_transformedSlice$con = transformedSlice.content.firstChild) === null || _transformedSlice$con === void 0 ? void 0 : _transformedSlice$con.type) === paragraph) {
122
+ tr.replaceSelection(transformedSlice).scrollIntoView();
123
+ } else {
124
+ // This maintains both the selection (destination) and the slice (paste content).
125
+ safeInsert(transformedSlice.content)(tr).scrollIntoView();
126
+ }
127
+ queueCardsFromChangedTr === null || queueCardsFromChangedTr === void 0 || queueCardsFromChangedTr(state, tr, INPUT_METHOD.CLIPBOARD);
128
+ if (dispatch) {
129
+ dispatch(tr);
130
+ }
131
+ return true;
132
+ };
133
+ }
134
+ export function handlePasteNonNestableBlockNodesIntoList(slice) {
135
+ return function (state, dispatch) {
136
+ var _tr$doc$nodeAt, _sliceContent$firstCh, _findParentNodeOfType;
137
+ var tr = state.tr;
138
+ var selection = tr.selection;
139
+ var $from = selection.$from,
140
+ $to = selection.$to,
141
+ from = selection.from,
142
+ to = selection.to;
143
+ var _state$schema$nodes = state.schema.nodes,
144
+ orderedList = _state$schema$nodes.orderedList,
145
+ bulletList = _state$schema$nodes.bulletList,
146
+ listItem = _state$schema$nodes.listItem;
147
+
148
+ // Selected nodes
149
+ var selectionParentListItemNode = findParentNodeOfType(listItem)(selection);
150
+ var selectionParentListNodeWithPos = findParentNodeOfType([bulletList, orderedList])(selection);
151
+ var selectionParentListNode = selectionParentListNodeWithPos === null || selectionParentListNodeWithPos === void 0 ? void 0 : selectionParentListNodeWithPos.node;
152
+
153
+ // Slice info
154
+ var sliceContent = slice.content;
155
+ var sliceIsListItems = isListNode(sliceContent.firstChild) && isListNode(sliceContent.lastChild);
156
+
157
+ // Find case of slices that can be inserted into a list item
158
+ // (eg. paragraphs, list items, code blocks, media single)
159
+ // These scenarios already get handled elsewhere and don't need to split the list
160
+ var sliceContainsBlockNodesOtherThanThoseAllowedInListItem = false;
161
+ slice.content.forEach(function (child) {
162
+ var _listItem$spec$conten;
163
+ if (!listItem || child.isBlock && !((_listItem$spec$conten = listItem.spec.content) !== null && _listItem$spec$conten !== void 0 && _listItem$spec$conten.includes(child.type.name))) {
164
+ sliceContainsBlockNodesOtherThanThoseAllowedInListItem = true;
165
+ }
166
+ });
167
+ if (!selectionParentListItemNode || !sliceContent || canInsert($from, sliceContent) ||
168
+ // eg. inline nodes that can be inserted in a list item
169
+ !sliceContainsBlockNodesOtherThanThoseAllowedInListItem || sliceIsListItems || !selectionParentListNodeWithPos) {
170
+ return false;
171
+ }
172
+
173
+ // Offsets
174
+ var listWrappingOffset = $to.depth - selectionParentListNodeWithPos.depth + 1; // difference in depth between to position and list node
175
+ var listItemWrappingOffset = $to.depth - selectionParentListNodeWithPos.depth; // difference in depth between to position and list item node
176
+
177
+ // Anything to do with nested lists should safeInsert and not be handled here
178
+ var grandParentListNode = findParentNodeOfTypeClosestToPos(tr.doc.resolve(selectionParentListNodeWithPos.pos), [bulletList, orderedList]);
179
+ var selectionIsInNestedList = !!grandParentListNode;
180
+ var selectedListItemHasNestedList = false;
181
+ selectionParentListItemNode.node.content.forEach(function (child) {
182
+ if (isListNode(child)) {
183
+ selectedListItemHasNestedList = true;
184
+ }
185
+ });
186
+ if (selectedListItemHasNestedList || selectionIsInNestedList) {
187
+ return false;
188
+ }
189
+
190
+ // Node after the insert position
191
+ var nodeAfterInsertPositionIsListItem = ((_tr$doc$nodeAt = tr.doc.nodeAt(to + listItemWrappingOffset)) === null || _tr$doc$nodeAt === void 0 ? void 0 : _tr$doc$nodeAt.type.name) === 'listItem';
192
+
193
+ // Get the next list items position (used later to find the split out ordered list)
194
+ var indexOfNextListItem = $to.indexAfter($to.depth - listItemWrappingOffset);
195
+ var positionOfNextListItem = tr.doc.resolve(selectionParentListNodeWithPos.pos + 1).posAtIndex(indexOfNextListItem);
196
+
197
+ // These nodes paste as plain text by default so need to be handled differently
198
+ var sliceContainsNodeThatPastesAsPlainText = sliceContent.firstChild && ['taskItem', 'taskList', 'heading', 'blockquote'].includes(sliceContent.firstChild.type.name);
199
+
200
+ // Work out position to replace up to
201
+ var replaceTo;
202
+ if (sliceContainsNodeThatPastesAsPlainText && nodeAfterInsertPositionIsListItem) {
203
+ replaceTo = to + listItemWrappingOffset;
204
+ } else if (sliceContainsNodeThatPastesAsPlainText || !nodeAfterInsertPositionIsListItem) {
205
+ replaceTo = to;
206
+ } else {
207
+ replaceTo = to + listWrappingOffset;
208
+ }
209
+
210
+ // handle the insertion of the slice
211
+ if (sliceContainsNodeThatPastesAsPlainText || nodeAfterInsertPositionIsListItem || sliceContent.childCount > 1 && ((_sliceContent$firstCh = sliceContent.firstChild) === null || _sliceContent$firstCh === void 0 ? void 0 : _sliceContent$firstCh.type.name) !== 'paragraph') {
212
+ tr.replaceWith(from, replaceTo, sliceContent).scrollIntoView();
213
+ } else {
214
+ // When the selection is not at the end of a list item
215
+ // eg. middle of list item, start of list item
216
+ tr.replaceSelection(slice).scrollIntoView();
217
+ }
218
+
219
+ // Find the ordered list node after the pasted content so we can set it's order
220
+ var mappedPositionOfNextListItem = tr.mapping.map(positionOfNextListItem);
221
+ if (mappedPositionOfNextListItem > tr.doc.nodeSize) {
222
+ return false;
223
+ }
224
+ var nodeAfterPastedContentResolvedPos = findParentNodeOfTypeClosestToPos(tr.doc.resolve(mappedPositionOfNextListItem), [orderedList]);
225
+
226
+ // Work out the new split out lists 'order' (the number it starts from)
227
+ var originalParentOrderedListNodeOrder = selectionParentListNode === null || selectionParentListNode === void 0 ? void 0 : selectionParentListNode.attrs.order;
228
+ var numOfListItemsInOriginalList = (_findParentNodeOfType = findParentNodeOfTypeClosestToPos(tr.doc.resolve(from - 1), [orderedList])) === null || _findParentNodeOfType === void 0 ? void 0 : _findParentNodeOfType.node.childCount;
229
+
230
+ // Set the new split out lists order attribute
231
+ if (typeof originalParentOrderedListNodeOrder === 'number' && numOfListItemsInOriginalList && nodeAfterPastedContentResolvedPos) {
232
+ tr.setNodeMarkup(nodeAfterPastedContentResolvedPos.pos, orderedList, _objectSpread(_objectSpread({}, nodeAfterPastedContentResolvedPos.node.attrs), {}, {
233
+ order: originalParentOrderedListNodeOrder + numOfListItemsInOriginalList
234
+ }));
235
+ }
236
+
237
+ // dispatch transaction
238
+ if (tr.docChanged) {
239
+ if (dispatch) {
240
+ dispatch(tr);
241
+ }
242
+ return true;
243
+ }
244
+ return false;
245
+ };
246
+ }
247
+ export var doesSelectionWhichStartsOrEndsInListContainEntireList = function doesSelectionWhichStartsOrEndsInListContainEntireList(selection, findRootParentListNode) {
248
+ var $from = selection.$from,
249
+ $to = selection.$to,
250
+ from = selection.from,
251
+ to = selection.to;
252
+ var selectionParentListItemNodeResolvedPos = findRootParentListNode ? findRootParentListNode($from) || findRootParentListNode($to) : null;
253
+ var selectionParentListNode = selectionParentListItemNodeResolvedPos === null || selectionParentListItemNodeResolvedPos === void 0 ? void 0 : selectionParentListItemNodeResolvedPos.parent;
254
+ if (!selectionParentListItemNodeResolvedPos || !selectionParentListNode) {
255
+ return false;
256
+ }
257
+ var startOfEntireList = $from.pos < $to.pos ? selectionParentListItemNodeResolvedPos.pos + $from.depth - 1 : selectionParentListItemNodeResolvedPos.pos + $to.depth - 1;
258
+ var endOfEntireList = $from.pos < $to.pos ? selectionParentListItemNodeResolvedPos.pos + selectionParentListNode.nodeSize - $to.depth - 1 : selectionParentListItemNodeResolvedPos.pos + selectionParentListNode.nodeSize - $from.depth - 1;
259
+ if (!startOfEntireList || !endOfEntireList) {
260
+ return false;
261
+ }
262
+ if (from < to) {
263
+ return startOfEntireList >= $from.pos && endOfEntireList <= $to.pos;
264
+ } else if (from > to) {
265
+ return startOfEntireList >= $to.pos && endOfEntireList <= $from.pos;
266
+ } else {
267
+ return false;
268
+ }
269
+ };
270
+ export function handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode) {
271
+ return function (state, dispatch) {
272
+ var schema = state.schema,
273
+ tr = state.tr;
274
+ var selection = tr.selection;
275
+ // Check this pasting action is related to copy content from panel node into a selected the list node
276
+ var blockNode = slice.content.firstChild;
277
+ var isSliceWholeNode = slice.openStart === 0 && slice.openEnd === 0;
278
+ var selectionParentListItemNode = selection.$to.node(selection.$to.depth - 1);
279
+ var sliceIsWholeNodeButShouldNotReplaceSelection = isSliceWholeNode && !doesSelectionWhichStartsOrEndsInListContainEntireList(selection, findRootParentListNode);
280
+ if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !['panel', 'decisionList'].includes(blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
281
+ return false;
282
+ }
283
+
284
+ // Paste the panel node contents extracted instead of pasting the entire panel node
285
+ tr.replaceSelection(slice).scrollIntoView();
286
+ if (dispatch) {
287
+ dispatch(tr);
288
+ }
289
+ return true;
290
+ };
291
+ }
292
+
293
+ // If we paste a link onto some selected text, apply the link as a mark
294
+ export function handlePasteLinkOnSelectedText(slice) {
295
+ return function (state, dispatch) {
296
+ var schema = state.schema,
297
+ selection = state.selection,
298
+ _state$selection = state.selection,
299
+ from = _state$selection.from,
300
+ to = _state$selection.to,
301
+ tr = state.tr;
302
+ var linkMark;
303
+
304
+ // check if we have a link on the clipboard
305
+ if (slice.content.childCount === 1 && isParagraph(slice.content.child(0), schema)) {
306
+ var paragraph = slice.content.child(0);
307
+ if (paragraph.content.childCount === 1 && isText(paragraph.content.child(0), schema)) {
308
+ var text = paragraph.content.child(0);
309
+
310
+ // If pasteType is plain text, then
311
+ // @atlaskit/editor-markdown-transformer in getMarkdownSlice decode
312
+ // url before setting text property of text node.
313
+ // However href of marks will be without decoding.
314
+ // So, if there is character (e.g space) in url eligible escaping then
315
+ // mark.attrs.href will not be equal to text.text.
316
+ // That's why decoding mark.attrs.href before comparing.
317
+ // However, if pasteType is richText, that means url in text.text
318
+ // and href in marks, both won't be decoded.
319
+ linkMark = text.marks.find(function (mark) {
320
+ return isLinkMark(mark, schema) && (mark.attrs.href === text.text || decodeURI(mark.attrs.href) === text.text);
321
+ });
322
+ }
323
+ }
324
+
325
+ // if we have a link, apply it to the selected text if we have any and it's allowed
326
+ if (linkMark && selection instanceof TextSelection && !selection.empty && canLinkBeCreatedInRange(from, to)(state)) {
327
+ tr.addMark(from, to, linkMark);
328
+ if (dispatch) {
329
+ dispatch(tr);
330
+ }
331
+ return true;
332
+ }
333
+ return false;
334
+ };
335
+ }
336
+ export function handlePasteAsPlainText(slice, _event, editorAnalyticsAPI) {
337
+ return function (state, dispatch, view) {
338
+ var _input;
339
+ if (!view) {
340
+ return false;
341
+ }
342
+
343
+ // prosemirror-bump-fix
344
+ // Yes, this is wrong by default. But, we need to keep the private PAI usage to unblock the prosemirror bump
345
+ // So, this code will make sure we are checking for both version (current and the newest prosemirror-view version
346
+ var isShiftKeyPressed =
347
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
348
+ view.shiftKey || ((_input = view.input) === null || _input === void 0 ? void 0 : _input.shiftKey);
349
+ // In case of SHIFT+CMD+V ("Paste and Match Style") we don't want to run the usual
350
+ // fuzzy matching of content. ProseMirror already handles this scenario and will
351
+ // provide us with slice containing paragraphs with plain text, which we decorate
352
+ // with "stored marks".
353
+ // @see prosemirror-view/src/clipboard.js:parseFromClipboard()).
354
+ // @see prosemirror-view/src/input.js:doPaste().
355
+ if (isShiftKeyPressed) {
356
+ var tr = closeHistory(state.tr);
357
+ var _tr = tr,
358
+ selection = _tr.selection;
359
+
360
+ // <- using the same internal flag that prosemirror-view is using
361
+
362
+ // if user has selected table we need custom logic to replace the table
363
+ tr = replaceSelectedTable(state, slice);
364
+
365
+ // add analytics after replacing selected table
366
+ tr = addReplaceSelectedTableAnalytics(state, tr, editorAnalyticsAPI);
367
+
368
+ // otherwise just replace the selection
369
+ if (!tr.docChanged) {
370
+ tr.replaceSelection(slice);
371
+ }
372
+ (state.storedMarks || []).forEach(function (mark) {
373
+ tr.addMark(selection.from, selection.from + slice.size, mark);
374
+ });
375
+ tr.scrollIntoView();
376
+ if (dispatch) {
377
+ dispatch(tr);
378
+ }
379
+ return true;
380
+ }
381
+ return false;
382
+ };
383
+ }
384
+ export function handlePastePreservingMarks(slice, queueCardsFromChangedTr) {
385
+ return function (state, dispatch) {
386
+ var schema = state.schema,
387
+ selection = state.tr.selection;
388
+ var _schema$marks = schema.marks,
389
+ codeMark = _schema$marks.code,
390
+ annotationMark = _schema$marks.annotation,
391
+ _schema$nodes2 = schema.nodes,
392
+ bulletList = _schema$nodes2.bulletList,
393
+ emoji = _schema$nodes2.emoji,
394
+ hardBreak = _schema$nodes2.hardBreak,
395
+ heading = _schema$nodes2.heading,
396
+ listItem = _schema$nodes2.listItem,
397
+ mention = _schema$nodes2.mention,
398
+ orderedList = _schema$nodes2.orderedList,
399
+ text = _schema$nodes2.text;
400
+ if (!(selection instanceof TextSelection)) {
401
+ return false;
402
+ }
403
+ var selectionMarks = selection.$head.marks();
404
+ if (selectionMarks.length === 0) {
405
+ return false;
406
+ }
407
+
408
+ // special case for codeMark: will preserve mark only if codeMark is currently active
409
+ // won't preserve mark if cursor is on the edge on the mark (namely inactive)
410
+ var hasActiveCodeMark = codeMark && codeMark.isInSet(selectionMarks) && anyMarkActive(state, codeMark);
411
+ var hasAnnotationMark = annotationMark && annotationMark.isInSet(selectionMarks);
412
+ var selectionIsHeading = hasParentNodeOfType([heading])(state.selection);
413
+
414
+ // if the pasted data is one of the node types below
415
+ // we apply current selection marks to the pasted slice
416
+ if (hasOnlyNodesOfType(bulletList, hardBreak, heading, listItem, text, emoji, mention, orderedList)(slice) || selectionIsHeading || hasActiveCodeMark || hasAnnotationMark) {
417
+ var transformedSlice = applyTextMarksToSlice(schema, selectionMarks)(slice);
418
+ var tr = closeHistory(state.tr).replaceSelection(transformedSlice).setStoredMarks(selectionMarks).scrollIntoView();
419
+ queueCardsFromChangedTr === null || queueCardsFromChangedTr === void 0 || queueCardsFromChangedTr(state, tr, INPUT_METHOD.CLIPBOARD);
420
+ if (dispatch) {
421
+ dispatch(tr);
422
+ }
423
+ return true;
424
+ }
425
+ return false;
426
+ };
427
+ }
428
+ function getSmartLinkAdf(_x, _x2, _x3) {
429
+ return _getSmartLinkAdf.apply(this, arguments);
430
+ }
431
+ function _getSmartLinkAdf() {
432
+ _getSmartLinkAdf = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(text, type, cardOptions) {
433
+ var provider;
434
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
435
+ while (1) switch (_context.prev = _context.next) {
436
+ case 0:
437
+ if (cardOptions.provider) {
438
+ _context.next = 2;
439
+ break;
440
+ }
441
+ throw Error('No card provider found');
442
+ case 2:
443
+ _context.next = 4;
444
+ return cardOptions.provider;
445
+ case 4:
446
+ provider = _context.sent;
447
+ _context.next = 7;
448
+ return provider.resolve(text, type);
449
+ case 7:
450
+ return _context.abrupt("return", _context.sent);
451
+ case 8:
452
+ case "end":
453
+ return _context.stop();
454
+ }
455
+ }, _callee);
456
+ }));
457
+ return _getSmartLinkAdf.apply(this, arguments);
458
+ }
459
+ function insertAutoMacro(slice, macro, view, from, to) {
460
+ if (view) {
461
+ // insert the text or linkified/md-converted clipboard data
462
+ var selection = view.state.tr.selection;
463
+ var tr;
464
+ var before;
465
+ if (typeof from === 'number' && typeof to === 'number') {
466
+ tr = view.state.tr.replaceRange(from, to, slice);
467
+ before = tr.mapping.map(from, -1);
468
+ } else {
469
+ tr = view.state.tr.replaceSelection(slice);
470
+ before = tr.mapping.map(selection.from, -1);
471
+ }
472
+ view.dispatch(tr);
473
+
474
+ // replace the text with the macro as a separate transaction
475
+ // so the autoconversion generates 2 undo steps
476
+ view.dispatch(closeHistory(view.state.tr).replaceRangeWith(before, before + slice.size, macro).scrollIntoView());
477
+ return true;
478
+ }
479
+ return false;
480
+ }
481
+ export function handleMacroAutoConvert(text, slice, queueCardsFromChangedTr, runMacroAutoConvert, cardsOptions, extensionAutoConverter) {
482
+ return function (state, dispatch, view) {
483
+ var macro = null;
484
+
485
+ // try to use auto convert from extension provider first
486
+ if (extensionAutoConverter) {
487
+ var extension = extensionAutoConverter(text);
488
+ if (extension) {
489
+ macro = PMNode.fromJSON(state.schema, extension);
490
+ }
491
+ }
492
+
493
+ // then try from macro provider (which will be removed some time in the future)
494
+ if (!macro) {
495
+ var _runMacroAutoConvert;
496
+ macro = (_runMacroAutoConvert = runMacroAutoConvert === null || runMacroAutoConvert === void 0 ? void 0 : runMacroAutoConvert(state, text)) !== null && _runMacroAutoConvert !== void 0 ? _runMacroAutoConvert : null;
497
+ }
498
+ if (macro) {
499
+ /**
500
+ * if FF enabled, run through smart links and check for result
501
+ */
502
+ if (cardsOptions && cardsOptions.resolveBeforeMacros && cardsOptions.resolveBeforeMacros.length) {
503
+ var _startTrackingPastedM;
504
+ if (cardsOptions.resolveBeforeMacros.indexOf(macro.attrs.extensionKey) < 0) {
505
+ return insertAutoMacro(slice, macro, view);
506
+ }
507
+ if (!view) {
508
+ throw new Error('View is missing');
509
+ }
510
+ var trackingId = uuid();
511
+ var trackingFrom = "handleMacroAutoConvert-from-".concat(trackingId);
512
+ var trackingTo = "handleMacroAutoConvert-to-".concat(trackingId);
513
+ startTrackingPastedMacroPositions((_startTrackingPastedM = {}, _defineProperty(_startTrackingPastedM, trackingFrom, state.selection.from), _defineProperty(_startTrackingPastedM, trackingTo, state.selection.to), _startTrackingPastedM))(state, dispatch);
514
+ getSmartLinkAdf(text, 'inline', cardsOptions).then(function () {
515
+ // we use view.state rather than state because state becomes a stale
516
+ // state reference after getSmartLinkAdf's async work
517
+ var _getPastePluginState = getPastePluginState(view.state),
518
+ pastedMacroPositions = _getPastePluginState.pastedMacroPositions;
519
+ if (dispatch) {
520
+ handleMarkdown(slice, queueCardsFromChangedTr, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo])(view.state, dispatch);
521
+ }
522
+ }).catch(function () {
523
+ var _getPastePluginState2 = getPastePluginState(view.state),
524
+ pastedMacroPositions = _getPastePluginState2.pastedMacroPositions;
525
+ insertAutoMacro(slice, macro, view, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo]);
526
+ }).finally(function () {
527
+ stopTrackingPastedMacroPositions([trackingFrom, trackingTo])(view.state, dispatch);
528
+ });
529
+ return true;
530
+ }
531
+ return insertAutoMacro(slice, macro, view);
532
+ }
533
+ return !!macro;
534
+ };
535
+ }
536
+ export function handleCodeBlock(text) {
537
+ return function (state, dispatch) {
538
+ var codeBlock = state.schema.nodes.codeBlock;
539
+ if (text && hasParentNodeOfType(codeBlock)(state.selection)) {
540
+ var tr = closeHistory(state.tr);
541
+ tr.scrollIntoView();
542
+ if (dispatch) {
543
+ dispatch(tr.insertText(text));
544
+ }
545
+ return true;
546
+ }
547
+ return false;
548
+ };
549
+ }
550
+ function isOnlyMedia(state, slice) {
551
+ var media = state.schema.nodes.media;
552
+ return slice.content.childCount === 1 && slice.content.firstChild.type === media;
553
+ }
554
+ function isOnlyMediaSingle(state, slice) {
555
+ var mediaSingle = state.schema.nodes.mediaSingle;
556
+ return mediaSingle && slice.content.childCount === 1 && slice.content.firstChild.type === mediaSingle;
557
+ }
558
+ export function handleMediaSingle(inputMethod, insertMediaAsMediaSingle) {
559
+ return function (slice) {
560
+ return function (state, dispatch, view) {
561
+ if (view) {
562
+ if (isOnlyMedia(state, slice)) {
563
+ var _insertMediaAsMediaSi;
564
+ return (_insertMediaAsMediaSi = insertMediaAsMediaSingle === null || insertMediaAsMediaSingle === void 0 ? void 0 : insertMediaAsMediaSingle(view, slice.content.firstChild, inputMethod)) !== null && _insertMediaAsMediaSi !== void 0 ? _insertMediaAsMediaSi : false;
565
+ }
566
+ if (insideTable(state) && isOnlyMediaSingle(state, slice)) {
567
+ var tr = state.tr.replaceSelection(slice);
568
+ var nextPos = tr.doc.resolve(tr.mapping.map(state.selection.$from.pos));
569
+ if (dispatch) {
570
+ dispatch(tr.setSelection(new GapCursorSelection(nextPos, Side.RIGHT)));
571
+ }
572
+ return true;
573
+ }
574
+ }
575
+ return false;
576
+ };
577
+ };
578
+ }
579
+ var checkExpand = function checkExpand(slice) {
580
+ var hasExpand = false;
581
+ slice.content.forEach(function (node) {
582
+ if (node.type.name === 'expand') {
583
+ hasExpand = true;
584
+ }
585
+ });
586
+ return hasExpand;
587
+ };
588
+ export function handleExpandPasteInTable(slice) {
589
+ return function (state, dispatch) {
590
+ // Do not handle expand if it's not being pasted into a table
591
+ // OR if it's nested within another node when being pasted into a table
592
+ if (!insideTable(state) || !checkExpand(slice)) {
593
+ return false;
594
+ }
595
+ var _state$schema$nodes2 = state.schema.nodes,
596
+ expand = _state$schema$nodes2.expand,
597
+ nestedExpand = _state$schema$nodes2.nestedExpand;
598
+ var tr = state.tr;
599
+ var hasExpand = false;
600
+ var newSlice = mapSlice(slice, function (maybeNode) {
601
+ if (maybeNode.type === expand) {
602
+ hasExpand = true;
603
+ try {
604
+ return nestedExpand.createChecked(maybeNode.attrs, maybeNode.content, maybeNode.marks);
605
+ } catch (e) {
606
+ tr = safeInsert(maybeNode, tr.selection.$to.pos)(tr);
607
+ return Fragment.empty;
608
+ }
609
+ }
610
+ return maybeNode;
611
+ });
612
+ if (hasExpand && dispatch) {
613
+ // If the slice is a subset, we can let PM replace the selection
614
+ // it will insert as text where it can't place the node.
615
+ // Otherwise we use safeInsert to insert below instead of
616
+ // replacing/splitting the current node.
617
+ if (slice.openStart > 1 && slice.openEnd > 1) {
618
+ dispatch(tr.replaceSelection(newSlice));
619
+ } else {
620
+ dispatch(safeInsert(newSlice.content)(tr));
621
+ }
622
+ return true;
623
+ }
624
+ return false;
625
+ };
626
+ }
627
+ export function handleMarkdown(markdownSlice, queueCardsFromChangedTr, from, to) {
628
+ return function (state, dispatch) {
629
+ var tr = closeHistory(state.tr);
630
+ var pastesFrom = typeof from === 'number' ? from : tr.selection.from;
631
+ if (typeof from === 'number' && typeof to === 'number') {
632
+ tr.replaceRange(from, to, markdownSlice);
633
+ } else {
634
+ tr.replaceSelection(markdownSlice);
635
+ }
636
+ var textPosition = tr.doc.resolve(Math.min(pastesFrom + markdownSlice.size, tr.doc.content.size));
637
+ tr.setSelection(TextSelection.near(textPosition, -1));
638
+ queueCardsFromChangedTr === null || queueCardsFromChangedTr === void 0 || queueCardsFromChangedTr(state, tr, INPUT_METHOD.CLIPBOARD);
639
+ if (dispatch) {
640
+ dispatch(tr.scrollIntoView());
641
+ }
642
+ return true;
643
+ };
644
+ }
645
+ function removePrecedingBackTick(tr) {
646
+ var _tr$selection = tr.selection,
647
+ nodeBefore = _tr$selection.$from.nodeBefore,
648
+ from = _tr$selection.from;
649
+ if (nodeBefore && nodeBefore.isText && nodeBefore.text.endsWith('`')) {
650
+ tr.delete(from - 1, from);
651
+ }
652
+ }
653
+ function hasInlineCode(state, slice) {
654
+ return slice.content.firstChild && slice.content.firstChild.marks.some(function (m) {
655
+ return m.type === state.schema.marks.code;
656
+ });
657
+ }
658
+ function rollupLeafListItems(list, leafListItems) {
659
+ list.content.forEach(function (child) {
660
+ if (isListNode(child) || isListItemNode(child) && isListNode(child.firstChild)) {
661
+ rollupLeafListItems(child, leafListItems);
662
+ } else {
663
+ leafListItems.push(child);
664
+ }
665
+ });
666
+ }
667
+ function shouldFlattenList(state, slice) {
668
+ var node = slice.content.firstChild;
669
+ return node && insideTable(state) && isListNode(node) && slice.openStart > slice.openEnd;
670
+ }
671
+ function sliceHasTopLevelMarks(slice) {
672
+ var hasTopLevelMarks = false;
673
+ slice.content.descendants(function (node) {
674
+ if (node.marks.length > 0) {
675
+ hasTopLevelMarks = true;
676
+ }
677
+ return false;
678
+ });
679
+ return hasTopLevelMarks;
680
+ }
681
+ function getTopLevelMarkTypesInSlice(slice) {
682
+ var markTypes = new Set();
683
+ slice.content.descendants(function (node) {
684
+ node.marks.map(function (mark) {
685
+ return mark.type;
686
+ }).forEach(function (markType) {
687
+ return markTypes.add(markType);
688
+ });
689
+ return false;
690
+ });
691
+ return markTypes;
692
+ }
693
+ export function handleParagraphBlockMarks(state, slice) {
694
+ if (slice.content.size === 0) {
695
+ return slice;
696
+ }
697
+ var schema = state.schema,
698
+ $from = state.selection.$from;
699
+
700
+ // If no paragraph in the slice contains marks, there's no need for special handling
701
+ // Note: this doesn't check for marks applied to lower level nodes such as text
702
+ if (!sliceHasTopLevelMarks(slice)) {
703
+ return slice;
704
+ }
705
+
706
+ // If pasting a single paragraph into pre-existing content, match destination formatting
707
+ var destinationHasContent = $from.parent.textContent.length > 0;
708
+ if (slice.content.childCount === 1 && destinationHasContent) {
709
+ return slice;
710
+ }
711
+
712
+ // Check the parent of (paragraph -> text) because block marks are assigned to a wrapper
713
+ // element around the paragraph node
714
+ var grandparent = $from.node(Math.max(0, $from.depth - 1));
715
+ var markTypesInSlice = getTopLevelMarkTypesInSlice(slice);
716
+ var forbiddenMarkTypes = [];
717
+ var _iterator = _createForOfIteratorHelper(markTypesInSlice),
718
+ _step;
719
+ try {
720
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
721
+ var markType = _step.value;
722
+ if (!grandparent.type.allowsMarkType(markType)) {
723
+ forbiddenMarkTypes.push(markType);
724
+ }
725
+ }
726
+ } catch (err) {
727
+ _iterator.e(err);
728
+ } finally {
729
+ _iterator.f();
730
+ }
731
+ if (forbiddenMarkTypes.length === 0) {
732
+ // In a slice containing one or more paragraphs at the document level (not wrapped in
733
+ // another node), the first paragraph will only have its text content captured and pasted
734
+ // since openStart is 1. We decrement the open depth of the slice so it retains any block
735
+ // marks applied to it. We only care about the depth at the start of the selection so
736
+ // there's no need to change openEnd - the rest of the slice gets pasted correctly.
737
+ var openStart = Math.max(0, slice.openStart - 1);
738
+ return new Slice(slice.content, openStart, slice.openEnd);
739
+ }
740
+
741
+ // If the paragraph contains marks forbidden by the parent node (e.g. alignment/indentation),
742
+ // drop those marks from the slice
743
+ return mapSlice(slice, function (node) {
744
+ if (node.type === schema.nodes.paragraph) {
745
+ return schema.nodes.paragraph.createChecked(undefined, node.content, node.marks.filter(function (mark) {
746
+ return !forbiddenMarkTypes.includes(mark.type);
747
+ }));
748
+ }
749
+ return node;
750
+ });
751
+ }
752
+
753
+ /**
754
+ * ED-6300: When a nested list is pasted in a table cell and the slice has openStart > openEnd,
755
+ * it splits the table. As a workaround, we flatten the list to even openStart and openEnd.
756
+ *
757
+ * Note: this only happens if the first child is a list
758
+ *
759
+ * Example: copying "one" and "two"
760
+ * - zero
761
+ * - one
762
+ * - two
763
+ *
764
+ * Before:
765
+ * ul
766
+ * ┗━ li
767
+ * ┗━ ul
768
+ * ┗━ li
769
+ * ┗━ p -> "one"
770
+ * ┗━ li
771
+ * ┗━ p -> "two"
772
+ *
773
+ * After:
774
+ * ul
775
+ * ┗━ li
776
+ * ┗━ p -> "one"
777
+ * ┗━ li
778
+ * ┗━p -> "two"
779
+ */
780
+ export function flattenNestedListInSlice(slice) {
781
+ if (!slice.content.firstChild) {
782
+ return slice;
783
+ }
784
+ var listToFlatten = slice.content.firstChild;
785
+ var leafListItems = [];
786
+ rollupLeafListItems(listToFlatten, leafListItems);
787
+ var contentWithFlattenedList = slice.content.replaceChild(0, listToFlatten.type.createChecked(listToFlatten.attrs, leafListItems));
788
+ return new Slice(contentWithFlattenedList, slice.openEnd, slice.openEnd);
789
+ }
790
+ export function handleRichText(slice, queueCardsFromChangedTr) {
791
+ return function (state, dispatch) {
792
+ var _slice$content, _slice$content2, _firstChildOfSlice$ty, _lastChildOfSlice$typ, _panelParentOverCurre;
793
+ var _state$schema$nodes3 = state.schema.nodes,
794
+ codeBlock = _state$schema$nodes3.codeBlock,
795
+ heading = _state$schema$nodes3.heading,
796
+ paragraph = _state$schema$nodes3.paragraph,
797
+ panel = _state$schema$nodes3.panel;
798
+ var selection = state.selection,
799
+ schema = state.schema;
800
+ var firstChildOfSlice = (_slice$content = slice.content) === null || _slice$content === void 0 ? void 0 : _slice$content.firstChild;
801
+ var lastChildOfSlice = (_slice$content2 = slice.content) === null || _slice$content2 === void 0 ? void 0 : _slice$content2.lastChild;
802
+
803
+ // In case user is pasting inline code,
804
+ // any backtick ` immediately preceding it should be removed.
805
+ var tr = state.tr;
806
+ if (hasInlineCode(state, slice)) {
807
+ removePrecedingBackTick(tr);
808
+ }
809
+ if (shouldFlattenList(state, slice)) {
810
+ slice = flattenNestedListInSlice(slice);
811
+ }
812
+ closeHistory(tr);
813
+ var isFirstChildListNode = isListNode(firstChildOfSlice);
814
+ var isLastChildListNode = isListNode(lastChildOfSlice);
815
+ var isSliceContentListNodes = isFirstChildListNode || isLastChildListNode;
816
+ var isFirstChildTaskListNode = (firstChildOfSlice === null || firstChildOfSlice === void 0 || (_firstChildOfSlice$ty = firstChildOfSlice.type) === null || _firstChildOfSlice$ty === void 0 ? void 0 : _firstChildOfSlice$ty.name) === 'taskList';
817
+ var isLastChildTaskListNode = (lastChildOfSlice === null || lastChildOfSlice === void 0 || (_lastChildOfSlice$typ = lastChildOfSlice.type) === null || _lastChildOfSlice$typ === void 0 ? void 0 : _lastChildOfSlice$typ.name) === 'taskList';
818
+ var isSliceContentTaskListNodes = isFirstChildTaskListNode || isLastChildTaskListNode;
819
+
820
+ // We want to use safeInsert to insert invalid content, as it inserts at the closest non schema violating position
821
+ // rather than spliting the selection parent node in half (which is what replaceSelection does)
822
+ // Exception is paragraph and heading nodes, these should be split, provided their parent supports the pasted content
823
+ var textNodes = [heading, paragraph];
824
+ var selectionParent = selection.$to.node(selection.$to.depth - 1);
825
+ var noNeedForSafeInsert = selection.$to.node().type.validContent(slice.content) || textNodes.includes(selection.$to.node().type) && selectionParent.type.validContent(slice.content);
826
+ var panelParentOverCurrentSelection = findParentNodeOfType(panel)(tr.selection);
827
+ var isTargetPanelEmpty = panelParentOverCurrentSelection && ((_panelParentOverCurre = panelParentOverCurrentSelection.node) === null || _panelParentOverCurre === void 0 ? void 0 : _panelParentOverCurre.content.size) === 2;
828
+ if (!isSliceContentTaskListNodes && (isSliceContentListNodes || isTargetPanelEmpty)) {
829
+ insertSliceForLists({
830
+ tr: tr,
831
+ slice: slice,
832
+ schema: schema
833
+ });
834
+ } else if (noNeedForSafeInsert) {
835
+ var _firstChildOfSlice$ty2, _firstChildOfSlice$co, _firstChildOfSlice$co2;
836
+ if ((firstChildOfSlice === null || firstChildOfSlice === void 0 || (_firstChildOfSlice$ty2 = firstChildOfSlice.type) === null || _firstChildOfSlice$ty2 === void 0 ? void 0 : _firstChildOfSlice$ty2.name) === 'blockquote' && firstChildOfSlice !== null && firstChildOfSlice !== void 0 && (_firstChildOfSlice$co = firstChildOfSlice.content.firstChild) !== null && _firstChildOfSlice$co !== void 0 && _firstChildOfSlice$co.type.name && ['bulletList', 'orderedList'].includes(firstChildOfSlice === null || firstChildOfSlice === void 0 || (_firstChildOfSlice$co2 = firstChildOfSlice.content.firstChild) === null || _firstChildOfSlice$co2 === void 0 ? void 0 : _firstChildOfSlice$co2.type.name)) {
837
+ // checks if parent node is a blockquote and child node is either a bulletlist or orderedlist
838
+ insertSliceForListsInsideBlockquote({
839
+ tr: tr,
840
+ slice: slice
841
+ });
842
+ } else {
843
+ var _slice$content$lastCh;
844
+ tr.replaceSelection(slice);
845
+ // when cursor is inside a table cell, and slice.content.lastChild is a panel, expand, or decisionList
846
+ // need to make sure the cursor position is is right after the panel, expand, or decisionList
847
+ // still in the same table cell, see issue: https://product-fabric.atlassian.net/browse/ED-17862
848
+ var shouldUpdateCursorPosAfterPaste = ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 || (_slice$content$lastCh = _slice$content$lastCh.type) === null || _slice$content$lastCh === void 0 ? void 0 : _slice$content$lastCh.name) || '');
849
+ if (insideTableCell(state) && shouldUpdateCursorPosAfterPaste) {
850
+ var nextPos = tr.doc.resolve(tr.mapping.map(selection.$from.pos));
851
+ tr.setSelection(new GapCursorSelection(nextPos, Side.RIGHT));
852
+ }
853
+ }
854
+ } else {
855
+ // need to scan the slice if there's a block node or list items inside it
856
+ var sliceHasList = false;
857
+ slice.content.nodesBetween(0, slice.content.size, function (node, start) {
858
+ if (node.type === state.schema.nodes.listItem) {
859
+ sliceHasList = true;
860
+ return false;
861
+ }
862
+ });
863
+ if (insideTableCell(state) && isInListItem(state) && canInsert(selection.$from, slice.content) && canInsert(selection.$to, slice.content) || sliceHasList) {
864
+ tr.replaceSelection(slice);
865
+ } else {
866
+ // need safeInsert rather than replaceSelection, so that nodes aren't split in half
867
+ // e.g. when pasting a layout into a table, replaceSelection splits the table in half and adds the layout in the middle
868
+ tr = safeInsert(slice.content, tr.selection.$to.pos)(tr);
869
+ }
870
+ }
871
+ tr.setStoredMarks([]);
872
+ if (tr.selection.empty && tr.selection.$from.parent.type === codeBlock) {
873
+ tr.setSelection(TextSelection.near(tr.selection.$from, 1));
874
+ }
875
+ tr.scrollIntoView();
876
+
877
+ // queue link cards, ignoring any errors
878
+ queueCardsFromChangedTr === null || queueCardsFromChangedTr === void 0 || queueCardsFromChangedTr(state, tr, INPUT_METHOD.CLIPBOARD);
879
+ if (dispatch) {
880
+ dispatch(tr);
881
+ }
882
+ return true;
883
+ };
884
+ }
885
+ export function handlePasteIntoCaption(slice) {
886
+ return function (state, dispatch) {
887
+ var caption = state.schema.nodes.caption;
888
+ var tr = state.tr;
889
+ if (hasParentNodeOfType(caption)(state.selection)) {
890
+ // We let PM replace the selection and it will insert as text where it can't place the node
891
+ // This is totally fine as caption is just a simple block that only contains inline contents
892
+ // And it is more in line with WYSIWYG expectations
893
+ tr.replaceSelection(slice).scrollIntoView();
894
+ if (dispatch) {
895
+ dispatch(tr);
896
+ }
897
+ return true;
898
+ }
899
+ return false;
900
+ };
901
+ }
902
+ export var handleSelectedTable = function handleSelectedTable(editorAnalyticsAPI) {
903
+ return function (slice) {
904
+ return function (state, dispatch) {
905
+ var tr = replaceSelectedTable(state, slice);
906
+
907
+ // add analytics after replacing selected table
908
+ tr = addReplaceSelectedTableAnalytics(state, tr, editorAnalyticsAPI);
909
+ if (tr.docChanged) {
910
+ if (dispatch) {
911
+ dispatch(tr);
912
+ }
913
+ return true;
914
+ }
915
+ return false;
916
+ };
917
+ };
918
+ };