2020-03-26 03:42:35 +08:00

143 lines
3.8 KiB
TypeScript

import { Component, MouseEvent as ReactMouseEvent } from 'react';
import { observer } from '../../../globals';
import { Tree } from '../tree';
import TreeNodeView from './tree-node';
import { isRootNode } from '../../../designer/src/designer/document/node/root-node';
import Node from '../../../designer/src/designer/document/node/node';
import { DragObjectType, isShaken } from '../../../designer/src/designer/helper/dragon';
function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {
let target: Element | null = e.target as Element;
if (!target || !stop.contains(target)) {
return null;
}
target = target.closest('[data-id]');
if (!target || !stop.contains(target)) {
return null;
}
return (target as HTMLDivElement).dataset.id || null;
}
@observer
export default class TreeView extends Component<{ tree: Tree }> {
private shell: HTMLDivElement | null = null;
private hover(e: ReactMouseEvent) {
const { tree } = this.props;
const doc = tree.document;
const hovering = doc.designer.hovering;
if (!hovering.enable) {
return;
}
const node = this.getTreeNodeFromEvent(e)?.node;
hovering.hover(node || null);
}
private onClick = (e: ReactMouseEvent) => {
if (this.ignoreUpSelected) {
return;
}
if (this.boostEvent && isShaken(this.boostEvent, e.nativeEvent)) {
return;
}
const treeNode = this.getTreeNodeFromEvent(e);
if (!treeNode) {
return;
}
const { node } = treeNode;
const designer = treeNode.designer;
const doc = node.document;
const selection = doc.selection;
const id = node.id;
const isMulti = e.metaKey || e.ctrlKey;
designer.activeTracker.track(node);
if (isMulti && !isRootNode(node) && selection.has(id)) {
selection.remove(id);
} else {
selection.select(id);
}
};
private onMouseOver = (e: ReactMouseEvent) => {
this.hover(e);
};
private getTreeNodeFromEvent(e: ReactMouseEvent) {
if (!this.shell) {
return;
}
const id = getTreeNodeIdByEvent(e, this.shell);
if (!id) {
return;
}
const { tree } = this.props;
return tree.getTreeNodeById(id);
}
private ignoreUpSelected = false;
private boostEvent?: MouseEvent;
private onMouseDown = (e: ReactMouseEvent) => {
const treeNode = this.getTreeNodeFromEvent(e);
if (!treeNode) {
return;
}
const { node } = treeNode;
const designer = treeNode.designer;
const doc = node.document;
const selection = doc.selection;
const isMulti = e.metaKey || e.ctrlKey;
const isLeftButton = e.button === 0;
if (isLeftButton && !isRootNode(node)) {
let nodes: Node[] = [node];
this.ignoreUpSelected = false;
if (isMulti) {
// multi select mode, directily add
if (!selection.has(node.id)) {
designer.activeTracker.track(node);
selection.add(node.id);
this.ignoreUpSelected = true;
}
selection.remove(doc.rootNode.id);
// 获得顶层 nodes
nodes = selection.getTopNodes();
}
this.boostEvent = e.nativeEvent;
designer.dragon.boost(
{
type: DragObjectType.Node,
nodes,
},
this.boostEvent,
);
}
};
private onMouseLeave = () => {
const { tree } = this.props;
const doc = tree.document;
doc.designer.hovering.leave(doc);
};
render() {
const { tree } = this.props;
const root = tree.root;
return (
<div
className="lc-outline-tree"
ref={shell => (this.shell = shell)}
onMouseDown={this.onMouseDown}
onMouseOver={this.onMouseOver}
onClick={this.onClick}
onMouseLeave={this.onMouseLeave}
>
<TreeNodeView key={root.id} treeNode={root} />
</div>
);
}
}