@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
133 lines (125 loc) • 5.16 kB
JavaScript
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { findNodeDecs } from '../pm-plugins/decorations-anchor';
import { getDecorations, key } from '../pm-plugins/main';
import { getNestedNodePosition, getNestedNodeStartingPosition } from '../pm-plugins/utils/getNestedNodePosition';
import { NODE_ANCHOR_ATTR_NAME, NODE_NODE_TYPE_ATTR_NAME } from '../ui/utils/dom-attr-name';
var findParentPosForHandle = function findParentPosForHandle(state) {
var _activeNode$handleOpt;
var $from = state.selection.$from;
var _ref = key.getState(state) || {},
activeNode = _ref.activeNode;
// if a node handle is already focused, return the parent pos of that node (with focused handle)
if (activeNode && (_activeNode$handleOpt = activeNode.handleOptions) !== null && _activeNode$handleOpt !== void 0 && _activeNode$handleOpt.isFocused) {
var $activeNodePos = state.doc.resolve(activeNode.pos);
// if the handle is at the top level already, do nothing
if ($activeNodePos.depth === 0) {
return undefined;
}
return $activeNodePos.before();
}
// if we are in second level of nested node, we should focus the node at level 1
if ($from.depth <= 1) {
return $from.before(1);
}
// if we are inside a table, we should focus the table's handle
var parentTableNode = findParentNodeOfType([state.schema.nodes.table])(state.selection);
if (parentTableNode) {
return parentTableNode.pos;
}
// else find closest parent node
return expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ?
// With native anchor enabled, all nodes have anchor name attribute despite no drag handle support, e.g. listItem, caption,
// as opposed to old approach, node decoration is only added to the node that have drag handle,
// hence, we need to return the exact position of the node that can have drag handle
getNestedNodeStartingPosition({
selection: state.selection,
schema: state.schema,
resolve: state.doc.resolve.bind(state.doc)
}) : getNestedNodePosition({
selection: state.selection,
schema: state.schema,
resolve: state.doc.resolve.bind(state.doc)
});
};
var findNextAnchorDecoration = function findNextAnchorDecoration(state) {
var decorations = getDecorations(state);
if (!decorations) {
return undefined;
}
var nextHandleNodePos = findParentPosForHandle(state);
if (nextHandleNodePos === undefined) {
return undefined;
}
var nextHandleNode = state.doc.nodeAt(nextHandleNodePos);
var nodeDecorations = nextHandleNode && findNodeDecs(state, decorations, nextHandleNodePos, nextHandleNodePos + nextHandleNode.nodeSize);
if (!nodeDecorations || nodeDecorations.length === 0) {
return undefined;
}
// ensure the decoration covers the position of the look up node
nodeDecorations = nodeDecorations.filter(function (decoration) {
return decoration.from <= nextHandleNodePos;
});
if (nodeDecorations.length === 0) {
return undefined;
}
// sort the decorations by the position of the node
// so we can find the closest decoration to the node
nodeDecorations.sort(function (a, b) {
if (a.from === b.from) {
return a.to - b.to;
}
return b.from - a.from;
});
// return the closest decoration to the node
return nodeDecorations[0];
};
var findNextAnchorNode = function findNextAnchorNode(view) {
var nextHandleNodePos = findParentPosForHandle(view.state);
if (nextHandleNodePos === undefined) {
return undefined;
}
var dom = view.nodeDOM(nextHandleNodePos);
if (!(dom instanceof HTMLElement)) {
return undefined;
}
var nodeDOM = dom.closest("[".concat(NODE_ANCHOR_ATTR_NAME, "]"));
if (!nodeDOM) {
return undefined;
}
var nodeType = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_NODE_TYPE_ATTR_NAME);
var anchorName = nodeDOM === null || nodeDOM === void 0 ? void 0 : nodeDOM.getAttribute(NODE_ANCHOR_ATTR_NAME);
if (nodeType && anchorName) {
return {
pos: nextHandleNodePos,
nodeType: nodeType,
anchorName: anchorName
};
}
};
export var showDragHandleAtSelection = function showDragHandleAtSelection(api) {
return function (state, _, view) {
if (view && expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
var anchorNode = findNextAnchorNode(view);
if (api && anchorNode) {
var pos = anchorNode.pos,
anchorName = anchorNode.anchorName,
nodeType = anchorNode.nodeType;
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(pos, anchorName, nodeType, {
isFocused: true
}));
return true;
}
return false;
} else {
var decoration = findNextAnchorDecoration(state);
if (api && decoration) {
api.core.actions.execute(api.blockControls.commands.showDragHandleAt(decoration.from, decoration.spec.anchorName, decoration.spec.nodeTypeWithLevel, {
isFocused: true
}));
return true;
}
return false;
}
};
};