diff --git a/projects/common/component-utils.ts b/projects/common/component-utils.ts deleted file mode 100644 index 2fb91550f6f5fb5cb6cde5fa8ee5f1257482a0ec..0000000000000000000000000000000000000000 --- 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 ebeecbee76300fbac1f968ef7db54b96993f6d5c..06470986f5cc35726ae38b22a6cb87345b8b12fd 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 af8faa3eec957576902f96c05a9ce0438556de54..9d4546bb70508b025be16d86fed891be452d2113 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 d5b4504b1587b32943ed9776a292c654927cf62f..78329ce7f863885e110523d79eddd9d70adbf971 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 192a635d0dc75111b2e8989cb44403125de56318..0999d8041387ed8cfe693e73c35b493f63d88282 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 012578d96050cc03398946c2a2d779c2005f402b..4439ea03b3e431a659427e2e2815d61608cdb151 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 fa698c833f6cef02bc3cb875c3116c8cac8934d5..c5bc5f2050eceff83e70e64579fdae6939defe0a 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 5f7c42a7f00c1f9d53834f745c874bdfd569438c..0000000000000000000000000000000000000000 --- 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 9bfab2aa2f5f7d842c82829725e8d844a0e03869..0000000000000000000000000000000000000000 --- 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 7e189f55f513f099d2f35ab791763d065669aa21..0000000000000000000000000000000000000000 --- 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 4f748b1d2e0b199e4abdf26313225dc7b22031bc..0000000000000000000000000000000000000000 --- 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 dbec053591d6bd94bc3aece5268d837161fc1227..0000000000000000000000000000000000000000 --- 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 68934fed714217c30cd7ce5b139fa09ae01b66a5..0000000000000000000000000000000000000000 --- 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 3773e738f93f58060bfcb25dc91679e5fe5399fb..0000000000000000000000000000000000000000 --- 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 b09d2f485c98f0f2f14551d33356fdbd58714d89..0000000000000000000000000000000000000000 --- 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 124ac1e9221b8e50ba0614e1dd7ed0b28d975db3..e62396e537ed3c8d3472da1a5c513c88ce3d5725 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 3b28683e9044090546dbe9eb6680b5d6cf1c7371..0000000000000000000000000000000000000000 --- 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 875c1c3fc2c334d709ce0f030a98326c8f3731c4..0000000000000000000000000000000000000000 --- 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 639db0d8c55332b0249bd42a20d10901e4ea9e65..0000000000000000000000000000000000000000 --- 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 c006d6afaa2385348b036ffb9902e7ca8e1b601c..251d08657e1e3a7b2198492cf6089cf4d8e81d4c 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 987fea472090c17901131fe478dd479364676a47..0000000000000000000000000000000000000000 --- 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 8e69f4d210a692c6c9baa31dc3315314a7cfbddf..9edf676b700d5cbe8ef7755623f1887743fa7743 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 464646b9dd511db8db06c0af3532e8b5a8966619..fdebce769e625b49d1408637a414fcc925ce6ef4 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 0000000000000000000000000000000000000000..a8bf96ace40fd7de217839bbef498c28d1cadf24 --- /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 db5cc3c1a9fcc3a5e87f00ff8b6b6c3ec27776d7..39d7f65b867c5fcb97fa8f1f9a52de3e10232ef2 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 0000000000000000000000000000000000000000..7378189a5417a624043335760b13225f7f802ca6 --- /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 ee2127d561e2e3a342dd14b94a90a3a3c67a163a..5f08a3b66e5656c1665692799e85a3fce29fc86c 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 0000000000000000000000000000000000000000..397b9e65b40ee84fe66e3e03d18aec1e6e0c6f7b --- /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 52c1cb260573925ff3d39db20a71defdcc24a9da..63f48f9a00fe42ea202ea10b851480f327d7169a 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 4132d926befdc26e419af0a0ae5504c3f117f3d0..fcc11f40695318158e0fd62225687f08ef6f0217 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 74219b106411da703d4ca38746e7de083dcf927e..3a7efb71524f2d50f37a4b771d8b1470f8c7302d 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 878bbd3af3a1b3a196045849064c5d9d36377e0c..5f711567d3a1bfd4ee8be3f0dc5b9d439b012ef6 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 0000000000000000000000000000000000000000..491d4b8041036c696c0a8e05b3cdc42bd3e8a79a --- /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 0000000000000000000000000000000000000000..e7f61b7ec0e669c89561339a8a6be5a283c34257 --- /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 fd76fca20353fe77f79b81c422605f41a04bb1e7..fa480e36b9e1c4d3544166565073d0536325a7fe 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 2c6ee045a2a090a847a10d0e7b481e4e81db6602..7aa0cbaac774af812e2f49631608985ecce8583a 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 7d56bb7925518b8f3a44582553d06e08cc6fc0e1..3100d46848cb90947342806ae24a31a06039555f 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 e896aca9a9677a332e34544a0c8696e7c571c5a5..059492009d04bc052fec6c1360f83b3628ba60d8 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 44cfa1745ead4a02afed11af14badaf3fcb5bcf3..aba80d6f0df0e7c841302e65ed6a92162f62845d 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 9f5e6f0c2bfe34aa477c79d679b5a0334f0a26e9..6d6cfe486377a947232107e841bc72e2f3b88710 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 a1cdbde1428e42bd9ddcf640625d073bbd4b940a..6f2ea7a2062679df989a3f5436f9816ed30efadd 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 4cffed822beb95bec52ff7d51d3883d79fe7bab9..30c22a510ea7de977dc15c2b7898d50c0b4e8176 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 7954fe8228f4b18d9ac1ca02eccb6a85d0d3c0c7..bfa521653d68d688adc75ca474b41cee14c60058 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 0000000000000000000000000000000000000000..28ab5270ec5c4e202280d0ba54e944cb19aca47b --- /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 0000000000000000000000000000000000000000..01e429e9d3a2fa8e4e12b13eac491a902603b6a3 --- /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 39feccf07f5f421b94cec3e2f00f0fbc46b0e43c..42f1e740b5a3347f1d05a9c5c725411e64fd0a07 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 0000000000000000000000000000000000000000..842c0fd7c4455ad2c011f5e2da92f50b6d951fc2 --- /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 401ce1760fc61d7fdbc9e810509139ffee1cc745..8963f5cf4366bb8cdeb60d9d1373c3569238783c 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 0000000000000000000000000000000000000000..db71baa6ad46b4741de39ac384a0af348f989330 --- /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 176fc1c56c86b1bb0c8b6cef7ca1bbe3f6dfa6e6..00606307308b125e11fe271fe25b80b2e22d2ecf 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 0000000000000000000000000000000000000000..0a442ac36c901da1b9ce274485319f233d9070dc --- /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 93a228cef1bf1f3e1d76c7bd04bb66e9ec2cfee6..65ca7e4a9a483e256251bc6fecd2a964ebca8cfe 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 6eb9edff221a1d658eef035f3cbb2f2630336903..77c56a80f794b606b92ab49e406d9795fe243b6f 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 6b668e640d5ac835e18f486323a58074ce61982c..6443e91384e00f8b3b9e09d839896bb6e5394606 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 0000000000000000000000000000000000000000..784ee7c0e7e6e75fb6f173c128160261caf862e1 --- /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 d9ad61b129526575f63fa7b9031a5b5ed44b0696..da938882a74fd5cfd2f7472883b9064a05f8af19 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 dee9e0a180e9fea9c3655a0d55227b15f8912ca2..8baa07ccab337ae44567765a9e44913b4c4fc7f4 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 4b5d5ca7e7e5e4859ee7dbda9c9f9282b5cbb451..2ebf73d7bb2907cc904c4985c7686f16326bb507 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 74dd6b3f0948ccf1e5c053277e4f0e1638d25fcd..f775e3dfe20b184e87d060e5b9e144a2dc8c8c53 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 8cdcba1b16b3f6b52bce3388558cfc1f16071731..d5e86b927a526db6aea59dfa8492973eee34d9c8 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 8ce581e24a45b76ac04dff2dec986fe3fed0bca9..de21ee54cef372a23480e52cc12df1e96bda3a49 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 c74ea895afd80191ad78afc299d0cb209cfcdc45..b5df03bc30dc62fcefbb140bae4bdc3be52a3061 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 1dd5084dc24b4be89daad0db89f296c07c4f6210..77157747b006300d1b94ceffb16d30796dea39c6 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 f49ea1e51f0100f5850bda4f8e56c7592bf3b708..f22a93c949cca52516c9c6831c39804537003983 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 486e171b51a46411e0c7c064d493ee06760d15f3..bd4c8c7c8eae12e26f2139c4110c25f75d745d86 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 b643936d8b40191f87f126e603136b27da075938..7b82ef45061bc2fac3777b5333e8a420c08011c4 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 7341691be725b49118989e89804c1a61e0e3cb98..82cdaf3ab63bf80b18a174351246cce8c9d7c88e 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 faf9c2057f9f1ff352404e425578d00e536ffa7a..41bcc0e6ad4119ba3608c3eb76fd549a0ad2ff4e 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 e69f45f6d4a585f14c11480af5635a18467bf991..0f35d0b604be66e5fd76ec6468b9943a9c44a093 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 8198d016f31b4f47399ae554165e03fc5e03a98c..b8b01fbe009331d283577d8420fe524153d6ac31 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 a65d7afcbb00f4df28515fa6301fbe0398236dbf..c9a50a43ed0af5d68cd9665d6fe89d6c5fef3bb4 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 a4fd9ce0d0922632337964c4eacff45d55ca449a..06b248aafb4d56a1d46d3c7c35fce1cc75bd5ff9 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 e0f7a9e4b326ae1f119228b5844085ab7d6bdcac..a9325248c1239d14be036d939b2ce2a0c3042172 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 75b03cbe9342fb303fb2b80cfc141961d2883b0c..443457e9470aa795003bc78ae655733ffa4baf31 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 6fe7a7355addd11c2efd4e47eab1a1a7b7ae50bd..4f14641a300f2f6b5580ebd0d54acdfa4c70f911 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 b02f69b273a61b01ad5072c8cec2661ac80571e8..f6adf3bd9ebe5a01f8044285f5466f308f42d27f 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 cd49bbc16da35b4fe96322573b5844c32a3285f6..07d601025e3bda1f1b6e62ce701f3ad824023863 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 1bdeb46b86dbc8c4dfbb3be7a04d4e43cb641ebe..ebf223e0e5f59391b6364ed29e99a843afdd4ce4 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 429f6972e95c3ba83643e52a1a293ddd51b4799b..071dad7f2af3070e8ef20059dfff3a175c118cf8 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'