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