Skip to content
Snippets Groups Projects
math-input.component.ts 4.27 KiB
Newer Older
  • Learn to ignore specific revisions
  • rhenck's avatar
    rhenck committed
    import {
    
      AfterViewInit,
      Component,
      ElementRef,
      EventEmitter,
      Input,
    
      OnChanges, OnDestroy,
    
      Output,
      SimpleChanges,
      ViewChild
    
    rhenck's avatar
    rhenck committed
    } from '@angular/core';
    
    import { MathfieldElement } from '@iqb/mathlive';
    
    import { MatButtonToggleChange } from '@angular/material/button-toggle';
    import { IQB_MATH_KEYBOARD_LAYOUTS } from 'common/math-editor/keyboard-layout.config';
    
    rhenck's avatar
    rhenck committed
    
    @Component({
    
    jojohoch's avatar
    jojohoch committed
      selector: 'aspect-math-input',
    
    rhenck's avatar
    rhenck committed
      template: `
        <mat-button-toggle-group *ngIf="enableModeSwitch"
    
    rhenck's avatar
    rhenck committed
                                 [value]="mathFieldElement.mode"
                                 (change)="setParseMode($event)">
    
    rhenck's avatar
    rhenck committed
          <mat-button-toggle value="math">Formel</mat-button-toggle>
          <mat-button-toggle value="text">Text</mat-button-toggle>
        </mat-button-toggle-group>
    
    jojohoch's avatar
    jojohoch committed
        <div #inputRef
             (input)="onInput()"
             [class.full-width]="fullWidth"
             [class.inline-block]="!fullWidth"
             [class.read-only]="readonly"
    
             (focusin)="onFocusIn()"
             (focusout)="onFocusOut()">
    
    rhenck's avatar
    rhenck committed
        </div>
      `,
    
      styles: [`
        mat-button-toggle-group {
          height: auto;
        }
    
    jojohoch's avatar
    jojohoch committed
        :host ::ng-deep .full-width math-field {
          display: block;
        }
    
        .inline-block{
          display: inline-block;
        }
    
        :host ::ng-deep  math-field::part(virtual-keyboard-toggle) {
          display: none;
        }
        :host ::ng-deep math-field::part(menu-toggle) {
          display: none;
        }
    
        :host ::ng-deep .read-only math-field {
    
    jojohoch's avatar
    jojohoch committed
          outline: unset;
          border: unset;
    
        }
        :host ::ng-deep .mat-button-toggle-label-content {
          line-height: unset;
        }`
    
    rhenck's avatar
    rhenck committed
      ]
    })
    
    export class MathInputComponent implements AfterViewInit, OnChanges, OnDestroy {
    
    rhenck's avatar
    rhenck committed
      @Input() value!: string;
    
    jojohoch's avatar
    jojohoch committed
      @Input() fullWidth: boolean = true;
    
      @Input() readonly: boolean = false;
    
    rhenck's avatar
    rhenck committed
      @Input() enableModeSwitch: boolean = false;
    
    jojohoch's avatar
    jojohoch committed
      @Output() valueChange: EventEmitter<string> = new EventEmitter();
    
      @Output() focusIn: EventEmitter<MathfieldElement> = new EventEmitter();
      @Output() focusOut: EventEmitter<MathfieldElement> = new EventEmitter();
    
    jojohoch's avatar
    jojohoch committed
      @ViewChild('inputRef') inputRef!: ElementRef;
    
      protected readonly window = window;
    
    jojohoch's avatar
    jojohoch committed
      private readonly mathKeyboardLayout = IQB_MATH_KEYBOARD_LAYOUTS;
    
    rhenck's avatar
    rhenck committed
    
      mathFieldElement: MathfieldElement = new MathfieldElement({
    
        mathVirtualKeyboardPolicy: 'manual'
    
      constructor(public elementRef: ElementRef) {}
    
    jojohoch's avatar
    jojohoch committed
    
    
    rhenck's avatar
    rhenck committed
      ngAfterViewInit(): void {
    
        this.setupMathField();
    
        this.setKeyboardLayout();
    
    jojohoch's avatar
    jojohoch committed
        MathInputComponent.setupMathKeyboard();
    
      private setupMathField(): void {
    
    jojohoch's avatar
    jojohoch committed
        this.inputRef.nativeElement.appendChild(this.mathFieldElement);
    
    rhenck's avatar
    rhenck committed
        this.mathFieldElement.value = this.value;
    
        this.mathFieldElement.readOnly = this.readonly;
    
        setTimeout(() => {
          this.mathFieldElement.menuItems = [];
        }); // Disable context menu
    
    jojohoch's avatar
    jojohoch committed
      private static setupMathKeyboard(): void {
    
        window.mathVirtualKeyboard.addEventListener('virtual-keyboard-layer-change', () => MathInputComponent.resetShift());
      }
    
      private static resetShift(): void {
        window.mathVirtualKeyboard.shiftPressCount = 0;
    
    rhenck's avatar
    rhenck committed
      ngOnChanges(changes: SimpleChanges): void {
    
        if (changes.value) {
          this.mathFieldElement.setValue(changes.value.currentValue, { mode: 'text' });
        }
    
      // eslint-disable-next-line
    
    jojohoch's avatar
    jojohoch committed
      setFocus(offset?: number): void {
        this.mathFieldElement.focus();
      }
    
    
    rhenck's avatar
    rhenck committed
      setParseMode(event: MatButtonToggleChange) {
        this.mathFieldElement.mode = event.value;
    
    jojohoch's avatar
    jojohoch committed
        (this.inputRef.nativeElement.childNodes[0] as HTMLElement).focus();
    
    rhenck's avatar
    rhenck committed
      }
    
    jojohoch's avatar
    jojohoch committed
      onInput() {
        this.valueChange.emit(this.mathFieldElement.getValue());
      }
    
    
      onFocusIn() {
    
        // give iqb keyboard time to animate
        setTimeout(() => {
          this.focusIn.emit(this.mathFieldElement);
          window.mathVirtualKeyboard.show({ firstLayer: true, resetShift: true });
        }, 250);
    
      }
    
      private setKeyboardLayout(): void {
        window.mathVirtualKeyboard.layouts = [
          this.mathKeyboardLayout.iqbNumeric,
          this.mathKeyboardLayout.iqbSymbols,
          this.mathKeyboardLayout.iqbText,
          this.mathKeyboardLayout.iqbGreek
        ];
      }
    
    
      onFocusOut() {
        this.focusOut.emit(this.mathFieldElement);
    
    jojohoch's avatar
    jojohoch committed
        window.mathVirtualKeyboard.hide();
      }
    
    
      // eslint-disable-next-line class-methods-use-this
      ngOnDestroy(): void {
        window.mathVirtualKeyboard
          .removeEventListener('virtual-keyboard-layer-change', () => MathInputComponent.resetShift());
      }
    
    rhenck's avatar
    rhenck committed
    }