UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

167 lines (162 loc) 7.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setCursorPositionAtMovedNode = exports.selectNode = exports.rootTaskListDepth = exports.rootListDepth = exports.newGetSelection = exports.isNodeWithCodeBlock = exports.isHandleCorrelatedToSelection = exports.getSelection = exports.getInlineNodePos = void 0; var _nodeSelection = require("@atlaskit/editor-common/node-selection"); var _selection2 = require("@atlaskit/editor-common/selection"); var _toolbarFlagCheck = require("@atlaskit/editor-common/toolbar-flag-check"); var _state = require("@atlaskit/editor-prosemirror/state"); var _utils = require("@atlaskit/editor-prosemirror/utils"); var _utils2 = require("@atlaskit/editor-tables/utils"); var _fg = require("@atlaskit/platform-feature-flags/fg"); var getInlineNodePos = exports.getInlineNodePos = function getInlineNodePos(doc, start, nodeSize) { var $startPos = doc.resolve(start); // To trigger the annotation floating toolbar for non-selectable node, we need to select inline nodes // Find the first inline node in the node var inlineNodePos = start; var foundInlineNode = false; var inlineNodeEndPos = 0; doc.nodesBetween($startPos.pos, $startPos.pos + nodeSize, function (n, pos) { if (n.isInline) { inlineNodeEndPos = pos + n.nodeSize; } if (n.isInline && !foundInlineNode) { inlineNodePos = pos; foundInlineNode = true; } return true; }); return { inlineNodePos: inlineNodePos, inlineNodeEndPos: inlineNodeEndPos }; }; var isNodeWithCodeBlock = exports.isNodeWithCodeBlock = function isNodeWithCodeBlock(tr, start, nodeSize) { var $startPos = tr.doc.resolve(start); var hasCodeBlock = false; tr.doc.nodesBetween($startPos.pos, $startPos.pos + nodeSize, function (n) { if (['codeBlock'].includes(n.type.name)) { hasCodeBlock = true; } }); return hasCodeBlock; }; /** * Gets the appropriate selection for the node at the given start position. * * @param doc The ProseMirror document. * @param selectionEmpty Indicates if the current selection is empty. * @param start The start position of the node. * @returns The appropriate selection for the node. */ var newGetSelection = exports.newGetSelection = function newGetSelection(doc, selectionEmpty, start) { if ((0, _fg.fg)('platform_editor_maui_jira_updates')) { return (0, _nodeSelection.getNodeSelectionForPos)(doc, start) || false; } var node = doc.nodeAt(start); var nodeName = node === null || node === void 0 ? void 0 : node.type.name; // if mediaGroup only has a single child, we want to select the child if (nodeName === 'mediaGroup' && (node === null || node === void 0 ? void 0 : node.childCount) === 1) { var $mediaStartPos = doc.resolve(start + 1); return new _state.NodeSelection($mediaStartPos); } return new _state.NodeSelection(doc.resolve(start)); }; var getSelection = exports.getSelection = function getSelection(tr, start) { return newGetSelection(tr.doc, tr.selection.empty, start); }; var selectNode = exports.selectNode = function selectNode(tr, start, nodeType, api) { if ((0, _fg.fg)('platform_editor_maui_jira_updates')) { return (0, _nodeSelection.selectNodeAtPos)(tr, start, nodeType); } if (nodeType === 'table') { tr = (0, _utils2.selectTableClosestToPos)(tr, tr.doc.resolve(start + 1)); return tr; } var selection = getSelection(tr, start); if (selection) { tr.setSelection(selection); } return tr; }; var setCursorPositionAtMovedNode = exports.setCursorPositionAtMovedNode = function setCursorPositionAtMovedNode(tr, start, api) { var node = tr.doc.nodeAt(start); var isNodeSelection = node && _state.NodeSelection.isSelectable(node); var nodeSize = node ? node.nodeSize : 1; var selection; // decisionList node is not selectable, but we want to select the whole node not just text // blockQuote is selectable, but we want to set cursor at the inline end Pos instead of the gap cursor as this causes jittering post drop if (isNodeSelection && node.type.name !== 'blockquote' || (node === null || node === void 0 ? void 0 : node.type.name) === 'decisionList') { selection = new _selection2.GapCursorSelection(tr.doc.resolve(start + node.nodeSize), _selection2.Side.RIGHT); tr.setSelection(selection); return tr; } // this is a fix for empty paragraph selection - can safely use start position as the paragraph is empty if ((node === null || node === void 0 ? void 0 : node.type.name) === 'paragraph' && (node === null || node === void 0 ? void 0 : node.childCount) === 0 && (0, _toolbarFlagCheck.areToolbarFlagsEnabled)(Boolean(api === null || api === void 0 ? void 0 : api.toolbar))) { var _selection = new _state.TextSelection(tr.doc.resolve(start)); tr.setSelection(_selection); return tr; } var _getInlineNodePos = getInlineNodePos(tr.doc, start, nodeSize), inlineNodeEndPos = _getInlineNodePos.inlineNodeEndPos; selection = new _state.TextSelection(tr.doc.resolve(inlineNodeEndPos)); tr.setSelection(selection); return tr; }; /** * Checks if handle position is with the selection or corresponds to a (partially) selected node * @param state * @param selection * @param handlePos * @returns */ var isHandleCorrelatedToSelection = exports.isHandleCorrelatedToSelection = function isHandleCorrelatedToSelection(state, selection, handlePos) { if (selection.empty) { return false; } var nodeStart; var $selectionFrom = selection.$from; nodeStart = $selectionFrom.before($selectionFrom.sharedDepth(selection.to) + 1); if (nodeStart === $selectionFrom.pos) { nodeStart = $selectionFrom.depth ? $selectionFrom.before() : $selectionFrom.pos; } var $resolvedNodePos = state.doc.resolve(nodeStart); if (['tableRow', 'tableCell', 'tableHeader'].includes($resolvedNodePos.node().type.name)) { var parentNodeFindRes = (0, _utils.findParentNodeOfType)(state.schema.nodes['table'])(selection); var tablePos = parentNodeFindRes === null || parentNodeFindRes === void 0 ? void 0 : parentNodeFindRes.pos; nodeStart = typeof tablePos === 'undefined' ? nodeStart : tablePos; } else if (['listItem'].includes($resolvedNodePos.node().type.name)) { nodeStart = $resolvedNodePos.before(rootListDepth($resolvedNodePos)); } else if (['taskList'].includes($resolvedNodePos.node().type.name)) { var listdepth = rootTaskListDepth($resolvedNodePos); nodeStart = $resolvedNodePos.before(listdepth); } else if (['blockquote'].includes($resolvedNodePos.node().type.name)) { nodeStart = $resolvedNodePos.before(); } return Boolean(handlePos < selection.$to.pos && handlePos >= nodeStart); }; var rootListDepth = exports.rootListDepth = function rootListDepth(itemPos) { var depth; for (var i = itemPos.depth; i > 1; i -= 2) { var node = itemPos.node(i); if (node.type.name === 'listItem') { depth = i - 1; } else { break; } } return depth; }; var rootTaskListDepth = exports.rootTaskListDepth = function rootTaskListDepth(taskListPos) { var depth; for (var i = taskListPos.depth; i > 0; i--) { var node = taskListPos.node(i); if (node.type.name === 'taskList' || node.type.name === 'taskItem') { depth = i; } else { break; } } return depth; };