UNPKG

@atlaskit/editor-plugin-selection

Version:

Selection plugin for @atlaskit/editor-core

109 lines (105 loc) 4.28 kB
import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state'; var DOC_START_POS = 0; function isNodeContentEmpty(maybeNode) { return (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.content.size) === 0 || (maybeNode === null || maybeNode === void 0 ? void 0 : maybeNode.textContent) === ''; } function findEmptySelectableParentNodePosition($pos) { var doc = $pos.doc; if ($pos.pos > doc.content.size) { return null; } if (isCurrentNodeAtomOrEmptySelectable($pos)) { return $pos; } if ($pos.nodeBefore !== null) { return null; } if ($pos.depth === 0 && $pos.pos === 0) { return $pos; } var positionLevelUp = $pos.before(); var resolvedPositionLevelUp = doc.resolve(positionLevelUp); return findEmptySelectableParentNodePosition(resolvedPositionLevelUp); } var isCurrentNodeAtomOrEmptySelectable = function isCurrentNodeAtomOrEmptySelectable($pos) { //ED-20209: Using $resolvedJustBeforeNodePos so that $resolvedJustBeforeNodePos.nodeAfter return the node at $pos.pos even if that is an atomic node if ($pos.pos === DOC_START_POS) { return false; } var justBeforeNodePos = $pos.pos - 1; var $resolvedjustBeforePos = $pos.doc.resolve(justBeforeNodePos); var maybeNode = $resolvedjustBeforePos.nodeAfter; if (!maybeNode || !maybeNode.isBlock) { return false; } if (maybeNode.isAtom) { return true; } return isNodeContentEmpty(maybeNode) && NodeSelection.isSelectable(maybeNode); }; function findNextSelectionPosition(_ref) { var $targetHead = _ref.$targetHead, $anchor = _ref.$anchor, doc = _ref.doc; var direction = $anchor.pos < $targetHead.pos ? 'down' : 'up'; //ED-20209: If the targetHead position is just before some node, Then return $targetHead and not select any node. var maybeNode = null; // prosemirror calls 'createSelectionBetween' for native 'drop' events, it passes $anchor // and $head which are based on a transformed document, but only provides the original // doc. Need to remap the $head pos to last element in doc to avoid RangeErrors. if ($targetHead.pos >= doc.nodeSize) { maybeNode = doc.resolve(doc.nodeSize - 2).nodeBefore; } else if ($targetHead.pos !== DOC_START_POS) { var justBeforeHeadPos = $targetHead.pos - 1; var $resolvedJustBeforeHeadPos = doc.resolve(justBeforeHeadPos); maybeNode = $resolvedJustBeforeHeadPos.nodeAfter; } if (maybeNode === null) { maybeNode = $targetHead.nodeAfter; if (maybeNode !== null) { $targetHead = doc.resolve($targetHead.pos + 1); } else { return null; } } var maybeNextPosition = findEmptySelectableParentNodePosition($targetHead); if (maybeNextPosition) { var justBeforeMaybeNextPos = maybeNextPosition.pos - 1; if (direction === 'up') { return doc.resolve(Math.max(justBeforeMaybeNextPos, 0)); } else { var maybeNextNode = doc.resolve(justBeforeMaybeNextPos).nodeAfter; if (maybeNextNode) { return doc.resolve(Math.min(justBeforeMaybeNextPos + maybeNextNode.nodeSize, doc.content.size)); } } } return null; } export var onCreateSelectionBetween = function onCreateSelectionBetween(view, $anchor, $head) { var _$head$parent, _$head$parent2; if ($anchor.pos === $head.pos) { return null; } if ($anchor.depth === $head.depth && $anchor.sameParent($head)) { return null; } // If the head is targeting a paragraph on root, then let ProseMirror handle the text selection if ($head.depth === 1 && ((_$head$parent = $head.parent) === null || _$head$parent === void 0 ? void 0 : _$head$parent.type.name) === 'paragraph') { return null; } // If head is at the beginning of a non-empty textblock, let ProseMirror handle the text selection if ((_$head$parent2 = $head.parent) !== null && _$head$parent2 !== void 0 && _$head$parent2.isTextblock && !isNodeContentEmpty($head.parent) && $head.parentOffset === 0) { return null; } var $nextHeadPosition = findNextSelectionPosition({ $targetHead: $head, $anchor: $anchor, doc: view.state.doc }); if (!$nextHeadPosition) { return null; } var forcedTextSelection = TextSelection.create(view.state.doc, $anchor.pos, $nextHeadPosition.pos); return forcedTextSelection; };