@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
143 lines (137 loc) • 6.66 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import { Decoration } from '@atlaskit/editor-prosemirror/view';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { getNodeAnchor, getNodeTypeWithLevel, NESTED_DEPTH, TYPE_NODE_DEC } from './decorations-common';
var IGNORE_NODES = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption', 'layoutColumn'];
export var IGNORE_NODES_NEXT = ['tableCell', 'tableHeader', 'tableRow', 'listItem', 'caption'];
var IGNORE_NODE_DESCENDANTS = ['listItem', 'taskList', 'decisionList', 'mediaSingle'];
export var IGNORE_NODE_DESCENDANTS_ADVANCED_LAYOUT = ['listItem', 'taskList', 'decisionList'];
export var shouldDescendIntoNode = function shouldDescendIntoNode(node) {
// Optimisation to avoid drawing node decorations for empty table cells
if (['tableCell', 'tableHeader'].includes(node.type.name)) {
var _node$firstChild;
if (node.childCount === 1 && ((_node$firstChild = node.firstChild) === null || _node$firstChild === void 0 ? void 0 : _node$firstChild.type.name) === 'paragraph' && node.firstChild.childCount === 0) {
return false;
}
}
if (editorExperiment('advanced_layouts', true)) {
return !IGNORE_NODE_DESCENDANTS_ADVANCED_LAYOUT.includes(node.type.name);
}
return !IGNORE_NODE_DESCENDANTS.includes(node.type.name);
};
var shouldIgnoreNode = function shouldIgnoreNode(node, ignore_nodes, depth, parent) {
var _nodeTypes$table, _node$attrs, _node$attrs2;
var isEmbedCard = node.type.name === 'embedCard';
var isMediaSingle = node.type.name === 'mediaSingle';
var nodeTypes = node.type.schema.nodes;
var isTable = node.type.name === (nodeTypes === null || nodeTypes === void 0 || (_nodeTypes$table = nodeTypes.table) === null || _nodeTypes$table === void 0 ? void 0 : _nodeTypes$table.name);
var parentIsTable = parent && [nodeTypes.tableHeader, nodeTypes.tableCell].includes(parent.type);
var isNestedTable = isTable && parentIsTable;
if (isNestedTable) {
return true;
}
var isFirstTableRow = (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'table' && depth === 1 && node === parent.firstChild && 'tableRow' === node.type.name && editorExperiment('advanced_layouts', true);
if (isFirstTableRow) {
return false;
}
var isLegacyContentMacroExtension = node.type.name === 'extension' && ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionType) === 'com.atlassian.confluence.migration' && ((_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.extensionKey) === 'legacy-content';
if (isLegacyContentMacroExtension) {
return true;
}
return (isEmbedCard || isMediaSingle) && ['wrap-right', 'wrap-left'].includes(node.attrs.layout) && !editorExperiment('platform_editor_fix_selection_wrapped_media_embed', true, {
exposure: true
}) ? true : ignore_nodes.includes(node.type.name);
};
var getPositionBeforeNodeAtPos = function getPositionBeforeNodeAtPos(state, pos) {
if (pos <= 0 || pos >= state.doc.nodeSize - 2) {
return pos;
}
var $pos = state.doc.resolve(pos);
if ($pos.depth > 0) {
return $pos.before();
}
return pos;
};
/**
* Find node decorations corresponding to nodes with starting position between from and to (non-inclusive)
* @param from Position to start search from (inclusive)
* @param to Position to end search at (non-inclusive)
* @returns
*/
export var findNodeDecs = function findNodeDecs(state, decorations, from, to) {
var newFrom = from;
if (editorExperiment('platform_editor_block_control_optimise_render', true)) {
// return empty array if range reversed
if (typeof to === 'number' && typeof newFrom === 'number' && newFrom > to) {
return [];
}
var decs = decorations.find(newFrom, to, function (spec) {
return spec.type === TYPE_NODE_DEC;
});
// Prosemirror finds any decorations that overlap with the provided position range, but we don't want to include decorations of nodes that start outside of the range
if (typeof to === 'number' && typeof newFrom === 'number') {
decs = decs.filter(function (dec) {
return dec.from >= (newFrom || 0) && dec.from < to;
});
}
return decs;
} else {
var newTo = to;
// make it non-inclusive
if (newFrom !== undefined) {
newFrom++;
}
// make it non-inclusive
if (newTo !== undefined) {
newTo--;
}
// return empty array if range reversed
if (newFrom !== undefined && newTo !== undefined && newFrom > newTo) {
return [];
}
return decorations.find(newFrom, newTo, function (spec) {
return spec.type === TYPE_NODE_DEC;
});
}
};
export var nodeDecorations = function nodeDecorations(newState, from, to) {
var decs = [];
if (expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
return [];
}
var docFrom = from === undefined || from < 0 ? 0 : from;
var docTo = to === undefined || to > newState.doc.nodeSize - 2 ? newState.doc.nodeSize - 2 : to;
var ignore_nodes = editorExperiment('advanced_layouts', true) ? IGNORE_NODES_NEXT : IGNORE_NODES;
newState.doc.nodesBetween(docFrom, docTo, function (node, pos, parent, _) {
var depth = 0;
var shouldDescend = shouldDescendIntoNode(node);
var anchorName = getNodeAnchor(node);
var nodeTypeWithLevel = getNodeTypeWithLevel(node);
if (editorExperiment('platform_editor_block_control_optimise_render', true)) {
// We don't want to create decorations for nodes that start outside of the provided position range
if (pos < getPositionBeforeNodeAtPos(newState, docFrom)) {
return shouldDescend;
}
}
// Doesn't descend into a node
if (node.isInline) {
return false;
}
depth = newState.doc.resolve(pos).depth;
if (shouldIgnoreNode(node, ignore_nodes, depth, parent)) {
return shouldDescend; //skip over, don't consider it a valid depth
}
var anchorStyles = "anchor-name: ".concat(anchorName, ";");
decs.push(Decoration.node(pos, pos + node.nodeSize, _defineProperty(_defineProperty(_defineProperty({
style: anchorStyles
}, 'data-drag-handler-anchor-name', anchorName), 'data-drag-handler-node-type', nodeTypeWithLevel), 'data-drag-handler-anchor-depth', "".concat(depth)), {
type: TYPE_NODE_DEC,
anchorName: anchorName,
nodeType: node.type.name,
nodeTypeWithLevel: nodeTypeWithLevel
}));
return shouldDescend && depth < NESTED_DEPTH;
});
return decs;
};