@atlaskit/editor-plugin-selection
Version:
Selection plugin for @atlaskit/editor-core
260 lines (258 loc) • 14.8 kB
JavaScript
"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;
};
};