diff --git a/projects/common/classes/element.ts b/projects/common/classes/element.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c0a0fcb2b19a93b7f51a775d225e9ab613cf2db --- /dev/null +++ b/projects/common/classes/element.ts @@ -0,0 +1,454 @@ +import { + BasicStyles, + DragNDropValueObject, + ElementStyling, InputAssistancePreset, + PlayerProperties, + PositionProperties, TextImageLabel, UIElementType, UIElementValue +} from 'common/interfaces/elements'; +import { ElementFactory } from 'common/util/element.factory'; +import { ClozeDocument } from 'common/interfaces/cloze'; + +export abstract class UIElement { + [index: string]: any; + id: string = 'id_placeholder'; + type: UIElementType; + width: number = 180; + height: number = 60; + position?: PositionProperties; + styling?: ElementStyling; + player?: PlayerProperties; + + constructor(type: UIElementType) { + this.type = type; + } + + setProperty(property: string, value: UIElementValue): void { + (this as UIElement)[property] = value; + } +} + +export type InputElementValue = string[] | string | number | boolean | DragNDropValueObject[] | null; + +export abstract class InputElement extends UIElement { + label?: string; + value: InputElementValue = null; + required: boolean = false; + requiredWarnMessage: string = 'Eingabe erforderlich'; + readOnly: boolean = false; +} + +export interface PositionedUIElement extends UIElement { + position: PositionProperties; +} + +export class ButtonElement extends UIElement implements PositionedUIElement { + label: string = 'Knopf'; + imageSrc: string | null = null; + asLink: boolean = false; + action: null | 'unitNav' | 'pageNav' = null; + actionParam: null | 'previous' | 'next' | 'first' | 'last' | 'end' | number = null; + position: PositionProperties; + styling: BasicStyles & { + borderRadius: number; + }; + + constructor(button: ButtonElement) { + super('button'); + Object.assign(this, button); + this.position = ElementFactory.initPositionProps(button.position); + this.styling = { + ...ElementFactory.initStylingProps(button.styling), + borderRadius: button.styling?.borderRadius | 0 + }; + } +} + +export class CheckboxElement extends InputElement implements PositionedUIElement { + position: PositionProperties; + styling: BasicStyles; + + constructor(checkbox: CheckboxElement) { + super('checkbox'); + this.position = ElementFactory.initPositionProps(checkbox.position); + this.styling = ElementFactory.initStylingProps(checkbox.styling); + } +} + +export class ClozeElement extends UIElement implements PositionedUIElement { + document: ClozeDocument; + columnCount: number = 1; + position: PositionProperties; + styling: BasicStyles & { + lineHeight: number; + }; + + constructor(cloze: Partial<ClozeElement>) { + super('cloze'); + Object.assign(this, cloze); + this.document = {} as ClozeDocument; + this.position = ElementFactory.initPositionProps(cloze.position); + this.styling = { + ...ElementFactory.initStylingProps(cloze.styling), + lineHeight: cloze.styling?.lineHeight || 150 + }; + } +} + +export class DropdownElement extends InputElement implements PositionedUIElement { + options: string[] = []; + allowUnset: boolean = false; + position: PositionProperties; + styling: BasicStyles; + + constructor(dropdown: DropdownElement) { + super('dropdown'); + Object.assign(this, dropdown); + this.position = ElementFactory.initPositionProps(dropdown.position); + this.styling = { + ...ElementFactory.initStylingProps(dropdown.styling) + }; + } +} + +export class DropListElement extends InputElement implements PositionedUIElement { + onlyOneItem: boolean = false; + connectedTo: string[] = []; + copyOnDrop: boolean = false; + orientation: 'vertical' | 'horizontal' | 'flex' = 'vertical'; + highlightReceivingDropList: boolean = false; + highlightReceivingDropListColor: string = '#006064'; + position: PositionProperties; + styling: BasicStyles & { + itemBackgroundColor: string; + }; + + constructor(dropList: DropListElement) { + super('drop-list'); + Object.assign(this, dropList); + this.position = ElementFactory.initPositionProps(dropList.position); + this.styling = { + ...ElementFactory.initStylingProps(dropList.styling), + itemBackgroundColor: dropList.styling?.itemBackgroundColor || '#c9e0e0' + }; + } +} + +export class DropListSimpleElement extends InputElement { + connectedTo: string[] = []; + copyOnDrop: boolean = false; + highlightReceivingDropList: boolean = false; + highlightReceivingDropListColor: string = '#006064'; + styling: BasicStyles & { + itemBackgroundColor: string; + }; + + constructor(dropListSimple: DropListSimpleElement) { + super('drop-list-simple'); + Object.assign(this, dropListSimple); + this.position = ElementFactory.initPositionProps(dropListSimple.position); + this.styling = { + ...ElementFactory.initStylingProps(dropListSimple.styling), + itemBackgroundColor: dropListSimple.styling?.itemBackgroundColor || '#c9e0e0' + }; + } +} + +export class FrameElement extends UIElement implements PositionedUIElement { + position: PositionProperties; + styling: BasicStyles & { + borderWidth: number; + borderColor: string; + borderStyle: 'solid' | 'dotted' | 'dashed' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset'; + borderRadius: number; + }; + + constructor(frame: FrameElement) { + super('frame'); + Object.assign(this, frame); + this.position = ElementFactory.initPositionProps(frame.position); + this.styling = { + ...ElementFactory.initStylingProps(frame.styling), + borderWidth: frame.styling?.borderWidth || 1, + borderColor: frame.styling?.borderColor || 'black', + borderStyle: frame.styling?.borderStyle || 'solid', + borderRadius: frame.styling?.borderRadius || 0 + }; + } +} + +export class ImageElement extends UIElement implements PositionedUIElement { + src: string | undefined; + scale: boolean = false; + magnifier: boolean = false; + magnifierSize: number = 100; + magnifierZoom: number = 1.5; + magnifierUsed: boolean = false; + position: PositionProperties; + + constructor(image: ImageElement) { + super('image'); + Object.assign(this, image); + this.position = ElementFactory.initPositionProps(image.position); + } +} + +export class LikertElement extends UIElement implements PositionedUIElement { + rows: LikertRowElement[] = []; + columns: TextImageLabel[] = []; + firstColumnSizeRatio: number = 5; + position: PositionProperties; + styling: BasicStyles & { + lineHeight: number; + lineColoring: boolean; + lineColoringColor: string; + }; + + constructor(likert: Partial<LikertElement>) { + super('likert'); + Object.assign(this, likert); + this.position = ElementFactory.initPositionProps(likert.position); + this.styling = { + ...ElementFactory.initStylingProps(likert.styling), + lineHeight: likert.styling?.lineHeight || 135, + lineColoring: likert.styling?.lineColoring !== undefined ? likert.styling.lineColoring as boolean : true, + lineColoringColor: likert.styling?.lineColoringColor || '#c9e0e0' + }; + } +} + +export class LikertRowElement extends InputElement { + rowLabel: TextImageLabel; + columnCount: number = 0; + firstColumnSizeRatio: number = 5; + verticalButtonAlignment: 'auto' | 'center' = 'center'; + + constructor(likertRow: Partial<LikertRowElement>) { + super('likert-row'); + Object.assign(this, likertRow); + this.rowLabel = ElementFactory.initTextImageLabel(); + } +} + +export class RadioButtonGroupElement extends InputElement implements PositionedUIElement { + richTextOptions: string[] = []; + alignment: 'column' | 'row' = 'column'; + strikeOtherOptions: boolean = false; + position: PositionProperties; + styling: BasicStyles; + + constructor(radio: Partial<RadioButtonGroupElement>) { + super('radio'); + Object.assign(this, radio); + this.position = ElementFactory.initPositionProps(radio.position); + this.styling = { + ...ElementFactory.initStylingProps(radio.styling) + }; + } +} + +export class RadioButtonGroupComplexElement extends InputElement implements PositionedUIElement { + columns: TextImageLabel[] = []; + position: PositionProperties; + styling: BasicStyles; + + constructor(radio: RadioButtonGroupComplexElement) { + super('radio-group-images'); + Object.assign(this, radio); + this.position = ElementFactory.initPositionProps(radio.position); + this.styling = { + ...ElementFactory.initStylingProps(radio.styling) + }; + } +} + +export class SliderElement extends InputElement implements PositionedUIElement { + minValue: number = 0; + maxValue: number = 100; + showValues: boolean = true; + barStyle: boolean = false; + thumbLabel: boolean = false; + position: PositionProperties; + styling: BasicStyles; + + constructor(slider: SliderElement) { + super('slider'); + Object.assign(this, slider); + this.position = ElementFactory.initPositionProps(slider.position); + this.styling = { + ...ElementFactory.initStylingProps(slider.styling) + }; + } +} + +export class SpellCorrectElement extends InputElement implements PositionedUIElement { + inputAssistancePreset: InputAssistancePreset = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + restrictedToInputAssistanceChars: boolean = true; + showSoftwareKeyboard: boolean = false; + softwareKeyboardShowFrench: boolean = false; + position: PositionProperties; + styling: BasicStyles; + + constructor(element: SpellCorrectElement) { + super('spell-correct'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling) + }; + } +} + +export class TextFieldElement extends InputElement implements PositionedUIElement { + appearance: 'fill' | 'outline' = 'outline'; + minLength: number | undefined; + minLengthWarnMessage: string = 'Eingabe zu kurz'; + maxLength: number | undefined; + maxLengthWarnMessage: string = 'Eingabe zu lang'; + pattern: string | undefined; + patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; + inputAssistancePreset: InputAssistancePreset = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + restrictedToInputAssistanceChars: boolean = true; // TODO refactor + showSoftwareKeyboard: boolean = false; + softwareKeyboardShowFrench: boolean = false; + clearable: boolean = false; + position: PositionProperties; + styling: BasicStyles & { + lineHeight: number; + }; + + constructor(element: TextFieldElement) { + super('text-field'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling), + lineHeight: element.styling?.lineHeight || 135 + }; + } +} + +export class TextFieldSimpleElement extends InputElement { + minLength: number | undefined; + minLengthWarnMessage: string = 'Eingabe zu kurz'; + maxLength: number | undefined; + maxLengthWarnMessage: string = 'Eingabe zu lang'; + pattern: string | undefined; + patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe'; + inputAssistancePreset: InputAssistancePreset = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + restrictedToInputAssistanceChars: boolean = true; + showSoftwareKeyboard: boolean = false; + softwareKeyboardShowFrench: boolean = false; + clearable: boolean = false; + styling: BasicStyles & { + lineHeight: number; + }; + + constructor(element: TextFieldSimpleElement) { + super('text-field-simple'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling), + lineHeight: element.styling?.lineHeight || 135 + }; + } +} + +export class TextAreaElement extends InputElement implements PositionedUIElement { + appearance: 'fill' | 'outline' = 'outline'; + resizeEnabled: boolean = false; + rowCount: number = 3; + inputAssistancePreset: InputAssistancePreset = 'none'; + inputAssistancePosition: 'floating' | 'right' = 'floating'; + restrictedToInputAssistanceChars: boolean = true; + showSoftwareKeyboard: boolean = false; + softwareKeyboardShowFrench: boolean = false; + position: PositionProperties; + styling: BasicStyles & { + lineHeight: number; + }; + + constructor(element: TextAreaElement) { + super('text-area'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling), + lineHeight: element.styling?.lineHeight || 135 + }; + } +} + +export class TextElement extends UIElement implements PositionedUIElement { + text: string = 'Lorem ipsum dolor sit amet'; + highlightableOrange: boolean = false; + highlightableTurquoise: boolean = false; + highlightableYellow: boolean = false; + columnCount: number = 1; + position: PositionProperties; + styling: BasicStyles & { + lineHeight: number; + }; + + constructor(element: TextElement) { + super('text'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling), + lineHeight: element.styling?.lineHeight || 135 + }; + } +} + +export class ToggleButtonElement extends InputElement { + richTextOptions: string[] = []; + strikeOtherOptions: boolean = false; + verticalOrientation: boolean = false; + dynamicWidth: boolean = true; + styling: BasicStyles & { + lineHeight: number; + selectionColor: string; + }; + + constructor(element: Partial<ToggleButtonElement>) { + super('toggle-button'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.styling = { + ...ElementFactory.initStylingProps(element.styling), + lineHeight: element.styling?.lineHeight || 135, + selectionColor: element.styling?.selectionColor || '#c7f3d0' + }; + } +} + +export class AudioElement extends UIElement implements PositionedUIElement { + src: string | undefined; + position: PositionProperties; + player: PlayerProperties; + + constructor(element: AudioElement) { + super('audio'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.player = ElementFactory.initPlayerProps(element.player); + } +} + +export class VideoElement extends UIElement implements PositionedUIElement { + src: string | undefined; + scale: boolean = false; // TODO besserer name + position: PositionProperties; + player: PlayerProperties; + + constructor(element: VideoElement) { + super('video'); + Object.assign(this, element); + this.position = ElementFactory.initPositionProps(element.position); + this.player = ElementFactory.initPlayerProps(element.player); + } +} diff --git a/projects/common/classes/unit.ts b/projects/common/classes/unit.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a0368d5b8cebfbaa46dc7f3c939dccbc6e4478f --- /dev/null +++ b/projects/common/classes/unit.ts @@ -0,0 +1,53 @@ +import packageJSON from '../../../package.json'; +import { ElementFactory } from 'common/util/element.factory'; +import { PositionedUIElement } from 'common/classes/element'; + +export class Unit { + type = 'aspect-unit-definition'; + version: string; + pages: Page[] = []; + + constructor(unit?: Unit) { + this.version = packageJSON.config.unit_definition_version; + this.pages = unit?.pages.map(page => new Page(page)) || [new Page()]; + } +} + +export class Page { + [index: string]: any; + sections: Section[] = []; + hasMaxWidth: boolean = false; + maxWidth: number = 900; + margin: number = 30; + backgroundColor: string = '#ffffff'; + alwaysVisible: boolean = false; + alwaysVisiblePagePosition: 'left' | 'right' | 'top' | 'bottom' = 'left'; + alwaysVisibleAspectRatio: number = 50; + + constructor(page?: Page) { + this.sections = page?.sections.map(section => new Section(section)) || [new Section()]; + Object.assign(this, page); + } +} + +export class Section { + [index: string]: any; + elements: PositionedUIElement[] = []; + height: number = 400; + backgroundColor: string = '#ffffff'; + dynamicPositioning: boolean = true; + autoColumnSize: boolean = true; + autoRowSize: boolean = true; + gridColumnSizes: string = '1fr 1fr'; + gridRowSizes: string = '1fr'; + activeAfterID: string | null = null; + + constructor(section?: Partial<Section>) { + this.elements = section?.elements?.map(element => ElementFactory.createElement(element) as PositionedUIElement) || []; + Object.assign(this, section); + } + + setProperty(property: string, value: any): void { + this[property] = value; + } +} diff --git a/projects/common/components/compound-child-overlay.component.ts b/projects/common/components/compound-child-overlay.component.ts index 79da270468f4e0bf8ae7ed0c6617c3300c06f843..4406c7dec0e43dbcd55a27c95edb0ca2f2446756 100644 --- a/projects/common/components/compound-child-overlay.component.ts +++ b/projects/common/components/compound-child-overlay.component.ts @@ -4,9 +4,8 @@ import { } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ElementComponent } from '../directives/element-component.directive'; -import { - DropListSimpleElement, TextFieldSimpleElement, ToggleButtonElement, ValueChangeElement -} from '../interfaces/elements'; +import { DropListSimpleElement, TextFieldSimpleElement, ToggleButtonElement } from 'common/classes/element'; +import { ValueChangeElement } from 'common/interfaces/elements'; @Component({ selector: 'aspect-compound-child-overlay', diff --git a/projects/common/components/text-marking-bar/text-marking-bar.component.ts b/projects/common/components/text-marking-bar/text-marking-bar.component.ts index 9245d57120952fe34f3f31f5a24fa067dfc1d6f1..0c22b5dd87386a896ce225ea1b9e3c9348931032 100644 --- a/projects/common/components/text-marking-bar/text-marking-bar.component.ts +++ b/projects/common/components/text-marking-bar/text-marking-bar.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { TextElement } from '../../interfaces/elements'; +import { TextElement } from 'common/classes/element'; @Component({ selector: 'aspect-text-marking-bar', diff --git a/projects/common/components/ui-elements/button.component.ts b/projects/common/components/ui-elements/button.component.ts index c9c5e73e23ba383b0afeed52ebe7699c66aeae0e..a721750897a323a9d365b2a7e0fa73c979dd002c 100644 --- a/projects/common/components/ui-elements/button.component.ts +++ b/projects/common/components/ui-elements/button.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ElementComponent } from '../../directives/element-component.directive'; -import { ButtonElement } from '../../interfaces/elements'; +import { ButtonElement } from 'common/classes/element'; @Component({ selector: 'aspect-button', diff --git a/projects/common/components/ui-elements/checkbox.component.ts b/projects/common/components/ui-elements/checkbox.component.ts index f67cdb20cb394d1db608cbc790d442f8804d34cb..dff377abf850640daa01e4ae10b26a74567f9d78 100644 --- a/projects/common/components/ui-elements/checkbox.component.ts +++ b/projects/common/components/ui-elements/checkbox.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { CheckboxElement } from '../../interfaces/elements'; +import { CheckboxElement } from 'common/classes/element'; @Component({ selector: 'aspect-checkbox', diff --git a/projects/common/components/ui-elements/cloze.component.ts b/projects/common/components/ui-elements/cloze.component.ts index a82668229b7abc575926b17749b1a7a0a2c3c329..9802b27a98b41aea62512defe56cbbca74e553fa 100644 --- a/projects/common/components/ui-elements/cloze.component.ts +++ b/projects/common/components/ui-elements/cloze.component.ts @@ -4,7 +4,7 @@ import { import { CompoundElementComponent } from '../../directives/compound-element.directive'; import { CompoundChildOverlayComponent } from '../compound-child-overlay.component'; import { ElementComponent } from '../../directives/element-component.directive'; -import { ClozeElement, InputElement } from '../../interfaces/elements'; +import { ClozeElement, InputElement } from 'common/classes/element'; import { ClozeUtils } from '../../util/cloze'; // TODO background color implementieren diff --git a/projects/common/components/ui-elements/drop-list-simple.component.ts b/projects/common/components/ui-elements/drop-list-simple.component.ts index 388d481302c9d4de1c43dc0e164f1589fad8c52c..08cd4e586983c35a770be3d600f825759b8bf794 100644 --- a/projects/common/components/ui-elements/drop-list-simple.component.ts +++ b/projects/common/components/ui-elements/drop-list-simple.component.ts @@ -4,7 +4,8 @@ import { CdkDrag, CdkDropList, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { DragNDropValueObject, DropListSimpleElement } from '../../interfaces/elements'; +import { DropListSimpleElement } from 'common/classes/element'; +import { DragNDropValueObject } from 'common/interfaces/elements'; @Component({ selector: 'aspect-drop-list-simple', diff --git a/projects/common/components/ui-elements/drop-list.component.ts b/projects/common/components/ui-elements/drop-list.component.ts index 590b835aead55240d30ceba051688c4c82b376f6..114aa4381f5de3e76e516ae990098df9b455345e 100644 --- a/projects/common/components/ui-elements/drop-list.component.ts +++ b/projects/common/components/ui-elements/drop-list.component.ts @@ -1,10 +1,11 @@ import { Component, Input } from '@angular/core'; import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events'; import { - CdkDrag, CdkDropList, moveItemInArray, transferArrayItem, copyArrayItem + CdkDrag, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { DragNDropValueObject, DropListElement } from '../../interfaces/elements'; +import { DropListElement } from 'common/classes/element'; +import { DragNDropValueObject } from 'common/interfaces/elements'; @Component({ selector: 'aspect-drop-list', diff --git a/projects/common/components/ui-elements/dropdown.component.ts b/projects/common/components/ui-elements/dropdown.component.ts index e6118c65a16db6d931f1cbd364679ad6b32dbb9c..59118c93ddab60b3061d8a336651be635df1424c 100644 --- a/projects/common/components/ui-elements/dropdown.component.ts +++ b/projects/common/components/ui-elements/dropdown.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { DropdownElement } from '../../interfaces/elements'; +import { DropdownElement } from 'common/classes/element'; @Component({ selector: 'aspect-dropdown', diff --git a/projects/common/components/ui-elements/frame.component.ts b/projects/common/components/ui-elements/frame.component.ts index 4cada7b076abcdcaa0312349ba860c43beec4ca5..20618321f5f7770abba88b681057584e971d75fb 100644 --- a/projects/common/components/ui-elements/frame.component.ts +++ b/projects/common/components/ui-elements/frame.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { ElementComponent } from '../../directives/element-component.directive'; -import { FrameElement } from '../../interfaces/elements'; +import { FrameElement } from 'common/classes/element'; @Component({ selector: 'aspect-frame', diff --git a/projects/common/components/ui-elements/likert-radio-button-group.component.ts b/projects/common/components/ui-elements/likert-radio-button-group.component.ts index ccca1812779f6a9a1890041cea954db823fd84a2..40a8e2d852063c7d7307b40be45f21023e092009 100644 --- a/projects/common/components/ui-elements/likert-radio-button-group.component.ts +++ b/projects/common/components/ui-elements/likert-radio-button-group.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { LikertRowElement } from '../../interfaces/elements'; +import { LikertRowElement } from 'common/classes/element'; @Component({ selector: 'aspect-likert-radio-button-group', diff --git a/projects/common/components/ui-elements/likert.component.ts b/projects/common/components/ui-elements/likert.component.ts index dcde7af097fe47a86038875430bc513c6a33fa5a..08af8efe6f38c8d2cc5f1db786c9d1e23c0ea131 100644 --- a/projects/common/components/ui-elements/likert.component.ts +++ b/projects/common/components/ui-elements/likert.component.ts @@ -4,7 +4,7 @@ import { import { LikertRadioButtonGroupComponent } from './likert-radio-button-group.component'; import { CompoundElementComponent } from '../../directives/compound-element.directive'; import { ElementComponent } from '../../directives/element-component.directive'; -import { LikertElement, LikertRowElement } from '../../interfaces/elements'; +import { LikertElement, LikertRowElement } from 'common/classes/element'; @Component({ selector: 'aspect-likert', diff --git a/projects/common/components/ui-elements/radio-button-group.component.ts b/projects/common/components/ui-elements/radio-button-group.component.ts index 4db4e73646edb6ece1e753c5caa0bbc35e9000be..e6af8b0cbdc11ef4be5f7f96ca93e60149ad80a3 100644 --- a/projects/common/components/ui-elements/radio-button-group.component.ts +++ b/projects/common/components/ui-elements/radio-button-group.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { RadioButtonGroupElement } from '../../interfaces/elements'; +import { RadioButtonGroupElement } from 'common/classes/element'; @Component({ selector: 'aspect-radio-button-group', diff --git a/projects/common/components/ui-elements/radio-group-images.component.ts b/projects/common/components/ui-elements/radio-group-images.component.ts index 85bc1f2e4f7b629ad4c3d5982eb1bb8036a4006d..534dd3604c1d6052e234d6a1c49e9c4590518fc2 100644 --- a/projects/common/components/ui-elements/radio-group-images.component.ts +++ b/projects/common/components/ui-elements/radio-group-images.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { RadioButtonGroupComplexElement } from '../../interfaces/elements'; +import { RadioButtonGroupComplexElement } from 'common/classes/element'; @Component({ selector: 'aspect-radio-group-images', diff --git a/projects/common/components/ui-elements/slider.component.ts b/projects/common/components/ui-elements/slider.component.ts index cd395eef7447b4c29564c7ba3e8d866579b98623..4359f70775c2137647b6f3b9a7559f66c1906534 100644 --- a/projects/common/components/ui-elements/slider.component.ts +++ b/projects/common/components/ui-elements/slider.component.ts @@ -3,7 +3,7 @@ import { } from '@angular/core'; import { MatSlider } from '@angular/material/slider'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { SliderElement } from '../../interfaces/elements'; +import { SliderElement } from 'common/classes/element'; @Component({ selector: 'aspect-slider', diff --git a/projects/common/components/ui-elements/spell-correct.component.ts b/projects/common/components/ui-elements/spell-correct.component.ts index 59a4876add7f593017ec437c4eee83c447953b79..4058f700aa9fc7fe88bfc29321ed547afe884306 100644 --- a/projects/common/components/ui-elements/spell-correct.component.ts +++ b/projects/common/components/ui-elements/spell-correct.component.ts @@ -3,7 +3,7 @@ import { } from '@angular/core'; import { MatInput } from '@angular/material/input'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { SpellCorrectElement } from '../../interfaces/elements'; +import { SpellCorrectElement } from 'common/classes/element'; @Component({ selector: 'aspect-spell-correct', diff --git a/projects/common/components/ui-elements/text-area.component.ts b/projects/common/components/ui-elements/text-area.component.ts index 1c4ad3116a989e218e5623e716c38b819943171a..64f735bcdc4dc398df1a361bff673504d6b1d1b8 100644 --- a/projects/common/components/ui-elements/text-area.component.ts +++ b/projects/common/components/ui-elements/text-area.component.ts @@ -2,7 +2,7 @@ import { Component, Output, EventEmitter, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { TextAreaElement } from '../../interfaces/elements'; +import { TextAreaElement } from 'common/classes/element'; @Component({ selector: 'aspect-text-area', diff --git a/projects/common/components/ui-elements/text-field-simple.component.ts b/projects/common/components/ui-elements/text-field-simple.component.ts index 9b33f69ff758d091f0665b253432185947c070bf..a075a3a56f00618fd98bbeff2efe781e004c1776 100644 --- a/projects/common/components/ui-elements/text-field-simple.component.ts +++ b/projects/common/components/ui-elements/text-field-simple.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { TextFieldSimpleElement } from '../../interfaces/elements'; +import { TextFieldSimpleElement } from 'common/classes/element'; @Component({ selector: 'aspect-text-field-simple', diff --git a/projects/common/components/ui-elements/text-field.component.ts b/projects/common/components/ui-elements/text-field.component.ts index 2ca25ddfe5de2ce598f54c2a28c73adf2e482c96..1cc1432ae18d64d0a97d981ac8adb5d2fb323c2a 100644 --- a/projects/common/components/ui-elements/text-field.component.ts +++ b/projects/common/components/ui-elements/text-field.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { TextFieldElement } from '../../interfaces/elements'; +import { TextFieldElement } from 'common/classes/element'; @Component({ selector: 'aspect-text-field', @@ -28,7 +28,7 @@ import { TextFieldElement } from '../../interfaces/elements'; value="{{elementModel.value}}" [attr.inputmode]="elementModel.showSoftwareKeyboard ? 'none' : 'text'" [formControl]="elementFormControl" - [pattern]="elementModel.pattern" + [pattern]="$any(elementModel.pattern)" [readonly]="elementModel.readOnly" (keydown)="elementModel.showSoftwareKeyboard ? onKeyDown.emit(input) : null" (focus)="onFocusChanged.emit(input)" diff --git a/projects/common/components/ui-elements/text.component.ts b/projects/common/components/ui-elements/text.component.ts index facc29d7ae5b5eef2556210fd16703a5c69d423d..afad470889d6a402c43964f4b8cef3a980bd08e5 100644 --- a/projects/common/components/ui-elements/text.component.ts +++ b/projects/common/components/ui-elements/text.component.ts @@ -2,7 +2,8 @@ import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { ElementComponent } from '../../directives/element-component.directive'; -import { TextElement, ValueChangeElement } from '../../interfaces/elements'; +import { TextElement } from 'common/classes/element'; +import { ValueChangeElement } from 'common/interfaces/elements'; @Component({ selector: 'aspect-text', diff --git a/projects/common/components/ui-elements/toggle-button.component.ts b/projects/common/components/ui-elements/toggle-button.component.ts index ab7ef5aae03225aa6adcc587a2ba9c726b457e32..d21cd10570d26aacfe2f64b932b365b5d8aa84e1 100644 --- a/projects/common/components/ui-elements/toggle-button.component.ts +++ b/projects/common/components/ui-elements/toggle-button.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormElementComponent } from '../../directives/form-element-component.directive'; -import { ToggleButtonElement } from '../../interfaces/elements'; +import { ToggleButtonElement } from 'common/classes/element'; @Component({ selector: 'aspect-toggle-button', diff --git a/projects/common/directives/compound-element.directive.ts b/projects/common/directives/compound-element.directive.ts index c7eb2b4ef6834bb2f8e5f7bfd4986a9deccd2983..653dba4e8c74cfcbd2382adff54b9da73292b314 100644 --- a/projects/common/directives/compound-element.directive.ts +++ b/projects/common/directives/compound-element.directive.ts @@ -6,7 +6,7 @@ import { FormGroup } from '@angular/forms'; import { ElementComponent } from './element-component.directive'; import { CompoundChildOverlayComponent } from '../components/compound-child-overlay.component'; import { LikertRadioButtonGroupComponent } from '../components/ui-elements/likert-radio-button-group.component'; -import { InputElement } from '../interfaces/elements'; +import { InputElement } from 'common/classes/element'; @Directive() export abstract class CompoundElementComponent extends ElementComponent implements AfterViewInit { diff --git a/projects/common/directives/element-component.directive.ts b/projects/common/directives/element-component.directive.ts index 032f097946d67880b02b9c99c97ad56bb79d7238..c57153ef9fed2826a3a7e38044828e23569579ef 100644 --- a/projects/common/directives/element-component.directive.ts +++ b/projects/common/directives/element-component.directive.ts @@ -3,7 +3,7 @@ import { Directive, ElementRef } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; -import { UIElement } from '../interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Directive() export abstract class ElementComponent implements AfterContentChecked { diff --git a/projects/common/directives/media-player-element-component.directive.ts b/projects/common/directives/media-player-element-component.directive.ts index b2e1e989011ace19984c26765e3f683083e396e9..0f1808867fe5c2791b78007e42759b2885fdf216 100644 --- a/projects/common/directives/media-player-element-component.directive.ts +++ b/projects/common/directives/media-player-element-component.directive.ts @@ -4,7 +4,8 @@ import { import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { ElementComponent } from './element-component.directive'; -import { AudioElement, ValueChangeElement, VideoElement } from '../interfaces/elements'; +import { ValueChangeElement } from 'common/interfaces/elements'; +import { AudioElement, VideoElement } from 'common/classes/element'; @Directive() export abstract class MediaPlayerElementComponent extends ElementComponent implements OnInit, OnDestroy { diff --git a/projects/common/interfaces/cloze.ts b/projects/common/interfaces/cloze.ts index 761f6aa52adfb380cbff1edf8e87aecb839aacc5..b861aa06328bc6fad65b274172f5adc6f09bf568 100644 --- a/projects/common/interfaces/cloze.ts +++ b/projects/common/interfaces/cloze.ts @@ -1,4 +1,4 @@ -import { InputElement } from './elements'; +import { InputElement } from 'common/classes/element'; export interface ClozeDocument { type: string; diff --git a/projects/common/interfaces/elements.ts b/projects/common/interfaces/elements.ts index 23dd806aefec11930724089b434d660caf8f3de3..af1dec5122acb6e7652215c513c1f08bffb290e0 100644 --- a/projects/common/interfaces/elements.ts +++ b/projects/common/interfaces/elements.ts @@ -16,30 +16,7 @@ export type UIElementValue = string | number | boolean | undefined | UIElementTy TextImageLabel[] | ClozeDocument | TextImageLabel | PositionProperties | ElementStyling | PlayerProperties | BasicStyles; -export interface UIElement { - [index: string]: UIElementValue; - type: UIElementType; - id: string; - width: number; - height: number; - position?: PositionProperties; // position - styling?: ElementStyling; // styling - player?: PlayerProperties; // player -} - -export interface InputElement extends UIElement { - label?: string; - value: InputElementValue; - required: boolean; - requiredWarnMessage: string; - readOnly: boolean; -} - -export interface PositionedElement extends UIElement { - position: PositionProperties; -} - -export interface PlayerElement extends UIElement { +export interface PlayerElement { player: PlayerProperties; } @@ -124,243 +101,3 @@ export interface PlayerProperties { showRestTime: boolean; playbackTime: number; } - -export interface ButtonElement extends UIElement { - type: 'button'; - label: string; - imageSrc: string | null; - asLink: boolean; - action: null | 'unitNav' | 'pageNav' - actionParam: null | 'previous' | 'next' | 'first' | 'last' | 'end' | number; - position: PositionProperties; - styling: BasicStyles & { - borderRadius: number; - } -} - -export interface CheckboxElement extends InputElement { - type: 'checkbox'; - position: PositionProperties; - styling: BasicStyles; -} - -export interface ClozeElement extends UIElement { - type: 'cloze'; - document: ClozeDocument; - columnCount: number; - position: PositionProperties; - styling: BasicStyles & { - lineHeight: number; - } -} - -export interface DropdownElement extends InputElement { - type: 'dropdown'; - options: string[]; - allowUnset: boolean; - position: PositionProperties; - styling: BasicStyles -} - -export interface DropListElement extends InputElement { - type: 'drop-list'; - onlyOneItem: boolean; - connectedTo: string[]; - copyOnDrop: boolean; - orientation: 'vertical' | 'horizontal' | 'flex'; - highlightReceivingDropList: boolean; - highlightReceivingDropListColor: string; - position: PositionProperties; - styling: BasicStyles & { - itemBackgroundColor: string; - } -} - -export interface DropListSimpleElement extends InputElement { - type: 'drop-list-simple'; - connectedTo: string[]; - copyOnDrop: boolean; - highlightReceivingDropList: boolean; - highlightReceivingDropListColor: string; - styling: BasicStyles & { - itemBackgroundColor: string; - } -} - -export interface FrameElement extends UIElement { - type: 'frame'; - position: PositionProperties; - styling: BasicStyles & { - borderWidth: number; - borderColor: string; - borderStyle: 'solid' | 'dotted' | 'dashed' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset'; - borderRadius: number; - } -} - -export interface ImageElement extends UIElement { - type: 'image'; - src: string; - scale: boolean; - magnifier: boolean; - magnifierSize: number; - magnifierZoom: number; - magnifierUsed: boolean; - position: PositionProperties; -} - -export interface LikertElement extends UIElement { - type: 'likert'; - rows: LikertRowElement[]; - columns: TextImageLabel[]; - firstColumnSizeRatio: number; - readOnly: boolean; - position: PositionProperties; - styling: BasicStyles & { - lineHeight: number; - lineColoring: boolean; - lineColoringColor: string; - }; -} - -export interface LikertRowElement extends InputElement { - type: 'likert-row'; - rowLabel: TextImageLabel; - columnCount: number; - firstColumnSizeRatio: number; - verticalButtonAlignment: 'auto' | 'center'; -} - -export interface RadioButtonGroupElement extends InputElement { - type: 'radio'; - richTextOptions: string[]; - alignment: 'column' | 'row'; - strikeOtherOptions: boolean; - position: PositionProperties; - styling: BasicStyles; -} - -export interface RadioButtonGroupComplexElement extends InputElement { - type: 'radio-group-images' // TODO better name - columns: TextImageLabel[]; - position: PositionProperties; - styling: BasicStyles; -} - -export interface SliderElement extends InputElement { - type: 'slider'; - minValue: number; - maxValue: number; - showValues: boolean; - barStyle: boolean; // TODO besserer name - thumbLabel: boolean; - position: PositionProperties; - styling: BasicStyles; -} - -export interface SpellCorrectElement extends InputElement { - type: 'spell-correct'; - inputAssistancePreset: InputAssistancePreset; - inputAssistancePosition: 'floating' | 'right'; - restrictedToInputAssistanceChars: boolean; - showSoftwareKeyboard: boolean; - softwareKeyboardShowFrench: boolean; - position: PositionProperties; - styling: BasicStyles; -} - -export interface TextFieldElement extends InputElement { - type: 'text-field'; - appearance: 'fill' | 'outline'; - minLength: number; - minLengthWarnMessage: string; - maxLength: number; - maxLengthWarnMessage: string; - pattern: string; - patternWarnMessage: string; - inputAssistancePreset: InputAssistancePreset; - inputAssistancePosition: 'floating' | 'right'; - restrictedToInputAssistanceChars: boolean; - showSoftwareKeyboard: boolean; - softwareKeyboardShowFrench: boolean; - clearable: boolean; - position: PositionProperties; - styling: BasicStyles & { - lineHeight: number; - }; -} - -export interface TextFieldSimpleElement extends InputElement { - type: 'text-field-simple'; - minLength: number; - minLengthWarnMessage: string; - maxLength: number; - maxLengthWarnMessage: string; - pattern: string; - patternWarnMessage: string; - inputAssistancePreset: InputAssistancePreset; - inputAssistancePosition: 'floating' | 'right'; - restrictedToInputAssistanceChars: boolean; - showSoftwareKeyboard: boolean; - softwareKeyboardShowFrench: boolean; - clearable: boolean; - styling: BasicStyles & { - lineHeight: number; - }; -} - -export interface TextAreaElement extends InputElement { - type: 'text-area'; - appearance: 'fill' | 'outline'; - resizeEnabled: boolean; - rowCount: number; - inputAssistancePreset: InputAssistancePreset; - inputAssistancePosition: 'floating' | 'right'; - restrictedToInputAssistanceChars: boolean; - showSoftwareKeyboard: boolean; - softwareKeyboardShowFrench: boolean; - position: PositionProperties; - styling: BasicStyles & { - lineHeight: number; - }; -} - -export interface TextElement extends UIElement { - type: 'text'; - text: string; - highlightableOrange: boolean; - highlightableTurquoise: boolean; - highlightableYellow: boolean; - columnCount: number; - position: PositionProperties; - styling: BasicStyles & { - lineHeight: number; - } -} - -export interface ToggleButtonElement extends InputElement { - type: 'toggle-button'; - richTextOptions: string[]; - strikeOtherOptions: boolean; - verticalOrientation: boolean; - dynamicWidth: boolean; - styling: BasicStyles & { - lineHeight: number; - selectionColor: string; - }; -} - -export interface AudioElement extends UIElement { - type: 'audio'; - src: string; - position: PositionProperties; - player: PlayerProperties; -} - -export interface VideoElement extends UIElement { - type: 'video'; - src: string; - scale: boolean; // TODO besserer name - position: PositionProperties; - player: PlayerProperties; -} diff --git a/projects/common/interfaces/unit.ts b/projects/common/interfaces/unit.ts deleted file mode 100644 index 6a2cee82f80fad426f3fcc0056c7ff164164b8e0..0000000000000000000000000000000000000000 --- a/projects/common/interfaces/unit.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { PositionedElement } from './elements'; - -export interface Unit { - type: 'aspect-unit-definition'; - version: string; - pages: Page[]; -} - -export interface Page { - [index: string]: string | number | boolean | Section[] | undefined; - sections: Section[]; - hasMaxWidth: boolean; - maxWidth: number; - margin: number; - backgroundColor: string; - alwaysVisible: boolean; - alwaysVisiblePagePosition: 'left' | 'right' | 'top' | 'bottom'; - alwaysVisibleAspectRatio: number; -} - -export interface Section { - [index: string]: string | number | boolean | PositionedElement[] | undefined; - elements: PositionedElement[]; - height: number; - backgroundColor: string; - dynamicPositioning: boolean; - autoColumnSize: boolean; - autoRowSize: boolean; - gridColumnSizes: string; - gridRowSizes: string; - activeAfterID: string; -} diff --git a/projects/common/pipes/error-transform.pipe.ts b/projects/common/pipes/error-transform.pipe.ts index 94eab50a8da6122e37149e9e7828f11217dd8c9c..d0e1fb8dff70d4c54cc6097966b6ab9a84baf1f6 100644 --- a/projects/common/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 '../interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Pipe({ name: 'errorTransform' diff --git a/projects/common/services/sanitization.service.ts b/projects/common/services/sanitization.service.ts index c5055efc2879cb8a8e396310013fe2398842b7ab..d46a0e9919444a85a1dc911b9fa5fdfbc4521f22 100644 --- a/projects/common/services/sanitization.service.ts +++ b/projects/common/services/sanitization.service.ts @@ -1,15 +1,5 @@ import { Injectable } from '@angular/core'; import packageJSON from '../../../package.json'; -import { Page, Section, Unit } from 'common/interfaces/unit'; -import { - ClozeElement, DragNDropValueObject, DropListElement, - ElementStyling, - InputElement, LikertElement, LikertRowElement, PlayerProperties, - PositionedElement, PositionProperties, RadioButtonGroupElement, TextElement, - ToggleButtonElement, - UIElement, - UIElementValue -} from 'common/interfaces/elements'; import { ClozeDocument, ClozeDocumentParagraph, ClozeDocumentParagraphPart } from 'common/interfaces/cloze'; import { ClozeUtils } from 'common/util/cloze'; import { Editor } from '@tiptap/core'; @@ -18,6 +8,22 @@ import ToggleButtonExtension from 'common/tiptap-editor-extensions/toggle-button import DropListExtension from 'common/tiptap-editor-extensions/drop-list'; import TextFieldExtension from 'common/tiptap-editor-extensions/text-field'; import { IDService } from './id.service'; +import { Page, Section, Unit } from 'common/classes/unit'; +import { + ClozeElement, DropListElement, + InputElement, + LikertElement, LikertRowElement, + PositionedUIElement, + RadioButtonGroupElement, TextElement, ToggleButtonElement, + UIElement +} from 'common/classes/element'; +import { + DragNDropValueObject, + ElementStyling, + PlayerProperties, + PositionProperties, + UIElementValue +} from 'common/interfaces/elements'; @Injectable({ providedIn: 'root' @@ -74,8 +80,8 @@ export class SanitizationService { return { ...section, elements: section.elements.map((element: UIElement) => ( - this.sanitizeElement(element, section.dynamicPositioning))) as PositionedElement[] - }; + this.sanitizeElement(element, section.dynamicPositioning))) as PositionedUIElement[] + } as Section; } private sanitizeElement(element: Record<string, UIElementValue>, @@ -254,7 +260,7 @@ export class SanitizationService { childElement.type = childElement.type === 'drop-list' ? 'drop-list-simple' : childElement.type; }); - return { + return new ClozeElement({ ...element, document: { ...doc, @@ -277,7 +283,7 @@ export class SanitizationService { )) : undefined })) } as ClozeDocument - } as ClozeElement; + }); } private static createClozeDocument(element: Record<string, UIElementValue>): ClozeDocument { @@ -329,10 +335,10 @@ export class SanitizationService { } private handleLikertElement(element: LikertElement): LikertElement { - return { + return new LikertElement({ ...element, - rows: element.rows.map((row: LikertRowElement) => this.sanitizeElement(row)) - } as LikertElement; + rows: element.rows.map((row: LikertRowElement) => this.sanitizeElement(row) as LikertRowElement) + }); } private static handleLikertRowElement(element: LikertRowElement): LikertRowElement { @@ -340,14 +346,14 @@ export class SanitizationService { if (newElement.rowLabel) { return newElement; } - return { + return new LikertRowElement({ ...newElement, rowLabel: { text: newElement.text, imgSrc: null, position: 'above' } - } as LikertRowElement; + }); } // version 1.1.0 is the only version where there was a plus one for values, which was rolled back afterwards. @@ -356,7 +362,7 @@ export class SanitizationService { { ...element, value: (element.value as number) - 1 - } : + } as InputElement : element; } @@ -364,19 +370,19 @@ export class SanitizationService { if (element.richTextOptions) { return element; } - return { + return new RadioButtonGroupElement({ ...element, richTextOptions: element.options as string[] - }; + }); } private static handleToggleButtonElement(element: ToggleButtonElement): ToggleButtonElement { if (element.richTextOptions) { return element; } - return { + return new ToggleButtonElement({ ...element, richTextOptions: element.options as string[] - }; + }); } } diff --git a/projects/common/util/cloze.ts b/projects/common/util/cloze.ts index fdb354c4f310df1d6d0f9b6dc37f425ea5ea0f6a..de7a414fbbf72412cafd0076537f45f910a5627e 100644 --- a/projects/common/util/cloze.ts +++ b/projects/common/util/cloze.ts @@ -1,5 +1,5 @@ -import { ClozeElement, InputElement } from '../interfaces/elements'; import { ClozeDocument, ClozeDocumentParagraph, ClozeDocumentParagraphPart } from '../interfaces/cloze'; +import { ClozeElement, InputElement } from 'common/classes/element'; export abstract class ClozeUtils { static getClozeChildElements(clozeElement: ClozeElement): InputElement[] { diff --git a/projects/common/util/element.factory.ts b/projects/common/util/element.factory.ts index 591e43a4195b3c5e6c089d4f792650733234d879..74cc6648449c550f82bc183c3013cd9fe147aa09 100644 --- a/projects/common/util/element.factory.ts +++ b/projects/common/util/element.factory.ts @@ -18,98 +18,77 @@ import { SpellCorrectComponent } from '../components/ui-elements/spell-correct.c import { FrameComponent } from '../components/ui-elements/frame.component'; import { ElementComponent } from '../directives/element-component.directive'; import { - AudioElement, BasicStyles, + AudioElement, ButtonElement, - CheckboxElement, - ClozeElement, - DropdownElement, - DropListElement, - DropListSimpleElement, - FrameElement, + CheckboxElement, ClozeElement, + DropdownElement, DropListElement, DropListSimpleElement, FrameElement, ImageElement, - InputElement, InputElementValue, LikertElement, LikertRowElement, PlayerProperties, PositionProperties, - RadioButtonGroupComplexElement, + LikertElement, RadioButtonGroupComplexElement, RadioButtonGroupElement, SliderElement, SpellCorrectElement, TextAreaElement, TextElement, - TextFieldElement, TextFieldSimpleElement, ToggleButtonElement, - UIElement, UIElementType, UIElementValue, + TextFieldElement, + TextFieldSimpleElement, ToggleButtonElement, + UIElement, VideoElement -} from '../interfaces/elements'; -import { ClozeDocument, ClozeDocumentParagraph, ClozeDocumentParagraphPart } from '../interfaces/cloze'; +} from 'common/classes/element'; +import { + BasicStyles, + PlayerProperties, + PositionProperties, + TextImageLabel, + UIElementValue +} from 'common/interfaces/elements'; export abstract class ElementFactory { static createElement(element: Partial<UIElement>): UIElement { - // console.log('createElement', element); switch (element.type) { case 'text': - return ElementFactory.createTextElement(element as Partial<TextElement>); + return new TextElement(element as TextElement); case 'button': - return ElementFactory.createButtonElement(element as Partial<ButtonElement>); + return new ButtonElement(element as ButtonElement); case 'text-field': - return ElementFactory.createTextFieldElement(element as Partial<TextFieldElement>); + return new TextFieldElement(element as TextFieldElement); case 'text-field-simple': - return ElementFactory.createTextFieldSimpleElement(element as Partial<TextFieldSimpleElement>); + return new TextFieldSimpleElement(element as TextFieldSimpleElement); case 'text-area': - return ElementFactory.createTextAreaElement(element as Partial<TextAreaElement>); + return new TextAreaElement(element as TextAreaElement); case 'checkbox': - return ElementFactory.createCheckboxElement(element as Partial<CheckboxElement>); + return new CheckboxElement(element as CheckboxElement); case 'dropdown': - return ElementFactory.createDropdownElement(element as Partial<DropdownElement>); + return new DropdownElement(element as DropdownElement); case 'radio': - return ElementFactory.createRadioButtonGroupElement(element as Partial<RadioButtonGroupElement>); + return new RadioButtonGroupElement(element as RadioButtonGroupElement); case 'image': - return ElementFactory.createImageElement(element as Partial<ImageElement>); + return new ImageElement(element as ImageElement); case 'audio': - return ElementFactory.createAudioElement(element as Partial<AudioElement>); + return new AudioElement(element as AudioElement); case 'video': - return ElementFactory.createVideoElement(element as Partial<VideoElement>); + return new VideoElement(element as VideoElement); case 'likert': - return ElementFactory.createLikertElement(element as Partial<LikertElement>); + return new LikertElement(element as LikertElement); case 'radio-group-images': - return ElementFactory.createRadioButtonGroupComplexElement(element as Partial<RadioButtonGroupComplexElement>); + return new RadioButtonGroupComplexElement(element as RadioButtonGroupComplexElement); case 'drop-list': - return ElementFactory.createDropListElement(element as Partial<DropListElement>); + return new DropListElement(element as DropListElement); case 'drop-list-simple': - return ElementFactory.createDropListSimpleElement(element as Partial<DropListSimpleElement>); + return new DropListSimpleElement(element as DropListSimpleElement); case 'cloze': - return ElementFactory.createClozeElement(element as Partial<ClozeElement>); + return new ClozeElement(element as ClozeElement); case 'slider': - return ElementFactory.createSliderElement(element as Partial<SliderElement>); + return new SliderElement(element as SliderElement); case 'spell-correct': - return ElementFactory.createSpellCorrectElement(element as Partial<SpellCorrectElement>); + return new SpellCorrectElement(element as SpellCorrectElement); case 'frame': - return ElementFactory.createFrameElement(element as Partial<FrameElement>); + return new FrameElement(element as FrameElement); case 'toggle-button': - return ElementFactory.createToggleButtonElement(element as Partial<ToggleButtonElement>); + return new ToggleButtonElement(element as ToggleButtonElement); default: throw new Error(`ElementType ${element.type} not found!`); } } - private static initElement(element: Partial<UIElement>): UIElement { - return { - type: element.type as UIElementType, - id: element.id ? String(element.id) : 'id_placeholder', - width: element.width || 180, - height: element.height || 60 - }; - } - - private static initInputElement(element: Partial<UIElement>): InputElement { - return { - ...ElementFactory.initElement(element), - label: element.value !== undefined ? element.label as string : 'Beschriftung', - value: element.value !== undefined ? element.value as InputElementValue : null, - required: element.required !== undefined ? element.required as boolean : false, - requiredWarnMessage: element.requiredWarnMessage !== undefined ? - element.requiredWarnMessage as string : - 'Eingabe erforderlich', - readOnly: element.readOnly !== undefined ? element.readOnly as boolean : false - }; - } - - private static initPositionProps(defaults: Record<string, UIElementValue> = {}): PositionProperties { + static initPositionProps(defaults: Record<string, UIElementValue> = {}): PositionProperties { return { fixedSize: defaults.fixedSize !== undefined ? defaults.fixedSize as boolean : false, dynamicPositioning: defaults.dynamicPositioning !== undefined ? defaults.dynamicPositioning as boolean : true, @@ -128,7 +107,8 @@ export abstract class ElementFactory { }; } - private static initBasicStyles(defaults: Record<string, UIElementValue> = {}): BasicStyles { + static initStylingProps(defaults?: Record<string, UIElementValue>): BasicStyles { + if (!defaults) return {} as BasicStyles; return { fontColor: defaults.fontColor !== undefined ? defaults.fontColor as string : '#000000', font: defaults.font !== undefined ? defaults.font as string : 'Roboto', @@ -140,7 +120,15 @@ export abstract class ElementFactory { }; } - private static initPlayerProps(defaults: Record<string, UIElementValue> = {}): PlayerProperties { + static initTextImageLabel(): TextImageLabel { + return { + text: '', + imgSrc: null, + position: 'above' + }; + } + + static initPlayerProps(defaults: Record<string, UIElementValue> = {}): PlayerProperties { return { autostart: defaults.autostart !== undefined ? defaults.autostart as boolean : false, autostartDelay: defaults.autostartDelay !== undefined ? defaults.autostartDelay as number : 0, @@ -211,386 +199,4 @@ export abstract class ElementFactory { throw new Error('unknown element'); } } - - private static createButtonElement(element: Partial<ButtonElement>): ButtonElement { - return { - ...ElementFactory.initElement(element), - type: 'button', - label: element.label !== undefined ? element.label : 'Knopf', - imageSrc: element.imageSrc || null, - asLink: element.asLink !== undefined ? element.asLink : false, - action: element.action || null, - actionParam: element.actionParam !== undefined ? element.actionParam : null, - position: ElementFactory.initPositionProps(element.position as Record<string, UIElementValue>), - styling: { - ...ElementFactory.initBasicStyles(element.styling), - borderRadius: element.borderRadius !== undefined ? element.borderRadius as number : 0 - } - }; - } - - private static createCheckboxElement(element: Partial<CheckboxElement>): CheckboxElement { - return { - ...ElementFactory.initInputElement({ width: 215, ...element }), - type: 'checkbox', - value: element.value !== undefined ? element.value : false, - position: ElementFactory.initPositionProps(element.position), - styling: ElementFactory.initBasicStyles(element.styling) - }; - } - - private static createClozeElement(element: Partial<ClozeElement>): ClozeElement { - return { - ...ElementFactory.initElement({ height: 200, ...element }), - type: 'cloze', - document: element.document !== undefined ? - { - ...element.document, - content: element.document.content - .map((paragraph: ClozeDocumentParagraph) => ({ - ...paragraph, - content: paragraph.content ? paragraph.content - .map((paraPart: ClozeDocumentParagraphPart) => ( - ['TextField', 'DropList', 'ToggleButton'].includes(paraPart.type) ? - { - ...paraPart, - attrs: { - ...paraPart.attrs, - model: ElementFactory.createElement(paraPart.attrs!.model as InputElement) - } - } : - { - ...paraPart - } - )) : undefined - })) - } as ClozeDocument : - { type: 'doc', content: [] }, - columnCount: element.columnCount !== undefined ? element.columnCount : 1, - position: ElementFactory.initPositionProps(element.position), - styling: { - ...ElementFactory.initBasicStyles(element.styling), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 150 - } - }; - } - - private static createDropdownElement(element: Partial<DropdownElement>): DropdownElement { - return { - ...ElementFactory.initInputElement({ width: 240, height: 83, ...element }), - type: 'dropdown', - options: element.options !== undefined ? element.options : [], - allowUnset: element.allowUnset !== undefined ? element.allowUnset : false, - position: ElementFactory.initPositionProps(element.position), - styling: ElementFactory.initBasicStyles(element.styling) - }; - } - - private static createDropListElement(element: Partial<DropListElement>): DropListElement { - return { - ...ElementFactory.initInputElement({ height: 100, ...element }), - type: 'drop-list', - value: element.value !== undefined ? element.value : [], - onlyOneItem: element.onlyOneItem !== undefined ? element.onlyOneItem : false, - connectedTo: element.connectedTo !== undefined ? element.connectedTo : [], - copyOnDrop: element.copyOnDrop !== undefined ? element.copyOnDrop : false, - orientation: element.orientation !== undefined ? element.orientation : 'vertical', - highlightReceivingDropList: element.highlightReceivingDropList !== undefined ? - element.highlightReceivingDropList : - false, - highlightReceivingDropListColor: element.highlightReceivingDropListColor !== undefined ? - element.highlightReceivingDropListColor : '#006064', - position: ElementFactory.initPositionProps({ useMinHeight: true, ...element.position }), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: '#f4f4f2', ...element.styling }), - itemBackgroundColor: element.styling?.itemBackgroundColor !== undefined ? - element.styling.itemBackgroundColor as string : '#c9e0e0' - } - }; - } - - private static createDropListSimpleElement(element: Partial<DropListSimpleElement>): DropListSimpleElement { - return { - ...ElementFactory.initInputElement({ width: 150, height: 30, ...element }), - type: 'drop-list-simple', - value: element.value !== undefined ? element.value : [], - connectedTo: element.connectedTo !== undefined ? element.connectedTo : [], - copyOnDrop: element.copyOnDrop !== undefined ? element.copyOnDrop : false, - highlightReceivingDropList: element.highlightReceivingDropList !== undefined ? - element.highlightReceivingDropList : false, - highlightReceivingDropListColor: element.highlightReceivingDropListColor !== undefined ? - element.highlightReceivingDropListColor : '#add8e6', - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: '#f4f4f2', ...element.styling }), - itemBackgroundColor: element.itemBackgroundColor !== undefined ? - element.itemBackgroundColor as string : '#c9e0e0' - } - }; - } - - private static createFrameElement(element: Partial<FrameElement>): FrameElement { - return { - ...ElementFactory.initElement(element), - type: 'frame', - position: ElementFactory.initPositionProps({ zIndex: -1, ...element.position }), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }) as BasicStyles, - borderWidth: element.styling?.borderWidth !== undefined ? element.styling.borderWidth as number : 1, - borderColor: element.styling?.borderColor !== undefined ? element.styling.borderColor as string : 'black', - borderStyle: element.styling?.borderStyle !== undefined ? - element.styling.borderStyle as 'solid' | 'dotted' | 'dashed' | 'double' | 'groove' | - 'ridge' | 'inset' | 'outset' : - 'solid', - borderRadius: element.styling?.borderRadius !== undefined ? element.styling.borderRadius as number : 0 - } - }; - } - - private static createImageElement(element: Partial<ImageElement>): ImageElement { - return { - ...ElementFactory.initElement({ height: 100, ...element }), - type: 'image', - src: element.src || '', // TODO eigentlich undefined - scale: element.scale !== undefined ? element.scale : false, - magnifier: element.magnifier !== undefined ? element.magnifier : false, - magnifierSize: element.magnifierSize !== undefined ? element.magnifierSize : 100, - magnifierZoom: element.magnifierZoom !== undefined ? element.magnifierZoom : 1.5, - magnifierUsed: element.magnifierUsed !== undefined ? element.magnifierUsed : false, - position: ElementFactory.initPositionProps({ ...element.position }) - }; - } - - private static createLikertElement(element: Partial<LikertElement>): LikertElement { - return { - ...ElementFactory.initElement({ width: 250, height: 200, ...element }), - type: 'likert', - rows: element.rows !== undefined ? - element.rows.map(row => ElementFactory.createLikertRowElement(row)) : - [], - columns: element.columns !== undefined ? element.columns : [], - firstColumnSizeRatio: element.firstColumnSizeRatio !== undefined ? element.firstColumnSizeRatio : 5, - readOnly: element.readOnly !== undefined ? element.readOnly : false, - position: ElementFactory.initPositionProps({ marginBottom: 30, ...element.position }), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135, - lineColoring: element.lineColoring !== undefined ? element.lineColoring as boolean : true, - lineColoringColor: element.lineColoringColor !== undefined ? element.lineColoringColor as string : '#c9e0e0' - } - }; - } - - static createLikertRowElement(element: Partial<LikertRowElement>): LikertRowElement { - return { - ...ElementFactory.initInputElement(element), - type: 'likert-row', - rowLabel: element.rowLabel !== undefined ? element.rowLabel : { - text: '', - imgSrc: null, - position: 'above' - }, - columnCount: element.columnCount !== undefined ? element.columnCount : 0, - firstColumnSizeRatio: element.firstColumnSizeRatio !== undefined ? element.firstColumnSizeRatio : 5, - verticalButtonAlignment: - element.verticalButtonAlignment !== undefined ? element.verticalButtonAlignment : 'center' - }; - } - - private static createRadioButtonGroupElement(element: Partial<RadioButtonGroupElement>): RadioButtonGroupElement { - return { - ...ElementFactory.initInputElement({ height: 100, ...element }), - type: 'radio', - richTextOptions: element.richTextOptions !== undefined ? element.richTextOptions : [], - alignment: element.alignment !== undefined ? element.alignment : 'column', - strikeOtherOptions: element.strikeOtherOptions !== undefined ? element.strikeOtherOptions : false, - position: ElementFactory.initPositionProps({ marginBottom: 30, ...element.position }), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135 - } - }; - } - - private static createRadioButtonGroupComplexElement(element: Partial<RadioButtonGroupComplexElement>): - RadioButtonGroupComplexElement { - return { - ...ElementFactory.initInputElement({ height: 100, ...element }), // TODO better name - type: 'radio-group-images', - columns: element.columns !== undefined ? element.columns : [], - position: ElementFactory.initPositionProps({ marginBottom: 40, ...element.position }), - styling: ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }) - }; - } - - private static createSliderElement(element: Partial<SliderElement>): SliderElement { - return { - ...ElementFactory.initInputElement({ width: 300, height: 75, ...element }), - type: 'slider', - minValue: element.minValue !== undefined ? element.minValue : 0, - maxValue: element.maxValue !== undefined ? element.maxValue : 100, - showValues: element.showValues !== undefined ? element.showValues : true, - barStyle: element.barStyle !== undefined ? element.barStyle : false, - thumbLabel: element.thumbLabel !== undefined ? element.thumbLabel : false, - position: ElementFactory.initPositionProps(element.position), - styling: ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }) - }; - } - - private static createSpellCorrectElement(element: Partial<SpellCorrectElement>): SpellCorrectElement { - return { - ...ElementFactory.initInputElement({ width: 230, height: 80, ...element }), - type: 'spell-correct', - inputAssistancePreset: element.inputAssistancePreset !== undefined ? element.inputAssistancePreset : 'none', - inputAssistancePosition: element.inputAssistancePosition !== undefined ? - element.inputAssistancePosition : 'floating', - restrictedToInputAssistanceChars: element.restrictedToInputAssistanceChars !== undefined ? - element.restrictedToInputAssistanceChars : true, - showSoftwareKeyboard: element.showSoftwareKeyboard !== undefined ? - element.showSoftwareKeyboard : false, - softwareKeyboardShowFrench: element.softwareKeyboardShowFrench !== undefined ? - element.softwareKeyboardShowFrench : false, - position: ElementFactory.initPositionProps(element.position), - styling: ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }) - }; - } - - private static createTextElement(element: Partial<TextElement>): TextElement { - return { - ...ElementFactory.initElement({ height: 98, ...element }), - type: 'text', - text: element.text !== undefined ? element.text : 'Lorem ipsum dolor sit amet', - highlightableOrange: element.highlightableOrange !== undefined ? element.highlightableOrange : false, - highlightableTurquoise: element.highlightableTurquoise !== undefined ? element.highlightableTurquoise : false, - highlightableYellow: element.highlightableYellow !== undefined ? element.highlightableYellow : false, - columnCount: element.columnCount !== undefined ? element.columnCount : 1, - position: ElementFactory.initPositionProps(element.position), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135 - } - }; - } - - private static createTextAreaElement(element: Partial<TextAreaElement>): TextAreaElement { - return { - ...ElementFactory.initInputElement({ width: 230, height: 132, ...element }), - type: 'text-area', - appearance: element.appearance !== undefined ? element.appearance : 'outline', - resizeEnabled: element.resizeEnabled !== undefined ? element.resizeEnabled : false, - rowCount: element.rowCount !== undefined ? element.rowCount : 3, - inputAssistancePreset: element.inputAssistancePreset !== undefined ? element.inputAssistancePreset : 'none', - inputAssistancePosition: element.inputAssistancePosition !== undefined ? - element.inputAssistancePosition : 'floating', - restrictedToInputAssistanceChars: element.restrictedToInputAssistanceChars !== undefined ? - element.restrictedToInputAssistanceChars : true, - showSoftwareKeyboard: element.showSoftwareKeyboard !== undefined ? - element.showSoftwareKeyboard : false, - softwareKeyboardShowFrench: element.softwareKeyboardShowFrench !== undefined ? - element.softwareKeyboardShowFrench : false, - position: ElementFactory.initPositionProps(element.position), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135 - } - }; - } - - private static createTextFieldElement(element: Partial<TextFieldElement>): TextFieldElement { - return { - ...ElementFactory.initInputElement({ width: 180, height: 120, ...element }), - type: 'text-field', - appearance: element.appearance !== undefined ? element.appearance : 'outline', - minLength: element.minLength !== undefined ? element.minLength : 0, - minLengthWarnMessage: element.minLengthWarnMessage !== undefined ? - element.minLengthWarnMessage : 'Eingabe zu kurz', - maxLength: element.maxLength !== undefined ? element.maxLength : 0, - maxLengthWarnMessage: element.maxLengthWarnMessage !== undefined ? - element.maxLengthWarnMessage : 'Eingabe zu lang', - pattern: element.pattern !== undefined ? element.pattern : '', - patternWarnMessage: element.patternWarnMessage !== undefined ? - element.patternWarnMessage : 'Eingabe entspricht nicht der Vorgabe', - inputAssistancePreset: element.inputAssistancePreset !== undefined ? element.inputAssistancePreset : 'none', - inputAssistancePosition: element.inputAssistancePosition !== undefined ? - element.inputAssistancePosition : 'floating', - restrictedToInputAssistanceChars: element.restrictedToInputAssistanceChars !== undefined ? - element.restrictedToInputAssistanceChars : true, - showSoftwareKeyboard: element.showSoftwareKeyboard !== undefined ? - element.showSoftwareKeyboard : false, - softwareKeyboardShowFrench: element.softwareKeyboardShowFrench !== undefined ? - element.softwareKeyboardShowFrench : false, - clearable: element.clearable !== undefined ? element.clearable : false, - position: ElementFactory.initPositionProps(element.position), - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135 - } - }; - } - - private static createTextFieldSimpleElement(element: Partial<TextFieldSimpleElement>): TextFieldSimpleElement { - return { - ...ElementFactory.initInputElement({ width: 150, height: 30, ...element }), - type: 'text-field-simple', - minLength: element.minLength !== undefined ? element.minLength : 0, - minLengthWarnMessage: element.minLengthWarnMessage !== undefined ? - element.minLengthWarnMessage : 'Eingabe zu kurz', - maxLength: element.maxLength !== undefined ? element.maxLength : 0, - maxLengthWarnMessage: element.maxLengthWarnMessage !== undefined ? - element.maxLengthWarnMessage : 'Eingabe zu lang', - pattern: element.pattern !== undefined ? element.pattern : '', - patternWarnMessage: element.patternWarnMessage !== undefined ? - element.patternWarnMessage : 'Eingabe entspricht nicht der Vorgabe', - inputAssistancePreset: element.inputAssistancePreset !== undefined ? element.inputAssistancePreset : 'none', - inputAssistancePosition: element.inputAssistancePosition !== undefined ? - element.inputAssistancePosition : 'floating', - restrictedToInputAssistanceChars: element.restrictedToInputAssistanceChars !== undefined ? - element.restrictedToInputAssistanceChars : true, - showSoftwareKeyboard: element.showSoftwareKeyboard !== undefined ? - element.showSoftwareKeyboard : false, - softwareKeyboardShowFrench: element.softwareKeyboardShowFrench !== undefined ? - element.softwareKeyboardShowFrench : false, - clearable: element.clearable !== undefined ? element.clearable : false, - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135 - } - }; - } - - private static createToggleButtonElement(element: Partial<ToggleButtonElement>): ToggleButtonElement { - return { - ...ElementFactory.initInputElement({ height: 25, ...element }), - type: 'toggle-button', - richTextOptions: element.richTextOptions !== undefined ? element.richTextOptions : [], - strikeOtherOptions: element.strikeOtherOptions !== undefined ? element.strikeOtherOptions : false, - verticalOrientation: element.verticalOrientation !== undefined ? element.verticalOrientation : false, - dynamicWidth: element.dynamicWidth !== undefined ? element.dynamicWidth : true, - styling: { - ...ElementFactory.initBasicStyles({ backgroundColor: 'transparent', ...element.styling }), - lineHeight: element.styling?.lineHeight !== undefined ? element.styling?.lineHeight as number : 135, - selectionColor: element.styling?.selectionColor !== undefined ? element.styling.selectionColor : '#c7f3d0' - } - }; - } - - private static createAudioElement(element: Partial<AudioElement>): AudioElement { - return { - ...ElementFactory.initElement({ width: 250, height: 90, ...element }), - type: 'audio', - src: element.src !== undefined ? element.src : '', // TODO eigentlich undefined - position: ElementFactory.initPositionProps(element.position), - player: ElementFactory.initPlayerProps(element.player) - }; - } - - private static createVideoElement(element: Partial<VideoElement>): VideoElement { - return { - ...ElementFactory.initElement({ width: 280, height: 230, ...element }), - type: 'video', - src: element.src !== undefined ? element.src : '', // TODO eigentlich undefined - scale: element.scale !== undefined ? element.scale : false, - position: ElementFactory.initPositionProps(element.position), - player: ElementFactory.initPlayerProps(element.player) - }; - } } diff --git a/projects/common/classes/importedModuleVersion.ts b/projects/common/util/importedModuleVersion.ts similarity index 100% rename from projects/common/classes/importedModuleVersion.ts rename to projects/common/util/importedModuleVersion.ts diff --git a/projects/common/util/unit-utils.ts b/projects/common/util/unit-utils.ts index 621fb277764cef0151b878b219056038175f20bc..877ee9ea387c52f589d95774dd5f0de2bb6f3b45 100644 --- a/projects/common/util/unit-utils.ts +++ b/projects/common/util/unit-utils.ts @@ -1,4 +1,4 @@ -import { UIElement } from '../interfaces/elements'; +import { UIElement } from 'common/classes/element'; export abstract class UnitUtils { static findUIElements(value: any | unknown[], type?: string): UIElement[] { diff --git a/projects/common/util/unit.factory.ts b/projects/common/util/unit.factory.ts deleted file mode 100644 index 14b8ede78af60113dd21a0d4b766eb0e00ec577a..0000000000000000000000000000000000000000 --- a/projects/common/util/unit.factory.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Page, Section, Unit } from '../interfaces/unit'; -import { ElementFactory } from './element.factory'; -import { PositionedElement } from '../interfaces/elements'; -import packageJSON from '../../../package.json'; - -export abstract class UnitFactory { - static createUnit(unit?: Unit): Unit { - return { - type: 'aspect-unit-definition', - version: packageJSON.config.unit_definition_version, - pages: unit?.pages ? unit.pages.map(page => UnitFactory.createPage(page)) : [UnitFactory.createPage()] - }; - } - - static createPage(page?: Page): Page { - return { - sections: page ? page.sections.map(section => UnitFactory.createSection(section)) : [UnitFactory.createSection()], - hasMaxWidth: page && page.hasMaxWidth !== undefined ? page.hasMaxWidth : false, - maxWidth: page && page.hasMaxWidth !== undefined ? page.maxWidth : 900, - margin: page && page.margin !== undefined ? page.margin : 30, - backgroundColor: page && page.backgroundColor !== undefined ? page.backgroundColor : '#ffffff', - alwaysVisible: page && page.alwaysVisible !== undefined ? page.alwaysVisible : false, - alwaysVisiblePagePosition: page && page.alwaysVisiblePagePosition !== undefined ? - page.alwaysVisiblePagePosition : - 'left', - alwaysVisibleAspectRatio: page && page.alwaysVisibleAspectRatio !== undefined ? page.alwaysVisibleAspectRatio : 50 - }; - } - - static createSection(section?: Section): Section { - return { - elements: section ? - section.elements.map(element => ElementFactory.createElement(element) as PositionedElement) : - [], - height: section && section.height !== undefined ? section.height : 400, - backgroundColor: section && section.backgroundColor !== undefined ? section.backgroundColor : '#ffffff', - dynamicPositioning: section && section.dynamicPositioning !== undefined ? section.dynamicPositioning : true, - autoColumnSize: section && section.autoColumnSize !== undefined ? section.autoColumnSize : true, - autoRowSize: section && section.autoRowSize !== undefined ? section.autoRowSize : true, - gridColumnSizes: section && section.gridColumnSizes !== undefined ? section.gridColumnSizes : '1fr 1fr', - gridRowSizes: section && section.gridRowSizes !== undefined ? section.gridRowSizes : '1fr', - activeAfterID: section && section.activeAfterID !== undefined ? section.activeAfterID : '' - }; - } -} diff --git a/projects/editor/src/app/components/canvas/canvas.component.ts b/projects/editor/src/app/components/canvas/canvas.component.ts index 3e0d94bcf5861b10b5006b0f9d8c1a4d92ed81b7..0659e6f237f51a11135c3a03f13218e07512f9eb 100644 --- a/projects/editor/src/app/components/canvas/canvas.component.ts +++ b/projects/editor/src/app/components/canvas/canvas.component.ts @@ -7,8 +7,8 @@ import { SelectionService } from '../../services/selection.service'; import { CanvasElementOverlay } from './overlays/canvas-element-overlay'; import { SectionStaticComponent } from './section-static.component'; import { SectionDynamicComponent } from './section-dynamic.component'; -import { Page, Section } from 'common/interfaces/unit'; -import { PositionedElement, UIElement } from 'common/interfaces/elements'; +import { Page, Section } from 'common/classes/unit'; +import { PositionedUIElement, UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-page-canvas', @@ -35,14 +35,14 @@ export class CanvasComponent { } elementDropped(event: CdkDragDrop<{ sectionIndex: number; gridCoordinates?: number[]; }>): void { - const selectedElements = this.selectionService.getSelectedElements() as PositionedElement[]; + const selectedElements = this.selectionService.getSelectedElements() as PositionedUIElement[]; if (event.previousContainer !== event.container) { this.moveElementsBetweenSections(selectedElements, event.previousContainer.data.sectionIndex, event.container.data.sectionIndex); } else { - selectedElements.forEach((element: PositionedElement) => { + selectedElements.forEach((element: PositionedUIElement) => { let newXPosition = element.position.xPosition + event.distance.x; if (newXPosition < 0) { newXPosition = 0; diff --git a/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts b/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts index dad86d3b992640fe03d80e48fbea78d88a712fe3..663c61d850a4504c8125509e04ca448654da39f7 100644 --- a/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts +++ b/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts @@ -2,9 +2,10 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events'; import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; -import { UIElement, UIElementType } from 'common/interfaces/elements'; import { UnitService } from '../../services/unit.service'; -import { Section } from 'common/interfaces/unit'; +import { UIElementType } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; +import { Section } from 'common/classes/unit'; @Component({ selector: '[app-dynamic-section-helper-grid]', diff --git a/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts b/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts index 1b8ff4a0af3cd216e55cd369d30c6daa86d4d2dc..7aa8a3fa8599c69bb19ea70a4894177e3fe0e2e3 100644 --- a/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts +++ b/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts @@ -13,7 +13,7 @@ import { CompoundElementComponent } from 'common/directives/compound-element.directive'; import { ClozeComponent } from 'common/components/ui-elements/cloze.component'; import { CompoundChildOverlayComponent } from 'common/components/compound-child-overlay.component'; -import { UIElement } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Directive() export abstract class CanvasElementOverlay implements OnInit, OnDestroy { diff --git a/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts b/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts index 279a68468221fff619eb24119922aaa4cef5fff4..c7449fdc17e38d75f11c9f539b6d8dd57ba6a6d3 100644 --- a/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts +++ b/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { take } from 'rxjs/operators'; import { CdkDragEnd, CdkDragMove } from '@angular/cdk/drag-drop'; import { CanvasElementOverlay } from './canvas-element-overlay'; -import { UIElement } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-static-canvas-overlay', diff --git a/projects/editor/src/app/components/canvas/section-dynamic.component.ts b/projects/editor/src/app/components/canvas/section-dynamic.component.ts index aafce3a93460715400200b6d631dbc106d0dbdf7..d3f423bf0d2baea32ef495ef792f3dd45957c573 100644 --- a/projects/editor/src/app/components/canvas/section-dynamic.component.ts +++ b/projects/editor/src/app/components/canvas/section-dynamic.component.ts @@ -3,8 +3,8 @@ import { ViewChildren, QueryList, ViewChild } from '@angular/core'; import { CanvasElementOverlay } from './overlays/canvas-element-overlay'; -import { Section } from 'common/interfaces/unit'; import { DynamicSectionHelperGridComponent } from './dynamic-section-helper-grid.component'; +import { Section } from 'common/classes/unit'; @Component({ selector: 'aspect-section-dynamic', diff --git a/projects/editor/src/app/components/canvas/section-menu.component.ts b/projects/editor/src/app/components/canvas/section-menu.component.ts index 5ac32219419fb4c9724eaecb02944e049eea0c29..bb6e34274cc79d77ae770eddf3ef1cb224f19762 100644 --- a/projects/editor/src/app/components/canvas/section-menu.component.ts +++ b/projects/editor/src/app/components/canvas/section-menu.component.ts @@ -8,10 +8,9 @@ import { Clipboard } from '@angular/cdk/clipboard'; import { UnitService } from '../../services/unit.service'; import { DialogService } from '../../services/dialog.service'; import { SelectionService } from '../../services/selection.service'; -import { Section } from 'common/interfaces/unit'; -import { UIElement } from 'common/interfaces/elements'; -import { UnitFactory } from 'common/util/unit.factory'; import { MessageService } from 'common/services/message.service'; +import { Section } from 'common/classes/unit'; +import { UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-section-menu', @@ -315,7 +314,7 @@ export class SectionMenuComponent implements OnInit, OnDestroy { // TODO try catch if (!pastedText) return; try { - const newSection = UnitFactory.createSection(JSON.parse(pastedText) as Section); + const newSection = new Section(JSON.parse(pastedText) as Section); this.unitService.replaceSection(this.selectionService.selectedPageIndex, this.sectionIndex, newSection); } catch (e) { this.messageService.showError('Fehler beim Lesen der Sektion'); diff --git a/projects/editor/src/app/components/canvas/section-static.component.ts b/projects/editor/src/app/components/canvas/section-static.component.ts index 9e99ce13ca9b43f602ac0dde85369f5c0863ca17..b794f6ce8a37fee41fa5a8a38e75f70c3a71d564 100644 --- a/projects/editor/src/app/components/canvas/section-static.component.ts +++ b/projects/editor/src/app/components/canvas/section-static.component.ts @@ -3,8 +3,8 @@ import { } from '@angular/core'; import { UnitService } from '../../services/unit.service'; import { CanvasElementOverlay } from './overlays/canvas-element-overlay'; -import { Section } from 'common/interfaces/unit'; import { UIElementType } from 'common/interfaces/elements'; +import { Section } from 'common/classes/unit'; @Component({ selector: 'aspect-section-static', 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 5cd40c0d222febc01d45bc7af5fb6efb41b73747..bd4667f6284c049d936889ce5cdcaca8c58780f8 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,8 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { TextImageLabel, LikertRowElement } from 'common/interfaces/elements'; +import { TextImageLabel } from 'common/interfaces/elements'; import { FileService } from 'common/services/file.service'; +import { LikertRowElement } from 'common/classes/element'; @Component({ selector: 'aspect-likert-row-edit-dialog', diff --git a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts index 02959ff49ca1a62ccf5e7f314985c9e999d73972..e2355e5160442148f560c751e3e6804808a74a99 100644 --- a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts +++ b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts @@ -11,9 +11,9 @@ import { MessageService } from 'common/services/message.service'; import { TextImageLabel, DragNDropValueObject, - UIElement, UIElementValue } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-properties', diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts index c5276f1a81f0782487c52373aa589213990b53fe..a543786d87c22b6c96676e255d372790df9aa18a 100644 --- a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts +++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts @@ -8,13 +8,12 @@ import { UnitService } from '../../../services/unit.service'; import { TextImageLabel, DragNDropValueObject, - InputElementValue, - LikertElement, LikertRowElement, - UIElement + InputElementValue } from 'common/interfaces/elements'; import { SelectionService } from '../../../services/selection.service'; import { DialogService } from '../../../services/dialog.service'; import { DomSanitizer } from '@angular/platform-browser'; +import { LikertElement, LikertRowElement, UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-model-properties-component', diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts index b879658444f83025c0dc18a4618aa526264cc89b..d0e52b646eefacf63aa7859a69217b403dfafdc9 100644 --- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts +++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts @@ -1,9 +1,9 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { TextElement } from 'common/interfaces/elements'; import { DialogService } from '../../../../services/dialog.service'; import { SelectionService } from '../../../../services/selection.service'; +import { TextElement } from 'common/classes/element'; @Component({ selector: 'aspect-text-properties-field-set', diff --git a/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts b/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts index 539d4bd7043cfbaa2a82aa8c0a859c2fa081fdbe..59fb7bbee3730e6d4b385819420a4a7a1a63ca1a 100644 --- a/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts +++ b/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts @@ -3,7 +3,8 @@ import { } from '@angular/core'; import { UnitService } from '../../../services/unit.service'; import { SelectionService } from '../../../services/selection.service'; -import { PositionedElement, PositionProperties } from 'common/interfaces/elements'; +import { PositionProperties } from 'common/interfaces/elements'; +import { PositionedUIElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-postion-properties', @@ -53,6 +54,6 @@ export class ElementPositionPropertiesComponent { constructor(private unitService: UnitService, public selectionService: SelectionService) { } alignElements(direction: 'left' | 'right' | 'top' | 'bottom'): void { - this.unitService.alignElements(this.selectionService.getSelectedElements() as PositionedElement[], direction); + this.unitService.alignElements(this.selectionService.getSelectedElements() as PositionedUIElement[], direction); } } 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 c149d4a2d65402c5fc2fff4a66434dd1e57148a7..5cd730058dd88d4a1987d7434866488dd70e7a30 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 @@ -5,9 +5,8 @@ import { UnitService } from '../../services/unit.service'; import { DialogService } from '../../services/dialog.service'; import { SelectionService } from '../../services/selection.service'; import { MessageService } from 'common/services/message.service'; -import { Page } from 'common/interfaces/unit'; import { ArrayUtils } from 'common/util/array'; -import { UnitFactory } from 'common/util/unit.factory'; +import { Page } from 'common/classes/unit'; @Component({ selector: 'aspect-unit-view', @@ -31,7 +30,7 @@ export class UnitViewComponent implements OnDestroy { } addPage(): void { - this.unitService.unit.pages.push(UnitFactory.createPage()); + this.unitService.unit.pages.push(new Page()); this.selectedPageIndex = this.unitService.unit.pages.length - 1; this.selectionService.selectedPageIndex = this.selectedPageIndex; diff --git a/projects/editor/src/app/services/dialog.service.ts b/projects/editor/src/app/services/dialog.service.ts index a1e9e961dd71bb796b632b30681a881c4bfa984a..99842aa646d872a64527cf206c47381bff7bff6b 100644 --- a/projects/editor/src/app/services/dialog.service.ts +++ b/projects/editor/src/app/services/dialog.service.ts @@ -12,12 +12,12 @@ import { DropListOptionEditDialogComponent } from '../components/dialogs/drop-li import { TextImageLabel, DragNDropValueObject, - LikertRowElement, PlayerProperties } from 'common/interfaces/elements'; import { ClozeDocument } from 'common/interfaces/cloze'; import { RichTextEditorSimpleComponent } from '../text-editor-simple/rich-text-editor-simple.component'; import { RichTextSimpleEditDialogComponent } from '../components/dialogs/rich-text-simple-edit-dialog.component'; +import { LikertRowElement } from 'common/classes/element'; @Injectable({ providedIn: 'root' diff --git a/projects/editor/src/app/services/selection.service.ts b/projects/editor/src/app/services/selection.service.ts index f12ba487bb5075496dde10c9f1cb96f2f7323e3e..492a8889c7e74f7afcfbffddd456ccede7485ea9 100644 --- a/projects/editor/src/app/services/selection.service.ts +++ b/projects/editor/src/app/services/selection.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; -import { UIElement } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Injectable({ providedIn: 'root' diff --git a/projects/editor/src/app/services/unit.service.ts b/projects/editor/src/app/services/unit.service.ts index 9cbbac221fc750ba2c41b070a60f399cc0bee6f0..11e083459dea3bca6597ed4a5e99cbb1a06111af 100644 --- a/projects/editor/src/app/services/unit.service.ts +++ b/projects/editor/src/app/services/unit.service.ts @@ -11,20 +11,26 @@ import { SelectionService } from './selection.service'; import { ElementFactory } from 'common/util/element.factory'; import { ClozeParser } from '../util/cloze-parser'; import { Copy } from 'common/util/copy'; -import { UnitFactory } from 'common/util/unit.factory'; -import { Page, Section, Unit } from 'common/interfaces/unit'; -import { - ClozeElement, TextImageLabel, DragNDropValueObject, - DropListElement, InputElement, InputElementValue, LikertElement, - LikertRowElement, PlayerElement, PlayerProperties, - PositionedElement, TextElement, - UIElement, UIElementType -} from 'common/interfaces/elements'; import { ClozeDocument } from 'common/interfaces/cloze'; import { UnitUtils } from 'common/util/unit-utils'; import { ArrayUtils } from 'common/util/array'; import { ClozeUtils } from 'common/util/cloze'; import { SanitizationService } from 'common/services/sanitization.service'; +import { Page, Section, Unit } from 'common/classes/unit'; +import { + ClozeElement, DropListElement, InputElement, + InputElementValue, + LikertElement, + LikertRowElement, PositionedUIElement, + TextElement, + UIElement +} from 'common/classes/element'; +import { + DragNDropValueObject, PlayerElement, + PlayerProperties, + TextImageLabel, + UIElementType +} from 'common/interfaces/elements'; @Injectable({ providedIn: 'root' @@ -42,17 +48,18 @@ export class UnitService { private sanitizationService: SanitizationService, private sanitizer: DomSanitizer, private translateService: TranslateService) { - this.unit = UnitFactory.createUnit({} as Unit); + this.unit = new Unit(); } loadUnitDefinition(unitDefinition: string): void { this.idService.reset(); const unitDef = JSON.parse(unitDefinition); if (SanitizationService.isUnitDefinitionOutdated(unitDef)) { - this.unit = UnitFactory.createUnit(this.sanitizationService.sanitizeUnitDefinition(unitDef)); + // this.unit = UnitFactory.createUnit(this.sanitizationService.sanitizeUnitDefinition(unitDef)); + this.unit = new Unit(this.sanitizationService.sanitizeUnitDefinition(unitDef)); this.messageService.showMessage(this.translateService.instant('outdatedUnit')); } else { - this.unit = UnitFactory.createUnit(unitDef); + this.unit = new Unit(unitDef); } this.readIDs(this.unit); } @@ -75,7 +82,7 @@ export class UnitService { } addSection(page: Page): void { - page.sections.push(UnitFactory.createSection()); + page.sections.push(new Section()); this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit); } @@ -88,10 +95,10 @@ export class UnitService { } duplicateSection(section: Section, page: Page, sectionIndex: number): void { - const newSection: Section = { + const newSection: Section = new Section({ ...section, - elements: section.elements.map(element => this.duplicateElement(element) as PositionedElement) - }; + elements: section.elements.map(element => this.duplicateElement(element) as PositionedUIElement) + }); page.sections.splice(sectionIndex + 1, 0, newSection); this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit); } @@ -115,7 +122,7 @@ export class UnitService { async addElementToSection(elementType: UIElementType, section: Section, coordinates?: { x: number, y: number }): Promise<void> { - let newElement: PositionedElement; + let newElement: PositionedUIElement; if (['audio', 'video', 'image'].includes(elementType)) { let mediaSrc = ''; switch (elementType) { @@ -137,7 +144,7 @@ export class UnitService { position: { dynamicPositioning: section.dynamicPositioning } - } as unknown as UIElement) as PositionedElement; + } as unknown as UIElement) as PositionedUIElement; } else { newElement = ElementFactory.createElement({ type: elementType, @@ -145,7 +152,7 @@ export class UnitService { position: { dynamicPositioning: section.dynamicPositioning } - } as unknown as UIElement) as PositionedElement; + } as unknown as UIElement) as PositionedUIElement; } if (coordinates && section.dynamicPositioning) { newElement.position.gridColumn = coordinates.x; @@ -183,8 +190,8 @@ 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 as PositionedElement); - (element as PositionedElement).position.dynamicPositioning = newSection.dynamicPositioning; + newSection.elements.push(element as PositionedUIElement); + (element as PositionedUIElement).position.dynamicPositioning = newSection.dynamicPositioning; }); this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit); } @@ -192,7 +199,7 @@ export class UnitService { duplicateElementsInSection(elements: UIElement[], pageIndex: number, sectionIndex: number): void { const section = this.unit.pages[pageIndex].sections[sectionIndex]; elements.forEach((element: UIElement) => { - section.elements.push(this.duplicateElement(element) as PositionedElement); + section.elements.push(this.duplicateElement(element) as PositionedUIElement); }); this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit); } @@ -233,11 +240,12 @@ export class UnitService { updateSectionProperty(section: Section, property: string, value: string | number | boolean): void { if (property === 'dynamicPositioning') { section.dynamicPositioning = value as boolean; - section.elements.forEach((element: PositionedElement) => { - element.position.dynamicPositioning = value as boolean; + section.elements.forEach((element: UIElement) => { + (element as PositionedUIElement).position.dynamicPositioning = value as boolean; }); } else { - section[property] = value; + // section[property] = value; + section.setProperty(property, value); } this.elementPropertyUpdated.next(); this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit); @@ -289,7 +297,7 @@ export class UnitService { } createLikertRowElement(rowLabelText: string, columnCount: number): LikertRowElement { - return ElementFactory.createLikertRowElement({ + return new LikertRowElement({ id: this.idService.getNewID('likert_row'), rowLabel: { text: rowLabelText, @@ -297,10 +305,10 @@ export class UnitService { position: 'above' }, columnCount: columnCount - }); + } as Partial<LikertRowElement>); } - alignElements(elements: PositionedElement[], alignmentDirection: 'left' | 'right' | 'top' | 'bottom'): void { + alignElements(elements: PositionedUIElement[], alignmentDirection: 'left' | 'right' | 'top' | 'bottom'): void { switch (alignmentDirection) { case 'left': this.updateElementProperty( diff --git a/projects/editor/src/app/services/verona-api.service.ts b/projects/editor/src/app/services/verona-api.service.ts index 464b29f915417a470c57e2525ca12ae052bb757a..459028bc603b2026769536aff768d329b0f920d6 100644 --- a/projects/editor/src/app/services/verona-api.service.ts +++ b/projects/editor/src/app/services/verona-api.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { fromEvent, Observable, Subject } from 'rxjs'; import packageJSON from '../../../../../package.json'; -import { Unit } from 'common/interfaces/unit'; +import { Unit } from 'common/classes/unit'; @Injectable({ providedIn: 'root' diff --git a/projects/editor/src/app/util/cloze-parser.ts b/projects/editor/src/app/util/cloze-parser.ts index 7ac203b9e6608f9adca8605e93869cbf7607a218..9187435995352216b25246ddd5437209db1de45d 100644 --- a/projects/editor/src/app/util/cloze-parser.ts +++ b/projects/editor/src/app/util/cloze-parser.ts @@ -1,7 +1,7 @@ import { IDService } from 'common/services/id.service'; import { ElementFactory } from 'common/util/element.factory'; import { ClozeDocument } from 'common/interfaces/cloze'; -import { InputElement, UIElement } from 'common/interfaces/elements'; +import { InputElement, UIElement } from 'common/classes/element'; export abstract class ClozeParser { static setMissingIDs(clozeJSON: ClozeDocument, idService: IDService): ClozeDocument { diff --git a/projects/player/modules/unit-definition-menu/components/unit-definition-menu/unit-definition-menu.component.ts b/projects/player/modules/unit-definition-menu/components/unit-definition-menu/unit-definition-menu.component.ts index f9b86e5087ee4b114d74c8e307d541d50701cda8..6f8a82a41434d0cbcec2fca7b0ebbae37665e9d6 100644 --- a/projects/player/modules/unit-definition-menu/components/unit-definition-menu/unit-definition-menu.component.ts +++ b/projects/player/modules/unit-definition-menu/components/unit-definition-menu/unit-definition-menu.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { FileService } from 'common/services/file.service'; -import { Page } from 'common/interfaces/unit'; import { ElementCode, PagingMode, UnitState, VopPageNavigationCommand, VopStartCommand } from 'verona/models/verona'; +import { Page } from 'common/classes/unit'; @Component({ selector: 'aspect-unit-definition-menu', diff --git a/projects/player/src/app/app.component.ts b/projects/player/src/app/app.component.ts index 871141b9ed47c3cd646fe8f738e4691ac166b965..7e17837359291dc6bdae522f1d8a05e8efa6be43 100644 --- a/projects/player/src/app/app.component.ts +++ b/projects/player/src/app/app.component.ts @@ -10,13 +10,13 @@ import { NativeEventService } from './services/native-event.service'; import { MetaDataService } from './services/meta-data.service'; import { UnitStateService } from './services/unit-state.service'; import { MediaPlayerService } from './services/media-player.service'; -import { Page, Unit } from 'common/interfaces/unit'; import { ValidationService } from './services/validation.service'; -import { UnitFactory } from 'common/util/unit.factory'; import { SanitizationService } from 'common/services/sanitization.service'; import { UnitUtils } from 'common/util/unit-utils'; -import { DragNDropValueObject, UIElement } from 'common/interfaces/elements'; import { LogService } from 'logging/services/log.service'; +import { Page, Unit } from 'common/classes/unit'; +import { DragNDropValueObject } from 'common/interfaces/elements'; +import { UIElement } from 'common/classes/element'; @Component({ selector: 'aspect-player', @@ -70,7 +70,7 @@ export class AppComponent implements OnInit { setTimeout(() => { LogService.info('player: onStart', message); if (message.unitDefinition) { - const unitDefinition: Unit = UnitFactory.createUnit( + const unitDefinition: Unit = new Unit( this.sanitizationService.sanitizeUnitDefinition(JSON.parse(message.unitDefinition)) ); this.configureSession(message, unitDefinition); diff --git a/projects/player/src/app/components/element-compound-group/element-compound-group.component.ts b/projects/player/src/app/components/element-compound-group/element-compound-group.component.ts index 4e05a92f1b019581ddbdcb5088ac9a38d47d61d2..1c310adb6bec51fb417579aa3245a01b96fbf628 100644 --- a/projects/player/src/app/components/element-compound-group/element-compound-group.component.ts +++ b/projects/player/src/app/components/element-compound-group/element-compound-group.component.ts @@ -1,9 +1,6 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { - ClozeElement, InputElement, LikertElement -} from 'common/interfaces/elements'; import { ClozeUtils } from 'common/util/cloze'; import { UnitStateService } from '../../services/unit-state.service'; import { ElementComponent } from 'common/directives/element-component.directive'; @@ -16,6 +13,7 @@ import { ElementFormGroupDirective } from '../../directives/element-form-group.d import { KeyboardService } from '../../services/keyboard.service'; import { DeviceService } from '../../services/device.service'; import { TextFieldSimpleComponent } from 'common/components/ui-elements/text-field-simple.component'; +import { ClozeElement, InputElement, LikertElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-compound-group', diff --git a/projects/player/src/app/components/element-group-selection/element-group-selection.component.ts b/projects/player/src/app/components/element-group-selection/element-group-selection.component.ts index 78b9f47fb8a858de1f0802faee402092c87aa5d3..bacdc4e7dab26f803b6d75c13c4091810fd35640 100644 --- a/projects/player/src/app/components/element-group-selection/element-group-selection.component.ts +++ b/projects/player/src/app/components/element-group-selection/element-group-selection.component.ts @@ -1,8 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; -import { - UIElement, UIElementType -} from 'common/interfaces/elements'; import { ElementGroup, ElementGroupName } from '../../models/element-group'; +import { UIElement } from 'common/classes/element'; +import { UIElementType } from 'common/interfaces/elements'; @Component({ selector: 'aspect-element-group-selection', diff --git a/projects/player/src/app/components/element-input-group/element-input-group.component.ts b/projects/player/src/app/components/element-input-group/element-input-group.component.ts index 9b1e2b96f47e59c4c1b0260bda7e96ce573d1b1d..c6b2de76ab94ef6d45972b5d867c0c911e6b8e7b 100644 --- a/projects/player/src/app/components/element-input-group/element-input-group.component.ts +++ b/projects/player/src/app/components/element-input-group/element-input-group.component.ts @@ -2,10 +2,6 @@ import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { - CheckboxElement, DropListElement, InputElement, SliderElement, - RadioButtonGroupElement, RadioButtonGroupComplexElement, DropdownElement -} from 'common/interfaces/elements'; import { UnitStateService } from '../../services/unit-state.service'; import { ElementModelElementCodeMappingService } from '../../services/element-model-element-code-mapping.service'; import { ElementFormGroupDirective } from '../../directives/element-form-group.directive'; @@ -13,6 +9,15 @@ import { MessageService } from 'common/services/message.service'; import { VeronaSubscriptionService } from 'verona/services/verona-subscription.service'; import { ElementComponent } from 'common/directives/element-component.directive'; import { ValidationService } from '../../services/validation.service'; +import { + CheckboxElement, + DropdownElement, + DropListElement, + InputElement, + RadioButtonGroupComplexElement, + RadioButtonGroupElement, + SliderElement +} from 'common/classes/element'; @Component({ selector: 'aspect-element-input-group', diff --git a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts index 85a558bc2665073113457a4943392a22900571f4..7c4758bdbc1f8cf78f73871daf591054db581d4c 100644 --- a/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts +++ b/projects/player/src/app/components/element-interactive-group/element-interactive-group.component.ts @@ -1,15 +1,13 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core'; -import { - ButtonElement, FrameElement, ImageElement, InputElementValue -} from 'common/interfaces/elements'; import { VeronaPostService } from 'verona/services/verona-post.service'; import { UnitStateService } from '../../services/unit-state.service'; import { ElementGroupDirective } from '../../directives/element-group.directive'; import { ElementComponent } from 'common/directives/element-component.directive'; import { NavigationService } from '../../services/navigation.service'; import { ElementModelElementCodeMappingService } from '../../services/element-model-element-code-mapping.service'; +import { ButtonElement, FrameElement, ImageElement, InputElementValue } from 'common/classes/element'; @Component({ selector: 'aspect-element-interactive-group', diff --git a/projects/player/src/app/components/element-media-player-group/element-media-player-group.component.ts b/projects/player/src/app/components/element-media-player-group/element-media-player-group.component.ts index 199aa9f6eda91562033119cc9385cbc2303d62c7..cddc0a2c4858ed9b6708ec32713c66a507dd1fdd 100644 --- a/projects/player/src/app/components/element-media-player-group/element-media-player-group.component.ts +++ b/projects/player/src/app/components/element-media-player-group/element-media-player-group.component.ts @@ -1,14 +1,12 @@ import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core'; -import { - AudioElement, VideoElement, UIElement -} from 'common/interfaces/elements'; import { MediaPlayerService } from '../../services/media-player.service'; import { UnitStateService } from '../../services/unit-state.service'; import { MediaPlayerElementComponent } from 'common/directives/media-player-element-component.directive'; import { ElementGroupDirective } from '../../directives/element-group.directive'; import { ElementModelElementCodeMappingService } from '../../services/element-model-element-code-mapping.service'; +import { AudioElement, UIElement, VideoElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-media-player-group', diff --git a/projects/player/src/app/components/element-text-group/element-text-group.component.ts b/projects/player/src/app/components/element-text-group/element-text-group.component.ts index e5185c4d3eba544d304c8ce96e5c73c02f276d1f..6fb9a9a980a3b0d37696a5391556c591b8c99a70 100644 --- a/projects/player/src/app/components/element-text-group/element-text-group.component.ts +++ b/projects/player/src/app/components/element-text-group/element-text-group.component.ts @@ -3,7 +3,6 @@ import { } from '@angular/core'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; -import { TextElement } from 'common/interfaces/elements'; import { TextComponent } from 'common/components/ui-elements/text.component'; import { TextMarkingService } from '../../services/text-marking.service'; import { NativeEventService } from '../../services/native-event.service'; @@ -11,6 +10,7 @@ import { UnitStateService } from '../../services/unit-state.service'; import { ElementGroupDirective } from '../../directives/element-group.directive'; import { ElementModelElementCodeMappingService } from '../../services/element-model-element-code-mapping.service'; import { ElementComponent } from 'common/directives/element-component.directive'; +import { TextElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-text-group', diff --git a/projects/player/src/app/components/element-text-input-group/element-text-input-group.component.ts b/projects/player/src/app/components/element-text-input-group/element-text-input-group.component.ts index ba73589b456a4c6dce862970215e3849123b7fdd..42193a3939b063a3edeb8557348c3051028118a8 100644 --- a/projects/player/src/app/components/element-text-input-group/element-text-input-group.component.ts +++ b/projects/player/src/app/components/element-text-input-group/element-text-input-group.component.ts @@ -3,9 +3,6 @@ import { } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { KeypadService } from '../../services/keypad.service'; -import { - InputElement, TextAreaElement, TextFieldElement, SpellCorrectElement -} from 'common/interfaces/elements'; import { UnitStateService } from '../../services/unit-state.service'; import { ElementModelElementCodeMappingService } from '../../services/element-model-element-code-mapping.service'; import { MessageService } from 'common/services/message.service'; @@ -18,6 +15,7 @@ import { TextFieldComponent } from 'common/components/ui-elements/text-field.com import { KeyboardService } from '../../services/keyboard.service'; import { SpellCorrectComponent } from 'common/components/ui-elements/spell-correct.component'; import { DeviceService } from '../../services/device.service'; +import { InputElement, SpellCorrectElement, TextAreaElement, TextFieldElement } from 'common/classes/element'; @Component({ selector: 'aspect-element-text-input-group', diff --git a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts index 6a293e8b6b0ee09b2cc6ac62686a6fcb277b98c2..e84b541031399742e0855c55693139f90d1c82ad 100644 --- a/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts +++ b/projects/player/src/app/components/floating-marking-bar/floating-marking-bar.component.ts @@ -4,7 +4,7 @@ import { import { ConnectedPosition } from '@angular/cdk/overlay'; import { ElementComponent } from 'common/directives/element-component.directive'; import { TextComponent } from 'common/components/ui-elements/text.component'; -import { TextElement } from 'common/interfaces/elements'; +import { TextElement } from 'common/classes/element'; @Component({ selector: 'aspect-floating-marking-bar', diff --git a/projects/player/src/app/components/layout-pages/layout-pages.component.ts b/projects/player/src/app/components/layout-pages/layout-pages.component.ts index e92c01745623fa5fecdda639a59a1c0ccf0e2719..011de4bd2518102a6154bccc7af164477e6fc6f3 100644 --- a/projects/player/src/app/components/layout-pages/layout-pages.component.ts +++ b/projects/player/src/app/components/layout-pages/layout-pages.component.ts @@ -4,7 +4,7 @@ import { import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { NativeEventService } from '../../services/native-event.service'; -import { Page } from 'common/interfaces/unit'; +import { Page } from 'common/classes/unit'; @Component({ selector: '[aspect-layout-pages]', diff --git a/projects/player/src/app/components/page/page.component.ts b/projects/player/src/app/components/page/page.component.ts index f08a67b59240430f1be8f885be5339bdf9d548e4..f576d5cd056a31cbe15579d752d0c907873eb93f 100644 --- a/projects/player/src/app/components/page/page.component.ts +++ b/projects/player/src/app/components/page/page.component.ts @@ -1,8 +1,8 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { Page } from 'common/interfaces/unit'; import { MediaPlayerService } from '../../services/media-player.service'; +import { Page } from 'common/classes/unit'; @Component({ selector: 'aspect-page', diff --git a/projects/player/src/app/components/player-state/player-state.component.ts b/projects/player/src/app/components/player-state/player-state.component.ts index 3399f5407e1767ba250982cc74c2b1a6464b334a..7e8b75204e48ad2b610910f1d204a98a5fb7447b 100644 --- a/projects/player/src/app/components/player-state/player-state.component.ts +++ b/projects/player/src/app/components/player-state/player-state.component.ts @@ -9,9 +9,9 @@ import { VopContinueCommand, VopGetStateRequest, VopPageNavigationCommand, VopStopCommand } from 'verona/models/verona'; import { VeronaPostService } from 'verona/services/verona-post.service'; -import { Page } from 'common/interfaces/unit'; import { NavigationService } from '../../services/navigation.service'; import { LogService } from 'logging/services/log.service'; +import { Page } from 'common/classes/unit'; @Component({ selector: 'aspect-player-state', diff --git a/projects/player/src/app/components/section-container/section-container.component.ts b/projects/player/src/app/components/section-container/section-container.component.ts index aa1e75438924cf2978e75bcb9768371792ee3141..f4711a5d3c916331d5ff51a6a1b806f53501ecd2 100644 --- a/projects/player/src/app/components/section-container/section-container.component.ts +++ b/projects/player/src/app/components/section-container/section-container.component.ts @@ -3,7 +3,7 @@ import { } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { Section } from 'common/interfaces/unit'; +import { Section } from 'common/classes/unit'; @Component({ selector: 'aspect-section-container', diff --git a/projects/player/src/app/components/section/section.component.ts b/projects/player/src/app/components/section/section.component.ts index eec618408c2f8facb322f0f0d8665b374a9c4bd8..8f0c93ef5c7868043eda65fdc46de2f13969b61e 100644 --- a/projects/player/src/app/components/section/section.component.ts +++ b/projects/player/src/app/components/section/section.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { Section } from 'common/interfaces/unit'; +import { Section } from 'common/classes/unit'; @Component({ selector: 'aspect-section', diff --git a/projects/player/src/app/directives/element-form-group.directive.ts b/projects/player/src/app/directives/element-form-group.directive.ts index edc7ff6c7baddeceec4d74c2dff851053329c162..342c185923f86b3a20a21b622d0df1bd9ea1aa9d 100644 --- a/projects/player/src/app/directives/element-form-group.directive.ts +++ b/projects/player/src/app/directives/element-form-group.directive.ts @@ -5,7 +5,6 @@ import { import { takeUntil } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { InputElement, InputElementValue, SliderElement } from 'common/interfaces/elements'; import { UnitStateService } from '../services/unit-state.service'; import { ElementModelElementCodeMappingService } from '../services/element-model-element-code-mapping.service'; import { ElementGroupDirective } from './element-group.directive'; @@ -14,6 +13,7 @@ import { MessageService } from 'common/services/message.service'; import { VeronaSubscriptionService } from 'verona/services/verona-subscription.service'; import { ValidationService } from '../services/validation.service'; import { LogService } from 'logging/services/log.service'; +import { InputElement, InputElementValue, SliderElement } from 'common/classes/element'; @Directive() export abstract class ElementFormGroupDirective extends ElementGroupDirective implements OnDestroy { diff --git a/projects/player/src/app/directives/element-group.directive.ts b/projects/player/src/app/directives/element-group.directive.ts index ab7d1c0ff329649cedd147d0a7901251139cff23..64bec93367db963b4752d82e1b9511c68d9cec23 100644 --- a/projects/player/src/app/directives/element-group.directive.ts +++ b/projects/player/src/app/directives/element-group.directive.ts @@ -1,7 +1,7 @@ import { Directive, Input } from '@angular/core'; -import { InputElementValue, UIElement } from 'common/interfaces/elements'; import { UnitStateService } from '../services/unit-state.service'; import { ElementComponent } from 'common/directives/element-component.directive'; +import { InputElementValue, UIElement } from 'common/classes/element'; @Directive() export abstract class ElementGroupDirective { diff --git a/projects/player/src/app/pipes/always-visible-page.pipe.ts b/projects/player/src/app/pipes/always-visible-page.pipe.ts index 0cd597752c1638940f7dc0da015515d548ada755..fc75e4b0bd9a52f0a46dffd58d9f0954401be23f 100644 --- a/projects/player/src/app/pipes/always-visible-page.pipe.ts +++ b/projects/player/src/app/pipes/always-visible-page.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { Page } from 'common/interfaces/unit'; +import { Page } from 'common/classes/unit'; @Pipe({ name: 'alwaysVisiblePage' diff --git a/projects/player/src/app/pipes/page-index.pipe.ts b/projects/player/src/app/pipes/page-index.pipe.ts index cae1cad319d52cb760665abf113b531367847fd0..907671c19be8a87a7a8a899096ef42b9ec2bd068 100644 --- a/projects/player/src/app/pipes/page-index.pipe.ts +++ b/projects/player/src/app/pipes/page-index.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { Page } from 'common/interfaces/unit'; +import { Page } from 'common/classes/unit'; @Pipe({ name: 'pageIndex' diff --git a/projects/player/src/app/pipes/scroll-pages.pipe.ts b/projects/player/src/app/pipes/scroll-pages.pipe.ts index 0cbf3bbdb1762883480752604721fe7aaf346766..128a363cc91cb2ca44d677f899b413be01fe248a 100644 --- a/projects/player/src/app/pipes/scroll-pages.pipe.ts +++ b/projects/player/src/app/pipes/scroll-pages.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { Page } from 'common/interfaces/unit'; +import { Page } from 'common/classes/unit'; @Pipe({ name: 'scrollPages' diff --git a/projects/player/src/app/pipes/valid-pages.pipe.ts b/projects/player/src/app/pipes/valid-pages.pipe.ts index 002cf10ce7f58349463ade257efc0915ba88cadc..b0bea0431adbbcfdb7fdac78b1af7970f33f4ba2 100644 --- a/projects/player/src/app/pipes/valid-pages.pipe.ts +++ b/projects/player/src/app/pipes/valid-pages.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { Page } from 'common/interfaces/unit'; +import { Page } from 'common/classes/unit'; @Pipe({ name: 'validPages' diff --git a/projects/player/src/app/services/element-model-element-code-mapping.service.ts b/projects/player/src/app/services/element-model-element-code-mapping.service.ts index dfca85f158520092ba3e2a274b99385c3880dac3..705fe190eae170693ec400d2166af4cd56e38f7a 100644 --- a/projects/player/src/app/services/element-model-element-code-mapping.service.ts +++ b/projects/player/src/app/services/element-model-element-code-mapping.service.ts @@ -1,9 +1,14 @@ import { Injectable } from '@angular/core'; import { TextMarkingService } from './text-marking.service'; +import { DragNDropValueObject, UIElementType } from 'common/interfaces/elements'; import { - AudioElement, DragNDropValueObject, ImageElement, InputElement, InputElementValue, - TextElement, UIElement, UIElementType, VideoElement -} from 'common/interfaces/elements'; + AudioElement, + ImageElement, + InputElement, + InputElementValue, + TextElement, UIElement, + VideoElement +} from 'common/classes/element'; @Injectable({ providedIn: 'root'