@node-projects/web-component-designer 0.0.87 → 0.0.88

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,734 @@
1
+ import { EventNames } from "../../../enums/EventNames";
2
+ import { InstanceServiceContainer } from '../../services/InstanceServiceContainer';
3
+ import { UndoService } from '../../services/undoService/UndoService';
4
+ import { SelectionService } from '../../services/selectionService/SelectionService';
5
+ import { DesignItem } from '../../item/DesignItem';
6
+ import { BaseCustomWebComponentLazyAppend, css, html, TypedEvent } from '@node-projects/base-custom-webcomponent';
7
+ import { dragDropFormatNameElementDefinition, dragDropFormatNameBindingObject } from '../../../Constants';
8
+ import { ContentService } from '../../services/contentService/ContentService';
9
+ import { InsertAction } from '../../services/undoService/transactionItems/InsertAction';
10
+ import { Snaplines } from './Snaplines';
11
+ import { ContextMenuHelper } from '../../helper/contextMenu/ContextMenuHelper';
12
+ import { DeleteAction } from '../../services/undoService/transactionItems/DeleteAction';
13
+ import { CommandType } from '../../../commandHandling/CommandType';
14
+ import { DefaultHtmlParserService } from "../../services/htmlParserService/DefaultHtmlParserService";
15
+ import { ExtensionType } from "./extensions/ExtensionType";
16
+ import { ExtensionManager } from "./extensions/ExtensionManager";
17
+ import { NamedTools } from "./tools/NamedTools";
18
+ import { Screenshot } from '../../helper/Screenshot';
19
+ import { dataURItoBlob, exportData } from "../../helper/Helper";
20
+ import { DomHelper } from '@node-projects/base-custom-webcomponent/dist/DomHelper';
21
+ import { OverlayLayer } from "./extensions/OverlayLayer";
22
+ import { OverlayLayerView } from './overlayLayerView';
23
+ export class DesignerCanvas extends BaseCustomWebComponentLazyAppend {
24
+ // Public Properties
25
+ serviceContainer;
26
+ instanceServiceContainer;
27
+ containerBoundingRect;
28
+ outerRect;
29
+ // IPlacementView
30
+ gridSize = 10;
31
+ alignOnGrid = false;
32
+ alignOnSnap = true;
33
+ snapLines;
34
+ overlayLayer;
35
+ rootDesignItem;
36
+ eatEvents;
37
+ transformHelperElement;
38
+ _zoomFactor = 1; //if scale or zoom css property is used this needs to be the value
39
+ _scaleFactor = 1; //if scale css property is used this need to be the scale value
40
+ _canvasOffset = { x: 0, y: 0 };
41
+ get zoomFactor() {
42
+ return this._zoomFactor;
43
+ }
44
+ set zoomFactor(value) {
45
+ this._zoomFactor = value;
46
+ this.zoomFactorChanged();
47
+ }
48
+ get scaleFactor() {
49
+ return this._scaleFactor;
50
+ }
51
+ get canvasOffset() {
52
+ return this._canvasOffset;
53
+ }
54
+ set canvasOffset(value) {
55
+ this._canvasOffset = value;
56
+ this.zoomFactorChanged();
57
+ }
58
+ onContentChanged = new TypedEvent();
59
+ // Private Variables
60
+ _canvas;
61
+ _canvasContainer;
62
+ _outercanvas2;
63
+ _lastHoverDesignItem;
64
+ _onContextMenuBound;
65
+ _pointerEventHandlerBound;
66
+ _firstConnect;
67
+ _onKeyDownBound;
68
+ _onKeyUpBound;
69
+ static style = css `
70
+ :host {
71
+ display: block;
72
+ box-sizing: border-box;
73
+ width: 100%;
74
+ position: relative;
75
+ transform: translateZ(0);
76
+ overflow: hidden;
77
+
78
+ font-family: initial;
79
+ font-size: initial;
80
+ font-weight: initial;
81
+ font-style: initial;
82
+ line-height: initial;
83
+ }
84
+ * {
85
+ touch-action: none;
86
+ }
87
+ #node-projects-designer-canvas-canvas {
88
+ background-color: var(--canvas-background, white);
89
+ /* 10px grid, using http://www.patternify.com/ */
90
+ background-image: url(data:image/png;base64,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);
91
+ background-position: 0px 0px;
92
+ box-sizing: border-box;
93
+ width: 100%;
94
+ height: 100%;
95
+ transform-origin: 0 0;
96
+ }
97
+
98
+ #node-projects-designer-canvas-canvas.dragFileActive {
99
+ outline: blue 4px solid;
100
+ outline-offset: -4px;
101
+ }
102
+
103
+ node-projects-overlay-layer-view {
104
+ box-sizing: border-box;
105
+ width: 100%;
106
+ height: 100%;
107
+ position: absolute;
108
+ top: 0;
109
+ left: 0;
110
+ pointer-events: none;
111
+ overflow: visible;
112
+ user-select: none;
113
+ -webkit-user-select: none;
114
+ z-index: 999999999999;
115
+ }
116
+
117
+ #node-projects-designer-canvas-canvas * {
118
+ cursor: pointer;
119
+ user-select: none;
120
+ -webkit-user-select: none;
121
+ }
122
+
123
+ #transformHelper {
124
+ height: 0;
125
+ width: 0;
126
+ }`;
127
+ static template = html `
128
+ <div style="display: flex;flex-direction: column;width: 100%;height: 100%;">
129
+ <div style="width: 100%;height: 100%;">
130
+ <div id="node-projects-designer-canvas-outercanvas2"
131
+ style="width:100%;height:100%;position:relative;">
132
+ <div id="node-projects-designer-canvas-canvasContainer"
133
+ style="width: 100%;height: 100%;margin: auto;position: absolute;top: 0;/* bottom: 0; does not work with fixed sized when size is bigger then view */left: 0;user-select: none;">
134
+ <div id="node-projects-designer-canvas-canvas" part="canvas" tabindex="0"></div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ <div id="transformHelper"></div>
139
+ </div>`;
140
+ extensionManager;
141
+ _pointerextensions;
142
+ _onDblClickBound;
143
+ constructor() {
144
+ super();
145
+ this._canvas = this._getDomElement('node-projects-designer-canvas-canvas');
146
+ this._canvasContainer = this._getDomElement('node-projects-designer-canvas-canvasContainer');
147
+ this._outercanvas2 = this._getDomElement('node-projects-designer-canvas-outercanvas2');
148
+ this.transformHelperElement = this._getDomElement('transformHelper');
149
+ this._onKeyDownBound = this.onKeyDown.bind(this);
150
+ this._onKeyUpBound = this.onKeyUp.bind(this);
151
+ this._onDblClickBound = this._onDblClick.bind(this);
152
+ this._onContextMenuBound = this._onContextMenu.bind(this);
153
+ this._pointerEventHandlerBound = this._pointerEventHandler.bind(this);
154
+ this._canvas.oncontextmenu = this._onContextMenuBound;
155
+ }
156
+ get designerWidth() {
157
+ return this._canvasContainer.style.width;
158
+ }
159
+ set designerWidth(value) {
160
+ this._canvasContainer.style.width = value;
161
+ this.zoomFactorChanged();
162
+ }
163
+ get designerHeight() {
164
+ return this._canvasContainer.style.height;
165
+ }
166
+ set designerHeight(value) {
167
+ this._canvasContainer.style.height = value;
168
+ this.zoomFactorChanged();
169
+ }
170
+ get designerOffsetWidth() {
171
+ return this._canvasContainer.offsetWidth;
172
+ }
173
+ get designerOffsetHeight() {
174
+ return this._canvasContainer.offsetHeight;
175
+ }
176
+ set additionalStyle(value) {
177
+ if (value) {
178
+ for (let r of value.rules) {
179
+ if (r instanceof CSSStyleRule) {
180
+ let parts = r.selectorText.split(',');
181
+ let t = '';
182
+ for (let p of parts) {
183
+ if (r.selectorText)
184
+ t += ',';
185
+ t += '#canvas ' + p;
186
+ }
187
+ r.selectorText = t;
188
+ }
189
+ }
190
+ this.shadowRoot.adoptedStyleSheets = [this.constructor.style, value];
191
+ }
192
+ else
193
+ this.shadowRoot.adoptedStyleSheets = [this.constructor.style];
194
+ }
195
+ /* --- start IUiCommandHandler --- */
196
+ async executeCommand(command) {
197
+ const modelCommandService = this.serviceContainer.modelCommandService;
198
+ if (modelCommandService) {
199
+ let handeled = await modelCommandService.executeCommand(this, command);
200
+ if (handeled != null)
201
+ return;
202
+ }
203
+ switch (command.type) {
204
+ case CommandType.screenshot:
205
+ {
206
+ if (!this.instanceServiceContainer.selectionService.primarySelection)
207
+ alert("you need to select an element!");
208
+ else {
209
+ if (!Screenshot.screenshotsEnabled) {
210
+ alert("you need to select current tab in next browser dialog, or screenshots will not work correctly");
211
+ }
212
+ const el = this.instanceServiceContainer.selectionService.primarySelection.element;
213
+ const sel = this.instanceServiceContainer.selectionService.selectedElements;
214
+ this.instanceServiceContainer.selectionService.setSelectedElements(null);
215
+ const screenshot = await Screenshot.takeScreenshot(el, el.clientWidth, el.clientHeight);
216
+ await exportData(dataURItoBlob(screenshot), "screenshot.png");
217
+ this.instanceServiceContainer.selectionService.setSelectedElements(sel);
218
+ }
219
+ }
220
+ break;
221
+ case CommandType.setTool:
222
+ {
223
+ this.serviceContainer.globalContext.tool = this.serviceContainer.designerTools.get(command.parameter);
224
+ }
225
+ break;
226
+ case CommandType.setStrokeColor:
227
+ {
228
+ this.serviceContainer.globalContext.strokeColor = command.parameter;
229
+ }
230
+ break;
231
+ case CommandType.setFillBrush:
232
+ {
233
+ this.serviceContainer.globalContext.fillBrush = command.parameter;
234
+ }
235
+ break;
236
+ case CommandType.setStrokeThickness:
237
+ {
238
+ this.serviceContainer.globalContext.strokeThickness = command.parameter;
239
+ }
240
+ break;
241
+ case CommandType.delete:
242
+ this.handleDeleteCommand();
243
+ break;
244
+ case CommandType.undo:
245
+ this.instanceServiceContainer.undoService.undo();
246
+ break;
247
+ case CommandType.redo:
248
+ this.instanceServiceContainer.undoService.redo();
249
+ break;
250
+ case CommandType.copy:
251
+ this.handleCopyCommand();
252
+ break;
253
+ case CommandType.cut:
254
+ this.handleCopyCommand();
255
+ this.handleDeleteCommand();
256
+ break;
257
+ case CommandType.paste:
258
+ this.handlePasteCommand();
259
+ break;
260
+ case CommandType.selectAll:
261
+ this.handleSelectAll();
262
+ break;
263
+ }
264
+ }
265
+ canExecuteCommand(command) {
266
+ const modelCommandService = this.serviceContainer.modelCommandService;
267
+ if (modelCommandService) {
268
+ let handeled = modelCommandService.canExecuteCommand(this, command);
269
+ if (handeled !== null)
270
+ return handeled;
271
+ }
272
+ if (command.type === CommandType.undo) {
273
+ return this.instanceServiceContainer.undoService.canUndo();
274
+ }
275
+ if (command.type === CommandType.redo) {
276
+ return this.instanceServiceContainer.undoService.canRedo();
277
+ }
278
+ if (command.type === CommandType.setTool) {
279
+ return this.serviceContainer.designerTools.has(command.parameter);
280
+ }
281
+ return true;
282
+ }
283
+ /* --- end IUiCommandHandler --- */
284
+ handleSelectAll() {
285
+ this.instanceServiceContainer.selectionService.setSelectedElements(Array.from(this.rootDesignItem.children()));
286
+ }
287
+ async handleCopyCommand() {
288
+ await this.serviceContainer.copyPasteService.copyItems(this.instanceServiceContainer.selectionService.selectedElements);
289
+ }
290
+ async handlePasteCommand() {
291
+ const designItems = await this.serviceContainer.copyPasteService.getPasteItems(this.serviceContainer, this.instanceServiceContainer);
292
+ let grp = this.rootDesignItem.openGroup("Insert");
293
+ if (designItems) {
294
+ for (let di of designItems) {
295
+ this.instanceServiceContainer.undoService.execute(new InsertAction(this.rootDesignItem, this.rootDesignItem.childCount, di));
296
+ }
297
+ const intializationService = this.serviceContainer.intializationService;
298
+ if (intializationService) {
299
+ for (let di of designItems)
300
+ intializationService.init(di);
301
+ }
302
+ this.instanceServiceContainer.selectionService.setSelectedElements(designItems);
303
+ }
304
+ grp.commit();
305
+ this.snapLines.clearSnaplines();
306
+ }
307
+ handleDeleteCommand() {
308
+ let items = this.instanceServiceContainer.selectionService.selectedElements;
309
+ this.instanceServiceContainer.undoService.execute(new DeleteAction(items));
310
+ this.instanceServiceContainer.selectionService.setSelectedElements(null);
311
+ }
312
+ initialize(serviceContainer) {
313
+ this.serviceContainer = serviceContainer;
314
+ this.instanceServiceContainer = new InstanceServiceContainer(this);
315
+ this.instanceServiceContainer.register("undoService", new UndoService(this));
316
+ this.instanceServiceContainer.register("selectionService", new SelectionService);
317
+ this.rootDesignItem = DesignItem.GetOrCreateDesignItem(this._canvas, this.serviceContainer, this.instanceServiceContainer);
318
+ this.instanceServiceContainer.register("contentService", new ContentService(this.rootDesignItem));
319
+ this.extensionManager = new ExtensionManager(this);
320
+ this.overlayLayer = new OverlayLayerView(serviceContainer);
321
+ this.overlayLayer.style.pointerEvents = 'none';
322
+ this._canvasContainer.appendChild(this.overlayLayer);
323
+ this.snapLines = new Snaplines(this.overlayLayer);
324
+ this.snapLines.initialize(this.rootDesignItem);
325
+ if (this.serviceContainer.designerPointerExtensions)
326
+ for (let pe of this.serviceContainer.designerPointerExtensions) {
327
+ if (!this._pointerextensions)
328
+ this._pointerextensions = [];
329
+ this._pointerextensions.push(pe.getExtension(this));
330
+ }
331
+ if (this.children) {
332
+ let children = this.children;
333
+ if (this.children.length == 1 && this.children[0] instanceof HTMLSlotElement) {
334
+ children = this.children[0].assignedElements();
335
+ }
336
+ const parser = this.serviceContainer.getLastServiceWhere('htmlParserService', x => x.constructor == DefaultHtmlParserService);
337
+ this.addDesignItems(parser.createDesignItems(children, this.serviceContainer, this.instanceServiceContainer));
338
+ }
339
+ }
340
+ elementFromPoint(x, y) {
341
+ //@ts-ignore
342
+ return this.shadowRoot.elementFromPoint(x, y);
343
+ }
344
+ connectedCallback() {
345
+ if (!this._firstConnect) {
346
+ this._firstConnect = true;
347
+ this._outercanvas2.addEventListener(EventNames.PointerDown, this._pointerEventHandlerBound);
348
+ this._outercanvas2.addEventListener(EventNames.PointerMove, this._pointerEventHandlerBound);
349
+ this._outercanvas2.addEventListener(EventNames.PointerUp, this._pointerEventHandlerBound);
350
+ this._outercanvas2.addEventListener(EventNames.DragEnter, event => this._onDragEnter(event));
351
+ this._outercanvas2.addEventListener(EventNames.DragLeave, event => this._onDragLeave(event));
352
+ this._outercanvas2.addEventListener(EventNames.DragOver, event => this._onDragOver(event));
353
+ this._outercanvas2.addEventListener(EventNames.Drop, event => this._onDrop(event));
354
+ this._canvas.addEventListener(EventNames.KeyDown, this._onKeyDownBound, true);
355
+ this._canvas.addEventListener(EventNames.KeyUp, this._onKeyUpBound, true);
356
+ this._canvas.addEventListener(EventNames.DblClick, this._onDblClickBound, true);
357
+ }
358
+ }
359
+ zoomFactorChanged() {
360
+ //a@ts-ignore
361
+ //this._canvasContainer.style.zoom = <any>this._zoomFactor;
362
+ //this._canvasContainer.style.transform = 'scale(' + this._zoomFactor+') translate(' + this._translate.x + ', '+this._translate.y+')';
363
+ //this._canvasContainer.style.transformOrigin = '0 0';
364
+ this._canvasContainer.style.bottom = this._outercanvas2.offsetHeight >= this._canvasContainer.offsetHeight ? '0' : '';
365
+ this._canvasContainer.style.right = this._outercanvas2.offsetWidth >= this._canvasContainer.offsetWidth ? '0' : '';
366
+ this._updateTransform();
367
+ }
368
+ _updateTransform() {
369
+ this._scaleFactor = this._zoomFactor;
370
+ this._canvasContainer.style.transform = 'scale(' + this._zoomFactor + ') translate(' + this._canvasOffset.x + 'px, ' + this._canvasOffset.y + 'px)';
371
+ this._canvasContainer.style.transformOrigin = '0 0';
372
+ this.snapLines.clearSnaplines();
373
+ }
374
+ setDesignItems(designItems) {
375
+ this._fillCalculationrects();
376
+ this.instanceServiceContainer.undoService.clear();
377
+ this.overlayLayer.removeAllOverlays();
378
+ DomHelper.removeAllChildnodes(this.overlayLayer);
379
+ this.rootDesignItem.clearChildren();
380
+ this.addDesignItems(designItems);
381
+ this.instanceServiceContainer.contentService.onContentChanged.emit({ changeType: 'parsed' });
382
+ }
383
+ addDesignItems(designItems) {
384
+ if (designItems) {
385
+ for (let di of designItems) {
386
+ this.rootDesignItem._insertChildInternal(di);
387
+ }
388
+ }
389
+ const intializationService = this.serviceContainer.intializationService;
390
+ if (intializationService) {
391
+ for (let di of designItems)
392
+ intializationService.init(di);
393
+ }
394
+ this.snapLines.clearSnaplines();
395
+ const prepService = this.serviceContainer.prepareElementsForDesignerService;
396
+ if (prepService)
397
+ requestAnimationFrame(() => prepService.prepareElementsForDesigner(this.rootDesignItem));
398
+ }
399
+ _onDragEnter(event) {
400
+ this._fillCalculationrects();
401
+ event.preventDefault();
402
+ const hasTransferDataBindingObject = event.dataTransfer.types.indexOf(dragDropFormatNameBindingObject) >= 0;
403
+ if (hasTransferDataBindingObject) {
404
+ const ddService = this.serviceContainer.bindableObjectDragDropService;
405
+ if (ddService) {
406
+ const effect = ddService.dragEnter(this, event);
407
+ event.dataTransfer.dropEffect = effect;
408
+ }
409
+ }
410
+ }
411
+ _onDragLeave(event) {
412
+ this._fillCalculationrects();
413
+ event.preventDefault();
414
+ this._canvas.classList.remove('dragFileActive');
415
+ const hasTransferDataBindingObject = event.dataTransfer.types.indexOf(dragDropFormatNameBindingObject) >= 0;
416
+ if (hasTransferDataBindingObject) {
417
+ const ddService = this.serviceContainer.bindableObjectDragDropService;
418
+ if (ddService) {
419
+ const effect = ddService.dragLeave(this, event);
420
+ event.dataTransfer.dropEffect = effect;
421
+ }
422
+ }
423
+ }
424
+ _onDragOver(event) {
425
+ event.preventDefault();
426
+ /*if (this.alignOnSnap) {
427
+ this.snapLines.calculateSnaplines(this.instanceServiceContainer.selectionService.selectedElements);
428
+ //TODO: fix this following code...
429
+ const currentPoint = this.getDesignerMousepoint(event);
430
+ let containerService = this.serviceContainer.getLastServiceWhere('containerService', x => x.serviceForContainer(this.rootDesignItem))
431
+ containerService.finishPlace(this, this.rootDesignItem, this._initialPoint, currentPoint, this.instanceServiceContainer.selectionService.selectedElements);
432
+ }*/
433
+ this._fillCalculationrects();
434
+ if (event.dataTransfer.types.length > 0 && event.dataTransfer.types[0] == 'Files') {
435
+ const ddService = this.serviceContainer.dragDropService;
436
+ if (ddService) {
437
+ const effect = ddService.dragOver(event);
438
+ event.dataTransfer.dropEffect = effect;
439
+ if (effect !== 'none')
440
+ this._canvas.classList.add('dragFileActive');
441
+ }
442
+ }
443
+ const hasTransferDataBindingObject = event.dataTransfer.types.indexOf(dragDropFormatNameBindingObject) >= 0;
444
+ if (hasTransferDataBindingObject) {
445
+ const ddService = this.serviceContainer.bindableObjectDragDropService;
446
+ if (ddService) {
447
+ const effect = ddService.dragOver(this, event);
448
+ event.dataTransfer.dropEffect = effect;
449
+ }
450
+ }
451
+ }
452
+ async _onDrop(event) {
453
+ event.preventDefault();
454
+ this._canvas.classList.remove('dragFileActive');
455
+ this._fillCalculationrects();
456
+ if (event.dataTransfer.files?.length > 0) {
457
+ const ddService = this.serviceContainer.dragDropService;
458
+ if (ddService) {
459
+ ddService.drop(this, event);
460
+ }
461
+ }
462
+ else {
463
+ const transferDataBindingObject = event.dataTransfer.getData(dragDropFormatNameBindingObject);
464
+ if (transferDataBindingObject) {
465
+ const bo = JSON.parse(transferDataBindingObject);
466
+ const ddService = this.serviceContainer.bindableObjectDragDropService;
467
+ if (ddService) {
468
+ const effect = ddService.drop(this, event, bo);
469
+ event.dataTransfer.dropEffect = effect;
470
+ }
471
+ }
472
+ else {
473
+ this._fillCalculationrects();
474
+ const position = this.getNormalizedEventCoordinates(event);
475
+ const transferData = event.dataTransfer.getData(dragDropFormatNameElementDefinition);
476
+ const elementDefinition = JSON.parse(transferData);
477
+ const di = await this.serviceContainer.forSomeServicesTillResult("instanceService", (service) => service.getElement(elementDefinition, this.serviceContainer, this.instanceServiceContainer));
478
+ const grp = di.openGroup("Insert");
479
+ di.setStyle('position', 'absolute');
480
+ di.setStyle('left', position.x + 'px');
481
+ di.setStyle('top', position.y + 'px');
482
+ this.instanceServiceContainer.undoService.execute(new InsertAction(this.rootDesignItem, this.rootDesignItem.childCount, di));
483
+ grp.commit();
484
+ requestAnimationFrame(() => this.instanceServiceContainer.selectionService.setSelectedElements([di]));
485
+ }
486
+ }
487
+ }
488
+ _onContextMenu(event) {
489
+ event.preventDefault();
490
+ if (!event.shiftKey) {
491
+ let items = this.getItemsBelowMouse(event);
492
+ if (items.indexOf(this.instanceServiceContainer.selectionService.primarySelection.element) >= 0)
493
+ this.showDesignItemContextMenu(this.instanceServiceContainer.selectionService.primarySelection, event);
494
+ else {
495
+ const designItem = DesignItem.GetOrCreateDesignItem(event.target, this.serviceContainer, this.instanceServiceContainer);
496
+ if (!this.instanceServiceContainer.selectionService.isSelected(designItem)) {
497
+ this.instanceServiceContainer.selectionService.setSelectedElements([designItem]);
498
+ }
499
+ this.showDesignItemContextMenu(designItem, event);
500
+ }
501
+ }
502
+ }
503
+ showDesignItemContextMenu(designItem, event) {
504
+ const mnuItems = [];
505
+ for (let cme of this.serviceContainer.designerContextMenuExtensions) {
506
+ if (cme.shouldProvideContextmenu(event, this, designItem, 'designer')) {
507
+ mnuItems.push(...cme.provideContextMenuItems(event, this, designItem));
508
+ }
509
+ }
510
+ let ctxMnu = ContextMenuHelper.showContextMenu(null, event, null, mnuItems);
511
+ return ctxMnu;
512
+ }
513
+ _onDblClick(event) {
514
+ event.preventDefault();
515
+ this.extensionManager.applyExtension(this.instanceServiceContainer.selectionService.primarySelection, ExtensionType.Doubleclick);
516
+ }
517
+ onKeyUp(event) {
518
+ if (event.composedPath().indexOf(this.eatEvents) >= 0)
519
+ return;
520
+ switch (event.key) {
521
+ case 'ArrowUp':
522
+ //this._resetPointerEventsForClickThrough();
523
+ break;
524
+ }
525
+ event.preventDefault();
526
+ }
527
+ onKeyDown(event) {
528
+ if (event.composedPath().indexOf(this.eatEvents) >= 0)
529
+ return;
530
+ //TODO: keyboard events maybe should also be handeled by tools
531
+ if ((event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey)
532
+ this.executeCommand({ type: CommandType.undo });
533
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'z' && event.shiftKey)
534
+ this.executeCommand({ type: CommandType.redo });
535
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'y')
536
+ this.executeCommand({ type: CommandType.redo });
537
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'a')
538
+ this.executeCommand({ type: CommandType.selectAll });
539
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'c')
540
+ this.executeCommand({ type: CommandType.copy });
541
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'v')
542
+ this.executeCommand({ type: CommandType.paste });
543
+ else if ((event.ctrlKey || event.metaKey) && event.key === 'x')
544
+ this.executeCommand({ type: CommandType.cut });
545
+ else {
546
+ let primarySelection = this.instanceServiceContainer.selectionService.primarySelection;
547
+ if (!primarySelection) {
548
+ return;
549
+ }
550
+ let moveOffset = 1;
551
+ if (event.shiftKey)
552
+ moveOffset = 10;
553
+ switch (event.key) {
554
+ case 'Delete':
555
+ case 'Backspace':
556
+ this.executeCommand({ type: CommandType.delete });
557
+ break;
558
+ case 'ArrowUp':
559
+ {
560
+ this.instanceServiceContainer.selectionService.selectedElements.forEach(x => x.setStyle('top', parseInt(x.element.style.top) - moveOffset + 'px'));
561
+ this.extensionManager.refreshExtensions(this.instanceServiceContainer.selectionService.selectedElements);
562
+ }
563
+ break;
564
+ case 'ArrowDown':
565
+ {
566
+ this.instanceServiceContainer.selectionService.selectedElements.forEach(x => x.setStyle('top', parseInt(x.element.style.top) + moveOffset + 'px'));
567
+ this.extensionManager.refreshExtensions(this.instanceServiceContainer.selectionService.selectedElements);
568
+ }
569
+ break;
570
+ case 'ArrowLeft':
571
+ {
572
+ this.instanceServiceContainer.selectionService.selectedElements.forEach(x => x.setStyle('left', parseInt(x.element.style.left) - moveOffset + 'px'));
573
+ this.extensionManager.refreshExtensions(this.instanceServiceContainer.selectionService.selectedElements);
574
+ }
575
+ break;
576
+ case 'ArrowRight':
577
+ {
578
+ this.instanceServiceContainer.selectionService.selectedElements.forEach(x => x.setStyle('left', parseInt(x.element.style.left) + moveOffset + 'px'));
579
+ this.extensionManager.refreshExtensions(this.instanceServiceContainer.selectionService.selectedElements);
580
+ }
581
+ break;
582
+ }
583
+ }
584
+ event.preventDefault();
585
+ }
586
+ getNormalizedEventCoordinates(event) {
587
+ const offsetOfOuterX = (event.clientX - this.outerRect.x) / this.zoomFactor;
588
+ const offsetOfCanvasX = this.containerBoundingRect.x - this.outerRect.x / this.zoomFactor * this._scaleFactor;
589
+ const offsetOfOuterY = (event.clientY - this.outerRect.y) / this.zoomFactor;
590
+ const offsetOfCanvasY = this.containerBoundingRect.y - this.outerRect.y / this.zoomFactor * this._scaleFactor;
591
+ return {
592
+ x: offsetOfOuterX - offsetOfCanvasX + offsetOfCanvasX - offsetOfCanvasX / this.zoomFactor,
593
+ y: offsetOfOuterY - offsetOfCanvasY + offsetOfCanvasY - offsetOfCanvasY / this.zoomFactor
594
+ };
595
+ }
596
+ getNormalizedElementCoordinates(element) {
597
+ const targetRect = element.getBoundingClientRect();
598
+ return { x: (targetRect.x - this.containerBoundingRect.x) / this.scaleFactor, y: (targetRect.y - this.containerBoundingRect.y) / this.scaleFactor, width: targetRect.width / this.scaleFactor, height: targetRect.height / this.scaleFactor };
599
+ }
600
+ getNormalizedOffsetInElement(event, element) {
601
+ const normEvt = this.getNormalizedEventCoordinates(event);
602
+ const normEl = this.getNormalizedElementCoordinates(element);
603
+ return { x: normEvt.x - normEl.x, y: normEvt.y - normEl.y };
604
+ }
605
+ getElementAtPoint(point, ignoreElementCallback) {
606
+ let backupPEventsMap = new Map();
607
+ let currentElement = this.elementFromPoint(point.x, point.y);
608
+ let lastElement = null;
609
+ try {
610
+ while (currentElement != null) {
611
+ if (currentElement == lastElement) {
612
+ currentElement = null;
613
+ break;
614
+ }
615
+ lastElement = currentElement;
616
+ if (currentElement == this._canvas) {
617
+ break;
618
+ }
619
+ if (currentElement === this.overlayLayer) {
620
+ currentElement = this.overlayLayer.elementFromPoint(point.x, point.y);
621
+ break;
622
+ }
623
+ if (!ignoreElementCallback || !ignoreElementCallback(currentElement)) {
624
+ break;
625
+ }
626
+ backupPEventsMap.set(currentElement, currentElement.style.pointerEvents);
627
+ currentElement.style.pointerEvents = 'none';
628
+ if (currentElement.shadowRoot) {
629
+ for (let e of currentElement.shadowRoot.querySelectorAll('*')) {
630
+ if (!backupPEventsMap.has(e)) {
631
+ if (e.style)
632
+ backupPEventsMap.set(e, e.style.pointerEvents);
633
+ e.style.pointerEvents = 'none';
634
+ }
635
+ }
636
+ }
637
+ currentElement = this.elementFromPoint(point.x, point.y);
638
+ }
639
+ }
640
+ finally {
641
+ for (let e of backupPEventsMap.entries()) {
642
+ e[0].style.pointerEvents = e[1];
643
+ }
644
+ }
645
+ return currentElement;
646
+ }
647
+ _rect;
648
+ _pointerEventHandler(event, forceElement = null) {
649
+ this._fillCalculationrects();
650
+ if (this._pointerextensions) {
651
+ for (let pe of this._pointerextensions)
652
+ pe.refresh(event);
653
+ }
654
+ if (event.composedPath().indexOf(this.eatEvents) >= 0)
655
+ return;
656
+ if (event.buttons == 2)
657
+ return;
658
+ let currentElement;
659
+ if (forceElement)
660
+ currentElement = forceElement;
661
+ else {
662
+ currentElement = this.serviceContainer.elementAtPointService.getElementAtPoint(this, { x: event.x, y: event.y });
663
+ if (currentElement === this._outercanvas2 || currentElement === this.overlayLayer || !currentElement) {
664
+ currentElement = this._canvas;
665
+ }
666
+ } /* else {
667
+ if (!DesignerCanvas.hasOrIsParent(currentElement, this._canvas))
668
+ return;
669
+ }*/
670
+ //TODO: remove duplication when tool refactoring starts
671
+ //this._fillCalculationrects();
672
+ const currentDesignItem = DesignItem.GetOrCreateDesignItem(currentElement, this.serviceContainer, this.instanceServiceContainer);
673
+ if (this._lastHoverDesignItem != currentDesignItem) {
674
+ if (this._lastHoverDesignItem)
675
+ this.extensionManager.removeExtension(this._lastHoverDesignItem, ExtensionType.MouseOver);
676
+ if (currentDesignItem && currentDesignItem != this.rootDesignItem && DomHelper.getHost(currentElement.parentNode) !== this.overlayLayer)
677
+ this.extensionManager.applyExtension(currentDesignItem, ExtensionType.MouseOver);
678
+ this._lastHoverDesignItem = currentDesignItem;
679
+ }
680
+ if (currentElement && DomHelper.getHost(currentElement.parentNode) === this.overlayLayer) {
681
+ if (this.eatEvents)
682
+ return;
683
+ currentElement = this.instanceServiceContainer.selectionService.primarySelection?.element ?? this._canvas;
684
+ }
685
+ this._fillCalculationrects();
686
+ let tool = this.serviceContainer.globalContext.tool ?? this.serviceContainer.designerTools.get(NamedTools.Pointer);
687
+ this._canvas.style.cursor = tool.cursor;
688
+ tool.pointerEventHandler(this, event, currentElement);
689
+ }
690
+ _fillCalculationrects() {
691
+ this.containerBoundingRect = this._canvasContainer.getBoundingClientRect();
692
+ this.outerRect = this._outercanvas2.getBoundingClientRect();
693
+ }
694
+ addOverlay(element, overlayLayer = OverlayLayer.Normal) {
695
+ this.overlayLayer.addOverlay(element, overlayLayer);
696
+ }
697
+ removeOverlay(element) {
698
+ this.overlayLayer.removeOverlay(element);
699
+ }
700
+ getItemsBelowMouse(event) {
701
+ const lstEl = [];
702
+ //search for containers below mouse cursor.
703
+ //to do this, we need to disable pointer events for each in a loop and search wich element is there
704
+ let backupPEventsMap = new Map();
705
+ try {
706
+ let el = this.elementFromPoint(event.x, event.y);
707
+ backupPEventsMap.set(el, el.style.pointerEvents);
708
+ el.style.pointerEvents = 'none';
709
+ if (el !== this.rootDesignItem.element) {
710
+ el = this.elementFromPoint(event.x, event.y);
711
+ while (el != null) {
712
+ if (el === this.rootDesignItem.element)
713
+ break;
714
+ if (el !== this.overlayLayer && el.parentElement !== this.overlayLayer && el.getRootNode() === this.shadowRoot)
715
+ lstEl.push(el);
716
+ if (!backupPEventsMap.has(el))
717
+ backupPEventsMap.set(el, el.style.pointerEvents);
718
+ el.style.pointerEvents = 'none';
719
+ const oldEl = el;
720
+ el = this.elementFromPoint(event.x, event.y);
721
+ if (oldEl === el)
722
+ break;
723
+ }
724
+ }
725
+ }
726
+ finally {
727
+ for (let e of backupPEventsMap.entries()) {
728
+ e[0].style.pointerEvents = e[1];
729
+ }
730
+ }
731
+ return lstEl;
732
+ }
733
+ }
734
+ customElements.define('node-projects-designer-canvas', DesignerCanvas);