UNPKG

@atlaskit/editor-common

Version:

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

150 lines (143 loc) 4.82 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 var stepHasSlice = function stepHasSlice(step) { return 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) { var adds = false; if (!stepHasSlice(step)) { return adds; } step.slice.content.descendants(function (node) { if (nodeTypes.has(node.type)) { adds = true; } return !adds; }); return adds; } export var extractSliceFromStep = function 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 var slice = step.slice; return slice; }; export var isTextSelection = function isTextSelection(selection) { return selection instanceof TextSelection; }; export var isElementInTableCell = function isElementInTableCell(element) { return closest(element, 'td') || closest(element, 'th'); }; export var isLastItemMediaGroup = function isLastItemMediaGroup(node) { var content = node.content; return !!content.lastChild && content.lastChild.type.name === 'mediaGroup'; }; export var setNodeSelection = function setNodeSelection(view, pos) { var state = view.state, dispatch = view.dispatch; if (!isFinite(pos)) { return; } var tr = state.tr.setSelection(NodeSelection.create(state.doc, pos)); dispatch(tr); }; export function setTextSelection(view, anchor, head) { var state = view.state, dispatch = view.dispatch; var tr = state.tr.setSelection(TextSelection.create(state.doc, anchor, head)); dispatch(tr); } export function setAllSelection(view) { var state = view.state, dispatch = view.dispatch; var tr = state.tr.setSelection(new AllSelection(view.state.doc)); dispatch(tr); } export function setCellSelection(view, anchor, head) { var state = view.state, dispatch = view.dispatch; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any 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 var isValidPosition = function isValidPosition(pos, state) { if (typeof pos !== 'number') { return false; } if (pos >= 0 && pos <= state.doc.resolve(0).end()) { return true; } return false; }; export var isInLayoutColumn = function isInLayoutColumn(state) { return hasParentNodeOfType(state.schema.nodes.layoutSection)(state.selection); }; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/max-params export function filterChildrenBetween(doc, from, to, predicate) { var results = []; doc.nodesBetween(from, to, function (node, pos, parent) { if (predicate(node, pos, parent)) { results.push({ node: node, pos: pos }); } }); return results; } export var removeBlockMarks = function removeBlockMarks(state, marks) { var selection = state.selection, schema = state.schema; var tr = state.tr; // Marks might not exist in Schema var marksToRemove = marks.filter(Boolean); if (marksToRemove.length === 0) { return undefined; } /** Saves an extra dispatch */ var blockMarksExists = false; var hasMark = function hasMark(mark) { return 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, function (node, pos) { if (node.type === schema.nodes.paragraph && node.marks.some(hasMark)) { blockMarksExists = true; var resolvedPos = state.doc.resolve(pos); var withoutBlockMarks = node.marks.filter(not(hasMark)); tr = tr.setNodeMarkup(resolvedPos.pos, undefined, node.attrs, withoutBlockMarks); } }); return blockMarksExists ? tr : undefined; }; var not = function not(fn) { return function (arg) { return !fn(arg); }; };