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