File

projects/maplander/shared/src/lib/components/upload-file/upload-file.component.ts

Implements

OnInit

Metadata

exportAs lib-upload-file
selector lib-upload-file
styleUrls ./upload-file.component.scss
templateUrl ./upload-file.component.html

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor(_document: any, _snackBarService: SnackBarService, _dialog: MatDialog)
Parameters :
Name Type Optional
_document any No
_snackBarService SnackBarService No
_dialog MatDialog No

Inputs

aspectRatio
Type : number
circle
Type : boolean
content
Type : TemplateRef<any>
disabled
Type : boolean
fab
Type : boolean
fileType
Type : "image" | "image360" | "document"
isLoaded
Type : boolean
multiple
Type : boolean

Outputs

loadImage
Type : EventEmitter<UserMedia | []>

Methods

Private createDocuments
createDocuments(files: any[])
Parameters :
Name Type Optional
files any[] No
Returns : void
Private createImages360
createImages360(files: any[])
Parameters :
Name Type Optional
files any[] No
Returns : void
ngOnInit
ngOnInit()
Returns : void
Public onChangeFile
onChangeFile(event)
Parameters :
Name Optional
event No
Returns : void
Public onDeletePhoto
onDeletePhoto()
Returns : void
Private openCropper
openCropper(files: any[])
Parameters :
Name Type Optional
files any[] No
Returns : void
Public update
update()
Returns : void
Private Static validateDocuments
validateDocuments(files: FileList)
Parameters :
Name Type Optional
files FileList No
Returns : any[]
Private Static validateImages
validateImages(files: FileList)
Parameters :
Name Type Optional
files FileList No
Returns : any[]

Properties

Public _document
Type : any
Decorators :
@Inject(DOCUMENT)
Public accept
Type : string
Public id
Type : string
import {Component, ContentChild, EventEmitter, Inject, Input, OnInit, Optional, Output, TemplateRef} from '@angular/core';
import {MatDialog} from '@angular/material/dialog';
import {DOCUMENT} from '@angular/common';
import {CropImageComponent} from '../crop-image/crop-image.component';
import {PFileTypeEnum, UserMedia} from '@maplander/types';
import {Utils} from '../../../utils/utils';
import {SnackBarService} from '@maplander/core';
import {DataCropImage} from '../../../utils/models/data-crop-image';

@Component({
  exportAs: 'lib-upload-file',
  selector: 'lib-upload-file',
  templateUrl: './upload-file.component.html',
  styleUrls: ['./upload-file.component.scss']
})
export class UploadFileComponent implements OnInit {

  @ContentChild(TemplateRef, {static: true})
  @Input() content: TemplateRef<any>;
  @Input() fab: boolean;
  @Input() multiple: boolean;
  @Input() circle: boolean;
  @Input() fileType: 'image' | 'image360' | 'document';
  @Input() disabled: boolean;
  @Input() aspectRatio: number;
  @Input() isLoaded: boolean;
  @Output() loadImage: EventEmitter<UserMedia | UserMedia[]>;
  public id: string;
  public accept: string;

  constructor(
    @Inject(DOCUMENT) public _document: any,
    @Optional() private _snackBarService: SnackBarService,
    private _dialog: MatDialog
  ) {
    this.id = Utils.randomString();
    this.loadImage = new EventEmitter<UserMedia | UserMedia[]>();
    this.accept = 'image/jpg, image/jpeg, image/png';
  }

  private static validateImages(files: FileList): any[] {
    const result = [];
    const types = [
      'image/jpg',
      'image/jpeg',
      'image/png'
    ];
    for (let i = 0; i < files.length; i++) {
      if (types.includes(files.item(i).type)) {
        result.push(files.item(i));
      }
    }
    return result;
  }

  private static validateDocuments(files: FileList): any[] {
    const result = [];
    const types = [
      'application/pdf'
    ];
    for (let i = 0; i < files.length; i++) {
      if (types.includes(files.item(i).type)) {
        result.push(files.item(i));
      }
    }
    return result;
  }

  ngOnInit() {
    if (this.fileType && this.fileType === 'document') {
      this.accept = 'application/pdf';
    }
  }

  public update(): void {
    this._document.getElementById(this.id).click();
  }

  public onDeletePhoto(): void {
    this.isLoaded = false;
    this.loadImage.emit(new UserMedia(null, ''));
  }

  public onChangeFile(event): void {
    const files: FileList = event.target.files;
    let validImages;
    switch (this.fileType) {
      case 'image360':
        validImages = UploadFileComponent.validateImages(files);
        if (validImages.length < files.length) {
          this._snackBarService.setMessage(
            'Suba imagenes con extensiones .jpeg / .jpg / .png solamente.',
            'OK',
            2000
          );
        }
        if (validImages.length > 0) {
          this.createImages360(validImages);
        }
        break;
      case 'document':
        const validDocuments = UploadFileComponent.validateDocuments(files);
        if (validDocuments.length < files.length) {
          this._snackBarService.setMessage('Suba archivos con extensión .pdf solamente.', 'OK', 2000);
        }
        if (validDocuments.length > 0) {
          this.createDocuments(validDocuments);
        }
        break;
      default:
        validImages = UploadFileComponent.validateImages(files);
        if (validImages.length < files.length) {
          this._snackBarService.setMessage(
            'Suba imagenes con extensiones .jpeg / .jpg / .png solamente.',
            'OK',
            2000
          );
        }
        if (validImages.length > 0) {
          this.openCropper(validImages);
        }
        break;
    }
  }

  private createDocuments(files: any[]): void {
    const result = [];
    const readDoc = (file: any) => {
      let base = null;
      const reader = new FileReader();
      reader.onload = (event: any) => {
        if (base === null) {
          base = event.target.result;
          reader.readAsArrayBuffer(file);
        } else {
          result.push(new UserMedia(new Blob([event.target.result]), base));
          validate();
        }
      };
      reader.readAsDataURL(file);
    };
    const validate = () => {
      if (files.length > 0) {
        const file = files.splice(0, 1);
        readDoc(file[0]);
      } else {
        this.loadImage.emit(result.length === 1 ? result[0] : result);
      }
    };
    validate();
  }

  private createImages360(files: any[]): void {
    const result = [];
    let discarded = 0;
    const createImage = (file: any) => {
      let img;
      const reader = new FileReader();
      const onLoadImg = () => {
        if ((img.width / 2) >= img.height) {
          reader.readAsArrayBuffer(file);
        } else {
          discarded++;
          validate();
        }
      };
      reader.onload = (event: any) => {
        if (!img) {
          img = new Image();
          img.src = event.target.result;
          img.onload = onLoadImg;
        } else {
          result.push(new UserMedia(new Blob([event.target.result], {type: file.type}), img.src, PFileTypeEnum.SPHERIC));
          validate();
        }
      };
      reader.readAsDataURL(file);
    };
    const validate = () => {
      if (files.length > 0) {
        const file = files.splice(0, 1);
        createImage(file[0]);
      } else {
        if (discarded > 0) {
          this._snackBarService.setMessage(`Se decartaron ${discarded}`, 'OK', 2000);
        }
        this.loadImage.emit(result.length === 1 ? result[0] : result);
      }
    };
    validate();
  }

  private openCropper(files: any[]): void {
    this._dialog.open<CropImageComponent, DataCropImage, UserMedia[]>(CropImageComponent,
      {
        data:
          {
            aspectRatio: this.aspectRatio,
            circle: this.circle,
            files: files
          },
        disableClose: true
      }
    ).afterClosed().subscribe((response) => {
      if (!response) {
        return;
      }
      this.loadImage.emit(response.length === 1 ? response[0] : response);
    });
  }
}
<!--
  ~ Copyright (C) MapLander S de R.L de C.V - All Rights Reserved
  ~ Unauthorized copying of this file, via any medium is strictly prohibited
  ~ Proprietary and confidential
  ~
  -->

<div id="upload-file-component">
  <ng-container [ngTemplateOutlet]="content">
    <input #fileInput type="file" [accept]="accept" [id]="id" (change)="onChangeFile($event)"
           [multiple]="multiple" (click)="fileInput.value = null" class="inputHiddenForFileInComponent"/>
    <ng-template [ngIf]="fab" [ngIfElse]="layerWithButtons">
      <div class="btn_edit_photo_fab" (click)="update()" [attr.data-disabled-upload]="disabled ? '' : null"></div>
    </ng-template>
    <ng-template #layerWithButtons>
      <div id="buttonHiddenForUploadFileComponent" [attr.data-disabled-upload]="disabled ? '' : null">
        <div class="btn_edit_photo" (click)="update()">
          <mat-icon>edit</mat-icon>
        </div>
        <ng-template [ngIf]="isLoaded">
          <div class="btn_delete_photo" (click)="onDeletePhoto()">
            <mat-icon>delete</mat-icon>
          </div>
        </ng-template>
      </div>
    </ng-template>
  </ng-container>
</div>

./upload-file.component.scss

/*!
 * Copyright (C) MapLander S de R.L de C.V - All Rights Reserved
 * Unauthorized copying of this file, via any medium is strictly prohibited
 * Proprietary and confidential
 *
 */

:host{
  display: block;
  width: fit-content;
  height: fit-content;
  position: inherit;
  margin: inherit;
  top: inherit;
  left: inherit;
  right: inherit;
  bottom: inherit;
}


[data-disabled-upload]{
  display: none;
}

#upload-file-component{
  position: relative;
  display: flex;
  justify-content: center;
  width: fit-content;
  height: fit-content;
  .inputHiddenForFileInComponent{
    display: none;
  }
  #buttonHiddenForUploadFileComponent{
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    right: 0;
    border: 0;
    margin: 0;
    padding: 0 28px;
    background-color: transparent;
  }

  #buttonHiddenForUploadFileComponent:hover{
    & .btn_edit_photo, .btn_delete_photo{
      display: initial;
    }
  }

  .btn_edit_photo_fab{
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    cursor: pointer;
    background: transparent;
  }

  .btn_edit_photo{
    position: absolute;
    bottom: 0;
    right: 0;
    padding: 4px;
    border-radius: 4px;
    color: white;
    display: none;
    cursor: pointer;
    background-color: rgba(0, 0, 0, .4);
    mat-icon{
      width: 20px;
      height: 20px;
      font-size: 20px;
    }
  }

  .btn_delete_photo{
    position: absolute;
    bottom: 0;
    right: 36px;
    padding: 4px;
    border-radius: 4px;
    color: white;
    display: none;
    cursor: pointer;
    background-color: rgba(0, 0, 0, .4);
    mat-icon{
      width: 20px;
      height: 20px;
      font-size: 20px;
    }
  }

  input:focus{
    outline: none !important;
  }
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""