mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-14 13:03:07 +00:00
fix outlines&events
This commit is contained in:
parent
69e9c981a2
commit
573f91507c
@ -8,17 +8,17 @@ import OffsetObserver from '../../../../designer/helper/offset-observer';
|
||||
import Node from '../../../../designer/document/node/node';
|
||||
|
||||
@observer
|
||||
export class OutlineSelectingInstance extends Component<{ observed: OffsetObserver; highlight?: boolean }> {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
export class OutlineSelectingInstance extends Component<{
|
||||
observed: OffsetObserver;
|
||||
highlight?: boolean;
|
||||
dragging?: boolean;
|
||||
}> {
|
||||
componentWillUnmount() {
|
||||
this.props.observed.purge();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { observed, highlight } = this.props;
|
||||
const { observed, highlight, dragging } = this.props;
|
||||
if (!observed.hasOffset) {
|
||||
return null;
|
||||
}
|
||||
@ -33,6 +33,7 @@ export class OutlineSelectingInstance extends Component<{ observed: OffsetObserv
|
||||
|
||||
const className = classNames('lc-outlines lc-outlines-selecting', {
|
||||
highlight,
|
||||
dragging,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -51,6 +52,10 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
get dragging(): boolean {
|
||||
return this.host.designer.dragon.dragging;
|
||||
}
|
||||
|
||||
@computed get instances() {
|
||||
return this.host.getComponentInstances(this.props.node);
|
||||
}
|
||||
@ -77,7 +82,7 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
|
||||
if (!observed) {
|
||||
return null;
|
||||
}
|
||||
return <OutlineSelectingInstance key={observed.id} observed={observed} />;
|
||||
return <OutlineSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
@ -92,12 +97,17 @@ export class OutlineSelecting extends Component {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
get dragging(): boolean {
|
||||
return this.host.designer.dragon.dragging;
|
||||
}
|
||||
|
||||
@computed get selecting() {
|
||||
const doc = this.host.document;
|
||||
if (doc.suspensed) {
|
||||
return null;
|
||||
}
|
||||
return doc.selection.getNodes();
|
||||
const selection = doc.selection;
|
||||
return this.dragging ? selection.getTopNodes() : selection.getNodes();
|
||||
}
|
||||
|
||||
shouldComponentUpdate() {
|
||||
@ -106,6 +116,7 @@ export class OutlineSelecting extends Component {
|
||||
|
||||
render() {
|
||||
const selecting = this.selecting;
|
||||
console.info(selecting);
|
||||
if (!selecting || selecting.length < 1) {
|
||||
// DIRTY FIX, recore has a bug!
|
||||
return <Fragment />;
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
&&-hovering {
|
||||
z-index: 1;
|
||||
border-style: dashed;
|
||||
background: rgba(95, 240, 114, 0.04);
|
||||
background: rgba(0,121,242,.04);
|
||||
|
||||
&.x-loop {
|
||||
border-color: rgba(138, 93, 226, 0.8);
|
||||
@ -44,6 +44,7 @@
|
||||
|
||||
&&-selecting {
|
||||
z-index: 2;
|
||||
border-width: 2px;
|
||||
|
||||
&.x-loop {
|
||||
border-color: rgba(147, 112, 219, 1.0);
|
||||
|
||||
@ -145,9 +145,6 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
||||
readonly scroller = this.designer.createScroller(this.viewport);
|
||||
|
||||
mountViewport(viewport: Element | null) {
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
this.viewport.mount(viewport);
|
||||
}
|
||||
|
||||
@ -174,10 +171,12 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
||||
|
||||
readonly libraryMap: { [key: string]: string } = {};
|
||||
|
||||
private _iframe?: HTMLIFrameElement;
|
||||
async mountContentFrame(iframe: HTMLIFrameElement | null) {
|
||||
if (!iframe) {
|
||||
if (!iframe || this._iframe === iframe) {
|
||||
return;
|
||||
}
|
||||
this._iframe = iframe;
|
||||
|
||||
this._contentWindow = iframe.contentWindow!;
|
||||
|
||||
@ -234,63 +233,89 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
||||
|
||||
// TODO: think of lock when edit a node
|
||||
// 事件路由
|
||||
doc.addEventListener('mousedown', (downEvent: MouseEvent) => {
|
||||
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
|
||||
const node = nodeInst?.node || this.document.rootNode;
|
||||
const isMulti = downEvent.metaKey || downEvent.ctrlKey;
|
||||
const isLeftButton = downEvent.which === 1 || downEvent.button === 0;
|
||||
const checkSelect = (e: MouseEvent) => {
|
||||
doc.removeEventListener('mouseup', checkSelect, true);
|
||||
if (!isShaken(downEvent, e)) {
|
||||
const id = node.id;
|
||||
designer.activeTracker.track(node);
|
||||
if (isMulti && !isRootNode(node) && selection.has(id)) {
|
||||
selection.remove(id);
|
||||
} else {
|
||||
selection.select(id);
|
||||
}
|
||||
}
|
||||
};
|
||||
doc.addEventListener(
|
||||
'mousedown',
|
||||
(downEvent: MouseEvent) => {
|
||||
// stop response document focus event
|
||||
downEvent.stopPropagation();
|
||||
downEvent.preventDefault();
|
||||
|
||||
if (isLeftButton && !isRootNode(node)) {
|
||||
let nodes: Node[] = [node];
|
||||
let ignoreUpSelected = false;
|
||||
// 排除根节点拖拽
|
||||
selection.remove(this.document.rootNode.id);
|
||||
if (isMulti) {
|
||||
// multi select mode, directily add
|
||||
if (!selection.has(node.id)) {
|
||||
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
|
||||
const node = nodeInst?.node || this.document.rootNode;
|
||||
const isMulti = downEvent.metaKey || downEvent.ctrlKey;
|
||||
const isLeftButton = downEvent.which === 1 || downEvent.button === 0;
|
||||
const checkSelect = (e: MouseEvent) => {
|
||||
doc.removeEventListener('mouseup', checkSelect, true);
|
||||
if (!isShaken(downEvent, e)) {
|
||||
const id = node.id;
|
||||
designer.activeTracker.track(node);
|
||||
selection.add(node.id);
|
||||
ignoreUpSelected = true;
|
||||
if (isMulti && !isRootNode(node) && selection.has(id)) {
|
||||
selection.remove(id);
|
||||
} else {
|
||||
selection.select(id);
|
||||
}
|
||||
}
|
||||
// 获得顶层 nodes
|
||||
nodes = selection.getTopNodes();
|
||||
} else if (selection.containsNode(node)) {
|
||||
nodes = selection.getTopNodes();
|
||||
} else {
|
||||
// will clear current selection & select dragment in dragstart
|
||||
}
|
||||
designer.dragon.boost(
|
||||
{
|
||||
type: DragObjectType.Node,
|
||||
nodes,
|
||||
},
|
||||
downEvent,
|
||||
);
|
||||
if (ignoreUpSelected) {
|
||||
// multi select mode has add selected, should return
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
doc.addEventListener('mouseup', checkSelect, true);
|
||||
});
|
||||
if (isLeftButton && !isRootNode(node)) {
|
||||
let nodes: Node[] = [node];
|
||||
let ignoreUpSelected = false;
|
||||
// 排除根节点拖拽
|
||||
selection.remove(this.document.rootNode.id);
|
||||
if (isMulti) {
|
||||
// multi select mode, directily add
|
||||
if (!selection.has(node.id)) {
|
||||
designer.activeTracker.track(node);
|
||||
selection.add(node.id);
|
||||
ignoreUpSelected = true;
|
||||
}
|
||||
// 获得顶层 nodes
|
||||
nodes = selection.getTopNodes();
|
||||
} else if (selection.containsNode(node)) {
|
||||
nodes = selection.getTopNodes();
|
||||
} else {
|
||||
// will clear current selection & select dragment in dragstart
|
||||
}
|
||||
designer.dragon.boost(
|
||||
{
|
||||
type: DragObjectType.Node,
|
||||
nodes,
|
||||
},
|
||||
downEvent,
|
||||
);
|
||||
if (ignoreUpSelected) {
|
||||
// multi select mode has add selected, should return
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
doc.addEventListener('mouseup', checkSelect, true);
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
doc.addEventListener(
|
||||
'click',
|
||||
e => {
|
||||
// stop response document click event
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// todo: catch link redirect
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
// cause edit
|
||||
doc.addEventListener('dblclick', (e: MouseEvent) => {
|
||||
// TODO:
|
||||
});
|
||||
doc.addEventListener(
|
||||
'dblclick',
|
||||
(e: MouseEvent) => {
|
||||
// stop response document dblclick event
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
// todo: quick editing
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
private disableHovering?: () => void;
|
||||
@ -443,18 +468,28 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
||||
let last: { x: number; y: number; r: number; b: number } | undefined;
|
||||
let computed = false;
|
||||
const elems = elements.slice();
|
||||
const commonParent: Element | null = null;
|
||||
while (true) {
|
||||
if (!rects || rects.length < 1) {
|
||||
const elem = elems.pop();
|
||||
if (!elem) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (!commonParent) {
|
||||
commonParent = elem.parentElement;
|
||||
} else if (elem.parentElement !== commonParent) {
|
||||
continue;
|
||||
}*/
|
||||
rects = renderer.getClientRects(elem);
|
||||
}
|
||||
const rect = rects.pop();
|
||||
if (!rect) {
|
||||
break;
|
||||
}
|
||||
if (rect.width === 0 && rect.height === 0) {
|
||||
continue;
|
||||
}
|
||||
if (!last) {
|
||||
last = {
|
||||
x: rect.left,
|
||||
@ -677,8 +712,10 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
||||
}
|
||||
|
||||
const target = dropTarget;
|
||||
const targetInstance = e.targetInstance as ReactInstance;
|
||||
|
||||
// FIXME: e.target is #document, etc., does not has e.targetInstance
|
||||
|
||||
const targetInstance = e.targetInstance as ReactInstance;
|
||||
const parentInstance = this.getClosestNodeInstance(targetInstance, target.id);
|
||||
const edge = this.computeComponentInstanceRect(parentInstance?.instance as any);
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export default class Viewport implements IViewport {
|
||||
|
||||
private viewportElement?: Element;
|
||||
mount(viewportElement: Element | null) {
|
||||
if (!viewportElement) {
|
||||
if (!viewportElement || this.viewportElement === viewportElement) {
|
||||
return;
|
||||
}
|
||||
this.viewportElement = viewportElement;
|
||||
@ -54,7 +54,7 @@ export default class Viewport implements IViewport {
|
||||
/**
|
||||
* 缩放比例
|
||||
*/
|
||||
get scale(): number {
|
||||
@computed get scale(): number {
|
||||
if (!this.rect || this.contentWidth === AutoFit) {
|
||||
return 1;
|
||||
}
|
||||
@ -63,14 +63,14 @@ export default class Viewport implements IViewport {
|
||||
|
||||
@obx.ref private _contentWidth: number | AutoFit = AutoFit;
|
||||
|
||||
get contentHeight(): number | AutoFit {
|
||||
@computed get contentHeight(): number | AutoFit {
|
||||
if (!this.rect || this.scale === 1) {
|
||||
return AutoFit;
|
||||
}
|
||||
return this.height / this.scale;
|
||||
}
|
||||
|
||||
get contentWidth(): number | AutoFit {
|
||||
@computed get contentWidth(): number | AutoFit {
|
||||
if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) {
|
||||
return AutoFit;
|
||||
}
|
||||
@ -98,7 +98,7 @@ export default class Viewport implements IViewport {
|
||||
return this._scrollTarget;
|
||||
}
|
||||
|
||||
@obx private _scrolling: boolean = false;
|
||||
@obx private _scrolling = false;
|
||||
get scrolling(): boolean {
|
||||
return this._scrolling;
|
||||
}
|
||||
@ -120,6 +120,7 @@ export default class Viewport implements IViewport {
|
||||
this._scrolling = false;
|
||||
}, 80);
|
||||
});
|
||||
target.addEventListener('resize', () => this.touch());
|
||||
this._scrollTarget = scrollTarget;
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
--font-size-btn-medium: @fontSize-4;
|
||||
--font-size-btn-small: @fontSize-5;
|
||||
|
||||
--color-brand-light: rgb(102, 188, 92);
|
||||
--color-brand: #006cff;
|
||||
--color-brand-light: #197aff;
|
||||
--color-brand-dark: #0060e5;
|
||||
--color-icon: rgba(255, 255, 255, 0.8);
|
||||
--color-visited: rgba(179, 182, 201, 0.4);
|
||||
--color-actived: #498ee6;
|
||||
|
||||
@ -61,9 +61,13 @@ export default class Designer {
|
||||
this.dragon.onDragstart(e => {
|
||||
this.hovering.enable = false;
|
||||
const { dragObject } = e;
|
||||
if (isDragNodeObject(dragObject) && dragObject.nodes.length === 1) {
|
||||
// ensure current selecting
|
||||
dragObject.nodes[0].select();
|
||||
if (isDragNodeObject(dragObject)) {
|
||||
if (dragObject.nodes.length === 1) {
|
||||
// ensure current selecting
|
||||
dragObject.nodes[0].select();
|
||||
}
|
||||
} else {
|
||||
this.currentSelection?.clear();
|
||||
}
|
||||
if (this.props?.onDragstart) {
|
||||
this.props.onDragstart(e);
|
||||
|
||||
@ -374,7 +374,7 @@ export default class Node {
|
||||
* 2 thisNode before or after otherNode
|
||||
* 0 thisNode same as otherNode
|
||||
*/
|
||||
comparePosition(otherNode: Node): number {
|
||||
comparePosition(otherNode: Node): PositionNO {
|
||||
return comparePosition(this, otherNode);
|
||||
}
|
||||
|
||||
@ -455,31 +455,37 @@ export function contains(node1: Node, node2: Node): boolean {
|
||||
// 8 node1 contained_by node2
|
||||
// 2 node1 before or after node2
|
||||
// 0 node1 same as node2
|
||||
export function comparePosition(node1: Node, node2: Node): number {
|
||||
export enum PositionNO {
|
||||
Contains = 16,
|
||||
ContainedBy = 8,
|
||||
BeforeOrAfter = 2,
|
||||
TheSame = 0,
|
||||
}
|
||||
export function comparePosition(node1: Node, node2: Node): PositionNO {
|
||||
if (node1 === node2) {
|
||||
return 0;
|
||||
return PositionNO.TheSame;
|
||||
}
|
||||
const l1 = node1.zLevel;
|
||||
const l2 = node2.zLevel;
|
||||
if (l1 === l2) {
|
||||
return 2;
|
||||
return PositionNO.BeforeOrAfter;
|
||||
}
|
||||
|
||||
let p: any;
|
||||
if (l1 > l2) {
|
||||
if (l1 < l2) {
|
||||
p = getZLevelTop(node2, l1);
|
||||
if (p && p === node1) {
|
||||
return 16;
|
||||
return PositionNO.Contains;
|
||||
}
|
||||
return 2;
|
||||
return PositionNO.BeforeOrAfter;
|
||||
}
|
||||
|
||||
p = getZLevelTop(node1, l2);
|
||||
if (p && p === node2) {
|
||||
return 8;
|
||||
return PositionNO.ContainedBy;
|
||||
}
|
||||
|
||||
return 2;
|
||||
return PositionNO.BeforeOrAfter;
|
||||
}
|
||||
|
||||
export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import Node, { comparePosition } from './node/node';
|
||||
import Node, { comparePosition, PositionNO } from './node/node';
|
||||
import { obx } from '@recore/obx';
|
||||
import DocumentModel from './document-model';
|
||||
import { EventEmitter } from 'events';
|
||||
@ -136,12 +136,12 @@ export class Selection {
|
||||
while (i-- > 0) {
|
||||
const n = comparePosition(nodes[i], node);
|
||||
// nodes[i] contains node
|
||||
if (n === 16 || n === 0) {
|
||||
if (n === PositionNO.Contains || n === PositionNO.TheSame) {
|
||||
isTop = false;
|
||||
break;
|
||||
}
|
||||
// node contains nodes[i], delete nodes[i]
|
||||
if (n === 8) {
|
||||
if (n === PositionNO.ContainedBy) {
|
||||
nodes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +209,6 @@ registerMetadataTransducer(metadata => {
|
||||
props.push(propConfigToFieldConfig(prop));
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
...metadata,
|
||||
configure: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user