From bcec1fc68384d88474edf9dcba9c43959d590656 Mon Sep 17 00:00:00 2001
From: rhenck <richard.henck@iqb.hu-berlin.de>
Date: Sun, 26 Sep 2021 12:51:25 +0200
Subject: [PATCH] [editor] Improve drag and drop of multiple elements

Can now be repositioned and moved between sections properly.
---
 .../canvas/canvas-element-overlay.ts          |  4 +-
 .../dynamic-canvas-overlay.component.ts       | 11 ++---
 .../canvas/page-canvas.component.html         |  2 +-
 .../page-view/canvas/page-canvas.component.ts | 44 ++++++++++---------
 .../canvas/section-dynamic.component.ts       |  5 +--
 .../canvas/static-canvas-overlay.component.ts | 24 +++++-----
 6 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/canvas-element-overlay.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/canvas-element-overlay.ts
index d9266e73e..cdd435c11 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/canvas-element-overlay.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/canvas-element-overlay.ts
@@ -19,7 +19,7 @@ export abstract class CanvasElementOverlay implements OnInit, OnDestroy {
   @Input() element!: UnitUIElement;
   @Input() viewMode: boolean = false;
   @ViewChild('elementContainer', { read: ViewContainerRef, static: true }) private elementContainer!: ViewContainerRef;
-  selected = false;
+  isSelected = false;
   protected childComponent!: ComponentRef<ElementComponent>;
   private ngUnsubscribe = new Subject<void>();
 
@@ -72,7 +72,7 @@ export abstract class CanvasElementOverlay implements OnInit, OnDestroy {
   }
 
   setSelected(newValue: boolean): void {
-    this.selected = newValue;
+    this.isSelected = newValue;
     // This avoids: "NG0100: Expression has changed after it was checked"
     // The selection service may change the "selected" variable after onInit has run.
     // Therefore we need to run it again after this.
diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-canvas-overlay.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-canvas-overlay.component.ts
index ee21c0efe..7458064d2 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-canvas-overlay.component.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-canvas-overlay.component.ts
@@ -8,12 +8,13 @@ import { UnitUIElement } from '../../../../../../../common/unit';
 @Component({
   selector: 'app-dynamic-canvas-overlay',
   template: `
-      <div #draggableElement class="draggable-element" [class.draggable-element-selected]="selected"
-           cdkDrag [cdkDragData]="{dragType: 'move', element: element}" [cdkDragDisabled]="!selected"
-           (click)="selectElement($event.shiftKey)" (dblclick)="openEditDialog()" (cdkDragStarted)="selectElement()"
+      <div #draggableElement class="draggable-element" [class.draggable-element-selected]="isSelected"
+           cdkDrag [cdkDragData]="{dragType: 'move', element: element}" [cdkDragDisabled]="!isSelected"
+           (click)="selectElement($event.shiftKey)" (dblclick)="openEditDialog()"
+           (cdkDragStarted)="!isSelected && selectElement()"
            [style.height.%]="100"
-           [style.border]="selected ? '1px solid' : ''">
-          <div *ngIf="selected" class="resizeHandle"
+           [style.border]="isSelected ? '1px solid' : ''">
+          <div *ngIf="isSelected" class="resizeHandle"
                cdkDrag [cdkDragData]="{dragType: 'resize', element: element}"
                (cdkDragStarted)="dragStart()" (cdkDragEnded)="dragEnd()" (cdkDragMoved)="resizeElement($event)"
                cdkDragBoundary=".section-wrapper"
diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html
index 3324f2d3c..93b7cfda9 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html
@@ -31,7 +31,7 @@
              [section]="section" [sectionIndex]="i"
              [isSelected]="selectionService.selectedPageSectionIndex === i"
              [dropListList]="dropListList"
-             (transferElement)="moveElementBetweenSections($event.element,
+             (transferElement)="moveElementsBetweenSections(selectionService.getSelectedElements(),
                                                            $event.previousSectionIndex,
                                                            $event.newSectionIndex)"
              (mouseover)="hoveredSection = i" (mouseleave)="hoveredSection = -1"
diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts
index 034e0ff3d..0b05c56f2 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts
@@ -65,37 +65,39 @@ export class PageCanvasComponent implements OnInit, OnDestroy {
     });
   }
 
-  moveElementBetweenSections(element: UnitUIElement, previousSectionIndex: number, newSectionIndex: number): void {
-    this.unitService.transferElement([element],
+  moveElementsBetweenSections(elements: UnitUIElement[], previousSectionIndex: number, newSectionIndex: number): void {
+    this.unitService.transferElement(elements,
       this.page.sections[previousSectionIndex],
       this.page.sections[newSectionIndex]);
   }
 
   elementDropped(event: CdkDragDrop<DropListData>): void {
-    const sourceItemModel = (event.item.data as DragItemData).element;
+    const selectedElements = this.selectionService.getSelectedElements();
 
     if (event.previousContainer !== event.container) {
-      this.moveElementBetweenSections(event.item.data.element,
+      this.moveElementsBetweenSections(selectedElements,
         event.previousContainer.data.sectionIndex,
         event.container.data.sectionIndex);
     } else {
-      let newXPosition = sourceItemModel.xPosition + event.distance.x;
-      if (newXPosition < 0) {
-        newXPosition = 0;
-      }
-      if (newXPosition > this.page.maxWidth - sourceItemModel.width) {
-        newXPosition = this.page.maxWidth - sourceItemModel.width;
-      }
-      this.unitService.updateElementProperty(this.selectionService.getSelectedElements(), 'xPosition', newXPosition);
-
-      let newYPosition = sourceItemModel.yPosition + event.distance.y;
-      if (newYPosition < 0) {
-        newYPosition = 0;
-      }
-      if (newYPosition > this.getPageHeight() - sourceItemModel.height) {
-        newYPosition = this.getPageHeight() - sourceItemModel.height;
-      }
-      this.unitService.updateElementProperty(this.selectionService.getSelectedElements(), 'yPosition', newYPosition);
+      selectedElements.forEach((element: UnitUIElement) => {
+        let newXPosition = element.xPosition + event.distance.x;
+        if (newXPosition < 0) {
+          newXPosition = 0;
+        }
+        if (newXPosition > this.page.maxWidth - element.width) {
+          newXPosition = this.page.maxWidth - element.width;
+        }
+        this.unitService.updateElementProperty([element], 'xPosition', newXPosition);
+
+        let newYPosition = element.yPosition + event.distance.y;
+        if (newYPosition < 0) {
+          newYPosition = 0;
+        }
+        if (newYPosition > this.getPageHeight() - element.height) {
+          newYPosition = this.getPageHeight() - element.height;
+        }
+        this.unitService.updateElementProperty([element], 'yPosition', newYPosition);
+      });
     }
   }
 
diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/section-dynamic.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/section-dynamic.component.ts
index e5da1f3b8..df1a210c0 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/section-dynamic.component.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/section-dynamic.component.ts
@@ -68,9 +68,7 @@ export class SectionDynamicComponent {
   @Input() sectionIndex!: number;
   @Input() dropListList!: string[];
   @Input() isSelected!: boolean;
-  @Output() transferElement = new EventEmitter<{ element: UnitUIElement,
-    previousSectionIndex: number,
-    newSectionIndex: number }>();
+  @Output() transferElement = new EventEmitter<{ previousSectionIndex: number, newSectionIndex: number }>();
 
   dragging = false;
   draggingElementWidth: number | undefined = 0;
@@ -84,7 +82,6 @@ export class SectionDynamicComponent {
     // Move element to other section - handled by parent (page-canvas).
     if (event.previousContainer.data.sectionIndex !== event.container.data.sectionIndex) {
       this.transferElement.emit({
-        element: event.item.data.element,
         previousSectionIndex: event.previousContainer.data.sectionIndex,
         newSectionIndex: event.container.data.sectionIndex
       });
diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/static-canvas-overlay.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/static-canvas-overlay.component.ts
index dae3bee20..00aadf61a 100644
--- a/projects/editor/src/app/components/unit-view/page-view/canvas/static-canvas-overlay.component.ts
+++ b/projects/editor/src/app/components/unit-view/page-view/canvas/static-canvas-overlay.component.ts
@@ -6,28 +6,28 @@ import { CanvasElementOverlay } from './canvas-element-overlay';
   selector: 'app-static-canvas-overlay',
   template: `
     <!-- Is also a droplist to catch the resize drop and not let it bubble up to the canvas drop handler. -->
-    <div class="draggable-element" [class.draggable-element-selected]="selected"
+    <div class="draggable-element" [class.draggable-element-selected]="isSelected"
          cdkDrag [cdkDragData]="{dragType: 'move', element: element}"
-         (click)="selectElement($event.shiftKey)" (cdkDragStarted)="selectElement()"
+         (click)="selectElement($event.shiftKey)" (cdkDragStarted)="!isSelected && selectElement()"
          (dblclick)="openEditDialog()"
          cdkDropList>
       <!-- Needs extra div because styling can interfere with drag and drop-->
       <div [style.position]="'absolute'"
-           [style.border]="selected ? '2px solid' : ''"
+           [style.border]="isSelected ? '2px solid' : ''"
            [style.width.px]="element.width"
            [style.height.px]="element.height"
            [style.left.px]="element.xPosition"
            [style.top.px]="element.yPosition"
            [style.z-index]="element.zIndex">
-          <div *ngIf="selected" class="resizeHandle"
-               cdkDrag (cdkDragStarted)="resizeDragStart()" (cdkDragMoved)="resizeElement($event)"
-               cdkDragBoundary=".section-wrapper"
-               [style.right.px]="-1"
-               [style.bottom.px]="-7"
-               [style.z-index]="5">
-            <mat-icon>aspect_ratio</mat-icon>
-            <div *cdkDragPlaceholder></div>
-          </div>
+        <div *ngIf="isSelected" class="resizeHandle"
+             cdkDrag (cdkDragStarted)="resizeDragStart()" (cdkDragMoved)="resizeElement($event)"
+             cdkDragBoundary=".section-wrapper"
+             [style.right.px]="-1"
+             [style.bottom.px]="-7"
+             [style.z-index]="5">
+          <mat-icon>aspect_ratio</mat-icon>
+          <div *cdkDragPlaceholder></div>
+        </div>
         <ng-template #elementContainer></ng-template>
       </div>
     </div>
-- 
GitLab