File

src/app/file-dir-card/file-dir-card.component.ts

Implements

OnInit

Metadata

selector app-file-dir-card
styleUrls ./file-dir-card.component.scss
templateUrl ./file-dir-card.component.html

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor(fileService: FileService, apiService: ApiService)
Parameters :
Name Type Optional
fileService FileService No
apiService ApiService No

Inputs

directory
Type : Directory
file
Type : File
isFile
Type : boolean
isNew
Type : boolean
level
Type : number
noEdits
Default value : false
parentDirs
Type : Directory[]
parentFiles
Type : File[]
parentPath
Type : string
trace
Type : number[]

Outputs

cancelled
Type : EventEmitter<boolean>
createDir
Type : EventEmitter<any>
createFile
Type : EventEmitter<File>
deleteDir
Type : EventEmitter<any>
deleteFile
Type : EventEmitter<any>

Methods

addToTraceDir
addToTraceDir(dir: Directory)
Parameters :
Name Type Optional
dir Directory No
Returns : number[]
addToTraceFile
addToTraceFile(file: File)
Parameters :
Name Type Optional
file File No
Returns : number[]
Private countFiles
countFiles(directory: Directory)
Parameters :
Name Type Optional
directory Directory No
Returns : number
createDirExec
createDirExec(name: string)
Parameters :
Name Type Optional
name string No
Returns : void
createFileExec
createFileExec(file: File)
Parameters :
Name Type Optional
file File No
Returns : void
deleteDirExec
deleteDirExec($event: any)
Parameters :
Name Type Optional
$event any No
Returns : void
deleteFileExec
deleteFileExec($event: any)
Parameters :
Name Type Optional
$event any No
Returns : void
getRouterLink
getRouterLink()
Returns : string
ngOnInit
ngOnInit()
Returns : void
onCreateDir
onCreateDir()
Returns : void
onCreateFile
onCreateFile()
Returns : void
onDelete
onDelete()
Returns : void
present
present(newName: string)
Parameters :
Name Type Optional
newName string No
Returns : boolean

Properties

creating
Default value : false
creatingNewSub
Type : number
Default value : 0
deleting
Type : boolean
dirnames
Type : []
Default value : []
extensions
Type : []
Default value : ['.cpp', '.py', '.java']
filenames
Type : []
Default value : []
isErrorCreating
Default value : false
isErrorDeleting
Default value : false
isExpanded
Default value : false
lang
Type : number
Default value : 0
newName
Type : string
Default value : ''
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {File} from '../file';
import {Directory} from '../directory';
import {FileService} from '../file.service';
import {ApiService} from '../api.service';

@Component({
  selector: 'app-file-dir-card',
  templateUrl: './file-dir-card.component.html',
  styleUrls: ['./file-dir-card.component.scss']
})
export class FileDirCardComponent implements OnInit {

  @Input() isFile: boolean;
  @Input() level: number;
  @Input() file: File;
  @Input() directory: Directory;
  @Input() trace: number[];
  @Input() isNew: boolean;
  @Input() parentPath: string;
  @Input() noEdits = false;
  @Input() parentDirs: Directory[];
  @Input() parentFiles: File[];

  deleting: boolean;
  isExpanded = false;
  newName = '';
  isErrorDeleting = false;
  isErrorCreating = false;
  creating = false;
  creatingNewSub = 0;
  extensions = ['.cpp', '.py', '.java'];
  lang = 0;
  filenames = [];
  dirnames = [];

  @Output() deleteFile: EventEmitter<any> = new EventEmitter();
  @Output() deleteDir: EventEmitter<any> = new EventEmitter();
  @Output() createDir: EventEmitter<any> = new EventEmitter();
  @Output() createFile: EventEmitter<File> = new EventEmitter();
  @Output() cancelled: EventEmitter<boolean> = new EventEmitter();

  constructor(private fileService: FileService, private apiService: ApiService) {
  }

  ngOnInit(): void {
    if (!this.isFile && !this.isNew) {
      this.filenames = this.directory.files.map(item => item.filename);
      this.dirnames = this.directory.dirs.map(item => item.name);
    }
  }

  onDelete(): void {
    this.deleting = true;
    this.fileService.delete(this.isFile ? this.file : this.directory, this.isFile,
      JSON.parse(this.apiService.getToken()).username, this.isFile ? 0 : this.countFiles(this.directory)).subscribe(
      data => {
        console.log(data);
        if (this.isFile) {
          this.deleteFile.emit(this.file);
        } else {
          this.deleteDir.emit(this.directory);
        }
        this.deleting = false;
      }, error => {
        console.log(error);
      }
    );
  }

  addToTraceDir(dir: Directory): number[] {
    const arr = JSON.parse(JSON.stringify(this.trace));
    arr.push(this.directory.dirs.indexOf(dir));
    return arr;
  }

  addToTraceFile(file: File): number[] {
    const arr = JSON.parse(JSON.stringify(this.trace));
    arr.push(this.directory.files.indexOf(file));
    return arr;
  }

  deleteFileExec($event: any): void {
    const index = this.directory.files.indexOf($event, 0);
    if (index > -1) {
      this.directory.files.splice(index, 1);
    }
  }

  deleteDirExec($event: any): void {
    const index = this.directory.dirs.indexOf($event, 0);
    if (index > -1) {
      this.directory.dirs.splice(index, 1);
    }
  }

  onCreateDir(): void {
    this.creating = true;
    this.fileService.createDirectory(JSON.parse(this.apiService.getToken()).username, this.newName, this.parentPath)
      .subscribe(data => {
        if (data === '0') {
          this.creating = false;
          this.isErrorCreating = true;
        } else {
          this.createDir.emit(this.newName);
        }
      });
  }

  getRouterLink(): string {
    return '/arena/file/' + encodeURIComponent(this.file.path + '/' + this.file.filename + this.file.language);
  }

  onCreateFile(): void {
    this.creating = true;
    const file: File = {
      username: JSON.parse(this.apiService.getToken()).username,
      filename: this.newName,
      language: this.extensions[this.lang],
      text: '',
      path: this.parentPath
    };
    this.fileService.upload(file, false).subscribe(data => {
      if (data === '1') {
        console.log(data);
        this.createFile.emit(file);
      } else {
        console.log(data);
        this.creating = false;
        this.isErrorCreating = true;
      }
    });
  }

  createFileExec(file: File): void {
    this.directory.files.push(file);
    this.creatingNewSub = 0;
  }

  createDirExec(name: string): void {
    this.directory.dirs.push({
      name,
      dirs: [],
      files: [],
      path: this.directory.path + this.directory.name + '/',
    });
    this.creatingNewSub = 0;
  }

  private countFiles(directory: Directory): number {
    let count = directory.files.length;
    for (const dir of directory.dirs) {
      count += this.countFiles(dir);
    }
    return count;
  }

  present(newName: string): boolean {
    if (this.isFile) {
      return this.parentFiles.map(item => item.filename + item.language).includes(newName + this.extensions[this.lang]);
    } else {
      return this.parentDirs.map(item => item.name).includes(newName);
    }
  }
}
<div [style.background]="isFile ? '#002' : '#022'" [style.marginLeft]="level * 20 + 'px'" class="card">
  <div *ngIf="!isNew && isFile" class="title">{{file.filename}}{{file.language}}</div>
  <div *ngIf="!isNew && !isFile" class="title">{{directory.name}}</div>
  <div *ngIf="!isNew && !isFile" class="dir-desc">{{directory.dirs.length}} directories, {{directory.files.length}}
    files
  </div>

  <div *ngIf="isNew" class="title">
    <input (input)="isErrorCreating = false" [(ngModel)]="newName" [disabled]="creating" [placeholder]="'Name of new ' + (isFile ? 'file' : 'directory')"
           id="newFilenameInput" type="text">
    <label (click)="lang = (lang + 1) % 3" *ngIf="isFile" for="newFilenameInput">{{extensions[lang]}}</label>
  </div>

  <div *ngIf="isNew || isFile"></div>
  <div *ngIf="!isNew" class="file-buttons">
    <button *ngIf="!noEdits" (click)="onDelete()" [class.disabled]="deleting || isErrorDeleting"
            [disabled]="deleting || isErrorDeleting">{{isErrorDeleting ? 'Error' : (deleting ? 'Deleting...' : 'Delete')}}</button>
    <button (click)="isExpanded = !isExpanded" *ngIf="!isFile">{{isExpanded ? 'Collapse' : 'Expand'}}</button>
    <button (click)="isExpanded = true; creatingNewSub = 1" *ngIf="!noEdits && !isFile && level < 3" [class.disabled]="deleting" [disabled]="deleting">New Directory</button>
    <button (click)="isExpanded = true; creatingNewSub = 2" *ngIf="!noEdits && !isFile" [class.disabled]="deleting" [disabled]="deleting">New File</button>
    <button *ngIf="!noEdits && isFile" [class.disabled]="deleting" [disabled]="deleting"
            [routerLink]="getRouterLink()">Edit
    </button>
  </div>

  <div *ngIf="isNew" class="file-buttons">
    <button (click)="cancelled.emit(true)" [class.disabled]="creating" [disabled]="creating">Cancel</button>
    <button (click)="isFile ? onCreateFile() : onCreateDir()"
            [class.disabled]="newName==='' || present(newName) || creating || isErrorCreating"
            [disabled]="newName==='' || present(newName) || creating || isErrorCreating">{{isErrorCreating ? 'Error' : (creating ? 'Creating...' : 'Create')}}</button>
  </div>

</div>

<div *ngIf="!isNew && !isFile" [style.display]="isExpanded ? 'block' : 'none'" class="subs">

  <app-file-dir-card (cancelled)="creatingNewSub = 0" (createDir)="createDirExec($event)"
                     (createFile)="createFileExec($event)"
                     *ngIf="creatingNewSub !== 0" [isFile]="creatingNewSub === 2" [isNew]="true"
                     [parentDirs]="this.directory.dirs" [parentFiles]="this.directory.files"
                     [level]="level + 1" [parentPath]="directory.path + directory.name + '/'"></app-file-dir-card>

  <app-file-dir-card (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"
                     *ngFor="let dir of directory.dirs" [directory]="dir"
                     [isFile]="false" [isNew]="false" [level]="level + 1"
                     [trace]="addToTraceDir(dir)" [noEdits]="noEdits"></app-file-dir-card>

  <app-file-dir-card (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"
                     *ngFor="let file of directory.files" [file]="file"
                     [isFile]="true" [isNew]="false" [level]="level + 1"
                     [trace]="addToTraceFile(file)" [noEdits]="noEdits"></app-file-dir-card>
</div>

./file-dir-card.component.scss

.card {
  display: grid;
  grid-template-columns: 30% 20% 50%;
  height: 3em;
  border-bottom: 1px solid #fff;

  button {
    float: right;
    border: none;
    user-select: none;
  }

  .title {
    padding: 1em 20px;

    input {
      background: none;
      border: none;
      border-bottom: 1px solid #ddf;
      font: inherit;
      color: inherit;
      width: 60%;

      &::placeholder {
        font-size: 0.8em;
      }
    }

    label {
      font-size: 0.9em;
      padding: 5px;
      background: #202;
      border-radius: 5px;
      cursor: pointer;
      user-select: none;
    }
  }

  .dir-desc {
    padding: 1.1em 20px;
    font-size: 0.8em;
  }

  .file-buttons {
    padding: 0.7em 20px;
  }
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""