sequential-workflow-designer 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4315 @@
1
+ 'use strict';
2
+
3
+ var sequentialWorkflowModel = require('sequential-workflow-model');
4
+
5
+ class ControlBarApi {
6
+ constructor(state, historyController, definitionModifier, viewportApi) {
7
+ this.state = state;
8
+ this.historyController = historyController;
9
+ this.definitionModifier = definitionModifier;
10
+ this.viewportApi = viewportApi;
11
+ }
12
+ /**
13
+ * @deprecated Don't use this method
14
+ */
15
+ subscribe(handler) {
16
+ // TODO: this should be refactored
17
+ this.state.onIsReadonlyChanged.subscribe(handler);
18
+ this.state.onSelectedStepIdChanged.subscribe(handler);
19
+ this.state.onIsDragDisabledChanged.subscribe(handler);
20
+ if (this.isUndoRedoSupported()) {
21
+ this.state.onDefinitionChanged.subscribe(handler);
22
+ }
23
+ }
24
+ resetViewport() {
25
+ this.viewportApi.resetViewport();
26
+ }
27
+ zoomIn() {
28
+ this.viewportApi.zoom(true);
29
+ }
30
+ zoomOut() {
31
+ this.viewportApi.zoom(false);
32
+ }
33
+ isDragDisabled() {
34
+ return this.state.isDragDisabled;
35
+ }
36
+ toggleIsDragDisabled() {
37
+ this.state.toggleIsDragDisabled();
38
+ }
39
+ isUndoRedoSupported() {
40
+ return !!this.historyController;
41
+ }
42
+ tryUndo() {
43
+ if (this.canUndo() && this.historyController) {
44
+ this.historyController.undo();
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ canUndo() {
50
+ return !!this.historyController && this.historyController.canUndo() && !this.state.isReadonly && !this.state.isDragging;
51
+ }
52
+ tryRedo() {
53
+ if (this.canRedo() && this.historyController) {
54
+ this.historyController.redo();
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+ canRedo() {
60
+ return !!this.historyController && this.historyController.canRedo() && !this.state.isReadonly && !this.state.isDragging;
61
+ }
62
+ tryDelete() {
63
+ if (this.canDelete() && this.state.selectedStepId) {
64
+ this.definitionModifier.tryDelete(this.state.selectedStepId);
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+ canDelete() {
70
+ return (!!this.state.selectedStepId &&
71
+ !this.state.isReadonly &&
72
+ !this.state.isDragging &&
73
+ this.definitionModifier.isDeletable(this.state.selectedStepId));
74
+ }
75
+ }
76
+
77
+ class SimpleEvent {
78
+ constructor() {
79
+ this.listeners = [];
80
+ }
81
+ subscribe(listener) {
82
+ this.listeners.push(listener);
83
+ }
84
+ unsubscribe(listener) {
85
+ const index = this.listeners.indexOf(listener);
86
+ if (index >= 0) {
87
+ this.listeners.splice(index, 1);
88
+ }
89
+ else {
90
+ throw new Error('Unknown listener');
91
+ }
92
+ }
93
+ forward(value) {
94
+ if (this.listeners.length > 0) {
95
+ this.listeners.forEach(listener => listener(value));
96
+ }
97
+ }
98
+ count() {
99
+ return this.listeners.length;
100
+ }
101
+ }
102
+
103
+ class Vector {
104
+ constructor(x, y) {
105
+ this.x = x;
106
+ this.y = y;
107
+ }
108
+ add(v) {
109
+ return new Vector(this.x + v.x, this.y + v.y);
110
+ }
111
+ subtract(v) {
112
+ return new Vector(this.x - v.x, this.y - v.y);
113
+ }
114
+ multiplyByScalar(s) {
115
+ return new Vector(this.x * s, this.y * s);
116
+ }
117
+ divideByScalar(s) {
118
+ return new Vector(this.x / s, this.y / s);
119
+ }
120
+ round() {
121
+ return new Vector(Math.round(this.x), Math.round(this.y));
122
+ }
123
+ distance() {
124
+ return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
125
+ }
126
+ }
127
+
128
+ exports.DefinitionChangeType = void 0;
129
+ (function (DefinitionChangeType) {
130
+ DefinitionChangeType[DefinitionChangeType["stepNameChanged"] = 1] = "stepNameChanged";
131
+ DefinitionChangeType[DefinitionChangeType["stepPropertyChanged"] = 2] = "stepPropertyChanged";
132
+ DefinitionChangeType[DefinitionChangeType["stepChildrenChanged"] = 3] = "stepChildrenChanged";
133
+ DefinitionChangeType[DefinitionChangeType["stepDeleted"] = 4] = "stepDeleted";
134
+ DefinitionChangeType[DefinitionChangeType["stepMoved"] = 5] = "stepMoved";
135
+ DefinitionChangeType[DefinitionChangeType["stepInserted"] = 6] = "stepInserted";
136
+ DefinitionChangeType[DefinitionChangeType["globalPropertyChanged"] = 7] = "globalPropertyChanged";
137
+ DefinitionChangeType[DefinitionChangeType["rootReplaced"] = 8] = "rootReplaced";
138
+ })(exports.DefinitionChangeType || (exports.DefinitionChangeType = {}));
139
+ class DesignerState {
140
+ constructor(definition, isReadonly, isToolboxCollapsed, isEditorCollapsed) {
141
+ this.definition = definition;
142
+ this.isReadonly = isReadonly;
143
+ this.isToolboxCollapsed = isToolboxCollapsed;
144
+ this.isEditorCollapsed = isEditorCollapsed;
145
+ this.onViewportChanged = new SimpleEvent();
146
+ this.onSelectedStepIdChanged = new SimpleEvent();
147
+ this.onFolderPathChanged = new SimpleEvent();
148
+ this.onIsReadonlyChanged = new SimpleEvent();
149
+ this.onIsDraggingChanged = new SimpleEvent();
150
+ this.onIsDragDisabledChanged = new SimpleEvent();
151
+ this.onDefinitionChanged = new SimpleEvent();
152
+ this.onIsToolboxCollapsedChanged = new SimpleEvent();
153
+ this.onIsEditorCollapsedChanged = new SimpleEvent();
154
+ this.viewport = {
155
+ position: new Vector(0, 0),
156
+ scale: 1
157
+ };
158
+ this.selectedStepId = null;
159
+ this.folderPath = [];
160
+ this.isDragging = false;
161
+ this.isDragDisabled = false;
162
+ }
163
+ setSelectedStepId(stepId) {
164
+ if (this.selectedStepId !== stepId) {
165
+ this.selectedStepId = stepId;
166
+ this.onSelectedStepIdChanged.forward(stepId);
167
+ }
168
+ }
169
+ pushStepIdToFolderPath(stepId) {
170
+ this.folderPath.push(stepId);
171
+ this.onFolderPathChanged.forward(this.folderPath);
172
+ }
173
+ setFolderPath(path) {
174
+ this.folderPath = path;
175
+ this.onFolderPathChanged.forward(path);
176
+ }
177
+ tryGetLastStepIdFromFolderPath() {
178
+ return this.folderPath.length > 0 ? this.folderPath[this.folderPath.length - 1] : null;
179
+ }
180
+ setDefinition(definition) {
181
+ this.definition = definition;
182
+ this.notifyDefinitionChanged(exports.DefinitionChangeType.rootReplaced, null);
183
+ }
184
+ notifyDefinitionChanged(changeType, stepId) {
185
+ this.onDefinitionChanged.forward({ changeType, stepId });
186
+ }
187
+ setViewport(viewport) {
188
+ this.viewport = viewport;
189
+ this.onViewportChanged.forward(viewport);
190
+ }
191
+ setIsReadonly(isReadonly) {
192
+ if (this.isReadonly !== isReadonly) {
193
+ this.isReadonly = isReadonly;
194
+ this.onIsReadonlyChanged.forward(isReadonly);
195
+ }
196
+ }
197
+ setIsDragging(isDragging) {
198
+ if (this.isDragging !== isDragging) {
199
+ this.isDragging = isDragging;
200
+ this.onIsDraggingChanged.forward(isDragging);
201
+ }
202
+ }
203
+ toggleIsDragDisabled() {
204
+ this.isDragDisabled = !this.isDragDisabled;
205
+ this.onIsDragDisabledChanged.forward(this.isDragDisabled);
206
+ }
207
+ setIsToolboxCollapsed(isCollapsed) {
208
+ if (this.isToolboxCollapsed !== isCollapsed) {
209
+ this.isToolboxCollapsed = isCollapsed;
210
+ this.onIsToolboxCollapsedChanged.forward(isCollapsed);
211
+ }
212
+ }
213
+ setIsEditorCollapsed(isCollapsed) {
214
+ if (this.isEditorCollapsed !== isCollapsed) {
215
+ this.isEditorCollapsed = isCollapsed;
216
+ this.onIsEditorCollapsedChanged.forward(isCollapsed);
217
+ }
218
+ }
219
+ }
220
+
221
+ class Dom {
222
+ static svg(name, attributes) {
223
+ const element = document.createElementNS('http://www.w3.org/2000/svg', name);
224
+ if (attributes) {
225
+ Dom.attrs(element, attributes);
226
+ }
227
+ return element;
228
+ }
229
+ static translate(element, x, y) {
230
+ element.setAttribute('transform', `translate(${x}, ${y})`);
231
+ }
232
+ static attrs(element, attributes) {
233
+ Object.keys(attributes).forEach(name => {
234
+ const value = attributes[name];
235
+ element.setAttribute(name, typeof value === 'string' ? value : value.toString());
236
+ });
237
+ }
238
+ static element(name, attributes) {
239
+ const element = document.createElement(name);
240
+ if (attributes) {
241
+ Dom.attrs(element, attributes);
242
+ }
243
+ return element;
244
+ }
245
+ static toggleClass(element, isEnabled, className) {
246
+ if (isEnabled) {
247
+ element.classList.add(className);
248
+ }
249
+ else {
250
+ element.classList.remove(className);
251
+ }
252
+ }
253
+ }
254
+
255
+ // Source: https://fonts.google.com/icons or https://github.com/google/material-design-icons
256
+ class Icons {
257
+ static appendPath(parent, pathClassName, d, size) {
258
+ const g = Dom.svg('g');
259
+ const scale = size / 48;
260
+ const path = Dom.svg('path', {
261
+ d,
262
+ class: pathClassName,
263
+ transform: `scale(${scale})`
264
+ });
265
+ g.appendChild(path);
266
+ parent.appendChild(g);
267
+ return g;
268
+ }
269
+ static createSvg(className, d) {
270
+ const icon = Dom.svg('svg', {
271
+ class: className,
272
+ viewBox: '0 0 48 48'
273
+ });
274
+ const path = Dom.svg('path', {
275
+ d,
276
+ class: 'sqd-icon-path'
277
+ });
278
+ icon.appendChild(path);
279
+ return icon;
280
+ }
281
+ }
282
+ Icons.folderIn = 'M42.05 42.25H11.996v-7.12h17.388L6 11.746 11.546 6.2 34.93 29.584V12.196h7.12V42.25z';
283
+ Icons.folderOut = 'M6 6.2h30.054v7.12H18.666L42.05 36.704l-5.546 5.546L13.12 18.866v17.388H6V6.2z';
284
+ Icons.center = 'M9 42q-1.2 0-2.1-.9Q6 40.2 6 39v-8.6h3V39h8.6v3Zm21.4 0v-3H39v-8.6h3V39q0 1.2-.9 2.1-.9.9-2.1.9ZM24 31.15q-3.15 0-5.15-2-2-2-2-5.15 0-3.15 2-5.15 2-2 5.15-2 3.15 0 5.15 2 2 2 2 5.15 0 3.15-2 5.15-2 2-5.15 2ZM6 17.6V9q0-1.2.9-2.1Q7.8 6 9 6h8.6v3H9v8.6Zm33 0V9h-8.6V6H39q1.2 0 2.1.9.9.9.9 2.1v8.6Z';
285
+ Icons.zoomIn = 'M39.8 41.95 26.65 28.8q-1.5 1.3-3.5 2.025-2 .725-4.25.725-5.4 0-9.15-3.75T6 18.75q0-5.3 3.75-9.05 3.75-3.75 9.1-3.75 5.3 0 9.025 3.75 3.725 3.75 3.725 9.05 0 2.15-.7 4.15-.7 2-2.1 3.75L42 39.75Zm-20.95-13.4q4.05 0 6.9-2.875Q28.6 22.8 28.6 18.75t-2.85-6.925Q22.9 8.95 18.85 8.95q-4.1 0-6.975 2.875T9 18.75q0 4.05 2.875 6.925t6.975 2.875ZM17.3 24.3v-4.1h-4.1v-3h4.1v-4.05h3v4.05h4.05v3H20.3v4.1Z';
286
+ Icons.zoomOut = 'M39.8 41.95 26.65 28.8q-1.5 1.3-3.5 2.025-2 .725-4.25.725-5.4 0-9.15-3.75T6 18.75q0-5.3 3.75-9.05 3.75-3.75 9.1-3.75 5.3 0 9.025 3.75 3.725 3.75 3.725 9.05 0 2.15-.7 4.15-.7 2-2.1 3.75L42 39.75Zm-20.95-13.4q4.05 0 6.9-2.875Q28.6 22.8 28.6 18.75t-2.85-6.925Q22.9 8.95 18.85 8.95q-4.1 0-6.975 2.875T9 18.75q0 4.05 2.875 6.925t6.975 2.875Zm-5.1-8.35v-3H23.8v3Z';
287
+ Icons.undo = 'M14 38v-3h14.45q3.5 0 6.025-2.325Q37 30.35 37 26.9t-2.525-5.775Q31.95 18.8 28.45 18.8H13.7l5.7 5.7-2.1 2.1L8 17.3 17.3 8l2.1 2.1-5.7 5.7h14.7q4.75 0 8.175 3.2Q40 22.2 40 26.9t-3.425 7.9Q33.15 38 28.4 38Z';
288
+ Icons.redo = 'M19.6 38q-4.75 0-8.175-3.2Q8 31.6 8 26.9t3.425-7.9q3.425-3.2 8.175-3.2h14.7l-5.7-5.7L30.7 8l9.3 9.3-9.3 9.3-2.1-2.1 5.7-5.7H19.55q-3.5 0-6.025 2.325Q11 23.45 11 26.9t2.525 5.775Q16.05 35 19.55 35H34v3Z';
289
+ Icons.move = 'm24 44-8.15-8.15 2.2-2.2 4.45 4.45v-9.45h3v9.45l4.45-4.45 2.2 2.2ZM11.9 31.9 4 24l7.95-7.95 2.2 2.2L9.9 22.5h9.45v3H9.9l4.2 4.2Zm24.2 0-2.2-2.2 4.2-4.2h-9.4v-3h9.4l-4.2-4.2 2.2-2.2L44 24ZM22.5 19.3V9.9l-4.2 4.2-2.2-2.2L24 4l7.9 7.9-2.2 2.2-4.2-4.2v9.4Z';
290
+ Icons.delete = 'm16.5 33.6 7.5-7.5 7.5 7.5 2.1-2.1-7.5-7.5 7.5-7.5-2.1-2.1-7.5 7.5-7.5-7.5-2.1 2.1 7.5 7.5-7.5 7.5ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Z';
291
+ Icons.folderUp = 'M22.5 34h3V23.75l3.7 3.7 2.1-2.1-7.3-7.3-7.3 7.3 2.1 2.1 3.7-3.7ZM7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z';
292
+ Icons.close = 'm12.45 37.65-2.1-2.1L21.9 24 10.35 12.45l2.1-2.1L24 21.9l11.55-11.55 2.1 2.1L26.1 24l11.55 11.55-2.1 2.1L24 26.1Z';
293
+ Icons.options = 'm19.4 44-1-6.3q-.95-.35-2-.95t-1.85-1.25l-5.9 2.7L4 30l5.4-3.95q-.1-.45-.125-1.025Q9.25 24.45 9.25 24q0-.45.025-1.025T9.4 21.95L4 18l4.65-8.2 5.9 2.7q.8-.65 1.85-1.25t2-.9l1-6.35h9.2l1 6.3q.95.35 2.025.925Q32.7 11.8 33.45 12.5l5.9-2.7L44 18l-5.4 3.85q.1.5.125 1.075.025.575.025 1.075t-.025 1.05q-.025.55-.125 1.05L44 30l-4.65 8.2-5.9-2.7q-.8.65-1.825 1.275-1.025.625-2.025.925l-1 6.3ZM24 30.5q2.7 0 4.6-1.9 1.9-1.9 1.9-4.6 0-2.7-1.9-4.6-1.9-1.9-4.6-1.9-2.7 0-4.6 1.9-1.9 1.9-1.9 4.6 0 2.7 1.9 4.6 1.9 1.9 4.6 1.9Z';
294
+ Icons.expand = 'm24 30.75-12-12 2.15-2.15L24 26.5l9.85-9.85L36 18.8Z';
295
+ Icons.alert = 'M24 42q-1.45 0-2.475-1.025Q20.5 39.95 20.5 38.5q0-1.45 1.025-2.475Q22.55 35 24 35q1.45 0 2.475 1.025Q27.5 37.05 27.5 38.5q0 1.45-1.025 2.475Q25.45 42 24 42Zm-3.5-12V6h7v24Z';
296
+ Icons.play = 'M14.75 40.15V7.55l25.6 16.3Z';
297
+ Icons.stop = 'M10.75 37.25V10.7H37.3v26.55Z';
298
+ Icons.folder = 'M7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Z';
299
+
300
+ class ObjectCloner {
301
+ static deepClone(instance) {
302
+ if (typeof window.structuredClone !== 'undefined') {
303
+ return window.structuredClone(instance);
304
+ }
305
+ return JSON.parse(JSON.stringify(instance));
306
+ }
307
+ }
308
+
309
+ class Uid {
310
+ static next() {
311
+ const bytes = new Uint8Array(16);
312
+ window.crypto.getRandomValues(bytes);
313
+ return Array.from(bytes, v => v.toString(16).padStart(2, '0')).join('');
314
+ }
315
+ }
316
+
317
+ function race(timeout, a, b, c) {
318
+ const value = [undefined, undefined, undefined];
319
+ const result = new SimpleEvent();
320
+ let scheduled = false;
321
+ function forward() {
322
+ if (scheduled) {
323
+ return;
324
+ }
325
+ scheduled = true;
326
+ setTimeout(() => {
327
+ try {
328
+ result.forward(value);
329
+ }
330
+ finally {
331
+ scheduled = false;
332
+ value.fill(undefined);
333
+ }
334
+ }, timeout);
335
+ }
336
+ [a, b, c]
337
+ .filter(e => e)
338
+ .forEach((e, index) => {
339
+ e.subscribe(v => {
340
+ value[index] = v;
341
+ forward();
342
+ });
343
+ });
344
+ return result;
345
+ }
346
+
347
+ class EditorRenderer {
348
+ static create(state, definitionWalker, handler) {
349
+ const listener = new EditorRenderer(state, definitionWalker, handler);
350
+ race(0, state.onDefinitionChanged, state.onSelectedStepIdChanged).subscribe(r => {
351
+ const [definitionChanged, selectedStepId] = r;
352
+ if (definitionChanged) {
353
+ listener.onDefinitionChanged(definitionChanged);
354
+ }
355
+ else if (selectedStepId !== undefined) {
356
+ listener.onSelectedStepIdChanged(selectedStepId);
357
+ }
358
+ });
359
+ listener.tryRender(state.selectedStepId);
360
+ return listener;
361
+ }
362
+ constructor(state, definitionWalker, handler) {
363
+ this.state = state;
364
+ this.definitionWalker = definitionWalker;
365
+ this.handler = handler;
366
+ this.currentStepId = undefined;
367
+ }
368
+ destroy() {
369
+ // TODO: unsubscribe from events
370
+ }
371
+ render(stepId) {
372
+ const step = stepId ? this.definitionWalker.getById(this.state.definition, stepId) : null;
373
+ this.currentStepId = stepId;
374
+ this.handler(step);
375
+ }
376
+ tryRender(stepId) {
377
+ if (this.currentStepId !== stepId) {
378
+ this.render(stepId);
379
+ }
380
+ }
381
+ onDefinitionChanged(event) {
382
+ if (event.changeType === exports.DefinitionChangeType.rootReplaced) {
383
+ this.render(this.state.selectedStepId);
384
+ }
385
+ else {
386
+ this.tryRender(this.state.selectedStepId);
387
+ }
388
+ }
389
+ onSelectedStepIdChanged(stepId) {
390
+ this.tryRender(stepId);
391
+ }
392
+ }
393
+
394
+ class EditorApi {
395
+ constructor(state, definitionWalker, definitionModifier) {
396
+ this.state = state;
397
+ this.definitionWalker = definitionWalker;
398
+ this.definitionModifier = definitionModifier;
399
+ }
400
+ isCollapsed() {
401
+ return this.state.isEditorCollapsed;
402
+ }
403
+ toggleIsCollapsed() {
404
+ this.state.setIsEditorCollapsed(!this.state.isEditorCollapsed);
405
+ }
406
+ subscribeIsCollapsed(listener) {
407
+ this.state.onIsEditorCollapsedChanged.subscribe(listener);
408
+ }
409
+ getDefinition() {
410
+ return this.state.definition;
411
+ }
412
+ runRenderer(rendererHandler) {
413
+ return EditorRenderer.create(this.state, this.definitionWalker, rendererHandler);
414
+ }
415
+ createStepEditorContext(stepId) {
416
+ if (!stepId) {
417
+ throw new Error('Step id is empty');
418
+ }
419
+ return {
420
+ notifyPropertiesChanged: () => {
421
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepPropertyChanged, stepId);
422
+ },
423
+ notifyNameChanged: () => {
424
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepNameChanged, stepId);
425
+ },
426
+ notifyChildrenChanged: () => {
427
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepChildrenChanged, stepId);
428
+ this.definitionModifier.updateDependantFields();
429
+ }
430
+ };
431
+ }
432
+ createGlobalEditorContext() {
433
+ return {
434
+ notifyPropertiesChanged: () => {
435
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.globalPropertyChanged, null);
436
+ }
437
+ };
438
+ }
439
+ }
440
+
441
+ class PathBarApi {
442
+ constructor(state, definitionWalker) {
443
+ this.state = state;
444
+ this.definitionWalker = definitionWalker;
445
+ }
446
+ /**
447
+ * @deprecated Don't use this method
448
+ */
449
+ subscribe(handler) {
450
+ // TODO: this should be refactored
451
+ race(0, this.state.onFolderPathChanged, this.state.onDefinitionChanged).subscribe(handler);
452
+ }
453
+ setFolderPath(path) {
454
+ this.state.setFolderPath(path);
455
+ }
456
+ getFolderPath() {
457
+ return this.state.folderPath;
458
+ }
459
+ getFolderPathStepNames() {
460
+ return this.state.folderPath.map(stepId => {
461
+ return this.definitionWalker.getById(this.state.definition, stepId).name;
462
+ });
463
+ }
464
+ }
465
+
466
+ class DragStepView {
467
+ static create(step, theme, componentContext) {
468
+ const layer = Dom.element('div', {
469
+ class: `sqd-drag sqd-theme-${theme}`
470
+ });
471
+ document.body.appendChild(layer);
472
+ const component = componentContext.services.draggedComponent.create(layer, step, componentContext);
473
+ return new DragStepView(component, layer);
474
+ }
475
+ constructor(component, layer) {
476
+ this.component = component;
477
+ this.layer = layer;
478
+ }
479
+ setPosition(position) {
480
+ this.layer.style.top = position.y + 'px';
481
+ this.layer.style.left = position.x + 'px';
482
+ }
483
+ remove() {
484
+ this.component.destroy();
485
+ document.body.removeChild(this.layer);
486
+ }
487
+ }
488
+
489
+ class PlaceholderFinder {
490
+ static create(placeholders, state) {
491
+ const checker = new PlaceholderFinder(placeholders, state);
492
+ state.onViewportChanged.subscribe(checker.clearCacheHandler);
493
+ window.addEventListener('scroll', checker.clearCacheHandler, false);
494
+ return checker;
495
+ }
496
+ constructor(placeholders, state) {
497
+ this.placeholders = placeholders;
498
+ this.state = state;
499
+ this.clearCacheHandler = () => this.clearCache();
500
+ }
501
+ find(vLt, vWidth, vHeight) {
502
+ var _a;
503
+ if (!this.cache) {
504
+ const scroll = new Vector(window.scrollX, window.scrollY);
505
+ this.cache = this.placeholders.map(placeholder => {
506
+ const rect = placeholder.getClientRect();
507
+ return {
508
+ placeholder,
509
+ lt: new Vector(rect.x, rect.y).add(scroll),
510
+ br: new Vector(rect.x + rect.width, rect.y + rect.height).add(scroll)
511
+ };
512
+ });
513
+ this.cache.sort((a, b) => a.lt.y - b.lt.y);
514
+ }
515
+ const vR = vLt.x + vWidth;
516
+ const vB = vLt.y + vHeight;
517
+ return (_a = this.cache.find(p => {
518
+ return Math.max(vLt.x, p.lt.x) < Math.min(vR, p.br.x) && Math.max(vLt.y, p.lt.y) < Math.min(vB, p.br.y);
519
+ })) === null || _a === void 0 ? void 0 : _a.placeholder;
520
+ }
521
+ destroy() {
522
+ this.state.onViewportChanged.unsubscribe(this.clearCacheHandler);
523
+ window.removeEventListener('scroll', this.clearCacheHandler, false);
524
+ }
525
+ clearCache() {
526
+ this.cache = undefined;
527
+ }
528
+ }
529
+
530
+ class DragStepBehavior {
531
+ static create(designerContext, step, draggedStepComponent) {
532
+ const view = DragStepView.create(step, designerContext.theme, designerContext.componentContext);
533
+ return new DragStepBehavior(view, designerContext.workspaceController, designerContext.state, step, designerContext.definitionModifier, draggedStepComponent);
534
+ }
535
+ constructor(view, workspaceController, designerState, step, definitionModifier, draggedStepComponent) {
536
+ this.view = view;
537
+ this.workspaceController = workspaceController;
538
+ this.designerState = designerState;
539
+ this.step = step;
540
+ this.definitionModifier = definitionModifier;
541
+ this.draggedStepComponent = draggedStepComponent;
542
+ }
543
+ onStart(position) {
544
+ let offset = null;
545
+ if (this.draggedStepComponent) {
546
+ this.draggedStepComponent.setIsDisabled(true);
547
+ const hasSameSize = this.draggedStepComponent.view.width === this.view.component.width &&
548
+ this.draggedStepComponent.view.height === this.view.component.height;
549
+ if (hasSameSize) {
550
+ const scroll = new Vector(window.scrollX, window.scrollY);
551
+ // Mouse cursor will be positioned on the same place as the source component.
552
+ const pagePosition = this.draggedStepComponent.view.getClientPosition().add(scroll);
553
+ offset = position.subtract(pagePosition);
554
+ }
555
+ }
556
+ if (!offset) {
557
+ // Mouse cursor will be positioned in the center of the component.
558
+ offset = new Vector(this.view.component.width, this.view.component.height).divideByScalar(2);
559
+ }
560
+ this.view.setPosition(position.subtract(offset));
561
+ this.designerState.setIsDragging(true);
562
+ const placeholders = this.workspaceController.getPlaceholders();
563
+ this.state = {
564
+ startPosition: position,
565
+ finder: PlaceholderFinder.create(placeholders, this.designerState),
566
+ offset
567
+ };
568
+ }
569
+ onMove(delta) {
570
+ if (this.state) {
571
+ const newPosition = this.state.startPosition.subtract(delta).subtract(this.state.offset);
572
+ this.view.setPosition(newPosition);
573
+ const placeholder = this.state.finder.find(newPosition, this.view.component.width, this.view.component.height);
574
+ if (this.currentPlaceholder !== placeholder) {
575
+ if (this.currentPlaceholder) {
576
+ this.currentPlaceholder.setIsHover(false);
577
+ }
578
+ if (placeholder) {
579
+ placeholder.setIsHover(true);
580
+ }
581
+ this.currentPlaceholder = placeholder;
582
+ }
583
+ }
584
+ }
585
+ onEnd(interrupt) {
586
+ if (!this.state) {
587
+ throw new Error('Invalid state');
588
+ }
589
+ this.state.finder.destroy();
590
+ this.state = undefined;
591
+ this.view.remove();
592
+ this.designerState.setIsDragging(false);
593
+ let modified = false;
594
+ if (!interrupt && this.currentPlaceholder) {
595
+ if (this.draggedStepComponent) {
596
+ modified = this.definitionModifier.tryMove(this.draggedStepComponent.parentSequence, this.draggedStepComponent.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
597
+ }
598
+ else {
599
+ modified = this.definitionModifier.tryInsert(this.step, this.currentPlaceholder.parentSequence, this.currentPlaceholder.index);
600
+ }
601
+ }
602
+ if (!modified) {
603
+ if (this.draggedStepComponent) {
604
+ this.draggedStepComponent.setIsDisabled(false);
605
+ }
606
+ if (this.currentPlaceholder) {
607
+ this.currentPlaceholder.setIsHover(false);
608
+ }
609
+ }
610
+ this.currentPlaceholder = undefined;
611
+ }
612
+ }
613
+
614
+ class ToolboxApi {
615
+ constructor(state, designerContext, behaviorController, iconProvider, configuration, uidGenerator) {
616
+ this.state = state;
617
+ this.designerContext = designerContext;
618
+ this.behaviorController = behaviorController;
619
+ this.iconProvider = iconProvider;
620
+ this.configuration = configuration;
621
+ this.uidGenerator = uidGenerator;
622
+ }
623
+ isCollapsed() {
624
+ return this.state.isToolboxCollapsed;
625
+ }
626
+ toggleIsCollapsed() {
627
+ this.state.setIsToolboxCollapsed(!this.state.isToolboxCollapsed);
628
+ }
629
+ subscribeIsCollapsed(listener) {
630
+ this.state.onIsToolboxCollapsedChanged.subscribe(listener);
631
+ }
632
+ tryGetIconUrl(step) {
633
+ return this.iconProvider.getIconUrl(step);
634
+ }
635
+ getLabel(step) {
636
+ const labelProvider = this.getConfiguration().labelProvider;
637
+ return labelProvider ? labelProvider(step) : step.name;
638
+ }
639
+ filterGroups(filter) {
640
+ return this.getConfiguration()
641
+ .groups.map(group => {
642
+ return {
643
+ name: group.name,
644
+ steps: group.steps.filter(s => {
645
+ return filter ? s.name.toLowerCase().includes(filter) : true;
646
+ })
647
+ };
648
+ })
649
+ .filter(group => group.steps.length > 0);
650
+ }
651
+ /**
652
+ * @param position Mouse or touch position.
653
+ * @param step Step definition.
654
+ * @returns If started dragging returns true, otherwise returns false.
655
+ */
656
+ tryDrag(position, step) {
657
+ if (!this.state.isReadonly) {
658
+ const newStep = this.activateStep(step);
659
+ this.behaviorController.start(position, DragStepBehavior.create(this.designerContext, newStep));
660
+ return true;
661
+ }
662
+ return false;
663
+ }
664
+ activateStep(step) {
665
+ const newStep = ObjectCloner.deepClone(step);
666
+ newStep.id = this.uidGenerator ? this.uidGenerator() : Uid.next();
667
+ return newStep;
668
+ }
669
+ getConfiguration() {
670
+ if (!this.configuration) {
671
+ throw new Error('Toolbox is disabled');
672
+ }
673
+ return this.configuration;
674
+ }
675
+ }
676
+
677
+ class ViewportApi {
678
+ constructor(workspaceController, viewportController) {
679
+ this.workspaceController = workspaceController;
680
+ this.viewportController = viewportController;
681
+ }
682
+ resetViewport() {
683
+ this.viewportController.setDefault();
684
+ }
685
+ zoom(direction) {
686
+ this.viewportController.zoom(direction);
687
+ }
688
+ moveViewportToStep(stepId) {
689
+ const component = this.workspaceController.getComponentByStepId(stepId);
690
+ const componentPosition = component.view.getClientPosition();
691
+ const componentSize = new Vector(component.view.width, component.view.height);
692
+ this.viewportController.focusOnComponent(componentPosition, componentSize);
693
+ }
694
+ }
695
+
696
+ class WorkspaceApi {
697
+ constructor(state, workspaceController) {
698
+ this.state = state;
699
+ this.workspaceController = workspaceController;
700
+ }
701
+ getCanvasPosition() {
702
+ return this.workspaceController.getCanvasPosition();
703
+ }
704
+ getCanvasSize() {
705
+ return this.workspaceController.getCanvasSize();
706
+ }
707
+ getRootComponentSize() {
708
+ return this.workspaceController.getRootComponentSize();
709
+ }
710
+ getViewport() {
711
+ return this.state.viewport;
712
+ }
713
+ setViewport(viewport) {
714
+ this.state.setViewport(viewport);
715
+ }
716
+ updateRootComponent() {
717
+ this.workspaceController.updateRootComponent();
718
+ }
719
+ updateBadges() {
720
+ this.workspaceController.updateBadges();
721
+ }
722
+ updateCanvasSize() {
723
+ this.workspaceController.updateCanvasSize();
724
+ }
725
+ }
726
+
727
+ class DesignerApi {
728
+ static create(context) {
729
+ const workspace = new WorkspaceApi(context.state, context.workspaceController);
730
+ const viewportController = context.services.viewportController.create(workspace);
731
+ const viewport = new ViewportApi(context.workspaceController, viewportController);
732
+ return new DesignerApi(new ControlBarApi(context.state, context.historyController, context.definitionModifier, viewport), new ToolboxApi(context.state, context, context.behaviorController, context.componentContext.iconProvider, context.configuration.toolbox, context.configuration.uidGenerator), new EditorApi(context.state, context.definitionWalker, context.definitionModifier), workspace, viewport, new PathBarApi(context.state, context.definitionWalker));
733
+ }
734
+ constructor(controlBar, toolbox, editor, workspace, viewport, pathBar) {
735
+ this.controlBar = controlBar;
736
+ this.toolbox = toolbox;
737
+ this.editor = editor;
738
+ this.workspace = workspace;
739
+ this.viewport = viewport;
740
+ this.pathBar = pathBar;
741
+ }
742
+ }
743
+
744
+ class DefinitionValidator {
745
+ constructor(configuration, state) {
746
+ this.configuration = configuration;
747
+ this.state = state;
748
+ }
749
+ validateStep(step, parentSequence) {
750
+ var _a;
751
+ if ((_a = this.configuration) === null || _a === void 0 ? void 0 : _a.step) {
752
+ return this.configuration.step(step, parentSequence, this.state.definition);
753
+ }
754
+ return true;
755
+ }
756
+ validateRoot() {
757
+ var _a;
758
+ if ((_a = this.configuration) === null || _a === void 0 ? void 0 : _a.root) {
759
+ return this.configuration.root(this.state.definition);
760
+ }
761
+ return true;
762
+ }
763
+ }
764
+
765
+ class IconProvider {
766
+ constructor(configuration) {
767
+ this.configuration = configuration;
768
+ }
769
+ getIconUrl(step) {
770
+ if (this.configuration.iconUrlProvider) {
771
+ return this.configuration.iconUrlProvider(step.componentType, step.type);
772
+ }
773
+ return null;
774
+ }
775
+ }
776
+
777
+ const BADGE_GAP = 4;
778
+ class Badges {
779
+ static createForStep(stepContext, view, componentContext) {
780
+ const g = createG(view.g);
781
+ const badges = componentContext.services.badges.map(ext => ext.createForStep(g, stepContext, componentContext));
782
+ const position = new Vector(view.width, 0);
783
+ return new Badges(g, position, badges);
784
+ }
785
+ static createForRoot(parentElement, position, componentContext) {
786
+ const g = createG(parentElement);
787
+ const badges = componentContext.services.badges.map(ext => {
788
+ return ext.createForRoot ? ext.createForRoot(g, componentContext) : null;
789
+ });
790
+ return new Badges(g, position, badges);
791
+ }
792
+ constructor(g, position, badges) {
793
+ this.g = g;
794
+ this.position = position;
795
+ this.badges = badges;
796
+ }
797
+ update(result) {
798
+ const count = this.badges.length;
799
+ for (let i = 0; i < count; i++) {
800
+ const badge = this.badges[i];
801
+ if (badge) {
802
+ result[i] = badge.update(result[i]);
803
+ }
804
+ }
805
+ let offsetX = 0;
806
+ let maxHeight = 0;
807
+ let j = 0;
808
+ for (let i = 0; i < count; i++) {
809
+ const badge = this.badges[i];
810
+ if (badge && badge.view) {
811
+ offsetX += j === 0 ? badge.view.width / 2 : badge.view.width;
812
+ maxHeight = Math.max(maxHeight, badge.view.height);
813
+ Dom.translate(badge.view.g, -offsetX, 0);
814
+ offsetX += BADGE_GAP;
815
+ j++;
816
+ }
817
+ }
818
+ Dom.translate(this.g, this.position.x, this.position.y + -maxHeight / 2);
819
+ }
820
+ resolveClick(click) {
821
+ for (const badge of this.badges) {
822
+ const command = badge && badge.resolveClick(click);
823
+ if (command) {
824
+ return command;
825
+ }
826
+ }
827
+ return null;
828
+ }
829
+ }
830
+ function createG(parentElement) {
831
+ const g = Dom.svg('g', {
832
+ class: 'sqd-badges'
833
+ });
834
+ parentElement.appendChild(g);
835
+ return g;
836
+ }
837
+
838
+ exports.ClickCommandType = void 0;
839
+ (function (ClickCommandType) {
840
+ ClickCommandType[ClickCommandType["selectStep"] = 1] = "selectStep";
841
+ ClickCommandType[ClickCommandType["rerenderStep"] = 2] = "rerenderStep";
842
+ ClickCommandType[ClickCommandType["openFolder"] = 3] = "openFolder";
843
+ ClickCommandType[ClickCommandType["triggerCustomAction"] = 4] = "triggerCustomAction";
844
+ })(exports.ClickCommandType || (exports.ClickCommandType = {}));
845
+ exports.PlaceholderDirection = void 0;
846
+ (function (PlaceholderDirection) {
847
+ PlaceholderDirection[PlaceholderDirection["none"] = 0] = "none";
848
+ PlaceholderDirection[PlaceholderDirection["in"] = 1] = "in";
849
+ PlaceholderDirection[PlaceholderDirection["out"] = 2] = "out";
850
+ })(exports.PlaceholderDirection || (exports.PlaceholderDirection = {}));
851
+
852
+ class StepComponent {
853
+ static create(view, stepContext, componentContext) {
854
+ const badges = Badges.createForStep(stepContext, view, componentContext);
855
+ return new StepComponent(view, stepContext.step, stepContext.parentSequence, view.hasOutput(), badges);
856
+ }
857
+ constructor(view, step, parentSequence, hasOutput, badges) {
858
+ this.view = view;
859
+ this.step = step;
860
+ this.parentSequence = parentSequence;
861
+ this.hasOutput = hasOutput;
862
+ this.badges = badges;
863
+ this.isDisabled = false;
864
+ }
865
+ findById(stepId) {
866
+ if (this.step.id === stepId) {
867
+ return this;
868
+ }
869
+ if (this.view.sequenceComponents) {
870
+ for (const component of this.view.sequenceComponents) {
871
+ const result = component.findById(stepId);
872
+ if (result) {
873
+ return result;
874
+ }
875
+ }
876
+ }
877
+ return null;
878
+ }
879
+ resolveClick(click) {
880
+ if (this.view.sequenceComponents) {
881
+ for (const component of this.view.sequenceComponents) {
882
+ const result = component.resolveClick(click);
883
+ if (result) {
884
+ return result;
885
+ }
886
+ }
887
+ }
888
+ const badgeResult = this.badges.resolveClick(click);
889
+ if (badgeResult) {
890
+ return badgeResult;
891
+ }
892
+ const viewResult = this.view.resolveClick(click);
893
+ if (viewResult) {
894
+ return viewResult === true
895
+ ? {
896
+ type: exports.ClickCommandType.selectStep,
897
+ component: this
898
+ }
899
+ : viewResult;
900
+ }
901
+ return null;
902
+ }
903
+ getPlaceholders(result) {
904
+ if (!this.isDisabled) {
905
+ if (this.view.sequenceComponents) {
906
+ this.view.sequenceComponents.forEach(component => component.getPlaceholders(result));
907
+ }
908
+ if (this.view.placeholders) {
909
+ this.view.placeholders.forEach(ph => result.push(ph));
910
+ }
911
+ }
912
+ }
913
+ setIsDragging(isDragging) {
914
+ if (!this.isDisabled) {
915
+ if (this.view.sequenceComponents) {
916
+ this.view.sequenceComponents.forEach(component => component.setIsDragging(isDragging));
917
+ }
918
+ if (this.view.placeholders) {
919
+ this.view.placeholders.forEach(ph => ph.setIsVisible(isDragging));
920
+ }
921
+ }
922
+ this.view.setIsDragging(isDragging);
923
+ }
924
+ setIsSelected(isSelected) {
925
+ this.view.setIsSelected(isSelected);
926
+ }
927
+ setIsDisabled(isDisabled) {
928
+ this.isDisabled = isDisabled;
929
+ this.view.setIsDisabled(isDisabled);
930
+ }
931
+ updateBadges(result) {
932
+ if (this.view.sequenceComponents) {
933
+ this.view.sequenceComponents.forEach(component => component.updateBadges(result));
934
+ }
935
+ this.badges.update(result);
936
+ }
937
+ }
938
+
939
+ class StepComponentViewContextFactory {
940
+ static create(stepContext, componentContext) {
941
+ return {
942
+ getStepIconUrl: () => componentContext.iconProvider.getIconUrl(stepContext.step),
943
+ createSequenceComponent: (parentElement, sequence) => {
944
+ const sequenceContext = {
945
+ sequence,
946
+ depth: stepContext.depth + 1,
947
+ isInputConnected: true,
948
+ isOutputConnected: stepContext.isOutputConnected
949
+ };
950
+ return componentContext.services.sequenceComponent.create(parentElement, sequenceContext, componentContext);
951
+ },
952
+ createPlaceholderForArea: componentContext.services.placeholder.createForArea.bind(componentContext.services.placeholder)
953
+ };
954
+ }
955
+ }
956
+
957
+ class StepComponentFactory {
958
+ constructor(stepExtensionResolver) {
959
+ this.stepExtensionResolver = stepExtensionResolver;
960
+ }
961
+ create(parentElement, stepContext, componentContext) {
962
+ const viewContext = StepComponentViewContextFactory.create(stepContext, componentContext);
963
+ const extension = this.stepExtensionResolver.resolve(stepContext.step.componentType);
964
+ const view = extension.createComponentView(parentElement, stepContext, viewContext);
965
+ const wrappedView = componentContext.services.stepComponentViewWrapper.wrap(view, stepContext);
966
+ return StepComponent.create(wrappedView, stepContext, componentContext);
967
+ }
968
+ }
969
+
970
+ class ComponentContext {
971
+ static create(stepsConfiguration, validatorConfiguration, state, stepExtensionResolver, services) {
972
+ const validator = new DefinitionValidator(validatorConfiguration, state);
973
+ const iconProvider = new IconProvider(stepsConfiguration);
974
+ const placeholderController = services.placeholderController.create();
975
+ const stepComponentFactory = new StepComponentFactory(stepExtensionResolver);
976
+ return new ComponentContext(validator, iconProvider, placeholderController, stepComponentFactory, services);
977
+ }
978
+ constructor(validator, iconProvider, placeholderController, stepComponentFactory, services) {
979
+ this.validator = validator;
980
+ this.iconProvider = iconProvider;
981
+ this.placeholderController = placeholderController;
982
+ this.stepComponentFactory = stepComponentFactory;
983
+ this.services = services;
984
+ }
985
+ }
986
+
987
+ class EditorView {
988
+ static create(parent) {
989
+ return new EditorView(parent);
990
+ }
991
+ constructor(parent) {
992
+ this.parent = parent;
993
+ this.currentContainer = null;
994
+ }
995
+ setContent(content, className) {
996
+ const container = Dom.element('div', {
997
+ class: className
998
+ });
999
+ container.appendChild(content);
1000
+ if (this.currentContainer) {
1001
+ this.parent.removeChild(this.currentContainer);
1002
+ }
1003
+ this.parent.appendChild(container);
1004
+ this.currentContainer = container;
1005
+ }
1006
+ destroy() {
1007
+ if (this.currentContainer) {
1008
+ this.parent.removeChild(this.currentContainer);
1009
+ }
1010
+ }
1011
+ }
1012
+
1013
+ class Editor {
1014
+ static create(parent, api, stepEditorClassName, stepEditorProvider, globalEditorClassName, globalEditorProvider) {
1015
+ const view = EditorView.create(parent);
1016
+ function render(step) {
1017
+ const definition = api.getDefinition();
1018
+ let content;
1019
+ let className;
1020
+ if (step) {
1021
+ const stepContext = api.createStepEditorContext(step.id);
1022
+ content = stepEditorProvider(step, stepContext, definition);
1023
+ className = stepEditorClassName;
1024
+ }
1025
+ else {
1026
+ const globalContext = api.createGlobalEditorContext();
1027
+ content = globalEditorProvider(definition, globalContext);
1028
+ className = globalEditorClassName;
1029
+ }
1030
+ view.setContent(content, className);
1031
+ }
1032
+ const renderer = api.runRenderer(step => render(step));
1033
+ return new Editor(view, renderer);
1034
+ }
1035
+ constructor(view, renderer) {
1036
+ this.view = view;
1037
+ this.renderer = renderer;
1038
+ }
1039
+ destroy() {
1040
+ this.view.destroy();
1041
+ this.renderer.destroy();
1042
+ }
1043
+ }
1044
+
1045
+ class ValidationErrorBadgeView {
1046
+ static create(parent, cfg) {
1047
+ const g = Dom.svg('g');
1048
+ const halfOfSize = cfg.size / 2;
1049
+ const circle = Dom.svg('path', {
1050
+ class: 'sqd-validation-error',
1051
+ d: `M 0 ${-halfOfSize} l ${halfOfSize} ${cfg.size} l ${-cfg.size} 0 Z`
1052
+ });
1053
+ Dom.translate(circle, halfOfSize, halfOfSize);
1054
+ g.appendChild(circle);
1055
+ const icon = Icons.appendPath(g, 'sqd-validation-error-icon-path', Icons.alert, cfg.iconSize);
1056
+ const offsetX = (cfg.size - cfg.iconSize) * 0.5;
1057
+ const offsetY = offsetX * 1.5;
1058
+ Dom.translate(icon, offsetX, offsetY);
1059
+ parent.appendChild(g);
1060
+ return new ValidationErrorBadgeView(parent, g, cfg.size, cfg.size);
1061
+ }
1062
+ constructor(parent, g, width, height) {
1063
+ this.parent = parent;
1064
+ this.g = g;
1065
+ this.width = width;
1066
+ this.height = height;
1067
+ }
1068
+ destroy() {
1069
+ this.parent.removeChild(this.g);
1070
+ }
1071
+ }
1072
+
1073
+ class ValidationErrorBadge {
1074
+ static createForStep(parentElement, stepContext, componentContext, configuration) {
1075
+ const validator = () => componentContext.validator.validateStep(stepContext.step, stepContext.parentSequence);
1076
+ return new ValidationErrorBadge(parentElement, validator, configuration);
1077
+ }
1078
+ static createForRoot(parentElement, componentContext, configuration) {
1079
+ const validator = () => componentContext.validator.validateRoot();
1080
+ return new ValidationErrorBadge(parentElement, validator, configuration);
1081
+ }
1082
+ constructor(parentElement, validator, configuration) {
1083
+ this.parentElement = parentElement;
1084
+ this.validator = validator;
1085
+ this.configuration = configuration;
1086
+ this.view = null;
1087
+ }
1088
+ update(result) {
1089
+ const isValid = this.validator();
1090
+ if (isValid) {
1091
+ if (this.view) {
1092
+ this.view.destroy();
1093
+ this.view = null;
1094
+ }
1095
+ }
1096
+ else if (!this.view) {
1097
+ this.view = ValidationErrorBadgeView.create(this.parentElement, this.configuration);
1098
+ }
1099
+ return isValid && result;
1100
+ }
1101
+ resolveClick() {
1102
+ return null;
1103
+ }
1104
+ }
1105
+
1106
+ const defaultConfiguration$5 = {
1107
+ view: {
1108
+ size: 22,
1109
+ iconSize: 12
1110
+ }
1111
+ };
1112
+ class ValidationErrorBadgeExtension {
1113
+ static create(configuration) {
1114
+ return new ValidationErrorBadgeExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$5);
1115
+ }
1116
+ constructor(configuration) {
1117
+ this.configuration = configuration;
1118
+ this.id = 'validationError';
1119
+ this.createStartValue = () => true;
1120
+ }
1121
+ createForStep(parentElement, stepContext, componentContext) {
1122
+ return ValidationErrorBadge.createForStep(parentElement, stepContext, componentContext, this.configuration.view);
1123
+ }
1124
+ createForRoot(parentElement, componentContext) {
1125
+ return ValidationErrorBadge.createForRoot(parentElement, componentContext, this.configuration.view);
1126
+ }
1127
+ }
1128
+
1129
+ class InputView {
1130
+ static createRectInput(parent, x, y, size, iconSize, iconUrl) {
1131
+ const g = Dom.svg('g');
1132
+ parent.appendChild(g);
1133
+ const rect = Dom.svg('rect', {
1134
+ class: 'sqd-input',
1135
+ width: size,
1136
+ height: size,
1137
+ x: x - size / 2,
1138
+ y: y + size / -2 + 0.5,
1139
+ rx: 4,
1140
+ ry: 4
1141
+ });
1142
+ g.appendChild(rect);
1143
+ if (iconUrl) {
1144
+ const icon = Dom.svg('image', {
1145
+ href: iconUrl,
1146
+ width: iconSize,
1147
+ height: iconSize,
1148
+ x: x - iconSize / 2,
1149
+ y: y + iconSize / -2
1150
+ });
1151
+ g.appendChild(icon);
1152
+ }
1153
+ return new InputView(g);
1154
+ }
1155
+ static createRoundInput(parent, x, y, size) {
1156
+ const circle = Dom.svg('circle', {
1157
+ class: 'sqd-input',
1158
+ cx: x,
1159
+ xy: y,
1160
+ r: size / 2
1161
+ });
1162
+ parent.appendChild(circle);
1163
+ return new InputView(circle);
1164
+ }
1165
+ constructor(root) {
1166
+ this.root = root;
1167
+ }
1168
+ setIsHidden(isHidden) {
1169
+ Dom.attrs(this.root, {
1170
+ visibility: isHidden ? 'hidden' : 'visible'
1171
+ });
1172
+ }
1173
+ }
1174
+
1175
+ class JoinView {
1176
+ static createStraightJoin(parent, start, height) {
1177
+ const join = Dom.svg('line', {
1178
+ class: 'sqd-join',
1179
+ x1: start.x,
1180
+ y1: start.y,
1181
+ x2: start.x,
1182
+ y2: start.y + height
1183
+ });
1184
+ parent.insertBefore(join, parent.firstChild);
1185
+ }
1186
+ static createJoins(parent, start, targets) {
1187
+ const firstTarget = targets[0];
1188
+ const h = Math.abs(firstTarget.y - start.y) / 2; // half height
1189
+ const y = Math.sign(firstTarget.y - start.y); // y direction
1190
+ switch (targets.length) {
1191
+ case 1:
1192
+ if (start.x === targets[0].x) {
1193
+ JoinView.createStraightJoin(parent, start, firstTarget.y * y);
1194
+ }
1195
+ else {
1196
+ appendCurvedJoins(parent, start, targets, h, y);
1197
+ }
1198
+ break;
1199
+ case 2:
1200
+ appendCurvedJoins(parent, start, targets, h, y);
1201
+ break;
1202
+ default:
1203
+ {
1204
+ const f = targets[0]; // first
1205
+ const l = targets[targets.length - 1]; // last
1206
+ appendJoin(parent, `M ${f.x} ${f.y} q ${h * 0.3} ${h * -y * 0.8} ${h} ${h * -y} ` +
1207
+ `l ${l.x - f.x - h * 2} 0 q ${h * 0.8} ${-h * -y * 0.3} ${h} ${-h * -y}`);
1208
+ for (let i = 1; i < targets.length - 1; i++) {
1209
+ JoinView.createStraightJoin(parent, targets[i], h * -y);
1210
+ }
1211
+ JoinView.createStraightJoin(parent, start, h * y);
1212
+ }
1213
+ break;
1214
+ }
1215
+ }
1216
+ }
1217
+ function appendCurvedJoins(parent, start, targets, h, y) {
1218
+ for (const target of targets) {
1219
+ const l = Math.abs(target.x - start.x) - h * 2; // line size
1220
+ const x = Math.sign(target.x - start.x); // x direction
1221
+ appendJoin(parent, `M ${start.x} ${start.y} q ${x * h * 0.3} ${y * h * 0.8} ${x * h} ${y * h} ` +
1222
+ `l ${x * l} 0 q ${x * h * 0.7} ${y * h * 0.2} ${x * h} ${y * h}`);
1223
+ }
1224
+ }
1225
+ function appendJoin(parent, d) {
1226
+ const join = Dom.svg('path', {
1227
+ class: 'sqd-join',
1228
+ fill: 'none',
1229
+ d
1230
+ });
1231
+ parent.insertBefore(join, parent.firstChild);
1232
+ }
1233
+
1234
+ class LabelView {
1235
+ static create(parent, y, cfg, text, theme) {
1236
+ const g = Dom.svg('g', {
1237
+ class: `sqd-label sqd-label-${theme}`
1238
+ });
1239
+ parent.appendChild(g);
1240
+ const nameText = Dom.svg('text', {
1241
+ class: 'sqd-label-text',
1242
+ y: y + cfg.height / 2
1243
+ });
1244
+ nameText.textContent = text;
1245
+ g.appendChild(nameText);
1246
+ const width = Math.max(nameText.getBBox().width + cfg.paddingX * 2, cfg.minWidth);
1247
+ const nameRect = Dom.svg('rect', {
1248
+ class: 'sqd-label-rect',
1249
+ width: width,
1250
+ height: cfg.height,
1251
+ x: -width / 2 + 0.5,
1252
+ y: y + 0.5,
1253
+ rx: cfg.radius,
1254
+ ry: cfg.radius
1255
+ });
1256
+ g.insertBefore(nameRect, nameText);
1257
+ return new LabelView(g, width, cfg.height);
1258
+ }
1259
+ constructor(g, width, height) {
1260
+ this.g = g;
1261
+ this.width = width;
1262
+ this.height = height;
1263
+ }
1264
+ }
1265
+
1266
+ class OutputView {
1267
+ static create(parent, x, y, size) {
1268
+ const circle = Dom.svg('circle', {
1269
+ class: 'sqd-output',
1270
+ cx: x,
1271
+ cy: y,
1272
+ r: size / 2
1273
+ });
1274
+ parent.appendChild(circle);
1275
+ return new OutputView(circle);
1276
+ }
1277
+ constructor(root) {
1278
+ this.root = root;
1279
+ }
1280
+ setIsHidden(isHidden) {
1281
+ Dom.attrs(this.root, {
1282
+ visibility: isHidden ? 'hidden' : 'visible'
1283
+ });
1284
+ }
1285
+ }
1286
+
1287
+ class RegionView {
1288
+ static create(parent, widths, height) {
1289
+ const totalWidth = widths.reduce((result, width) => result + width, 0);
1290
+ const lines = [
1291
+ drawLine(parent, 0, 0, totalWidth, 0),
1292
+ drawLine(parent, 0, 0, 0, height),
1293
+ drawLine(parent, 0, height, totalWidth, height),
1294
+ drawLine(parent, totalWidth, 0, totalWidth, height)
1295
+ ];
1296
+ let offsetX = widths[0];
1297
+ for (let i = 1; i < widths.length; i++) {
1298
+ lines.push(drawLine(parent, offsetX, 0, offsetX, height));
1299
+ offsetX += widths[i];
1300
+ }
1301
+ return new RegionView(lines, totalWidth, height);
1302
+ }
1303
+ constructor(lines, width, height) {
1304
+ this.lines = lines;
1305
+ this.width = width;
1306
+ this.height = height;
1307
+ }
1308
+ getClientPosition() {
1309
+ const rect = this.lines[0].getBoundingClientRect();
1310
+ return new Vector(rect.x, rect.y);
1311
+ }
1312
+ resolveClick(click) {
1313
+ const regionPosition = this.getClientPosition();
1314
+ const d = click.position.subtract(regionPosition);
1315
+ return d.x >= 0 && d.y >= 0 && d.x < this.width * click.scale && d.y < this.height * click.scale;
1316
+ }
1317
+ setIsSelected(isSelected) {
1318
+ this.lines.forEach(region => {
1319
+ Dom.toggleClass(region, isSelected, 'sqd-selected');
1320
+ });
1321
+ }
1322
+ }
1323
+ function drawLine(parent, x1, y1, x2, y2) {
1324
+ const line = Dom.svg('line', {
1325
+ class: 'sqd-region',
1326
+ x1,
1327
+ y1,
1328
+ x2,
1329
+ y2
1330
+ });
1331
+ parent.insertBefore(line, parent.firstChild);
1332
+ return line;
1333
+ }
1334
+
1335
+ class RectPlaceholderView {
1336
+ static create(parent, width, height, radius, iconSize, direction) {
1337
+ const g = Dom.svg('g', {
1338
+ visibility: 'hidden',
1339
+ class: 'sqd-placeholder'
1340
+ });
1341
+ parent.appendChild(g);
1342
+ const rect = Dom.svg('rect', {
1343
+ class: 'sqd-placeholder-rect',
1344
+ width,
1345
+ height,
1346
+ rx: radius,
1347
+ ry: radius
1348
+ });
1349
+ g.appendChild(rect);
1350
+ if (direction) {
1351
+ const iconD = direction === exports.PlaceholderDirection.in ? Icons.folderIn : Icons.folderOut;
1352
+ const icon = Icons.appendPath(g, 'sqd-placeholder-icon-path', iconD, iconSize);
1353
+ Dom.translate(icon, (width - iconSize) / 2, (height - iconSize) / 2);
1354
+ }
1355
+ parent.appendChild(g);
1356
+ return new RectPlaceholderView(rect, g);
1357
+ }
1358
+ constructor(rect, g) {
1359
+ this.rect = rect;
1360
+ this.g = g;
1361
+ }
1362
+ setIsHover(isHover) {
1363
+ Dom.toggleClass(this.g, isHover, 'sqd-hover');
1364
+ }
1365
+ setIsVisible(isVisible) {
1366
+ Dom.attrs(this.g, {
1367
+ visibility: isVisible ? 'visible' : 'hidden'
1368
+ });
1369
+ }
1370
+ }
1371
+
1372
+ class DefaultSequenceComponentView {
1373
+ static create(parent, sequenceContext, componentContext) {
1374
+ const phWidth = componentContext.services.placeholder.gapSize.x;
1375
+ const phHeight = componentContext.services.placeholder.gapSize.y;
1376
+ const { sequence } = sequenceContext;
1377
+ const g = Dom.svg('g');
1378
+ parent.appendChild(g);
1379
+ const components = [];
1380
+ for (let index = 0; index < sequence.length; index++) {
1381
+ const stepContext = {
1382
+ parentSequence: sequenceContext.sequence,
1383
+ step: sequence[index],
1384
+ depth: sequenceContext.depth,
1385
+ position: index,
1386
+ isInputConnected: index === 0 ? sequenceContext.isInputConnected : components[index - 1].hasOutput,
1387
+ isOutputConnected: index === sequence.length - 1 ? sequenceContext.isOutputConnected : true
1388
+ };
1389
+ components[index] = componentContext.stepComponentFactory.create(g, stepContext, componentContext);
1390
+ }
1391
+ let joinX;
1392
+ let totalWidth;
1393
+ if (components.length > 0) {
1394
+ const restWidth = Math.max(...components.map(c => c.view.width - c.view.joinX));
1395
+ joinX = Math.max(...components.map(c => c.view.joinX));
1396
+ totalWidth = joinX + restWidth;
1397
+ }
1398
+ else {
1399
+ joinX = phWidth / 2;
1400
+ totalWidth = phWidth;
1401
+ }
1402
+ let offsetY = phHeight;
1403
+ const placeholders = [];
1404
+ for (let i = 0; i < components.length; i++) {
1405
+ const component = components[i];
1406
+ const offsetX = joinX - component.view.joinX;
1407
+ if ((i === 0 && sequenceContext.isInputConnected) || (i > 0 && components[i - 1].hasOutput)) {
1408
+ JoinView.createStraightJoin(g, new Vector(joinX, offsetY - phHeight), phHeight);
1409
+ }
1410
+ if (componentContext.placeholderController.canCreate(sequence, i)) {
1411
+ const ph = componentContext.services.placeholder.createForGap(g, sequence, i);
1412
+ Dom.translate(ph.view.g, joinX - phWidth / 2, offsetY - phHeight);
1413
+ placeholders.push(ph);
1414
+ }
1415
+ Dom.translate(component.view.g, offsetX, offsetY);
1416
+ offsetY += component.view.height + phHeight;
1417
+ }
1418
+ if (sequenceContext.isOutputConnected && (components.length === 0 || components[components.length - 1].hasOutput)) {
1419
+ JoinView.createStraightJoin(g, new Vector(joinX, offsetY - phHeight), phHeight);
1420
+ }
1421
+ const newIndex = components.length;
1422
+ if (componentContext.placeholderController.canCreate(sequence, newIndex)) {
1423
+ const ph = componentContext.services.placeholder.createForGap(g, sequence, newIndex);
1424
+ Dom.translate(ph.view.g, joinX - phWidth / 2, offsetY - phHeight);
1425
+ placeholders.push(ph);
1426
+ }
1427
+ return new DefaultSequenceComponentView(g, totalWidth, offsetY, joinX, placeholders, components);
1428
+ }
1429
+ constructor(g, width, height, joinX, placeholders, components) {
1430
+ this.g = g;
1431
+ this.width = width;
1432
+ this.height = height;
1433
+ this.joinX = joinX;
1434
+ this.placeholders = placeholders;
1435
+ this.components = components;
1436
+ }
1437
+ setIsDragging(isDragging) {
1438
+ this.placeholders.forEach(placeholder => {
1439
+ placeholder.setIsVisible(isDragging);
1440
+ });
1441
+ }
1442
+ hasOutput() {
1443
+ if (this.components.length > 0) {
1444
+ return this.components[this.components.length - 1].hasOutput;
1445
+ }
1446
+ return true;
1447
+ }
1448
+ }
1449
+
1450
+ class DefaultSequenceComponent {
1451
+ static create(parentElement, sequenceContext, context) {
1452
+ const view = DefaultSequenceComponentView.create(parentElement, sequenceContext, context);
1453
+ return new DefaultSequenceComponent(view, view.hasOutput());
1454
+ }
1455
+ constructor(view, hasOutput) {
1456
+ this.view = view;
1457
+ this.hasOutput = hasOutput;
1458
+ }
1459
+ resolveClick(click) {
1460
+ for (const component of this.view.components) {
1461
+ const result = component.resolveClick(click);
1462
+ if (result) {
1463
+ return result;
1464
+ }
1465
+ }
1466
+ for (const placeholder of this.view.placeholders) {
1467
+ const result = placeholder.resolveClick(click);
1468
+ if (result) {
1469
+ return result;
1470
+ }
1471
+ }
1472
+ return null;
1473
+ }
1474
+ findById(stepId) {
1475
+ for (const component of this.view.components) {
1476
+ const sc = component.findById(stepId);
1477
+ if (sc) {
1478
+ return sc;
1479
+ }
1480
+ }
1481
+ return null;
1482
+ }
1483
+ getPlaceholders(result) {
1484
+ this.view.placeholders.forEach(placeholder => result.push(placeholder));
1485
+ this.view.components.forEach(c => c.getPlaceholders(result));
1486
+ }
1487
+ setIsDragging(isDragging) {
1488
+ this.view.setIsDragging(isDragging);
1489
+ this.view.components.forEach(c => c.setIsDragging(isDragging));
1490
+ }
1491
+ updateBadges(result) {
1492
+ for (const component of this.view.components) {
1493
+ component.updateBadges(result);
1494
+ }
1495
+ }
1496
+ }
1497
+
1498
+ const createContainerStepComponentViewFactory = (cfg) => (parentElement, stepContext, viewContext) => {
1499
+ const { step } = stepContext;
1500
+ const g = Dom.svg('g', {
1501
+ class: `sqd-step-container sqd-type-${step.type}`
1502
+ });
1503
+ parentElement.appendChild(g);
1504
+ const labelView = LabelView.create(g, cfg.paddingTop, cfg.label, step.name, 'primary');
1505
+ const sequenceComponent = viewContext.createSequenceComponent(g, step.sequence);
1506
+ const halfOfWidestElement = labelView.width / 2;
1507
+ const offsetLeft = Math.max(halfOfWidestElement - sequenceComponent.view.joinX, 0) + cfg.paddingX;
1508
+ const offsetRight = Math.max(halfOfWidestElement - (sequenceComponent.view.width - sequenceComponent.view.joinX), 0) + cfg.paddingX;
1509
+ const width = offsetLeft + sequenceComponent.view.width + offsetRight;
1510
+ const height = cfg.paddingTop + cfg.label.height + sequenceComponent.view.height;
1511
+ const joinX = sequenceComponent.view.joinX + offsetLeft;
1512
+ Dom.translate(labelView.g, joinX, 0);
1513
+ Dom.translate(sequenceComponent.view.g, offsetLeft, cfg.paddingTop + cfg.label.height);
1514
+ const iconUrl = viewContext.getStepIconUrl();
1515
+ const inputView = InputView.createRectInput(g, joinX, 0, cfg.inputSize, cfg.inputIconSize, iconUrl);
1516
+ JoinView.createStraightJoin(g, new Vector(joinX, 0), cfg.paddingTop);
1517
+ const regionView = RegionView.create(g, [width], height);
1518
+ return {
1519
+ g,
1520
+ width,
1521
+ height,
1522
+ joinX,
1523
+ placeholders: null,
1524
+ sequenceComponents: [sequenceComponent],
1525
+ getClientPosition() {
1526
+ return regionView.getClientPosition();
1527
+ },
1528
+ resolveClick(click) {
1529
+ return regionView.resolveClick(click) || g.contains(click.element) ? true : null;
1530
+ },
1531
+ setIsDragging(isDragging) {
1532
+ inputView.setIsHidden(isDragging);
1533
+ },
1534
+ setIsSelected(isSelected) {
1535
+ regionView.setIsSelected(isSelected);
1536
+ },
1537
+ setIsDisabled(isDisabled) {
1538
+ Dom.toggleClass(g, isDisabled, 'sqd-disabled');
1539
+ },
1540
+ hasOutput() {
1541
+ return sequenceComponent.hasOutput;
1542
+ }
1543
+ };
1544
+ };
1545
+
1546
+ const createSwitchStepComponentViewFactory = (cfg) => (parent, stepContext, viewContext) => {
1547
+ const { step } = stepContext;
1548
+ const g = Dom.svg('g', {
1549
+ class: `sqd-step-switch sqd-type-${step.type}`
1550
+ });
1551
+ parent.appendChild(g);
1552
+ const branchNames = Object.keys(step.branches);
1553
+ const branchComponents = branchNames.map(branchName => {
1554
+ return viewContext.createSequenceComponent(g, step.branches[branchName]);
1555
+ });
1556
+ const branchLabelViews = branchNames.map(branchName => {
1557
+ const labelY = cfg.paddingTop + cfg.nameLabel.height + cfg.connectionHeight;
1558
+ return LabelView.create(g, labelY, cfg.branchNameLabel, branchName, 'secondary');
1559
+ });
1560
+ const nameLabelView = LabelView.create(g, cfg.paddingTop, cfg.nameLabel, step.name, 'primary');
1561
+ let prevOffsetX = 0;
1562
+ const branchSizes = branchComponents.map((component, i) => {
1563
+ const halfOfWidestBranchElement = Math.max(branchLabelViews[i].width, cfg.minContainerWidth) / 2;
1564
+ const branchOffsetLeft = Math.max(halfOfWidestBranchElement - component.view.joinX, 0) + cfg.paddingX;
1565
+ const branchOffsetRight = Math.max(halfOfWidestBranchElement - (component.view.width - component.view.joinX), 0) + cfg.paddingX;
1566
+ const width = component.view.width + branchOffsetLeft + branchOffsetRight;
1567
+ const joinX = component.view.joinX + branchOffsetLeft;
1568
+ const offsetX = prevOffsetX;
1569
+ prevOffsetX += width;
1570
+ return { width, branchOffsetLeft, offsetX, joinX };
1571
+ });
1572
+ const centerBranchIndex = Math.floor(branchNames.length / 2);
1573
+ const centerBranchSize = branchSizes[centerBranchIndex];
1574
+ let joinX = centerBranchSize.offsetX;
1575
+ if (branchNames.length % 2 !== 0) {
1576
+ joinX += centerBranchSize.joinX;
1577
+ }
1578
+ const totalBranchesWidth = branchSizes.reduce((result, s) => result + s.width, 0);
1579
+ const maxBranchesHeight = Math.max(...branchComponents.map(s => s.view.height));
1580
+ const halfOfWidestSwitchElement = nameLabelView.width / 2 + cfg.paddingX;
1581
+ const switchOffsetLeft = Math.max(halfOfWidestSwitchElement - joinX, 0);
1582
+ const switchOffsetRight = Math.max(halfOfWidestSwitchElement - (totalBranchesWidth - joinX), 0);
1583
+ const viewWidth = switchOffsetLeft + totalBranchesWidth + switchOffsetRight;
1584
+ const viewHeight = maxBranchesHeight + cfg.paddingTop + cfg.nameLabel.height + cfg.branchNameLabel.height + cfg.connectionHeight * 2;
1585
+ const shiftedJoinX = switchOffsetLeft + joinX;
1586
+ Dom.translate(nameLabelView.g, shiftedJoinX, 0);
1587
+ const branchOffsetTop = cfg.paddingTop + cfg.nameLabel.height + cfg.branchNameLabel.height + cfg.connectionHeight;
1588
+ branchComponents.forEach((component, i) => {
1589
+ const branchSize = branchSizes[i];
1590
+ const branchOffsetLeft = switchOffsetLeft + branchSize.offsetX + branchSize.branchOffsetLeft;
1591
+ Dom.translate(branchLabelViews[i].g, switchOffsetLeft + branchSize.offsetX + branchSize.joinX, 0);
1592
+ Dom.translate(component.view.g, branchOffsetLeft, branchOffsetTop);
1593
+ if (component.hasOutput && stepContext.isOutputConnected) {
1594
+ const endOffsetTopOfComponent = cfg.paddingTop + cfg.nameLabel.height + cfg.branchNameLabel.height + cfg.connectionHeight + component.view.height;
1595
+ const missingHeight = viewHeight - endOffsetTopOfComponent - cfg.connectionHeight;
1596
+ if (missingHeight > 0) {
1597
+ JoinView.createStraightJoin(g, new Vector(switchOffsetLeft + branchSize.offsetX + branchSize.joinX, endOffsetTopOfComponent), missingHeight);
1598
+ }
1599
+ }
1600
+ });
1601
+ let inputView = null;
1602
+ if (cfg.inputSize > 0) {
1603
+ const iconUrl = viewContext.getStepIconUrl();
1604
+ inputView = InputView.createRectInput(g, shiftedJoinX, 0, cfg.inputSize, cfg.inputIconSize, iconUrl);
1605
+ }
1606
+ JoinView.createStraightJoin(g, new Vector(shiftedJoinX, 0), cfg.paddingTop);
1607
+ JoinView.createJoins(g, new Vector(shiftedJoinX, cfg.paddingTop + cfg.nameLabel.height), branchSizes.map(o => new Vector(switchOffsetLeft + o.offsetX + o.joinX, cfg.paddingTop + cfg.nameLabel.height + cfg.connectionHeight)));
1608
+ if (stepContext.isOutputConnected) {
1609
+ const ongoingSequenceIndexes = branchComponents
1610
+ .map((component, index) => (component.hasOutput ? index : null))
1611
+ .filter(index => index !== null);
1612
+ const ongoingJoinTargets = ongoingSequenceIndexes.map((i) => new Vector(switchOffsetLeft + branchSizes[i].offsetX + branchSizes[i].joinX, cfg.paddingTop + cfg.connectionHeight + cfg.nameLabel.height + cfg.branchNameLabel.height + maxBranchesHeight));
1613
+ if (ongoingJoinTargets.length > 0) {
1614
+ JoinView.createJoins(g, new Vector(shiftedJoinX, viewHeight), ongoingJoinTargets);
1615
+ }
1616
+ }
1617
+ const regions = branchSizes.map(s => s.width);
1618
+ regions[0] += switchOffsetLeft;
1619
+ regions[regions.length - 1] += switchOffsetRight;
1620
+ const regionView = RegionView.create(g, regions, viewHeight);
1621
+ return {
1622
+ g,
1623
+ width: viewWidth,
1624
+ height: viewHeight,
1625
+ joinX: shiftedJoinX,
1626
+ placeholders: null,
1627
+ sequenceComponents: branchComponents,
1628
+ getClientPosition() {
1629
+ return regionView.getClientPosition();
1630
+ },
1631
+ resolveClick(click) {
1632
+ return regionView.resolveClick(click) || g.contains(click.element) ? true : null;
1633
+ },
1634
+ setIsDragging(isDragging) {
1635
+ inputView === null || inputView === void 0 ? void 0 : inputView.setIsHidden(isDragging);
1636
+ },
1637
+ setIsSelected(isSelected) {
1638
+ regionView.setIsSelected(isSelected);
1639
+ },
1640
+ setIsDisabled(isDisabled) {
1641
+ Dom.toggleClass(g, isDisabled, 'sqd-disabled');
1642
+ },
1643
+ hasOutput() {
1644
+ return branchComponents.some(c => c.hasOutput);
1645
+ }
1646
+ };
1647
+ };
1648
+
1649
+ const createTaskStepComponentViewFactory = (isInterrupted, cfg) => (parentElement, stepContext, viewContext) => {
1650
+ const { step } = stepContext;
1651
+ const g = Dom.svg('g', {
1652
+ class: `sqd-step-task sqd-type-${step.type}`
1653
+ });
1654
+ parentElement.appendChild(g);
1655
+ const boxHeight = cfg.paddingY * 2 + cfg.iconSize;
1656
+ const text = Dom.svg('text', {
1657
+ x: cfg.paddingLeft + cfg.iconSize + cfg.textMarginLeft,
1658
+ y: boxHeight / 2,
1659
+ class: 'sqd-step-task-text'
1660
+ });
1661
+ text.textContent = step.name;
1662
+ g.appendChild(text);
1663
+ const textWidth = Math.max(text.getBBox().width, cfg.minTextWidth);
1664
+ const boxWidth = cfg.iconSize + cfg.paddingLeft + cfg.paddingRight + cfg.textMarginLeft + textWidth;
1665
+ const rect = Dom.svg('rect', {
1666
+ x: 0.5,
1667
+ y: 0.5,
1668
+ class: 'sqd-step-task-rect',
1669
+ width: boxWidth,
1670
+ height: boxHeight,
1671
+ rx: cfg.radius,
1672
+ ry: cfg.radius
1673
+ });
1674
+ g.insertBefore(rect, text);
1675
+ const iconUrl = viewContext.getStepIconUrl();
1676
+ const icon = iconUrl
1677
+ ? Dom.svg('image', {
1678
+ href: iconUrl
1679
+ })
1680
+ : Dom.svg('rect', {
1681
+ class: 'sqd-step-task-empty-icon',
1682
+ rx: cfg.radius,
1683
+ ry: cfg.radius
1684
+ });
1685
+ Dom.attrs(icon, {
1686
+ x: cfg.paddingLeft,
1687
+ y: cfg.paddingY,
1688
+ width: cfg.iconSize,
1689
+ height: cfg.iconSize
1690
+ });
1691
+ g.appendChild(icon);
1692
+ const isInputViewHidden = stepContext.depth === 0 && stepContext.position === 0 && !stepContext.isInputConnected;
1693
+ const isOutputViewHidden = isInterrupted;
1694
+ const inputView = isInputViewHidden ? null : InputView.createRoundInput(g, boxWidth / 2, 0, cfg.inputSize);
1695
+ const outputView = isOutputViewHidden ? null : OutputView.create(g, boxWidth / 2, boxHeight, cfg.outputSize);
1696
+ return {
1697
+ g,
1698
+ width: boxWidth,
1699
+ height: boxHeight,
1700
+ joinX: boxWidth / 2,
1701
+ sequenceComponents: null,
1702
+ placeholders: null,
1703
+ hasOutput() {
1704
+ return !!outputView;
1705
+ },
1706
+ getClientPosition() {
1707
+ const r = rect.getBoundingClientRect();
1708
+ return new Vector(r.x, r.y);
1709
+ },
1710
+ resolveClick(click) {
1711
+ return g.contains(click.element) ? true : null;
1712
+ },
1713
+ setIsDragging(isDragging) {
1714
+ inputView === null || inputView === void 0 ? void 0 : inputView.setIsHidden(isDragging);
1715
+ outputView === null || outputView === void 0 ? void 0 : outputView.setIsHidden(isDragging);
1716
+ },
1717
+ setIsDisabled(isDisabled) {
1718
+ Dom.toggleClass(g, isDisabled, 'sqd-disabled');
1719
+ },
1720
+ setIsSelected(isSelected) {
1721
+ Dom.toggleClass(rect, isSelected, 'sqd-selected');
1722
+ }
1723
+ };
1724
+ };
1725
+
1726
+ class CenteredViewportCalculator {
1727
+ static center(margin, canvasSize, rootComponentSize) {
1728
+ const canvasSafeWidth = Math.max(canvasSize.x - margin * 2, 0);
1729
+ const canvasSafeHeight = Math.max(canvasSize.y - margin * 2, 0);
1730
+ const scale = Math.min(Math.min(canvasSafeWidth / rootComponentSize.x, canvasSafeHeight / rootComponentSize.y), 1);
1731
+ const width = rootComponentSize.x * scale;
1732
+ const height = rootComponentSize.y * scale;
1733
+ const x = Math.max(0, (canvasSize.x - width) / 2);
1734
+ const y = Math.max(0, (canvasSize.y - height) / 2);
1735
+ return {
1736
+ position: new Vector(x, y),
1737
+ scale
1738
+ };
1739
+ }
1740
+ static focusOnComponent(canvasSize, viewport, componentPosition, componentSize) {
1741
+ const realPosition = viewport.position.divideByScalar(viewport.scale).subtract(componentPosition.divideByScalar(viewport.scale));
1742
+ const componentOffset = componentSize.divideByScalar(2);
1743
+ const position = realPosition.add(canvasSize.divideByScalar(2)).subtract(componentOffset);
1744
+ return { position, scale: 1 };
1745
+ }
1746
+ }
1747
+
1748
+ class NextQuantifiedNumber {
1749
+ constructor(values) {
1750
+ this.values = values;
1751
+ }
1752
+ next(value, direction) {
1753
+ let bestIndex = 0;
1754
+ let bestDistance = Number.MAX_VALUE;
1755
+ for (let i = 0; i < this.values.length; i++) {
1756
+ const distance = Math.abs(this.values[i] - value);
1757
+ if (bestDistance > distance) {
1758
+ bestIndex = i;
1759
+ bestDistance = distance;
1760
+ }
1761
+ }
1762
+ let index;
1763
+ if (direction) {
1764
+ index = Math.min(bestIndex + 1, this.values.length - 1);
1765
+ }
1766
+ else {
1767
+ index = Math.max(bestIndex - 1, 0);
1768
+ }
1769
+ return {
1770
+ current: this.values[bestIndex],
1771
+ next: this.values[index]
1772
+ };
1773
+ }
1774
+ }
1775
+
1776
+ const SCALES = [0.06, 0.08, 0.1, 0.12, 0.16, 0.2, 0.26, 0.32, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
1777
+ const MAX_DELTA_Y = 16;
1778
+ const quantifiedScale = new NextQuantifiedNumber(SCALES);
1779
+ class QuantifiedScaleViewportCalculator {
1780
+ static zoom(current, direction) {
1781
+ const nextScale = quantifiedScale.next(current.scale, direction);
1782
+ return {
1783
+ position: current.position,
1784
+ scale: nextScale.next
1785
+ };
1786
+ }
1787
+ static zoomByWheel(current, e, canvasPosition) {
1788
+ if (e.deltaY === 0) {
1789
+ return null;
1790
+ }
1791
+ const nextScale = quantifiedScale.next(current.scale, e.deltaY < 0);
1792
+ let scale;
1793
+ const absDeltaY = Math.abs(e.deltaY);
1794
+ if (absDeltaY < MAX_DELTA_Y) {
1795
+ const fraction = absDeltaY / MAX_DELTA_Y;
1796
+ const step = nextScale.next - nextScale.current;
1797
+ scale = current.scale + step * fraction;
1798
+ }
1799
+ else {
1800
+ scale = nextScale.next;
1801
+ }
1802
+ const mousePoint = new Vector(e.pageX, e.pageY).subtract(canvasPosition);
1803
+ // The real point is point on canvas with no scale.
1804
+ const mouseRealPoint = mousePoint.divideByScalar(current.scale).subtract(current.position.divideByScalar(current.scale));
1805
+ const position = mouseRealPoint.multiplyByScalar(-scale).add(mousePoint);
1806
+ return { position, scale };
1807
+ }
1808
+ }
1809
+
1810
+ class ClassicWheelController {
1811
+ static create(api) {
1812
+ return new ClassicWheelController(api);
1813
+ }
1814
+ constructor(api) {
1815
+ this.api = api;
1816
+ }
1817
+ onWheel(e) {
1818
+ const viewport = this.api.getViewport();
1819
+ const canvasPosition = this.api.getCanvasPosition();
1820
+ const newViewport = QuantifiedScaleViewportCalculator.zoomByWheel(viewport, e, canvasPosition);
1821
+ if (newViewport) {
1822
+ this.api.setViewport(newViewport);
1823
+ }
1824
+ }
1825
+ }
1826
+
1827
+ class ClassicWheelControllerExtension {
1828
+ constructor() {
1829
+ this.create = ClassicWheelController.create;
1830
+ }
1831
+ }
1832
+
1833
+ function animate(interval, handler) {
1834
+ const iv = setInterval(tick, 15);
1835
+ const startTime = Date.now();
1836
+ const anim = {
1837
+ isAlive: true,
1838
+ stop: () => {
1839
+ anim.isAlive = false;
1840
+ clearInterval(iv);
1841
+ }
1842
+ };
1843
+ function tick() {
1844
+ const progress = Math.min((Date.now() - startTime) / interval, 1);
1845
+ handler(progress);
1846
+ if (progress === 1) {
1847
+ anim.stop();
1848
+ }
1849
+ }
1850
+ return anim;
1851
+ }
1852
+
1853
+ class ViewportAnimator {
1854
+ constructor(api) {
1855
+ this.api = api;
1856
+ }
1857
+ execute(target) {
1858
+ if (this.animation && this.animation.isAlive) {
1859
+ this.animation.stop();
1860
+ }
1861
+ const viewport = this.api.getViewport();
1862
+ const startPosition = viewport.position;
1863
+ const startScale = viewport.scale;
1864
+ const deltaPosition = startPosition.subtract(target.position);
1865
+ const deltaScale = startScale - target.scale;
1866
+ this.animation = animate(150, progress => {
1867
+ const newScale = startScale - deltaScale * progress;
1868
+ this.api.setViewport({
1869
+ position: startPosition.subtract(deltaPosition.multiplyByScalar(progress)),
1870
+ scale: newScale
1871
+ });
1872
+ });
1873
+ }
1874
+ }
1875
+
1876
+ const CENTER_MARGIN = 10;
1877
+ class DefaultViewportController {
1878
+ static create(api) {
1879
+ return new DefaultViewportController(api);
1880
+ }
1881
+ constructor(api) {
1882
+ this.api = api;
1883
+ this.animator = new ViewportAnimator(this.api);
1884
+ }
1885
+ setDefault() {
1886
+ const rootComponentSize = this.api.getRootComponentSize();
1887
+ const canvasSize = this.api.getCanvasSize();
1888
+ const target = CenteredViewportCalculator.center(CENTER_MARGIN, canvasSize, rootComponentSize);
1889
+ this.api.setViewport(target);
1890
+ }
1891
+ zoom(direction) {
1892
+ const viewport = this.api.getViewport();
1893
+ const target = QuantifiedScaleViewportCalculator.zoom(viewport, direction);
1894
+ this.api.setViewport(target);
1895
+ }
1896
+ focusOnComponent(componentPosition, componentSize) {
1897
+ const viewport = this.api.getViewport();
1898
+ const canvasSize = this.api.getCanvasSize();
1899
+ const target = CenteredViewportCalculator.focusOnComponent(canvasSize, viewport, componentPosition, componentSize);
1900
+ this.animateTo(target);
1901
+ }
1902
+ animateTo(viewport) {
1903
+ this.animator.execute(viewport);
1904
+ }
1905
+ }
1906
+
1907
+ class DefaultViewportControllerExtension {
1908
+ constructor() {
1909
+ this.create = DefaultViewportController.create;
1910
+ }
1911
+ }
1912
+
1913
+ class StepExtensionResolver {
1914
+ static create(services) {
1915
+ const dict = {};
1916
+ for (let i = services.steps.length - 1; i >= 0; i--) {
1917
+ const extension = services.steps[i];
1918
+ dict[extension.componentType] = extension;
1919
+ }
1920
+ return new StepExtensionResolver(dict);
1921
+ }
1922
+ constructor(dict) {
1923
+ this.dict = dict;
1924
+ }
1925
+ resolve(componentType) {
1926
+ const extension = this.dict[componentType];
1927
+ if (!extension) {
1928
+ throw new Error(`Not supported component type: ${componentType}`);
1929
+ }
1930
+ return extension;
1931
+ }
1932
+ }
1933
+
1934
+ class RectPlaceholder {
1935
+ static create(parent, size, direction, sequence, index, configuration) {
1936
+ const view = RectPlaceholderView.create(parent, size.x, size.y, configuration.radius, configuration.iconSize, direction);
1937
+ return new RectPlaceholder(view, sequence, index);
1938
+ }
1939
+ constructor(view, parentSequence, index) {
1940
+ this.view = view;
1941
+ this.parentSequence = parentSequence;
1942
+ this.index = index;
1943
+ }
1944
+ getClientRect() {
1945
+ return this.view.rect.getBoundingClientRect();
1946
+ }
1947
+ setIsHover(isHover) {
1948
+ this.view.setIsHover(isHover);
1949
+ }
1950
+ setIsVisible(isVisible) {
1951
+ this.view.setIsVisible(isVisible);
1952
+ }
1953
+ resolveClick() {
1954
+ return null;
1955
+ }
1956
+ }
1957
+
1958
+ function readMousePosition(e) {
1959
+ return new Vector(e.pageX, e.pageY);
1960
+ }
1961
+ function readTouchClientPosition(e) {
1962
+ if (e.touches.length > 0) {
1963
+ const touch = e.touches[0];
1964
+ return new Vector(touch.clientX, touch.clientY);
1965
+ }
1966
+ throw new Error('Unknown touch position');
1967
+ }
1968
+ function readTouchPosition(e) {
1969
+ if (e.touches.length > 0) {
1970
+ const touch = e.touches[0];
1971
+ return new Vector(touch.pageX, touch.pageY);
1972
+ }
1973
+ throw new Error('Unknown touch position');
1974
+ }
1975
+
1976
+ const notInitializedError = 'State is not initialized';
1977
+ const nonPassiveOptions = {
1978
+ passive: false
1979
+ };
1980
+ class BehaviorController {
1981
+ constructor() {
1982
+ this.onMouseMove = (e) => {
1983
+ e.preventDefault();
1984
+ this.move(readMousePosition(e));
1985
+ };
1986
+ this.onTouchMove = (e) => {
1987
+ e.preventDefault();
1988
+ this.move(readTouchPosition(e));
1989
+ };
1990
+ this.onMouseUp = (e) => {
1991
+ e.preventDefault();
1992
+ this.stop(false, e.target);
1993
+ };
1994
+ this.onTouchEnd = (e) => {
1995
+ var _a;
1996
+ e.preventDefault();
1997
+ if (!this.state) {
1998
+ throw new Error(notInitializedError);
1999
+ }
2000
+ const position = (_a = this.state.lastPosition) !== null && _a !== void 0 ? _a : this.state.startPosition;
2001
+ const element = document.elementFromPoint(position.x, position.y);
2002
+ this.stop(false, element);
2003
+ };
2004
+ this.onTouchStart = (e) => {
2005
+ e.preventDefault();
2006
+ if (e.touches.length !== 1) {
2007
+ this.stop(true, null);
2008
+ }
2009
+ };
2010
+ }
2011
+ start(startPosition, behavior) {
2012
+ if (this.state) {
2013
+ this.stop(true, null);
2014
+ return;
2015
+ }
2016
+ this.state = {
2017
+ startPosition,
2018
+ behavior
2019
+ };
2020
+ behavior.onStart(this.state.startPosition);
2021
+ window.addEventListener('mousemove', this.onMouseMove, false);
2022
+ window.addEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
2023
+ window.addEventListener('mouseup', this.onMouseUp, false);
2024
+ window.addEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
2025
+ window.addEventListener('touchstart', this.onTouchStart, nonPassiveOptions);
2026
+ }
2027
+ move(position) {
2028
+ if (!this.state) {
2029
+ throw new Error(notInitializedError);
2030
+ }
2031
+ this.state.lastPosition = position;
2032
+ const delta = this.state.startPosition.subtract(position);
2033
+ const newBehavior = this.state.behavior.onMove(delta);
2034
+ if (newBehavior) {
2035
+ this.state.behavior.onEnd(true, null);
2036
+ this.state.behavior = newBehavior;
2037
+ this.state.startPosition = position;
2038
+ this.state.behavior.onStart(this.state.startPosition);
2039
+ }
2040
+ }
2041
+ stop(interrupt, element) {
2042
+ if (!this.state) {
2043
+ throw new Error(notInitializedError);
2044
+ }
2045
+ window.removeEventListener('mousemove', this.onMouseMove, false);
2046
+ window.removeEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
2047
+ window.removeEventListener('mouseup', this.onMouseUp, false);
2048
+ window.removeEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
2049
+ window.removeEventListener('touchstart', this.onTouchStart, nonPassiveOptions);
2050
+ this.state.behavior.onEnd(interrupt, element);
2051
+ this.state = undefined;
2052
+ }
2053
+ }
2054
+
2055
+ class SequenceModifier {
2056
+ static tryMoveStep(sourceSequence, step, targetSequence, targetIndex) {
2057
+ const sourceIndex = sourceSequence.indexOf(step);
2058
+ if (sourceIndex < 0) {
2059
+ throw new Error('Step not found in source sequence');
2060
+ }
2061
+ const isSameSequence = sourceSequence === targetSequence;
2062
+ if (isSameSequence) {
2063
+ if (sourceIndex < targetIndex) {
2064
+ targetIndex--;
2065
+ }
2066
+ if (sourceIndex === targetIndex) {
2067
+ return null; // No changes
2068
+ }
2069
+ }
2070
+ return function apply() {
2071
+ sourceSequence.splice(sourceIndex, 1);
2072
+ targetSequence.splice(targetIndex, 0, step);
2073
+ };
2074
+ }
2075
+ static insertStep(step, targetSequence, targetIndex) {
2076
+ targetSequence.splice(targetIndex, 0, step);
2077
+ }
2078
+ static deleteStep(step, parentSequence) {
2079
+ const index = parentSequence.indexOf(step);
2080
+ if (index < 0) {
2081
+ throw new Error('Unknown step');
2082
+ }
2083
+ parentSequence.splice(index, 1);
2084
+ }
2085
+ }
2086
+
2087
+ class StepDuplicator {
2088
+ constructor(uidGenerator, definitionWalker) {
2089
+ this.uidGenerator = uidGenerator;
2090
+ this.definitionWalker = definitionWalker;
2091
+ }
2092
+ duplicate(step) {
2093
+ const newStep = ObjectCloner.deepClone(step);
2094
+ newStep.id = this.uidGenerator();
2095
+ this.definitionWalker.forEachChildren(newStep, s => {
2096
+ s.id = this.uidGenerator();
2097
+ });
2098
+ return newStep;
2099
+ }
2100
+ }
2101
+
2102
+ class DefinitionModifier {
2103
+ constructor(definitionWalker, state, configuration) {
2104
+ this.definitionWalker = definitionWalker;
2105
+ this.state = state;
2106
+ this.configuration = configuration;
2107
+ }
2108
+ isDeletable(stepId) {
2109
+ if (this.configuration.steps.isDeletable) {
2110
+ const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2111
+ return this.configuration.steps.isDeletable(result.step, result.parentSequence);
2112
+ }
2113
+ return true;
2114
+ }
2115
+ tryDelete(stepId) {
2116
+ const result = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2117
+ const canDeleteStep = this.configuration.steps.canDeleteStep
2118
+ ? this.configuration.steps.canDeleteStep(result.step, result.parentSequence)
2119
+ : true;
2120
+ if (!canDeleteStep) {
2121
+ return false;
2122
+ }
2123
+ SequenceModifier.deleteStep(result.step, result.parentSequence);
2124
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepDeleted, result.step.id);
2125
+ this.updateDependantFields();
2126
+ return true;
2127
+ }
2128
+ tryInsert(step, targetSequence, targetIndex) {
2129
+ const canInsertStep = this.configuration.steps.canInsertStep
2130
+ ? this.configuration.steps.canInsertStep(step, targetSequence, targetIndex)
2131
+ : true;
2132
+ if (!canInsertStep) {
2133
+ return false;
2134
+ }
2135
+ SequenceModifier.insertStep(step, targetSequence, targetIndex);
2136
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepInserted, step.id);
2137
+ this.state.setSelectedStepId(step.id);
2138
+ return true;
2139
+ }
2140
+ isDraggable(step, parentSequence) {
2141
+ return this.configuration.steps.isDraggable ? this.configuration.steps.isDraggable(step, parentSequence) : true;
2142
+ }
2143
+ tryMove(sourceSequence, step, targetSequence, targetIndex) {
2144
+ const apply = SequenceModifier.tryMoveStep(sourceSequence, step, targetSequence, targetIndex);
2145
+ if (!apply) {
2146
+ return false;
2147
+ }
2148
+ const canMoveStep = this.configuration.steps.canMoveStep
2149
+ ? this.configuration.steps.canMoveStep(sourceSequence, step, targetSequence, targetIndex)
2150
+ : true;
2151
+ if (!canMoveStep) {
2152
+ return false;
2153
+ }
2154
+ apply();
2155
+ this.state.notifyDefinitionChanged(exports.DefinitionChangeType.stepMoved, step.id);
2156
+ this.state.setSelectedStepId(step.id);
2157
+ return true;
2158
+ }
2159
+ isDuplicable(step, parentSequence) {
2160
+ return this.configuration.steps.isDuplicable ? this.configuration.steps.isDuplicable(step, parentSequence) : false;
2161
+ }
2162
+ tryDuplicate(step, parentSequence) {
2163
+ const uidGenerator = this.configuration.uidGenerator ? this.configuration.uidGenerator : Uid.next;
2164
+ const duplicator = new StepDuplicator(uidGenerator, this.definitionWalker);
2165
+ const index = parentSequence.indexOf(step);
2166
+ const newStep = duplicator.duplicate(step);
2167
+ return this.tryInsert(newStep, parentSequence, index + 1);
2168
+ }
2169
+ replaceDefinition(definition) {
2170
+ if (!definition) {
2171
+ throw new Error('Definition is empty');
2172
+ }
2173
+ this.state.setDefinition(definition);
2174
+ this.updateDependantFields();
2175
+ }
2176
+ updateDependantFields() {
2177
+ if (this.state.selectedStepId) {
2178
+ const found = this.definitionWalker.findById(this.state.definition, this.state.selectedStepId);
2179
+ if (!found) {
2180
+ // We need to unselect step when it's deleted.
2181
+ this.state.setSelectedStepId(null);
2182
+ }
2183
+ }
2184
+ for (let index = 0; index < this.state.folderPath.length; index++) {
2185
+ const stepId = this.state.folderPath[index];
2186
+ const found = this.definitionWalker.findById(this.state.definition, stepId);
2187
+ if (!found) {
2188
+ // We need to update path if any folder is deleted.
2189
+ const newPath = this.state.folderPath.slice(0, index);
2190
+ this.state.setFolderPath(newPath);
2191
+ break;
2192
+ }
2193
+ }
2194
+ }
2195
+ }
2196
+
2197
+ class HistoryController {
2198
+ static create(state, definitionModifier, configuration) {
2199
+ if (!configuration.undoStackSize || configuration.undoStackSize < 1) {
2200
+ throw new Error('Invalid undo stack size');
2201
+ }
2202
+ const controller = new HistoryController(state, definitionModifier, configuration.undoStackSize);
2203
+ controller.remember(exports.DefinitionChangeType.rootReplaced, null);
2204
+ state.onDefinitionChanged.subscribe(event => {
2205
+ if (event.changeType !== exports.DefinitionChangeType.rootReplaced) {
2206
+ controller.remember(event.changeType, event.stepId);
2207
+ }
2208
+ });
2209
+ return controller;
2210
+ }
2211
+ constructor(state, definitionModifier, stackSize) {
2212
+ this.state = state;
2213
+ this.definitionModifier = definitionModifier;
2214
+ this.stackSize = stackSize;
2215
+ this.stack = [];
2216
+ this.currentIndex = 0;
2217
+ }
2218
+ canUndo() {
2219
+ return this.currentIndex > 1;
2220
+ }
2221
+ undo() {
2222
+ this.currentIndex--;
2223
+ this.commit();
2224
+ }
2225
+ canRedo() {
2226
+ return this.currentIndex < this.stack.length;
2227
+ }
2228
+ redo() {
2229
+ this.currentIndex++;
2230
+ this.commit();
2231
+ }
2232
+ remember(changeType, stepId) {
2233
+ const definition = ObjectCloner.deepClone(this.state.definition);
2234
+ if (this.stack.length > 0 && this.currentIndex === this.stack.length) {
2235
+ const lastItem = this.stack[this.stack.length - 1];
2236
+ if (areItemsEqual(lastItem, changeType, stepId)) {
2237
+ lastItem.definition = definition;
2238
+ return;
2239
+ }
2240
+ }
2241
+ this.stack.splice(this.currentIndex);
2242
+ this.stack.push({
2243
+ definition,
2244
+ changeType,
2245
+ stepId
2246
+ });
2247
+ if (this.stack.length > this.stackSize) {
2248
+ this.stack.splice(0, this.stack.length - this.stackSize - 1);
2249
+ }
2250
+ this.currentIndex = this.stack.length;
2251
+ }
2252
+ commit() {
2253
+ const definition = ObjectCloner.deepClone(this.stack[this.currentIndex - 1].definition);
2254
+ this.definitionModifier.replaceDefinition(definition);
2255
+ }
2256
+ }
2257
+ function areItemsEqual(item, changeType, stepId) {
2258
+ return item.changeType === changeType && item.stepId === stepId;
2259
+ }
2260
+
2261
+ class LayoutController {
2262
+ constructor(parent) {
2263
+ this.parent = parent;
2264
+ }
2265
+ isMobile() {
2266
+ return this.parent.clientWidth < 400; // TODO
2267
+ }
2268
+ }
2269
+
2270
+ class WorkspaceControllerWrapper {
2271
+ set(controller) {
2272
+ if (this.controller) {
2273
+ throw new Error('Controller is already set');
2274
+ }
2275
+ this.controller = controller;
2276
+ }
2277
+ get() {
2278
+ if (!this.controller) {
2279
+ throw new Error('Controller is not set');
2280
+ }
2281
+ return this.controller;
2282
+ }
2283
+ getPlaceholders() {
2284
+ return this.get().getPlaceholders();
2285
+ }
2286
+ getComponentByStepId(stepId) {
2287
+ return this.get().getComponentByStepId(stepId);
2288
+ }
2289
+ getCanvasPosition() {
2290
+ return this.get().getCanvasPosition();
2291
+ }
2292
+ getCanvasSize() {
2293
+ return this.get().getCanvasSize();
2294
+ }
2295
+ getRootComponentSize() {
2296
+ return this.get().getRootComponentSize();
2297
+ }
2298
+ updateBadges() {
2299
+ this.get().updateBadges();
2300
+ }
2301
+ updateRootComponent() {
2302
+ this.get().updateRootComponent();
2303
+ }
2304
+ updateCanvasSize() {
2305
+ this.get().updateCanvasSize();
2306
+ }
2307
+ }
2308
+
2309
+ class DesignerContext {
2310
+ static create(parent, startDefinition, configuration, services) {
2311
+ var _a, _b, _c;
2312
+ const definition = ObjectCloner.deepClone(startDefinition);
2313
+ const layoutController = new LayoutController(parent);
2314
+ const isReadonly = !!configuration.isReadonly;
2315
+ const isToolboxCollapsed = configuration.toolbox ? (_a = configuration.toolbox.isCollapsed) !== null && _a !== void 0 ? _a : layoutController.isMobile() : false;
2316
+ const isEditorCollapsed = configuration.editors ? (_b = configuration.editors.isCollapsed) !== null && _b !== void 0 ? _b : layoutController.isMobile() : false;
2317
+ const theme = configuration.theme || 'light';
2318
+ const state = new DesignerState(definition, isReadonly, isToolboxCollapsed, isEditorCollapsed);
2319
+ const workspaceController = new WorkspaceControllerWrapper();
2320
+ const behaviorController = new BehaviorController();
2321
+ const stepExtensionResolver = StepExtensionResolver.create(services);
2322
+ const definitionWalker = (_c = configuration.definitionWalker) !== null && _c !== void 0 ? _c : new sequentialWorkflowModel.DefinitionWalker();
2323
+ const definitionModifier = new DefinitionModifier(definitionWalker, state, configuration);
2324
+ let historyController = undefined;
2325
+ if (configuration.undoStackSize) {
2326
+ historyController = HistoryController.create(state, definitionModifier, configuration);
2327
+ }
2328
+ const componentContext = ComponentContext.create(configuration.steps, configuration.validator, state, stepExtensionResolver, services);
2329
+ return new DesignerContext(theme, state, configuration, services, componentContext, definitionWalker, definitionModifier, layoutController, workspaceController, behaviorController, historyController);
2330
+ }
2331
+ constructor(theme, state, configuration, services, componentContext, definitionWalker, definitionModifier, layoutController, workspaceController, behaviorController, historyController) {
2332
+ this.theme = theme;
2333
+ this.state = state;
2334
+ this.configuration = configuration;
2335
+ this.services = services;
2336
+ this.componentContext = componentContext;
2337
+ this.definitionWalker = definitionWalker;
2338
+ this.definitionModifier = definitionModifier;
2339
+ this.layoutController = layoutController;
2340
+ this.workspaceController = workspaceController;
2341
+ this.behaviorController = behaviorController;
2342
+ this.historyController = historyController;
2343
+ }
2344
+ setWorkspaceController(controller) {
2345
+ this.workspaceController.set(controller);
2346
+ }
2347
+ }
2348
+
2349
+ function isElementAttached(element) {
2350
+ return !(document.compareDocumentPosition(element) & Node.DOCUMENT_POSITION_DISCONNECTED);
2351
+ }
2352
+
2353
+ let lastGridPatternId = 0;
2354
+ class WorkspaceView {
2355
+ static create(parent, componentContext) {
2356
+ const patternId = 'sqd-grid-pattern-' + lastGridPatternId++;
2357
+ const pattern = Dom.svg('pattern', {
2358
+ id: patternId,
2359
+ patternUnits: 'userSpaceOnUse'
2360
+ });
2361
+ const gridPattern = componentContext.services.grid.create();
2362
+ const defs = Dom.svg('defs');
2363
+ pattern.appendChild(gridPattern.element);
2364
+ defs.appendChild(pattern);
2365
+ const foreground = Dom.svg('g');
2366
+ const workspace = Dom.element('div', {
2367
+ class: 'sqd-workspace'
2368
+ });
2369
+ const canvas = Dom.svg('svg', {
2370
+ class: 'sqd-workspace-canvas'
2371
+ });
2372
+ canvas.appendChild(defs);
2373
+ canvas.appendChild(Dom.svg('rect', {
2374
+ width: '100%',
2375
+ height: '100%',
2376
+ fill: `url(#${patternId})`
2377
+ }));
2378
+ canvas.appendChild(foreground);
2379
+ workspace.appendChild(canvas);
2380
+ parent.appendChild(workspace);
2381
+ const view = new WorkspaceView(workspace, canvas, pattern, gridPattern, foreground, componentContext);
2382
+ window.addEventListener('resize', view.onResizeHandler, false);
2383
+ return view;
2384
+ }
2385
+ constructor(workspace, canvas, pattern, gridPattern, foreground, context) {
2386
+ this.workspace = workspace;
2387
+ this.canvas = canvas;
2388
+ this.pattern = pattern;
2389
+ this.gridPattern = gridPattern;
2390
+ this.foreground = foreground;
2391
+ this.context = context;
2392
+ this.onResizeHandler = () => this.onResize();
2393
+ }
2394
+ render(sequence, parentSequencePlaceIndicator) {
2395
+ if (this.rootComponent) {
2396
+ this.foreground.removeChild(this.rootComponent.view.g);
2397
+ }
2398
+ this.rootComponent = this.context.services.rootComponent.create(this.foreground, sequence, parentSequencePlaceIndicator, this.context);
2399
+ this.refreshSize();
2400
+ }
2401
+ setPositionAndScale(position, scale) {
2402
+ const scaledSize = this.gridPattern.size.multiplyByScalar(scale);
2403
+ Dom.attrs(this.pattern, {
2404
+ x: position.x,
2405
+ y: position.y,
2406
+ width: scaledSize.x,
2407
+ height: scaledSize.y
2408
+ });
2409
+ this.gridPattern.setScale(scale, scaledSize);
2410
+ Dom.attrs(this.foreground, {
2411
+ transform: `translate(${position.x}, ${position.y}) scale(${scale})`
2412
+ });
2413
+ }
2414
+ getCanvasPosition() {
2415
+ const rect = this.canvas.getBoundingClientRect();
2416
+ return new Vector(rect.x + window.scrollX, rect.y + window.scrollY);
2417
+ }
2418
+ getCanvasSize() {
2419
+ return new Vector(this.canvas.clientWidth, this.canvas.clientHeight);
2420
+ }
2421
+ bindClick(handler) {
2422
+ this.canvas.addEventListener('mousedown', e => {
2423
+ e.preventDefault();
2424
+ handler(readMousePosition(e), e.target, e.button);
2425
+ }, false);
2426
+ this.canvas.addEventListener('touchstart', e => {
2427
+ e.preventDefault();
2428
+ const clientPosition = readTouchClientPosition(e);
2429
+ const element = document.elementFromPoint(clientPosition.x, clientPosition.y);
2430
+ if (element) {
2431
+ const position = readTouchPosition(e);
2432
+ handler(position, element, 0);
2433
+ }
2434
+ }, { passive: false });
2435
+ }
2436
+ bindContextMenu(handler) {
2437
+ this.canvas.addEventListener('contextmenu', e => {
2438
+ e.preventDefault();
2439
+ handler(readMousePosition(e), e.target);
2440
+ }, false);
2441
+ }
2442
+ bindWheel(handler) {
2443
+ this.canvas.addEventListener('wheel', handler, false);
2444
+ }
2445
+ destroy() {
2446
+ window.removeEventListener('resize', this.onResizeHandler, false);
2447
+ }
2448
+ refreshSize() {
2449
+ Dom.attrs(this.canvas, {
2450
+ width: this.workspace.offsetWidth,
2451
+ height: this.workspace.offsetHeight
2452
+ });
2453
+ }
2454
+ onResize() {
2455
+ this.refreshSize();
2456
+ }
2457
+ }
2458
+
2459
+ class MoveViewportBehavior {
2460
+ static create(state, resetSelectedStep) {
2461
+ return new MoveViewportBehavior(state.viewport.position, resetSelectedStep, state);
2462
+ }
2463
+ constructor(startPosition, resetSelectedStep, state) {
2464
+ this.startPosition = startPosition;
2465
+ this.resetSelectedStep = resetSelectedStep;
2466
+ this.state = state;
2467
+ }
2468
+ onStart() {
2469
+ if (this.resetSelectedStep) {
2470
+ const stepId = this.state.tryGetLastStepIdFromFolderPath();
2471
+ this.state.setSelectedStepId(stepId);
2472
+ }
2473
+ }
2474
+ onMove(delta) {
2475
+ this.state.setViewport({
2476
+ position: this.startPosition.subtract(delta),
2477
+ scale: this.state.viewport.scale
2478
+ });
2479
+ }
2480
+ onEnd() {
2481
+ // Nothing to do.
2482
+ }
2483
+ }
2484
+
2485
+ class SelectStepBehavior {
2486
+ static create(pressedStepComponent, forceDisableDrag, context) {
2487
+ const isDragDisabled = forceDisableDrag ||
2488
+ context.state.isDragDisabled ||
2489
+ !context.definitionModifier.isDraggable(pressedStepComponent.step, pressedStepComponent.parentSequence);
2490
+ return new SelectStepBehavior(pressedStepComponent, isDragDisabled, context, context.state);
2491
+ }
2492
+ constructor(pressedStepComponent, isDragDisabled, context, state) {
2493
+ this.pressedStepComponent = pressedStepComponent;
2494
+ this.isDragDisabled = isDragDisabled;
2495
+ this.context = context;
2496
+ this.state = state;
2497
+ }
2498
+ onStart() {
2499
+ // Nothing to do.
2500
+ }
2501
+ onMove(delta) {
2502
+ if (delta.distance() > 2) {
2503
+ const canDrag = !this.state.isReadonly && !this.isDragDisabled;
2504
+ if (canDrag) {
2505
+ this.state.setSelectedStepId(null);
2506
+ return DragStepBehavior.create(this.context, this.pressedStepComponent.step, this.pressedStepComponent);
2507
+ }
2508
+ else {
2509
+ return MoveViewportBehavior.create(this.state, false);
2510
+ }
2511
+ }
2512
+ }
2513
+ onEnd(interrupt) {
2514
+ if (!interrupt) {
2515
+ this.state.setSelectedStepId(this.pressedStepComponent.step.id);
2516
+ }
2517
+ }
2518
+ }
2519
+
2520
+ class PressingBehavior {
2521
+ static create(clickedElement, handler) {
2522
+ return new PressingBehavior(clickedElement, handler);
2523
+ }
2524
+ constructor(clickedElement, handler) {
2525
+ this.clickedElement = clickedElement;
2526
+ this.handler = handler;
2527
+ }
2528
+ onStart() {
2529
+ // Nothing...
2530
+ }
2531
+ onMove() {
2532
+ // Nothing...
2533
+ }
2534
+ onEnd(interrupt, element) {
2535
+ if (!interrupt && element && this.clickedElement === element) {
2536
+ this.handler.handle();
2537
+ }
2538
+ }
2539
+ }
2540
+
2541
+ class RerenderStepPressingBehaviorHandler {
2542
+ constructor(designerContext) {
2543
+ this.designerContext = designerContext;
2544
+ }
2545
+ handle() {
2546
+ this.designerContext.workspaceController.updateRootComponent();
2547
+ }
2548
+ }
2549
+
2550
+ class OpenFolderPressingBehaviorHandler {
2551
+ constructor(command, designerContext) {
2552
+ this.command = command;
2553
+ this.designerContext = designerContext;
2554
+ }
2555
+ handle() {
2556
+ const stepId = this.command.step.id;
2557
+ this.designerContext.state.pushStepIdToFolderPath(stepId);
2558
+ }
2559
+ }
2560
+
2561
+ class TriggerCustomActionPressingBehaviorHandler {
2562
+ constructor(command, designerContext) {
2563
+ this.command = command;
2564
+ this.designerContext = designerContext;
2565
+ }
2566
+ handle() {
2567
+ const customActionHandler = this.designerContext.configuration.customActionHandler;
2568
+ if (!customActionHandler) {
2569
+ console.warn(`Custom action handler is not defined (action type: ${this.command.action.type})`);
2570
+ return;
2571
+ }
2572
+ const context = this.createContext();
2573
+ customActionHandler(this.command.action, this.command.step, this.command.sequence, context);
2574
+ }
2575
+ createContext() {
2576
+ return {
2577
+ notifyStepNameChanged: (stepId) => this.notifyStepChanged(exports.DefinitionChangeType.stepNameChanged, stepId),
2578
+ notifyStepPropertiesChanged: (stepId) => this.notifyStepChanged(exports.DefinitionChangeType.stepPropertyChanged, stepId),
2579
+ notifyStepInserted: (stepId) => this.notifyStepChanged(exports.DefinitionChangeType.stepInserted, stepId),
2580
+ notifyStepMoved: (stepId) => this.notifyStepChanged(exports.DefinitionChangeType.stepMoved, stepId),
2581
+ notifyStepDeleted: (stepId) => this.notifyStepChanged(exports.DefinitionChangeType.stepDeleted, stepId)
2582
+ };
2583
+ }
2584
+ notifyStepChanged(changeType, stepId) {
2585
+ if (!stepId) {
2586
+ throw new Error('Step id is empty');
2587
+ }
2588
+ this.designerContext.state.notifyDefinitionChanged(changeType, stepId);
2589
+ }
2590
+ }
2591
+
2592
+ class ClickBehaviorResolver {
2593
+ constructor(designerContext, state) {
2594
+ this.designerContext = designerContext;
2595
+ this.state = state;
2596
+ }
2597
+ resolve(commandOrNull, element, forceDisableDrag) {
2598
+ if (!commandOrNull) {
2599
+ return MoveViewportBehavior.create(this.state, true);
2600
+ }
2601
+ switch (commandOrNull.type) {
2602
+ case exports.ClickCommandType.selectStep:
2603
+ return SelectStepBehavior.create(commandOrNull.component, forceDisableDrag, this.designerContext);
2604
+ case exports.ClickCommandType.rerenderStep:
2605
+ return PressingBehavior.create(element, new RerenderStepPressingBehaviorHandler(this.designerContext));
2606
+ case exports.ClickCommandType.openFolder:
2607
+ return PressingBehavior.create(element, new OpenFolderPressingBehaviorHandler(commandOrNull, this.designerContext));
2608
+ case exports.ClickCommandType.triggerCustomAction:
2609
+ return PressingBehavior.create(element, new TriggerCustomActionPressingBehaviorHandler(commandOrNull, this.designerContext));
2610
+ default:
2611
+ throw new Error('Not supported behavior type');
2612
+ }
2613
+ }
2614
+ }
2615
+
2616
+ class BadgesResultFactory {
2617
+ static create(services) {
2618
+ return services.badges.map(ext => ext.createStartValue());
2619
+ }
2620
+ }
2621
+
2622
+ function findValidationBadgeIndex(extensions) {
2623
+ return extensions.findIndex(ext => ext.id === 'validationError');
2624
+ }
2625
+
2626
+ class ContextMenu {
2627
+ static create(position, theme, items) {
2628
+ const menu = document.createElement('div');
2629
+ menu.style.left = `${position.x}px`;
2630
+ menu.style.top = `${position.y}px`;
2631
+ menu.className = `sqd-context-menu sqd-theme-${theme}`;
2632
+ const elements = [];
2633
+ for (let index = 0; index < items.length; index++) {
2634
+ const item = items[index];
2635
+ const element = document.createElement('div');
2636
+ if (typeof item === 'string') {
2637
+ element.className = 'sqd-context-menu-group';
2638
+ element.innerText = item;
2639
+ }
2640
+ else {
2641
+ element.className = 'sqd-context-menu-item';
2642
+ element.innerText = item.label;
2643
+ }
2644
+ elements.push(element);
2645
+ menu.appendChild(element);
2646
+ }
2647
+ const instance = new ContextMenu(menu, elements, items, Date.now());
2648
+ document.addEventListener('mousedown', instance.mouseDown, false);
2649
+ document.addEventListener('mouseup', instance.mouseUp, false);
2650
+ document.addEventListener('touchstart', instance.mouseDown, false);
2651
+ document.addEventListener('touchend', instance.mouseUp, false);
2652
+ document.body.appendChild(menu);
2653
+ return instance;
2654
+ }
2655
+ constructor(menu, elements, items, startTime) {
2656
+ this.menu = menu;
2657
+ this.elements = elements;
2658
+ this.items = items;
2659
+ this.startTime = startTime;
2660
+ this.isAttached = true;
2661
+ this.mouseDown = (e) => {
2662
+ const index = this.findIndex(e.target);
2663
+ if (index === null) {
2664
+ this.tryDestroy();
2665
+ }
2666
+ else {
2667
+ e.preventDefault();
2668
+ e.stopPropagation();
2669
+ }
2670
+ };
2671
+ this.mouseUp = (e) => {
2672
+ const dt = Date.now() - this.startTime;
2673
+ if (dt < 300) {
2674
+ e.preventDefault();
2675
+ e.stopPropagation();
2676
+ return;
2677
+ }
2678
+ try {
2679
+ const index = this.findIndex(e.target);
2680
+ if (index !== null) {
2681
+ const item = this.items[index];
2682
+ if (typeof item !== 'string') {
2683
+ item.callback();
2684
+ }
2685
+ }
2686
+ }
2687
+ finally {
2688
+ this.tryDestroy();
2689
+ }
2690
+ };
2691
+ }
2692
+ findIndex(element) {
2693
+ for (let index = 0; index < this.elements.length; index++) {
2694
+ if (this.elements[index].contains(element)) {
2695
+ return index;
2696
+ }
2697
+ }
2698
+ return null;
2699
+ }
2700
+ tryDestroy() {
2701
+ if (this.isAttached) {
2702
+ document.body.removeChild(this.menu);
2703
+ document.removeEventListener('mousedown', this.mouseDown, false);
2704
+ document.removeEventListener('mouseup', this.mouseUp, false);
2705
+ document.removeEventListener('touchstart', this.mouseDown, false);
2706
+ document.removeEventListener('touchend', this.mouseUp, false);
2707
+ this.isAttached = false;
2708
+ }
2709
+ }
2710
+ }
2711
+
2712
+ class ContextMenuItemsBuilder {
2713
+ static build(commandOrNull, viewportApi, definitionModifier, state) {
2714
+ const items = [];
2715
+ if (commandOrNull && commandOrNull.type === exports.ClickCommandType.selectStep) {
2716
+ const ssc = commandOrNull;
2717
+ const step = ssc.component.step;
2718
+ const parentSequence = ssc.component.parentSequence;
2719
+ items.push(step.name);
2720
+ if (state.selectedStepId === step.id) {
2721
+ items.push({
2722
+ label: `Unselect`,
2723
+ callback: () => {
2724
+ state.setSelectedStepId(null);
2725
+ }
2726
+ });
2727
+ }
2728
+ else {
2729
+ items.push({
2730
+ label: 'Select',
2731
+ callback: () => {
2732
+ state.setSelectedStepId(step.id);
2733
+ }
2734
+ });
2735
+ }
2736
+ if (!state.isReadonly) {
2737
+ if (definitionModifier.isDeletable(step.id)) {
2738
+ items.push({
2739
+ label: 'Delete',
2740
+ callback: () => {
2741
+ definitionModifier.tryDelete(step.id);
2742
+ }
2743
+ });
2744
+ }
2745
+ if (definitionModifier.isDuplicable(step, parentSequence)) {
2746
+ items.push({
2747
+ label: 'Duplicate',
2748
+ callback: () => {
2749
+ definitionModifier.tryDuplicate(step, parentSequence);
2750
+ }
2751
+ });
2752
+ }
2753
+ }
2754
+ }
2755
+ items.push({
2756
+ label: 'Reset view',
2757
+ callback: () => {
2758
+ viewportApi.resetViewport();
2759
+ }
2760
+ });
2761
+ return items;
2762
+ }
2763
+ }
2764
+
2765
+ class ContextMenuController {
2766
+ constructor(theme, viewportApi, definitionModifier, state, configuration) {
2767
+ this.theme = theme;
2768
+ this.viewportApi = viewportApi;
2769
+ this.definitionModifier = definitionModifier;
2770
+ this.state = state;
2771
+ this.configuration = configuration;
2772
+ }
2773
+ tryOpen(position, commandOrNull) {
2774
+ if (this.configuration.contextMenu === false) {
2775
+ // Context menu is disabled.
2776
+ return;
2777
+ }
2778
+ if (this.last) {
2779
+ this.last.tryDestroy();
2780
+ }
2781
+ const items = ContextMenuItemsBuilder.build(commandOrNull, this.viewportApi, this.definitionModifier, this.state);
2782
+ this.last = ContextMenu.create(position, this.theme, items);
2783
+ }
2784
+ destroy() {
2785
+ if (this.last) {
2786
+ this.last.tryDestroy();
2787
+ }
2788
+ }
2789
+ }
2790
+
2791
+ class Workspace {
2792
+ static create(parent, designerContext, api) {
2793
+ const view = WorkspaceView.create(parent, designerContext.componentContext);
2794
+ const clickBehaviorResolver = new ClickBehaviorResolver(designerContext, designerContext.state);
2795
+ const wheelController = designerContext.services.wheelController.create(api.workspace);
2796
+ const contextMenuController = new ContextMenuController(designerContext.theme, api.viewport, designerContext.definitionModifier, designerContext.state, designerContext.configuration);
2797
+ const workspace = new Workspace(view, designerContext.definitionWalker, designerContext.state, designerContext.behaviorController, wheelController, contextMenuController, clickBehaviorResolver, api.viewport, designerContext.services);
2798
+ setTimeout(() => {
2799
+ workspace.updateRootComponent();
2800
+ api.viewport.resetViewport();
2801
+ workspace.onReady.forward();
2802
+ });
2803
+ designerContext.setWorkspaceController(workspace);
2804
+ designerContext.state.onViewportChanged.subscribe(vp => workspace.onViewportChanged(vp));
2805
+ designerContext.state.onIsDraggingChanged.subscribe(is => workspace.onIsDraggingChanged(is));
2806
+ race(0, designerContext.state.onDefinitionChanged, designerContext.state.onSelectedStepIdChanged, designerContext.state.onFolderPathChanged).subscribe(r => {
2807
+ workspace.onStateChanged(r[0], r[1], r[2]);
2808
+ });
2809
+ view.bindClick((p, t, b) => workspace.onClick(p, t, b));
2810
+ view.bindWheel(e => workspace.onWheel(e));
2811
+ view.bindContextMenu((p, t) => workspace.onContextMenu(p, t));
2812
+ return workspace;
2813
+ }
2814
+ constructor(view, definitionWalker, state, behaviorController, wheelController, contextMenuController, clickBehaviorResolver, viewportApi, services) {
2815
+ this.view = view;
2816
+ this.definitionWalker = definitionWalker;
2817
+ this.state = state;
2818
+ this.behaviorController = behaviorController;
2819
+ this.wheelController = wheelController;
2820
+ this.contextMenuController = contextMenuController;
2821
+ this.clickBehaviorResolver = clickBehaviorResolver;
2822
+ this.viewportApi = viewportApi;
2823
+ this.services = services;
2824
+ this.onReady = new SimpleEvent();
2825
+ this.isValid = false;
2826
+ this.selectedStepComponent = null;
2827
+ this.validationErrorBadgeIndex = null;
2828
+ }
2829
+ updateRootComponent() {
2830
+ this.selectedStepComponent = null;
2831
+ let parentSequencePlaceIndicator;
2832
+ let sequence;
2833
+ const stepId = this.state.tryGetLastStepIdFromFolderPath();
2834
+ if (stepId) {
2835
+ const parentSequence = this.definitionWalker.getParentSequence(this.state.definition, stepId);
2836
+ const children = this.definitionWalker.getChildren(parentSequence.step);
2837
+ if (!children || children.type !== sequentialWorkflowModel.StepChildrenType.sequence) {
2838
+ throw new Error('Cannot find single sequence in folder step');
2839
+ }
2840
+ sequence = children.items;
2841
+ parentSequencePlaceIndicator = {
2842
+ sequence: parentSequence.parentSequence,
2843
+ index: parentSequence.index
2844
+ };
2845
+ }
2846
+ else {
2847
+ sequence = this.state.definition.sequence;
2848
+ parentSequencePlaceIndicator = null;
2849
+ }
2850
+ this.view.render(sequence, parentSequencePlaceIndicator);
2851
+ this.trySelectStepComponent(this.state.selectedStepId);
2852
+ this.updateBadges();
2853
+ }
2854
+ updateBadges() {
2855
+ const result = BadgesResultFactory.create(this.services);
2856
+ this.getRootComponent().updateBadges(result);
2857
+ if (this.validationErrorBadgeIndex === null) {
2858
+ this.validationErrorBadgeIndex = findValidationBadgeIndex(this.services.badges);
2859
+ }
2860
+ this.isValid = Boolean(result[this.validationErrorBadgeIndex]);
2861
+ }
2862
+ getPlaceholders() {
2863
+ const result = [];
2864
+ this.getRootComponent().getPlaceholders(result);
2865
+ return result;
2866
+ }
2867
+ getComponentByStepId(stepId) {
2868
+ const component = this.getRootComponent().findById(stepId);
2869
+ if (!component) {
2870
+ throw new Error(`Cannot find component for step id: ${stepId}`);
2871
+ }
2872
+ return component;
2873
+ }
2874
+ getCanvasPosition() {
2875
+ return this.view.getCanvasPosition();
2876
+ }
2877
+ getCanvasSize() {
2878
+ return this.view.getCanvasSize();
2879
+ }
2880
+ getRootComponentSize() {
2881
+ const view = this.getRootComponent().view;
2882
+ return new Vector(view.width, view.height);
2883
+ }
2884
+ updateCanvasSize() {
2885
+ setTimeout(() => this.view.refreshSize());
2886
+ }
2887
+ destroy() {
2888
+ this.contextMenuController.destroy();
2889
+ this.view.destroy();
2890
+ }
2891
+ onClick(position, target, buttonIndex) {
2892
+ const isPrimaryButton = buttonIndex === 0;
2893
+ const isMiddleButton = buttonIndex === 1;
2894
+ if (isPrimaryButton || isMiddleButton) {
2895
+ const commandOrNull = this.resolveClick(target, position);
2896
+ const forceDisableDrag = isMiddleButton;
2897
+ const behavior = this.clickBehaviorResolver.resolve(commandOrNull, target, forceDisableDrag);
2898
+ this.behaviorController.start(position, behavior);
2899
+ }
2900
+ }
2901
+ onWheel(e) {
2902
+ e.preventDefault();
2903
+ e.stopPropagation();
2904
+ this.wheelController.onWheel(e);
2905
+ }
2906
+ onContextMenu(position, target) {
2907
+ const commandOrNull = this.resolveClick(target, position);
2908
+ this.contextMenuController.tryOpen(position, commandOrNull);
2909
+ }
2910
+ onIsDraggingChanged(isDragging) {
2911
+ this.getRootComponent().setIsDragging(isDragging);
2912
+ }
2913
+ onViewportChanged(viewport) {
2914
+ this.view.setPositionAndScale(viewport.position, viewport.scale);
2915
+ }
2916
+ onStateChanged(definitionChanged, selectedStepIdChanged, folderPathChanged) {
2917
+ if (folderPathChanged) {
2918
+ this.updateRootComponent();
2919
+ this.viewportApi.resetViewport();
2920
+ }
2921
+ else if (definitionChanged) {
2922
+ if (definitionChanged.changeType === exports.DefinitionChangeType.stepPropertyChanged) {
2923
+ this.updateBadges();
2924
+ }
2925
+ else {
2926
+ this.updateRootComponent();
2927
+ }
2928
+ }
2929
+ else if (selectedStepIdChanged !== undefined) {
2930
+ this.trySelectStepComponent(selectedStepIdChanged);
2931
+ }
2932
+ }
2933
+ trySelectStepComponent(stepId) {
2934
+ if (this.selectedStepComponent) {
2935
+ this.selectedStepComponent.setIsSelected(false);
2936
+ this.selectedStepComponent = null;
2937
+ }
2938
+ if (stepId) {
2939
+ this.selectedStepComponent = this.getRootComponent().findById(stepId);
2940
+ if (this.selectedStepComponent) {
2941
+ this.selectedStepComponent.setIsSelected(true);
2942
+ }
2943
+ }
2944
+ }
2945
+ resolveClick(element, position) {
2946
+ const click = {
2947
+ element,
2948
+ position,
2949
+ scale: this.state.viewport.scale
2950
+ };
2951
+ return this.getRootComponent().resolveClick(click);
2952
+ }
2953
+ getRootComponent() {
2954
+ if (this.view.rootComponent) {
2955
+ return this.view.rootComponent;
2956
+ }
2957
+ throw new Error('Root component not found');
2958
+ }
2959
+ }
2960
+
2961
+ class DesignerView {
2962
+ static create(parent, designerContext, api) {
2963
+ const root = Dom.element('div', {
2964
+ class: `sqd-designer sqd-theme-${designerContext.theme}`
2965
+ });
2966
+ parent.appendChild(root);
2967
+ const workspace = Workspace.create(root, designerContext, api);
2968
+ const uiComponents = designerContext.services.uiComponents.map(factory => factory.create(root, api));
2969
+ const daemons = designerContext.services.daemons.map(factory => factory.create(api));
2970
+ const view = new DesignerView(root, designerContext.layoutController, workspace, uiComponents, daemons);
2971
+ view.reloadLayout();
2972
+ window.addEventListener('resize', view.onResizeHandler, false);
2973
+ return view;
2974
+ }
2975
+ constructor(root, layoutController, workspace, uiComponents, daemons) {
2976
+ this.root = root;
2977
+ this.layoutController = layoutController;
2978
+ this.workspace = workspace;
2979
+ this.uiComponents = uiComponents;
2980
+ this.daemons = daemons;
2981
+ this.onResizeHandler = () => this.onResize();
2982
+ }
2983
+ destroy() {
2984
+ var _a;
2985
+ window.removeEventListener('resize', this.onResizeHandler, false);
2986
+ this.workspace.destroy();
2987
+ this.uiComponents.forEach(component => component.destroy());
2988
+ this.daemons.forEach(daemon => daemon.destroy());
2989
+ (_a = this.root.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(this.root);
2990
+ }
2991
+ onResize() {
2992
+ this.reloadLayout();
2993
+ }
2994
+ reloadLayout() {
2995
+ const isMobile = this.layoutController.isMobile();
2996
+ Dom.toggleClass(this.root, !isMobile, 'sqd-layout-desktop');
2997
+ Dom.toggleClass(this.root, isMobile, 'sqd-layout-mobile');
2998
+ }
2999
+ }
3000
+
3001
+ const SAFE_OFFSET = 10;
3002
+ class DefaultDraggedComponent {
3003
+ static create(parent, step, componentContext) {
3004
+ const canvas = Dom.svg('svg');
3005
+ canvas.style.marginLeft = -SAFE_OFFSET + 'px';
3006
+ canvas.style.marginTop = -SAFE_OFFSET + 'px';
3007
+ parent.appendChild(canvas);
3008
+ const fakeStepContext = {
3009
+ parentSequence: [],
3010
+ step,
3011
+ depth: 0,
3012
+ position: 0,
3013
+ isInputConnected: true,
3014
+ isOutputConnected: true
3015
+ };
3016
+ const stepComponent = componentContext.stepComponentFactory.create(canvas, fakeStepContext, componentContext);
3017
+ Dom.attrs(canvas, {
3018
+ width: stepComponent.view.width + SAFE_OFFSET * 2,
3019
+ height: stepComponent.view.height + SAFE_OFFSET * 2
3020
+ });
3021
+ Dom.translate(stepComponent.view.g, SAFE_OFFSET, SAFE_OFFSET);
3022
+ return new DefaultDraggedComponent(stepComponent.view.width, stepComponent.view.height);
3023
+ }
3024
+ constructor(width, height) {
3025
+ this.width = width;
3026
+ this.height = height;
3027
+ }
3028
+ destroy() {
3029
+ // Nothing to destroy...
3030
+ }
3031
+ }
3032
+
3033
+ class DefaultDraggedComponentExtension {
3034
+ constructor() {
3035
+ this.create = DefaultDraggedComponent.create;
3036
+ }
3037
+ }
3038
+
3039
+ class ControlBarView {
3040
+ static create(parent, isUndoRedoSupported) {
3041
+ const root = Dom.element('div', {
3042
+ class: 'sqd-control-bar'
3043
+ });
3044
+ const resetButton = createButton(Icons.center, 'Reset view');
3045
+ root.appendChild(resetButton);
3046
+ const zoomInButton = createButton(Icons.zoomIn, 'Zoom in');
3047
+ root.appendChild(zoomInButton);
3048
+ const zoomOutButton = createButton(Icons.zoomOut, 'Zoom out');
3049
+ root.appendChild(zoomOutButton);
3050
+ let undoButton = null;
3051
+ let redoButton = null;
3052
+ if (isUndoRedoSupported) {
3053
+ undoButton = createButton(Icons.undo, 'Undo');
3054
+ root.appendChild(undoButton);
3055
+ redoButton = createButton(Icons.redo, 'Redo');
3056
+ root.appendChild(redoButton);
3057
+ }
3058
+ const disableDragButton = createButton(Icons.move, 'Turn on/off drag and drop');
3059
+ disableDragButton.classList.add('sqd-disabled');
3060
+ root.appendChild(disableDragButton);
3061
+ const deleteButton = createButton(Icons.delete, 'Delete selected step');
3062
+ deleteButton.classList.add('sqd-delete');
3063
+ deleteButton.classList.add('sqd-hidden');
3064
+ root.appendChild(deleteButton);
3065
+ parent.appendChild(root);
3066
+ return new ControlBarView(resetButton, zoomInButton, zoomOutButton, undoButton, redoButton, disableDragButton, deleteButton);
3067
+ }
3068
+ constructor(resetButton, zoomInButton, zoomOutButton, undoButton, redoButton, disableDragButton, deleteButton) {
3069
+ this.resetButton = resetButton;
3070
+ this.zoomInButton = zoomInButton;
3071
+ this.zoomOutButton = zoomOutButton;
3072
+ this.undoButton = undoButton;
3073
+ this.redoButton = redoButton;
3074
+ this.disableDragButton = disableDragButton;
3075
+ this.deleteButton = deleteButton;
3076
+ }
3077
+ bindResetButtonClick(handler) {
3078
+ bindClick(this.resetButton, handler);
3079
+ }
3080
+ bindZoomInButtonClick(handler) {
3081
+ bindClick(this.zoomInButton, handler);
3082
+ }
3083
+ bindZoomOutButtonClick(handler) {
3084
+ bindClick(this.zoomOutButton, handler);
3085
+ }
3086
+ bindUndoButtonClick(handler) {
3087
+ if (!this.undoButton) {
3088
+ throw new Error('Undo button is disabled');
3089
+ }
3090
+ bindClick(this.undoButton, handler);
3091
+ }
3092
+ bindRedoButtonClick(handler) {
3093
+ if (!this.redoButton) {
3094
+ throw new Error('Redo button is disabled');
3095
+ }
3096
+ bindClick(this.redoButton, handler);
3097
+ }
3098
+ bindDisableDragButtonClick(handler) {
3099
+ bindClick(this.disableDragButton, handler);
3100
+ }
3101
+ bindDeleteButtonClick(handler) {
3102
+ bindClick(this.deleteButton, handler);
3103
+ }
3104
+ setIsDeleteButtonHidden(isHidden) {
3105
+ Dom.toggleClass(this.deleteButton, isHidden, 'sqd-hidden');
3106
+ }
3107
+ setDisableDragButtonDisabled(isDisabled) {
3108
+ Dom.toggleClass(this.disableDragButton, isDisabled, 'sqd-disabled');
3109
+ }
3110
+ setUndoButtonDisabled(isDisabled) {
3111
+ if (!this.undoButton) {
3112
+ throw new Error('Undo button is disabled');
3113
+ }
3114
+ Dom.toggleClass(this.undoButton, isDisabled, 'sqd-disabled');
3115
+ }
3116
+ setRedoButtonDisabled(isDisabled) {
3117
+ if (!this.redoButton) {
3118
+ throw new Error('Redo button is disabled');
3119
+ }
3120
+ Dom.toggleClass(this.redoButton, isDisabled, 'sqd-disabled');
3121
+ }
3122
+ }
3123
+ function bindClick(element, handler) {
3124
+ element.addEventListener('click', e => {
3125
+ e.preventDefault();
3126
+ handler();
3127
+ }, false);
3128
+ }
3129
+ function createButton(d, title) {
3130
+ const button = Dom.element('div', {
3131
+ class: 'sqd-control-bar-button',
3132
+ title
3133
+ });
3134
+ const icon = Icons.createSvg('sqd-control-bar-button-icon', d);
3135
+ button.appendChild(icon);
3136
+ return button;
3137
+ }
3138
+
3139
+ class ControlBar {
3140
+ static create(parent, api) {
3141
+ const isUndoRedoSupported = api.controlBar.isUndoRedoSupported();
3142
+ const view = ControlBarView.create(parent, isUndoRedoSupported);
3143
+ const bar = new ControlBar(view, api.controlBar, isUndoRedoSupported);
3144
+ view.bindResetButtonClick(() => bar.onResetButtonClicked());
3145
+ view.bindZoomInButtonClick(() => bar.onZoomInButtonClicked());
3146
+ view.bindZoomOutButtonClick(() => bar.onZoomOutButtonClicked());
3147
+ view.bindDisableDragButtonClick(() => bar.onMoveButtonClicked());
3148
+ view.bindDeleteButtonClick(() => bar.onDeleteButtonClicked());
3149
+ api.controlBar.subscribe(() => bar.refreshButtons());
3150
+ if (isUndoRedoSupported) {
3151
+ view.bindUndoButtonClick(() => bar.onUndoButtonClicked());
3152
+ view.bindRedoButtonClick(() => bar.onRedoButtonClicked());
3153
+ }
3154
+ bar.refreshButtons();
3155
+ return bar;
3156
+ }
3157
+ constructor(view, controlBarApi, isUndoRedoSupported) {
3158
+ this.view = view;
3159
+ this.controlBarApi = controlBarApi;
3160
+ this.isUndoRedoSupported = isUndoRedoSupported;
3161
+ }
3162
+ destroy() {
3163
+ //
3164
+ }
3165
+ onResetButtonClicked() {
3166
+ this.controlBarApi.resetViewport();
3167
+ }
3168
+ onZoomInButtonClicked() {
3169
+ this.controlBarApi.zoomIn();
3170
+ }
3171
+ onZoomOutButtonClicked() {
3172
+ this.controlBarApi.zoomOut();
3173
+ }
3174
+ onMoveButtonClicked() {
3175
+ this.controlBarApi.toggleIsDragDisabled();
3176
+ }
3177
+ onUndoButtonClicked() {
3178
+ this.controlBarApi.tryUndo();
3179
+ }
3180
+ onRedoButtonClicked() {
3181
+ this.controlBarApi.tryRedo();
3182
+ }
3183
+ onDeleteButtonClicked() {
3184
+ this.controlBarApi.tryDelete();
3185
+ }
3186
+ refreshButtons() {
3187
+ this.refreshDeleteButtonVisibility();
3188
+ this.refreshIsDragDisabled();
3189
+ if (this.isUndoRedoSupported) {
3190
+ this.refreshUndoRedoAvailability();
3191
+ }
3192
+ }
3193
+ //
3194
+ refreshIsDragDisabled() {
3195
+ const isDragDisabled = this.controlBarApi.isDragDisabled();
3196
+ this.view.setDisableDragButtonDisabled(!isDragDisabled);
3197
+ }
3198
+ refreshUndoRedoAvailability() {
3199
+ const canUndo = this.controlBarApi.canUndo();
3200
+ const canRedo = this.controlBarApi.canRedo();
3201
+ this.view.setUndoButtonDisabled(!canUndo);
3202
+ this.view.setRedoButtonDisabled(!canRedo);
3203
+ }
3204
+ refreshDeleteButtonVisibility() {
3205
+ const canDelete = this.controlBarApi.canDelete();
3206
+ this.view.setIsDeleteButtonHidden(!canDelete);
3207
+ }
3208
+ }
3209
+
3210
+ class ControlBarExtension {
3211
+ constructor() {
3212
+ this.create = ControlBar.create;
3213
+ }
3214
+ }
3215
+
3216
+ const supportedKeys = ['Backspace', 'Delete'];
3217
+ const ignoreTagNames = ['INPUT', 'TEXTAREA'];
3218
+ class KeyboardDaemon {
3219
+ static create(api) {
3220
+ const controller = new KeyboardDaemon(api.controlBar);
3221
+ document.addEventListener('keyup', controller.onKeyUp, false);
3222
+ return controller;
3223
+ }
3224
+ constructor(controlBarApi) {
3225
+ this.controlBarApi = controlBarApi;
3226
+ this.onKeyUp = (e) => {
3227
+ if (!supportedKeys.includes(e.key)) {
3228
+ return;
3229
+ }
3230
+ if (document.activeElement && ignoreTagNames.includes(document.activeElement.tagName)) {
3231
+ return;
3232
+ }
3233
+ const isDeletable = this.controlBarApi.canDelete();
3234
+ if (isDeletable) {
3235
+ e.preventDefault();
3236
+ e.stopPropagation();
3237
+ this.controlBarApi.tryDelete();
3238
+ }
3239
+ };
3240
+ }
3241
+ destroy() {
3242
+ document.removeEventListener('keyup', this.onKeyUp, false);
3243
+ }
3244
+ }
3245
+
3246
+ class KeyboardDaemonExtension {
3247
+ constructor() {
3248
+ this.create = KeyboardDaemon.create;
3249
+ }
3250
+ }
3251
+
3252
+ class SmartEditorView {
3253
+ static create(parent, api, configuration) {
3254
+ const root = Dom.element('div', {
3255
+ class: 'sqd-smart-editor'
3256
+ });
3257
+ const toggle = Dom.element('div', {
3258
+ class: 'sqd-smart-editor-toggle',
3259
+ title: 'Toggle editor'
3260
+ });
3261
+ parent.appendChild(toggle);
3262
+ parent.appendChild(root);
3263
+ const editor = Editor.create(root, api, 'sqd-editor sqd-step-editor', configuration.stepEditorProvider, 'sqd-editor sqd-global-editor', configuration.globalEditorProvider);
3264
+ return new SmartEditorView(root, toggle, editor);
3265
+ }
3266
+ constructor(root, toggle, editor) {
3267
+ this.root = root;
3268
+ this.toggle = toggle;
3269
+ this.editor = editor;
3270
+ }
3271
+ bindToggleClick(handler) {
3272
+ this.toggle.addEventListener('click', e => {
3273
+ e.preventDefault();
3274
+ handler();
3275
+ }, false);
3276
+ }
3277
+ setIsCollapsed(isCollapsed) {
3278
+ Dom.toggleClass(this.root, isCollapsed, 'sqd-hidden');
3279
+ Dom.toggleClass(this.toggle, isCollapsed, 'sqd-collapsed');
3280
+ if (this.toggleIcon) {
3281
+ this.toggle.removeChild(this.toggleIcon);
3282
+ }
3283
+ this.toggleIcon = Icons.createSvg('sqd-smart-editor-toggle-icon', isCollapsed ? Icons.options : Icons.close);
3284
+ this.toggle.appendChild(this.toggleIcon);
3285
+ }
3286
+ destroy() {
3287
+ this.editor.destroy();
3288
+ }
3289
+ }
3290
+
3291
+ class SmartEditor {
3292
+ static create(parent, api, configuration) {
3293
+ const view = SmartEditorView.create(parent, api.editor, configuration);
3294
+ const editor = new SmartEditor(view, api.editor, api.workspace);
3295
+ editor.updateVisibility();
3296
+ view.bindToggleClick(() => editor.onToggleClicked());
3297
+ api.editor.subscribeIsCollapsed(() => editor.onIsCollapsedChanged());
3298
+ return editor;
3299
+ }
3300
+ constructor(view, editorApi, workspaceApi) {
3301
+ this.view = view;
3302
+ this.editorApi = editorApi;
3303
+ this.workspaceApi = workspaceApi;
3304
+ }
3305
+ onToggleClicked() {
3306
+ this.editorApi.toggleIsCollapsed();
3307
+ }
3308
+ setIsCollapsed(isCollapsed) {
3309
+ this.view.setIsCollapsed(isCollapsed);
3310
+ }
3311
+ onIsCollapsedChanged() {
3312
+ this.updateVisibility();
3313
+ this.workspaceApi.updateCanvasSize();
3314
+ }
3315
+ updateVisibility() {
3316
+ this.setIsCollapsed(this.editorApi.isCollapsed());
3317
+ }
3318
+ destroy() {
3319
+ this.view.destroy();
3320
+ }
3321
+ }
3322
+
3323
+ class SmartEditorExtension {
3324
+ constructor(configuration) {
3325
+ this.configuration = configuration;
3326
+ }
3327
+ create(root, api) {
3328
+ return SmartEditor.create(root, api, this.configuration);
3329
+ }
3330
+ }
3331
+
3332
+ const listenerOptions = {
3333
+ passive: false
3334
+ };
3335
+ class ScrollBoxView {
3336
+ static create(parent, viewport) {
3337
+ const root = Dom.element('div', {
3338
+ class: 'sqd-scrollbox'
3339
+ });
3340
+ parent.appendChild(root);
3341
+ const view = new ScrollBoxView(root, viewport);
3342
+ window.addEventListener('resize', view.onResize, false);
3343
+ root.addEventListener('wheel', e => view.onWheel(e), false);
3344
+ root.addEventListener('touchstart', e => view.onTouchStart(e), listenerOptions);
3345
+ root.addEventListener('mousedown', e => view.onMouseDown(e), false);
3346
+ return view;
3347
+ }
3348
+ constructor(root, viewport) {
3349
+ this.root = root;
3350
+ this.viewport = viewport;
3351
+ this.onResize = () => {
3352
+ this.refresh();
3353
+ };
3354
+ this.onTouchStart = (e) => {
3355
+ e.preventDefault();
3356
+ this.startScroll(readTouchPosition(e));
3357
+ };
3358
+ this.onMouseDown = (e) => {
3359
+ this.startScroll(readMousePosition(e));
3360
+ };
3361
+ this.onTouchMove = (e) => {
3362
+ e.preventDefault();
3363
+ this.moveScroll(readTouchPosition(e));
3364
+ };
3365
+ this.onMouseMove = (e) => {
3366
+ e.preventDefault();
3367
+ this.moveScroll(readMousePosition(e));
3368
+ };
3369
+ this.onTouchEnd = (e) => {
3370
+ e.preventDefault();
3371
+ this.stopScroll();
3372
+ };
3373
+ this.onMouseUp = (e) => {
3374
+ e.preventDefault();
3375
+ this.stopScroll();
3376
+ };
3377
+ }
3378
+ setContent(element) {
3379
+ if (this.content) {
3380
+ this.root.removeChild(this.content.element);
3381
+ }
3382
+ element.classList.add('sqd-scrollbox-body');
3383
+ this.root.appendChild(element);
3384
+ this.reload(element);
3385
+ }
3386
+ refresh() {
3387
+ if (this.content) {
3388
+ this.reload(this.content.element);
3389
+ }
3390
+ }
3391
+ destroy() {
3392
+ window.removeEventListener('resize', this.onResize, false);
3393
+ }
3394
+ reload(element) {
3395
+ const maxHeightPercent = 0.7;
3396
+ const minDistance = 206;
3397
+ let height = Math.min(this.viewport.clientHeight * maxHeightPercent, element.clientHeight);
3398
+ height = Math.min(height, this.viewport.clientHeight - minDistance);
3399
+ this.root.style.height = height + 'px';
3400
+ element.style.top = '0px';
3401
+ this.content = {
3402
+ element,
3403
+ height
3404
+ };
3405
+ }
3406
+ onWheel(e) {
3407
+ e.stopPropagation();
3408
+ if (this.content) {
3409
+ const delta = e.deltaY > 0 ? -25 : 25;
3410
+ const scrollTop = this.getScrollTop();
3411
+ this.setScrollTop(scrollTop + delta);
3412
+ }
3413
+ }
3414
+ startScroll(startPosition) {
3415
+ if (!this.scroll) {
3416
+ window.addEventListener('touchmove', this.onTouchMove, listenerOptions);
3417
+ window.addEventListener('mousemove', this.onMouseMove, false);
3418
+ window.addEventListener('touchend', this.onTouchEnd, listenerOptions);
3419
+ window.addEventListener('mouseup', this.onMouseUp, false);
3420
+ }
3421
+ this.scroll = {
3422
+ startPositionY: startPosition.y,
3423
+ startScrollTop: this.getScrollTop()
3424
+ };
3425
+ }
3426
+ moveScroll(position) {
3427
+ if (this.scroll) {
3428
+ const delta = position.y - this.scroll.startPositionY;
3429
+ this.setScrollTop(this.scroll.startScrollTop + delta);
3430
+ }
3431
+ }
3432
+ stopScroll() {
3433
+ if (this.scroll) {
3434
+ window.removeEventListener('touchmove', this.onTouchMove, listenerOptions);
3435
+ window.removeEventListener('mousemove', this.onMouseMove, false);
3436
+ window.removeEventListener('touchend', this.onTouchEnd, listenerOptions);
3437
+ window.removeEventListener('mouseup', this.onMouseUp, false);
3438
+ this.scroll = undefined;
3439
+ }
3440
+ }
3441
+ getScrollTop() {
3442
+ if (this.content && this.content.element.style.top) {
3443
+ return parseInt(this.content.element.style.top);
3444
+ }
3445
+ return 0;
3446
+ }
3447
+ setScrollTop(scrollTop) {
3448
+ if (this.content) {
3449
+ const max = this.content.element.clientHeight - this.content.height;
3450
+ const limited = Math.max(Math.min(scrollTop, 0), -max);
3451
+ this.content.element.style.top = limited + 'px';
3452
+ }
3453
+ }
3454
+ }
3455
+
3456
+ const regexp = /^[a-zA-Z][a-zA-Z0-9_-]+$/;
3457
+ class StepTypeValidator {
3458
+ static validate(type) {
3459
+ if (!regexp.test(type)) {
3460
+ throw new Error(`Step type "${type}" contains not allowed characters`);
3461
+ }
3462
+ }
3463
+ }
3464
+
3465
+ class ToolboxItemView {
3466
+ static create(parent, step, api) {
3467
+ const label = api.getLabel(step);
3468
+ const root = Dom.element('div', {
3469
+ class: `sqd-toolbox-item sqd-type-${step.type}`,
3470
+ title: label
3471
+ });
3472
+ const iconUrl = api.tryGetIconUrl(step);
3473
+ const icon = Dom.element('div', {
3474
+ class: 'sqd-toolbox-item-icon'
3475
+ });
3476
+ if (iconUrl) {
3477
+ const iconImage = Dom.element('img', {
3478
+ class: 'sqd-toolbox-item-icon-image',
3479
+ src: iconUrl
3480
+ });
3481
+ icon.appendChild(iconImage);
3482
+ }
3483
+ else {
3484
+ icon.classList.add('sqd-no-icon');
3485
+ }
3486
+ const text = Dom.element('div', {
3487
+ class: 'sqd-toolbox-item-text'
3488
+ });
3489
+ text.textContent = label;
3490
+ root.appendChild(icon);
3491
+ root.appendChild(text);
3492
+ parent.appendChild(root);
3493
+ return new ToolboxItemView(root);
3494
+ }
3495
+ constructor(root) {
3496
+ this.root = root;
3497
+ }
3498
+ bindMousedown(handler) {
3499
+ this.root.addEventListener('mousedown', handler, false);
3500
+ }
3501
+ bindTouchstart(handler) {
3502
+ this.root.addEventListener('touchstart', handler, false);
3503
+ }
3504
+ bindContextMenu(handler) {
3505
+ this.root.addEventListener('contextmenu', handler, false);
3506
+ }
3507
+ }
3508
+
3509
+ class ToolboxItem {
3510
+ static create(parent, step, api) {
3511
+ StepTypeValidator.validate(step.type);
3512
+ const view = ToolboxItemView.create(parent, step, api);
3513
+ const item = new ToolboxItem(step, api);
3514
+ view.bindMousedown(e => item.onMousedown(e));
3515
+ view.bindTouchstart(e => item.onTouchstart(e));
3516
+ view.bindContextMenu(e => item.onContextMenu(e));
3517
+ return item;
3518
+ }
3519
+ constructor(step, api) {
3520
+ this.step = step;
3521
+ this.api = api;
3522
+ }
3523
+ onTouchstart(e) {
3524
+ e.preventDefault();
3525
+ if (e.touches.length === 1) {
3526
+ e.stopPropagation();
3527
+ this.tryDrag(readTouchPosition(e));
3528
+ }
3529
+ }
3530
+ onMousedown(e) {
3531
+ e.stopPropagation();
3532
+ const isPrimaryButton = e.button === 0;
3533
+ if (isPrimaryButton) {
3534
+ this.tryDrag(readMousePosition(e));
3535
+ }
3536
+ }
3537
+ onContextMenu(e) {
3538
+ e.preventDefault();
3539
+ }
3540
+ tryDrag(position) {
3541
+ this.api.tryDrag(position, this.step);
3542
+ }
3543
+ }
3544
+
3545
+ class ToolboxView {
3546
+ static create(parent, api) {
3547
+ const root = Dom.element('div', {
3548
+ class: 'sqd-toolbox'
3549
+ });
3550
+ const header = Dom.element('div', {
3551
+ class: 'sqd-toolbox-header'
3552
+ });
3553
+ const headerTitle = Dom.element('div', {
3554
+ class: 'sqd-toolbox-header-title'
3555
+ });
3556
+ headerTitle.innerText = 'Toolbox';
3557
+ const body = Dom.element('div', {
3558
+ class: 'sqd-toolbox-body'
3559
+ });
3560
+ const filterInput = Dom.element('input', {
3561
+ class: 'sqd-toolbox-filter',
3562
+ type: 'text',
3563
+ placeholder: 'Search...'
3564
+ });
3565
+ root.appendChild(header);
3566
+ root.appendChild(body);
3567
+ header.appendChild(headerTitle);
3568
+ body.appendChild(filterInput);
3569
+ parent.appendChild(root);
3570
+ const scrollBoxView = ScrollBoxView.create(body, parent);
3571
+ return new ToolboxView(header, body, filterInput, scrollBoxView, api);
3572
+ }
3573
+ constructor(header, body, filterInput, scrollBoxView, api) {
3574
+ this.header = header;
3575
+ this.body = body;
3576
+ this.filterInput = filterInput;
3577
+ this.scrollBoxView = scrollBoxView;
3578
+ this.api = api;
3579
+ }
3580
+ bindToggleClick(handler) {
3581
+ function forward(e) {
3582
+ e.preventDefault();
3583
+ handler();
3584
+ }
3585
+ this.header.addEventListener('click', forward, false);
3586
+ }
3587
+ bindFilterInputChange(handler) {
3588
+ function forward(e) {
3589
+ handler(e.target.value);
3590
+ }
3591
+ this.filterInput.addEventListener('keyup', forward, false);
3592
+ this.filterInput.addEventListener('blur', forward, false);
3593
+ }
3594
+ setIsCollapsed(isCollapsed) {
3595
+ Dom.toggleClass(this.body, isCollapsed, 'sqd-hidden');
3596
+ if (this.headerToggleIcon) {
3597
+ this.header.removeChild(this.headerToggleIcon);
3598
+ }
3599
+ this.headerToggleIcon = Icons.createSvg('sqd-toolbox-toggle-icon', isCollapsed ? Icons.expand : Icons.close);
3600
+ this.header.appendChild(this.headerToggleIcon);
3601
+ if (!isCollapsed) {
3602
+ this.scrollBoxView.refresh();
3603
+ }
3604
+ }
3605
+ setGroups(groups) {
3606
+ const list = Dom.element('div');
3607
+ groups.forEach(group => {
3608
+ const groupTitle = Dom.element('div', {
3609
+ class: 'sqd-toolbox-group-title'
3610
+ });
3611
+ groupTitle.innerText = group.name;
3612
+ list.appendChild(groupTitle);
3613
+ group.steps.forEach(s => ToolboxItem.create(list, s, this.api));
3614
+ });
3615
+ this.scrollBoxView.setContent(list);
3616
+ }
3617
+ destroy() {
3618
+ this.scrollBoxView.destroy();
3619
+ }
3620
+ }
3621
+
3622
+ class Toolbox {
3623
+ static create(root, api) {
3624
+ const view = ToolboxView.create(root, api);
3625
+ const toolbox = new Toolbox(view, api);
3626
+ toolbox.render();
3627
+ toolbox.onIsCollapsedChanged();
3628
+ view.bindToggleClick(() => toolbox.onToggleClicked());
3629
+ view.bindFilterInputChange(v => toolbox.onFilterInputChanged(v));
3630
+ api.subscribeIsCollapsed(() => toolbox.onIsCollapsedChanged());
3631
+ return toolbox;
3632
+ }
3633
+ constructor(view, api) {
3634
+ this.view = view;
3635
+ this.api = api;
3636
+ }
3637
+ destroy() {
3638
+ this.view.destroy();
3639
+ }
3640
+ render() {
3641
+ const groups = this.api.filterGroups(this.filter);
3642
+ this.view.setGroups(groups);
3643
+ }
3644
+ onIsCollapsedChanged() {
3645
+ this.view.setIsCollapsed(this.api.isCollapsed());
3646
+ }
3647
+ onToggleClicked() {
3648
+ this.api.toggleIsCollapsed();
3649
+ }
3650
+ onFilterInputChanged(value) {
3651
+ this.filter = value.toLowerCase();
3652
+ this.render();
3653
+ }
3654
+ }
3655
+
3656
+ class ToolboxExtension {
3657
+ create(root, api) {
3658
+ return Toolbox.create(root, api.toolbox);
3659
+ }
3660
+ }
3661
+
3662
+ const defaultConfiguration$4 = {
3663
+ view: {
3664
+ paddingTop: 20,
3665
+ paddingX: 20,
3666
+ inputSize: 18,
3667
+ inputIconSize: 14,
3668
+ label: {
3669
+ height: 22,
3670
+ paddingX: 10,
3671
+ minWidth: 50,
3672
+ radius: 10
3673
+ }
3674
+ }
3675
+ };
3676
+ class ContainerStepExtension {
3677
+ static create(configuration) {
3678
+ return new ContainerStepExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$4);
3679
+ }
3680
+ constructor(configuration) {
3681
+ this.configuration = configuration;
3682
+ this.componentType = 'container';
3683
+ this.createComponentView = createContainerStepComponentViewFactory(this.configuration.view);
3684
+ }
3685
+ }
3686
+
3687
+ class DefaultPlaceholderControllerExtension {
3688
+ create() {
3689
+ return {
3690
+ canCreate: () => true
3691
+ };
3692
+ }
3693
+ }
3694
+
3695
+ const defaultConfiguration$3 = {
3696
+ gapWidth: 100,
3697
+ gapHeight: 24,
3698
+ radius: 6,
3699
+ iconSize: 16
3700
+ };
3701
+ class RectPlaceholderExtension {
3702
+ static create(configuration) {
3703
+ return new RectPlaceholderExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$3);
3704
+ }
3705
+ constructor(configuration) {
3706
+ this.configuration = configuration;
3707
+ this.gapSize = new Vector(this.configuration.gapWidth, this.configuration.gapHeight);
3708
+ }
3709
+ createForGap(parent, parentSequence, index) {
3710
+ return RectPlaceholder.create(parent, this.gapSize, exports.PlaceholderDirection.none, parentSequence, index, this.configuration);
3711
+ }
3712
+ createForArea(parent, size, direction, parentSequence, index) {
3713
+ return RectPlaceholder.create(parent, size, direction, parentSequence, index, this.configuration);
3714
+ }
3715
+ }
3716
+
3717
+ const SIZE = 30;
3718
+ const DEFAULT_ICON_SIZE = 22;
3719
+ const FOLDER_ICON_SIZE = 18;
3720
+ class StartStopRootComponentView {
3721
+ static create(parent, sequence, parentPlaceIndicator, context) {
3722
+ const g = Dom.svg('g', {
3723
+ class: 'sqd-root-start-stop'
3724
+ });
3725
+ parent.appendChild(g);
3726
+ const sequenceComponent = DefaultSequenceComponent.create(g, {
3727
+ sequence,
3728
+ depth: 0,
3729
+ isInputConnected: true,
3730
+ isOutputConnected: true
3731
+ }, context);
3732
+ const view = sequenceComponent.view;
3733
+ const x = view.joinX - SIZE / 2;
3734
+ const endY = SIZE + view.height;
3735
+ const iconSize = parentPlaceIndicator ? FOLDER_ICON_SIZE : DEFAULT_ICON_SIZE;
3736
+ const startCircle = createCircle(parentPlaceIndicator ? Icons.folder : Icons.play, iconSize);
3737
+ Dom.translate(startCircle, x, 0);
3738
+ g.appendChild(startCircle);
3739
+ Dom.translate(view.g, 0, SIZE);
3740
+ const endCircle = createCircle(parentPlaceIndicator ? Icons.folder : Icons.stop, iconSize);
3741
+ Dom.translate(endCircle, x, endY);
3742
+ g.appendChild(endCircle);
3743
+ let startPlaceholder = null;
3744
+ let endPlaceholder = null;
3745
+ if (parentPlaceIndicator) {
3746
+ const size = new Vector(SIZE, SIZE);
3747
+ startPlaceholder = context.services.placeholder.createForArea(g, size, exports.PlaceholderDirection.out, parentPlaceIndicator.sequence, parentPlaceIndicator.index);
3748
+ endPlaceholder = context.services.placeholder.createForArea(g, size, exports.PlaceholderDirection.out, parentPlaceIndicator.sequence, parentPlaceIndicator.index);
3749
+ Dom.translate(startPlaceholder.view.g, x, 0);
3750
+ Dom.translate(endPlaceholder.view.g, x, endY);
3751
+ }
3752
+ const badges = Badges.createForRoot(g, new Vector(x + SIZE, 0), context);
3753
+ return new StartStopRootComponentView(g, view.width, view.height + SIZE * 2, view.joinX, sequenceComponent, startPlaceholder, endPlaceholder, badges);
3754
+ }
3755
+ constructor(g, width, height, joinX, component, startPlaceholder, endPlaceholder, badges) {
3756
+ this.g = g;
3757
+ this.width = width;
3758
+ this.height = height;
3759
+ this.joinX = joinX;
3760
+ this.component = component;
3761
+ this.startPlaceholder = startPlaceholder;
3762
+ this.endPlaceholder = endPlaceholder;
3763
+ this.badges = badges;
3764
+ }
3765
+ destroy() {
3766
+ var _a;
3767
+ (_a = this.g.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.g);
3768
+ }
3769
+ }
3770
+ function createCircle(d, iconSize) {
3771
+ const r = SIZE / 2;
3772
+ const circle = Dom.svg('circle', {
3773
+ class: 'sqd-root-start-stop-circle',
3774
+ cx: r,
3775
+ cy: r,
3776
+ r: r
3777
+ });
3778
+ const g = Dom.svg('g');
3779
+ g.appendChild(circle);
3780
+ const offset = (SIZE - iconSize) / 2;
3781
+ const icon = Icons.appendPath(g, 'sqd-root-start-stop-icon', d, iconSize);
3782
+ Dom.translate(icon, offset, offset);
3783
+ return g;
3784
+ }
3785
+
3786
+ class StartStopRootComponent {
3787
+ static create(parentElement, sequence, parentPlaceIndicator, context) {
3788
+ const view = StartStopRootComponentView.create(parentElement, sequence, parentPlaceIndicator, context);
3789
+ return new StartStopRootComponent(view);
3790
+ }
3791
+ constructor(view) {
3792
+ this.view = view;
3793
+ }
3794
+ resolveClick(click) {
3795
+ return this.view.component.resolveClick(click);
3796
+ }
3797
+ findById(stepId) {
3798
+ return this.view.component.findById(stepId);
3799
+ }
3800
+ getPlaceholders(result) {
3801
+ this.view.component.getPlaceholders(result);
3802
+ if (this.view.startPlaceholder && this.view.endPlaceholder) {
3803
+ result.push(this.view.startPlaceholder);
3804
+ result.push(this.view.endPlaceholder);
3805
+ }
3806
+ }
3807
+ setIsDragging(isDragging) {
3808
+ this.view.component.setIsDragging(isDragging);
3809
+ if (this.view.startPlaceholder && this.view.endPlaceholder) {
3810
+ this.view.startPlaceholder.setIsVisible(isDragging);
3811
+ this.view.endPlaceholder.setIsVisible(isDragging);
3812
+ }
3813
+ }
3814
+ updateBadges(result) {
3815
+ this.view.badges.update(result);
3816
+ this.view.component.updateBadges(result);
3817
+ }
3818
+ }
3819
+
3820
+ class StartStopRootComponentExtension {
3821
+ constructor() {
3822
+ this.create = StartStopRootComponent.create;
3823
+ }
3824
+ }
3825
+
3826
+ const defaultConfiguration$2 = {
3827
+ view: {
3828
+ minContainerWidth: 40,
3829
+ paddingX: 20,
3830
+ paddingTop: 20,
3831
+ connectionHeight: 16,
3832
+ inputSize: 18,
3833
+ inputIconSize: 14,
3834
+ branchNameLabel: {
3835
+ height: 22,
3836
+ paddingX: 10,
3837
+ minWidth: 50,
3838
+ radius: 10
3839
+ },
3840
+ nameLabel: {
3841
+ height: 22,
3842
+ paddingX: 10,
3843
+ minWidth: 50,
3844
+ radius: 10
3845
+ }
3846
+ }
3847
+ };
3848
+ class SwitchStepExtension {
3849
+ static create(configuration) {
3850
+ return new SwitchStepExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$2);
3851
+ }
3852
+ constructor(configuration) {
3853
+ this.configuration = configuration;
3854
+ this.componentType = 'switch';
3855
+ this.createComponentView = createSwitchStepComponentViewFactory(this.configuration.view);
3856
+ }
3857
+ }
3858
+
3859
+ const defaultConfiguration$1 = {
3860
+ view: {
3861
+ paddingLeft: 12,
3862
+ paddingRight: 12,
3863
+ paddingY: 10,
3864
+ textMarginLeft: 12,
3865
+ minTextWidth: 70,
3866
+ iconSize: 22,
3867
+ radius: 5,
3868
+ inputSize: 14,
3869
+ outputSize: 10
3870
+ }
3871
+ };
3872
+ class TaskStepExtension {
3873
+ static create(configuration) {
3874
+ return new TaskStepExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$1);
3875
+ }
3876
+ constructor(configuration) {
3877
+ this.configuration = configuration;
3878
+ this.componentType = 'task';
3879
+ this.createComponentView = createTaskStepComponentViewFactory(false, this.configuration.view);
3880
+ }
3881
+ }
3882
+
3883
+ class DefaultSequenceComponentExtension {
3884
+ constructor() {
3885
+ this.create = DefaultSequenceComponent.create;
3886
+ }
3887
+ }
3888
+
3889
+ class DefaultStepComponentViewWrapperExtension {
3890
+ constructor() {
3891
+ this.wrap = (view) => view;
3892
+ }
3893
+ }
3894
+
3895
+ class LineGrid {
3896
+ static create(size) {
3897
+ const path = Dom.svg('path', {
3898
+ class: 'sqd-grid-path',
3899
+ fill: 'none'
3900
+ });
3901
+ return new LineGrid(size, path);
3902
+ }
3903
+ constructor(size, element) {
3904
+ this.size = size;
3905
+ this.element = element;
3906
+ }
3907
+ setScale(_, scaledSize) {
3908
+ Dom.attrs(this.element, {
3909
+ d: `M ${scaledSize.x} 0 L 0 0 0 ${scaledSize.y}`
3910
+ });
3911
+ }
3912
+ }
3913
+
3914
+ const defaultConfiguration = {
3915
+ gridSizeX: 48,
3916
+ gridSizeY: 48
3917
+ };
3918
+ class LineGridExtension {
3919
+ static create(configuration) {
3920
+ return new LineGridExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration);
3921
+ }
3922
+ constructor(configuration) {
3923
+ this.configuration = configuration;
3924
+ }
3925
+ create() {
3926
+ const size = new Vector(this.configuration.gridSizeX, this.configuration.gridSizeY);
3927
+ return LineGrid.create(size);
3928
+ }
3929
+ }
3930
+
3931
+ class ServicesResolver {
3932
+ static resolve(extensions, configuration) {
3933
+ const services = {};
3934
+ merge(services, extensions || []);
3935
+ setDefault(services, configuration);
3936
+ return services;
3937
+ }
3938
+ }
3939
+ function merge(services, extensions) {
3940
+ for (const ext of extensions) {
3941
+ if (ext.steps) {
3942
+ services.steps = (services.steps || []).concat(ext.steps);
3943
+ }
3944
+ if (ext.stepComponentViewWrapper) {
3945
+ services.stepComponentViewWrapper = ext.stepComponentViewWrapper;
3946
+ }
3947
+ if (ext.badges) {
3948
+ services.badges = (services.badges || []).concat(ext.badges);
3949
+ }
3950
+ if (ext.uiComponents) {
3951
+ services.uiComponents = (services.uiComponents || []).concat(ext.uiComponents);
3952
+ }
3953
+ if (ext.draggedComponent) {
3954
+ services.draggedComponent = ext.draggedComponent;
3955
+ }
3956
+ if (ext.wheelController) {
3957
+ services.wheelController = ext.wheelController;
3958
+ }
3959
+ if (ext.placeholderController) {
3960
+ services.placeholderController = ext.placeholderController;
3961
+ }
3962
+ if (ext.placeholder) {
3963
+ services.placeholder = ext.placeholder;
3964
+ }
3965
+ if (ext.viewportController) {
3966
+ services.viewportController = ext.viewportController;
3967
+ }
3968
+ if (ext.grid) {
3969
+ services.grid = ext.grid;
3970
+ }
3971
+ if (ext.rootComponent) {
3972
+ services.rootComponent = ext.rootComponent;
3973
+ }
3974
+ if (ext.sequenceComponent) {
3975
+ services.sequenceComponent = ext.sequenceComponent;
3976
+ }
3977
+ if (ext.daemons) {
3978
+ services.daemons = (services.daemons || []).concat(ext.daemons);
3979
+ }
3980
+ }
3981
+ }
3982
+ function setDefault(services, configuration) {
3983
+ if (!services.steps) {
3984
+ services.steps = [];
3985
+ }
3986
+ services.steps.push(ContainerStepExtension.create());
3987
+ services.steps.push(SwitchStepExtension.create());
3988
+ services.steps.push(TaskStepExtension.create());
3989
+ if (!services.stepComponentViewWrapper) {
3990
+ services.stepComponentViewWrapper = new DefaultStepComponentViewWrapperExtension();
3991
+ }
3992
+ if (!services.badges) {
3993
+ services.badges = [];
3994
+ }
3995
+ if (findValidationBadgeIndex(services.badges) < 0) {
3996
+ services.badges.push(ValidationErrorBadgeExtension.create());
3997
+ }
3998
+ if (!services.draggedComponent) {
3999
+ services.draggedComponent = new DefaultDraggedComponentExtension();
4000
+ }
4001
+ if (!services.uiComponents) {
4002
+ services.uiComponents = [];
4003
+ }
4004
+ if (configuration.controlBar) {
4005
+ services.uiComponents.push(new ControlBarExtension());
4006
+ }
4007
+ if (configuration.editors) {
4008
+ services.uiComponents.push(new SmartEditorExtension(configuration.editors));
4009
+ }
4010
+ if (configuration.toolbox) {
4011
+ services.uiComponents.push(new ToolboxExtension());
4012
+ }
4013
+ if (!services.wheelController) {
4014
+ services.wheelController = new ClassicWheelControllerExtension();
4015
+ }
4016
+ if (!services.placeholderController) {
4017
+ services.placeholderController = new DefaultPlaceholderControllerExtension();
4018
+ }
4019
+ if (!services.placeholder) {
4020
+ services.placeholder = RectPlaceholderExtension.create();
4021
+ }
4022
+ if (!services.viewportController) {
4023
+ services.viewportController = new DefaultViewportControllerExtension();
4024
+ }
4025
+ if (!services.grid) {
4026
+ services.grid = LineGridExtension.create();
4027
+ }
4028
+ if (!services.rootComponent) {
4029
+ services.rootComponent = new StartStopRootComponentExtension();
4030
+ }
4031
+ if (!services.sequenceComponent) {
4032
+ services.sequenceComponent = new DefaultSequenceComponentExtension();
4033
+ }
4034
+ if (!services.daemons) {
4035
+ services.daemons = [];
4036
+ }
4037
+ services.daemons.push(new KeyboardDaemonExtension());
4038
+ }
4039
+
4040
+ function throwDepreciatedError(propertyName, groupName) {
4041
+ throw new Error(`The "${propertyName}" property in the "${groupName}" configuration is depreciated`);
4042
+ }
4043
+ function validateConfiguration(configuration) {
4044
+ if (configuration.controlBar === undefined) {
4045
+ throw new Error('The "controlBar" property is not defined in the configuration');
4046
+ }
4047
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4048
+ if (configuration.toolbox && configuration.toolbox.isHidden !== undefined) {
4049
+ throwDepreciatedError('isHidden', 'toolbox');
4050
+ }
4051
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4052
+ if (configuration.editors && configuration.editors.isHidden !== undefined) {
4053
+ throwDepreciatedError('isHidden', 'editors');
4054
+ }
4055
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4056
+ if (configuration.steps.validator) {
4057
+ throwDepreciatedError('validator', 'steps');
4058
+ }
4059
+ }
4060
+
4061
+ class Designer {
4062
+ /**
4063
+ * Creates a designer.
4064
+ * @param placeholder Placeholder where the designer will be attached.
4065
+ * @param startDefinition Start definition of a flow.
4066
+ * @param configuration Designer's configuration.
4067
+ * @returns An instance of the designer.
4068
+ */
4069
+ static create(placeholder, startDefinition, configuration) {
4070
+ if (!placeholder) {
4071
+ throw new Error('Placeholder is not set');
4072
+ }
4073
+ if (!isElementAttached(placeholder)) {
4074
+ throw new Error('Placeholder is not attached to the DOM');
4075
+ }
4076
+ if (!startDefinition) {
4077
+ throw new Error('Start definition is not set');
4078
+ }
4079
+ if (!configuration) {
4080
+ throw new Error('Configuration is not set');
4081
+ }
4082
+ const config = configuration;
4083
+ validateConfiguration(config);
4084
+ const services = ServicesResolver.resolve(configuration.extensions, config);
4085
+ const designerContext = DesignerContext.create(placeholder, startDefinition, config, services);
4086
+ const designerApi = DesignerApi.create(designerContext);
4087
+ const view = DesignerView.create(placeholder, designerContext, designerApi);
4088
+ const designer = new Designer(view, designerContext.state, designerContext.definitionWalker, designerApi);
4089
+ view.workspace.onReady.subscribe(() => designer.onReady.forward());
4090
+ designerContext.state.onDefinitionChanged.subscribe(() => {
4091
+ setTimeout(() => designer.onDefinitionChanged.forward(designerContext.state.definition));
4092
+ });
4093
+ designerContext.state.onSelectedStepIdChanged.subscribe(() => designer.onSelectedStepIdChanged.forward(designerContext.state.selectedStepId));
4094
+ designer.state.onIsToolboxCollapsedChanged.subscribe(isCollapsed => {
4095
+ designer.onIsToolboxCollapsedChanged.forward(isCollapsed);
4096
+ });
4097
+ designer.state.onIsEditorCollapsedChanged.subscribe(isCollapsed => {
4098
+ designer.onIsEditorCollapsedChanged.forward(isCollapsed);
4099
+ });
4100
+ return designer;
4101
+ }
4102
+ constructor(view, state, walker, api) {
4103
+ this.view = view;
4104
+ this.state = state;
4105
+ this.walker = walker;
4106
+ this.api = api;
4107
+ /**
4108
+ * @description Fires when the designer is initialized and ready to use.
4109
+ */
4110
+ this.onReady = new SimpleEvent();
4111
+ /**
4112
+ * @description Fires when the definition has changed.
4113
+ */
4114
+ this.onDefinitionChanged = new SimpleEvent();
4115
+ /**
4116
+ * @description Fires when the selected step has changed.
4117
+ */
4118
+ this.onSelectedStepIdChanged = new SimpleEvent();
4119
+ /**
4120
+ * @description Fires when the toolbox is collapsed or expanded.
4121
+ */
4122
+ this.onIsToolboxCollapsedChanged = new SimpleEvent();
4123
+ /**
4124
+ * @description Fires when the editor is collapsed or expanded.
4125
+ */
4126
+ this.onIsEditorCollapsedChanged = new SimpleEvent();
4127
+ }
4128
+ /**
4129
+ * @returns the current definition of the workflow.
4130
+ */
4131
+ getDefinition() {
4132
+ return this.state.definition;
4133
+ }
4134
+ /**
4135
+ * @returns the validation result of the current definition.
4136
+ */
4137
+ isValid() {
4138
+ return this.view.workspace.isValid;
4139
+ }
4140
+ /**
4141
+ * @returns the readonly flag.
4142
+ */
4143
+ isReadonly() {
4144
+ return this.state.isReadonly;
4145
+ }
4146
+ /**
4147
+ * @description Changes the readonly flag.
4148
+ */
4149
+ setIsReadonly(isReadonly) {
4150
+ this.state.setIsReadonly(isReadonly);
4151
+ }
4152
+ /**
4153
+ * @returns current selected step id or `null` if nothing is selected.
4154
+ */
4155
+ getSelectedStepId() {
4156
+ return this.state.selectedStepId;
4157
+ }
4158
+ /**
4159
+ * @description Selects a step by the id.
4160
+ */
4161
+ selectStepById(stepId) {
4162
+ this.state.setSelectedStepId(stepId);
4163
+ }
4164
+ /**
4165
+ * @description Unselects the selected step.
4166
+ */
4167
+ clearSelectedStep() {
4168
+ this.state.setSelectedStepId(null);
4169
+ }
4170
+ /**
4171
+ * @description Moves the viewport to the step with the animation.
4172
+ */
4173
+ moveViewportToStep(stepId) {
4174
+ this.api.viewport.moveViewportToStep(stepId);
4175
+ }
4176
+ /**
4177
+ * @deprecated Use `moveViewportToStep` instead.
4178
+ */
4179
+ moveViewPortToStep(stepId) {
4180
+ this.moveViewportToStep(stepId);
4181
+ }
4182
+ /**
4183
+ * @description Rerender the root component and all its children.
4184
+ */
4185
+ updateRootComponent() {
4186
+ this.api.workspace.updateRootComponent();
4187
+ }
4188
+ /**
4189
+ * @description Updates all badges.
4190
+ */
4191
+ updateBadges() {
4192
+ this.api.workspace.updateBadges();
4193
+ }
4194
+ /**
4195
+ * @returns a flag that indicates whether the toolbox is collapsed.
4196
+ */
4197
+ isToolboxCollapsed() {
4198
+ return this.state.isToolboxCollapsed;
4199
+ }
4200
+ /**
4201
+ * @description Sets a flag that indicates whether the toolbox is collapsed.
4202
+ */
4203
+ setIsToolboxCollapsed(isCollapsed) {
4204
+ this.state.setIsToolboxCollapsed(isCollapsed);
4205
+ }
4206
+ /**
4207
+ * @returns a flag that indicates whether the editor is collapsed.
4208
+ */
4209
+ isEditorCollapsed() {
4210
+ return this.state.isEditorCollapsed;
4211
+ }
4212
+ /**
4213
+ * @description Sets a flag that indicates whether the editor is collapsed.
4214
+ */
4215
+ setIsEditorCollapsed(isCollapsed) {
4216
+ this.state.setIsEditorCollapsed(isCollapsed);
4217
+ }
4218
+ /**
4219
+ * @param needle A step, a sequence or a step id.
4220
+ * @returns parent steps and branch names.
4221
+ */
4222
+ getStepParents(needle) {
4223
+ return this.walker.getParents(this.state.definition, needle);
4224
+ }
4225
+ /**
4226
+ * @description Destroys the designer and deletes all nodes from the placeholder.
4227
+ */
4228
+ destroy() {
4229
+ this.view.destroy();
4230
+ }
4231
+ }
4232
+
4233
+ class LineGridDesignerExtension {
4234
+ static create(configuration) {
4235
+ const grid = LineGridExtension.create(configuration);
4236
+ return new LineGridDesignerExtension(grid);
4237
+ }
4238
+ constructor(grid) {
4239
+ this.grid = grid;
4240
+ }
4241
+ }
4242
+
4243
+ class StepsDesignerExtension {
4244
+ static create(configuration) {
4245
+ const steps = [];
4246
+ if (configuration.container) {
4247
+ steps.push(ContainerStepExtension.create(configuration.container));
4248
+ }
4249
+ if (configuration.switch) {
4250
+ steps.push(SwitchStepExtension.create(configuration.switch));
4251
+ }
4252
+ if (configuration.task) {
4253
+ steps.push(TaskStepExtension.create(configuration.task));
4254
+ }
4255
+ return new StepsDesignerExtension(steps);
4256
+ }
4257
+ constructor(steps) {
4258
+ this.steps = steps;
4259
+ }
4260
+ }
4261
+ /**
4262
+ * @deprecated Use `StepsDesignerExtension` instead.
4263
+ */
4264
+ class StepsExtension extends StepsDesignerExtension {
4265
+ }
4266
+
4267
+ exports.Badges = Badges;
4268
+ exports.CenteredViewportCalculator = CenteredViewportCalculator;
4269
+ exports.ClassicWheelControllerExtension = ClassicWheelControllerExtension;
4270
+ exports.ComponentContext = ComponentContext;
4271
+ exports.ControlBarApi = ControlBarApi;
4272
+ exports.DefaultSequenceComponent = DefaultSequenceComponent;
4273
+ exports.DefaultSequenceComponentView = DefaultSequenceComponentView;
4274
+ exports.DefaultViewportController = DefaultViewportController;
4275
+ exports.DefaultViewportControllerExtension = DefaultViewportControllerExtension;
4276
+ exports.Designer = Designer;
4277
+ exports.DesignerApi = DesignerApi;
4278
+ exports.DesignerContext = DesignerContext;
4279
+ exports.DesignerState = DesignerState;
4280
+ exports.Dom = Dom;
4281
+ exports.Editor = Editor;
4282
+ exports.EditorApi = EditorApi;
4283
+ exports.Icons = Icons;
4284
+ exports.InputView = InputView;
4285
+ exports.JoinView = JoinView;
4286
+ exports.LabelView = LabelView;
4287
+ exports.LineGridDesignerExtension = LineGridDesignerExtension;
4288
+ exports.ObjectCloner = ObjectCloner;
4289
+ exports.OutputView = OutputView;
4290
+ exports.PathBarApi = PathBarApi;
4291
+ exports.QuantifiedScaleViewportCalculator = QuantifiedScaleViewportCalculator;
4292
+ exports.RectPlaceholder = RectPlaceholder;
4293
+ exports.RectPlaceholderView = RectPlaceholderView;
4294
+ exports.RegionView = RegionView;
4295
+ exports.ServicesResolver = ServicesResolver;
4296
+ exports.SimpleEvent = SimpleEvent;
4297
+ exports.StepComponent = StepComponent;
4298
+ exports.StepExtensionResolver = StepExtensionResolver;
4299
+ exports.StepsDesignerExtension = StepsDesignerExtension;
4300
+ exports.StepsExtension = StepsExtension;
4301
+ exports.ToolboxApi = ToolboxApi;
4302
+ exports.Uid = Uid;
4303
+ exports.ValidationErrorBadgeExtension = ValidationErrorBadgeExtension;
4304
+ exports.Vector = Vector;
4305
+ exports.WorkspaceApi = WorkspaceApi;
4306
+ exports.createContainerStepComponentViewFactory = createContainerStepComponentViewFactory;
4307
+ exports.createSwitchStepComponentViewFactory = createSwitchStepComponentViewFactory;
4308
+ exports.createTaskStepComponentViewFactory = createTaskStepComponentViewFactory;
4309
+ exports.race = race;
4310
+ Object.keys(sequentialWorkflowModel).forEach(function (k) {
4311
+ if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
4312
+ enumerable: true,
4313
+ get: function () { return sequentialWorkflowModel[k]; }
4314
+ });
4315
+ });