UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

136 lines (131 loc) 5.06 kB
import { JSONTransformer } from '@atlaskit/editor-json-transformer'; import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils'; /** * Finds all top level nodes affected by the transaction * Uses from/to positions in transaction's steps to work out which nodes will * be changed by the transaction */ export var findChangedNodesFromTransaction = function findChangedNodesFromTransaction(tr) { var nodes = []; var steps = tr.steps || []; steps.forEach(function (step) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/max-params step.getMap().forEach(function (oldStart, oldEnd, newStart, newEnd) { tr.doc.nodesBetween(newStart, Math.min(newEnd, tr.doc.content.size), function (node) { if (!nodes.find(function (n) { return n === node; })) { nodes.push(node); } return false; }); }); }); return nodes; }; export var validNode = function validNode(node) { try { node.check(); // this will throw an error if the node is invalid } catch (error) { return false; } return true; }; /** Validates prosemirror nodes, and returns true only if all nodes are valid */ export var validateNodes = function validateNodes(nodes) { return nodes.every(validNode); }; export var isType = function isType(node, type) { return type && node && node.type === type; }; export var isParagraph = function isParagraph(node, schema) { return isType(node, schema.nodes.paragraph); }; export var isText = function isText(node, schema) { return isType(node, schema.nodes.text); }; export var isLinkMark = function isLinkMark(node, schema) { return isType(node, schema.marks.link); }; export var SelectedState = /*#__PURE__*/function (SelectedState) { SelectedState[SelectedState["selectedInRange"] = 0] = "selectedInRange"; SelectedState[SelectedState["selectedInside"] = 1] = "selectedInside"; return SelectedState; }({}); /** * Returns if the current selection from achor-head is selecting the node. * If the node is not selected then null is returned. * If the node is selected then an enum is returned that describes weather the node * is fully selected by a range or if the "inside" of the node has been selected or clicked. */ export var isNodeSelectedOrInRange = function isNodeSelectedOrInRange(anchorPosition, headPosition, nodePosition, nodeSize // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/max-params ) { if (typeof nodePosition !== 'number') { return null; } var rangeStart = Math.min(anchorPosition, headPosition); var rangeEnd = Math.max(anchorPosition, headPosition); var nodeStart = nodePosition; var nodeEnd = nodePosition + nodeSize; if (anchorPosition === headPosition) { return null; } if (rangeStart <= nodeStart && nodeEnd < rangeEnd || rangeStart < nodeStart && nodeEnd <= rangeEnd) { return SelectedState.selectedInRange; } if (nodeStart <= anchorPosition && headPosition <= nodeEnd) { return SelectedState.selectedInside; } return null; }; /** * Checks if a particular node fragment is supported in the parent * @param state EditorState * @param fragment The fragment to be checked for */ export var isSupportedInParent = function isSupportedInParent(state, fragment, currentAppearance) { var depth = currentAppearance === 'embed' || currentAppearance === 'block' ? undefined : -1; var parent = state.selection.$from.node(depth); return parent && parent.type.validContent(fragment); }; /** * Checks if the passed in node is a media node * Includes media, mediaInline, mediaGroup, mediaSingle * @param node The PM node to be checked */ export var isMediaNode = function isMediaNode(node) { return ['media', 'mediaInline', 'mediaGroup', 'mediaSingle'].includes(node.type.name); }; /** * Checks if the node before selection is a media node * If there is no node before, checks the node before the parent node * Includes media, mediaInline, mediaGroup, mediaSingle * @param $pos The position of the selection * @param state The editor state */ export var isNodeBeforeMediaNode = function isNodeBeforeMediaNode($pos, state) { var nodeBefore = $pos.nodeBefore; if (!nodeBefore) { var depthOfParent = $pos.depth - 1 || 1; var parentNode = findParentNodeOfType([state.schema.nodes["".concat($pos.node(depthOfParent).type.name)]])(state.selection); var resolvedPosOfParentNode = parentNode ? state.tr.doc.resolve(parentNode.pos) : undefined; var nodeBeforeParent = resolvedPosOfParentNode && resolvedPosOfParentNode.pos < state.doc.nodeSize ? resolvedPosOfParentNode.nodeBefore : undefined; if (nodeBeforeParent) { nodeBefore = nodeBeforeParent; } } if (nodeBefore) { return ['media', 'mediaInline', 'mediaGroup', 'mediaSingle'].includes(nodeBefore.type.name); } return false; }; var transformer = new JSONTransformer(); export function toJSON(node) { return transformer.encode(node); } export function nodeToJSON(node) { return transformer.encodeNode(node); }