From 2bd675dc6125c20b61d92c1fbc78fbbc15208c8c Mon Sep 17 00:00:00 2001
From: rhenck <richard.henck@iqb.hu-berlin.de>
Date: Mon, 28 Nov 2022 19:26:48 +0100
Subject: [PATCH] Add new DropList property: deleteDroppedItemWithSameID

Lists with this setting delete dropped value objects. This allows
putting items back.
(Only makes sense when used with copyOnDrop. Otherwise there can not be
duplicate value IDs).

Also improve constructor value checks to correctly handle nullish
booleans.

#281
---
 docs/unit_definition_changelog.txt            |  3 ++
 .../input-elements/drop-list.component.ts     | 30 +++++++++++++------
 .../elements/input-elements/drop-list.ts      |  8 +++--
 .../drop-list-properties.component.ts         |  8 +++++
 projects/editor/src/assets/i18n/de.json       |  2 ++
 5 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/docs/unit_definition_changelog.txt b/docs/unit_definition_changelog.txt
index 9c0318c5a..1a9fc32f9 100644
--- a/docs/unit_definition_changelog.txt
+++ b/docs/unit_definition_changelog.txt
@@ -58,3 +58,6 @@ iqb-aspect-definition@1.0.0
 - Remove drop-list-simple as cloze child; is now a drop-list
 - ButtonElement: action +highlightText
                  param +string
+
+3.9.0
+- DropListElement: +deleteDroppedItemWithSameID
diff --git a/projects/common/components/input-elements/drop-list.component.ts b/projects/common/components/input-elements/drop-list.component.ts
index 5f5ae072c..4c16df4a7 100644
--- a/projects/common/components/input-elements/drop-list.component.ts
+++ b/projects/common/components/input-elements/drop-list.component.ts
@@ -106,6 +106,7 @@ export class DropListComponent extends FormElementComponent implements OnInit, A
     DropListComponent.dragAndDropComponents[this.elementModel.id] = this;
   }
 
+  // TODO method names
   dragStart(dragEvent: DragEvent,
             dropListValueElement: DragNDropValueObject,
             sourceListIndex: number) {
@@ -191,25 +192,36 @@ export class DropListComponent extends FormElementComponent implements OnInit, A
   drop(event: DragEvent) {
     event.preventDefault();
 
+    // SortList viewModel already gets manipulated while dragging. Just set the value.
     if (DropListComponent.sourceList === this && this.elementModel.isSortList) {
       this.elementFormControl.setValue(this.viewModel);
     } else if (this.isDropAllowed((DropListComponent.sourceList as DropListComponent).elementModel.connectedTo)) {
-      const presentValueIDs = this.elementFormControl.value
-        .map((valueValue: DragNDropValueObject) => valueValue.id);
-      if (!presentValueIDs.includes(DropListComponent.draggedElement?.id)) {
-        this.viewModel.push(DropListComponent.draggedElement as DragNDropValueObject);
-        this.elementFormControl.setValue(this.viewModel);
+      const valueIDs = this.elementFormControl.value.map((valueValue: DragNDropValueObject) => valueValue.id);
+      if (!valueIDs.includes(DropListComponent.draggedElement?.id)) {
+        this.addDraggedElementToList();
         if (!DropListComponent.sourceList?.elementModel.copyOnDrop) {
-          DropListComponent.sourceList?.viewModel.splice(DropListComponent.sourceList.placeHolderIndex as number, 1);
-          DropListComponent.sourceList?.elementFormControl.setValue(DropListComponent.sourceList.viewModel);
+          DropListComponent.removeElementFromSourceList();
         }
+      } else if (this.elementModel.deleteDroppedItemWithSameID) {
+        DropListComponent.removeElementFromSourceList();
       }
-    } else {
-      console.log('Not an allowed target list');
     }
+    // else {
+    // console.log('Not an allowed target list');
+    // }
     this.dragEnd();
   }
 
+  addDraggedElementToList(): void {
+    this.viewModel.push(DropListComponent.draggedElement as DragNDropValueObject);
+    this.elementFormControl.setValue(this.viewModel);
+  }
+
+  static removeElementFromSourceList(): void {
+    DropListComponent.sourceList?.viewModel.splice(DropListComponent.sourceList.placeHolderIndex as number, 1);
+    DropListComponent.sourceList?.elementFormControl.setValue(DropListComponent.sourceList.viewModel);
+  }
+
   isDropAllowed(connectedDropLists: string[]): boolean {
     return (DropListComponent.sourceList === this) ||
       ((connectedDropLists as string[]).includes(this.elementModel.id) &&
diff --git a/projects/common/models/elements/input-elements/drop-list.ts b/projects/common/models/elements/input-elements/drop-list.ts
index ddde96ada..4c2e71da1 100644
--- a/projects/common/models/elements/input-elements/drop-list.ts
+++ b/projects/common/models/elements/input-elements/drop-list.ts
@@ -14,6 +14,7 @@ export class DropListElement extends InputElement {
   isSortList: boolean = false;
   connectedTo: string[] = [];
   copyOnDrop: boolean = false;
+  deleteDroppedItemWithSameID: boolean = false;
   orientation: 'vertical' | 'horizontal' | 'flex' = 'vertical';
   highlightReceivingDropList: boolean = false;
   highlightReceivingDropListColor: string = '#006064';
@@ -28,9 +29,12 @@ export class DropListElement extends InputElement {
       element.value.map(val => ({ ...val })) :
       [];
     if (element.onlyOneItem) this.onlyOneItem = element.onlyOneItem;
-    if (element.isSortList) this.isSortList = element.isSortList;
+    if (element.isSortList !== undefined) this.isSortList = element.isSortList;
     if (element.connectedTo) this.connectedTo = [...element.connectedTo];
-    if (element.copyOnDrop) this.copyOnDrop = element.copyOnDrop;
+    if (element.copyOnDrop !== undefined) this.copyOnDrop = element.copyOnDrop;
+    if (element.deleteDroppedItemWithSameID !== undefined) {
+      this.deleteDroppedItemWithSameID = element.deleteDroppedItemWithSameID;
+    }
     if (element.orientation) this.orientation = element.orientation;
     if (element.highlightReceivingDropList) this.highlightReceivingDropList = element.highlightReceivingDropList;
     if (element.highlightReceivingDropListColor) {
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
index f4a32ca9d..208cea5f5 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
@@ -68,6 +68,14 @@ import { DialogService } from '../../../../services/dialog.service';
         {{'propertiesPanel.copyOnDrop' | translate }}
       </mat-checkbox>
 
+      <mat-checkbox *ngIf="combinedProperties.deleteDroppedItemWithSameID !== undefined"
+                    matTooltip="{{'propertiesPanel.deleteDroppedItemWithSameIDTooltip' | translate }}"
+                    [disabled]="!combinedProperties.copyOnDrop"
+                    [checked]="$any(combinedProperties.deleteDroppedItemWithSameID)"
+                    (change)="updateModel.emit({ property: 'deleteDroppedItemWithSameID', value: $event.checked })">
+        {{'propertiesPanel.deleteDroppedItemWithSameID' | translate }}
+      </mat-checkbox>
+
       <mat-checkbox *ngIf="combinedProperties.highlightReceivingDropList !== undefined"
                     [checked]="$any(combinedProperties.highlightReceivingDropList)"
                     (change)="updateModel.emit({ property: 'highlightReceivingDropList', value: $event.checked })">
diff --git a/projects/editor/src/assets/i18n/de.json b/projects/editor/src/assets/i18n/de.json
index 7fd4aec89..b1bbf8c8a 100644
--- a/projects/editor/src/assets/i18n/de.json
+++ b/projects/editor/src/assets/i18n/de.json
@@ -189,6 +189,8 @@
     "hasDynamicRowCount": "Dynamische Zeilen",
     "expectedCharactersCount": "Erwartete Zeichenanzahl",
     "isSortList": "Sortierliste",
+    "deleteDroppedItemWithSameID": "Gleiche abgelegte Elemente löschen",
+    "deleteDroppedItemWithSameIDTooltip": "Elemente mit gleicher ID werden beim Zurücklegen gelöscht.",
     "setElementInteractionEnabled": "Elementinteraktion erlauben"
   },
   "hotspot": {
-- 
GitLab