Code owners
Assign users and groups as approvers for specific file changes. Learn more.
element.ts 6.14 KiB
// eslint-disable-next-line max-classes-per-file
import { ElementComponent } from 'common/directives/element-component.directive';
import { Type } from '@angular/core';
import { ClozeDocument } from 'common/models/elements/compound-elements/cloze/cloze';
import { ElementFactory } from 'common/util/element.factory';
import { IDManager } from 'common/util/id-manager';
import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
export type UIElementType = 'text' | 'button' | 'text-field' | 'text-field-simple' | 'text-area' | 'checkbox'
| 'dropdown' | 'radio' | 'image' | 'audio' | 'video' | 'likert' | 'likert-row' | 'radio-group-images'
| 'drop-list' | 'drop-list-simple' | 'cloze' | 'spell-correct' | 'slider' | 'frame' | 'toggle-button';
export type UIElementValue = string | number | boolean | undefined | UIElementType | InputElementValue |
TextLabel | TextLabel[] | ClozeDocument | LikertRowElement[] |
PositionProperties | PlayerProperties | BasicStyles;
export type InputAssistancePreset = null | 'french' | 'numbers' | 'numbersAndOperators' | 'numbersAndBasicOperators'
| 'comparisonOperators' | 'squareDashDot' | 'placeValue';
export abstract class UIElement {
[index: string]: unknown;
id: string = 'id_placeholder';
type: UIElementType;
width: number = 180;
height: number = 60;
position?: PositionProperties;
styling?: BasicStyles & ExtendedStyles;
player?: PlayerProperties;
constructor(element: Partial<UIElement>, ...args: unknown[]) {
if (!element.type) throw Error('Element has no type!');
this.type = element.type;
// IDManager is an optional parameter. When given, check/repair and register the ID.
if (args[0]) {
const idManager: IDManager = args[0] as IDManager;
if (!element.id) {
this.id = idManager.getNewID(element.type as string);
} else if (!IDManager.getInstance().isIdAvailable(element.id)) {
this.id = idManager.getNewID(element.type as string);
} else {
this.id = element.id;
}
idManager.addID(this.id);
} else if (element.id) {
this.id = element.id;
} else {
throw Error('No ID for element!');
}
if (element.width !== undefined) this.width = element.width;
if (element.height !== undefined) this.height = element.height;
}
setProperty(property: string, value: UIElementValue): void {
this[property] = value;
}
setStyleProperty(property: string, value: UIElementValue): void {
(this.styling as BasicStyles & ExtendedStyles)[property] = value;
}
setPositionProperty(property: string, value: UIElementValue): void {
(this.position as PositionProperties)[property] = value;
}
setPlayerProperty(property: string, value: UIElementValue): void {
(this.player as PlayerProperties)[property] = value;
}
abstract getComponentFactory(): Type<ElementComponent>;
}
export type InputElementValue = string[] | string | number | boolean | TextLabel[] | null;
export abstract class InputElement extends UIElement {
label: string = 'Beschriftung';
value: InputElementValue = null;
required: boolean = false;
requiredWarnMessage: string = 'Eingabe erforderlich';
readOnly: boolean = false;
protected constructor(element: Partial<InputElement>, ...args: unknown[]) {
super(element, ...args);
if (element.label !== undefined) this.label = element.label;
if (element.value !== undefined) this.value = element.value;
if (element.required) this.required = element.required;
if (element.requiredWarnMessage !== undefined) this.requiredWarnMessage = element.requiredWarnMessage;
if (element.readOnly) this.readOnly = element.readOnly;
}
}
export abstract class CompoundElement extends UIElement {
abstract getChildElements(): UIElement[];
}
export abstract class PlayerElement extends UIElement {
player: PlayerProperties;
protected constructor(element: Partial<PlayerElement>, ...args: unknown[]) {
super(element, ...args);
this.player = ElementFactory.initPlayerProps(element.player);
}
}
export interface PositionedUIElement extends UIElement {
position: PositionProperties;
}
export interface PositionProperties {
[index: string]: unknown;
fixedSize: boolean;
dynamicPositioning: boolean;
xPosition: number;
yPosition: number;
useMinHeight: boolean;
gridColumn: number | null;
gridColumnRange: number;
gridRow: number | null;
gridRowRange: number;
marginLeft: number;
marginRight: number;
marginTop: number;
marginBottom: number;
zIndex: number;
}
export interface BasicStyles {
[index: string]: unknown;
fontColor: string;
font: string;
fontSize: number;
bold: boolean;
italic: boolean;
underline: boolean;
backgroundColor: string;
}
export interface ExtendedStyles {
[index: string]: unknown;
lineHeight?: number;
borderRadius?: number;
itemBackgroundColor?: string;
borderWidth?: number;
borderColor?: string;
borderStyle?: 'solid' | 'dotted' | 'dashed' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
lineColoring?: boolean;
lineColoringColor?: string;
selectionColor?: string;
}
export interface PlayerElement {
player: PlayerProperties;
}
export interface PlayerProperties {
[index: string]: unknown;
autostart: boolean;
autostartDelay: number;
loop: boolean;
startControl: boolean;
pauseControl: boolean;
progressBar: boolean;
interactiveProgressbar: boolean;
volumeControl: boolean;
defaultVolume: number;
minVolume: number;
muteControl: boolean;
interactiveMuteControl: boolean;
hintLabel: string;
hintLabelDelay: number;
activeAfterID: string;
minRuns: number;
maxRuns: number | null;
showRestRuns: boolean;
showRestTime: boolean;
playbackTime: number;
}
export interface ValueChangeElement {
id: string;
value: InputElementValue;
}
export interface OptionElement extends UIElement {
getNewOption(optionText: string): Label;
}
export interface TextLabel {
text: string;
}
export interface TextImageLabel extends TextLabel {
imgSrc: string | null;
imgPosition: 'above' | 'below' | 'left' | 'right';
}
export interface DragNDropValueObject extends TextImageLabel {
id: string;
}
export type Label = TextLabel | TextImageLabel | DragNDropValueObject;