sequential-workflow-designer 0.10.3

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