diff --git a/projects/common/shared.module.ts b/projects/common/shared.module.ts index 6ff88e55bcf5482a3c0bf614392019d1da69861b..7d1bd4732076a6d2a8583509d13897d5ec83d740 100644 --- a/projects/common/shared.module.ts +++ b/projects/common/shared.module.ts @@ -43,6 +43,7 @@ import { RadioGroupImagesComponent } from './ui-elements/radio-with-images/radio import { DropListComponent } from './ui-elements/drop-list/drop-list.component'; import { ClozeComponent } from './ui-elements/cloze/cloze.component'; import { TextFieldSimpleComponent } from './ui-elements/textfield-simple/text-field-simple.component'; +import { DropListSimpleComponent } from './ui-elements/drop-list-simple/drop-list-simple.component'; @NgModule({ imports: [ @@ -86,7 +87,8 @@ import { TextFieldSimpleComponent } from './ui-elements/textfield-simple/text-fi RadioGroupImagesComponent, DropListComponent, ClozeComponent, - TextFieldSimpleComponent + TextFieldSimpleComponent, + DropListSimpleComponent ], exports: [ CommonModule, diff --git a/projects/common/ui-elements/cloze/cloze-element.ts b/projects/common/ui-elements/cloze/cloze-element.ts index cd803cf02dfd48b9d5eb32148f0a178e046fc1be..0f18c437a40b49d7eb65269396de3255db39f3de 100644 --- a/projects/common/ui-elements/cloze/cloze-element.ts +++ b/projects/common/ui-elements/cloze/cloze-element.ts @@ -135,10 +135,9 @@ export class ClozeElement extends CompoundElement implements PositionedElement, newElement = new DropdownElement(elementModel); break; case 'drop-list': - newElement = new DropListElement(elementModel); - newElement.height = 30; + newElement = new DropListSimpleElement(elementModel); + newElement.height = 25; newElement.width = 100; - newElement.onlyOneItem = true; break; default: throw new Error(`ElementType ${elementModel.type} not found!`); diff --git a/projects/common/ui-elements/cloze/cloze.component.ts b/projects/common/ui-elements/cloze/cloze.component.ts index 3a7efb71524f2d50f37a4b771d8b1470f8c7302d..f2561f966057e90203a0ca72f579d1992eaeb1b5 100644 --- a/projects/common/ui-elements/cloze/cloze.component.ts +++ b/projects/common/ui-elements/cloze/cloze.component.ts @@ -66,11 +66,11 @@ import { FormElementComponent } from '../../directives/form-element-component.di [style.vertical-align]="'middle'" [style.width.px]="$any(part.value).width" [style.height.px]="$any(part.value).height"> - <app-drop-list #droplistComponent + <app-drop-list-simple #droplistComponent [parentForm]="parentForm" (elementValueChanged)="elementValueChanged.emit($event)" [elementModel]="$any(part.value)"> - </app-drop-list> + </app-drop-list-simple> </div> </span> </ng-container> diff --git a/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts b/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..73a96e88acf6049fa3927c21adeef0ca8c165538 --- /dev/null +++ b/projects/common/ui-elements/drop-list-simple/drop-list-simple.component.ts @@ -0,0 +1,89 @@ +import { Component, Input } from '@angular/core'; +import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events'; +import { + CdkDrag, CdkDropList, moveItemInArray, transferArrayItem +} from '@angular/cdk/drag-drop'; +import { DropListSimpleElement } from './drop-list-simple'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; + +@Component({ + selector: 'app-drop-list-simple', + template: ` + <div class="list-container"> + <!-- Border width is a workaround to enable/disable the Material cdk-drop-list-receiving--> + <!-- class style.--> + <div class="list" + [class.dropList-highlight]="elementModel.highlightReceivingDropList" + [style.border-color]="elementModel.highlightReceivingDropListColor" + [style.border-width.px]="elementModel.highlightReceivingDropList ? 2 : 0" + [style.color]="elementModel.fontProps.fontColor" + [style.font-family]="elementModel.fontProps.font" + [style.font-size.px]="elementModel.fontProps.fontSize" + [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''" + [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''" + [style.backgroundColor]="elementModel.surfaceProps.backgroundColor" + cdkDropList + [id]="elementModel.id" + [cdkDropListData]="this" + [cdkDropListConnectedTo]="elementModel.connectedTo" + [cdkDropListEnterPredicate]="onlyOneItemPredicate" + (cdkDropListDropped)="drop($event)"> + <div class="item" *ngFor="let value of $any(elementModel.value)" cdkDrag + [style.line-height.px]="elementModel.height - 4" + [style.background-color]="elementModel.itemBackgroundColor"> + <div *cdkDragPreview + [style.font-size.px]="elementModel.fontProps.fontSize" + [style.background-color]="elementModel.itemBackgroundColor"> + {{value}} + </div> + <div class="drag-placeholder" *cdkDragPlaceholder [style.min-height.px]="elementModel.fontProps.fontSize"> + </div> + {{value}} + </div> + </div> + <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched" + class="error-message"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> + </div> + `, + styles: [ + '.list-container {display: flex; flex-direction: column; width: 100%; height: 100%;}', + '.list {width: 100%; height: 100%; border-radius: 5px}', + '.item {border-radius: 5px; padding: 0 5px; height: 100%}', + '.item:not(:last-child) {margin-bottom: 5px;}', + '.error-message {font-size: 75%; margin-top: 10px;}', + '.cdk-drag-preview {padding: 8px 20px; border-radius: 10px}', + '.drag-placeholder {background-color: lightgrey; border: dotted 3px #999; padding: 10px;}', + '.drag-placeholder {transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);}', + '.cdk-drag-animating {transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);}', + + '.dropList-highlight.cdk-drop-list-receiving {border: solid;}', + '.dropList-highlight.cdk-drop-list-dragging {border: solid;}' + ] +}) +export class DropListSimpleComponent extends FormElementComponent { + @Input() elementModel!: DropListSimpleElement; + + drop(event: CdkDragDrop<DropListSimpleComponent>): void { + if (!this.elementModel.readOnly) { + if (event.previousContainer === event.container) { + moveItemInArray(event.container.data.elementModel.value as string[], event.previousIndex, event.currentIndex); + } else { + transferArrayItem( + event.previousContainer.data.elementModel.value as string[], + event.container.data.elementModel.value as string[], + event.previousIndex, + event.currentIndex + ); + event.previousContainer.data.elementFormControl.setValue(event.previousContainer.data.elementModel.value); + } + this.elementFormControl.setValue(event.container.data.elementModel.value); + } + } + + onlyOneItemPredicate = (drag: CdkDrag, drop: CdkDropList): boolean => ( + !drop.data.elementModel.onlyOneItem || drop.data.elementModel.value.length < 1 + ); +} diff --git a/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts b/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b0e0a10be425a44163be563a1415e2b9defdda3 --- /dev/null +++ b/projects/common/ui-elements/drop-list-simple/drop-list-simple.ts @@ -0,0 +1,33 @@ +import { + FontElement, + FontProperties, + InputElement, + PositionedElement, PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class DropListSimpleElement extends InputElement implements FontElement, SurfaceElement { + connectedTo: string[] = []; + itemBackgroundColor: string = '#add8e6'; + highlightReceivingDropList: boolean = false; + highlightReceivingDropListColor: string = '#add8e6'; + + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.value = serializedElement.value as string[] || []; + this.height = serializedElement.height || 100; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + '#eeeeec'; + } +}