UNPKG

@atlaskit/editor-plugin-selection

Version:

Selection plugin for @atlaskit/editor-core

260 lines (258 loc) 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setSelectionRelativeToNode = exports.setSelectionInsideAtNodeEnd = exports.selectNearNode = exports.arrowRight = exports.arrowLeft = void 0; var _selection = require("@atlaskit/editor-common/selection"); var _utils = require("@atlaskit/editor-common/utils"); var _state = require("@atlaskit/editor-prosemirror/state"); var _types = require("../types"); var _actions = require("./actions"); var _pluginFactory = require("./plugin-factory"); var _utils2 = require("./utils"); /* eslint-disable import/no-extraneous-dependencies */ var selectNearNode = exports.selectNearNode = function selectNearNode(selectionRelativeToNode, selection) { return function (_ref) { var tr = _ref.tr; tr.setMeta(_types.selectionPluginKey, { type: _actions.SelectionActionTypes.SET_RELATIVE_SELECTION, selectionRelativeToNode: selectionRelativeToNode }); if (selection) { return tr.setSelection(selection); } return tr; }; }; var setSelectionRelativeToNode = exports.setSelectionRelativeToNode = function setSelectionRelativeToNode(selectionRelativeToNode, selection) { return (0, _pluginFactory.createCommand)({ type: _actions.SelectionActionTypes.SET_RELATIVE_SELECTION, selectionRelativeToNode: selectionRelativeToNode }, function (tr) { return selectNearNode(selectionRelativeToNode, selection)({ tr: tr }) || tr; }); }; var arrowRight = exports.arrowRight = function arrowRight(state, dispatch) { var selection = state.selection; if (selection instanceof _selection.GapCursorSelection) { return arrowRightFromGapCursor(selection)(state, dispatch); } else if (selection instanceof _state.NodeSelection) { return arrowRightFromNode(selection)(state, dispatch); } else if (selection instanceof _state.TextSelection) { return arrowRightFromText(selection)(state, dispatch); } return false; }; var arrowLeft = exports.arrowLeft = function arrowLeft(state, dispatch) { var selection = state.selection; if (selection instanceof _selection.GapCursorSelection) { return arrowLeftFromGapCursor(selection)(state, dispatch); } else if (selection instanceof _state.NodeSelection) { return arrowLeftFromNode(selection)(state, dispatch); } else if (selection instanceof _state.TextSelection) { return arrowLeftFromText(selection)(state, dispatch); } return false; }; var arrowRightFromGapCursor = function arrowRightFromGapCursor(selection) { return function (state, dispatch) { var $from = selection.$from, $to = selection.$to, side = selection.side; if (side === _selection.Side.LEFT) { var selectableNode = (0, _utils2.findSelectableContainerAfter)($to, state.doc); if (selectableNode) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.Start, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } } else if (side === _selection.Side.RIGHT && (0, _utils2.isSelectionAtEndOfParentNode)($from, selection)) { var _selectableNode = (0, _utils2.findSelectableContainerParent)(selection); if (_selectableNode) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, _selectableNode.pos))(state, dispatch); } } return false; }; }; var arrowLeftFromGapCursor = function arrowLeftFromGapCursor(selection) { return function (state, dispatch) { var $from = selection.$from, side = selection.side; var _getPluginState = (0, _pluginFactory.getPluginState)(state), selectionRelativeToNode = _getPluginState.selectionRelativeToNode; if (side === _selection.Side.RIGHT) { var selectableNode = (0, _utils2.findSelectableContainerBefore)($from, state.doc); if (selectableNode) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } } else if (side === _selection.Side.LEFT && (0, _utils2.isSelectionAtStartOfParentNode)($from, selection)) { if (selectionRelativeToNode === _selection.RelativeSelectionPos.Before) { var $parent = state.doc.resolve(selection.$from.before(selection.$from.depth)); if ($parent) { var _selectableNode2 = (0, _utils2.findSelectableContainerBefore)($parent, state.doc); if (_selectableNode2 && (0, _selection.isIgnored)(_selectableNode2.node)) { // selection is inside node without gap cursor preceeded by another node without gap cursor - set node selection for previous node return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, _selectableNode2.pos))(state, dispatch); } } // we don't return this as we want to reset the relative pos, but not block other plugins // from responding to arrow left key setSelectionRelativeToNode()(state, dispatch); } else { var _selectableNode3 = (0, _utils2.findSelectableContainerParent)(selection); if (_selectableNode3) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.Start, _state.NodeSelection.create(state.doc, _selectableNode3.pos))(state, dispatch); } } } return false; }; }; var arrowRightFromNode = function arrowRightFromNode(selection) { return function (state, dispatch) { var node = selection.node, from = selection.from, $to = selection.$to; var _getPluginState2 = (0, _pluginFactory.getPluginState)(state), selectionRelativeToNode = _getPluginState2.selectionRelativeToNode; if (node.isAtom) { if ((0, _utils2.isSelectionAtEndOfParentNode)($to, selection) && (node.isInline || (0, _selection.isIgnored)(node))) { // selection is for inline node or atom node which is ignored by gap-cursor and that is the last child of its parent node - set text selection after it return findAndSetTextSelection(_selection.RelativeSelectionPos.End, state.doc.resolve(from + 1), _types.SelectionDirection.After)(state, dispatch); } return false; } else if (selectionRelativeToNode === _selection.RelativeSelectionPos.Start) { // selection is for container node - set selection inside it at the start return setSelectionInsideAtNodeStart(_selection.RelativeSelectionPos.Inside, node, from)(state, dispatch); } else if ((0, _selection.isIgnored)(node) && (!selectionRelativeToNode || selectionRelativeToNode === _selection.RelativeSelectionPos.End)) { var selectableNode = (0, _utils2.findSelectableContainerAfter)($to, state.doc); if (selectableNode && (0, _selection.isIgnored)(selectableNode.node)) { // selection is for node without gap cursor followed by another node without gap cursor - set node selection for next node return setSelectionRelativeToNode(_selection.RelativeSelectionPos.Start, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } } return false; }; }; var arrowLeftFromNode = function arrowLeftFromNode(selection) { return function (state, dispatch) { var node = selection.node, from = selection.from, to = selection.to, $from = selection.$from; var _getPluginState3 = (0, _pluginFactory.getPluginState)(state), selectionRelativeToNode = _getPluginState3.selectionRelativeToNode; if (node.isAtom) { if ((0, _utils2.isSelectionAtStartOfParentNode)($from, selection) && (node.isInline || (0, _selection.isIgnored)(node))) { // selection is for inline node or atom node which is ignored by gap-cursor and that is the first child of its parent node - set text selection before it return findAndSetTextSelection(_selection.RelativeSelectionPos.Start, state.doc.resolve(from), _types.SelectionDirection.Before)(state, dispatch); } return false; } else if (selectionRelativeToNode === _selection.RelativeSelectionPos.End) { // selection is for container node - set selection inside it at the end return setSelectionInsideAtNodeEnd(_selection.RelativeSelectionPos.Inside, node, from, to)(state, dispatch); } else if (!selectionRelativeToNode || selectionRelativeToNode === _selection.RelativeSelectionPos.Inside) { // selection is for container node - set selection inside it at the start // (this is a special case when the user selects by clicking node) return setSelectionInsideAtNodeStart(_selection.RelativeSelectionPos.Before, node, from)(state, dispatch); } else if ((0, _selection.isIgnored)(node) && selectionRelativeToNode === _selection.RelativeSelectionPos.Start) { // selection is for node without gap cursor preceeded by another node without gap cursor - set node selection for previous node var selectableNode = (0, _utils2.findSelectableContainerBefore)($from, state.doc); if (selectableNode && (0, _selection.isIgnored)(selectableNode.node)) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } } return false; }; }; var arrowRightFromText = function arrowRightFromText(selection) { return function (state, dispatch) { if ((0, _utils2.isSelectionAtEndOfParentNode)(selection.$to, selection)) { var selectableNode = (0, _utils2.findSelectableContainerParent)(selection); if (selectableNode) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } } return false; }; }; var arrowLeftFromText = function arrowLeftFromText(selection) { return function (state, dispatch) { var _getPluginState4 = (0, _pluginFactory.getPluginState)(state), selectionRelativeToNode = _getPluginState4.selectionRelativeToNode; if (selectionRelativeToNode === _selection.RelativeSelectionPos.Before) { var selectableNode = (0, _utils2.findSelectableContainerBefore)(selection.$from, state.doc); if (selectableNode && (0, _selection.isIgnored)(selectableNode.node)) { // selection is inside node without gap cursor preceeded by another node without gap cursor - set node selection for previous node return setSelectionRelativeToNode(_selection.RelativeSelectionPos.End, _state.NodeSelection.create(state.doc, selectableNode.pos))(state, dispatch); } // we don't return this as we want to reset the relative pos, but not block other plugins // from responding to arrow left key setSelectionRelativeToNode(undefined)(state, dispatch); } else if ((0, _utils2.isSelectionAtStartOfParentNode)(selection.$from, selection)) { var _selectableNode4 = (0, _utils2.findSelectableContainerParent)(selection); if (_selectableNode4) { return setSelectionRelativeToNode(_selection.RelativeSelectionPos.Start, _state.NodeSelection.create(state.doc, _selectableNode4.pos))(state, dispatch); } } return false; }; }; var findAndSetTextSelection = function findAndSetTextSelection(selectionRelativeToNode, $pos, dir) { return function (state, dispatch) { var sel = _state.Selection.findFrom($pos, dir, true); if (sel) { return setSelectionRelativeToNode(selectionRelativeToNode, sel)(state, dispatch); } return false; }; }; var setSelectionInsideAtNodeStart = function setSelectionInsideAtNodeStart(selectionRelativeToNode, node, pos) { return function (state, dispatch) { if ((0, _utils.isNodeEmpty)(node)) { return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(pos), _types.SelectionDirection.After)(state, dispatch); } var selectableNode = (0, _utils2.findFirstChildNodeToSelect)(node); if (selectableNode) { var childNode = selectableNode.node, childPos = selectableNode.pos; var selectionPos = pos + childPos + 1; if (childNode.isText || childNode.isAtom && (0, _selection.isIgnored)(childNode) || childNode.isInline) { //selection is for text node, inline node or atom node which is ignored by gap-cursor. set selection before it. return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(selectionPos), _types.SelectionDirection.Before)(state, dispatch); } else if ((0, _utils.isEmptyParagraph)(childNode)) { return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(selectionPos + 1), _types.SelectionDirection.Before)(state, dispatch); } else if (!(0, _selection.isIgnored)(node)) { return setSelectionRelativeToNode(selectionRelativeToNode, new _selection.GapCursorSelection(state.doc.resolve(selectionPos), _selection.Side.LEFT))(state, dispatch); } else if ((0, _utils2.isSelectableContainerNode)(node)) { return setSelectionRelativeToNode(selectionRelativeToNode, _state.NodeSelection.create(state.doc, selectionPos))(state, dispatch); } } return false; }; }; var setSelectionInsideAtNodeEnd = exports.setSelectionInsideAtNodeEnd = function setSelectionInsideAtNodeEnd(selectionRelativeToNode, node, from, to) { return function (state, dispatch) { if ((0, _utils.isNodeEmpty)(node)) { return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(to), _types.SelectionDirection.Before)(state, dispatch); } var selectableNode = (0, _utils2.findLastChildNodeToSelect)(node); if (selectableNode) { var childNode = selectableNode.node, childPos = selectableNode.pos; var selectionPos = from + childPos + childNode.nodeSize; if (childNode.isText || childNode.isAtom && (0, _selection.isIgnored)(childNode) || childNode.isInline) { //selection is for text node, inline node or atom node which is ignored by gap-cursor. set selection after it. return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(selectionPos + 1), _types.SelectionDirection.After)(state, dispatch); } else if ((0, _utils.isEmptyParagraph)(childNode)) { return findAndSetTextSelection(selectionRelativeToNode, state.doc.resolve(selectionPos), _types.SelectionDirection.After)(state, dispatch); } else if (!(0, _selection.isIgnored)(node)) { return setSelectionRelativeToNode(selectionRelativeToNode, new _selection.GapCursorSelection(state.doc.resolve(selectionPos + 1), _selection.Side.RIGHT))(state, dispatch); } else if ((0, _utils2.isSelectableContainerNode)(node)) { return setSelectionRelativeToNode(selectionRelativeToNode, _state.NodeSelection.create(state.doc, selectionPos))(state, dispatch); } } return false; }; };