Skip to content
Snippets Groups Projects
cloze.component.ts 6.3 KiB
Newer Older
rhenck's avatar
rhenck committed
  Component, EventEmitter, Input, Output, QueryList, ViewChildren
} from '@angular/core';
rhenck's avatar
rhenck committed
import { ClozeElement } from './cloze-element';
import { CompoundElementComponent } from '../../directives/compound-element.directive';
rhenck's avatar
rhenck committed
import { ClozeDocumentParagraph, ClozeDocumentPart, InputElement } from '../../models/uI-element';
import { FormElementComponent } from '../../directives/form-element-component.directive';
rhenck's avatar
rhenck committed

@Component({
  selector: 'app-cloze',
  template: `
rhenck's avatar
rhenck committed
    <ng-container *ngIf="elementModel.document.content.length == 0">
      Kein Dokument vorhanden
    </ng-container>
    <div [class.center-content]="elementModel.positionProps.dynamicPositioning &&
                                 elementModel.positionProps.fixedSize"
         [style.width]="elementModel.positionProps.fixedSize ? elementModel.width + 'px' : '100%'"
         [style.height]="elementModel.positionProps.fixedSize ? elementModel.height + 'px' : 'auto'">
rhenck's avatar
rhenck committed
      <ng-container *ngFor="let part of elementModel.document.content">
        <p *ngIf="part.type === 'paragraph'"
           [style.line-height.%]="elementModel.fontProps.lineHeight"
           [style.color]="elementModel.fontProps.fontColor"
           [style.font-family]="elementModel.fontProps.font"
           [style.font-size.px]="elementModel.fontProps.fontSize"
           [style.font-weight]="elementModel.fontProps.bold ? 'bold' : ''"
           [style.font-style]="elementModel.fontProps.italic ? 'italic' : ''"
           [style.text-decoration]="elementModel.fontProps.underline ? 'underline' : ''">
          <ng-container *ngFor="let subPart of part.content">
            <ng-container *ngIf="subPart.type === 'text'">
              <span [style.font-weight]="$any((subPart.marks | mark)?.includes('bold')) ? 'bold' : ''"
                    [style.font-style]="$any((subPart.marks | mark)?.includes('italic')) ? 'italic' : ''"
                    [style.text-decoration]="$any((subPart.marks | mark)?.includes('underline')) ? 'underline' : ''">
                {{subPart.text}}
              </span>
            </ng-container>
            <span *ngIf="['ToggleButton', 'DropList', 'TextField'].includes(subPart.type)"
                  (click)="selectElement($any(subPart.attrs).model, $event)">
                <app-toggle-button *ngIf="subPart.type === 'ToggleButton'" #radioComponent
                                   [parentForm]="parentForm"
                                   [style.display]="'inline-block'"
                                   [style.vertical-align]="'middle'"
                                   [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
                                   [elementModel]="$any(subPart.attrs).model"
                                   (elementValueChanged)="elementValueChanged.emit($event)">
                </app-toggle-button>
                <app-text-field-simple *ngIf="subPart.type === 'TextField'" #textfieldComponent
                                       [parentForm]="parentForm"
                                       [style.display]="'inline-block'"
                                       [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
                                       [elementModel]="$any(subPart.attrs).model"
                                       (elementValueChanged)="elementValueChanged.emit($event)">
                </app-text-field-simple>
                <app-drop-list-simple *ngIf="subPart.type === 'DropList'" #droplistComponent
                                      [parentForm]="parentForm"
                                      [style.display]="'inline-block'"
                                      [style.vertical-align]="'middle'"
                                      [style.pointerEvents]="allowClickThrough ? 'auto' : 'none'"
                                      [elementModel]="$any(subPart.attrs).model"
                                      (elementValueChanged)="elementValueChanged.emit($event)">
                </app-drop-list-simple>
            </span>
          </ng-container>
        </p>
        <h1 *ngIf="part.type === 'heading' && part.attrs.level === 1"
            [style.display]="'inline'">
          {{part.content[0].text}}
        </h1>
        <h2 *ngIf="part.type === 'heading' && part.attrs.level === 2"
            [style.display]="'inline'">
          {{part.content[0].text}}
        </h2>
        <h3 *ngIf="part.type === 'heading' && part.attrs.level === 3"
            [style.display]="'inline'">
          {{part.content[0].text}}
        </h3>
        <h4 *ngIf="part.type === 'heading' && part.attrs.level === 4"
            [style.display]="'inline'">
          {{part.content[0].text}}
        </h4>
      </ng-container>
    ':host ::ng-deep app-text-field {vertical-align: middle}',
    ':host ::ng-deep app-text-field .mat-form-field-wrapper {height: 100%; padding-bottom: 0; margin: 0}',
    ':host ::ng-deep app-text-field .mat-form-field {height: 100%}',
    ':host ::ng-deep app-text-field .mat-form-field-flex {height: 100%}',
rhenck's avatar
rhenck committed
    'p {margin: 0}',
rhenck's avatar
rhenck committed
    ':host ::ng-deep p strong {letter-spacing: 0.04em; font-weight: 600;}', // bold less bold
    ':host ::ng-deep p:empty::after {content: "\\00A0"}', // render empty p
rhenck's avatar
rhenck committed
    'p span {font-size: inherit}'
rhenck's avatar
rhenck committed
})
export class ClozeComponent extends CompoundElementComponent {
rhenck's avatar
rhenck committed
  @Input() elementModel!: ClozeElement;
  @Output() elementSelected = new EventEmitter<{ element: ClozeElement, event: MouseEvent }>();
rhenck's avatar
rhenck committed
  @ViewChildren('drowdownComponent, textfieldComponent, droplistComponent, radioComponent')
  compoundChildren!: QueryList<FormElementComponent>;
rhenck's avatar
rhenck committed

  getFormElementModelChildren(): InputElement[] {
rhenck's avatar
rhenck committed
    return this.elementModel.document.content
      .filter((paragraph: ClozeDocumentParagraph) => paragraph.content) // filter empty paragraphs
      .map((paragraph: ClozeDocumentParagraph) => paragraph.content // get custom paragraph parts
        .filter((word: ClozeDocumentPart) => ['TextField', 'DropList', 'ToggleButton'].includes(word.type)))
      .reduce((accumulator: any[], currentValue: any) => accumulator // put all collected paragraph parts into one list
        .concat(currentValue.map((node: ClozeDocumentPart) => node.attrs?.model)), []); // model is in node.attrs.model
rhenck's avatar
rhenck committed
  }

  selectElement(element: ClozeElement, event: MouseEvent): void {
    this.elementSelected.emit({ element: element, event: event });
rhenck's avatar
rhenck committed
  }
}