UNPKG

@atlaskit/editor-common

Version:

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

149 lines (143 loc) 4.28 kB
import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state'; import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform'; import { hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils'; import { CellSelection } from '@atlaskit/editor-tables/cell-selection'; import { closest } from './dom'; /** * Checks if node is an empty paragraph. */ export function isEmptyParagraph(node) { return !!node && node.type.name === 'paragraph' && !node.childCount; } export const stepHasSlice = step => step && step.hasOwnProperty('slice'); /** * Checks whether a given step is adding nodes of given nodeTypes * * @param step Step to check * @param nodeTypes NodeTypes being added */ export function stepAddsOneOf(step, nodeTypes) { let adds = false; if (!stepHasSlice(step)) { return adds; } step.slice.content.descendants(node => { if (nodeTypes.has(node.type)) { adds = true; } return !adds; }); return adds; } export const extractSliceFromStep = step => { if (!(step instanceof ReplaceStep) && !(step instanceof ReplaceAroundStep)) { return null; } // @ts-ignore This is by design. Slice is a private property, but accesible, from ReplaceStep. // However, we need to read it to found if the step was adding a newline const slice = step.slice; return slice; }; export const isTextSelection = selection => selection instanceof TextSelection; export const isElementInTableCell = element => { return closest(element, 'td') || closest(element, 'th'); }; export const isLastItemMediaGroup = node => { const { content } = node; return !!content.lastChild && content.lastChild.type.name === 'mediaGroup'; }; export const setNodeSelection = (view, pos) => { const { state, dispatch } = view; if (!isFinite(pos)) { return; } const tr = state.tr.setSelection(NodeSelection.create(state.doc, pos)); dispatch(tr); }; export function setTextSelection(view, anchor, head) { const { state, dispatch } = view; const tr = state.tr.setSelection(TextSelection.create(state.doc, anchor, head)); dispatch(tr); } export function setAllSelection(view) { const { state, dispatch } = view; const tr = state.tr.setSelection(new AllSelection(view.state.doc)); dispatch(tr); } export function setCellSelection(view, anchor, head) { const { state, dispatch } = view; dispatch(state.tr.setSelection(CellSelection.create(state.doc, anchor, head))); } export function nonNullable(value) { return value !== null && value !== undefined; } // checks if the given position is within the ProseMirror document export const isValidPosition = (pos, state) => { if (typeof pos !== 'number') { return false; } if (pos >= 0 && pos <= state.doc.resolve(0).end()) { return true; } return false; }; export const isInLayoutColumn = state => { return hasParentNodeOfType(state.schema.nodes.layoutSection)(state.selection); }; export function filterChildrenBetween(doc, from, to, predicate) { const results = []; doc.nodesBetween(from, to, (node, pos, parent) => { if (predicate(node, pos, parent)) { results.push({ node, pos }); } }); return results; } export const removeBlockMarks = (state, marks) => { const { selection, schema } = state; let { tr } = state; // Marks might not exist in Schema const marksToRemove = marks.filter(Boolean); if (marksToRemove.length === 0) { return undefined; } /** Saves an extra dispatch */ let blockMarksExists = false; const hasMark = mark => marksToRemove.indexOf(mark.type) > -1; /** * When you need to toggle the selection * when another type which does not allow alignment is applied */ state.doc.nodesBetween(selection.from, selection.to, (node, pos) => { if (node.type === schema.nodes.paragraph && node.marks.some(hasMark)) { blockMarksExists = true; const resolvedPos = state.doc.resolve(pos); const withoutBlockMarks = node.marks.filter(not(hasMark)); tr = tr.setNodeMarkup(resolvedPos.pos, undefined, node.attrs, withoutBlockMarks); } }); return blockMarksExists ? tr : undefined; }; const not = fn => arg => !fn(arg);