File

projects/maplander/components/src/lib/components/property/components/multimedia-uploader/multimedia-uploader.component.ts

Implements

OnInit

Metadata

selector lib-property-multimedia-uploader
styleUrls ./multimedia-uploader.component.scss
templateUrl ./multimedia-uploader.component.html

Index

Properties
Methods

Constructor

constructor(_data: MultimediaUploaderData, _dialog: MatDialogRef)
Parameters :
Name Type Optional
_data MultimediaUploaderData No
_dialog MatDialogRef<MultimediaUploaderComponent | literal type> No

Methods

accept
accept()
Returns : void
close
close()
Returns : void
Private createImage360PFile
createImage360PFile(image: UserMedia)
Parameters :
Name Type Optional
image UserMedia No
Returns : void
Private createImagePFile
createImagePFile(image: UserMedia)
Parameters :
Name Type Optional
image UserMedia No
Returns : void
Private Static getYouTubeID
getYouTubeID(text: string)
Parameters :
Name Type Optional
text string No
Returns : string
Private joinMultimediaTypes
joinMultimediaTypes()
Returns : PFile[]
ngOnInit
ngOnInit()
Returns : void
onListChanged
onListChanged(ev: PFile[])
Parameters :
Name Type Optional
ev PFile[] No
Returns : void
onTabChanged
onTabChanged(tab: number)
Parameters :
Name Type Optional
tab number No
Returns : void
onUploadImage
onUploadImage(ev: UserMedia | UserMedia[])
Parameters :
Name Type Optional
ev UserMedia | UserMedia[] No
Returns : void
onYouTubeInputTextChanged
onYouTubeInputTextChanged(input: HTMLInputElement)
Parameters :
Name Type Optional
input HTMLInputElement No
Returns : void
Private parseMultimedia
parseMultimedia()
Returns : void
removeMedia
removeMedia(ev: PFile)
Parameters :
Name Type Optional
ev PFile No
Returns : void

Properties

Private _newMedia
Type : UserMedia[]
Public currentIndex
Type : number
Public fileType
Type : "image" | "image360" | "document"
Public images
Type : PFile[]
Public images360
Type : PFile[]
Public videos
Type : PFile[]
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {PFile, PFileTypeEnum, UserMedia} from '@maplander/types';

interface MultimediaUploaderData {
  currentType: PFileTypeEnum;
  multimedia: PFile[];
  newMedia: UserMedia[];
}

@Component({
  selector: 'lib-property-multimedia-uploader',
  templateUrl: './multimedia-uploader.component.html',
  styleUrls: ['./multimedia-uploader.component.scss']
})
export class MultimediaUploaderComponent implements OnInit {

  public fileType: 'image' | 'image360' | 'document';
  public images: PFile[];
  public images360: PFile[];
  public videos: PFile[];
  public currentIndex: number;
  private _newMedia: UserMedia[];

  constructor(
    @Inject(MAT_DIALOG_DATA) private _data: MultimediaUploaderData,
    private _dialog: MatDialogRef<MultimediaUploaderComponent, { multimedia: PFile[], newMedia: UserMedia[] }>
  ) {
    switch (this._data.currentType) {
      case PFileTypeEnum.IMAGE:
        this.fileType = 'image';
        this.currentIndex = 0;
        break;
      case PFileTypeEnum.SPHERIC:
        this.fileType = 'image360';
        this.currentIndex = 1;
        break;
      case PFileTypeEnum.VIDEO:
        this.fileType = 'document';
        this.currentIndex = 2;
        break;
    }
    this.images = [];
    this.images360 = [];
    this.videos = [];
    this._newMedia = [];
  }

  private static getYouTubeID(text: string): string {
    if (text.indexOf('https://youtu.be/') !== -1) {
      text = text.replace('https://youtu.be/', '');
    } else if (text.indexOf('https://www.youtube.com/') !== -1) {
      text = text.replace('https://www.youtube.com/', '');
    } else {
      return text = null;
    }
    if (text.indexOf('watch?v=') !== -1) {
      text = text.replace('watch?v=', '');
    } else {
      return text = null;
    }
    return text;
  }

  ngOnInit() {
    this.parseMultimedia();
  }

  onUploadImage(ev: UserMedia | UserMedia[]): void {
    if (!ev) {
      return;
    }
    switch (this.fileType) {
      case 'image':
        if (Array.isArray(ev)) {
          ev.forEach(image => {
            this.createImagePFile(image);
          });
        } else {
          this.createImagePFile(ev);
        }
        break;
      case 'image360':
        if (Array.isArray(ev)) {
          ev.forEach(image => {
            this.createImage360PFile(image);
          });
        } else {
          this.createImage360PFile(ev);
        }
        break;
    }
  }

  onTabChanged(tab: number): void {
    this.currentIndex = tab;
    switch (tab) {
      case 0:
        this.fileType = 'image';
        break;
      case 1:
        this.fileType = 'image360';
        break;
    }
  }

  onListChanged(ev: PFile[]): void {
    switch (this.currentIndex) {
      case 0:
        if (Array.isArray(ev) && ev.length > 0) {
          ev = ev.map((item, index) => {
            item.position = index;
            return item;
          });
          this.images = ev;
        }
        break;
      case 1:
        if (Array.isArray(ev) && ev.length > 0) {
          ev = ev.map((item, index) => {
            item.position = index;
            return item;
          });
          this.images360 = ev;
        }
        break;
      case 2:
        if (Array.isArray(ev) && ev.length > 0) {
          ev = ev.map((item, index) => {
            item.position = index;
            return item;
          });
          this.videos = ev;
        }
        break;
    }
  }

  removeMedia(ev: PFile): void {
    let i = -1;
    if (!ev.id) {
      switch (ev.type) {
        case PFileTypeEnum.IMAGE:
          this.images.splice(this.images.indexOf(ev), 1);
          break;
        case PFileTypeEnum.SPHERIC:
          this.images360.splice(this.images360.indexOf(ev), 1);
          break;
        case PFileTypeEnum.VIDEO:
          this.videos.splice(this.videos.indexOf(ev), 1);
          break;
      }
      this._newMedia.forEach((item, index) => {
        if (item.url === ev.fileCS.thumbnail) {
          i = index;
        }
      });
      if (i > -1) {
        this._newMedia.splice(i, 1);
      }
    } else {
      switch (ev.type) {
        case PFileTypeEnum.IMAGE:
          this.images.splice(this.images.indexOf(ev), 1);
          break;
        case PFileTypeEnum.SPHERIC:
          this.images360.splice(this.images360.indexOf(ev), 1);
          break;
        case PFileTypeEnum.VIDEO:
          this.videos.splice(this.videos.indexOf(ev), 1);
          break;
      }
    }
  }

  onYouTubeInputTextChanged(input: HTMLInputElement): void {
    if (input.value === '') {
      return;
    }
    const id = MultimediaUploaderComponent.getYouTubeID(input.value);
    if (!id) {
      return;
    }
    if (id.length >= 11) {
      const file = new PFile();
      file.type = PFileTypeEnum.VIDEO;
      file.media = true;
      file.name = `video_${new Date().getTime()}`;
      file.fileCS = {
        thumbnail: id,
        blobName: null
      };
      file.position = this.videos.length === 0 ? 0 : this.videos.length;
      this.videos.push(file);
      input.value = '';
    }
  }

  accept(): void {
    this._dialog.close({multimedia: this.joinMultimediaTypes(), newMedia: this._newMedia});
  }

  close(): void {
    this._dialog.close(null);
  }

  private createImagePFile(image: UserMedia): void {
    const file = new PFile();
    file.type = PFileTypeEnum.IMAGE;
    image.type = PFileTypeEnum.IMAGE;
    file.media = true;
    file.fileCS = {
      thumbnail: image.url,
      blobName: null
    };
    const fileName = `image_${Date.now()}_${Math.round(Math.random() * 1000000)}.${image.blob.type.replace('image/', '')}`;
    file.name = fileName;
    image.name = fileName;
    file.position = this.images.length === 0 ? 0 : this.images.length;
    this._newMedia.push(image);
    this.images.push(file);
  }

  private createImage360PFile(image: UserMedia): void {
    const file = new PFile();
    file.type = PFileTypeEnum.SPHERIC;
    image.type = PFileTypeEnum.SPHERIC;
    file.media = true;
    const fileName = `spheric_${Date.now()}_${Math.round(Math.random() * 1000000)}.${image.blob.type.replace('image/', '')}`;
    file.name = fileName;
    image.name = fileName;
    file.fileCS = {
      thumbnail: image.url,
      blobName: null
    };
    file.position = this.images360.length === 0 ? 0 : this.images360.length;
    this._newMedia.push(image);
    this.images360.push(file);
  }

  private parseMultimedia(): void {
    if (this._data) {
      this._data.multimedia.forEach(item => {
        switch (item.type) {
          case PFileTypeEnum.IMAGE:
            this.images.push(item);
            break;
          case PFileTypeEnum.SPHERIC:
            this.images360.push(item);
            break;
          case PFileTypeEnum.VIDEO:
            this.videos.push(item);
            break;
        }
      });
      this._newMedia = this._data.newMedia || [];
    }
  }

  private joinMultimediaTypes(): PFile[] {
    let response = [];
    response = response.concat(this.images);
    response = response.concat(this.images360);
    response = response.concat(this.videos);
    return response;
  }

}
<div class="multimedia-uploader">
  <p class="title">
    Multimedia
    <ng-template [ngIf]="currentIndex !== 2">
      <lib-upload-file [content]="buttonUploadTemplate" [fab]="true" [fileType]="fileType" [aspectRatio]="4 / 3"
                       [multiple]="true"
                       (loadImage)="onUploadImage($event)">
        <ng-template #buttonUploadTemplate>
          <button mat-icon-button color="primary">
            <mat-icon>add</mat-icon>
          </button>
        </ng-template>
      </lib-upload-file>
    </ng-template>
  </p>
  <mat-tab-group class="multimedia-uploader__tab-group" [selectedIndex]="currentIndex"
                 (selectedIndexChange)="onTabChanged($event)">
    <mat-tab label="Fotografias">
      <lib-custom-drag-and-drop [items]="images" [content]="imageTemplate" (itemsChanged)="onListChanged($event)">
        <ng-template #imageTemplate let-image="image" let-index="index">
          <div class="list__item" [ngClass]="{'first-photo': index === 0}">
            <img alt="Property image" [src]="image.fileCS.thumbnail" class="list__item-img">
            <button mat-icon-button class="list__item-button mat-elevation-z2" (click)="removeMedia(image)">
              <mat-icon class="list__item-icon">close</mat-icon>
            </button>
          </div>
        </ng-template>
      </lib-custom-drag-and-drop>
    </mat-tab>
    <mat-tab label="Esfericas">
      <lib-custom-drag-and-drop [items]="images360" [content]="image360Template" (itemsChanged)="onListChanged($event)">
        <ng-template #image360Template let-image="image">
          <div class="list__item">
            <img alt="Property image" [src]="image.fileCS.thumbnail" class="list__item-img">
            <button mat-icon-button class="list__item-button mat-elevation-z2" (click)="removeMedia(image)">
              <mat-icon class="list__item-icon">close</mat-icon>
            </button>
          </div>
        </ng-template>
      </lib-custom-drag-and-drop>
    </mat-tab>
    <mat-tab label="Videos">
      <div class="you-tube-container">
        <span class="you-tube-container__searchbox">
          <button *ngIf="inputYouTube.value !== ''" mat-icon-button class="you-tube-container__close-btn"
                  (click)="inputYouTube.value = ''"><mat-icon>close</mat-icon></button>
          <input class="you-tube-container__input" #inputYouTube (input)="onYouTubeInputTextChanged(inputYouTube)"
                 title="YouTube URL" placeholder="YouTube URL o YouTube Video ID">
        </span>
        <a href="https://www.youtube.com" target="_blank" mat-button color="primary">
          Ir a Youtube
        </a>
      </div>
      <lib-custom-drag-and-drop [items]="videos" [content]="videosTemplate" (itemsChanged)="onListChanged($event)">
        <ng-template #videosTemplate let-image="image">
          <div class="list__item">
            <img alt="Property image" [src]="'http://i3.ytimg.com/vi/'+image.fileCS.thumbnail+'/hqdefault.jpg'"
                 class="list__item-img">
            <button mat-icon-button class="list__item-button mat-elevation-z2" (click)="removeMedia(image)">
              <mat-icon class="list__item-icon">close</mat-icon>
            </button>
          </div>
        </ng-template>
      </lib-custom-drag-and-drop>
    </mat-tab>
  </mat-tab-group>
  <div class="multimedia-uploader__actions">
    <button mat-flat-button color="primary" class="actions__button" (click)="close()">
      CERRAR
    </button>
    <button mat-flat-button color="primary" class="actions__button" (click)="accept()">
      ACEPTAR
    </button>
  </div>
</div>

./multimedia-uploader.component.scss

:host {
  display: block;
  width: 100%;
  height: 100%;
}

::ng-deep .multimedia-uploader-panel-class {
  width: 50%;
  height: 70%;
  mat-dialog-container {
    width: 100%;
    height: 100%;
    padding: 16px;
    overflow: hidden;
    position: relative;
  }
  @media screen and (max-width: 600px) {
    width: 100% !important;
    max-width: 100% !important;
    height: 100% !important;
  }
}

.multimedia-uploader {
  width: 100%;
  height: 100%;
}

.multimedia-uploader__actions {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  background: white;
  z-index: 1;
}

.actions__button {
  width: 50%;
}

.actions__button:first-child {
  border-radius: 8px 0 0 0;
}

.actions__button:last-child {
  border-radius: 0 8px 0 0;
}

.title {
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  margin: 0;
}

.multimedia-uploader__tab-group {
  width: 100%;
  height: calc(100% - 36px);
}

.multimedia-uploader__list {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, calc(100% / 3));
  @media screen and (max-width: 600px){
    grid-template-columns: 100%;
  }
}

.list__item {
  width: 200px;
  height: 150px;
  border-radius: 8px;
  margin: 16px auto;
  position: relative;
}

.first-photo:after {
  content: 'Imagen principal del anuncio';
  position: absolute;
  top: 0;
  padding: 8px;
  box-sizing: border-box;
  font-size: 12px;
  width: 100%;
  color: white;
  background: rgba(0, 0, 0, .3);
}

.list__item-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 8px;
}

.list__item-button {
  position: absolute;
  width: 24px;
  height: 24px;
  top: -12px;
  right: -12px;
  background: black;
  color: white;
}

.list__item-icon {
  width: 24px;
  height: 24px;
  font-size: 16px;
  line-height: 8px;
}

.you-tube-container {
  display: flex;
  padding: 8px 0;
  box-sizing: border-box;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 5;
  background: white;
}

.you-tube-container__searchbox {
  position: relative;
  width: calc(100% - 120px);
  box-sizing: border-box;
  display: flex;
  align-items: center;
}

.you-tube-container__close-btn {
  position: absolute;
  right: 0;
}

.you-tube-container__input {
  width: 100%;
  border: 1px solid lightgrey;
  padding: 8px 32px 8px 8px;
  border-radius: 8px;
  outline: none;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""