@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
114 lines (111 loc) • 3.1 kB
JavaScript
import { isEmptyParagraph } from './editor-core-utils';
export const getStepRange = transaction => {
let from = -1;
let to = -1;
transaction.mapping.maps.forEach((stepMap, index) => {
stepMap.forEach((oldStart, oldEnd) => {
const newStart = transaction.mapping.slice(index).map(oldStart, -1);
const newEnd = transaction.mapping.slice(index).map(oldEnd);
from = newStart < from || from === -1 ? newStart : from;
to = newEnd > to || to === -1 ? newEnd : to;
});
});
if (from !== -1) {
return {
from,
to
};
}
return null;
};
// Checks to see if the parent node is the document, ie not contained within another entity
export function hasDocAsParent($anchor) {
return $anchor.depth === 1;
}
/**
* Checks if a node looks like an empty document
*/
export function isEmptyDocument(node) {
const nodeChild = node.content.firstChild;
if (node.childCount !== 1 || !nodeChild) {
return false;
}
return isEmptyParagraph(nodeChild);
}
export function bracketTyped(state) {
const {
selection
} = state;
const {
$cursor,
$anchor
} = selection;
if (!$cursor) {
return false;
}
const node = $cursor.nodeBefore;
if (!node) {
return false;
}
if (node.type.name === 'text' && node.text === '{') {
const paragraphNode = $anchor.node();
return paragraphNode.marks.length === 0 && hasDocAsParent($anchor);
}
return false;
}
export function nodesBetweenChanged(tr, f, startPos) {
const stepRange = getStepRange(tr);
if (!stepRange) {
return;
}
tr.doc.nodesBetween(stepRange.from, stepRange.to, f, startPos);
}
/**
* Returns false if node contains only empty inline nodes and hardBreaks.
*/
export function hasVisibleContent(node) {
const isInlineNodeHasVisibleContent = inlineNode => {
return inlineNode.isText ? !!inlineNode.textContent.trim() : inlineNode.type.name !== 'hardBreak';
};
if (node.isInline) {
return isInlineNodeHasVisibleContent(node);
} else if (node.isBlock && (node.isLeaf || node.isAtom)) {
return true;
} else if (!node.childCount) {
return false;
}
for (let index = 0; index < node.childCount; index++) {
const child = node.child(index);
const invisibleNodeTypes = ['paragraph', 'text', 'hardBreak'];
if (!invisibleNodeTypes.includes(child.type.name) || hasVisibleContent(child)) {
return true;
}
}
return false;
}
export const isSelectionEndOfParagraph = state => state.selection.$to.parent.type === state.schema.nodes.paragraph && state.selection.$to.pos === state.doc.resolve(state.selection.$to.pos).end();
function getChangedNodesIn({
tr,
doc
}) {
const nodes = [];
const stepRange = getStepRange(tr);
if (!stepRange) {
return nodes;
}
const from = Math.min(doc.nodeSize - 2, stepRange.from);
const to = Math.min(doc.nodeSize - 2, stepRange.to);
doc.nodesBetween(from, to, (node, pos) => {
nodes.push({
node,
pos
});
});
return nodes;
}
export function getChangedNodes(tr) {
return getChangedNodesIn({
tr: tr,
doc: tr.doc
});
}