From 4a413b60c8613232b17f0c4d7999bac3443c3ba1 Mon Sep 17 00:00:00 2001 From: rhenck <richard.henck@iqb.hu-berlin.de> Date: Fri, 26 Nov 2021 15:29:30 +0100 Subject: [PATCH] Refactor element class and interface structure The problem being solved is that compound-sub-elements must not have all the properties other elements have. For exampe positioning info. Sub-Elements are positioned inline. To avoid having similar class inheritance structures for positioned and inline elements, we use interface. Positioning is done via interface and is therefore optional. Those optional properties are kept in an object in a variable. This allows to hide specifics from element classes and removes the need to initialize all the fields in every class using the interface. The elements mostly care about their own specific properties anyway. The same technique is used for font and surface elements. Here we also don't want to initialize all the styles in every class. Changing values of element properties works like before. Just set the property as if it would be a direkt prop of the element. The element itself puts the value in the currect sub-object (positioningProps, fontProps etc). For reading the values there is a similar method, but it is not used anywhere by now. Since the properties panel operates on the raw values anyway (refer CombinedProperties) and for element components this would mean calling a function in the template, which caused change detection to run the function very often and is therefore bad practice. Additional notes and refactorings: - Restructure all files in common. UIElements in the same folder etc. - Move all interfaces to the UIElement file. This avoids circular imports, which would be needed to allow PositionedElement to extend UIElement. - Interface initializers also handle reading values in the old form. - Add PositionedElement for use in canvas overlays. This is a UIElement with guaranteed postionProps. - Don't export all Material packages from common, only the ones used in player and editor. The rest is only used in common and does not need to be exported. --- projects/common/component-utils.ts | 44 ----- .../control-bar/control-bar.component.css | 0 .../control-bar/control-bar.component.html | 37 ++-- .../control-bar/control-bar.component.ts | 43 ++--- .../control-bar/player-time-format.pipe.ts | 0 .../compound-element.directive.ts | 4 +- .../element-component.directive.ts | 2 +- .../form-element-component.directive.ts | 2 +- .../input-background-color.directive.ts | 0 ...edia-player-element-component.directive.ts | 2 +- .../common/interfaces/UIElementInterfaces.ts | 56 ------ projects/common/models/audio-element.ts | 37 ---- projects/common/models/button-element.ts | 27 --- projects/common/models/checkbox-element.ts | 26 --- .../models/compound-elements/drop-list.ts | 41 ----- .../compound-elements/radio-group-images.ts | 27 --- projects/common/models/dropdown-element.ts | 27 --- .../models/radio-button-group-element.ts | 29 ---- projects/common/models/section.ts | 28 +-- projects/common/models/text-area-element.ts | 32 ---- projects/common/models/text-element.ts | 38 ----- projects/common/models/text-field-element.ts | 38 ----- projects/common/models/uI-element.ts | 145 +++++++++++++--- projects/common/models/video-element.ts | 37 ---- .../pipes/error-transform.pipe.ts | 2 +- .../pipes/safe-resource-html.pipe.ts | 0 .../pipes/safe-resource-url.pipe.ts | 0 .../common/{ => services}/message.service.ts | 0 projects/common/shared.module.ts | 69 +++----- .../common/ui-elements/audio/audio-element.ts | 19 +++ .../audio}/audio.component.ts | 7 +- .../ui-elements/button/button-element.ts | 28 +++ .../button}/button.component.ts | 18 +- .../ui-elements/checkbox/checkbox-element.ts | 31 ++++ .../checkbox}/checkbox.component.ts | 18 +- .../cloze}/cloze-element.ts | 37 ++-- .../cloze}/cloze.component.ts | 20 +-- .../drop-list}/drop-list.component.ts | 23 +-- .../common/ui-elements/drop-list/drop-list.ts | 46 +++++ .../ui-elements/dropdown/dropdown-element.ts | 29 ++++ .../dropdown}/dropdown.component.ts | 18 +- .../image}/image-element.ts | 2 +- .../image}/image.component.ts | 6 +- .../image}/magnifier.component.ts | 2 +- .../likert}/likert-element-row.ts | 3 +- .../likert}/likert-element.ts | 32 ++-- .../likert-radio-button-group.component.ts | 4 +- .../likert}/likert.component.ts | 22 +-- .../radio-group-images.component.ts | 18 +- .../radio-with-images/radio-group-images.ts | 32 ++++ .../radio/radio-button-group-element.ts | 34 ++++ .../radio}/radio-button-group.component.ts | 18 +- .../text-area/text-area-element.ts | 36 ++++ .../text-area}/text-area.component.ts | 20 +-- .../text-field/text-field-element.ts | 41 +++++ .../text-field}/text-field.component.ts | 32 ++-- .../common/ui-elements/text/text-element.ts | 41 +++++ .../text}/text.component.ts | 20 +-- .../text-field-simple-element.ts | 2 +- .../text-field-simple.component.ts | 4 +- .../common/ui-elements/video/video-element.ts | 18 ++ .../video}/video.component.ts | 7 +- projects/common/util/element.factory.ts | 56 +++--- .../common/util/unit-interface-initializer.ts | 159 ++++++++++++++++-- projects/editor/src/app/app.module.ts | 16 ++ .../likert-column-edit-dialog.component.ts | 2 +- .../likert-row-edit-dialog.component.ts | 4 +- .../dialogs/player-edit-dialog.component.ts | 52 +++--- .../page-view/canvas/canvas.component.ts | 10 +- .../canvas/overlays/canvas-element-overlay.ts | 8 +- .../static-canvas-overlay.component.ts | 6 +- .../canvas/section-dynamic.component.ts | 16 +- ...nt-model-properties-component.component.ts | 9 +- .../element-properties.component.ts | 5 +- .../element-sizing-properties.component.ts | 28 +-- .../element-style-properties.component.ts | 40 ++--- .../unit-view/unit-view.component.ts | 2 +- .../editor/src/app/services/dialog.service.ts | 8 +- .../editor/src/app/services/unit.service.ts | 32 ++-- .../element-container.component.ts | 20 +-- .../components/section/section.component.html | 22 +-- .../unit-state/unit-state.component.ts | 2 +- .../src/app/services/keyboard.service.ts | 2 +- .../src/app/services/marking.service.ts | 2 +- .../src/app/services/media-player.service.ts | 2 +- 85 files changed, 1055 insertions(+), 929 deletions(-) delete mode 100644 projects/common/component-utils.ts rename projects/common/{element-components => components}/control-bar/control-bar.component.css (100%) rename projects/common/{element-components => components}/control-bar/control-bar.component.html (69%) rename projects/common/{element-components => components}/control-bar/control-bar.component.ts (77%) rename projects/common/{element-components => components}/control-bar/player-time-format.pipe.ts (100%) rename projects/common/{element-components/compound-elements => directives}/compound-element.directive.ts (82%) rename projects/common/{ => directives}/element-component.directive.ts (91%) rename projects/common/{ => directives}/form-element-component.directive.ts (98%) rename projects/common/{element-components => }/directives/input-background-color.directive.ts (100%) rename projects/common/{ => directives}/media-player-element-component.directive.ts (92%) delete mode 100644 projects/common/interfaces/UIElementInterfaces.ts delete mode 100644 projects/common/models/audio-element.ts delete mode 100644 projects/common/models/button-element.ts delete mode 100644 projects/common/models/checkbox-element.ts delete mode 100644 projects/common/models/compound-elements/drop-list.ts delete mode 100644 projects/common/models/compound-elements/radio-group-images.ts delete mode 100644 projects/common/models/dropdown-element.ts delete mode 100644 projects/common/models/radio-button-group-element.ts delete mode 100644 projects/common/models/text-area-element.ts delete mode 100644 projects/common/models/text-element.ts delete mode 100644 projects/common/models/text-field-element.ts delete mode 100644 projects/common/models/video-element.ts rename projects/common/{element-components => }/pipes/error-transform.pipe.ts (94%) rename projects/common/{element-components => }/pipes/safe-resource-html.pipe.ts (100%) rename projects/common/{element-components => }/pipes/safe-resource-url.pipe.ts (100%) rename projects/common/{ => services}/message.service.ts (100%) create mode 100644 projects/common/ui-elements/audio/audio-element.ts rename projects/common/{element-components => ui-elements/audio}/audio.component.ts (77%) create mode 100644 projects/common/ui-elements/button/button-element.ts rename projects/common/{element-components => ui-elements/button}/button.component.ts (67%) create mode 100644 projects/common/ui-elements/checkbox/checkbox-element.ts rename projects/common/{element-components => ui-elements/checkbox}/checkbox.component.ts (65%) rename projects/common/{models/compound-elements => ui-elements/cloze}/cloze-element.ts (82%) rename projects/common/{element-components/compound-elements => ui-elements/cloze}/cloze.component.ts (84%) rename projects/common/{element-components/compound-elements => ui-elements/drop-list}/drop-list.component.ts (82%) create mode 100644 projects/common/ui-elements/drop-list/drop-list.ts create mode 100644 projects/common/ui-elements/dropdown/dropdown-element.ts rename projects/common/{element-components => ui-elements/dropdown}/dropdown.component.ts (64%) rename projects/common/{models => ui-elements/image}/image-element.ts (87%) rename projects/common/{element-components => ui-elements/image}/image.component.ts (89%) rename projects/common/{element-components => ui-elements/image}/magnifier.component.ts (97%) rename projects/common/{models/compound-elements => ui-elements/likert}/likert-element-row.ts (69%) rename projects/common/{models/compound-elements => ui-elements/likert}/likert-element.ts (65%) rename projects/common/{element-components/compound-elements => ui-elements/likert}/likert-radio-button-group.component.ts (89%) rename projects/common/{element-components/compound-elements => ui-elements/likert}/likert.component.ts (77%) rename projects/common/{element-components/compound-elements => ui-elements/radio-with-images}/radio-group-images.component.ts (82%) create mode 100644 projects/common/ui-elements/radio-with-images/radio-group-images.ts create mode 100644 projects/common/ui-elements/radio/radio-button-group-element.ts rename projects/common/{element-components => ui-elements/radio}/radio-button-group.component.ts (77%) create mode 100644 projects/common/ui-elements/text-area/text-area-element.ts rename projects/common/{element-components => ui-elements/text-area}/text-area.component.ts (64%) create mode 100644 projects/common/ui-elements/text-field/text-field-element.ts rename projects/common/{element-components => ui-elements/text-field}/text-field.component.ts (74%) create mode 100644 projects/common/ui-elements/text/text-element.ts rename projects/common/{element-components => ui-elements/text}/text.component.ts (82%) rename projects/common/{models => ui-elements/textfield-simple}/text-field-simple-element.ts (73%) rename projects/common/{element-components => ui-elements/textfield-simple}/text-field-simple.component.ts (75%) create mode 100644 projects/common/ui-elements/video/video-element.ts rename projects/common/{element-components => ui-elements/video}/video.component.ts (80%) diff --git a/projects/common/component-utils.ts b/projects/common/component-utils.ts deleted file mode 100644 index 2fb91550f..000000000 --- a/projects/common/component-utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ComponentFactory, ComponentFactoryResolver } from '@angular/core'; -import { TextComponent } from './element-components/text.component'; -import { ButtonComponent } from './element-components/button.component'; -import { TextFieldComponent } from './element-components/text-field.component'; -import { TextAreaComponent } from './element-components/text-area.component'; -import { CheckboxComponent } from './element-components/checkbox.component'; -import { DropdownComponent } from './element-components/dropdown.component'; -import { RadioButtonGroupComponent } from './element-components/radio-button-group.component'; -import { ImageComponent } from './element-components/image.component'; -import { AudioComponent } from './element-components/audio.component'; -import { VideoComponent } from './element-components/video.component'; -import { LikertComponent } from './element-components/compound-elements/likert.component'; - -export function getComponentFactory( - elementType: string, componentFactoryResolver: ComponentFactoryResolver -): ComponentFactory<any> { - // TODO: Find better solution than any - switch (elementType) { - case 'text': - return componentFactoryResolver.resolveComponentFactory(TextComponent); - case 'button': - return componentFactoryResolver.resolveComponentFactory(ButtonComponent); - case 'text-field': - return componentFactoryResolver.resolveComponentFactory(TextFieldComponent); - case 'text-area': - return componentFactoryResolver.resolveComponentFactory(TextAreaComponent); - case 'checkbox': - return componentFactoryResolver.resolveComponentFactory(CheckboxComponent); - case 'dropdown': - return componentFactoryResolver.resolveComponentFactory(DropdownComponent); - case 'radio': - return componentFactoryResolver.resolveComponentFactory(RadioButtonGroupComponent); - case 'image': - return componentFactoryResolver.resolveComponentFactory(ImageComponent); - case 'audio': - return componentFactoryResolver.resolveComponentFactory(AudioComponent); - case 'video': - return componentFactoryResolver.resolveComponentFactory(VideoComponent); - case 'likert': - return componentFactoryResolver.resolveComponentFactory(LikertComponent); - default: - throw new Error('unknown element'); - } -} diff --git a/projects/common/element-components/control-bar/control-bar.component.css b/projects/common/components/control-bar/control-bar.component.css similarity index 100% rename from projects/common/element-components/control-bar/control-bar.component.css rename to projects/common/components/control-bar/control-bar.component.css diff --git a/projects/common/element-components/control-bar/control-bar.component.html b/projects/common/components/control-bar/control-bar.component.html similarity index 69% rename from projects/common/element-components/control-bar/control-bar.component.html rename to projects/common/components/control-bar/control-bar.component.html index ebeecbee7..06470986f 100644 --- a/projects/common/element-components/control-bar/control-bar.component.html +++ b/projects/common/components/control-bar/control-bar.component.html @@ -1,14 +1,14 @@ -<div *ngIf="elementModel.startControl || - elementModel.pauseControl || - elementModel.showRestRuns || - elementModel.progressBar || - elementModel.showRestTime || - elementModel.muteControl || - elementModel.volumeControl" +<div *ngIf="playerProperties.startControl || + playerProperties.pauseControl || + playerProperties.showRestRuns || + playerProperties.progressBar || + playerProperties.showRestTime || + playerProperties.muteControl || + playerProperties.volumeControl" class="control-bar" [class.hint-border]="showHint"> - <ng-container *ngIf="elementModel.startControl"> - <button *ngIf="!playing || !elementModel.pauseControl" + <ng-container *ngIf="playerProperties.startControl"> + <button *ngIf="!playing || !playerProperties.pauseControl" type="button" mat-button class="control-button" @@ -19,7 +19,7 @@ <mat-icon>play_arrow</mat-icon> </button> </ng-container> - <ng-container *ngIf="elementModel.pauseControl"> + <ng-container *ngIf="playerProperties.pauseControl"> <button *ngIf="playing" type="button" mat-button @@ -31,22 +31,22 @@ <mat-icon>pause</mat-icon> </button> </ng-container> - <ng-container *ngIf="elementModel.maxRuns && elementModel.showRestRuns"> + <ng-container *ngIf="playerProperties.maxRuns && playerProperties.showRestRuns"> <div class="runs mat-typography"> - {{ runCounter + 1 }} / {{ elementModel.maxRuns }} + {{ runCounter + 1 }} / {{ playerProperties.maxRuns }} </div> </ng-container> - <ng-container *ngIf="elementModel.progressBar"> + <ng-container *ngIf="playerProperties.progressBar"> <mat-slider class="duration" min="0" step="1" [max]="player.duration" [value]="player.currentTime" - [disabled]="disabled || !elementModel.interactiveProgressbar || !active || !dependencyDissolved" + [disabled]="disabled || !playerProperties.interactiveProgressbar || !active || !dependencyDissolved" (input)="onTimeChange($event)"> </mat-slider> </ng-container> - <ng-container *ngIf="elementModel.showRestTime"> + <ng-container *ngIf="playerProperties.showRestTime"> <div *ngIf="!restTimeMode" class="time mat-typography" (click)="toggleTime()"> @@ -58,7 +58,7 @@ {{currentRestTime ? '-' : ''}}{{currentRestTime | playerTimeFormat}} </div> </ng-container> - <ng-container *ngIf="elementModel.muteControl"> + <ng-container *ngIf="playerProperties.muteControl"> <button mat-button type="button" class="control-button enabled-control" @@ -67,7 +67,7 @@ <mat-icon *ngIf="player.muted">volume_off</mat-icon> </button> </ng-container> - <ng-container *ngIf="elementModel.volumeControl"> + <ng-container *ngIf="playerProperties.volumeControl"> <mat-slider class="volume" min="0" step="0.01" @@ -79,6 +79,5 @@ </div> <div *ngIf="showHint || project === 'editor'" class="status-bar mat-typography"> - {{elementModel.hintLabel}} + {{playerProperties.hintLabel}} </div> - diff --git a/projects/common/element-components/control-bar/control-bar.component.ts b/projects/common/components/control-bar/control-bar.component.ts similarity index 77% rename from projects/common/element-components/control-bar/control-bar.component.ts rename to projects/common/components/control-bar/control-bar.component.ts index af8faa3ee..9d4546bb7 100644 --- a/projects/common/element-components/control-bar/control-bar.component.ts +++ b/projects/common/components/control-bar/control-bar.component.ts @@ -2,9 +2,9 @@ import { OnInit, OnChanges, SimpleChanges, OnDestroy, Component, EventEmitter, Input, Output } from '@angular/core'; import { MatSliderChange } from '@angular/material/slider'; -import { AudioElement } from '../../models/audio-element'; -import { VideoElement } from '../../models/video-element'; -import { ValueChangeElement } from '../../models/uI-element'; +import { AudioElement } from '../../ui-elements/audio/audio-element'; +import { VideoElement } from '../../ui-elements/video/video-element'; +import { PlayerProperties, ValueChangeElement } from '../../models/uI-element'; @Component({ selector: 'app-control-bar', @@ -13,7 +13,8 @@ import { ValueChangeElement } from '../../models/uI-element'; }) export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { @Input() player!: HTMLVideoElement | HTMLAudioElement; - @Input() elementModel!: AudioElement | VideoElement; + @Input() id!: string; + @Input() playerProperties!: PlayerProperties; @Input() project!: 'player' | 'editor'; @Input() active!: boolean; @Input() dependencyDissolved!: boolean; @@ -39,7 +40,7 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { // hideOtherPages: boolean; // false (Solange nicht vollständig gespielt, sind alle anderen Seiten verborgen) ngOnInit(): void { - this.dependencyDissolved = !this.elementModel.activeAfterID; + this.dependencyDissolved = !this.playerProperties.activeAfterID; this.player.ondurationchange = () => this.initTimeValues(); this.player.ontimeupdate = () => { this.currentTime = this.player.currentTime / 60; @@ -59,7 +60,7 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { this.player.onended = () => { if (!this.checkDisabledState(this.runCounter + 1)) { this.runCounter += 1; - if (this.elementModel.loop) { + if (this.playerProperties.loop) { this._play(); } } @@ -68,7 +69,7 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { this.player.onvolumechange = () => { this.player.muted = !this.player.volume; }; - this.player.volume = this.elementModel.defaultVolume; + this.player.volume = this.playerProperties.defaultVolume; this.lastVolume = this.player.volume; } @@ -91,8 +92,8 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { } onVolumeChange(event: MatSliderChange): void { - event.source.value = event.value && event.value > this.elementModel.minVolume ? - event.value : this.elementModel.minVolume; + event.source.value = event.value && event.value > this.playerProperties.minVolume ? + event.value : this.playerProperties.minVolume; } toggleTime(): void { @@ -100,24 +101,24 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { } toggleVolume(): void { - if (this.player.volume > this.elementModel.minVolume) { + if (this.player.volume > this.playerProperties.minVolume) { this.lastVolume = this.player.volume; - this.player.volume = this.elementModel.minVolume; + this.player.volume = this.playerProperties.minVolume; } else { this.player.volume = this.lastVolume; } } private checkValidState(runCounter: number): boolean { - this.valid = this.elementModel.minRuns === 0 ? true : runCounter >= this.elementModel.minRuns; + this.valid = this.playerProperties.minRuns === 0 ? true : runCounter >= this.playerProperties.minRuns; if (this.valid) { - this.onMediaValidStatusChanged.emit(this.elementModel.id); + this.onMediaValidStatusChanged.emit(this.id); } return this.valid; } private checkDisabledState(runCounter: number): boolean { - this.disabled = !this.elementModel.maxRuns ? false : this.elementModel.maxRuns <= runCounter; + this.disabled = !this.playerProperties.maxRuns ? false : this.playerProperties.maxRuns <= runCounter; return this.disabled; } @@ -130,22 +131,22 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { } private initAutostart(): void { - if (this.elementModel.autostart) { + if (this.playerProperties.autostart) { setTimeout(() => { if (!this.started && this.dependencyDissolved) { this._play(); } - }, this.elementModel.autostartDelay); + }, this.playerProperties.autostartDelay); } } private initHint(): void { - if (this.elementModel.hintLabel) { + if (this.playerProperties.hintLabel) { setTimeout(() => { if (!this.started && this.dependencyDissolved) { this.showHint = true; } - }, this.elementModel.hintLabelDelay); + }, this.playerProperties.hintLabelDelay); } } @@ -157,7 +158,7 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { private sendPlaybackTimeChanged() { this.elementValueChanged.emit({ - id: this.elementModel.id, + id: this.id, values: [this.playbackTime, this.toPlaybackTime()] }); } @@ -176,8 +177,8 @@ export class ControlBarComponent implements OnInit, OnChanges, OnDestroy { if ((this.player.duration !== Infinity) && this.player.duration) { this.duration = this.player.duration / 60; this.currentRestTime = (this.player.duration - this.player.currentTime) / 60; - this.runCounter = Math.floor(this.elementModel.playbackTime); - this.player.currentTime = (this.elementModel.playbackTime - this.runCounter) * this.player.duration; + this.runCounter = Math.floor(this.playerProperties.playbackTime); + this.player.currentTime = (this.playerProperties.playbackTime - this.runCounter) * this.player.duration; this.checkDisabledState(this.runCounter); this.checkValidState(this.runCounter); } else { diff --git a/projects/common/element-components/control-bar/player-time-format.pipe.ts b/projects/common/components/control-bar/player-time-format.pipe.ts similarity index 100% rename from projects/common/element-components/control-bar/player-time-format.pipe.ts rename to projects/common/components/control-bar/player-time-format.pipe.ts diff --git a/projects/common/element-components/compound-elements/compound-element.directive.ts b/projects/common/directives/compound-element.directive.ts similarity index 82% rename from projects/common/element-components/compound-elements/compound-element.directive.ts rename to projects/common/directives/compound-element.directive.ts index d5b4504b1..78329ce7f 100644 --- a/projects/common/element-components/compound-elements/compound-element.directive.ts +++ b/projects/common/directives/compound-element.directive.ts @@ -3,8 +3,8 @@ import { Directive, EventEmitter, Output, QueryList } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { ElementComponent } from '../../element-component.directive'; -import { InputElement, ValueChangeElement } from '../../models/uI-element'; +import { ElementComponent } from './element-component.directive'; +import { InputElement, ValueChangeElement } from '../models/uI-element'; @Directive({ selector: 'app-compound-element' }) diff --git a/projects/common/element-component.directive.ts b/projects/common/directives/element-component.directive.ts similarity index 91% rename from projects/common/element-component.directive.ts rename to projects/common/directives/element-component.directive.ts index 192a635d0..0999d8041 100644 --- a/projects/common/element-component.directive.ts +++ b/projects/common/directives/element-component.directive.ts @@ -2,7 +2,7 @@ import { AfterContentChecked, Directive, ElementRef } from '@angular/core'; -import { UIElement } from './models/uI-element'; +import { UIElement } from '../models/uI-element'; @Directive() export abstract class ElementComponent implements AfterContentChecked { diff --git a/projects/common/form-element-component.directive.ts b/projects/common/directives/form-element-component.directive.ts similarity index 98% rename from projects/common/form-element-component.directive.ts rename to projects/common/directives/form-element-component.directive.ts index 012578d96..4439ea03b 100644 --- a/projects/common/form-element-component.directive.ts +++ b/projects/common/directives/form-element-component.directive.ts @@ -7,7 +7,7 @@ import { import { Subject } from 'rxjs'; import { pairwise, startWith, takeUntil } from 'rxjs/operators'; import { ElementComponent } from './element-component.directive'; -import { InputElement, InputElementValue, ValueChangeElement } from './models/uI-element'; +import { InputElement, InputElementValue, ValueChangeElement } from '../models/uI-element'; @Directive() export abstract class FormElementComponent extends ElementComponent implements OnInit, OnDestroy { diff --git a/projects/common/element-components/directives/input-background-color.directive.ts b/projects/common/directives/input-background-color.directive.ts similarity index 100% rename from projects/common/element-components/directives/input-background-color.directive.ts rename to projects/common/directives/input-background-color.directive.ts diff --git a/projects/common/media-player-element-component.directive.ts b/projects/common/directives/media-player-element-component.directive.ts similarity index 92% rename from projects/common/media-player-element-component.directive.ts rename to projects/common/directives/media-player-element-component.directive.ts index fa698c833..c5bc5f205 100644 --- a/projects/common/media-player-element-component.directive.ts +++ b/projects/common/directives/media-player-element-component.directive.ts @@ -1,5 +1,5 @@ import { Directive, EventEmitter, Output } from '@angular/core'; -import { ValueChangeElement } from './models/uI-element'; +import { ValueChangeElement } from '../models/uI-element'; import { ElementComponent } from './element-component.directive'; @Directive() diff --git a/projects/common/interfaces/UIElementInterfaces.ts b/projects/common/interfaces/UIElementInterfaces.ts deleted file mode 100644 index 5f7c42a7f..000000000 --- a/projects/common/interfaces/UIElementInterfaces.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { UIElement } from '../models/uI-element'; - -export interface FontElement { - fontColor: string; - font: string; - fontSize: number; - lineHeight: number; - bold: boolean; - italic: boolean; - underline: boolean; -} - -export interface SurfaceUIElement { - backgroundColor: string; -} - -export interface PlayerElement { - autostart: boolean; - autostartDelay: number; - loop: boolean; - startControl: boolean; - pauseControl: boolean; - progressBar: boolean; - interactiveProgressbar: boolean; - volumeControl: boolean; - defaultVolume: number; - minVolume: number; - muteControl: boolean; - hintLabel: string; - hintLabelDelay: number; - uninterruptible: boolean; - hideOtherPages: boolean; - activeAfterID: string; - minRuns: number; - maxRuns: number | null; - showRestRuns: boolean; - showRestTime: boolean; - playbackTime: number; -} - -export interface LikertColumn { - text: string; - imgSrc: string | null; - position: 'above' | 'below'; -} - -export interface LikertRow { - text: string; - columnCount: number; -} - -export interface ClozePart { - type: string; - value: string | UIElement; - style?: string; -} diff --git a/projects/common/models/audio-element.ts b/projects/common/models/audio-element.ts deleted file mode 100644 index 9bfab2aa2..000000000 --- a/projects/common/models/audio-element.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { UIElement } from './uI-element'; -import { PlayerElement } from '../interfaces/UIElementInterfaces'; -import { initPlayerElement } from '../util/unit-interface-initializer'; - -export class AudioElement extends UIElement implements PlayerElement { - src: string = ''; - - autostart: boolean = false; - autostartDelay: number = 0; - loop: boolean = false; - startControl: boolean = true; - pauseControl: boolean = false; - progressBar: boolean = true; - interactiveProgressbar: boolean = false; - volumeControl: boolean = true; - defaultVolume: number = 0.8; - minVolume: number = 0; - muteControl: boolean = true; - hintLabel: string = ''; - hintLabelDelay: number = 0; - uninterruptible: boolean = false; - hideOtherPages: boolean = false; - activeAfterID: string = ''; - minRuns: number = 1; - maxRuns: number | null = null; - showRestRuns: boolean = false; - showRestTime: boolean = true; - playbackTime: number = 0; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initPlayerElement(serializedElement)); - this.height = serializedElement.height || 90; - this.width = serializedElement.width || 250; - } -} diff --git a/projects/common/models/button-element.ts b/projects/common/models/button-element.ts deleted file mode 100644 index 7e189f55f..000000000 --- a/projects/common/models/button-element.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { UIElement } from './uI-element'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class ButtonElement extends UIElement implements FontElement, SurfaceUIElement { - label: string = 'Knopf'; - imageSrc: string | null = null; - borderRadius: number = 0; - action: null | 'previous' | 'next' | 'first' | 'last' | 'end' = null; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - } -} diff --git a/projects/common/models/checkbox-element.ts b/projects/common/models/checkbox-element.ts deleted file mode 100644 index 4f748b1d2..000000000 --- a/projects/common/models/checkbox-element.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { InputElement, UIElement } from './uI-element'; -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class CheckboxElement extends InputElement implements FontElement, SurfaceUIElement { - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.value = serializedElement.value as boolean || false; // booleans are always initialized false - - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - } -} diff --git a/projects/common/models/compound-elements/drop-list.ts b/projects/common/models/compound-elements/drop-list.ts deleted file mode 100644 index dbec05359..000000000 --- a/projects/common/models/compound-elements/drop-list.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { InputElement, UIElement } from '../uI-element'; -import { FontElement, SurfaceUIElement } from '../../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../../util/unit-interface-initializer'; - -export class DropListElement extends InputElement implements FontElement, SurfaceUIElement { - onlyOneItem: boolean = false; - connectedTo: string[] = []; - orientation: 'vertical' | 'horizontal' = 'vertical'; - itemBackgroundColor: string = '#add8e6'; - highlightReceivingDropList: boolean = false; - highlightReceivingDropListColor: string = '#add8e6'; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.value = serializedElement.value as string[] || []; - this.height = serializedElement.height || 100; - this.backgroundColor = serializedElement.backgroundColor as string || '#eeeeec'; - - this.handleBackwardsCompatibility(serializedElement); - } - - handleBackwardsCompatibility(serializedElement: UIElement): void { - if (serializedElement.options) { - this.value = serializedElement.options as string[]; - } - } -} diff --git a/projects/common/models/compound-elements/radio-group-images.ts b/projects/common/models/compound-elements/radio-group-images.ts deleted file mode 100644 index 68934fed7..000000000 --- a/projects/common/models/compound-elements/radio-group-images.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { InputElement, UIElement } from '../uI-element'; -import { LikertColumn, FontElement, SurfaceUIElement } from '../../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../../util/unit-interface-initializer'; - -export class RadioGroupImagesElement extends InputElement implements FontElement, SurfaceUIElement { - columns: LikertColumn[] = []; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.height = serializedElement.height || 100; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - } -} diff --git a/projects/common/models/dropdown-element.ts b/projects/common/models/dropdown-element.ts deleted file mode 100644 index 3773e738f..000000000 --- a/projects/common/models/dropdown-element.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { InputElement, UIElement } from './uI-element'; -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class DropdownElement extends InputElement implements FontElement, SurfaceUIElement { - options: string[] = []; - allowUnset: boolean = false; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.height = serializedElement.height || 83; - } -} diff --git a/projects/common/models/radio-button-group-element.ts b/projects/common/models/radio-button-group-element.ts deleted file mode 100644 index b09d2f485..000000000 --- a/projects/common/models/radio-button-group-element.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { InputElement, UIElement } from './uI-element'; -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class RadioButtonGroupElement extends InputElement implements FontElement, SurfaceUIElement { - options: string[] = []; - alignment: 'column' | 'row' = 'column'; - strikeOtherOptions: boolean = false; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.height = serializedElement.height || 85; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - } -} diff --git a/projects/common/models/section.ts b/projects/common/models/section.ts index 124ac1e92..e62396e53 100644 --- a/projects/common/models/section.ts +++ b/projects/common/models/section.ts @@ -1,11 +1,12 @@ import { + PositionedElement, UIElement } from './uI-element'; import * as ElementFactory from '../util/element.factory'; export class Section { [index: string]: string | number | boolean | UIElement[] | ((...args: any) => any); - elements: UIElement[] = []; + elements: PositionedElement[] = []; height: number = 400; backgroundColor: string = 'white'; dynamicPositioning: boolean = false; @@ -19,12 +20,12 @@ export class Section { this.elements = []; if (serializedSection) { serializedSection?.elements.forEach((element: UIElement) => { - this.elements.push(ElementFactory.createElement(element)); + this.elements.push(ElementFactory.createElement(element) as PositionedElement); }); } } - addElement(element: UIElement): void { + addElement(element: PositionedElement): void { this.elements.push(element); } @@ -47,41 +48,42 @@ export class Section { }); } - duplicateElements(elements: UIElement[]): void { - elements.forEach((element: UIElement) => { + duplicateElements(elements: PositionedElement[]): void { + elements.forEach((element: PositionedElement) => { const newElementConfig: Record<string, string | number | boolean | string[]> = { ...element } as Record<string, string | number | boolean | string[]>; delete newElementConfig.id; // remove ID from object, so a new one is created - const newElement: UIElement = ElementFactory.createElement(newElementConfig as UIElement); - newElement.xPosition += 10; - newElement.yPosition += 10; + const newElement: PositionedElement = + ElementFactory.createElement(newElementConfig as UIElement) as PositionedElement; + newElement.positionProps.xPosition += 10; + newElement.positionProps.yPosition += 10; this.elements.push(newElement); }); } - static alignElements(elements: UIElement[], alignmentDirection: 'left' | 'right' | 'top' | 'bottom'): void { + static alignElements(elements: PositionedElement[], alignmentDirection: 'left' | 'right' | 'top' | 'bottom'): void { let newValue: number; switch (alignmentDirection) { case 'left': - newValue = Math.min(...elements.map(element => element.xPosition)); + newValue = Math.min(...elements.map(element => element.positionProps.xPosition)); elements.forEach((element: UIElement) => { element.xPosition = newValue; }); break; case 'right': - newValue = Math.max(...elements.map(element => element.xPosition + element.width)); + newValue = Math.max(...elements.map(element => element.positionProps.xPosition + element.width)); elements.forEach((element: UIElement) => { element.xPosition = newValue - element.width; }); break; case 'top': - newValue = Math.min(...elements.map(element => element.yPosition)); + newValue = Math.min(...elements.map(element => element.positionProps.yPosition)); elements.forEach((element: UIElement) => { element.yPosition = newValue; }); break; case 'bottom': - newValue = Math.max(...elements.map(element => element.yPosition + element.height)); + newValue = Math.max(...elements.map(element => element.positionProps.yPosition + element.height)); elements.forEach((element: UIElement) => { element.yPosition = newValue - element.height; }); diff --git a/projects/common/models/text-area-element.ts b/projects/common/models/text-area-element.ts deleted file mode 100644 index 3b28683e9..000000000 --- a/projects/common/models/text-area-element.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { InputElement, UIElement } from './uI-element'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class TextAreaElement extends InputElement implements FontElement, SurfaceUIElement { - appearance: 'standard' | 'legacy' | 'fill' | 'outline' = 'outline'; - resizeEnabled: boolean = false; - rowCount: number = 3; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - inputAssistancePreset: 'none' | 'french' | 'numbers' | 'numbersAndOperators' = 'none'; - inputAssistancePosition: 'floating' | 'right' = 'floating'; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.height = serializedElement.height || 132; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - } -} diff --git a/projects/common/models/text-element.ts b/projects/common/models/text-element.ts deleted file mode 100644 index 875c1c3fc..000000000 --- a/projects/common/models/text-element.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { UIElement } from './uI-element'; -import { SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { initSurfaceElement } from '../util/unit-interface-initializer'; - -export class TextElement extends UIElement implements SurfaceUIElement { - text: string = '<p>Lorem ipsum dolor sit amet</p>'; - interaction: 'none' | 'highlightable' | 'underlinable' | 'strikable' = 'none'; - fontColor: string = 'black'; - font: string = 'Roboto'; - lineHeight: number = 135; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initSurfaceElement(serializedElement)); - this.fontColor = serializedElement.fontColor as string || 'black'; - this.font = serializedElement.font as string || 'Roboto'; - this.bold = serializedElement.bold as boolean || false; - this.italic = serializedElement.italic as boolean || false; - this.underline = serializedElement.underline as boolean || false; - - this.height = serializedElement.height || 78; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - - this.handleBackwardsCompatibility(serializedElement); - } - - handleBackwardsCompatibility(serializedElement: UIElement): void { - if (serializedElement.highlightable) { - this.interaction = 'highlightable'; - } - } -} diff --git a/projects/common/models/text-field-element.ts b/projects/common/models/text-field-element.ts deleted file mode 100644 index 639db0d8c..000000000 --- a/projects/common/models/text-field-element.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { InputElement, UIElement } from './uI-element'; -import { FontElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { initFontElement, initSurfaceElement } from '../util/unit-interface-initializer'; - -export class TextFieldElement extends InputElement implements FontElement, SurfaceUIElement { - appearance: 'standard' | 'legacy' | 'fill' | 'outline' = 'outline'; - minLength: number = 0; - minLengthWarnMessage: string = 'Eingabe zu kurz'; - maxLength: number = 0; - maxLengthWarnMessage: string = 'Eingabe zu lang'; - pattern: string = ''; - patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; - - inputAssistancePreset: 'none' | 'french' | 'numbers' | 'numbersAndOperators' = 'none'; - inputAssistancePosition: 'floating' | 'right' = 'floating'; - - clearable: boolean = false; - - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); - - this.height = serializedElement.height || 100; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; - } -} diff --git a/projects/common/models/uI-element.ts b/projects/common/models/uI-element.ts index c006d6afa..251d08657 100644 --- a/projects/common/models/uI-element.ts +++ b/projects/common/models/uI-element.ts @@ -1,39 +1,24 @@ // eslint-disable-next-line max-classes-per-file import { IdService } from '../id.service'; -import { LikertColumn, LikertRow, ClozePart } from '../interfaces/UIElementInterfaces'; export type UIElementType = 'text' | 'button' | 'text-field' | 'text-area' | 'checkbox' | 'dropdown' | 'radio' | 'image' | 'audio' | 'video' | 'likert' | 'likert_row' | 'radio-group-images' | 'drop-list' | 'cloze'; export type InputElementValue = string[] | string | number | boolean | null; -export interface ValueChangeElement { - id: string; - values: [InputElementValue, InputElementValue]; -} - export abstract class UIElement { - [index: string]: InputElementValue | LikertColumn[] | LikertRow[] | ClozePart[] - | UIElement[] | ClozePart[][] | ((...args: any) => any); + [index: string]: any; type!: UIElementType; id: string = 'id_placeholder'; - zIndex: number = 0; width: number = 180; height: number = 60; - dynamicPositioning: boolean = false; - xPosition: number = 0; - yPosition: number = 0; - useMinHeight: boolean = false; - gridColumnStart: number = 1; - gridColumnEnd: number = 2; - gridRowStart: number = 1; - gridRowEnd: number = 2; - marginLeft: number = 0; - marginRight: number = 0; - marginTop: number = 0; - marginBottom: number = 0; + + positionProps?: PositionProperties; + fontProps?: FontProperties; + surfaceProps?: SurfaceProperties; + playerProps?: PlayerProperties; protected constructor(serializedElement: UIElement) { Object.assign(this, serializedElement); @@ -42,10 +27,36 @@ export abstract class UIElement { } } + getProperty(property: string): any { + if (this.fontProps && property in this.fontProps) { + return this.fontProps[property]; + } + if (this.surfaceProps && property in this.surfaceProps) { + return this.surfaceProps[property]; + } + if (this.playerProps && property in this.playerProps) { + return this.playerProps[property]; + } + if (this.positionProps && property in this.positionProps) { + return this.positionProps[property]; + } + return this[property]; + } + // This can be overwritten by elements if they need to handle some property specifics. Likert does. setProperty(property: string, value: InputElementValue | string[] | LikertColumn[] | LikertRow[]): void { - this[property] = value; + if (this.fontProps && property in this.fontProps) { + this.fontProps[property] = value as string | number | boolean; + } else if (this.surfaceProps && property in this.surfaceProps) { + this.surfaceProps[property] = value as string; + } else if (this.playerProps && property in this.playerProps) { + this.playerProps[property] = value as string; + } else if (this.positionProps && property in this.positionProps) { + this.positionProps[property] = value as string; + } else { + this[property] = value; + } } } @@ -68,3 +79,93 @@ export abstract class InputElement extends UIElement { } export abstract class CompoundElement extends UIElement {} + +export interface ValueChangeElement { + id: string; + values: [InputElementValue, InputElementValue]; +} + +export interface PositionedElement extends UIElement { + positionProps: PositionProperties; +} + +export interface PositionProperties { + [index: string]: string | number | boolean; + dynamicPositioning: boolean; + xPosition: number; + yPosition: number; + useMinHeight: boolean; + gridColumnStart: number; + gridColumnEnd: number; + gridRowStart: number; + gridRowEnd: number; + marginLeft: number; + marginRight: number; + marginTop: number; + marginBottom: number; + zIndex: number; +} + +export interface FontElement { + fontProps: FontProperties; +} + +export interface FontProperties { + [index: string]: string | number | boolean | undefined; + fontColor?: string; + font?: string; + fontSize?: number; + lineHeight?: number; + bold?: boolean; + italic?: boolean; + underline?: boolean; +} + +export interface SurfaceElement { + surfaceProps: SurfaceProperties; +} + +export interface SurfaceProperties { + [index: string]: string; + backgroundColor: string; +} + +export interface PlayerElement { + playerProps: PlayerProperties; +} + +export interface PlayerProperties { + [index: string]: string | number | boolean | null; + autostart: boolean; + autostartDelay: number; + loop: boolean; + startControl: boolean; + pauseControl: boolean; + progressBar: boolean; + interactiveProgressbar: boolean; + volumeControl: boolean; + defaultVolume: number; + minVolume: number; + muteControl: boolean; + hintLabel: string; + hintLabelDelay: number; + uninterruptible: boolean; + hideOtherPages: boolean; + activeAfterID: string; + minRuns: number; + maxRuns: number | null; + showRestRuns: boolean; + showRestTime: boolean; + playbackTime: number; +} + +export interface LikertColumn { + text: string; + imgSrc: string | null; + position: 'above' | 'below'; +} + +export interface LikertRow { + text: string; + columnCount: number; +} diff --git a/projects/common/models/video-element.ts b/projects/common/models/video-element.ts deleted file mode 100644 index 987fea472..000000000 --- a/projects/common/models/video-element.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { UIElement } from './uI-element'; -import { initPlayerElement } from '../util/unit-interface-initializer'; -import { PlayerElement } from '../interfaces/UIElementInterfaces'; - -export class VideoElement extends UIElement implements PlayerElement { - src: string = ''; - - autostart: boolean = false; - autostartDelay: number = 0; - loop: boolean = false; - startControl: boolean = true; - pauseControl: boolean = false; - progressBar: boolean = true; - interactiveProgressbar: boolean = false; - volumeControl: boolean = true; - defaultVolume: number = 0.8; - minVolume: number = 0; - muteControl: boolean = true; - hintLabel: string = ''; - hintLabelDelay: number = 0; - uninterruptible: boolean = false; - hideOtherPages: boolean = false; - activeAfterID: string = ''; - minRuns: number = 1; - maxRuns: number | null = null; - showRestRuns: boolean = false; - showRestTime: boolean = true; - playbackTime: number = 0; - - constructor(serializedElement: UIElement) { - super(serializedElement); - Object.assign(this, serializedElement); - Object.assign(this, initPlayerElement(serializedElement)); - this.height = serializedElement.height || 230; - this.width = serializedElement.width || 280; - } -} diff --git a/projects/common/element-components/pipes/error-transform.pipe.ts b/projects/common/pipes/error-transform.pipe.ts similarity index 94% rename from projects/common/element-components/pipes/error-transform.pipe.ts rename to projects/common/pipes/error-transform.pipe.ts index 8e69f4d21..9edf676b7 100644 --- a/projects/common/element-components/pipes/error-transform.pipe.ts +++ b/projects/common/pipes/error-transform.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from '@angular/core'; import { ValidationErrors } from '@angular/forms'; -import { UIElement } from '../../models/uI-element'; +import { UIElement } from '../models/uI-element'; @Pipe({ name: 'errorTransform' diff --git a/projects/common/element-components/pipes/safe-resource-html.pipe.ts b/projects/common/pipes/safe-resource-html.pipe.ts similarity index 100% rename from projects/common/element-components/pipes/safe-resource-html.pipe.ts rename to projects/common/pipes/safe-resource-html.pipe.ts diff --git a/projects/common/element-components/pipes/safe-resource-url.pipe.ts b/projects/common/pipes/safe-resource-url.pipe.ts similarity index 100% rename from projects/common/element-components/pipes/safe-resource-url.pipe.ts rename to projects/common/pipes/safe-resource-url.pipe.ts diff --git a/projects/common/message.service.ts b/projects/common/services/message.service.ts similarity index 100% rename from projects/common/message.service.ts rename to projects/common/services/message.service.ts diff --git a/projects/common/shared.module.ts b/projects/common/shared.module.ts index 464646b9d..fdebce769 100644 --- a/projects/common/shared.module.ts +++ b/projects/common/shared.module.ts @@ -3,14 +3,10 @@ import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { MatToolbarModule } from '@angular/material/toolbar'; import { MatSelectModule } from '@angular/material/select'; import { MatIconModule } from '@angular/material/icon'; -import { MatListModule } from '@angular/material/list'; import { MatInputModule } from '@angular/material/input'; -import { MatSidenavModule } from '@angular/material/sidenav'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatExpansionModule } from '@angular/material/expansion'; import { MatRadioModule } from '@angular/material/radio'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -22,29 +18,29 @@ import { MatTooltipModule } from '@angular/material/tooltip'; import { TranslateModule } from '@ngx-translate/core'; import { MatDialogModule } from '@angular/material/dialog'; import { MatSliderModule } from '@angular/material/slider'; -import { TextComponent } from './element-components/text.component'; -import { ButtonComponent } from './element-components/button.component'; -import { TextFieldComponent } from './element-components/text-field.component'; -import { TextAreaComponent } from './element-components/text-area.component'; -import { CheckboxComponent } from './element-components/checkbox.component'; -import { DropdownComponent } from './element-components/dropdown.component'; -import { RadioButtonGroupComponent } from './element-components/radio-button-group.component'; -import { ImageComponent } from './element-components/image.component'; -import { VideoComponent } from './element-components/video.component'; -import { AudioComponent } from './element-components/audio.component'; -import { SafeResourceUrlPipe } from './element-components/pipes/safe-resource-url.pipe'; -import { InputBackgroundColorDirective } from './element-components/directives/input-background-color.directive'; -import { ErrorTransformPipe } from './element-components/pipes/error-transform.pipe'; -import { SafeResourceHTMLPipe } from './element-components/pipes/safe-resource-html.pipe'; -import { ControlBarComponent } from './element-components/control-bar/control-bar.component'; -import { PlayerTimeFormatPipe } from './element-components/control-bar/player-time-format.pipe'; -import { LikertComponent } from './element-components/compound-elements/likert.component'; -import { LikertRadioButtonGroupComponent } from './element-components/compound-elements/likert-radio-button-group.component'; -import { Magnifier } from './element-components/magnifier.component'; -import { RadioGroupImagesComponent } from './element-components/compound-elements/radio-group-images.component'; -import { DropListComponent } from './element-components/compound-elements/drop-list.component'; -import { ClozeComponent } from './element-components/compound-elements/cloze.component'; -import { TextFieldSimpleComponent } from './element-components/text-field-simple.component'; +import { TextComponent } from './ui-elements/text/text.component'; +import { ButtonComponent } from './ui-elements/button/button.component'; +import { TextFieldComponent } from './ui-elements/text-field/text-field.component'; +import { TextAreaComponent } from './ui-elements/text-area/text-area.component'; +import { CheckboxComponent } from './ui-elements/checkbox/checkbox.component'; +import { DropdownComponent } from './ui-elements/dropdown/dropdown.component'; +import { RadioButtonGroupComponent } from './ui-elements/radio/radio-button-group.component'; +import { ImageComponent } from './ui-elements/image/image.component'; +import { VideoComponent } from './ui-elements/video/video.component'; +import { AudioComponent } from './ui-elements/audio/audio.component'; +import { SafeResourceUrlPipe } from './pipes/safe-resource-url.pipe'; +import { InputBackgroundColorDirective } from './directives/input-background-color.directive'; +import { ErrorTransformPipe } from './pipes/error-transform.pipe'; +import { SafeResourceHTMLPipe } from './pipes/safe-resource-html.pipe'; +import { ControlBarComponent } from './components/control-bar/control-bar.component'; +import { PlayerTimeFormatPipe } from './components/control-bar/player-time-format.pipe'; +import { LikertComponent } from './ui-elements/likert/likert.component'; +import { LikertRadioButtonGroupComponent } from './ui-elements/likert/likert-radio-button-group.component'; +import { Magnifier } from './ui-elements/image/magnifier.component'; +import { RadioGroupImagesComponent } from './ui-elements/radio-with-images/radio-group-images.component'; +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'; @NgModule({ imports: [ @@ -92,31 +88,12 @@ import { TextFieldSimpleComponent } from './element-components/text-field-simple exports: [ CommonModule, FlexLayoutModule, - MatToolbarModule, MatIconModule, MatTabsModule, - MatButtonModule, - MatInputModule, FormsModule, ReactiveFormsModule, DragDropModule, - MatCheckboxModule, - MatSelectModule, - MatRadioModule, - MatListModule, - MatExpansionModule, - MatSidenavModule, MatFormFieldModule, - ButtonComponent, - TextComponent, - TextFieldComponent, - TextAreaComponent, - ImageComponent, - AudioComponent, - VideoComponent, - RadioButtonGroupComponent, - CheckboxComponent, - DropdownComponent, MatSnackBarModule, MatTooltipModule, MatDialogModule, diff --git a/projects/common/ui-elements/audio/audio-element.ts b/projects/common/ui-elements/audio/audio-element.ts new file mode 100644 index 000000000..a8bf96ace --- /dev/null +++ b/projects/common/ui-elements/audio/audio-element.ts @@ -0,0 +1,19 @@ +import { PlayerElement, PlayerProperties, PositionedElement, PositionProperties, UIElement } from '../../models/uI-element'; +import { initPlayerElement, initPositionedElement } from '../../util/unit-interface-initializer'; + +export class AudioElement extends UIElement implements PositionedElement, PlayerElement { + src: string = ''; + + positionProps: PositionProperties; + playerProps: PlayerProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.playerProps = initPlayerElement(serializedElement); + + this.height = serializedElement.height || 90; + this.width = serializedElement.width || 250; + } +} diff --git a/projects/common/element-components/audio.component.ts b/projects/common/ui-elements/audio/audio.component.ts similarity index 77% rename from projects/common/element-components/audio.component.ts rename to projects/common/ui-elements/audio/audio.component.ts index db5cc3c1a..39d7f65b8 100644 --- a/projects/common/element-components/audio.component.ts +++ b/projects/common/ui-elements/audio/audio.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { AudioElement } from '../models/audio-element'; -import { MediaPlayerElementComponent } from '../media-player-element-component.directive'; +import { AudioElement } from './audio-element'; +import { MediaPlayerElementComponent } from '../../directives/media-player-element-component.directive'; @Component({ selector: 'app-audio', @@ -15,7 +15,8 @@ import { MediaPlayerElementComponent } from '../media-player-element-component.d </audio> <app-control-bar [player]="player" [project]="project" - [elementModel]="elementModel" + [id]="elementModel.id" + [playerProperties]="elementModel.playerProps" [active]="active" [dependencyDissolved]="dependencyDissolved" (onMediaValidStatusChanged)="onMediaValidStatusChanged.emit($event)" diff --git a/projects/common/ui-elements/button/button-element.ts b/projects/common/ui-elements/button/button-element.ts new file mode 100644 index 000000000..7378189a5 --- /dev/null +++ b/projects/common/ui-elements/button/button-element.ts @@ -0,0 +1,28 @@ +import { + FontElement, + FontProperties, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class ButtonElement extends UIElement implements PositionedElement, FontElement, SurfaceElement { + label: string = 'Knopf'; + imageSrc: string | null = null; + borderRadius: number = 0; + action: null | 'previous' | 'next' | 'first' | 'last' | 'end' = null; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + } +} diff --git a/projects/common/element-components/button.component.ts b/projects/common/ui-elements/button/button.component.ts similarity index 67% rename from projects/common/element-components/button.component.ts rename to projects/common/ui-elements/button/button.component.ts index ee2127d56..5f08a3b66 100644 --- a/projects/common/element-components/button.component.ts +++ b/projects/common/ui-elements/button/button.component.ts @@ -1,8 +1,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ElementComponent } from '../element-component.directive'; -import { ButtonElement } from '../models/button-element'; +import { ElementComponent } from '../../directives/element-component.directive'; +import { ButtonElement } from './button-element'; @Component({ selector: 'app-button', @@ -11,13 +11,13 @@ import { ButtonElement } from '../models/button-element'; type='button' [style.width.%]="100" [style.height.%]="100" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" + [style.background-color]="elementModel.surfaceProps.backgroundColor" + [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.border-radius.px]="elementModel.borderRadius" (click)="onClick($event, elementModel.action)"> {{elementModel.label}} diff --git a/projects/common/ui-elements/checkbox/checkbox-element.ts b/projects/common/ui-elements/checkbox/checkbox-element.ts new file mode 100644 index 000000000..397b9e65b --- /dev/null +++ b/projects/common/ui-elements/checkbox/checkbox-element.ts @@ -0,0 +1,31 @@ +import { + FontElement, + FontProperties, + InputElement, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class CheckboxElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.value = serializedElement.value as boolean || false; // booleans are always initialized false + + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/element-components/checkbox.component.ts b/projects/common/ui-elements/checkbox/checkbox.component.ts similarity index 65% rename from projects/common/element-components/checkbox.component.ts rename to projects/common/ui-elements/checkbox/checkbox.component.ts index 52c1cb260..63f48f9a0 100644 --- a/projects/common/element-components/checkbox.component.ts +++ b/projects/common/ui-elements/checkbox/checkbox.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { ValidatorFn, Validators } from '@angular/forms'; -import { FormElementComponent } from '../form-element-component.directive'; -import { CheckboxElement } from '../models/checkbox-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { CheckboxElement } from './checkbox-element'; @Component({ selector: 'app-checkbox', @@ -9,16 +9,16 @@ import { CheckboxElement } from '../models/checkbox-element'; <div class="mat-form-field" [style.width.%]="100" [style.height.%]="100" - [style.background-color]="elementModel.backgroundColor"> + [style.background-color]="elementModel.surfaceProps.backgroundColor"> <mat-checkbox #checkbox class="example-margin" [formControl]="elementFormControl" [checked]="$any(elementModel.value)" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" + [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' : ''" (click)="elementModel.readOnly ? $event.preventDefault() : null"> <div [style.line-height.%]="elementModel.lineHeight" [innerHTML]="elementModel.label"></div> </mat-checkbox> diff --git a/projects/common/models/compound-elements/cloze-element.ts b/projects/common/ui-elements/cloze/cloze-element.ts similarity index 82% rename from projects/common/models/compound-elements/cloze-element.ts rename to projects/common/ui-elements/cloze/cloze-element.ts index 4132d926b..fcc11f406 100644 --- a/projects/common/models/compound-elements/cloze-element.ts +++ b/projects/common/ui-elements/cloze/cloze-element.ts @@ -1,39 +1,34 @@ import { - CompoundElement, InputElement, InputElementValue, UIElement -} from '../uI-element'; -import { - ClozePart, FontElement, LikertColumn, LikertRow -} from '../../interfaces/UIElementInterfaces'; -import { TextFieldElement } from '../text-field-element'; -import { TextAreaElement } from '../text-area-element'; -import { CheckboxElement } from '../checkbox-element'; -import { DropdownElement } from '../dropdown-element'; -import { DropListElement } from './drop-list'; + CompoundElement, FontElement, FontProperties, InputElement, InputElementValue, LikertColumn, LikertRow, UIElement +} from '../../models/uI-element'; +import { TextFieldElement } from '../text-field/text-field-element'; +import { TextAreaElement } from '../text-area/text-area-element'; +import { CheckboxElement } from '../checkbox/checkbox-element'; +import { DropdownElement } from '../dropdown/dropdown-element'; +import { DropListElement } from '../drop-list/drop-list'; import { initFontElement } from '../../util/unit-interface-initializer'; -import { TextFieldSimpleElement } from '../text-field-simple-element'; +import { TextFieldSimpleElement } from '../textfield-simple/text-field-simple-element'; // TODO styles like em dont continue after inserted components export class ClozeElement extends CompoundElement implements FontElement { text: string = '<p>Lorem ipsum dolor \\z sdfsdf \\i sdfsdf</p>'; + parts: { + type: string; + value: string | UIElement; + style?: string; + }[][] = []; - parts: ClozePart[][] = []; childElements: InputElement[] = []; - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 120; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; + fontProps: FontProperties; constructor(serializedElement: UIElement) { super(serializedElement); Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); + this.fontProps = initFontElement(serializedElement); this.height = 200; - this.width = 500; + this.width = 500; // TODO } setProperty(property: string, value: InputElementValue | string[] | LikertColumn[] | LikertRow[]): void { diff --git a/projects/common/element-components/compound-elements/cloze.component.ts b/projects/common/ui-elements/cloze/cloze.component.ts similarity index 84% rename from projects/common/element-components/compound-elements/cloze.component.ts rename to projects/common/ui-elements/cloze/cloze.component.ts index 74219b106..3a7efb715 100644 --- a/projects/common/element-components/compound-elements/cloze.component.ts +++ b/projects/common/ui-elements/cloze/cloze.component.ts @@ -1,22 +1,22 @@ import { Component, EventEmitter, Output, QueryList, ViewChildren } from '@angular/core'; -import { ClozeElement } from '../../models/compound-elements/cloze-element'; -import { CompoundElementComponent } from './compound-element.directive'; +import { ClozeElement } from './cloze-element'; +import { CompoundElementComponent } from '../../directives/compound-element.directive'; import { InputElement } from '../../models/uI-element'; -import { FormElementComponent } from '../../form-element-component.directive'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; @Component({ selector: 'app-cloze', template: ` <p *ngFor="let paragraph of elementModel.parts; let i = index" - [style.line-height.px]="elementModel.fontSize + 15" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + [style.line-height.px]="$any(elementModel.fontProps.fontSize) + 15" + [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' : ''"> <ng-container *ngFor="let part of paragraph; let j = index"> <span *ngIf="part.type === 'p'" diff --git a/projects/common/element-components/compound-elements/drop-list.component.ts b/projects/common/ui-elements/drop-list/drop-list.component.ts similarity index 82% rename from projects/common/element-components/compound-elements/drop-list.component.ts rename to projects/common/ui-elements/drop-list/drop-list.component.ts index 878bbd3af..5f711567d 100644 --- a/projects/common/element-components/compound-elements/drop-list.component.ts +++ b/projects/common/ui-elements/drop-list/drop-list.component.ts @@ -3,8 +3,8 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events'; import { CdkDrag, CdkDropList, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; -import { DropListElement } from '../../models/compound-elements/drop-list'; -import { FormElementComponent } from '../../form-element-component.directive'; +import { DropListElement } from './drop-list'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; @Component({ selector: 'app-drop-list', @@ -16,13 +16,13 @@ import { FormElementComponent } from '../../form-element-component.directive'; [class.dropList-highlight]="elementModel.highlightReceivingDropList" [style.border-color]="elementModel.highlightReceivingDropListColor" [style.border-width.px]="elementModel.highlightReceivingDropList ? 2 : 0" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" - [style.backgroundColor]="elementModel.backgroundColor" + [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" [style.display]="elementModel.orientation === 'horizontal' ? 'flex' : ''" [style.flex-direction]="elementModel.orientation === 'horizontal' ? 'row' : ''" cdkDropList @@ -35,11 +35,12 @@ import { FormElementComponent } from '../../form-element-component.directive'; <div class="item" *ngFor="let value of $any(elementModel.value)" cdkDrag [style.background-color]="elementModel.itemBackgroundColor"> <div *cdkDragPreview - [style.font-size.px]="elementModel.fontSize" + [style.font-size.px]="elementModel.fontProps.fontSize" [style.background-color]="elementModel.itemBackgroundColor"> {{value}} </div> - <div class="drag-placeholder" *cdkDragPlaceholder [style.min-height.px]="elementModel.fontSize"></div> + <div class="drag-placeholder" *cdkDragPlaceholder [style.min-height.px]="elementModel.fontProps.fontSize"> + </div> {{value}} </div> </div> diff --git a/projects/common/ui-elements/drop-list/drop-list.ts b/projects/common/ui-elements/drop-list/drop-list.ts new file mode 100644 index 000000000..491d4b804 --- /dev/null +++ b/projects/common/ui-elements/drop-list/drop-list.ts @@ -0,0 +1,46 @@ +import { + FontElement, + FontProperties, + InputElement, + PositionedElement, PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class DropListElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + onlyOneItem: boolean = false; + connectedTo: string[] = []; + orientation: 'vertical' | 'horizontal' = 'vertical'; + itemBackgroundColor: string = '#add8e6'; + highlightReceivingDropList: boolean = false; + highlightReceivingDropListColor: string = '#add8e6'; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(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 || + serializedElement.backgroundColor as string || + '#eeeeec'; + + this.handleBackwardsCompatibility(serializedElement); + } + + handleBackwardsCompatibility(serializedElement: UIElement): void { + if (serializedElement.options) { + this.value = serializedElement.options as string[]; + } + } +} diff --git a/projects/common/ui-elements/dropdown/dropdown-element.ts b/projects/common/ui-elements/dropdown/dropdown-element.ts new file mode 100644 index 000000000..e7f61b7ec --- /dev/null +++ b/projects/common/ui-elements/dropdown/dropdown-element.ts @@ -0,0 +1,29 @@ +import { + FontElement, + FontProperties, + InputElement, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class DropdownElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + options: string[] = []; + allowUnset: boolean = false; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.height = serializedElement.height || 83; + } +} diff --git a/projects/common/element-components/dropdown.component.ts b/projects/common/ui-elements/dropdown/dropdown.component.ts similarity index 64% rename from projects/common/element-components/dropdown.component.ts rename to projects/common/ui-elements/dropdown/dropdown.component.ts index fd76fca20..fa480e36b 100644 --- a/projects/common/element-components/dropdown.component.ts +++ b/projects/common/ui-elements/dropdown/dropdown.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { FormElementComponent } from '../form-element-component.directive'; -import { DropdownElement } from '../models/dropdown-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { DropdownElement } from './dropdown-element'; @Component({ selector: 'app-dropdown', @@ -8,13 +8,13 @@ import { DropdownElement } from '../models/dropdown-element'; <mat-form-field appearance="fill" [style.width.%]="100" [style.height.%]="100" - appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor"> - <mat-label [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + appInputBackgroundColor [backgroundColor]="elementModel.surfaceProps.backgroundColor"> + <mat-label [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' : ''"> {{$any(elementModel).label}} </mat-label> <mat-select [formControl]="elementFormControl" [value]="elementModel.value"> diff --git a/projects/common/models/image-element.ts b/projects/common/ui-elements/image/image-element.ts similarity index 87% rename from projects/common/models/image-element.ts rename to projects/common/ui-elements/image/image-element.ts index 2c6ee045a..7aa0cbaac 100644 --- a/projects/common/models/image-element.ts +++ b/projects/common/ui-elements/image/image-element.ts @@ -1,4 +1,4 @@ -import { UIElement } from './uI-element'; +import { UIElement } from '../../models/uI-element'; export class ImageElement extends UIElement { src: string = ''; diff --git a/projects/common/element-components/image.component.ts b/projects/common/ui-elements/image/image.component.ts similarity index 89% rename from projects/common/element-components/image.component.ts rename to projects/common/ui-elements/image/image.component.ts index 7d56bb792..3100d4684 100644 --- a/projects/common/element-components/image.component.ts +++ b/projects/common/ui-elements/image/image.component.ts @@ -1,9 +1,9 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ElementComponent } from '../element-component.directive'; -import { ImageElement } from '../models/image-element'; -import { ValueChangeElement } from '../models/uI-element'; +import { ElementComponent } from '../../directives/element-component.directive'; +import { ImageElement } from './image-element'; +import { ValueChangeElement } from '../../models/uI-element'; @Component({ selector: 'app-image', diff --git a/projects/common/element-components/magnifier.component.ts b/projects/common/ui-elements/image/magnifier.component.ts similarity index 97% rename from projects/common/element-components/magnifier.component.ts rename to projects/common/ui-elements/image/magnifier.component.ts index e896aca9a..059492009 100644 --- a/projects/common/element-components/magnifier.component.ts +++ b/projects/common/ui-elements/image/magnifier.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core'; -import { ValueChangeElement } from '../models/uI-element'; +import { ValueChangeElement } from '../../models/uI-element'; @Component({ selector: 'app-magnifier', diff --git a/projects/common/models/compound-elements/likert-element-row.ts b/projects/common/ui-elements/likert/likert-element-row.ts similarity index 69% rename from projects/common/models/compound-elements/likert-element-row.ts rename to projects/common/ui-elements/likert/likert-element-row.ts index 44cfa1745..aba80d6f0 100644 --- a/projects/common/models/compound-elements/likert-element-row.ts +++ b/projects/common/ui-elements/likert/likert-element-row.ts @@ -1,5 +1,4 @@ -import { InputElement, UIElement } from '../uI-element'; -import { LikertRow } from '../../interfaces/UIElementInterfaces'; +import { InputElement, LikertRow, UIElement } from '../../models/uI-element'; export class LikertElementRow extends InputElement implements LikertRow { text: string = ''; diff --git a/projects/common/models/compound-elements/likert-element.ts b/projects/common/ui-elements/likert/likert-element.ts similarity index 65% rename from projects/common/models/compound-elements/likert-element.ts rename to projects/common/ui-elements/likert/likert-element.ts index 9f5e6f0c2..6d6cfe486 100644 --- a/projects/common/models/compound-elements/likert-element.ts +++ b/projects/common/ui-elements/likert/likert-element.ts @@ -1,9 +1,15 @@ -import { CompoundElement, InputElementValue, UIElement } from '../uI-element'; +import { + CompoundElement, FontElement, FontProperties, + InputElementValue, + LikertColumn, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; import { LikertElementRow } from './likert-element-row'; -import { LikertColumn, FontElement, SurfaceUIElement } from '../../interfaces/UIElementInterfaces'; import { initFontElement, initSurfaceElement } from '../../util/unit-interface-initializer'; -export class LikertElement extends CompoundElement implements FontElement, SurfaceUIElement { +export class LikertElement extends CompoundElement implements FontElement, SurfaceElement { rows: LikertElementRow[] = []; columns: LikertColumn[] = []; firstColumnSizeRatio: number = 5; @@ -11,21 +17,14 @@ export class LikertElement extends CompoundElement implements FontElement, Surfa lineColoringColor: string = '#D0F6E7'; readOnly: boolean = false; - fontColor: string = 'black'; - font: string = 'Roboto'; - fontSize: number = 20; - lineHeight: number = 135; - bold: boolean = false; - italic: boolean = false; - underline: boolean = false; - - backgroundColor: string = 'transparent'; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; constructor(serializedElement: UIElement) { super(serializedElement); Object.assign(this, serializedElement); - Object.assign(this, initFontElement(serializedElement)); - Object.assign(this, initSurfaceElement(serializedElement)); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); if (serializedElement?.rows) { this.rows = []; @@ -36,7 +35,10 @@ export class LikertElement extends CompoundElement implements FontElement, Surfa this.height = serializedElement.height || 200; this.width = serializedElement.width || 250; - this.backgroundColor = serializedElement.backgroundColor as string || 'transparent'; + this.surfaceProps.backgroundColor = + (serializedElement as unknown as SurfaceElement).surfaceProps.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; } setProperty(property: string, value: InputElementValue): void { diff --git a/projects/common/element-components/compound-elements/likert-radio-button-group.component.ts b/projects/common/ui-elements/likert/likert-radio-button-group.component.ts similarity index 89% rename from projects/common/element-components/compound-elements/likert-radio-button-group.component.ts rename to projects/common/ui-elements/likert/likert-radio-button-group.component.ts index a1cdbde14..6f2ea7a20 100644 --- a/projects/common/element-components/compound-elements/likert-radio-button-group.component.ts +++ b/projects/common/ui-elements/likert/likert-radio-button-group.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { FormElementComponent } from '../../form-element-component.directive'; -import { LikertElementRow } from '../../models/compound-elements/likert-element-row'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { LikertElementRow } from './likert-element-row'; @Component({ selector: 'app-likert-radio-button-group', diff --git a/projects/common/element-components/compound-elements/likert.component.ts b/projects/common/ui-elements/likert/likert.component.ts similarity index 77% rename from projects/common/element-components/compound-elements/likert.component.ts rename to projects/common/ui-elements/likert/likert.component.ts index 4cffed822..30c22a510 100644 --- a/projects/common/element-components/compound-elements/likert.component.ts +++ b/projects/common/ui-elements/likert/likert.component.ts @@ -2,11 +2,11 @@ import { Component, EventEmitter, Output, QueryList, ViewChildren } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { LikertElement } from '../../models/compound-elements/likert-element'; +import { LikertElement } from './likert-element'; import { ValueChangeElement } from '../../models/uI-element'; -import { LikertElementRow } from '../../models/compound-elements/likert-element-row'; +import { LikertElementRow } from './likert-element-row'; import { LikertRadioButtonGroupComponent } from './likert-radio-button-group.component'; -import { CompoundElementComponent } from './compound-element.directive'; +import { CompoundElementComponent } from '../../directives/compound-element.directive'; @Component({ selector: 'app-likert', @@ -15,14 +15,14 @@ import { CompoundElementComponent } from './compound-element.directive'; [style.display]="'grid'" [style.grid-template-columns]="elementModel.firstColumnSizeRatio + 'fr ' + '1fr '.repeat(elementModel.columns.length)" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.line-height.%]="elementModel.lineHeight" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + [style.background-color]="elementModel.surfaceProps.backgroundColor" + [style.color]="elementModel.fontProps.fontColor" + [style.font-family]="elementModel.fontProps.font" + [style.font-size.px]="elementModel.fontProps.fontSize" + [style.line-height.%]="elementModel.fontProps.lineHeight" + [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''" + [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''"> <div *ngFor="let column of elementModel.columns; let i = index" class="columns" fxLayout="column" fxLayoutAlign="end center" [style.grid-column-start]="2 + i" diff --git a/projects/common/element-components/compound-elements/radio-group-images.component.ts b/projects/common/ui-elements/radio-with-images/radio-group-images.component.ts similarity index 82% rename from projects/common/element-components/compound-elements/radio-group-images.component.ts rename to projects/common/ui-elements/radio-with-images/radio-group-images.component.ts index 7954fe822..bfa521653 100644 --- a/projects/common/element-components/compound-elements/radio-group-images.component.ts +++ b/projects/common/ui-elements/radio-with-images/radio-group-images.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { RadioGroupImagesElement } from '../../models/compound-elements/radio-group-images'; -import { FormElementComponent } from '../../form-element-component.directive'; +import { RadioGroupImagesElement } from './radio-group-images'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; @Component({ selector: 'app-radio-group-images', @@ -9,13 +9,13 @@ import { FormElementComponent } from '../../form-element-component.directive'; [style.height.%]="100" [style.display]="'grid'" [style.grid-template-columns]="'1fr '.repeat(elementModel.columns.length)" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + [style.background-color]="elementModel.surfaceProps.backgroundColor" + [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' : ''"> <label id="radio-group-label" class="label" [style.grid-column-start]="1" [style.grid-column-end]="2 + elementModel.columns.length" diff --git a/projects/common/ui-elements/radio-with-images/radio-group-images.ts b/projects/common/ui-elements/radio-with-images/radio-group-images.ts new file mode 100644 index 000000000..28ab5270e --- /dev/null +++ b/projects/common/ui-elements/radio-with-images/radio-group-images.ts @@ -0,0 +1,32 @@ +import { + FontElement, + FontProperties, + InputElement, + LikertColumn, PositionedElement, PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class RadioGroupImagesElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + columns: LikertColumn[] = []; // TODO + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.height = serializedElement.height || 100; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/ui-elements/radio/radio-button-group-element.ts b/projects/common/ui-elements/radio/radio-button-group-element.ts new file mode 100644 index 000000000..01e429e9d --- /dev/null +++ b/projects/common/ui-elements/radio/radio-button-group-element.ts @@ -0,0 +1,34 @@ +import { + FontElement, + FontProperties, + InputElement, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class RadioButtonGroupElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + options: string[] = []; + alignment: 'column' | 'row' = 'column'; + strikeOtherOptions: boolean = false; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.height = serializedElement.height || 85; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/element-components/radio-button-group.component.ts b/projects/common/ui-elements/radio/radio-button-group.component.ts similarity index 77% rename from projects/common/element-components/radio-button-group.component.ts rename to projects/common/ui-elements/radio/radio-button-group.component.ts index 39feccf07..42f1e740b 100644 --- a/projects/common/element-components/radio-button-group.component.ts +++ b/projects/common/ui-elements/radio/radio-button-group.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { FormElementComponent } from '../form-element-component.directive'; -import { RadioButtonGroupElement } from '../models/radio-button-group-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { RadioButtonGroupElement } from './radio-button-group-element'; @Component({ selector: 'app-radio-button-group', @@ -8,13 +8,13 @@ import { RadioButtonGroupElement } from '../models/radio-button-group-element'; <div class="mat-form-field" [style.width.%]="100" [style.height.%]="100" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + [style.background-color]="elementModel.surfaceProps.backgroundColor" + [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' : ''"> <label id="radio-group-label" class="white-space-break" [innerHTML]="elementModel.label"> </label> diff --git a/projects/common/ui-elements/text-area/text-area-element.ts b/projects/common/ui-elements/text-area/text-area-element.ts new file mode 100644 index 000000000..842c0fd7c --- /dev/null +++ b/projects/common/ui-elements/text-area/text-area-element.ts @@ -0,0 +1,36 @@ +import { + FontElement, + FontProperties, + InputElement, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class TextAreaElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + appearance: 'standard' | 'legacy' | 'fill' | 'outline' = 'outline'; + resizeEnabled: boolean = false; + rowCount: number = 3; + inputAssistancePreset: 'none' | 'french' | 'numbers' | 'numbersAndOperators' = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.height = serializedElement.height || 132; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/element-components/text-area.component.ts b/projects/common/ui-elements/text-area/text-area.component.ts similarity index 64% rename from projects/common/element-components/text-area.component.ts rename to projects/common/ui-elements/text-area/text-area.component.ts index 401ce1760..8963f5cf4 100644 --- a/projects/common/element-components/text-area.component.ts +++ b/projects/common/ui-elements/text-area/text-area.component.ts @@ -1,19 +1,19 @@ import { Component, Output, EventEmitter, Input } from '@angular/core'; -import { FormElementComponent } from '../form-element-component.directive'; -import { TextAreaElement } from '../models/text-area-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { TextAreaElement } from './text-area-element'; @Component({ selector: 'app-text-area', template: ` <mat-form-field [style.width.%]="100" [style.min-height.%]="100" - appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" + appInputBackgroundColor [backgroundColor]="elementModel.surfaceProps.backgroundColor" + [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' : ''" [appearance]="$any(elementModel.appearance)"> <textarea matInput #input autocomplete="off" rows="{{elementModel.rowCount}}" placeholder="{{elementModel.label}}" @@ -21,7 +21,7 @@ import { TextAreaElement } from '../models/text-area-element'; [value]="elementModel.value" [readonly]="elementModel.readOnly" [style.min-width.%]="100" - [style.line-height.%]="elementModel.lineHeight" + [style.line-height.%]="elementModel.fontProps.lineHeight" [style.resize]="elementModel.resizeEnabled ? 'both' : 'none'" (focus)="elementModel.inputAssistancePreset !== 'none' ? onFocusChanged.emit(input) : null" (blur)="elementModel.inputAssistancePreset !== 'none' ? onFocusChanged.emit(null): null"> diff --git a/projects/common/ui-elements/text-field/text-field-element.ts b/projects/common/ui-elements/text-field/text-field-element.ts new file mode 100644 index 000000000..db71baa6a --- /dev/null +++ b/projects/common/ui-elements/text-field/text-field-element.ts @@ -0,0 +1,41 @@ +import { + FontElement, + FontProperties, + InputElement, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class TextFieldElement extends InputElement implements PositionedElement, FontElement, SurfaceElement { + appearance: 'standard' | 'legacy' | 'fill' | 'outline' = 'outline'; + minLength: number = 0; + minLengthWarnMessage: string = 'Eingabe zu kurz'; + maxLength: number = 0; + maxLengthWarnMessage: string = 'Eingabe zu lang'; + pattern: string = ''; + patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; + inputAssistancePreset: 'none' | 'french' | 'numbers' | 'numbersAndOperators' = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + clearable: boolean = false; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.height = serializedElement.height || 100; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/element-components/text-field.component.ts b/projects/common/ui-elements/text-field/text-field.component.ts similarity index 74% rename from projects/common/element-components/text-field.component.ts rename to projects/common/ui-elements/text-field/text-field.component.ts index 176fc1c56..006063073 100644 --- a/projects/common/element-components/text-field.component.ts +++ b/projects/common/ui-elements/text-field/text-field.component.ts @@ -2,8 +2,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ValidatorFn, Validators } from '@angular/forms'; -import { FormElementComponent } from '../form-element-component.directive'; -import { TextFieldElement } from '../models/text-field-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { TextFieldElement } from './text-field-element'; @Component({ selector: 'app-text-field', @@ -11,13 +11,13 @@ import { TextFieldElement } from '../models/text-field-element'; <mat-form-field *ngIf="elementModel.label !== ''" [style.width.%]="100" [style.height.%]="100" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" - appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor" + [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' : ''" + appInputBackgroundColor [backgroundColor]="elementModel.surfaceProps.backgroundColor" [appearance]="$any(elementModel.appearance)"> <mat-label>{{elementModel.label}}</mat-label> <input matInput type="text" #input autocomplete="off" @@ -40,13 +40,13 @@ import { TextFieldElement } from '../models/text-field-element'; <mat-form-field *ngIf="elementModel.label === ''" class="small-input" [style.width.%]="100" [style.height.%]="100" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" - appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor" + [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' : ''" + appInputBackgroundColor [backgroundColor]="elementModel.surfaceProps.backgroundColor" [appearance]="$any(elementModel.appearance)"> <input matInput type="text" #input autocomplete="off" [formControl]="elementFormControl" diff --git a/projects/common/ui-elements/text/text-element.ts b/projects/common/ui-elements/text/text-element.ts new file mode 100644 index 000000000..0a442ac36 --- /dev/null +++ b/projects/common/ui-elements/text/text-element.ts @@ -0,0 +1,41 @@ +import { + FontElement, + FontProperties, PositionedElement, + PositionProperties, + SurfaceElement, + SurfaceProperties, + UIElement +} from '../../models/uI-element'; +import { initFontElement, initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class TextElement extends UIElement implements PositionedElement, FontElement, SurfaceElement { + text: string = '<p>Lorem ipsum dolor sit amet</p>'; + interaction: 'none' | 'highlightable' | 'underlinable' | 'strikable' = 'none'; + + positionProps: PositionProperties; + fontProps: FontProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.fontProps = initFontElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + delete this.fontProps.fontSize; + + this.height = serializedElement.height || 78; + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + serializedElement.backgroundColor as string || + 'transparent'; + + this.handleBackwardsCompatibility(serializedElement); + } + + handleBackwardsCompatibility(serializedElement: UIElement): void { + if (serializedElement.highlightable) { // TODO + this.interaction = 'highlightable'; + } + } +} diff --git a/projects/common/element-components/text.component.ts b/projects/common/ui-elements/text/text.component.ts similarity index 82% rename from projects/common/element-components/text.component.ts rename to projects/common/ui-elements/text/text.component.ts index 93a228cef..65ca7e4a9 100644 --- a/projects/common/element-components/text.component.ts +++ b/projects/common/ui-elements/text/text.component.ts @@ -1,9 +1,9 @@ import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { ElementComponent } from '../element-component.directive'; -import { TextElement } from '../models/text-element'; -import { ValueChangeElement } from '../models/uI-element'; +import { ElementComponent } from '../../directives/element-component.directive'; +import { TextElement } from './text-element'; +import { ValueChangeElement } from '../../models/uI-element'; @Component({ selector: 'app-text', @@ -48,13 +48,13 @@ import { ValueChangeElement } from '../models/uI-element'; </div> <div #container class="text-container" (mousedown)="startSelection.emit($event)" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.line-height.%]="elementModel.lineHeight" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''" + [style.background-color]="elementModel.surfaceProps.backgroundColor" + [style.color]="elementModel.fontProps.fontColor" + [style.font-family]="elementModel.fontProps.font" + [style.line-height.%]="elementModel.fontProps.lineHeight" + [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''" + [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''" [innerHTML]="elementModel.text | safeResourceHTML"> </div> </div> diff --git a/projects/common/models/text-field-simple-element.ts b/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts similarity index 73% rename from projects/common/models/text-field-simple-element.ts rename to projects/common/ui-elements/textfield-simple/text-field-simple-element.ts index 6eb9edff2..77c56a80f 100644 --- a/projects/common/models/text-field-simple-element.ts +++ b/projects/common/ui-elements/textfield-simple/text-field-simple-element.ts @@ -1,4 +1,4 @@ -import { InputElement, UIElement } from './uI-element'; +import { InputElement, UIElement } from '../../models/uI-element'; export class TextFieldSimpleElement extends InputElement { constructor(serializedElement: UIElement) { diff --git a/projects/common/element-components/text-field-simple.component.ts b/projects/common/ui-elements/textfield-simple/text-field-simple.component.ts similarity index 75% rename from projects/common/element-components/text-field-simple.component.ts rename to projects/common/ui-elements/textfield-simple/text-field-simple.component.ts index 6b668e640..6443e9138 100644 --- a/projects/common/element-components/text-field-simple.component.ts +++ b/projects/common/ui-elements/textfield-simple/text-field-simple.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { FormElementComponent } from '../form-element-component.directive'; -import { TextFieldSimpleElement } from '../models/text-field-simple-element'; +import { FormElementComponent } from '../../directives/form-element-component.directive'; +import { TextFieldSimpleElement } from './text-field-simple-element'; @Component({ selector: 'app-text-field-simple', diff --git a/projects/common/ui-elements/video/video-element.ts b/projects/common/ui-elements/video/video-element.ts new file mode 100644 index 000000000..784ee7c0e --- /dev/null +++ b/projects/common/ui-elements/video/video-element.ts @@ -0,0 +1,18 @@ +import { PlayerElement, PlayerProperties, PositionedElement, PositionProperties, UIElement } from '../../models/uI-element'; +import { initPlayerElement, initPositionedElement } from '../../util/unit-interface-initializer'; + +export class VideoElement extends UIElement implements PositionedElement, PlayerElement { + src: string = ''; + + positionProps: PositionProperties; + playerProps: PlayerProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.playerProps = initPlayerElement(serializedElement); + this.height = serializedElement.height || 230; + this.width = serializedElement.width || 280; + } +} diff --git a/projects/common/element-components/video.component.ts b/projects/common/ui-elements/video/video.component.ts similarity index 80% rename from projects/common/element-components/video.component.ts rename to projects/common/ui-elements/video/video.component.ts index d9ad61b12..da938882a 100644 --- a/projects/common/element-components/video.component.ts +++ b/projects/common/ui-elements/video/video.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { VideoElement } from '../models/video-element'; -import { MediaPlayerElementComponent } from '../media-player-element-component.directive'; +import { VideoElement } from './video-element'; +import { MediaPlayerElementComponent } from '../../directives/media-player-element-component.directive'; @Component({ selector: 'app-video', @@ -17,7 +17,8 @@ import { MediaPlayerElementComponent } from '../media-player-element-component.d (pause)="onMediaPlayStatusChanged.emit(null)" [player]="player" [project]="project" - [elementModel]="elementModel" + [id]="elementModel.id" + [playerProperties]="elementModel.playerProps" [dependencyDissolved]="dependencyDissolved" (onMediaValidStatusChanged)="onMediaValidStatusChanged.emit($event)" (elementValueChanged)="elementValueChanged.emit($event)"> diff --git a/projects/common/util/element.factory.ts b/projects/common/util/element.factory.ts index dee9e0a18..8baa07cca 100644 --- a/projects/common/util/element.factory.ts +++ b/projects/common/util/element.factory.ts @@ -1,33 +1,33 @@ import { ComponentFactory, ComponentFactoryResolver } from '@angular/core'; import { UIElement } from '../models/uI-element'; -import { TextElement } from '../models/text-element'; -import { ButtonElement } from '../models/button-element'; -import { TextFieldElement } from '../models/text-field-element'; -import { TextAreaElement } from '../models/text-area-element'; -import { CheckboxElement } from '../models/checkbox-element'; -import { DropdownElement } from '../models/dropdown-element'; -import { RadioButtonGroupElement } from '../models/radio-button-group-element'; -import { ImageElement } from '../models/image-element'; -import { AudioElement } from '../models/audio-element'; -import { VideoElement } from '../models/video-element'; -import { TextComponent } from '../element-components/text.component'; -import { ButtonComponent } from '../element-components/button.component'; -import { TextFieldComponent } from '../element-components/text-field.component'; -import { TextAreaComponent } from '../element-components/text-area.component'; -import { CheckboxComponent } from '../element-components/checkbox.component'; -import { DropdownComponent } from '../element-components/dropdown.component'; -import { RadioButtonGroupComponent } from '../element-components/radio-button-group.component'; -import { ImageComponent } from '../element-components/image.component'; -import { AudioComponent } from '../element-components/audio.component'; -import { VideoComponent } from '../element-components/video.component'; -import { LikertElement } from '../models/compound-elements/likert-element'; -import { LikertComponent } from '../element-components/compound-elements/likert.component'; -import { RadioGroupImagesComponent } from '../element-components/compound-elements/radio-group-images.component'; -import { RadioGroupImagesElement } from '../models/compound-elements/radio-group-images'; -import { DropListComponent } from '../element-components/compound-elements/drop-list.component'; -import { DropListElement } from '../models/compound-elements/drop-list'; -import { ClozeComponent } from '../element-components/compound-elements/cloze.component'; -import { ClozeElement } from '../models/compound-elements/cloze-element'; +import { TextElement } from '../ui-elements/text/text-element'; +import { ButtonElement } from '../ui-elements/button/button-element'; +import { TextFieldElement } from '../ui-elements/text-field/text-field-element'; +import { TextAreaElement } from '../ui-elements/text-area/text-area-element'; +import { CheckboxElement } from '../ui-elements/checkbox/checkbox-element'; +import { DropdownElement } from '../ui-elements/dropdown/dropdown-element'; +import { RadioButtonGroupElement } from '../ui-elements/radio/radio-button-group-element'; +import { ImageElement } from '../ui-elements/image/image-element'; +import { AudioElement } from '../ui-elements/audio/audio-element'; +import { VideoElement } from '../ui-elements/video/video-element'; +import { TextComponent } from '../ui-elements/text/text.component'; +import { ButtonComponent } from '../ui-elements/button/button.component'; +import { TextFieldComponent } from '../ui-elements/text-field/text-field.component'; +import { TextAreaComponent } from '../ui-elements/text-area/text-area.component'; +import { CheckboxComponent } from '../ui-elements/checkbox/checkbox.component'; +import { DropdownComponent } from '../ui-elements/dropdown/dropdown.component'; +import { RadioButtonGroupComponent } from '../ui-elements/radio/radio-button-group.component'; +import { ImageComponent } from '../ui-elements/image/image.component'; +import { AudioComponent } from '../ui-elements/audio/audio.component'; +import { VideoComponent } from '../ui-elements/video/video.component'; +import { LikertElement } from '../ui-elements/likert/likert-element'; +import { LikertComponent } from '../ui-elements/likert/likert.component'; +import { RadioGroupImagesComponent } from '../ui-elements/radio-with-images/radio-group-images.component'; +import { RadioGroupImagesElement } from '../ui-elements/radio-with-images/radio-group-images'; +import { DropListComponent } from '../ui-elements/drop-list/drop-list.component'; +import { DropListElement } from '../ui-elements/drop-list/drop-list'; +import { ClozeComponent } from '../ui-elements/cloze/cloze.component'; +import { ClozeElement } from '../ui-elements/cloze/cloze-element'; export function createElement(elementModel: UIElement): UIElement { let newElement: UIElement; diff --git a/projects/common/util/unit-interface-initializer.ts b/projects/common/util/unit-interface-initializer.ts index 4b5d5ca7e..2ebf73d7b 100644 --- a/projects/common/util/unit-interface-initializer.ts +++ b/projects/common/util/unit-interface-initializer.ts @@ -1,23 +1,154 @@ -import { FontElement, PlayerElement, SurfaceUIElement } from '../interfaces/UIElementInterfaces'; -import { UIElement } from '../models/uI-element'; +import { + FontProperties, + PlayerProperties, + PositionProperties, + SurfaceProperties, + UIElement +} from '../models/uI-element'; -export function initFontElement(serializedElement: UIElement): FontElement { +// Properties check is only for backwards compatibility + +const DEFAULT_DYNAMIC_POSITIONING = false; + +const DEFAULT_FONT_COLOR = '#000000'; +const DEFAULT_FONT = 'Roboto'; +const DEFAULT_FONT_SIZE = 20; +const DEFAULT_LINE_HEIGHT = 120; +const DEFAULT_BOLD = false; +const DEFAULT_ITALIC = false; +const DEFAULT_UNDERLINE = false; + +const DEFAULT_BACKGROUND_COLOR = '#d3d3d3'; + +export function initPositionedElement(serializedElement: Partial<UIElement>): PositionProperties { + if (serializedElement.positionProps) { + return { + dynamicPositioning: serializedElement.positionProps.dynamicPositioning as boolean || DEFAULT_DYNAMIC_POSITIONING, + xPosition: serializedElement.positionProps.xPosition !== undefined ? + serializedElement.positionProps.xPosition as number : 0, + yPosition: serializedElement.positionProps.yPosition !== undefined ? + serializedElement.positionProps.yPosition as number : 0, + useMinHeight: serializedElement.positionProps.useMinHeight !== undefined ? + serializedElement.positionProps.useMinHeight as boolean : false, + gridColumnStart: serializedElement.positionProps.gridColumnStart !== undefined ? + serializedElement.positionProps.gridColumnStart as number : 1, + gridColumnEnd: serializedElement.positionProps.gridColumnEnd !== undefined ? + serializedElement.positionProps.gridColumnEnd as number : 2, + gridRowStart: serializedElement.positionProps.gridRowStart !== undefined ? + serializedElement.positionProps.gridRowStart as number : 1, + gridRowEnd: serializedElement.positionProps.gridRowEnd !== undefined ? + serializedElement.positionProps.gridRowEnd as number : 2, + marginLeft: serializedElement.positionProps.marginLeft !== undefined ? + serializedElement.positionProps.marginLeft as number : 0, + marginRight: serializedElement.positionProps.marginRight !== undefined ? + serializedElement.positionProps.marginRight as number : 0, + marginTop: serializedElement.positionProps.marginTop !== undefined ? + serializedElement.positionProps.marginTop as number : 0, + marginBottom: serializedElement.positionProps.marginBottom !== undefined ? + serializedElement.positionProps.marginBottom as number : 0, + zIndex: serializedElement.positionProps.zIndex !== undefined ? + serializedElement.positionProps.zIndex as number : 0 + }; + } return { - fontColor: serializedElement.fontColor as string || '#000000', - font: serializedElement.font as string || 'Roboto', - fontSize: serializedElement.fontSize !== undefined ? serializedElement.fontSize as number : 20, - lineHeight: serializedElement.lineHeight !== undefined ? serializedElement.lineHeight as number : 120, - bold: serializedElement.bold !== undefined ? serializedElement.bold as boolean : false, - italic: serializedElement.italic !== undefined ? serializedElement.italic as boolean : false, - underline: serializedElement.underline !== undefined ? serializedElement.underline as boolean : false + dynamicPositioning: serializedElement.dynamicPositioning as boolean || DEFAULT_DYNAMIC_POSITIONING, + xPosition: serializedElement.xPosition !== undefined ? serializedElement.xPosition as number : 0, + yPosition: serializedElement.yPosition !== undefined ? serializedElement.yPosition as number : 0, + useMinHeight: serializedElement.useMinHeight !== undefined ? serializedElement.useMinHeight as boolean : false, + gridColumnStart: serializedElement.gridColumnStart !== undefined ? serializedElement.gridColumnStart as number : 1, + gridColumnEnd: serializedElement.gridColumnEnd !== undefined ? serializedElement.gridColumnEnd as number : 2, + gridRowStart: serializedElement.gridRowStart !== undefined ? serializedElement.gridRowStart as number : 1, + gridRowEnd: serializedElement.gridRowEnd !== undefined ? serializedElement.gridRowEnd as number : 2, + marginLeft: serializedElement.marginLeft !== undefined ? serializedElement.marginLeft as number : 0, + marginRight: serializedElement.marginRight !== undefined ? serializedElement.marginRight as number : 0, + marginTop: serializedElement.marginTop !== undefined ? serializedElement.marginTop as number : 0, + marginBottom: serializedElement.marginBottom !== undefined ? serializedElement.marginBottom as number : 0, + zIndex: serializedElement.zIndex !== undefined ? serializedElement.zIndex as number : 0 }; } -export function initSurfaceElement(serializedElement: UIElement): SurfaceUIElement { - return { backgroundColor: serializedElement.backgroundColor as string || '#d3d3d3' }; +export function initFontElement(serializedElement: Partial<UIElement>): FontProperties { + if (serializedElement.fontProps) { + return { + fontColor: (serializedElement.fontProps as FontProperties).fontColor as string || DEFAULT_FONT_COLOR, + font: (serializedElement.fontProps as FontProperties).font as string || DEFAULT_FONT, + fontSize: (serializedElement.fontProps as FontProperties).fontSize !== undefined ? + serializedElement.fontSize as number : DEFAULT_FONT_SIZE, + lineHeight: (serializedElement.fontProps as FontProperties).lineHeight !== undefined ? + serializedElement.lineHeight as number : DEFAULT_LINE_HEIGHT, + bold: (serializedElement.fontProps as FontProperties).bold !== undefined ? + serializedElement.bold as boolean : DEFAULT_BOLD, + italic: (serializedElement.fontProps as FontProperties).italic !== undefined ? + serializedElement.italic as boolean : DEFAULT_ITALIC, + underline: (serializedElement.fontProps as FontProperties).underline !== undefined ? + serializedElement.underline as boolean : DEFAULT_UNDERLINE + }; + } + return { + fontColor: serializedElement.fontColor as string || DEFAULT_FONT_COLOR, + font: serializedElement.font as string || DEFAULT_FONT, + fontSize: serializedElement.fontSize !== undefined ? serializedElement.fontSize as number : DEFAULT_FONT_SIZE, + lineHeight: serializedElement.lineHeight !== undefined ? + serializedElement.lineHeight as number : DEFAULT_LINE_HEIGHT, + bold: serializedElement.bold !== undefined ? serializedElement.bold as boolean : DEFAULT_BOLD, + italic: serializedElement.italic !== undefined ? serializedElement.italic as boolean : DEFAULT_ITALIC, + underline: serializedElement.underline !== undefined ? serializedElement.underline as boolean : DEFAULT_UNDERLINE + }; +} + +export function initSurfaceElement(serializedElement: Partial<UIElement>): SurfaceProperties { + if (serializedElement.surfaceProps) { + return { backgroundColor: serializedElement.surfaceProps.backgroundColor as string || DEFAULT_BACKGROUND_COLOR }; + } + return { backgroundColor: serializedElement.backgroundColor as string || DEFAULT_BACKGROUND_COLOR }; } -export function initPlayerElement(serializedElement: UIElement): PlayerElement { +export function initPlayerElement(serializedElement: Partial<UIElement>): PlayerProperties { + if (serializedElement.playerProps) { + return { + autostart: serializedElement.playerProps.autostart !== undefined ? + serializedElement.playerProps.autostart as boolean : false, + autostartDelay: serializedElement.playerProps.autostartDelay !== undefined ? + serializedElement.playerProps.autostartDelay as number : 0, + loop: serializedElement.playerProps.loop !== undefined ? + serializedElement.playerProps.loop as boolean : false, + startControl: serializedElement.playerProps.startControl !== undefined ? + serializedElement.playerProps.startControl as boolean : true, + pauseControl: serializedElement.playerProps.pauseControl !== undefined ? + serializedElement.playerProps.pauseControl as boolean : false, + progressBar: serializedElement.playerProps.progressBar !== undefined ? + serializedElement.playerProps.progressBar as boolean : true, + interactiveProgressbar: serializedElement.playerProps.interactiveProgressbar !== undefined ? + serializedElement.playerProps.interactiveProgressbar as boolean : false, + volumeControl: serializedElement.playerProps.volumeControl !== undefined ? + serializedElement.playerProps.volumeControl as boolean : true, + defaultVolume: serializedElement.playerProps.defaultVolume !== undefined ? + serializedElement.playerProps.defaultVolume as number : 0.8, + minVolume: serializedElement.playerProps.minVolume !== undefined ? + serializedElement.playerProps.minVolume as number : 0, + muteControl: serializedElement.playerProps.muteControl !== undefined ? + serializedElement.playerProps.muteControl as boolean : true, + hintLabel: serializedElement.playerProps.hintLabel as string || '', + hintLabelDelay: serializedElement.playerProps.hintLabelDelay !== undefined ? + serializedElement.playerProps.hintLabelDelay as number : 0, + uninterruptible: serializedElement.playerProps.uninterruptible !== undefined ? + serializedElement.playerProps.uninterruptible as boolean : false, + hideOtherPages: serializedElement.playerProps.hideOtherPages !== undefined ? + serializedElement.playerProps.hideOtherPages as boolean : false, + activeAfterID: serializedElement.playerProps.activeAfterID as string || '', + minRuns: serializedElement.playerProps.minRuns !== undefined ? + serializedElement.playerProps.minRuns as number : 1, + maxRuns: serializedElement.playerProps.maxRuns !== undefined ? + serializedElement.playerProps.maxRuns as number | null : null, + showRestRuns: serializedElement.playerProps.showRestRuns !== undefined ? + serializedElement.playerProps.showRestRuns as boolean : false, + showRestTime: serializedElement.playerProps.showRestTime !== undefined ? + serializedElement.playerProps.showRestTime as boolean : true, + playbackTime: serializedElement.playerProps.playbackTime !== undefined ? + serializedElement.playerProps.playbackTime as number : 0 + }; + } + return { autostart: serializedElement.autostart !== undefined ? serializedElement.autostart as boolean : false, autostartDelay: serializedElement.autostartDelay !== undefined ? serializedElement.autostartDelay as number : 0, @@ -39,7 +170,7 @@ export function initPlayerElement(serializedElement: UIElement): PlayerElement { serializedElement.hideOtherPages !== undefined ? serializedElement.hideOtherPages as boolean : false, activeAfterID: serializedElement.activeAfterID as string || '', minRuns: serializedElement.minRuns !== undefined ? serializedElement.minRuns as number : 1, - maxRuns: serializedElement.maxRuns !== undefined ? serializedElement.maxRuns as number | null : null, + maxRuns: serializedElement.maxRuns !== undefined ? serializedElement.maxRuns as number : null, showRestRuns: serializedElement.showRestRuns !== undefined ? serializedElement.showRestRuns as boolean : false, showRestTime: serializedElement.showRestTime !== undefined ? serializedElement.showRestTime as boolean : true, playbackTime: serializedElement.playbackTime !== undefined ? serializedElement.playbackTime as number : 0 diff --git a/projects/editor/src/app/app.module.ts b/projects/editor/src/app/app.module.ts index 74dd6b3f0..f775e3dfe 100644 --- a/projects/editor/src/app/app.module.ts +++ b/projects/editor/src/app/app.module.ts @@ -10,6 +10,14 @@ import { NgxTiptapModule } from 'ngx-tiptap'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatMenuModule } from '@angular/material/menu'; import { MatSliderModule } from '@angular/material/slider'; +import { MatSelectModule } from '@angular/material/select'; +import { MatButtonModule } from '@angular/material/button'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatInputModule } from '@angular/material/input'; import { AppComponent } from './app.component'; import { ToolbarComponent } from './components/toolbar/toolbar.component'; @@ -68,9 +76,17 @@ import { ElementModelPropertiesComponentComponent } from './components/unit-view BrowserAnimationsModule, CommonModule, SharedModule, + MatButtonModule, + MatInputModule, MatButtonToggleModule, + MatCheckboxModule, + MatSelectModule, + MatToolbarModule, MatMenuModule, MatSliderModule, + MatExpansionModule, + MatSidenavModule, + MatDividerModule, NgxTiptapModule, TranslateModule.forRoot({ loader: { diff --git a/projects/editor/src/app/components/dialogs/likert-column-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/likert-column-edit-dialog.component.ts index 8cdcba1b1..d5e86b927 100644 --- a/projects/editor/src/app/components/dialogs/likert-column-edit-dialog.component.ts +++ b/projects/editor/src/app/components/dialogs/likert-column-edit-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { LikertColumn } from '../../../../../common/interfaces/UIElementInterfaces'; import { FileService } from '../../../../../common/file.service'; +import { LikertColumn } from '../../../../../common/models/uI-element'; @Component({ selector: 'app-likert-column-edit-dialog', diff --git a/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts index 8ce581e24..de21ee54c 100644 --- a/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts +++ b/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts @@ -1,7 +1,7 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { LikertElementRow } from '../../../../../common/models/compound-elements/likert-element-row'; -import { LikertColumn } from '../../../../../common/interfaces/UIElementInterfaces'; +import { LikertElementRow } from '../../../../../common/ui-elements/likert/likert-element-row'; +import { LikertColumn } from '../../../../../common/models/uI-element'; @Component({ selector: 'app-likert-row-edit-dialog', diff --git a/projects/editor/src/app/components/dialogs/player-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/player-edit-dialog.component.ts index c74ea895a..b5df03bc3 100644 --- a/projects/editor/src/app/components/dialogs/player-edit-dialog.component.ts +++ b/projects/editor/src/app/components/dialogs/player-edit-dialog.component.ts @@ -1,6 +1,6 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { PlayerElement } from '../../../../../common/interfaces/UIElementInterfaces'; +import { PlayerElement, PlayerProperties } from '../../../../../common/models/uI-element'; @Component({ selector: 'app-player-edit-dialog', @@ -9,102 +9,102 @@ import { PlayerElement } from '../../../../../common/interfaces/UIElementInterfa <mat-tab-group> <mat-tab label="{{ 'player.appearance' | translate }}"> <div fxLayout="column"> - <mat-checkbox [checked]="newPlayerConfig.startControl || data.player.startControl" + <mat-checkbox [checked]="newPlayerConfig.startControl || data.playerProps.startControl" (change)="newPlayerConfig.startControl = $event.checked"> {{ 'player.startControl' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.pauseControl || data.player.pauseControl" + <mat-checkbox [checked]="newPlayerConfig.pauseControl || data.playerProps.pauseControl" (change)="newPlayerConfig.pauseControl = $event.checked"> {{ 'player.pauseControl' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.progressBar || data.player.progressBar" + <mat-checkbox [checked]="newPlayerConfig.progressBar || data.playerProps.progressBar" (change)="newPlayerConfig.progressBar = $event.checked"> {{ 'player.progressBar' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.interactiveProgressbar || data.player.interactiveProgressbar" + <mat-checkbox [checked]="newPlayerConfig.interactiveProgressbar || data.playerProps.interactiveProgressbar" (change)="newPlayerConfig.interactiveProgressbar = $event.checked"> {{ 'player.interactiveProgressbar' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.volumeControl || data.player.volumeControl" + <mat-checkbox [checked]="newPlayerConfig.volumeControl || data.playerProps.volumeControl" (change)="newPlayerConfig.volumeControl = $event.checked"> {{ 'player.volumeControl' | translate }} </mat-checkbox> <mat-form-field appearance="fill"> <mat-label>{{ 'player.defaultVolume' | translate }}</mat-label> <input matInput type="number" min="0" max="1" step="0.1" - [ngModel]="newPlayerConfig.defaultVolume || data.player.defaultVolume" + [ngModel]="newPlayerConfig.defaultVolume || data.playerProps.defaultVolume" (ngModelChange)="newPlayerConfig.defaultVolume = $event"> </mat-form-field> <mat-form-field appearance="fill"> <mat-label>{{ 'player.minVolume' | translate }}</mat-label> <input matInput type="number" min="0" max="1" step="0.1" - [ngModel]="newPlayerConfig.minVolume || data.player.minVolume" + [ngModel]="newPlayerConfig.minVolume || data.playerProps.minVolume" (ngModelChange)="newPlayerConfig.minVolume = $event"> </mat-form-field> - <mat-checkbox [checked]="newPlayerConfig.muteControl || data.player.muteControl" + <mat-checkbox [checked]="newPlayerConfig.muteControl || data.playerProps.muteControl" (change)="newPlayerConfig.muteControl = $event.checked"> {{ 'player.muteControl' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.showRestTime || data.player.showRestTime" + <mat-checkbox [checked]="newPlayerConfig.showRestTime || data.playerProps.showRestTime" (change)="newPlayerConfig.showRestTime = $event.checked"> {{ 'player.showRestTime' | translate }} </mat-checkbox> <mat-form-field appearance="fill"> <mat-label>{{ 'player.hintLabel' | translate }}</mat-label> - <input matInput type="text" [value]="newPlayerConfig.hintLabel || data.player.hintLabel" + <input matInput type="text" [value]="newPlayerConfig.hintLabel || data.playerProps.hintLabel" (input)="newPlayerConfig.hintLabel = $any($event.target).value"> </mat-form-field> - <mat-form-field *ngIf="newPlayerConfig.hintLabel || data.player.hintLabel" + <mat-form-field *ngIf="newPlayerConfig.hintLabel || data.playerProps.hintLabel" appearance="fill"> <mat-label>{{ 'player.hintLabelDelay' | translate }}</mat-label> <input matInput type="number" step="1000" min="0" - [ngModel]="newPlayerConfig.hintLabelDelay || data.player.hintLabelDelay" + [ngModel]="newPlayerConfig.hintLabelDelay || data.playerProps.hintLabelDelay" (ngModelChange)="newPlayerConfig.hintLabelDelay = $event"> </mat-form-field> </div> </mat-tab> <mat-tab label="{{ 'player.behaviour' | translate }}"> <div fxLayout="column"> - <mat-checkbox [checked]="newPlayerConfig.autostart || data.player.autostart" + <mat-checkbox [checked]="newPlayerConfig.autostart || data.playerProps.autostart" (change)="newPlayerConfig.autostart = $event.checked"> {{ 'player.autoStart' | translate }} </mat-checkbox> - <mat-form-field *ngIf="newPlayerConfig.autostart || data.player.autostart" appearance="fill"> + <mat-form-field *ngIf="newPlayerConfig.autostart || data.playerProps.autostart" appearance="fill"> <mat-label>{{ 'player.autoStartDelay' | translate }}</mat-label> <input matInput type="number" step="1000" - [value]="newPlayerConfig.autostartDelay || data.player.autostartDelay" - (input)="newPlayerConfig.autostartDelay = $any($event.target).value"> + [ngModel]="newPlayerConfig.autostartDelay || data.playerProps.autostartDelay" + (ngModelChange)="newPlayerConfig.autostartDelay = $event"> </mat-form-field> - <mat-checkbox [checked]="newPlayerConfig.loop || data.player.loop" + <mat-checkbox [checked]="newPlayerConfig.loop || data.playerProps.loop" (change)="newPlayerConfig.loop = $event.checked"> {{ 'player.loop' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.uninterruptible || data.player.uninterruptible" + <mat-checkbox [checked]="newPlayerConfig.uninterruptible || data.playerProps.uninterruptible" (change)="newPlayerConfig.uninterruptible = $event.checked"> {{ 'player.uninterruptible' | translate }} </mat-checkbox> - <mat-checkbox [checked]="newPlayerConfig.hideOtherPages || data.player.hideOtherPages" + <mat-checkbox [checked]="newPlayerConfig.hideOtherPages || data.playerProps.hideOtherPages" (change)="newPlayerConfig.hideOtherPages = $event.checked"> {{ 'player.hideOtherPages' | translate }} </mat-checkbox> <mat-form-field appearance="fill"> <mat-label>{{ 'player.activeAfterID' | translate }}</mat-label> - <input matInput type="text" [value]="newPlayerConfig.activeAfterID || data.player.activeAfterID" + <input matInput type="text" [value]="newPlayerConfig.activeAfterID || data.playerProps.activeAfterID" (input)="newPlayerConfig.activeAfterID = $any($event.target).value"> </mat-form-field> <mat-form-field appearance="fill"> <mat-label>{{ 'player.minRuns' | translate }}</mat-label> <input matInput type="number" min="0" - [ngModel]="newPlayerConfig.minRuns || data.player.minRuns" + [ngModel]="newPlayerConfig.minRuns || data.playerProps.minRuns" (ngModelChange)="newPlayerConfig.minRuns = $event"> </mat-form-field> <mat-form-field appearance="fill"> <mat-label>{{ 'player.maxRuns' | translate }}</mat-label> <input matInput type="number" min="0" - [ngModel]="newPlayerConfig.maxRuns || data.player.maxRuns" + [ngModel]="newPlayerConfig.maxRuns || data.playerProps.maxRuns" (ngModelChange)="newPlayerConfig.maxRuns = $event"> </mat-form-field> - <mat-checkbox [checked]="newPlayerConfig.showRestRuns || data.player.showRestRuns" + <mat-checkbox [checked]="newPlayerConfig.showRestRuns || data.playerProps.showRestRuns" (change)="newPlayerConfig.showRestRuns = $event.checked"> {{ 'player.showRestRuns' | translate }} </mat-checkbox> @@ -119,7 +119,7 @@ import { PlayerElement } from '../../../../../common/interfaces/UIElementInterfa ` }) export class PlayerEditDialogComponent { - newPlayerConfig: PlayerElement = {} as PlayerElement; - constructor(@Inject(MAT_DIALOG_DATA)public data: { player: PlayerElement }) { + newPlayerConfig: PlayerProperties = {} as PlayerProperties; + constructor(@Inject(MAT_DIALOG_DATA)public data: { playerProps: PlayerProperties }) { } } diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/canvas.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/canvas.component.ts index 1dd5084dc..77157747b 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/canvas.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/canvas.component.ts @@ -7,7 +7,7 @@ import { takeUntil } from 'rxjs/operators'; import { UnitService } from '../../../../services/unit.service'; import { SelectionService } from '../../../../services/selection.service'; import { Page } from '../../../../../../../common/models/page'; -import { UIElement } from '../../../../../../../common/models/uI-element'; +import { PositionedElement, UIElement } from '../../../../../../../common/models/uI-element'; import { Section } from '../../../../../../../common/models/section'; @Component({ @@ -74,15 +74,15 @@ export class CanvasComponent implements OnInit, OnDestroy { } elementDropped(event: CdkDragDrop<DropListData>): void { - const selectedElements = this.selectionService.getSelectedElements(); + const selectedElements = this.selectionService.getSelectedElements() as PositionedElement[]; if (event.previousContainer !== event.container) { this.moveElementsBetweenSections(selectedElements, event.previousContainer.data.sectionIndex, event.container.data.sectionIndex); } else { - selectedElements.forEach((element: UIElement) => { - let newXPosition = element.xPosition + event.distance.x; + selectedElements.forEach((element: PositionedElement) => { + let newXPosition = element.positionProps.xPosition + event.distance.x; if (newXPosition < 0) { newXPosition = 0; } @@ -91,7 +91,7 @@ export class CanvasComponent implements OnInit, OnDestroy { } this.unitService.updateElementProperty([element], 'xPosition', newXPosition); - let newYPosition = element.yPosition + event.distance.y; + let newYPosition = element.positionProps.yPosition + event.distance.y; if (newYPosition < 0) { newYPosition = 0; } diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/canvas-element-overlay.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/canvas-element-overlay.ts index f49ea1e51..f22a93c94 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/canvas-element-overlay.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/canvas-element-overlay.ts @@ -7,13 +7,13 @@ import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { UnitService } from '../../../../../services/unit.service'; import * as ElementFactory from '../../../../../../../../common/util/element.factory'; -import { ElementComponent } from '../../../../../../../../common/element-component.directive'; +import { ElementComponent } from '../../../../../../../../common/directives/element-component.directive'; import { SelectionService } from '../../../../../services/selection.service'; import { UIElement } from '../../../../../../../../common/models/uI-element'; import { CompoundElementComponent } from - '../../../../../../../../common/element-components/compound-elements/compound-element.directive'; -import { ClozeComponent } from '../../../../../../../../common/element-components/compound-elements/cloze.component'; -import { ClozeElement } from '../../../../../../../../common/models/compound-elements/cloze-element'; + '../../../../../../../../common/directives/compound-element.directive'; +import { ClozeComponent } from '../../../../../../../../common/ui-elements/cloze/cloze.component'; +import { ClozeElement } from '../../../../../../../../common/ui-elements/cloze/cloze-element'; @Directive() export abstract class CanvasElementOverlay implements OnInit, OnDestroy { diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/static-canvas-overlay.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/static-canvas-overlay.component.ts index 486e171b5..bd4c8c7c8 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/static-canvas-overlay.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/overlays/static-canvas-overlay.component.ts @@ -20,9 +20,9 @@ import { UIElement } from '../../../../../../../../common/models/uI-element'; <!-- Needs extra div because styling can interfere with drag and drop--> <div [style.position]="'absolute'" [style.outline]="isSelected ? 'purple solid 1px' : ''" - [style.left.px]="element.xPosition" - [style.top.px]="element.yPosition" - [style.z-index]="element.zIndex"> + [style.left.px]="element.positionProps?.xPosition" + [style.top.px]="element.positionProps?.yPosition" + [style.z-index]="element.positionProps?.zIndex"> <div *ngIf="isSelected" class="resizeHandle" cdkDrag (cdkDragStarted)="resizeDragStart()" (cdkDragMoved)="resizeElement($event)" 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 b643936d8..7b82ef450 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 @@ -41,14 +41,14 @@ import { UIElementType } from '../../../../../../../common/models/uI-element'; [element]="$any(element)" [style.min-width.px]="element.width" [style.min-height.px]="element.height" - [style.margin-left.px]="element.marginLeft" - [style.margin-right.px]="element.marginRight" - [style.margin-top.px]="element.marginTop" - [style.margin-bottom.px]="element.marginBottom" - [style.grid-column-start]="element.gridColumnStart" - [style.grid-column-end]="element.gridColumnEnd" - [style.grid-row-start]="element.gridRowStart" - [style.grid-row-end]="element.gridRowEnd" + [style.margin-left.px]="element.positionProps.marginLeft" + [style.margin-right.px]="element.positionProps.marginRight" + [style.margin-top.px]="element.positionProps.marginTop" + [style.margin-bottom.px]="element.positionProps.marginBottom" + [style.grid-column-start]="element.positionProps.gridColumnStart" + [style.grid-column-end]="element.positionProps.gridColumnEnd" + [style.grid-row-start]="element.positionProps.gridRowStart" + [style.grid-row-end]="element.positionProps.gridRowEnd" cdkDropList cdkDropListSortingDisabled [cdkDropListData]="{ sectionIndex: sectionIndex }" [cdkDropListConnectedTo]="dropListList" diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties-component.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties-component.component.ts index 7341691be..82cdaf3ab 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties-component.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties-component.component.ts @@ -4,10 +4,9 @@ import { } from '@angular/core'; import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events'; import { moveItemInArray } from '@angular/cdk/drag-drop'; -import { InputElementValue, UIElement } from '../../../../../../../common/models/uI-element'; -import { LikertElement } from '../../../../../../../common/models/compound-elements/likert-element'; -import { LikertElementRow } from '../../../../../../../common/models/compound-elements/likert-element-row'; -import { LikertColumn, LikertRow } from '../../../../../../../common/interfaces/UIElementInterfaces'; +import { InputElementValue, LikertColumn, LikertRow, UIElement } from '../../../../../../../common/models/uI-element'; +import { LikertElement } from '../../../../../../../common/ui-elements/likert/likert-element'; +import { LikertElementRow } from '../../../../../../../common/ui-elements/likert/likert-element-row'; import { UnitService } from '../../../../services/unit.service'; import { FileService } from '../../../../../../../common/file.service'; @@ -36,7 +35,7 @@ import { FileService } from '../../../../../../../common/file.service'; </ng-container> <!-- Autostart for detecting a player-element --> - <ng-container *ngIf="combinedProperties.autostart !== undefined"> + <ng-container *ngIf="combinedProperties.playerProps"> <button (click)="unitService.showDefaultEditDialog(selectedElements[0])"> <mat-icon>build_circle</mat-icon> </button> diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-properties.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-properties.component.ts index faf9c2057..41bcc0e6a 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-properties.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-properties.component.ts @@ -7,9 +7,8 @@ import { takeUntil } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { UnitService } from '../../../../services/unit.service'; import { SelectionService } from '../../../../services/selection.service'; -import { MessageService } from '../../../../../../../common/message.service'; -import { UIElement } from '../../../../../../../common/models/uI-element'; -import { LikertColumn, LikertRow } from '../../../../../../../common/interfaces/UIElementInterfaces'; +import { MessageService } from '../../../../../../../common/services/message.service'; +import { LikertColumn, LikertRow, UIElement } from '../../../../../../../common/models/uI-element'; @Component({ selector: 'app-element-properties', diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts index e69f45f6d..0f35d0b60 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-sizing-properties.component.ts @@ -30,7 +30,7 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field appearance="fill"> <mat-label>{{'propertiesPanel.xPosition' | translate }}</mat-label> <input matInput type="number" #xPosition="ngModel" min="0" - [ngModel]="combinedProperties.xPosition" + [ngModel]="combinedProperties.positionProps?.xPosition" (ngModelChange)="updateModel.emit( { property: 'xPosition', value: $event, isInputValid: xPosition.valid && $event !== null })"> </mat-form-field> @@ -38,7 +38,7 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field appearance="fill"> <mat-label>{{'propertiesPanel.yPosition' | translate }}</mat-label> <input matInput type="number" #yPosition="ngModel" min="0" - [ngModel]="combinedProperties.yPosition" + [ngModel]="combinedProperties.positionProps?.yPosition" (ngModelChange)="updateModel.emit( { property: 'yPosition', value: $event, isInputValid: yPosition.valid && $event !== null })"> </mat-form-field> @@ -53,13 +53,13 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; isInputValid: width.valid && $event !== null })"> </mat-form-field> - <mat-checkbox *ngIf="combinedProperties.useMinHeight !== undefined" - [checked]="$any(combinedProperties.useMinHeight)" + <mat-checkbox *ngIf="combinedProperties.positionProps?.useMinHeight !== undefined" + [checked]="$any(combinedProperties.positionProps?.useMinHeight)" (change)="updateModel.emit({ property: 'useMinHeight', value: $event.checked })"> {{'propertiesPanel.useMinHeight' | translate }} </mat-checkbox> - <mat-form-field *ngIf="combinedProperties.useMinHeight" appearance="fill"> + <mat-form-field *ngIf="combinedProperties.positionProps?.useMinHeight" appearance="fill"> <mat-label>{{'propertiesPanel.minHeight' | translate }}</mat-label> <input matInput type="number" #height="ngModel" min="0" [ngModel]="combinedProperties.height" @@ -73,24 +73,24 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <div fxLayoutAlign="row"> <mat-form-field class="small-input"> <mat-label>{{'propertiesPanel.startColumn' | translate }}</mat-label> - <input matInput type="number" [ngModel]="combinedProperties.gridColumnStart" + <input matInput type="number" [ngModel]="combinedProperties.positionProps?.gridColumnStart" (ngModelChange)="updateModel.emit({ property: 'gridColumnStart', value: $event })"> </mat-form-field> <mat-form-field class="small-input"> <mat-label>{{'propertiesPanel.endColumn' | translate }}</mat-label> - <input matInput type="number" [ngModel]="combinedProperties.gridColumnEnd" + <input matInput type="number" [ngModel]="combinedProperties.positionProps?.gridColumnEnd" (ngModelChange)="updateModel.emit({ property: 'gridColumnEnd', value: $event })"> </mat-form-field> </div> <div fxLayoutAlign="row"> <mat-form-field class="small-input"> <mat-label>{{'propertiesPanel.startRow' | translate }}</mat-label> - <input matInput type="number" [ngModel]="combinedProperties.gridRowStart" + <input matInput type="number" [ngModel]="combinedProperties.positionProps?.gridRowStart" (ngModelChange)="updateModel.emit({ property: 'gridRowStart', value: $event })"> </mat-form-field> <mat-form-field class="small-input"> <mat-label>{{'propertiesPanel.endRow' | translate }}</mat-label> - <input matInput type="number" [ngModel]="combinedProperties.gridRowEnd" + <input matInput type="number" [ngModel]="combinedProperties.positionProps?.gridRowEnd" (ngModelChange)="updateModel.emit({ property: 'gridRowEnd', value: $event })"> </mat-form-field> </div> @@ -101,7 +101,7 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field class="centered-form-field small-input"> <mat-label>{{'propertiesPanel.top' | translate }}</mat-label> <input matInput type="number" #marginTop="ngModel" min="0" - [ngModel]="combinedProperties.marginTop" + [ngModel]="combinedProperties.positionProps?.marginTop" (ngModelChange)="updateModel.emit( { property: 'marginTop', value: $event, isInputValid: marginTop.valid && $event !== null })"> </mat-form-field> @@ -109,14 +109,14 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field class="small-input"> <mat-label>{{'propertiesPanel.left' | translate }}</mat-label> <input matInput type="number" #marginLeft="ngModel" min="0" - [ngModel]="combinedProperties.marginLeft" + [ngModel]="combinedProperties.positionProps?.marginLeft" (ngModelChange)="updateModel.emit( { property: 'marginLeft', value: $event, isInputValid: marginLeft.valid && $event !== null })"> </mat-form-field> <mat-form-field class="right-form-field small-input"> <mat-label>{{'propertiesPanel.right' | translate }}</mat-label> <input matInput type="number" #marginRight="ngModel" min="0" - [ngModel]="combinedProperties.marginRight" + [ngModel]="combinedProperties.positionProps?.marginRight" (ngModelChange)="updateModel.emit( { property: 'marginRight', value: $event, @@ -126,7 +126,7 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field class="centered-form-field small-input"> <mat-label>{{'propertiesPanel.bottom' | translate }}</mat-label> <input matInput type="number" #marginBottom="ngModel" min="0" - [ngModel]="combinedProperties.marginBottom" + [ngModel]="combinedProperties.positionProps?.marginBottom" (ngModelChange)="updateModel.emit( { property: 'marginBottom', value: $event, @@ -138,7 +138,7 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; <mat-form-field appearance="fill"> <mat-label>{{'propertiesPanel.zIndex' | translate }}</mat-label> <input matInput type="number" #zIndex="ngModel" min="0" - [ngModel]="combinedProperties.zIndex" + [ngModel]="combinedProperties.positionProps?.zIndex" (ngModelChange)="updateModel.emit({ property: 'zIndex', value: $event, isInputValid: zIndex.valid && $event !== null })" diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-style-properties.component.ts b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-style-properties.component.ts index 8198d016f..b8b01fbe0 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-style-properties.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-style-properties.component.ts @@ -26,69 +26,69 @@ import { UIElement } from '../../../../../../../common/models/uI-element'; (input)="updateModel.emit({ property: 'itemBackgroundColor', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.backgroundColor !== undefined" + <mat-form-field *ngIf="combinedProperties.surfaceProps?.backgroundColor !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.backgroundColor' | translate }}</mat-label> - <input matInput type="color" [value]="combinedProperties.backgroundColor" + <input matInput type="color" [value]="combinedProperties.surfaceProps?.backgroundColor" (input)="updateModel.emit({ property: 'backgroundColor', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.backgroundColor !== undefined" + <mat-form-field *ngIf="combinedProperties.surfaceProps?.backgroundColor !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.backgroundColor' | translate }}</mat-label> - <input matInput type="text" [value]="combinedProperties.backgroundColor" + <input matInput type="text" [value]="combinedProperties.surfaceProps?.backgroundColor" (input)="updateModel.emit({ property: 'backgroundColor', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.fontColor !== undefined" + <mat-form-field *ngIf="combinedProperties.fontProps?.fontColor !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.fontColor' | translate }}</mat-label> - <input matInput type="color" [value]="combinedProperties.fontColor" + <input matInput type="color" [value]="combinedProperties.fontProps?.fontColor" (input)="updateModel.emit({ property: 'fontColor', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.fontColor !== undefined" + <mat-form-field *ngIf="combinedProperties.fontProps?.fontColor !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.fontColor' | translate }}</mat-label> - <input matInput type="text" [value]="combinedProperties.fontColor" + <input matInput type="text" [value]="combinedProperties.fontProps?.fontColor" (input)="updateModel.emit({ property: 'fontColor', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.font !== undefined" + <mat-form-field *ngIf="combinedProperties.fontProps?.font !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.font' | translate }}</mat-label> - <input matInput type="text" [value]="combinedProperties.font" + <input matInput type="text" [value]="combinedProperties.fontProps?.font" (input)="updateModel.emit({ property: 'font', value: $any($event.target).value })"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.fontSize !== undefined" + <mat-form-field *ngIf="combinedProperties.fontProps?.fontSize !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.fontSize' | translate }}</mat-label> <input matInput type="number" #fontSize="ngModel" min="0" - [ngModel]="combinedProperties.fontSize" + [ngModel]="combinedProperties.fontProps?.fontSize" (ngModelChange)="updateModel.emit({ property: 'fontSize', value: $event, isInputValid: fontSize.valid && $event !== null})"> </mat-form-field> - <mat-form-field *ngIf="combinedProperties.lineHeight !== undefined" + <mat-form-field *ngIf="combinedProperties.fontProps?.lineHeight !== undefined" appearance="fill" class="mdInput textsingleline"> <mat-label>{{'propertiesPanel.lineHeight' | translate }}</mat-label> <input matInput type="number" #lineHeight="ngModel" min="0" - [ngModel]="combinedProperties.lineHeight" + [ngModel]="combinedProperties.fontProps?.lineHeight" (ngModelChange)="updateModel.emit({ property: 'lineHeight', value: $event, isInputValid: lineHeight.valid && $event !== null })"> </mat-form-field> - <mat-checkbox *ngIf="combinedProperties.bold !== undefined" - [checked]="$any(combinedProperties.bold)" + <mat-checkbox *ngIf="combinedProperties.fontProps?.bold !== undefined" + [checked]="$any(combinedProperties.fontProps?.bold)" (change)="updateModel.emit({ property: 'bold', value: $event.checked })"> {{'propertiesPanel.bold' | translate }} </mat-checkbox> - <mat-checkbox *ngIf="combinedProperties.italic !== undefined" - [checked]="$any(combinedProperties.italic)" + <mat-checkbox *ngIf="combinedProperties.fontProps?.italic !== undefined" + [checked]="$any(combinedProperties.fontProps?.italic)" (change)="updateModel.emit({ property: 'italic', value: $event.checked })"> {{'propertiesPanel.italic' | translate }} </mat-checkbox> - <mat-checkbox *ngIf="combinedProperties.underline !== undefined" - [checked]="$any(combinedProperties.underline)" + <mat-checkbox *ngIf="combinedProperties.fontProps?.underline !== undefined" + [checked]="$any(combinedProperties.fontProps?.underline)" (change)="updateModel.emit({ property: 'underline', value: $event.checked })"> {{'propertiesPanel.underline' | translate }} </mat-checkbox> diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.ts b/projects/editor/src/app/components/unit-view/unit-view.component.ts index a65d7afcb..c9a50a43e 100644 --- a/projects/editor/src/app/components/unit-view/unit-view.component.ts +++ b/projects/editor/src/app/components/unit-view/unit-view.component.ts @@ -4,7 +4,7 @@ import { takeUntil } from 'rxjs/operators'; import { UnitService } from '../../services/unit.service'; import { DialogService } from '../../services/dialog.service'; import { SelectionService } from '../../services/selection.service'; -import { MessageService } from '../../../../../common/message.service'; +import { MessageService } from '../../../../../common/services/message.service'; import { Page } from '../../../../../common/models/page'; import { Unit } from '../../../../../common/models/unit'; diff --git a/projects/editor/src/app/services/dialog.service.ts b/projects/editor/src/app/services/dialog.service.ts index a4fd9ce0d..06b248aaf 100644 --- a/projects/editor/src/app/services/dialog.service.ts +++ b/projects/editor/src/app/services/dialog.service.ts @@ -1,8 +1,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; -import { PlayerElement, LikertColumn } from '../../../../common/interfaces/UIElementInterfaces'; -import { LikertElementRow } from '../../../../common/models/compound-elements/likert-element-row'; +import { LikertElementRow } from '../../../../common/ui-elements/likert/likert-element-row'; import { ConfirmationDialogComponent } from '../components/dialogs/confirmation-dialog.component'; import { TextEditDialogComponent } from '../components/dialogs/text-edit-dialog.component'; import { TextEditMultilineDialogComponent } from '../components/dialogs/text-edit-multiline-dialog.component'; @@ -10,6 +9,7 @@ import { RichTextEditDialogComponent } from '../components/dialogs/rich-text-edi import { PlayerEditDialogComponent } from '../components/dialogs/player-edit-dialog.component'; import { LikertColumnEditDialogComponent } from '../components/dialogs/likert-column-edit-dialog.component'; import { LikertRowEditDialogComponent } from '../components/dialogs/likert-row-edit-dialog.component'; +import { LikertColumn, PlayerElement, PlayerProperties } from '../../../../common/models/uI-element'; @Injectable({ providedIn: 'root' @@ -65,10 +65,10 @@ export class DialogService { return dialogRef.afterClosed(); } - showPlayerEditDialog(player: PlayerElement): Observable<PlayerElement> { + showPlayerEditDialog(playerProps: PlayerProperties): Observable<PlayerProperties> { const dialogRef = this.dialog.open(PlayerEditDialogComponent, { data: { - player: player + playerProps: playerProps } }); return dialogRef.afterClosed(); diff --git a/projects/editor/src/app/services/unit.service.ts b/projects/editor/src/app/services/unit.service.ts index e0f7a9e4b..a9325248c 100644 --- a/projects/editor/src/app/services/unit.service.ts +++ b/projects/editor/src/app/services/unit.service.ts @@ -3,18 +3,24 @@ import { DomSanitizer } from '@angular/platform-browser'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; import { FileService } from '../../../../common/file.service'; -import { MessageService } from '../../../../common/message.service'; +import { MessageService } from '../../../../common/services/message.service'; import { IdService } from '../../../../common/id.service'; import { DialogService } from './dialog.service'; import { VeronaAPIService } from './verona-api.service'; import { Unit } from '../../../../common/models/unit'; import { Page } from '../../../../common/models/page'; import { Section } from '../../../../common/models/section'; -import { CompoundElement, InputElement, UIElement, UIElementType } from '../../../../common/models/uI-element'; -import { TextElement } from '../../../../common/models/text-element'; -import { LikertElement } from '../../../../common/models/compound-elements/likert-element'; -import { LikertElementRow } from '../../../../common/models/compound-elements/likert-element-row'; -import { LikertColumn, LikertRow, PlayerElement } from '../../../../common/interfaces/UIElementInterfaces'; +import { + InputElement, + LikertColumn, + LikertRow, PlayerElement, + PlayerProperties, PositionedElement, + UIElement, + UIElementType +} from '../../../../common/models/uI-element'; +import { TextElement } from '../../../../common/ui-elements/text/text-element'; +import { LikertElement } from '../../../../common/ui-elements/likert/likert-element'; +import { LikertElementRow } from '../../../../common/ui-elements/likert/likert-element-row'; import { SelectionService } from './selection.service'; import * as ElementFactory from '../../../../common/util/element.factory'; @@ -150,7 +156,7 @@ export class UnitService { ); } else { newElement = ElementFactory.createElement( - { type: elementType, dynamicPositioning: section.dynamicPositioning } as UIElement + { type: elementType, dynamicPositioning: section.dynamicPositioning } as unknown as UIElement ); } if (coordinates && section.dynamicPositioning) { @@ -162,7 +168,7 @@ export class UnitService { newElement.xPosition = coordinates.x; newElement.yPosition = coordinates.y; } - section.addElement(newElement); + section.addElement(newElement as PositionedElement); this.veronaApiService.sendVoeDefinitionChangedNotification(); } @@ -177,7 +183,7 @@ export class UnitService { transferElement(elements: UIElement[], previousSection: Section, newSection: Section): void { previousSection.elements = previousSection.elements.filter(element => !elements.includes(element)); elements.forEach(element => { - newSection.elements.push(element); + newSection.elements.push(element as PositionedElement); element.dynamicPositioning = newSection.dynamicPositioning; }); this._unit.next(this._unit.value); @@ -191,7 +197,7 @@ export class UnitService { } duplicateElementsInSection(elements: UIElement[], section: Section): void { - section.duplicateElements(elements); + section.duplicateElements(elements as PositionedElement[]); this.veronaApiService.sendVoeDefinitionChangedNotification(); } @@ -295,7 +301,7 @@ export class UnitService { } alignElements(elements: UIElement[], alignmentDirection: 'left' | 'right' | 'top' | 'bottom'): void { - Section.alignElements(elements, alignmentDirection); + Section.alignElements(elements as PositionedElement[], alignmentDirection); this.elementPropertyUpdated.next(); this.veronaApiService.sendVoeDefinitionChangedNotification(); } @@ -367,8 +373,8 @@ export class UnitService { break; case 'audio': case 'video': - this.dialogService.showPlayerEditDialog(element as unknown as PlayerElement) - .subscribe((result: PlayerElement) => { + this.dialogService.showPlayerEditDialog((element as PlayerElement).playerProps) + .subscribe((result: PlayerProperties) => { if (result) { for (const key in result) { // @ts-ignore diff --git a/projects/player/src/app/components/element-container/element-container.component.ts b/projects/player/src/app/components/element-container/element-container.component.ts index 75b03cbe9..443457e94 100644 --- a/projects/player/src/app/components/element-container/element-container.component.ts +++ b/projects/player/src/app/components/element-container/element-container.component.ts @@ -14,19 +14,19 @@ import { MarkingService } from '../../services/marking.service'; import { InputElement, InputElementValue, UIElement, ValueChangeElement } from '../../../../../common/models/uI-element'; -import { FormElementComponent } from '../../../../../common/form-element-component.directive'; +import { FormElementComponent } from '../../../../../common/directives/form-element-component.directive'; import { CompoundElementComponent } - from '../../../../../common/element-components/compound-elements/compound-element.directive'; -import { TextElement } from '../../../../../common/models/text-element'; -import { VideoElement } from '../../../../../common/models/video-element'; -import { AudioElement } from '../../../../../common/models/audio-element'; -import { ImageElement } from '../../../../../common/models/image-element'; + from '../../../../../common/directives/compound-element.directive'; +import { TextElement } from '../../../../../common/ui-elements/text/text-element'; +import { VideoElement } from '../../../../../common/ui-elements/video/video-element'; +import { AudioElement } from '../../../../../common/ui-elements/audio/audio-element'; +import { ImageElement } from '../../../../../common/ui-elements/image/image-element'; import { VeronaPostService } from '../../services/verona-post.service'; -import { MediaPlayerElementComponent } from '../../../../../common/media-player-element-component.directive'; +import { MediaPlayerElementComponent } from '../../../../../common/directives/media-player-element-component.directive'; import { MediaPlayerService } from '../../services/media-player.service'; -import { TextComponent } from '../../../../../common/element-components/text.component'; -import { TextFieldElement } from '../../../../../common/models/text-field-element'; -import { ElementComponent } from '../../../../../common/element-component.directive'; +import { TextComponent } from '../../../../../common/ui-elements/text/text.component'; +import { TextFieldElement } from '../../../../../common/ui-elements/text-field/text-field-element'; +import { ElementComponent } from '../../../../../common/directives/element-component.directive'; @Component({ selector: 'app-element-container', diff --git a/projects/player/src/app/components/section/section.component.html b/projects/player/src/app/components/section/section.component.html index 6fe7a7355..4f14641a3 100644 --- a/projects/player/src/app/components/section/section.component.html +++ b/projects/player/src/app/components/section/section.component.html @@ -8,8 +8,8 @@ [style.width.px]="element.width" [style.height.px]="element.height" [style.position]="'absolute'" - [style.left.px]="element.xPosition" - [style.top.px]="element.yPosition" + [style.left.px]="element.positionProps.xPosition" + [style.top.px]="element.positionProps.yPosition" [elementModel]="element" [parentForm]="sectionForm" [pageIndex]="pageIndex" @@ -27,15 +27,15 @@ <ng-container *ngFor="let element of section.elements; let i = index"> <app-element-container [style.min-width.px]="element.width" - [style.min-height.px]="element.useMinHeight ? element.height : 0" - [style.margin-left.px]="element.marginLeft" - [style.margin-right.px]="element.marginRight" - [style.margin-top.px]="element.marginTop" - [style.margin-bottom.px]="element.marginBottom" - [style.grid-column-start]="element.gridColumnStart" - [style.grid-column-end]="element.gridColumnEnd" - [style.grid-row-start]="element.gridRowStart" - [style.grid-row-end]="element.gridRowEnd" + [style.min-height.px]="element.positionProps.useMinHeight ? element.height : 0" + [style.margin-left.px]="element.positionProps.marginLeft" + [style.margin-right.px]="element.positionProps.marginRight" + [style.margin-top.px]="element.positionProps.marginTop" + [style.margin-bottom.px]="element.positionProps.marginBottom" + [style.grid-column-start]="element.positionProps.gridColumnStart" + [style.grid-column-end]="element.positionProps.gridColumnEnd" + [style.grid-row-start]="element.positionProps.gridRowStart" + [style.grid-row-end]="element.positionProps.gridRowEnd" [elementModel]="element" [parentForm]="sectionForm" [pageIndex]="pageIndex" diff --git a/projects/player/src/app/components/unit-state/unit-state.component.ts b/projects/player/src/app/components/unit-state/unit-state.component.ts index b02f69b27..f6adf3bd9 100644 --- a/projects/player/src/app/components/unit-state/unit-state.component.ts +++ b/projects/player/src/app/components/unit-state/unit-state.component.ts @@ -11,7 +11,7 @@ import { TranslateService } from '@ngx-translate/core'; import { FormService } from '../../services/form.service'; import { VeronaSubscriptionService } from '../../services/verona-subscription.service'; import { VeronaPostService } from '../../services/verona-post.service'; -import { MessageService } from '../../../../../common/message.service'; +import { MessageService } from '../../../../../common/services/message.service'; import { MetaDataService } from '../../services/meta-data.service'; import { FormControlElement, FormControlValidators, ChildFormGroup diff --git a/projects/player/src/app/services/keyboard.service.ts b/projects/player/src/app/services/keyboard.service.ts index cd49bbc16..07d601025 100644 --- a/projects/player/src/app/services/keyboard.service.ts +++ b/projects/player/src/app/services/keyboard.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { FormElementComponent } from '../../../../common/form-element-component.directive'; +import { FormElementComponent } from '../../../../common/directives/form-element-component.directive'; @Injectable({ providedIn: 'root' diff --git a/projects/player/src/app/services/marking.service.ts b/projects/player/src/app/services/marking.service.ts index 1bdeb46b8..ebf223e0e 100644 --- a/projects/player/src/app/services/marking.service.ts +++ b/projects/player/src/app/services/marking.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { TextComponent } from '../../../../common/element-components/text.component'; +import { TextComponent } from '../../../../common/ui-elements/text/text.component'; @Injectable({ providedIn: 'root' diff --git a/projects/player/src/app/services/media-player.service.ts b/projects/player/src/app/services/media-player.service.ts index 429f6972e..071dad7f2 100644 --- a/projects/player/src/app/services/media-player.service.ts +++ b/projects/player/src/app/services/media-player.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; -import { MediaPlayerElementComponent } from '../../../../common/media-player-element-component.directive'; +import { MediaPlayerElementComponent } from '../../../../common/directives/media-player-element-component.directive'; @Injectable({ providedIn: 'root' -- GitLab