UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

143 lines (137 loc) 6.66 kB
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; };