@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
136 lines (131 loc) • 5.06 kB
JavaScript
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);
}