Skip to content
Snippets Groups Projects
element.component.ts 5.82 KiB
Newer Older
  • Learn to ignore specific revisions
  •   Component, OnInit, Input, ComponentFactoryResolver,
    
      ViewChild, ViewContainerRef
    
    import { FormBuilder, FormGroup } from '@angular/forms';
    
    import { takeUntil } from 'rxjs/operators';
    
    import { Subject } from 'rxjs';
    
    import * as ElementFactory from '../../../../../common/util/element.factory';
    
    import { KeyboardService } from '../../services/keyboard.service';
    
    import { TextFieldComponent } from '../../../../../common/element-components/text-field.component';
    import { TextAreaComponent } from '../../../../../common/element-components/text-area.component';
    
    import { FormService } from '../../../../../common/form.service';
    
    import { ValueChangeElement } from '../../../../../common/form';
    
    import { UnitStateService } from '../../services/unit-state.service';
    
    import { MarkingService } from '../../services/marking.service';
    
    rhenck's avatar
    rhenck committed
    import { UIElement } from '../../../../../common/models/uI-element';
    
    import { TextFieldElement } from '../../../../../common/models/text-field-element';
    
      selector: 'app-element',
      templateUrl: './element.component.html',
      styleUrls: ['./element.component.css']
    
    export class ElementComponent implements OnInit {
    
      @Input() elementModel!: UIElement;
    
      @Input() parentForm!: FormGroup;
    
      @Input() parentArrayIndex!: number;
    
      isKeyboardOpen!: boolean;
    
      keyboardLayout!: 'french' | 'numbers' | 'numbersAndOperators' | 'none';
    
      private ngUnsubscribe = new Subject<void>();
    
      @ViewChild('elementComponentContainer',
        { read: ViewContainerRef, static: true }) private elementComponentContainer!: ViewContainerRef;
    
    
      constructor(public keyboardService: KeyboardService,
    
                  private componentFactoryResolver: ComponentFactoryResolver,
                  private formService: FormService,
    
                  private unitStateService: UnitStateService,
    
                  private formBuilder: FormBuilder,
                  private markingService: MarkingService) {
    
        const elementComponentFactory =
    
          ElementFactory.getComponentFactory(this.elementModel.type, this.componentFactoryResolver);
    
        const elementComponent = this.elementComponentContainer.createComponent(elementComponentFactory).instance;
    
        elementComponent.elementModel = this.elementModel;
    
        const unitStateElementCode = this.unitStateService.getUnitStateElement(this.elementModel.id);
    
        if (unitStateElementCode && unitStateElementCode.value !== undefined) {
    
          if (this.elementModel.type === 'text') {
    
            elementComponent.elementModel.text = unitStateElementCode.value;
    
          } else {
            elementComponent.elementModel.value = unitStateElementCode.value;
          }
    
        this.unitStateService.registerElement(elementComponent.elementModel);
    
    
        if (elementComponent.applySelection) {
          elementComponent.applySelection
            .pipe(takeUntil(this.ngUnsubscribe))
            .subscribe((selection: { color: string; element: HTMLElement; clear: boolean }) => {
              this.applySelection(selection.color, selection.element, selection.clear);
            });
        }
    
    
        if (Object.prototype.hasOwnProperty.call(this.elementModel, 'required')) {
    
          const elementForm = this.formBuilder.group({});
          elementComponent.parentForm = elementForm;
          this.registerFormGroup(elementForm);
    
    
          elementComponent.formValueChanged
            .pipe(takeUntil(this.ngUnsubscribe))
            .subscribe((changeElement: ValueChangeElement) => {
    
              this.unitStateService.changeElementValue(changeElement);
    
          if (this.elementModel.inputAssistancePreset !== 'none' &&
    
            (this.elementModel.type === 'text-field' || this.elementModel.type === 'text-area')) {
    
            this.keyboardLayout = (this.elementModel as TextFieldElement).inputAssistancePreset;
    
            this.initEventsForKeyboard(elementComponent);
          }
    
        } // no else
    
      private registerFormGroup(elementForm: FormGroup): void {
        this.formService.registerFormGroup({
          formGroup: elementForm,
          parentForm: this.parentForm,
          parentArray: 'elements',
          parentArrayIndex: this.parentArrayIndex
        });
      }
    
    
      private initEventsForKeyboard(elementComponent: TextFieldComponent | TextAreaComponent): void {
        elementComponent.onFocus
          .pipe(takeUntil(this.ngUnsubscribe))
          .subscribe((focussedInputControl: HTMLElement): void => {
    
            const inputElement = this.elementModel.type === 'text-area' ?
              focussedInputControl as HTMLTextAreaElement :
              focussedInputControl as HTMLInputElement;
            this.isKeyboardOpen = this.keyboardService.openKeyboard(inputElement);
    
          });
    
        elementComponent.onBlur
          .pipe(takeUntil(this.ngUnsubscribe))
          .subscribe((): void => {
    
            this.isKeyboardOpen = this.keyboardService.closeKeyboard();
    
      private applySelection(color: string, element: HTMLElement, clear: boolean): void {
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
    
          for (let i = 0; i < selection.rangeCount; i++) {
            const range = selection.getRangeAt(i);
            if (this.isDescendantOf(range.startContainer, element) &&
              this.isDescendantOf(range.endContainer, element)) {
              this.markingService.applySelection(range, selection, clear, color);
              this.unitStateService.changeElementValue({
                id: this.elementModel.id,
                values: [this.elementModel.text as string, element.innerHTML]
              });
              this.elementModel.text = element.innerHTML;
            }
    
          selection.removeAllRanges();
    
        } // nothing to do!
      }
    
      private isDescendantOf(node: Node | null, element: HTMLElement): boolean {
        if (!node || node === document) {
          return false;
        }
        if (node.parentElement === element) {
          return true;
        }
        return this.isDescendantOf(node.parentNode, element);
      }
    
    
      ngOnDestroy(): void {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
      }