5f317cb89452d984e391fd265dce3f8aefa220ae
[sdc/sdc-workflow-designer.git] /
1 /**
2  * Copyright (c) 2017 ZTE Corporation.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *     ZTE - initial API and implementation and/or initial documentation
11  */
12
13 import { AfterViewChecked, AfterViewInit, Component, ElementRef, HostListener, OnInit, OnDestroy, ViewChild } from '@angular/core';
14
15 import { SequenceFlow } from '../../model/workflow/sequence-flow';
16 import { WorkflowElement } from '../../model/workflow/workflow-element';
17 import { WorkflowNode } from '../../model/workflow/workflow-node';
18 import { BroadcastService } from '../../services/broadcast.service';
19 import { InterfaceService } from '../../services/interface.service';
20 import { JsPlumbService } from '../../services/jsplumb.service';
21 import { ModelService } from '../../services/model.service';
22
23 /**
24  * main canvas, it contains two parts: canvas and node property component
25  * bpmn task nodes can be dropped into this canvas, and then the workflow can be edit
26  */
27 @Component({
28     selector: 'wfm-container',
29     templateUrl: 'container.component.html',
30     styleUrls: ['./container.component.css']
31 })
32 export class ContainerComponent implements AfterViewChecked, AfterViewInit, OnInit, OnDestroy {
33     public allNotes: WorkflowNode[];
34     @ViewChild('nodeSelector') nodeSelector: ElementRef;
35     @ViewChild('mainContainer') mainContainer: ElementRef;
36
37     private isSelecting = false;
38     private selectedElements: WorkflowElement[] = [];
39     private showProperties = false;
40     private needInitSequence = false;
41
42     constructor(private broadcastService: BroadcastService, private jsPlumbService: JsPlumbService,
43         private interfaceService: InterfaceService, public modelService: ModelService) {
44     }
45
46     @HostListener('window:keyup.delete', ['$event']) ondelete(event: KeyboardEvent) {
47         if (this.showProperties || 0 >= this.selectedElements.length) {
48             return;
49         }
50         this.selectedElements.forEach(element => {
51             if (this.modelService.isNode(element)) {
52                 let selectNode = element as WorkflowNode;
53                 const parentId = this.jsPlumbService.getParentNodeId(selectNode.id);
54                 this.jsPlumbService.remove(selectNode);
55                 this.modelService.deleteNode(parentId, selectNode.id);
56             } else {
57                 let sequenceFlow = element as SequenceFlow;
58                 this.modelService.deleteConnection(sequenceFlow.sourceRef, sequenceFlow.targetRef);
59                 this.jsPlumbService.deleteConnect(sequenceFlow.sourceRef, sequenceFlow.targetRef);
60             }
61         });
62         this.selectedElements = [];
63     }
64
65     @HostListener('document:mouseup', ['$event']) onmouseup() {
66         if (this.isSelecting) {
67             this.nodeSelector.nativeElement.style.display = 'none';
68             this.mainContainer.nativeElement.onmousemove = null;
69             this.isSelecting = false;
70             this.broadcastService.broadcast(this.broadcastService.showProperty, null);
71             this.broadcastService.broadcast(this.broadcastService.selectedElement, this.selectedElements);
72         }
73     }
74
75     public ngOnInit() {
76         this.jsPlumbService.initJsPlumbInstance(this.modelService.rootNodeId);
77         this.broadcastService.initModel$.subscribe(() => {
78             this.needInitSequence = true;
79         });
80         this.broadcastService.showProperty$.subscribe(element=>{
81             this.showProperties = null !== element;
82         });
83     }
84
85     public ngAfterViewInit() {
86         this.jsPlumbService.canvasDroppable();
87         this.broadcastService.selectedElement$.subscribe(elements => {
88             if (elements) {
89                 this.selectedElements = elements;
90             } else {
91                 this.selectedElements = [];
92             }
93         });
94     }
95
96     public ngAfterViewChecked() {
97         if (this.needInitSequence) {
98             this.needInitSequence = false;
99             // Add the connection
100             this.jsPlumbService.connectChildrenNodes(this.modelService.rootNodeId);
101         }
102     }
103
104     public ngOnDestroy() {
105         if (this.mainContainer.nativeElement.onmousemove) {
106             this.mainContainer.nativeElement.document.onmousemove = null;
107         }
108     }
109
110     public canvasMouseDown(event) {
111         this.selectedElements = [];
112         this.isSelecting = true;
113         let posx = event.clientX + this.mainContainer.nativeElement.scrollLeft;
114         posx = 220 > posx ? 0 : posx - 220;
115         let posy = event.clientY + this.mainContainer.nativeElement.scrollTop;
116         posy = 60 > posy ? 0 : posy - 60;
117         let element = this.nodeSelector.nativeElement;
118         element.style.left = posx + "px";
119         element.style.top = posy + "px";
120         element.style.width = '0px';
121         element.style.height = '0px';
122         element.style.display = 'block';
123         let curThis = this;
124         this.mainContainer.nativeElement.onmousemove = function (moveEvent) {
125             let movePosx = moveEvent.clientX + curThis.mainContainer.nativeElement.scrollLeft;
126             movePosx = 220 > movePosx ? 0 : movePosx - 220;
127             let movePosy = moveEvent.clientY + curThis.mainContainer.nativeElement.scrollTop;
128             movePosy = 60 > movePosy ? 0 : movePosy - 60;
129             const left = Math.min(movePosx, posx);
130             const top = Math.min(movePosy, posy);
131             const width = Math.abs(posx - movePosx);
132             const height = Math.abs(posy - movePosy);
133             element.style.left = left + "px";
134             element.style.top = top + "px";
135             element.style.width = width + "px";
136             element.style.height = height + "px";
137             curThis.selectNodes(left, top, width, height);
138         };
139     }
140
141     private selectNodes(left: number, top: number, width: number, height: number) {
142         this.selectedElements = [];
143         const allNodes = this.modelService.getNodes();
144         allNodes.forEach(node => {
145             const np = node.position;
146             let selected = false;
147             if (left < np.left) {
148                 if ((top < np.top && left + width > np.left && top + height > np.top)
149                     || (top >= np.top && top < np.top + np.height && left + width > np.left)) {
150                     selected = true;
151                 }
152             } else if (left < np.left + np.width) {
153                 if ((top < np.top && top + height > np.top)
154                     || (top >= np.top && top < np.top + np.height)) {
155                     selected = true;
156                 }
157             }
158             if (selected) {
159                 this.selectedElements.push(node);
160             }
161         });
162         this.broadcastService.broadcast(this.broadcastService.selectedElement, this.selectedElements);
163     }
164
165 }