File

src/app/components/graph-import/graph-import.component.ts

Description

Allows importing graphs as text or by uploading files. Supports both JSON and YAML.

Implements

AfterViewInit

Metadata

Index

Properties
Methods
Outputs

Constructor

Public constructor(snackBarService: SnackBarService)
Parameters :
Name Type Optional
snackBarService SnackBarService No

Outputs

graphImport
Type : EventEmitter

Methods

Public handleTextInput
handleTextInput(textInput: string)
Parameters :
Name Type Optional Default value
textInput string No this.textInputFormControl.value
Returns : void
Public ngAfterViewInit
ngAfterViewInit()
Returns : void
Public onFileInput
onFileInput()
Returns : void
Public onPaste
onPaste(event: ClipboardEvent)
Parameters :
Name Type Optional
event ClipboardEvent No
Returns : void
Public triggerFileImport
triggerFileImport()
Returns : void

Properties

Private Readonly fileInput
Type : ElementRef<HTMLInputElement>
Decorators :
@ViewChild('fileInput')
Private Readonly textInput
Type : ElementRef<HTMLInputElement>
Decorators :
@ViewChild('textInput')
Public Readonly textInputFormControl
Default value : new UntypedFormControl('')
import { AfterViewInit, Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import * as YAML from 'yaml';

import D3Graph from 'src/app/model/d3/d3.graph';
import { FOLGraph } from 'src/app/model/domain/fol.graph';
import { SnackBarService } from 'src/app/services/snack-bar.service';
import { terminate } from 'src/app/utils/events';

/**
 * Allows importing graphs as text or by uploading files.
 * Supports both JSON and YAML.
 */
@Component({
  selector: 'apollo-graph-import',
  templateUrl: './graph-import.component.html',
  styleUrls: ['./graph-import.component.scss'],
})
export class GraphImportComponent implements AfterViewInit {
  @Output() public readonly graphImport = new EventEmitter<FOLGraph>();

  @ViewChild('textInput') private readonly textInput!: ElementRef<HTMLInputElement>;

  @ViewChild('fileInput') private readonly fileInput!: ElementRef<HTMLInputElement>;

  public readonly textInputFormControl = new UntypedFormControl('');

  public constructor(private readonly snackBarService: SnackBarService) {}

  public ngAfterViewInit(): void {
    this.textInput.nativeElement.addEventListener('keydown', (event: KeyboardEvent) => {
      const inputElement = this.textInput.nativeElement;
      if (event.key === 'Tab') {
        terminate(event);
        const start = inputElement.selectionStart ?? 0;
        const end = inputElement.selectionEnd ?? 0;
        inputElement.value = inputElement.value.substring(0, start) + '\t' + inputElement.value.substring(end);
        inputElement.selectionStart = inputElement.selectionEnd = start + 1;
      }
    });
  }

  public onPaste(event: ClipboardEvent): void {
    this.handleTextInput(event.clipboardData?.getData('text') ?? '');
  }

  public triggerFileImport(): void {
    this.fileInput.nativeElement.click();
  }

  public onFileInput(): void {
    const files: FileList | null = this.fileInput.nativeElement.files;
    if (files === null || files.length < 1) {
      this.snackBarService.openSnackBar({ key: 'import.file-error' }, undefined, 10000);
    } else {
      files[0].text().then((fileContent) => this.handleTextInput(fileContent));
    }
    this.fileInput.nativeElement.value = '';
  }

  public handleTextInput(textInput: string = this.textInputFormControl.value): void {
    try {
      // YAML::parse also works with JSON.
      const parsedGraph: FOLGraph = YAML.parse(textInput);
      D3Graph.fromDomainGraph(parsedGraph)
        .then(() => this.graphImport.emit(parsedGraph))
        .catch((error) => {
          if (error.key !== undefined) {
            this.snackBarService.openSnackBar(error, undefined);
          } else {
            this.snackBarService.openSnackBar({ key: 'validation.parse-error' }, undefined, 10000);
          }
        });
    } catch (error) {
      this.snackBarService.openSnackBar({ key: 'validation.parse-error' }, undefined, 10000);
    }
  }
}
<div>
  <mat-form-field (keyup.enter)="handleTextInput()" style="margin-bottom: -0.25rem" class="import-form-field">
    <mat-label>{{ "import.text" | translate }}</mat-label>
    <textarea
      #textInput
      matInput
      [formControl]="textInputFormControl"
      placeholder="{{ 'import.format-hint' | translate }}"
      (paste)="onPaste($event)"
      cdkTextareaAutosize
      #autosize="cdkTextareaAutosize"
      cdkAutosizeMinRows="1"
      cdkAutosizeMaxRows="50"
    ></textarea>
  </mat-form-field>
  <input #fileInput type="file" id="file" style="display: none" accept=".json,.yml,text/json,application/json,text/yml" (change)="onFileInput()" />
  <span>{{ "misc.or" | translate }}</span>
  <button mat-raised-button color="primary" (click)="triggerFileImport()">{{ "import.file" | translate }}</button>
</div>

./graph-import.component.scss

:host {
  display: block;
}

h1 {
  margin: 0;
}

div {
  display: flex;
  flex-direction: column;

  > *:not(:last-child) {
    margin-bottom: 1rem;
  }

  > button {
    max-width: fit-content;
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""