@atlaskit/editor-plugin-paste
Version:
Paste plugin for @atlaskit/editor-core
113 lines (108 loc) • 5.35 kB
JavaScript
import { isEmptyParagraph } from '@atlaskit/editor-common/utils';
import { Fragment } from '@atlaskit/editor-prosemirror/model';
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
import { Transform } from '@atlaskit/editor-prosemirror/transform';
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
export function insertSliceIntoEmptyNode(_ref) {
var tr = _ref.tr,
slice = _ref.slice;
tr.replaceSelection(slice);
}
export function insertSliceAtNodeEdge(_ref2) {
var tr = _ref2.tr,
slice = _ref2.slice;
var selection = tr.selection;
var _ref3 = selection,
$cursor = _ref3.$cursor;
if (!$cursor) {
return;
}
var position = !$cursor.nodeBefore ? $cursor.before() : $cursor.after();
tr.replaceRange(position, position, slice);
var startSlicePosition = tr.doc.resolve(Math.min(position + slice.content.size - slice.openEnd, tr.doc.content.size));
var direction = -1;
tr.setSelection(TextSelection.near(startSlicePosition, direction));
}
export function insertSliceIntoRangeSelectionInsideList(_ref4) {
var tr = _ref4.tr,
slice = _ref4.slice;
var _tr$selection = tr.selection,
$to = _tr$selection.$to,
$from = _tr$selection.$from,
to = _tr$selection.to,
from = _tr$selection.from;
// when the selection is inside of the same list item
// we can use a normal replace
if ($from.sameParent($to) || $from.depth === $to.depth) {
return tr.replaceSelection(slice);
}
// if pasting a list inside another list, ensure no empty list items get added
var newRange = $from.blockRange($to);
if (!newRange) {
return;
}
var startPos = from;
var endPos = $to.nodeAfter ? to : to + 2;
var newSlice = tr.doc.slice(endPos, newRange.end);
tr.deleteRange(startPos, newRange.end);
var mapped = tr.mapping.map(startPos);
tr.replaceRange(mapped, mapped, slice);
if (newSlice.size <= 0) {
return;
}
var newSelection = TextSelection.near(tr.doc.resolve(tr.mapping.map(mapped)), -1);
// @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
newSlice.openEnd = newSlice.openStart;
tr.replaceRange(newSelection.from, newSelection.from, newSlice);
tr.setSelection(TextSelection.near(tr.doc.resolve(newSelection.from), -1));
}
export function insertSliceInsideOfPanelNodeSelected(panelNode) {
return function (_ref5) {
var tr = _ref5.tr,
slice = _ref5.slice,
schema = _ref5.schema;
var selection = tr.selection,
_tr$selection2 = tr.selection,
$to = _tr$selection2.$to,
$from = _tr$selection2.$from;
var panelPosition = selection.from;
// if content of slice isn't valid for a panel node, insert the invalid node and following content after
if (panelNode && !panelNode.type.validContent(Fragment.from(slice.content))) {
var _parentNode$firstChil;
var insertPosition = $to.pos + 1;
/* Adapting above logic to handle MBE, as it currently assumes that slice can be safely inserted after the panel node, which is not the case for MBE
If insertPosition is in MBE and current slice contains invalid content for MBE, we need to insert the slice after the MBE node
*/
if (schema) {
var mbeParentOfPanel = findParentNodeOfType(schema.nodes.multiBodiedExtension)(selection);
if (mbeParentOfPanel && !mbeParentOfPanel.node.type.validContent(Fragment.from(slice.content))) {
insertPosition = mbeParentOfPanel.start + mbeParentOfPanel.node.nodeSize - 1;
}
}
tr.replaceRange(insertPosition, insertPosition, slice);
// need to delete the empty paragraph at the top of the panel
var parentNode = tr.doc.resolve($from.before()).node();
if (parentNode && parentNode.childCount > 1 && ((_parentNode$firstChil = parentNode.firstChild) === null || _parentNode$firstChil === void 0 ? void 0 : _parentNode$firstChil.type.name) === 'paragraph' && isEmptyParagraph(parentNode.firstChild)) {
var startPosDelete = tr.doc.resolve($from.before()).posAtIndex(0);
var endPosDelete = tr.doc.resolve($from.before()).posAtIndex(1);
var SIZE_OF_EMPTY_PARAGRAPH = 2; // {startPos}<p>{startPos + 1}</p>{endPos}
if (endPosDelete - startPosDelete === SIZE_OF_EMPTY_PARAGRAPH) {
tr.delete(startPosDelete, endPosDelete);
}
}
tr.setSelection(TextSelection.near(tr.doc.resolve(insertPosition + slice.content.size - slice.openStart - slice.openEnd + 1)));
return;
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
var temporaryDoc = new Transform(tr.doc.type.createAndFill());
temporaryDoc.replaceRange(0, temporaryDoc.doc.content.size, slice);
var sliceWithoutInvalidListSurrounding = temporaryDoc.doc.slice(0);
var newPanel = panelNode.copy(sliceWithoutInvalidListSurrounding.content);
var panelNodeSelected = selection instanceof NodeSelection ? selection.node : null;
var replaceFrom = panelNodeSelected ? panelPosition : tr.doc.resolve(panelPosition).start();
var replaceTo = panelNodeSelected ? panelPosition + panelNodeSelected.nodeSize : replaceFrom;
tr.replaceRangeWith(replaceFrom, replaceTo, newPanel);
tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + newPanel.content.size), -1));
};
}