@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,87 @@
|
|
|
1
|
+
import { isListNode } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
import { findParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { isCursorSelectionAtTextStartOrEnd, isEmptyNode, isSelectionInsidePanel } from '../util';
|
|
6
|
+
import { insertSliceAtNodeEdge, insertSliceInsideOfPanelNodeSelected, insertSliceIntoEmptyNode, insertSliceIntoRangeSelectionInsideList } from './lists';
|
|
7
|
+
export function insertSliceForLists({
|
|
8
|
+
tr,
|
|
9
|
+
slice,
|
|
10
|
+
schema
|
|
11
|
+
}) {
|
|
12
|
+
var _slice$content$firstC;
|
|
13
|
+
const {
|
|
14
|
+
selection,
|
|
15
|
+
selection: {
|
|
16
|
+
$to,
|
|
17
|
+
$from
|
|
18
|
+
}
|
|
19
|
+
} = tr;
|
|
20
|
+
const {
|
|
21
|
+
$cursor
|
|
22
|
+
} = selection;
|
|
23
|
+
const panelNode = isSelectionInsidePanel(selection);
|
|
24
|
+
const selectionIsInsideList = $from.blockRange($to, isListNode);
|
|
25
|
+
if (!$cursor && selectionIsInsideList) {
|
|
26
|
+
return insertSliceIntoRangeSelectionInsideList({
|
|
27
|
+
tr,
|
|
28
|
+
slice
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// if inside an empty panel, try and insert content inside it rather than replace it
|
|
33
|
+
if (panelNode && isEmptyNode(panelNode) && $from.node() === $to.node()) {
|
|
34
|
+
return insertSliceInsideOfPanelNodeSelected(panelNode)({
|
|
35
|
+
tr,
|
|
36
|
+
slice
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (!$cursor || selectionIsInsideList) {
|
|
40
|
+
return tr.replaceSelection(slice);
|
|
41
|
+
}
|
|
42
|
+
if (isEmptyNode(tr.doc.resolve($cursor.pos).node())) {
|
|
43
|
+
return insertSliceIntoEmptyNode({
|
|
44
|
+
tr,
|
|
45
|
+
slice
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// When pasting a single list item into an action or decision, we skip the special "insert at node edge"
|
|
50
|
+
// logic so that prosemirror pastes the list's content into the action/decision, rather than
|
|
51
|
+
// pasting a whole list node directly after the action/decision item. (But we still preserve the
|
|
52
|
+
// existing "insert at" node edge" behaviour if dealing with a list with more than one item, so that
|
|
53
|
+
// it still inserts whole list node after the action/decision item).
|
|
54
|
+
const pastingIntoActionOrDecision = Boolean(findParentNodeOfType([schema.nodes.taskList, schema.nodes.decisionList])(selection));
|
|
55
|
+
const oneListItem = slice.content.childCount === 1 && isListNode(slice.content.firstChild) && ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.childCount) === 1;
|
|
56
|
+
if (!(pastingIntoActionOrDecision && oneListItem) && isCursorSelectionAtTextStartOrEnd(selection)) {
|
|
57
|
+
return insertSliceAtNodeEdge({
|
|
58
|
+
tr,
|
|
59
|
+
slice
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
tr.replaceSelection(slice);
|
|
63
|
+
}
|
|
64
|
+
export function insertSliceForListsInsideBlockquote({
|
|
65
|
+
tr,
|
|
66
|
+
slice
|
|
67
|
+
}) {
|
|
68
|
+
safeInsert(slice.content, tr.selection.$to.pos)(tr).scrollIntoView();
|
|
69
|
+
// ProseMirror doesn't give a proper way to tell us where something was inserted.
|
|
70
|
+
// However, we can know "how" it inserted something.
|
|
71
|
+
//
|
|
72
|
+
// So, instead of weird depth calculations, we can use the step produced by the transform.
|
|
73
|
+
// For instance:
|
|
74
|
+
// The `replaceStep.to and replaceStep.from`, tell us the real position
|
|
75
|
+
// where the content will be insert.
|
|
76
|
+
// Then, we can use the `tr.mapping.map` to the updated position after the replace operation
|
|
77
|
+
const replaceStep = tr.steps[0];
|
|
78
|
+
if (!(replaceStep instanceof ReplaceStep)) {
|
|
79
|
+
return tr;
|
|
80
|
+
}
|
|
81
|
+
const nextPosition = tr.mapping.map(replaceStep.to);
|
|
82
|
+
// The findFrom will make search for both: TextSelection and NodeSelections.
|
|
83
|
+
const nextSelection = Selection.findFrom(tr.doc.resolve(Math.min(nextPosition, tr.doc.content.size)), -1);
|
|
84
|
+
if (nextSelection) {
|
|
85
|
+
tr.setSelection(nextSelection);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { Transform } from '@atlaskit/editor-prosemirror/transform';
|
|
5
|
+
export function insertSliceIntoEmptyNode({
|
|
6
|
+
tr,
|
|
7
|
+
slice
|
|
8
|
+
}) {
|
|
9
|
+
tr.replaceSelection(slice);
|
|
10
|
+
}
|
|
11
|
+
export function insertSliceAtNodeEdge({
|
|
12
|
+
tr,
|
|
13
|
+
slice
|
|
14
|
+
}) {
|
|
15
|
+
const {
|
|
16
|
+
selection
|
|
17
|
+
} = tr;
|
|
18
|
+
const {
|
|
19
|
+
$cursor
|
|
20
|
+
} = selection;
|
|
21
|
+
if (!$cursor) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const position = !$cursor.nodeBefore ? $cursor.before() : $cursor.after();
|
|
25
|
+
tr.replaceRange(position, position, slice);
|
|
26
|
+
const startSlicePosition = tr.doc.resolve(Math.min(position + slice.content.size - slice.openEnd, tr.doc.content.size));
|
|
27
|
+
const direction = -1;
|
|
28
|
+
tr.setSelection(TextSelection.near(startSlicePosition, direction));
|
|
29
|
+
}
|
|
30
|
+
export function insertSliceIntoRangeSelectionInsideList({
|
|
31
|
+
tr,
|
|
32
|
+
slice
|
|
33
|
+
}) {
|
|
34
|
+
const {
|
|
35
|
+
selection: {
|
|
36
|
+
$to,
|
|
37
|
+
$from,
|
|
38
|
+
to,
|
|
39
|
+
from
|
|
40
|
+
}
|
|
41
|
+
} = tr;
|
|
42
|
+
|
|
43
|
+
// when the selection is inside of the same list item
|
|
44
|
+
// we can use a normal replace
|
|
45
|
+
if ($from.sameParent($to) || $from.depth === $to.depth) {
|
|
46
|
+
return tr.replaceSelection(slice);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// if pasting a list inside another list, ensure no empty list items get added
|
|
50
|
+
const newRange = $from.blockRange($to);
|
|
51
|
+
if (!newRange) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const startPos = from;
|
|
55
|
+
const endPos = $to.nodeAfter ? to : to + 2;
|
|
56
|
+
const newSlice = tr.doc.slice(endPos, newRange.end);
|
|
57
|
+
tr.deleteRange(startPos, newRange.end);
|
|
58
|
+
const mapped = tr.mapping.map(startPos);
|
|
59
|
+
tr.replaceRange(mapped, mapped, slice);
|
|
60
|
+
if (newSlice.size <= 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const newSelection = TextSelection.near(tr.doc.resolve(tr.mapping.map(mapped)), -1);
|
|
64
|
+
// @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
|
|
65
|
+
newSlice.openEnd = newSlice.openStart;
|
|
66
|
+
tr.replaceRange(newSelection.from, newSelection.from, newSlice);
|
|
67
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(newSelection.from), -1));
|
|
68
|
+
}
|
|
69
|
+
export function insertSliceInsideOfPanelNodeSelected(panelNode) {
|
|
70
|
+
return ({
|
|
71
|
+
tr,
|
|
72
|
+
slice
|
|
73
|
+
}) => {
|
|
74
|
+
const {
|
|
75
|
+
selection,
|
|
76
|
+
selection: {
|
|
77
|
+
$to,
|
|
78
|
+
$from
|
|
79
|
+
}
|
|
80
|
+
} = tr;
|
|
81
|
+
const {
|
|
82
|
+
from: panelPosition
|
|
83
|
+
} = selection;
|
|
84
|
+
|
|
85
|
+
// if content of slice isn't valid for a panel node, insert the invalid node and following content after
|
|
86
|
+
if (panelNode && !panelNode.type.validContent(Fragment.from(slice.content))) {
|
|
87
|
+
var _parentNode$firstChil;
|
|
88
|
+
const insertPosition = $to.pos + 1;
|
|
89
|
+
tr.replaceRange(insertPosition, insertPosition, slice);
|
|
90
|
+
// need to delete the empty paragraph at the top of the panel
|
|
91
|
+
const parentNode = tr.doc.resolve($from.before()).node();
|
|
92
|
+
if (parentNode && parentNode.childCount > 1 && ((_parentNode$firstChil = parentNode.firstChild) === null || _parentNode$firstChil === void 0 ? void 0 : _parentNode$firstChil.type.name) === 'paragraph' && isEmptyParagraph(parentNode.firstChild)) {
|
|
93
|
+
const startPosDelete = tr.doc.resolve($from.before()).posAtIndex(0);
|
|
94
|
+
const endPosDelete = tr.doc.resolve($from.before()).posAtIndex(1);
|
|
95
|
+
const SIZE_OF_EMPTY_PARAGRAPH = 2; // {startPos}<p>{startPos + 1}</p>{endPos}
|
|
96
|
+
if (endPosDelete - startPosDelete === SIZE_OF_EMPTY_PARAGRAPH) {
|
|
97
|
+
tr.delete(startPosDelete, endPosDelete);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve(insertPosition + slice.content.size - slice.openStart - slice.openEnd + 1)));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const temporaryDoc = new Transform(tr.doc.type.createAndFill());
|
|
104
|
+
temporaryDoc.replaceRange(0, temporaryDoc.doc.content.size, slice);
|
|
105
|
+
const sliceWithoutInvalidListSurrounding = temporaryDoc.doc.slice(0);
|
|
106
|
+
const newPanel = panelNode.copy(sliceWithoutInvalidListSurrounding.content);
|
|
107
|
+
const panelNodeSelected = selection instanceof NodeSelection ? selection.node : null;
|
|
108
|
+
const replaceFrom = panelNodeSelected ? panelPosition : tr.doc.resolve(panelPosition).start();
|
|
109
|
+
const replaceTo = panelNodeSelected ? panelPosition + panelNodeSelected.nodeSize : replaceFrom;
|
|
110
|
+
tr.replaceRangeWith(replaceFrom, replaceTo, newPanel);
|
|
111
|
+
tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + newPanel.content.size), -1));
|
|
112
|
+
};
|
|
113
|
+
}
|