@dataclouder/ngx-cloud-storage 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,26 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Component, Input, Output, ViewChild } from '@angular/core';
2
+ import { inject, Injectable, input, output, ViewChild, Component, ChangeDetectorRef, Input } from '@angular/core';
3
3
  import { ImageCropperComponent } from 'ngx-image-cropper';
4
- import { NgIf } from '@angular/common';
5
- import * as i2 from '@angular/forms';
4
+ import * as i1 from '@angular/forms';
6
5
  import { FormsModule } from '@angular/forms';
7
- import * as i1$1 from '@angular/fire/storage';
8
- import { getStorage, listAll, deleteObject, getDownloadURL, ref as ref$1 } from '@angular/fire/storage';
9
- import { ref } from 'firebase/storage';
10
- import { lastValueFrom } from 'rxjs';
11
- import * as i1 from '@angular/fire/compat/storage';
12
- import * as i5 from 'primeng/dialog';
6
+ import { AngularFireStorage } from '@angular/fire/compat/storage';
7
+ import { getStorage, listAll, deleteObject, getDownloadURL, Storage, ref as ref$1 } from '@angular/fire/storage';
8
+ import { ref, getStorage as getStorage$1, listAll as listAll$1, getDownloadURL as getDownloadURL$1 } from 'firebase/storage';
9
+ import { lastValueFrom, BehaviorSubject } from 'rxjs';
10
+ import * as i4 from 'primeng/dialog';
13
11
  import { DialogModule } from 'primeng/dialog';
14
- import * as i6 from 'primeng/tooltip';
12
+ import * as i5 from 'primeng/tooltip';
15
13
  import { TooltipModule } from 'primeng/tooltip';
16
- import * as i3 from 'primeng/button';
14
+ import * as i2 from 'primeng/button';
17
15
  import { ButtonModule } from 'primeng/button';
18
- import * as i7 from 'primeng/message';
16
+ import * as i6 from 'primeng/message';
19
17
  import { MessageModule } from 'primeng/message';
20
- import * as i8 from 'primeng/select';
18
+ import * as i7 from 'primeng/select';
21
19
  import { SelectModule } from 'primeng/select';
22
- import * as i9 from 'primeng/inputtext';
20
+ import * as i8 from 'primeng/inputtext';
23
21
  import { InputTextModule } from 'primeng/inputtext';
24
- import * as i4 from 'primeng/api';
22
+ import * as i3 from 'primeng/api';
23
+ import { AsyncPipe } from '@angular/common';
25
24
 
26
25
  const AspectRatioOptions = [
27
26
  { value: '1:1', label: 'square', description: 'Square (1:1)', valueRatio: 1 / 1 },
@@ -84,8 +83,8 @@ const DEFAULT_SETTINGS = {
84
83
  };
85
84
 
86
85
  class MultiImagesStorageService {
87
- constructor(storage) {
88
- this.storage = storage;
86
+ constructor() {
87
+ this.storage = inject(AngularFireStorage);
89
88
  }
90
89
  async uploadImage(image, path) {
91
90
  try {
@@ -176,26 +175,26 @@ class MultiImagesStorageService {
176
175
  };
177
176
  return meta;
178
177
  }
179
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MultiImagesStorageService, deps: [{ token: i1.AngularFireStorage }], target: i0.ɵɵFactoryTarget.Injectable }); }
180
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MultiImagesStorageService, providedIn: 'root' }); }
178
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiImagesStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
179
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiImagesStorageService, providedIn: 'root' }); }
181
180
  }
182
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: MultiImagesStorageService, decorators: [{
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiImagesStorageService, decorators: [{
183
182
  type: Injectable,
184
183
  args: [{
185
184
  providedIn: 'root',
186
185
  }]
187
- }], ctorParameters: () => [{ type: i1.AngularFireStorage }] });
186
+ }] });
188
187
 
189
188
  class CropperComponent {
190
- constructor(multiImagesStorageService) {
191
- this.multiImagesStorageService = multiImagesStorageService;
189
+ constructor() {
190
+ this.multiImagesStorageService = inject(MultiImagesStorageService);
192
191
  // overrides name, path and resizeToWidth
193
- this.imageSettings = {};
194
- this.ratioType = AspectType.Square;
195
- this.resolutions = [ResolutionType.MediumLarge];
196
- this.imageUploaded = new EventEmitter();
197
- this.onImageCropped = new EventEmitter();
198
- this.onFileSelected = new EventEmitter();
192
+ this.imageSettings = input({});
193
+ this.ratioType = input(AspectType.Square);
194
+ this.resolutions = input([ResolutionType.MediumLarge]);
195
+ this.imageUploaded = output();
196
+ this.onImageCropped = output();
197
+ this.onFileSelected = output();
199
198
  this.fileMetadata = null;
200
199
  this.aspectRatio = 1;
201
200
  this.croppedImage = '';
@@ -206,13 +205,14 @@ class CropperComponent {
206
205
  this.showModal = false;
207
206
  }
208
207
  ngOnInit() {
209
- this.aspectRatio = AspectRatio[this.ratioType];
210
- if (this.imageSettings.path) {
211
- this.storagePath = `${this.imageSettings.path}/${this.imageSettings.fileName}.webp`;
208
+ this.aspectRatio = AspectRatio[this.ratioType()];
209
+ const imageSettings = this.imageSettings();
210
+ if (imageSettings.path) {
211
+ this.storagePath = `${imageSettings.path}/${imageSettings.fileName}.webp`;
212
212
  }
213
213
  }
214
214
  reloadPath() {
215
- this.storagePath = `${this.imageSettings.path}/${this.renameFile}.webp`;
215
+ this.storagePath = `${this.imageSettings().path}/${this.renameFile}.webp`;
216
216
  }
217
217
  async fileChangeEvent(event) {
218
218
  this.imageChangedEvent = event;
@@ -223,7 +223,7 @@ class CropperComponent {
223
223
  this.showModal = true; // Show modal when file is selected
224
224
  this.renameFile = this.fileMetadata?.name?.split('.')[0];
225
225
  console.log(this.renameFile);
226
- if (!this.imageSettings.fileName) {
226
+ if (!this.imageSettings().fileName) {
227
227
  this.reloadPath();
228
228
  }
229
229
  }
@@ -245,7 +245,7 @@ class CropperComponent {
245
245
  }
246
246
  async uploadToStorage(imageMulticrops) {
247
247
  // TODO: Nota si algo falla aquí puede causar inconsistencias en el sistema, ver como manejar errores
248
- const path = this.imageSettings.path;
248
+ const path = this.imageSettings().path;
249
249
  // const imageUploaded = await this.multiImagesStorageService.uploadImage(imageMulticrops, path);
250
250
  // this.modalRef.close();
251
251
  // console.log(imageUploaded);
@@ -268,40 +268,28 @@ class CropperComponent {
268
268
  closeModal() {
269
269
  this.showModal = false;
270
270
  }
271
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: CropperComponent, deps: [{ token: MultiImagesStorageService }], target: i0.ɵɵFactoryTarget.Component }); }
272
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.1", type: CropperComponent, isStandalone: true, selector: "app-cropper", inputs: { imageSettings: "imageSettings", ratioType: "ratioType", resolutions: "resolutions" }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n <div *ngIf=\"!isUploaded\">\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n <em *ngIf=\"!fileMetadata\">Carga una imagen para comenzar</em>\n </div>\n\n <span *ngIf=\"fileMetadata\">\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n</div>\n\n<div class=\"modal\" *ngIf=\"fileMetadata && !isUploaded\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n</div>\n\n<button *ngIf=\"croppedImage && !isUploaded\" [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }] }); }
271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CropperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
272
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: CropperComponent, isStandalone: true, selector: "app-cropper", inputs: { imageSettings: { classPropertyName: "imageSettings", publicName: "imageSettings", isSignal: true, isRequired: false, transformFunction: null }, ratioType: { classPropertyName: "ratioType", publicName: "ratioType", isSignal: true, isRequired: false, transformFunction: null }, resolutions: { classPropertyName: "resolutions", publicName: "resolutions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }] }); }
273
273
  }
274
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: CropperComponent, decorators: [{
274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CropperComponent, decorators: [{
275
275
  type: Component,
276
- args: [{ selector: 'app-cropper', standalone: true, imports: [NgIf, FormsModule, ImageCropperComponent], template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n <div *ngIf=\"!isUploaded\">\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n <em *ngIf=\"!fileMetadata\">Carga una imagen para comenzar</em>\n </div>\n\n <span *ngIf=\"fileMetadata\">\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n</div>\n\n<div class=\"modal\" *ngIf=\"fileMetadata && !isUploaded\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n</div>\n\n<button *ngIf=\"croppedImage && !isUploaded\" [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
277
- }], ctorParameters: () => [{ type: MultiImagesStorageService }], propDecorators: { imageSettings: [{
278
- type: Input
279
- }], ratioType: [{
280
- type: Input
281
- }], resolutions: [{
282
- type: Input
283
- }], imageUploaded: [{
284
- type: Output
285
- }], onImageCropped: [{
286
- type: Output
287
- }], onFileSelected: [{
288
- type: Output
289
- }], imageCropper: [{
276
+ args: [{ selector: 'app-cropper', standalone: true, imports: [FormsModule, ImageCropperComponent], template: "<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tama\u00F1o {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">\u00D7</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n", styles: [".options{display:flex}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
277
+ }], ctorParameters: () => [], propDecorators: { imageCropper: [{
290
278
  type: ViewChild,
291
279
  args: [ImageCropperComponent]
292
280
  }] } });
293
281
 
294
282
  class CropperComponentModal {
295
- constructor(multiImagesStorageService, changeDetectorRef) {
296
- this.multiImagesStorageService = multiImagesStorageService;
297
- this.changeDetectorRef = changeDetectorRef;
283
+ constructor() {
284
+ this.multiImagesStorageService = inject(MultiImagesStorageService);
285
+ this.changeDetectorRef = inject(ChangeDetectorRef);
298
286
  // overrides name, path and resizeToWidth
299
- this.imgStorageSettings = DEFAULT_SETTINGS;
300
- this.buttonLabel = 'Seleccionar archivo';
287
+ this.imgStorageSettings = input(DEFAULT_SETTINGS);
288
+ this.buttonLabel = input('Seleccionar archivo');
301
289
  this.currentStorage = {};
302
- this.imageUploaded = new EventEmitter();
303
- this.onImageCropped = new EventEmitter();
304
- this.onFileSelected = new EventEmitter();
290
+ this.imageUploaded = output();
291
+ this.onImageCropped = output();
292
+ this.onFileSelected = output();
305
293
  this.aspectRatioOptions = AspectRatioOptions;
306
294
  this.fileMetadata = null;
307
295
  this.displayDialog = false;
@@ -315,38 +303,39 @@ class CropperComponentModal {
315
303
  this.fileInputId = `file-upload-${Math.random().toString(36).substring(2, 11)}`;
316
304
  }
317
305
  ngOnInit() {
318
- if (!this.imgStorageSettings.path) {
306
+ if (!this.imgStorageSettings().path) {
319
307
  console.warn('⚠️ Remember to set imgStorageSettings, path and fileName are required , path example: /collection/id/subcollection ');
320
308
  }
321
309
  this.reloadPath();
322
310
  }
323
311
  reloadPath() {
324
312
  const randomCharacters = Math.random().toString(36).substring(2, 15);
325
- this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}-${randomCharacters}.webp`;
313
+ this.storagePath = `${this.imgStorageSettings().path}/${this.imgStorageSettings().fileName}-${randomCharacters}.webp`;
326
314
  }
327
315
  setSettingsForComponent() {
328
- console.log('setSettingsForComponent', this.imgStorageSettings);
316
+ const imgStorageSettings = this.imgStorageSettings();
317
+ console.log('setSettingsForComponent', imgStorageSettings);
329
318
  // TODO: remove all the imageSettings and keep only imgStorageSettings
330
- this.aspectRatioValue = this.imgStorageSettings?.cropSettings?.aspectRatio
331
- ? AspectRatio[this.imgStorageSettings?.cropSettings?.aspectRatio]
319
+ this.aspectRatioValue = imgStorageSettings?.cropSettings?.aspectRatio
320
+ ? AspectRatio[imgStorageSettings?.cropSettings?.aspectRatio]
332
321
  : AspectRatio[AspectType.Square];
333
- if (this.imgStorageSettings?.path) {
334
- this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}.webp`;
322
+ if (imgStorageSettings?.path) {
323
+ this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;
335
324
  }
336
- else if (this.imgStorageSettings.path) {
337
- this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}.webp`;
325
+ else if (imgStorageSettings.path) {
326
+ this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;
338
327
  }
339
- if (this.imgStorageSettings?.cropSettings?.resizeToWidth) {
340
- this.resizeToWidth = this.imgStorageSettings.cropSettings.resizeToWidth;
328
+ if (imgStorageSettings?.cropSettings?.resizeToWidth) {
329
+ this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;
341
330
  }
342
- else if (this.imgStorageSettings.cropSettings.resizeToWidth) {
343
- this.resizeToWidth = this.imgStorageSettings.cropSettings.resizeToWidth;
331
+ else if (imgStorageSettings.cropSettings.resizeToWidth) {
332
+ this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;
344
333
  }
345
- if (this.imgStorageSettings?.fileName) {
346
- this.renameFile = this.imgStorageSettings.fileName;
334
+ if (imgStorageSettings?.fileName) {
335
+ this.renameFile = imgStorageSettings.fileName;
347
336
  }
348
- else if (this.imgStorageSettings.fileName) {
349
- this.renameFile = this.imgStorageSettings.fileName;
337
+ else if (imgStorageSettings.fileName) {
338
+ this.renameFile = imgStorageSettings.fileName;
350
339
  }
351
340
  }
352
341
  async fileChangeEvent(event) {
@@ -362,7 +351,7 @@ class CropperComponentModal {
362
351
  .replace(/[^a-zA-Z0-9]/g, '')
363
352
  .slice(0, 80);
364
353
  console.log(this.renameFile);
365
- if (!this.imgStorageSettings.fileName) {
354
+ if (!this.imgStorageSettings().fileName) {
366
355
  this.reloadPath();
367
356
  }
368
357
  this.displayDialog = true;
@@ -401,32 +390,104 @@ class CropperComponentModal {
401
390
  this.aspectRatioValue = event.valueRatio;
402
391
  this.changeDetectorRef.detectChanges();
403
392
  }
404
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: CropperComponentModal, deps: [{ token: MultiImagesStorageService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
405
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.1", type: CropperComponentModal, isStandalone: true, selector: "dc-cropper-modal", inputs: { imgStorageSettings: "imgStorageSettings", buttonLabel: "buttonLabel", currentStorage: "currentStorage" }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel }}\n </label>\n</div>\n@if(displayDialog) {\n<!-- Cropper Dialog -->\n\n<p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings.path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n <div class=\"metadata-section\" *ngIf=\"fileMetadata\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i5.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i7.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i8.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
393
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CropperComponentModal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
394
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: CropperComponentModal, isStandalone: true, selector: "dc-cropper-modal", inputs: { imgStorageSettings: { classPropertyName: "imgStorageSettings", publicName: "imgStorageSettings", isSignal: true, isRequired: false, transformFunction: null }, buttonLabel: { classPropertyName: "buttonLabel", publicName: "buttonLabel", isSignal: true, isRequired: false, transformFunction: null }, currentStorage: { classPropertyName: "currentStorage", publicName: "currentStorage", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", onImageCropped: "onImageCropped", onFileSelected: "onFileSelected" }, viewQueries: [{ propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }], ngImport: i0, template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n@if(displayDialog) {\n <!-- Cropper Dialog -->\n\n <p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n </p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i6.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i8.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
406
395
  }
407
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: CropperComponentModal, decorators: [{
396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CropperComponentModal, decorators: [{
408
397
  type: Component,
409
- args: [{ selector: 'dc-cropper-modal', standalone: true, imports: [NgIf, FormsModule, ImageCropperComponent, ButtonModule, DialogModule, TooltipModule, MessageModule, SelectModule, InputTextModule], template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel }}\n </label>\n</div>\n@if(displayDialog) {\n<!-- Cropper Dialog -->\n\n<p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings.path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n <div class=\"metadata-section\" *ngIf=\"fileMetadata\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n</p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
410
- }], ctorParameters: () => [{ type: MultiImagesStorageService }, { type: i0.ChangeDetectorRef }], propDecorators: { imgStorageSettings: [{
411
- type: Input
412
- }], buttonLabel: [{
398
+ args: [{ selector: 'dc-cropper-modal', standalone: true, imports: [FormsModule, ImageCropperComponent, ButtonModule, DialogModule, TooltipModule, MessageModule, SelectModule, InputTextModule], template: "<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n@if(displayDialog) {\n <!-- Cropper Dialog -->\n\n <p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tama\u00F1o: {{ fileMetadata.size }}</span>\n </div>\n }\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n </p-dialog>\n}\n", styles: [":host{display:block}:host ::ng-deep .ngx-ic-overlay{width:100%!important}.upload-section{margin-bottom:1rem}.upload-section .file-input{display:none}.upload-section .upload-button{cursor:pointer}::ng-deep .cropper-dialog{max-width:90vw;width:800px}::ng-deep .cropper-dialog .p-dialog-content{padding:1.5rem}.settings-section{margin-bottom:1.5rem}.settings-section .settings-header{color:var(--text-color-secondary);margin-bottom:1rem}.settings-section .settings-grid{display:grid;gap:1rem;margin-bottom:1.5rem}.settings-section .settings-grid .setting-item .setting-label{font-weight:600;color:var(--text-color);display:block;margin-bottom:.5rem}.settings-section .settings-grid .setting-item .setting-value{color:var(--text-color-secondary);margin:0}.metadata-section{display:flex;gap:1.5rem;margin-bottom:1rem}.metadata-section .metadata-item{color:var(--text-color-secondary)}.rename-section{margin-bottom:5px}.rename-section .rename-input{width:100%;padding:.5rem;border:1px solid var(--surface-border);border-radius:4px}.rename-section .rename-input:disabled{background-color:var(--surface-200);cursor:not-allowed}.cropper-container-father{display:flex;justify-content:center;align-items:center;height:65vh}.dialog-footer{display:flex;justify-content:flex-end;gap:1rem}.btn-crop{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid transparent;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd;border-color:#0d6efd}.btn-crop :hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.file-input{display:none}.btn-upload{cursor:pointer;outline:0;display:inline-block;font-weight:400;line-height:1.5;text-align:center;background-color:transparent;border:1px solid #0d6efd;padding:6px 12px;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;color:#0d6efd}.btn-upload:hover{color:#fff;background-color:#0d6efd}.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:1000}.modal.show-modal{display:flex;align-items:center;justify-content:center}.modal .modal-content{background-color:#fff;border-radius:8px;width:90%;max-width:800px;max-height:90vh;overflow-y:auto;position:relative}.modal .modal-header{padding:1rem;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}.modal .modal-header h3{margin:0}.modal .modal-header .close-button{background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;color:#6c757d}.modal .modal-header .close-button:hover{color:#343a40}.modal .modal-body{padding:1rem;height:100vh;display:flex;flex-direction:column}.modal .modal-footer{padding:1rem;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end}\n"] }]
399
+ }], ctorParameters: () => [], propDecorators: { currentStorage: [{
413
400
  type: Input
414
- }], currentStorage: [{
415
- type: Input
416
- }], imageUploaded: [{
417
- type: Output
418
- }], onImageCropped: [{
419
- type: Output
420
- }], onFileSelected: [{
421
- type: Output
422
401
  }], imageCropper: [{
423
402
  type: ViewChild,
424
403
  args: [ImageCropperComponent]
425
404
  }] } });
426
405
 
406
+ class ImageStoragePreviewComponent {
407
+ constructor() {
408
+ this.storage = inject(AngularFireStorage);
409
+ this.imageSelected = output();
410
+ this.images$ = new BehaviorSubject([]);
411
+ this.loading$ = new BehaviorSubject(false);
412
+ this.error$ = new BehaviorSubject(null);
413
+ this.storagePath = '/images/resources';
414
+ this.subscriptions = [];
415
+ this.imgStorageSettings = {
416
+ path: this.storagePath,
417
+ cropSettings: {
418
+ aspectRatio: AspectType.Square,
419
+ resolutions: [ResolutionType.Small],
420
+ },
421
+ };
422
+ }
423
+ ngOnInit() {
424
+ this.loadImagesFromStorage();
425
+ }
426
+ ngOnDestroy() {
427
+ this.subscriptions.forEach((sub) => sub.unsubscribe());
428
+ }
429
+ /**
430
+ * Loads images from Firebase Storage at the specified path
431
+ */
432
+ async loadImagesFromStorage() {
433
+ try {
434
+ this.loading$.next(true);
435
+ this.error$.next(null);
436
+ const storage = getStorage$1();
437
+ const storageRef = ref(storage, this.storagePath);
438
+ const result = await listAll$1(storageRef);
439
+ if (result.items.length === 0) {
440
+ this.images$.next([]);
441
+ this.loading$.next(false);
442
+ return;
443
+ }
444
+ const imagePromises = result.items.map(async (itemRef) => {
445
+ try {
446
+ const url = await getDownloadURL$1(itemRef);
447
+ const image = {
448
+ url,
449
+ fullPath: itemRef.fullPath,
450
+ name: itemRef.name,
451
+ path: this.storagePath,
452
+ };
453
+ return image;
454
+ }
455
+ catch (error) {
456
+ console.error(`Error getting download URL for ${itemRef.fullPath}:`, error);
457
+ return null;
458
+ }
459
+ });
460
+ const images = (await Promise.all(imagePromises)).filter((img) => img !== null);
461
+ this.images$.next(images);
462
+ }
463
+ catch (error) {
464
+ console.error('Error loading images from storage:', error);
465
+ this.error$.next('Failed to load images from storage. Please try again later.');
466
+ }
467
+ finally {
468
+ this.loading$.next(false);
469
+ }
470
+ }
471
+ /**
472
+ * Refreshes the image list
473
+ */
474
+ refreshImages() {
475
+ this.loadImagesFromStorage();
476
+ }
477
+ selectImage(image) {
478
+ this.imageSelected.emit(image);
479
+ }
480
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ImageStoragePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
481
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.4", type: ImageStoragePreviewComponent, isStandalone: true, selector: "dc-image-storage-preview", outputs: { imageSelected: "imageSelected" }, ngImport: i0, template: "<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n", styles: [".image-storage-preview-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;padding:20px;max-width:1200px;margin:0 auto}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.header h2{margin:0;color:#333}.refresh-btn{background-color:#4285f4;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px;transition:background-color .2s}.refresh-btn:hover{background-color:#3367d6}.refresh-btn:disabled{background-color:#a9a9a9;cursor:not-allowed}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 0}.spinner{border:4px solid rgba(0,0,0,.1);border-radius:50%;border-top:4px solid #4285f4;width:30px;height:30px;animation:spin 1s linear infinite;margin-bottom:15px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.error-container{background-color:#ffebee;border:1px solid #ffcdd2;border-radius:4px;padding:16px;margin:20px 0;text-align:center}.error-message{color:#d32f2f;margin-bottom:10px}.error-container button{background-color:#d32f2f;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px}.images-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.image-card{border-radius:8px;overflow:hidden;box-shadow:0 2px 10px #0000001a;transition:transform .2s,box-shadow .2s;background-color:#fff}.image-card:hover{transform:translateY(-5px);box-shadow:0 5px 15px #00000026}.image-container{height:200px;overflow:hidden;position:relative;background-color:#f5f5f5}.image-container img{width:100%;height:100%;object-fit:cover;transition:transform .3s}.image-card:hover .image-container img{transform:scale(1.05)}.image-info{padding:15px}.image-name{margin:0 0 10px;font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.image-actions{display:flex;justify-content:flex-end}.action-btn{background-color:#4285f4;color:#fff;text-decoration:none;border-radius:4px;padding:6px 12px;font-size:12px;transition:background-color .2s}.action-btn:hover{background-color:#3367d6}.no-images{grid-column:1 / -1;text-align:center;padding:40px 0;color:#757575;background-color:#f5f5f5;border-radius:8px}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: CropperComponentModal, selector: "dc-cropper-modal", inputs: ["imgStorageSettings", "buttonLabel", "currentStorage"], outputs: ["imageUploaded", "onImageCropped", "onFileSelected"] }] }); }
482
+ }
483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ImageStoragePreviewComponent, decorators: [{
484
+ type: Component,
485
+ args: [{ selector: 'dc-image-storage-preview', standalone: true, imports: [AsyncPipe, CropperComponentModal], template: "<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n", styles: [".image-storage-preview-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;padding:20px;max-width:1200px;margin:0 auto}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.header h2{margin:0;color:#333}.refresh-btn{background-color:#4285f4;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px;transition:background-color .2s}.refresh-btn:hover{background-color:#3367d6}.refresh-btn:disabled{background-color:#a9a9a9;cursor:not-allowed}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 0}.spinner{border:4px solid rgba(0,0,0,.1);border-radius:50%;border-top:4px solid #4285f4;width:30px;height:30px;animation:spin 1s linear infinite;margin-bottom:15px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.error-container{background-color:#ffebee;border:1px solid #ffcdd2;border-radius:4px;padding:16px;margin:20px 0;text-align:center}.error-message{color:#d32f2f;margin-bottom:10px}.error-container button{background-color:#d32f2f;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:14px}.images-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.image-card{border-radius:8px;overflow:hidden;box-shadow:0 2px 10px #0000001a;transition:transform .2s,box-shadow .2s;background-color:#fff}.image-card:hover{transform:translateY(-5px);box-shadow:0 5px 15px #00000026}.image-container{height:200px;overflow:hidden;position:relative;background-color:#f5f5f5}.image-container img{width:100%;height:100%;object-fit:cover;transition:transform .3s}.image-card:hover .image-container img{transform:scale(1.05)}.image-info{padding:15px}.image-name{margin:0 0 10px;font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.image-actions{display:flex;justify-content:flex-end}.action-btn{background-color:#4285f4;color:#fff;text-decoration:none;border-radius:4px;padding:6px 12px;font-size:12px;transition:background-color .2s}.action-btn:hover{background-color:#3367d6}.no-images{grid-column:1 / -1;text-align:center;padding:40px 0;color:#757575;background-color:#f5f5f5;border-radius:8px}\n"] }]
486
+ }], ctorParameters: () => [] });
487
+
427
488
  class DCFilesCacheService {
428
- constructor(storage) {
429
- this.storage = storage;
489
+ constructor() {
490
+ this.storage = inject(Storage);
430
491
  this.files = {};
431
492
  }
432
493
  async getURLSrcFile(path) {
@@ -460,15 +521,113 @@ class DCFilesCacheService {
460
521
  const blob = await this.getBlob(url);
461
522
  return URL.createObjectURL(blob);
462
523
  }
463
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCFilesCacheService, deps: [{ token: i1$1.Storage }], target: i0.ɵɵFactoryTarget.Injectable }); }
464
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCFilesCacheService, providedIn: 'root' }); }
524
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCFilesCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
525
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCFilesCacheService, providedIn: 'root' }); }
526
+ }
527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DCFilesCacheService, decorators: [{
528
+ type: Injectable,
529
+ args: [{
530
+ providedIn: 'root',
531
+ }]
532
+ }], ctorParameters: () => [] });
533
+
534
+ class MultiObjectStorageService {
535
+ constructor() {
536
+ this.storage = inject(AngularFireStorage);
537
+ }
538
+ /**
539
+ * Uploads a Blob or File object to a specified path in Firebase Storage.
540
+ * @param objectToUpload The Blob or File to upload.
541
+ * @param path The desired storage path (e.g., 'documents/report.pdf').
542
+ * @returns A promise that resolves with the storage metadata of the uploaded object.
543
+ * @throws Throws an error if the upload fails.
544
+ */
545
+ async uploadObject(objectToUpload, path) {
546
+ try {
547
+ const refStorage = this.storage.ref(path);
548
+ const task = await refStorage.put(objectToUpload);
549
+ const { fullPath, bucket, name } = task.metadata;
550
+ const url = await lastValueFrom(refStorage.getDownloadURL());
551
+ const storageData = { url, path: fullPath, bucket, name };
552
+ return storageData;
553
+ }
554
+ catch (error) {
555
+ console.error(`Error uploading object to path "${path}": `, error);
556
+ // Re-throw the error to allow calling code to handle it
557
+ throw error;
558
+ }
559
+ }
560
+ /**
561
+ * Deletes all objects within a specified directory path in Firebase Storage.
562
+ * WARNING: Use with extreme caution as this will permanently delete all files in the directory.
563
+ * @param directoryPath The path to the directory to delete (e.g., 'users/userId/files/').
564
+ * @returns A promise that resolves when the deletion attempt is complete.
565
+ */
566
+ async deleteDirectory(directoryPath) {
567
+ const storage = getStorage();
568
+ const directoryRef = ref(storage, directoryPath);
569
+ try {
570
+ const res = await listAll(directoryRef);
571
+ const deletePromises = [];
572
+ res.items.forEach((itemRef) => {
573
+ console.log(`Deleting object: ${itemRef.fullPath}`);
574
+ deletePromises.push(deleteObject(itemRef));
575
+ });
576
+ // You might want to handle potential errors during individual deletions if needed
577
+ await Promise.all(deletePromises);
578
+ console.log(`Successfully deleted objects in directory: ${directoryPath}`);
579
+ }
580
+ catch (error) {
581
+ console.error(`Error deleting objects in directory "${directoryPath}":`, error);
582
+ // Optionally re-throw or handle the error appropriately
583
+ throw error;
584
+ }
585
+ }
586
+ /**
587
+ * Deletes a single object from Firebase Storage based on its full path.
588
+ * @param objectPath The full path of the object to delete (e.g., 'images/profile.jpg').
589
+ * @returns A promise that resolves when the deletion is complete.
590
+ */
591
+ async deleteObjectByPath(objectPath) {
592
+ const storageRef = this.storage.ref(objectPath);
593
+ try {
594
+ await lastValueFrom(storageRef.delete());
595
+ console.log(`Object deleted successfully: ${objectPath}`);
596
+ }
597
+ catch (error) {
598
+ console.error(`Error deleting object at path "${objectPath}":`, error);
599
+ // Optionally re-throw or handle the error appropriately
600
+ throw error;
601
+ }
602
+ }
603
+ /**
604
+ * Private helper to get metadata after an upload task completes.
605
+ * @param task The AngularFireUploadTask.
606
+ * @returns A promise resolving with the object's storage metadata.
607
+ */
608
+ async uploadAndGetObjectMetadata(task) {
609
+ const snap = await task;
610
+ const { fullPath, bucket, name } = snap.metadata;
611
+ const storage = getStorage();
612
+ const storageRef = ref(storage, fullPath);
613
+ const url = await getDownloadURL(storageRef);
614
+ const meta = {
615
+ url,
616
+ path: fullPath, // Use fullPath for the 'path' property
617
+ bucket,
618
+ name,
619
+ };
620
+ return meta;
621
+ }
622
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiObjectStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
623
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiObjectStorageService, providedIn: 'root' }); }
465
624
  }
466
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImport: i0, type: DCFilesCacheService, decorators: [{
625
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiObjectStorageService, decorators: [{
467
626
  type: Injectable,
468
627
  args: [{
469
628
  providedIn: 'root',
470
629
  }]
471
- }], ctorParameters: () => [{ type: i1$1.Storage }] });
630
+ }] });
472
631
 
473
632
  /*
474
633
  * Public API Surface of storage-uploader
@@ -478,5 +637,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.1", ngImpor
478
637
  * Generated bundle index. Do not edit.
479
638
  */
480
639
 
481
- export { AspectRatio, AspectRatio2, AspectRatioOptions, AspectType, CropperComponent, CropperComponentModal, DCFilesCacheService, DEFAULT_SETTINGS, MultiImagesStorageService, ResolutionType };
640
+ export { AspectRatio, AspectRatio2, AspectRatioOptions, AspectType, CropperComponent, CropperComponentModal, DCFilesCacheService, DEFAULT_SETTINGS, ImageStoragePreviewComponent, MultiImagesStorageService, MultiObjectStorageService, ResolutionType };
482
641
  //# sourceMappingURL=dataclouder-ngx-cloud-storage.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataclouder-ngx-cloud-storage.mjs","sources":["../../../../projects/dataclouder/ngx-cloud-storage/src/lib/classes/cropper.classes.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/services/multi-images-storage.service.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper/cropper.component.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper/cropper.component.html","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper-modal/cropper-modal.component.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper-modal/cropper-modal.component.html","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/services/dc-files-cache.service.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/public-api.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/dataclouder-ngx-cloud-storage.ts"],"sourcesContent":["export interface StorageImageSettings {\n path?: string;\n fileName?: string;\n cropSettings?: ImageCropSettings;\n}\n\nexport interface ImageCropSettings {\n resizeToWidth?: number;\n resolutions: Array<number>; // 400, 800, 1200, 1600\n aspectRatio: AspectType;\n}\n\nexport interface CropImageSettings {\n // Resolutions should be here.\n path: string;\n fileName?: string;\n resizeToWidth?: number;\n}\n\nexport interface ImageMultipleCrops {\n file: File;\n defaultImageBlob?: Blob;\n imagesBlobs: { [resolution: number]: Blob };\n settings: { renameFile: string; width?: number };\n}\n\nexport const AspectRatioOptions: AspectRatioOption[] = [\n { value: '1:1', label: 'square', description: 'Square (1:1)', valueRatio: 1 / 1 },\n { value: '1:2', label: 'vertical_1_2', description: 'Vertical (1:2)', valueRatio: 1 / 2 },\n { value: '2:3', label: 'vertical_2_3', description: 'Vertical (2:3)', valueRatio: 2 / 3 },\n { value: '3:4', label: 'vertical_3_4', description: 'Vertical (3:4)', valueRatio: 3 / 4 },\n { value: '4:5', label: 'vertical_4_5', description: 'Vertical (4:5)', valueRatio: 4 / 5 },\n { value: '9:16', label: 'vertical_9_16', description: 'Vertical (9:16)', valueRatio: 9 / 16 },\n { value: '2:1', label: 'horizontal_2_1', description: 'Horizontal (2:1)', valueRatio: 2 / 1 },\n { value: '3:2', label: 'horizontal_3_2', description: 'Horizontal (3:2)', valueRatio: 3 / 2 },\n { value: '4:3', label: 'horizontal_4_3', description: 'Horizontal (4:3)', valueRatio: 4 / 3 },\n { value: '5:4', label: 'horizontal_5_4', description: 'Horizontal (5:4)', valueRatio: 5 / 4 },\n { value: '16:9', label: 'horizontal_16_9', description: 'Horizontal (16:9)', valueRatio: 16 / 9 },\n];\n\nexport interface AspectRatioOption {\n label: string;\n description: string;\n value: string;\n valueRatio: number;\n}\n\nexport enum AspectType {\n Square = 'square',\n Rectangle = 'rectangle',\n Banner = 'banner',\n RectangleLarge = 'rectangleLarge',\n Vertical_9_16 = 'vertical_9_16',\n Vertical_3_5 = 'vertical_3_5',\n Vertical_2_3 = 'vertical_2_3',\n}\n\n// Creo que seria bueno refactorizar para solo enviar aspect ratio asi\nexport enum AspectRatio2 {\n // Vertical\n '9:16' = 16 / 9,\n '3:5' = 3 / 5,\n '5:8' = 5 / 8,\n '2:3' = 2 / 3,\n '1:1' = 1 / 1,\n}\n\nexport enum ResolutionType {\n Small = 200,\n Medium = 400,\n MediumLarge = 800,\n Large = 1200,\n VeryLarge = 1600,\n}\n\nexport const AspectRatio = {\n [AspectType.Square]: 1 / 1,\n [AspectType.Rectangle]: 16 / 9,\n [AspectType.Vertical_9_16]: 9 / 16,\n [AspectType.RectangleLarge]: 16 / 8,\n [AspectType.Banner]: 16 / 7,\n [AspectType.Vertical_3_5]: 3 / 5,\n [AspectType.Vertical_2_3]: 2 / 3,\n};\n\nexport interface ImgStorageData extends CloudStorageData {\n name?: string;\n bucket?: string;\n url?: string;\n path?: string; // path where the file is in the storage\n fullPath?: string; // path + name\n resolution?: string;\n resolutions?: any;\n}\n\nexport interface CloudStorageData {\n bucket?: string;\n url?: string;\n path?: string; // path where the file is in the storage\n}\n\nexport const DEFAULT_SETTINGS: StorageImageSettings = {\n path: '/default-collection/id/please-change-this-subcollection',\n fileName: 'image',\n cropSettings: {\n aspectRatio: AspectType.Square,\n resolutions: [ResolutionType.Small, ResolutionType.MediumLarge],\n resizeToWidth: 450,\n },\n};\n","import { Injectable } from '@angular/core';\nimport { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/compat/storage';\nimport { getDownloadURL, getStorage, deleteObject, listAll } from '@angular/fire/storage';\n\nimport { ref } from 'firebase/storage';\nimport { lastValueFrom } from 'rxjs';\nimport { ImageMultipleCrops, ImgStorageData } from '../classes/cropper.classes';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class MultiImagesStorageService {\n constructor(private storage: AngularFireStorage) {}\n\n public async uploadImage(image: Blob, path: string): Promise<ImgStorageData> {\n try {\n const refStorage = this.storage.ref(path);\n const task = await refStorage.put(image);\n const { fullPath, bucket } = task.metadata;\n const url = await lastValueFrom(refStorage.getDownloadURL());\n const imageStorage = { url, path: fullPath, bucket };\n return imageStorage;\n } catch (error) {\n console.error('uploading image error: ', error);\n return null;\n }\n }\n\n public uploadImage2(imageMulticrops: ImageMultipleCrops, path: string): Promise<ImgStorageData> {\n // path is usually [products/id] will create a new folder with the name and upload the images\n\n const blobs = imageMulticrops.imagesBlobs;\n\n const tasks: Array<Promise<any>> = [];\n let fileName = imageMulticrops.settings?.renameFile ?? imageMulticrops.file.name;\n fileName = fileName.split('.')[0];\n\n // load the default image jpeg\n path = `${path}/${fileName}`;\n const defaultImagePath = `${path}/${fileName}-400W.jpeg`;\n const refStorage = this.storage.ref(defaultImagePath);\n const task = refStorage.put(imageMulticrops.defaultImageBlob);\n\n tasks.push(this.uploadAndGetUrl(task, 'default'));\n\n // Upload webp images\n for (const resolutionStr of Object.keys(blobs)) {\n const fullName = `${fileName}-${resolutionStr}W.webp`;\n const filePath = `${path}/${fullName}`;\n\n const refStorage = this.storage.ref(filePath);\n\n const resolution = Number(resolutionStr);\n const task = refStorage.put(blobs[resolution]);\n tasks.push(this.uploadAndGetUrl(task, resolution + 'W'));\n }\n\n return Promise.all(tasks).then(async (upladedImages) => {\n let defaultImage: any = {};\n let resolutionsUrls: any = {};\n\n for (const image of upladedImages) {\n if (image.resolution === 'default') {\n defaultImage = image;\n } else {\n resolutionsUrls[image.resolution] = image.url;\n }\n }\n defaultImage['resolutions'] = resolutionsUrls;\n defaultImage['path'] = path;\n\n return defaultImage;\n });\n }\n\n public async delete_directory(imagePath: string): Promise<void> {\n // WARNING!! user very carefully could delete whatever folder\n const storage = getStorage();\n const directoryRef = ref(storage, imagePath);\n\n listAll(directoryRef)\n .then((res) => {\n res.items.forEach((itemRef) => {\n console.log(itemRef);\n deleteObject(itemRef);\n });\n })\n .catch((error) => {\n console.error('error al eliminar imagenes de cloud storage', error);\n });\n }\n\n public async deleteImage(imagePath: string): Promise<void> {\n const storageRef = this.storage.ref(imagePath);\n storageRef.delete().subscribe((res) => {\n console.log('image deleted', res);\n });\n }\n\n private async uploadAndGetUrl(task: AngularFireUploadTask, resolution: string): Promise<ImgStorageData> {\n const snap = await task;\n const { fullPath, bucket, name } = snap.metadata;\n const storage = getStorage();\n const storageRef = ref(storage, fullPath);\n const url = await getDownloadURL(storageRef);\n const meta: ImgStorageData = {\n url,\n fullPath,\n bucket,\n name,\n resolution,\n path: '',\n resolutions: {},\n };\n\n return meta;\n }\n}\n","import { Component, Input, OnInit, Output, EventEmitter, ViewChild } from '@angular/core';\nimport { ImageCroppedEvent, ImageCropperComponent, LoadedImage, base64ToFile } from 'ngx-image-cropper';\nimport { Observable } from 'rxjs';\nimport { AspectRatio, AspectType, ImageMultipleCrops, CropImageSettings, ResolutionType } from '../../classes/cropper.classes';\nimport { NgIf } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MultiImagesStorageService } from '../../services/multi-images-storage.service';\n\n@Component({\n selector: 'app-cropper',\n templateUrl: './cropper.component.html',\n styleUrls: ['./cropper.component.scss'],\n standalone: true,\n imports: [NgIf, FormsModule, ImageCropperComponent],\n})\nexport class CropperComponent implements OnInit {\n // overrides name, path and resizeToWidth\n @Input() imageSettings: CropImageSettings = {} as any;\n\n @Input() ratioType: AspectType | string = AspectType.Square;\n\n @Input() resolutions: Array<number> = [ResolutionType.MediumLarge];\n\n @Output() imageUploaded = new EventEmitter<any>();\n\n @Output() onImageCropped = new EventEmitter<ImageMultipleCrops>();\n\n @Output() onFileSelected = new EventEmitter<any>();\n\n @ViewChild(ImageCropperComponent) imageCropper!: ImageCropperComponent;\n\n public fileMetadata: File | null = null;\n public imageChangedEvent!: Event;\n\n public aspectRatio: number = 1;\n\n public croppedImage: any = '';\n\n public isLoading = false;\n public isUploaded = false;\n public renameFile: any = '';\n public storagePath: string = '';\n public showModal = false;\n\n constructor(private multiImagesStorageService: MultiImagesStorageService) {}\n\n ngOnInit(): void {\n this.aspectRatio = AspectRatio[this.ratioType];\n if (this.imageSettings.path) {\n this.storagePath = `${this.imageSettings.path}/${this.imageSettings.fileName}.webp`;\n }\n }\n\n public reloadPath(): void {\n this.storagePath = `${this.imageSettings.path}/${this.renameFile}.webp`;\n }\n\n async fileChangeEvent(event: any) {\n this.imageChangedEvent = event;\n const file = event?.target?.files[0];\n if (file) {\n this.fileMetadata = file;\n this.onFileSelected.emit(file);\n this.showModal = true; // Show modal when file is selected\n this.renameFile = this.fileMetadata?.name?.split('.')[0];\n console.log(this.renameFile);\n\n if (!this.imageSettings.fileName) {\n this.reloadPath();\n }\n }\n }\n\n onInnerImageCropped(event: ImageCroppedEvent) {\n this.croppedImage = event.base64;\n }\n\n imageLoaded(image: LoadedImage) {\n // show cropper\n }\n\n loadImageFailed() {\n console.error('fallo al cargar la imagen');\n }\n\n public downloadURL!: Observable<string>;\n\n public async simpleCropAndUpload() {\n const imageCropped: any = await this.imageCropper.crop();\n const imgStorage = await this.multiImagesStorageService.uploadImage(imageCropped?.blob, this.storagePath);\n this.imageUploaded.emit(imgStorage);\n this.closeModal();\n }\n\n public async uploadToStorage(imageMulticrops: ImageMultipleCrops): Promise<void> {\n // TODO: Nota si algo falla aquí puede causar inconsistencias en el sistema, ver como manejar errores\n const path = this.imageSettings.path;\n // const imageUploaded = await this.multiImagesStorageService.uploadImage(imageMulticrops, path);\n // this.modalRef.close();\n // console.log(imageUploaded);\n // const image = { type: 'cover', ...imageUploaded };\n\n // TODO: creo que esta parte va en el componente que llama a este componente\n // if (!this.lesson.media) {\n // this.lesson.media = {};\n // this.lesson.media.images = [image];\n // } else {\n // // solo sustituir el cover si ya existe\n // const currentCover = this.lesson.media.images.find((img) => img.type === 'cover');\n // this.multiImagesStorageService.delete_directory(currentCover.path);\n\n // this.lesson.media.images = this.lesson.media.images.filter((img) => img.type !== 'cover');\n\n // this.lesson.media.images.push(image);\n // }\n\n // await this.saveLesson();\n // this.updateCover();\n // this.imageUploaded.emit(image);\n }\n\n closeModal(): void {\n this.showModal = false;\n }\n}\n","<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n <div *ngIf=\"!isUploaded\">\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n <em *ngIf=\"!fileMetadata\">Carga una imagen para comenzar</em>\n </div>\n\n <span *ngIf=\"fileMetadata\">\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n\n <span style=\"margin: 1px 20px\"> tamaño {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n</div>\n\n<div class=\"modal\" *ngIf=\"fileMetadata && !isUploaded\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">×</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n</div>\n\n<button *ngIf=\"croppedImage && !isUploaded\" [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n","import { Component, Input, OnInit, Output, EventEmitter, ViewChild, ChangeDetectorRef, Attribute } from '@angular/core';\nimport { NgIf } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\nimport { DialogModule } from 'primeng/dialog';\n\nimport { ImageCroppedEvent, ImageCropperComponent, LoadedImage } from 'ngx-image-cropper';\nimport { Observable } from 'rxjs';\n\nimport { MultiImagesStorageService } from '../../services/multi-images-storage.service';\nimport {\n AspectRatio,\n AspectType,\n ImageMultipleCrops,\n StorageImageSettings,\n ImgStorageData,\n AspectRatioOptions,\n AspectRatioOption,\n DEFAULT_SETTINGS,\n} from '../../classes/cropper.classes';\nimport { TooltipModule } from 'primeng/tooltip';\n\nimport { ButtonModule } from 'primeng/button';\nimport { MessageModule } from 'primeng/message';\nimport { SelectModule } from 'primeng/select';\nimport { InputTextModule } from 'primeng/inputtext';\n\n@Component({\n selector: 'dc-cropper-modal',\n templateUrl: './cropper-modal.component.html',\n styleUrls: ['./cropper-modal.component.scss'],\n standalone: true,\n imports: [NgIf, FormsModule, ImageCropperComponent, ButtonModule, DialogModule, TooltipModule, MessageModule, SelectModule, InputTextModule],\n})\nexport class CropperComponentModal implements OnInit {\n // overrides name, path and resizeToWidth\n\n @Input() imgStorageSettings: StorageImageSettings = DEFAULT_SETTINGS;\n @Input() buttonLabel: string = 'Seleccionar archivo';\n @Input() currentStorage: ImgStorageData = {} as any;\n\n @Output() imageUploaded = new EventEmitter<ImgStorageData>();\n @Output() onImageCropped = new EventEmitter<ImageMultipleCrops>();\n @Output() onFileSelected = new EventEmitter<any>();\n\n @ViewChild(ImageCropperComponent) imageCropper!: ImageCropperComponent;\n\n public aspectRatioOptions = AspectRatioOptions;\n public fileMetadata: File | null = null;\n public imageChangedEvent!: Event;\n public displayDialog = false;\n public aspectRatioValue: number = 1;\n public croppedImage: any = '';\n public renameFile: any = '';\n public storagePath: string = '';\n public downloadURL!: Observable<string>;\n public resizeToWidth: number = 450;\n public ratioSelected: any = null;\n\n // Add a unique identifier for the file input\n public fileInputId: string;\n\n constructor(private multiImagesStorageService: MultiImagesStorageService, private changeDetectorRef: ChangeDetectorRef) {\n // Generate random ID for file input\n this.fileInputId = `file-upload-${Math.random().toString(36).substring(2, 11)}`;\n }\n\n ngOnInit(): void {\n if (!this.imgStorageSettings.path) {\n console.warn('⚠️ Remember to set imgStorageSettings, path and fileName are required , path example: /collection/id/subcollection ');\n }\n this.reloadPath();\n }\n\n public reloadPath(): void {\n const randomCharacters = Math.random().toString(36).substring(2, 15);\n this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}-${randomCharacters}.webp`;\n }\n\n private setSettingsForComponent(): void {\n console.log('setSettingsForComponent', this.imgStorageSettings);\n // TODO: remove all the imageSettings and keep only imgStorageSettings\n\n this.aspectRatioValue = this.imgStorageSettings?.cropSettings?.aspectRatio\n ? AspectRatio[this.imgStorageSettings?.cropSettings?.aspectRatio]\n : AspectRatio[AspectType.Square];\n\n if (this.imgStorageSettings?.path) {\n this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}.webp`;\n } else if (this.imgStorageSettings.path) {\n this.storagePath = `${this.imgStorageSettings.path}/${this.imgStorageSettings.fileName}.webp`;\n }\n if (this.imgStorageSettings?.cropSettings?.resizeToWidth) {\n this.resizeToWidth = this.imgStorageSettings.cropSettings.resizeToWidth;\n } else if (this.imgStorageSettings.cropSettings.resizeToWidth) {\n this.resizeToWidth = this.imgStorageSettings.cropSettings.resizeToWidth;\n }\n if (this.imgStorageSettings?.fileName) {\n this.renameFile = this.imgStorageSettings.fileName;\n } else if (this.imgStorageSettings.fileName) {\n this.renameFile = this.imgStorageSettings.fileName;\n }\n }\n\n async fileChangeEvent(event: any) {\n this.setSettingsForComponent();\n\n console.log(this.fileInputId);\n\n this.imageChangedEvent = event;\n const file = event?.target?.files[0];\n if (file) {\n this.fileMetadata = file;\n this.onFileSelected.emit(file);\n this.renameFile = this.fileMetadata?.name\n ?.split('.')[0]\n .replace(/[^a-zA-Z0-9]/g, '')\n .slice(0, 80);\n\n console.log(this.renameFile);\n\n if (!this.imgStorageSettings.fileName) {\n this.reloadPath();\n }\n this.displayDialog = true;\n this.changeDetectorRef.detectChanges();\n }\n }\n\n onInnerImageCropped(event: ImageCroppedEvent) {\n this.croppedImage = event.base64;\n }\n\n imageLoaded(image: LoadedImage) {\n this.changeDetectorRef.detectChanges();\n }\n\n cropperReady() {\n this.changeDetectorRef.detectChanges();\n }\n\n loadImageFailed() {\n console.error('fallo al cargar la imagen');\n }\n\n public async simpleCropAndUpload() {\n console.log(this.fileInputId);\n\n console.log('simpleCropAndUpload');\n const imageCropped: any = await this.imageCropper.crop();\n const imgStorage = await this.multiImagesStorageService.uploadImage(imageCropped?.blob, this.storagePath);\n if (this.currentStorage?.path) {\n console.warn('deleting current Image', this.currentStorage?.path);\n this.multiImagesStorageService.deleteImage(this.currentStorage.path);\n }\n console.log('imgStorage', imgStorage);\n this.imageUploaded.emit(imgStorage);\n this.displayDialog = false;\n this.changeDetectorRef.detectChanges();\n }\n\n public changeRatio(event: AspectRatioOption) {\n console.log('changeRatio', event);\n // this.imgStorageSettings.cropSettings.aspectRatio = event.valueRatio;\n this.aspectRatioValue = event.valueRatio;\n this.changeDetectorRef.detectChanges();\n }\n}\n","<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel }}\n </label>\n</div>\n@if(displayDialog) {\n<!-- Cropper Dialog -->\n\n<p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings.path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n <div class=\"metadata-section\" *ngIf=\"fileMetadata\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tamaño: {{ fileMetadata.size }}</span>\n </div>\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n</p-dialog>\n}\n","import { Injectable } from '@angular/core';\nimport { getDownloadURL, ref, Storage } from '@angular/fire/storage';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class DCFilesCacheService {\n constructor(private storage: Storage) {}\n\n public files: { [key: string]: string } = {};\n\n public async getURLSrcFile(path: string): Promise<string> {\n if (path in this.files) {\n return this.files[path];\n } else {\n const url = await getDownloadURL(ref(this.storage, path));\n const localUrl = await this.donwloadFileAndGetLocalURL(url);\n this.files[path] = localUrl;\n return localUrl;\n }\n }\n\n public getBlob(url: string): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.responseType = 'blob';\n xhr.overrideMimeType('audio/mp3');\n\n xhr.onload = (event) => {\n var blob = xhr.response;\n resolve(blob);\n };\n xhr.onerror = (event) => {\n reject(event);\n };\n\n xhr.open('GET', url);\n xhr.send();\n });\n }\n\n public async donwloadFileAndGetLocalURL(url: string) {\n const blob = await this.getBlob(url);\n\n return URL.createObjectURL(blob);\n }\n}\n","/*\n * Public API Surface of storage-uploader\n */\n\nexport * from './lib/components/cropper/cropper.component';\nexport * from './lib/components/cropper-modal/cropper-modal.component';\nexport * from './lib/classes/cropper.classes';\n\nexport * from './lib/services/multi-images-storage.service';\nexport * from './lib/services/dc-files-cache.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.MultiImagesStorageService","ref","i1"],"mappings":"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"}
1
+ {"version":3,"file":"dataclouder-ngx-cloud-storage.mjs","sources":["../../../../projects/dataclouder/ngx-cloud-storage/src/lib/classes/cropper.classes.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/services/multi-images-storage.service.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper/cropper.component.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper/cropper.component.html","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper-modal/cropper-modal.component.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/cropper-modal/cropper-modal.component.html","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/image-storage-preview/image-storage-preview.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/components/image-storage-preview/image-storage-preview.html","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/services/dc-files-cache.service.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/lib/services/multi-object-storage.service.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/public-api.ts","../../../../projects/dataclouder/ngx-cloud-storage/src/dataclouder-ngx-cloud-storage.ts"],"sourcesContent":["export interface StorageImageSettings {\n path?: string;\n fileName?: string;\n cropSettings?: ImageCropSettings;\n}\n\nexport interface ImageCropSettings {\n resizeToWidth?: number;\n resolutions: Array<number>; // 400, 800, 1200, 1600\n aspectRatio: AspectType;\n}\n\nexport interface CropImageSettings {\n // Resolutions should be here.\n path: string;\n fileName?: string;\n resizeToWidth?: number;\n}\n\nexport interface ImageMultipleCrops {\n file: File;\n defaultImageBlob?: Blob;\n imagesBlobs: { [resolution: number]: Blob };\n settings: { renameFile: string; width?: number };\n}\n\nexport const AspectRatioOptions: AspectRatioOption[] = [\n { value: '1:1', label: 'square', description: 'Square (1:1)', valueRatio: 1 / 1 },\n { value: '1:2', label: 'vertical_1_2', description: 'Vertical (1:2)', valueRatio: 1 / 2 },\n { value: '2:3', label: 'vertical_2_3', description: 'Vertical (2:3)', valueRatio: 2 / 3 },\n { value: '3:4', label: 'vertical_3_4', description: 'Vertical (3:4)', valueRatio: 3 / 4 },\n { value: '4:5', label: 'vertical_4_5', description: 'Vertical (4:5)', valueRatio: 4 / 5 },\n { value: '9:16', label: 'vertical_9_16', description: 'Vertical (9:16)', valueRatio: 9 / 16 },\n { value: '2:1', label: 'horizontal_2_1', description: 'Horizontal (2:1)', valueRatio: 2 / 1 },\n { value: '3:2', label: 'horizontal_3_2', description: 'Horizontal (3:2)', valueRatio: 3 / 2 },\n { value: '4:3', label: 'horizontal_4_3', description: 'Horizontal (4:3)', valueRatio: 4 / 3 },\n { value: '5:4', label: 'horizontal_5_4', description: 'Horizontal (5:4)', valueRatio: 5 / 4 },\n { value: '16:9', label: 'horizontal_16_9', description: 'Horizontal (16:9)', valueRatio: 16 / 9 },\n];\n\nexport interface AspectRatioOption {\n label: string;\n description: string;\n value: string;\n valueRatio: number;\n}\n\nexport enum AspectType {\n Square = 'square',\n Rectangle = 'rectangle',\n Banner = 'banner',\n RectangleLarge = 'rectangleLarge',\n Vertical_9_16 = 'vertical_9_16',\n Vertical_3_5 = 'vertical_3_5',\n Vertical_2_3 = 'vertical_2_3',\n}\n\n// Creo que seria bueno refactorizar para solo enviar aspect ratio asi\nexport enum AspectRatio2 {\n // Vertical\n '9:16' = 16 / 9,\n '3:5' = 3 / 5,\n '5:8' = 5 / 8,\n '2:3' = 2 / 3,\n '1:1' = 1 / 1,\n}\n\nexport enum ResolutionType {\n Small = 200,\n Medium = 400,\n MediumLarge = 800,\n Large = 1200,\n VeryLarge = 1600,\n}\n\nexport const AspectRatio = {\n [AspectType.Square]: 1 / 1,\n [AspectType.Rectangle]: 16 / 9,\n [AspectType.Vertical_9_16]: 9 / 16,\n [AspectType.RectangleLarge]: 16 / 8,\n [AspectType.Banner]: 16 / 7,\n [AspectType.Vertical_3_5]: 3 / 5,\n [AspectType.Vertical_2_3]: 2 / 3,\n};\n\nexport interface ImgStorageData extends CloudStorageData {\n name?: string;\n bucket?: string;\n url?: string;\n path?: string; // path where the file is in the storage\n fullPath?: string; // path + name\n resolution?: string;\n resolutions?: any;\n}\n\nexport interface CloudStorageData {\n bucket?: string;\n url?: string;\n path?: string; // path where the file is in the storage\n}\n\nexport const DEFAULT_SETTINGS: StorageImageSettings = {\n path: '/default-collection/id/please-change-this-subcollection',\n fileName: 'image',\n cropSettings: {\n aspectRatio: AspectType.Square,\n resolutions: [ResolutionType.Small, ResolutionType.MediumLarge],\n resizeToWidth: 450,\n },\n};\n","import { Injectable, inject } from '@angular/core';\nimport { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/compat/storage';\nimport { getDownloadURL, getStorage, deleteObject, listAll } from '@angular/fire/storage';\n\nimport { ref } from 'firebase/storage';\nimport { lastValueFrom } from 'rxjs';\nimport { ImageMultipleCrops, ImgStorageData } from '../classes/cropper.classes';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class MultiImagesStorageService {\n private storage = inject(AngularFireStorage);\n\n public async uploadImage(image: Blob, path: string): Promise<ImgStorageData> {\n try {\n const refStorage = this.storage.ref(path);\n const task = await refStorage.put(image);\n const { fullPath, bucket } = task.metadata;\n const url = await lastValueFrom(refStorage.getDownloadURL());\n const imageStorage = { url, path: fullPath, bucket };\n return imageStorage;\n } catch (error) {\n console.error('uploading image error: ', error);\n return null;\n }\n }\n\n public uploadImage2(imageMulticrops: ImageMultipleCrops, path: string): Promise<ImgStorageData> {\n // path is usually [products/id] will create a new folder with the name and upload the images\n\n const blobs = imageMulticrops.imagesBlobs;\n\n const tasks: Array<Promise<any>> = [];\n let fileName = imageMulticrops.settings?.renameFile ?? imageMulticrops.file.name;\n fileName = fileName.split('.')[0];\n\n // load the default image jpeg\n path = `${path}/${fileName}`;\n const defaultImagePath = `${path}/${fileName}-400W.jpeg`;\n const refStorage = this.storage.ref(defaultImagePath);\n const task = refStorage.put(imageMulticrops.defaultImageBlob);\n\n tasks.push(this.uploadAndGetUrl(task, 'default'));\n\n // Upload webp images\n for (const resolutionStr of Object.keys(blobs)) {\n const fullName = `${fileName}-${resolutionStr}W.webp`;\n const filePath = `${path}/${fullName}`;\n\n const refStorage = this.storage.ref(filePath);\n\n const resolution = Number(resolutionStr);\n const task = refStorage.put(blobs[resolution]);\n tasks.push(this.uploadAndGetUrl(task, resolution + 'W'));\n }\n\n return Promise.all(tasks).then(async (upladedImages) => {\n let defaultImage: any = {};\n let resolutionsUrls: any = {};\n\n for (const image of upladedImages) {\n if (image.resolution === 'default') {\n defaultImage = image;\n } else {\n resolutionsUrls[image.resolution] = image.url;\n }\n }\n defaultImage['resolutions'] = resolutionsUrls;\n defaultImage['path'] = path;\n\n return defaultImage;\n });\n }\n\n public async delete_directory(imagePath: string): Promise<void> {\n // WARNING!! user very carefully could delete whatever folder\n const storage = getStorage();\n const directoryRef = ref(storage, imagePath);\n\n listAll(directoryRef)\n .then((res) => {\n res.items.forEach((itemRef) => {\n console.log(itemRef);\n deleteObject(itemRef);\n });\n })\n .catch((error) => {\n console.error('error al eliminar imagenes de cloud storage', error);\n });\n }\n\n public async deleteImage(imagePath: string): Promise<void> {\n const storageRef = this.storage.ref(imagePath);\n storageRef.delete().subscribe((res) => {\n console.log('image deleted', res);\n });\n }\n\n private async uploadAndGetUrl(task: AngularFireUploadTask, resolution: string): Promise<ImgStorageData> {\n const snap = await task;\n const { fullPath, bucket, name } = snap.metadata;\n const storage = getStorage();\n const storageRef = ref(storage, fullPath);\n const url = await getDownloadURL(storageRef);\n const meta: ImgStorageData = {\n url,\n fullPath,\n bucket,\n name,\n resolution,\n path: '',\n resolutions: {},\n };\n\n return meta;\n }\n}\n","import { Component, OnInit, ViewChild, inject, output, input } from '@angular/core';\nimport { ImageCroppedEvent, ImageCropperComponent, LoadedImage, base64ToFile } from 'ngx-image-cropper';\nimport { Observable } from 'rxjs';\nimport { AspectRatio, AspectType, ImageMultipleCrops, CropImageSettings, ResolutionType } from '../../classes/cropper.classes';\n\nimport { FormsModule } from '@angular/forms';\nimport { MultiImagesStorageService } from '../../services/multi-images-storage.service';\n\n@Component({\n selector: 'app-cropper',\n templateUrl: './cropper.component.html',\n styleUrls: ['./cropper.component.scss'],\n standalone: true,\n imports: [FormsModule, ImageCropperComponent],\n})\nexport class CropperComponent implements OnInit {\n private multiImagesStorageService = inject(MultiImagesStorageService);\n\n // overrides name, path and resizeToWidth\n readonly imageSettings = input<CropImageSettings>({} as any);\n\n readonly ratioType = input<AspectType | string>(AspectType.Square);\n\n readonly resolutions = input<Array<number>>([ResolutionType.MediumLarge]);\n\n readonly imageUploaded = output<any>();\n\n readonly onImageCropped = output<ImageMultipleCrops>();\n\n readonly onFileSelected = output<any>();\n\n @ViewChild(ImageCropperComponent) imageCropper!: ImageCropperComponent;\n\n public fileMetadata: File | null = null;\n public imageChangedEvent!: Event;\n\n public aspectRatio: number = 1;\n\n public croppedImage: any = '';\n\n public isLoading = false;\n public isUploaded = false;\n public renameFile: any = '';\n public storagePath: string = '';\n public showModal = false;\n\n /** Inserted by Angular inject() migration for backwards compatibility */\n constructor(...args: unknown[]);\n\n constructor() {}\n\n ngOnInit(): void {\n this.aspectRatio = AspectRatio[this.ratioType()];\n const imageSettings = this.imageSettings();\n if (imageSettings.path) {\n this.storagePath = `${imageSettings.path}/${imageSettings.fileName}.webp`;\n }\n }\n\n public reloadPath(): void {\n this.storagePath = `${this.imageSettings().path}/${this.renameFile}.webp`;\n }\n\n async fileChangeEvent(event: any) {\n this.imageChangedEvent = event;\n const file = event?.target?.files[0];\n if (file) {\n this.fileMetadata = file;\n this.onFileSelected.emit(file);\n this.showModal = true; // Show modal when file is selected\n this.renameFile = this.fileMetadata?.name?.split('.')[0];\n console.log(this.renameFile);\n\n if (!this.imageSettings().fileName) {\n this.reloadPath();\n }\n }\n }\n\n onInnerImageCropped(event: ImageCroppedEvent) {\n this.croppedImage = event.base64;\n }\n\n imageLoaded(image: LoadedImage) {\n // show cropper\n }\n\n loadImageFailed() {\n console.error('fallo al cargar la imagen');\n }\n\n public downloadURL!: Observable<string>;\n\n public async simpleCropAndUpload() {\n const imageCropped: any = await this.imageCropper.crop();\n const imgStorage = await this.multiImagesStorageService.uploadImage(imageCropped?.blob, this.storagePath);\n this.imageUploaded.emit(imgStorage);\n this.closeModal();\n }\n\n public async uploadToStorage(imageMulticrops: ImageMultipleCrops): Promise<void> {\n // TODO: Nota si algo falla aquí puede causar inconsistencias en el sistema, ver como manejar errores\n const path = this.imageSettings().path;\n // const imageUploaded = await this.multiImagesStorageService.uploadImage(imageMulticrops, path);\n // this.modalRef.close();\n // console.log(imageUploaded);\n // const image = { type: 'cover', ...imageUploaded };\n\n // TODO: creo que esta parte va en el componente que llama a este componente\n // if (!this.lesson.media) {\n // this.lesson.media = {};\n // this.lesson.media.images = [image];\n // } else {\n // // solo sustituir el cover si ya existe\n // const currentCover = this.lesson.media.images.find((img) => img.type === 'cover');\n // this.multiImagesStorageService.delete_directory(currentCover.path);\n\n // this.lesson.media.images = this.lesson.media.images.filter((img) => img.type !== 'cover');\n\n // this.lesson.media.images.push(image);\n // }\n\n // await this.saveLesson();\n // this.updateCover();\n // this.imageUploaded.emit(image);\n }\n\n closeModal(): void {\n this.showModal = false;\n }\n}\n","<div> path: {{ storagePath }} </div>\n\n<div class=\"options\">\n @if (!isUploaded) {\n <div>\n <input type=\"file\" id=\"file-upload\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label for=\"file-upload\" class=\"btn-upload\">Seleccionar archivo</label>\n @if (!fileMetadata) {\n <em>Carga una imagen para comenzar</em>\n }\n </div>\n }\n\n @if (fileMetadata) {\n <span>\n <span style=\"margin: 1px 20px\"> tipo: {{ fileMetadata.type }} </span>\n <span style=\"margin: 1px 20px\"> tamaño {{ fileMetadata.size }} </span>\n <br />\n <input\n [disabled]=\"imageSettings()?.fileName\"\n style=\"margin: 1px 20px; width: 400px\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\" />\n <button class=\"btn-crop\" (click)=\"closeModal()\"> Recortar y Subir </button>\n </span>\n }\n</div>\n\n@if (fileMetadata && !isUploaded) {\n <div class=\"modal\" [class.show-modal]=\"showModal\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h3>Recortar imagen</h3>\n <button class=\"close-button\" (click)=\"closeModal()\">×</button>\n </div>\n <div class=\"modal-body\">\n <h1>Hlloa</h1>\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatio\"\n format=\"webp\"\n [resizeToWidth]=\"450\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (imageLoaded)=\"imageLoaded($event)\"\n [autoCrop]=\"false\"></image-cropper>\n <div class=\"modal-footer\">\n <button class=\"btn-crop\" (click)=\"simpleCropAndUpload()\">Recortar y Subir</button>\n </div>\n </div>\n </div>\n </div>\n}\n\n@if (croppedImage && !isUploaded) {\n <button [disabled]=\"isLoading\" nbButton status=\"info\"> upload </button>\n}\n","import { Component, Input, OnInit, ViewChild, ChangeDetectorRef, inject, output, input } from '@angular/core';\n\nimport { FormsModule } from '@angular/forms';\n\nimport { DialogModule } from 'primeng/dialog';\n\nimport { ImageCroppedEvent, ImageCropperComponent, LoadedImage } from 'ngx-image-cropper';\nimport { Observable } from 'rxjs';\n\nimport { MultiImagesStorageService } from '../../services/multi-images-storage.service';\nimport {\n AspectRatio,\n AspectType,\n ImageMultipleCrops,\n StorageImageSettings,\n ImgStorageData,\n AspectRatioOptions,\n AspectRatioOption,\n DEFAULT_SETTINGS,\n} from '../../classes/cropper.classes';\nimport { TooltipModule } from 'primeng/tooltip';\n\nimport { ButtonModule } from 'primeng/button';\nimport { MessageModule } from 'primeng/message';\nimport { SelectModule } from 'primeng/select';\nimport { InputTextModule } from 'primeng/inputtext';\n\n@Component({\n selector: 'dc-cropper-modal',\n templateUrl: './cropper-modal.component.html',\n styleUrls: ['./cropper-modal.component.scss'],\n standalone: true,\n imports: [FormsModule, ImageCropperComponent, ButtonModule, DialogModule, TooltipModule, MessageModule, SelectModule, InputTextModule],\n})\nexport class CropperComponentModal implements OnInit {\n private multiImagesStorageService = inject(MultiImagesStorageService);\n private changeDetectorRef = inject(ChangeDetectorRef);\n\n // overrides name, path and resizeToWidth\n\n readonly imgStorageSettings = input<StorageImageSettings>(DEFAULT_SETTINGS);\n readonly buttonLabel = input<string>('Seleccionar archivo');\n @Input() currentStorage: ImgStorageData = {} as any;\n\n readonly imageUploaded = output<ImgStorageData>();\n readonly onImageCropped = output<ImageMultipleCrops>();\n readonly onFileSelected = output<any>();\n\n @ViewChild(ImageCropperComponent) imageCropper!: ImageCropperComponent;\n\n public aspectRatioOptions = AspectRatioOptions;\n public fileMetadata: File | null = null;\n public imageChangedEvent!: Event;\n public displayDialog = false;\n public aspectRatioValue: number = 1;\n public croppedImage: any = '';\n public renameFile: any = '';\n public storagePath: string = '';\n public downloadURL!: Observable<string>;\n public resizeToWidth: number = 450;\n public ratioSelected: any = null;\n\n // Add a unique identifier for the file input\n public fileInputId: string;\n\n /** Inserted by Angular inject() migration for backwards compatibility */\n constructor(...args: unknown[]);\n\n constructor() {\n // Generate random ID for file input\n this.fileInputId = `file-upload-${Math.random().toString(36).substring(2, 11)}`;\n }\n\n ngOnInit(): void {\n if (!this.imgStorageSettings().path) {\n console.warn('⚠️ Remember to set imgStorageSettings, path and fileName are required , path example: /collection/id/subcollection ');\n }\n this.reloadPath();\n }\n\n public reloadPath(): void {\n const randomCharacters = Math.random().toString(36).substring(2, 15);\n this.storagePath = `${this.imgStorageSettings().path}/${this.imgStorageSettings().fileName}-${randomCharacters}.webp`;\n }\n\n private setSettingsForComponent(): void {\n const imgStorageSettings = this.imgStorageSettings();\n console.log('setSettingsForComponent', imgStorageSettings);\n // TODO: remove all the imageSettings and keep only imgStorageSettings\n\n this.aspectRatioValue = imgStorageSettings?.cropSettings?.aspectRatio\n ? AspectRatio[imgStorageSettings?.cropSettings?.aspectRatio]\n : AspectRatio[AspectType.Square];\n\n if (imgStorageSettings?.path) {\n this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;\n } else if (imgStorageSettings.path) {\n this.storagePath = `${imgStorageSettings.path}/${imgStorageSettings.fileName}.webp`;\n }\n if (imgStorageSettings?.cropSettings?.resizeToWidth) {\n this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;\n } else if (imgStorageSettings.cropSettings.resizeToWidth) {\n this.resizeToWidth = imgStorageSettings.cropSettings.resizeToWidth;\n }\n if (imgStorageSettings?.fileName) {\n this.renameFile = imgStorageSettings.fileName;\n } else if (imgStorageSettings.fileName) {\n this.renameFile = imgStorageSettings.fileName;\n }\n }\n\n async fileChangeEvent(event: any) {\n this.setSettingsForComponent();\n\n console.log(this.fileInputId);\n\n this.imageChangedEvent = event;\n const file = event?.target?.files[0];\n if (file) {\n this.fileMetadata = file;\n this.onFileSelected.emit(file);\n this.renameFile = this.fileMetadata?.name\n ?.split('.')[0]\n .replace(/[^a-zA-Z0-9]/g, '')\n .slice(0, 80);\n\n console.log(this.renameFile);\n\n if (!this.imgStorageSettings().fileName) {\n this.reloadPath();\n }\n this.displayDialog = true;\n this.changeDetectorRef.detectChanges();\n }\n }\n\n onInnerImageCropped(event: ImageCroppedEvent) {\n this.croppedImage = event.base64;\n }\n\n imageLoaded(image: LoadedImage) {\n this.changeDetectorRef.detectChanges();\n }\n\n cropperReady() {\n this.changeDetectorRef.detectChanges();\n }\n\n loadImageFailed() {\n console.error('fallo al cargar la imagen');\n }\n\n public async simpleCropAndUpload() {\n console.log(this.fileInputId);\n\n console.log('simpleCropAndUpload');\n const imageCropped: any = await this.imageCropper.crop();\n const imgStorage = await this.multiImagesStorageService.uploadImage(imageCropped?.blob, this.storagePath);\n if (this.currentStorage?.path) {\n console.warn('deleting current Image', this.currentStorage?.path);\n this.multiImagesStorageService.deleteImage(this.currentStorage.path);\n }\n console.log('imgStorage', imgStorage);\n this.imageUploaded.emit(imgStorage);\n this.displayDialog = false;\n this.changeDetectorRef.detectChanges();\n }\n\n public changeRatio(event: AspectRatioOption) {\n console.log('changeRatio', event);\n // this.imgStorageSettings.cropSettings.aspectRatio = event.valueRatio;\n this.aspectRatioValue = event.valueRatio;\n this.changeDetectorRef.detectChanges();\n }\n}\n","<div class=\"upload-section\">\n <input type=\"file\" [id]=\"fileInputId\" class=\"file-input\" (change)=\"fileChangeEvent($event)\" />\n <label pButton [for]=\"fileInputId\" [pTooltip]=\"storagePath\" class=\"upload-button\">\n {{ buttonLabel() }}\n </label>\n</div>\n@if(displayDialog) {\n <!-- Cropper Dialog -->\n\n <p-dialog header=\"Recortar imagen\" [(visible)]=\"displayDialog\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" styleClass=\"cropper-dialog\">\n <!-- Image Settings Section -->\n <div class=\"settings-section\">\n @if(!imgStorageSettings().path) {\n <p-message severity=\"warn\">Developer Note: make sure you have a path to save the image pass object imgStorageSettings</p-message>\n } @if(currentStorage.url) {\n\n <p-message severity=\"warn\" variant=\"outlined\">\n <div>\n <span class=\"setting-label\">Image will be replaced:</span>\n <img width=\"100\" height=\"Auto\" [src]=\"currentStorage?.url\" />\n </div>\n </p-message>\n\n }\n\n <p-message>\n <b>Estas opciones estan preconfiguradas y no se pueden cambiar</b>\n\n <ul>\n <li> <b>Path to save:</b> {{ storagePath }}< </li>\n <li>\n <b>Resoluciones:</b>\n <span>{{ imgStorageSettings()?.cropSettings?.resolutions }}</span>\n </li>\n </ul>\n </p-message>\n\n <div class=\"setting-item\">\n <span class=\"setting-label\">Aspecto:</span>\n <p class=\"setting-value\">{{ imgStorageSettings()?.cropSettings?.aspectRatio }}</p>\n </div>\n\n <p-select\n [options]=\"aspectRatioOptions\"\n [ngModel]=\"ratioSelected\"\n (ngModelChange)=\"changeRatio($event)\"\n optionLabel=\"description\"\n placeholder=\"Select a ratio\" />\n\n <!-- File Metadata Section -->\n @if (fileMetadata) {\n <div class=\"metadata-section\">\n <span class=\"metadata-item\">tipo: {{ fileMetadata.type }}</span>\n <span class=\"metadata-item\">tamaño: {{ fileMetadata.size }}</span>\n </div>\n }\n\n <!-- Rename Input -->\n <input\n pInputText\n [disabled]=\"imgStorageSettings()?.fileName\"\n [(ngModel)]=\"renameFile\"\n type=\"text\"\n placeholder=\"Rename File\"\n (ngModelChange)=\"reloadPath()\"\n class=\"rename-input\" />\n </div>\n\n <!-- Image Cropper -->\n\n <div class=\"cropper-container-father\">\n <image-cropper\n [imageChangedEvent]=\"imageChangedEvent\"\n [maintainAspectRatio]=\"true\"\n [aspectRatio]=\"aspectRatioValue\"\n format=\"webp\"\n [resizeToWidth]=\"resizeToWidth\"\n (imageCropped)=\"onInnerImageCropped($event)\"\n (loadImageFailed)=\"loadImageFailed()\"\n (cropperReady)=\"cropperReady()\"\n [autoCrop]=\"false\">\n </image-cropper>\n </div>\n <!-- Dialog Footer -->\n <ng-template pTemplate=\"footer\">\n <div class=\"dialog-footer\">\n <button pButton class=\"p-button-primary\" (click)=\"simpleCropAndUpload()\"> Recortar y Subir </button>\n </div>\n </ng-template>\n </p-dialog>\n}\n","import { Component, OnInit, OnDestroy, inject, output } from '@angular/core';\nimport { AngularFireStorage } from '@angular/fire/compat/storage';\nimport { getStorage, ref, listAll, getDownloadURL } from 'firebase/storage';\nimport { BehaviorSubject, Subscription } from 'rxjs';\nimport { AspectType, ImgStorageData, ResolutionType, StorageImageSettings } from '../../classes/cropper.classes';\nimport { AsyncPipe } from '@angular/common';\nimport { CropperComponentModal } from '../cropper-modal/cropper-modal.component';\n\n@Component({\n selector: 'dc-image-storage-preview',\n templateUrl: './image-storage-preview.html',\n styleUrls: ['./image-storage-preview.css'],\n standalone: true,\n imports: [AsyncPipe, CropperComponentModal],\n})\nexport class ImageStoragePreviewComponent implements OnInit, OnDestroy {\n private storage = inject(AngularFireStorage);\n\n readonly imageSelected = output<ImgStorageData>();\n public images$ = new BehaviorSubject<ImgStorageData[]>([]);\n public loading$ = new BehaviorSubject<boolean>(false);\n public error$ = new BehaviorSubject<string | null>(null);\n\n public readonly storagePath = '/images/resources';\n private subscriptions: Subscription[] = [];\n\n /** Inserted by Angular inject() migration for backwards compatibility */\n constructor(...args: unknown[]);\n\n constructor() {}\n\n ngOnInit(): void {\n this.loadImagesFromStorage();\n }\n\n public imgStorageSettings: StorageImageSettings = {\n path: this.storagePath,\n cropSettings: {\n aspectRatio: AspectType.Square,\n resolutions: [ResolutionType.Small],\n },\n };\n\n ngOnDestroy(): void {\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n }\n\n /**\n * Loads images from Firebase Storage at the specified path\n */\n private async loadImagesFromStorage(): Promise<void> {\n try {\n this.loading$.next(true);\n this.error$.next(null);\n\n const storage = getStorage();\n const storageRef = ref(storage, this.storagePath);\n\n const result = await listAll(storageRef);\n\n if (result.items.length === 0) {\n this.images$.next([]);\n this.loading$.next(false);\n return;\n }\n\n const imagePromises = result.items.map(async (itemRef) => {\n try {\n const url = await getDownloadURL(itemRef);\n const image: ImgStorageData = {\n url,\n fullPath: itemRef.fullPath,\n name: itemRef.name,\n path: this.storagePath,\n };\n return image;\n } catch (error) {\n console.error(`Error getting download URL for ${itemRef.fullPath}:`, error);\n return null;\n }\n });\n\n const images = (await Promise.all(imagePromises)).filter((img) => img !== null) as ImgStorageData[];\n this.images$.next(images);\n } catch (error) {\n console.error('Error loading images from storage:', error);\n this.error$.next('Failed to load images from storage. Please try again later.');\n } finally {\n this.loading$.next(false);\n }\n }\n\n /**\n * Refreshes the image list\n */\n public refreshImages(): void {\n this.loadImagesFromStorage();\n }\n\n public selectImage(image: ImgStorageData): void {\n this.imageSelected.emit(image);\n }\n}\n","<div class=\"image-storage-preview-container\">\n <div class=\"header\">\n <h2>Storage Images</h2>\n <button class=\"refresh-btn\" (click)=\"refreshImages()\" [disabled]=\"loading$ | async\">\n @if (!(loading$ | async)) {\n <span>Refresh</span>\n }\n @if (loading$ | async) {\n <span>Loading...</span>\n }\n </button>\n </div>\n\n @if (loading$ | async) {\n <div class=\"loading-container\">\n <div class=\"spinner\"></div>\n <p>Loading images...</p>\n </div>\n }\n\n @if (error$ | async) {\n <div class=\"error-container\">\n <p class=\"error-message\">{{ error$ | async }}</p>\n <button (click)=\"refreshImages()\">Try Again</button>\n </div>\n }\n\n @if (!(loading$ | async) && !(error$ | async)) {\n <div class=\"images-grid\">\n @if ((images$ | async)?.length) {\n @for (image of images$ | async; track image) {\n <div class=\"image-card\">\n <div class=\"image-container\">\n <img [src]=\"image.url\" [alt]=\"image.name || 'Storage image'\" loading=\"lazy\" />\n </div>\n <div class=\"image-info\">\n <p class=\"image-name\" [title]=\"image.name\">{{ image.name }}</p>\n <div class=\"image-actions\">\n <a [href]=\"image.url\" target=\"_blank\" class=\"action-btn\">View</a>\n <button (click)=\"selectImage(image)\" class=\"action-btn\">Select</button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"no-images\">\n <p>No images found in the storage path: {{ storagePath }}</p>\n </div>\n }\n <dc-cropper-modal [imgStorageSettings]=\"imgStorageSettings\"></dc-cropper-modal>\n </div>\n }\n</div>\n","import { Injectable, inject } from '@angular/core';\nimport { getDownloadURL, ref, Storage } from '@angular/fire/storage';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class DCFilesCacheService {\n private storage = inject(Storage);\n\n /** Inserted by Angular inject() migration for backwards compatibility */\n constructor(...args: unknown[]);\n\n constructor() {}\n\n public files: { [key: string]: string } = {};\n\n public async getURLSrcFile(path: string): Promise<string> {\n if (path in this.files) {\n return this.files[path];\n } else {\n const url = await getDownloadURL(ref(this.storage, path));\n const localUrl = await this.donwloadFileAndGetLocalURL(url);\n this.files[path] = localUrl;\n return localUrl;\n }\n }\n\n public getBlob(url: string): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.responseType = 'blob';\n xhr.overrideMimeType('audio/mp3');\n\n xhr.onload = (event) => {\n var blob = xhr.response;\n resolve(blob);\n };\n xhr.onerror = (event) => {\n reject(event);\n };\n\n xhr.open('GET', url);\n xhr.send();\n });\n }\n\n public async donwloadFileAndGetLocalURL(url: string) {\n const blob = await this.getBlob(url);\n\n return URL.createObjectURL(blob);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/compat/storage';\nimport { getDownloadURL, getStorage, deleteObject, listAll, StorageReference } from '@angular/fire/storage';\nimport { ref } from 'firebase/storage';\nimport { lastValueFrom } from 'rxjs';\n\n/**\n * Represents the metadata of an object stored in Firebase Storage.\n */\nexport interface ObjectStorageData {\n /** The download URL of the stored object. */\n url: string;\n /** The full path of the object in the storage bucket (e.g., 'folder/subfolder/file.txt'). */\n path: string;\n /** The name of the Firebase Storage bucket where the object is stored. */\n bucket: string;\n /** The name of the object file (e.g., 'file.txt'). */\n name?: string;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class MultiObjectStorageService {\n private storage = inject(AngularFireStorage);\n\n /**\n * Uploads a Blob or File object to a specified path in Firebase Storage.\n * @param objectToUpload The Blob or File to upload.\n * @param path The desired storage path (e.g., 'documents/report.pdf').\n * @returns A promise that resolves with the storage metadata of the uploaded object.\n * @throws Throws an error if the upload fails.\n */\n public async uploadObject(objectToUpload: Blob | File, path: string): Promise<ObjectStorageData> {\n try {\n const refStorage = this.storage.ref(path);\n const task = await refStorage.put(objectToUpload);\n const { fullPath, bucket, name } = task.metadata;\n const url = await lastValueFrom(refStorage.getDownloadURL());\n const storageData: ObjectStorageData = { url, path: fullPath, bucket, name };\n return storageData;\n } catch (error) {\n console.error(`Error uploading object to path \"${path}\": `, error);\n // Re-throw the error to allow calling code to handle it\n throw error;\n }\n }\n\n /**\n * Deletes all objects within a specified directory path in Firebase Storage.\n * WARNING: Use with extreme caution as this will permanently delete all files in the directory.\n * @param directoryPath The path to the directory to delete (e.g., 'users/userId/files/').\n * @returns A promise that resolves when the deletion attempt is complete.\n */\n public async deleteDirectory(directoryPath: string): Promise<void> {\n const storage = getStorage();\n const directoryRef = ref(storage, directoryPath);\n\n try {\n const res = await listAll(directoryRef);\n const deletePromises: Promise<void>[] = [];\n res.items.forEach((itemRef: StorageReference) => {\n console.log(`Deleting object: ${itemRef.fullPath}`);\n deletePromises.push(deleteObject(itemRef));\n });\n // You might want to handle potential errors during individual deletions if needed\n await Promise.all(deletePromises);\n console.log(`Successfully deleted objects in directory: ${directoryPath}`);\n } catch (error) {\n console.error(`Error deleting objects in directory \"${directoryPath}\":`, error);\n // Optionally re-throw or handle the error appropriately\n throw error;\n }\n }\n\n /**\n * Deletes a single object from Firebase Storage based on its full path.\n * @param objectPath The full path of the object to delete (e.g., 'images/profile.jpg').\n * @returns A promise that resolves when the deletion is complete.\n */\n public async deleteObjectByPath(objectPath: string): Promise<void> {\n const storageRef = this.storage.ref(objectPath);\n try {\n await lastValueFrom(storageRef.delete());\n console.log(`Object deleted successfully: ${objectPath}`);\n } catch (error) {\n console.error(`Error deleting object at path \"${objectPath}\":`, error);\n // Optionally re-throw or handle the error appropriately\n throw error;\n }\n }\n\n /**\n * Private helper to get metadata after an upload task completes.\n * @param task The AngularFireUploadTask.\n * @returns A promise resolving with the object's storage metadata.\n */\n private async uploadAndGetObjectMetadata(task: AngularFireUploadTask): Promise<ObjectStorageData> {\n const snap = await task;\n const { fullPath, bucket, name } = snap.metadata;\n const storage = getStorage();\n const storageRef = ref(storage, fullPath);\n const url = await getDownloadURL(storageRef);\n const meta: ObjectStorageData = {\n url,\n path: fullPath, // Use fullPath for the 'path' property\n bucket,\n name,\n };\n return meta;\n }\n}\n","/*\n * Public API Surface of storage-uploader\n */\n\nexport * from './lib/components/cropper/cropper.component';\nexport * from './lib/components/cropper-modal/cropper-modal.component';\nexport * from './lib/components/image-storage-preview/image-storage-preview';\nexport * from './lib/classes/cropper.classes';\n\nexport * from './lib/services/multi-images-storage.service';\nexport * from './lib/services/dc-files-cache.service';\nexport * from './lib/services/multi-object-storage.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["getStorage","listAll","getDownloadURL","ref"],"mappings":"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"}
@@ -1,17 +1,16 @@
1
- import { OnInit, EventEmitter } from '@angular/core';
1
+ import { OnInit } from '@angular/core';
2
2
  import { ImageCroppedEvent, ImageCropperComponent, LoadedImage } from 'ngx-image-cropper';
3
3
  import { Observable } from 'rxjs';
4
- import { AspectType, ImageMultipleCrops, CropImageSettings } from '../../classes/cropper.classes';
5
- import { MultiImagesStorageService } from '../../services/multi-images-storage.service';
4
+ import { ImageMultipleCrops, CropImageSettings } from '../../classes/cropper.classes';
6
5
  import * as i0 from "@angular/core";
7
6
  export declare class CropperComponent implements OnInit {
8
7
  private multiImagesStorageService;
9
- imageSettings: CropImageSettings;
10
- ratioType: AspectType | string;
11
- resolutions: Array<number>;
12
- imageUploaded: EventEmitter<any>;
13
- onImageCropped: EventEmitter<ImageMultipleCrops>;
14
- onFileSelected: EventEmitter<any>;
8
+ readonly imageSettings: import("@angular/core").InputSignal<CropImageSettings>;
9
+ readonly ratioType: import("@angular/core").InputSignal<string>;
10
+ readonly resolutions: import("@angular/core").InputSignal<number[]>;
11
+ readonly imageUploaded: import("@angular/core").OutputEmitterRef<any>;
12
+ readonly onImageCropped: import("@angular/core").OutputEmitterRef<ImageMultipleCrops>;
13
+ readonly onFileSelected: import("@angular/core").OutputEmitterRef<any>;
15
14
  imageCropper: ImageCropperComponent;
16
15
  fileMetadata: File | null;
17
16
  imageChangedEvent: Event;
@@ -22,7 +21,8 @@ export declare class CropperComponent implements OnInit {
22
21
  renameFile: any;
23
22
  storagePath: string;
24
23
  showModal: boolean;
25
- constructor(multiImagesStorageService: MultiImagesStorageService);
24
+ /** Inserted by Angular inject() migration for backwards compatibility */
25
+ constructor(...args: unknown[]);
26
26
  ngOnInit(): void;
27
27
  reloadPath(): void;
28
28
  fileChangeEvent(event: any): Promise<void>;
@@ -34,5 +34,5 @@ export declare class CropperComponent implements OnInit {
34
34
  uploadToStorage(imageMulticrops: ImageMultipleCrops): Promise<void>;
35
35
  closeModal(): void;
36
36
  static ɵfac: i0.ɵɵFactoryDeclaration<CropperComponent, never>;
37
- static ɵcmp: i0.ɵɵComponentDeclaration<CropperComponent, "app-cropper", never, { "imageSettings": { "alias": "imageSettings"; "required": false; }; "ratioType": { "alias": "ratioType"; "required": false; }; "resolutions": { "alias": "resolutions"; "required": false; }; }, { "imageUploaded": "imageUploaded"; "onImageCropped": "onImageCropped"; "onFileSelected": "onFileSelected"; }, never, never, true, never>;
37
+ static ɵcmp: i0.ɵɵComponentDeclaration<CropperComponent, "app-cropper", never, { "imageSettings": { "alias": "imageSettings"; "required": false; "isSignal": true; }; "ratioType": { "alias": "ratioType"; "required": false; "isSignal": true; }; "resolutions": { "alias": "resolutions"; "required": false; "isSignal": true; }; }, { "imageUploaded": "imageUploaded"; "onImageCropped": "onImageCropped"; "onFileSelected": "onFileSelected"; }, never, never, true, never>;
38
38
  }
@@ -1,18 +1,17 @@
1
- import { OnInit, EventEmitter, ChangeDetectorRef } from '@angular/core';
1
+ import { OnInit } from '@angular/core';
2
2
  import { ImageCroppedEvent, ImageCropperComponent, LoadedImage } from 'ngx-image-cropper';
3
3
  import { Observable } from 'rxjs';
4
- import { MultiImagesStorageService } from '../../services/multi-images-storage.service';
5
4
  import { ImageMultipleCrops, StorageImageSettings, ImgStorageData, AspectRatioOption } from '../../classes/cropper.classes';
6
5
  import * as i0 from "@angular/core";
7
6
  export declare class CropperComponentModal implements OnInit {
8
7
  private multiImagesStorageService;
9
8
  private changeDetectorRef;
10
- imgStorageSettings: StorageImageSettings;
11
- buttonLabel: string;
9
+ readonly imgStorageSettings: import("@angular/core").InputSignal<StorageImageSettings>;
10
+ readonly buttonLabel: import("@angular/core").InputSignal<string>;
12
11
  currentStorage: ImgStorageData;
13
- imageUploaded: EventEmitter<ImgStorageData>;
14
- onImageCropped: EventEmitter<ImageMultipleCrops>;
15
- onFileSelected: EventEmitter<any>;
12
+ readonly imageUploaded: import("@angular/core").OutputEmitterRef<ImgStorageData>;
13
+ readonly onImageCropped: import("@angular/core").OutputEmitterRef<ImageMultipleCrops>;
14
+ readonly onFileSelected: import("@angular/core").OutputEmitterRef<any>;
16
15
  imageCropper: ImageCropperComponent;
17
16
  aspectRatioOptions: AspectRatioOption[];
18
17
  fileMetadata: File | null;
@@ -26,7 +25,8 @@ export declare class CropperComponentModal implements OnInit {
26
25
  resizeToWidth: number;
27
26
  ratioSelected: any;
28
27
  fileInputId: string;
29
- constructor(multiImagesStorageService: MultiImagesStorageService, changeDetectorRef: ChangeDetectorRef);
28
+ /** Inserted by Angular inject() migration for backwards compatibility */
29
+ constructor(...args: unknown[]);
30
30
  ngOnInit(): void;
31
31
  reloadPath(): void;
32
32
  private setSettingsForComponent;
@@ -38,5 +38,5 @@ export declare class CropperComponentModal implements OnInit {
38
38
  simpleCropAndUpload(): Promise<void>;
39
39
  changeRatio(event: AspectRatioOption): void;
40
40
  static ɵfac: i0.ɵɵFactoryDeclaration<CropperComponentModal, never>;
41
- static ɵcmp: i0.ɵɵComponentDeclaration<CropperComponentModal, "dc-cropper-modal", never, { "imgStorageSettings": { "alias": "imgStorageSettings"; "required": false; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; }; "currentStorage": { "alias": "currentStorage"; "required": false; }; }, { "imageUploaded": "imageUploaded"; "onImageCropped": "onImageCropped"; "onFileSelected": "onFileSelected"; }, never, never, true, never>;
41
+ static ɵcmp: i0.ɵɵComponentDeclaration<CropperComponentModal, "dc-cropper-modal", never, { "imgStorageSettings": { "alias": "imgStorageSettings"; "required": false; "isSignal": true; }; "buttonLabel": { "alias": "buttonLabel"; "required": false; "isSignal": true; }; "currentStorage": { "alias": "currentStorage"; "required": false; }; }, { "imageUploaded": "imageUploaded"; "onImageCropped": "onImageCropped"; "onFileSelected": "onFileSelected"; }, never, never, true, never>;
42
42
  }
@@ -0,0 +1,29 @@
1
+ import { OnInit, OnDestroy } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import { ImgStorageData, StorageImageSettings } from '../../classes/cropper.classes';
4
+ import * as i0 from "@angular/core";
5
+ export declare class ImageStoragePreviewComponent implements OnInit, OnDestroy {
6
+ private storage;
7
+ readonly imageSelected: import("@angular/core").OutputEmitterRef<ImgStorageData>;
8
+ images$: BehaviorSubject<ImgStorageData[]>;
9
+ loading$: BehaviorSubject<boolean>;
10
+ error$: BehaviorSubject<string>;
11
+ readonly storagePath = "/images/resources";
12
+ private subscriptions;
13
+ /** Inserted by Angular inject() migration for backwards compatibility */
14
+ constructor(...args: unknown[]);
15
+ ngOnInit(): void;
16
+ imgStorageSettings: StorageImageSettings;
17
+ ngOnDestroy(): void;
18
+ /**
19
+ * Loads images from Firebase Storage at the specified path
20
+ */
21
+ private loadImagesFromStorage;
22
+ /**
23
+ * Refreshes the image list
24
+ */
25
+ refreshImages(): void;
26
+ selectImage(image: ImgStorageData): void;
27
+ static ɵfac: i0.ɵɵFactoryDeclaration<ImageStoragePreviewComponent, never>;
28
+ static ɵcmp: i0.ɵɵComponentDeclaration<ImageStoragePreviewComponent, "dc-image-storage-preview", never, {}, { "imageSelected": "imageSelected"; }, never, never, true, never>;
29
+ }
@@ -1,8 +1,8 @@
1
- import { Storage } from '@angular/fire/storage';
2
1
  import * as i0 from "@angular/core";
3
2
  export declare class DCFilesCacheService {
4
3
  private storage;
5
- constructor(storage: Storage);
4
+ /** Inserted by Angular inject() migration for backwards compatibility */
5
+ constructor(...args: unknown[]);
6
6
  files: {
7
7
  [key: string]: string;
8
8
  };
@@ -1,9 +1,7 @@
1
- import { AngularFireStorage } from '@angular/fire/compat/storage';
2
1
  import { ImageMultipleCrops, ImgStorageData } from '../classes/cropper.classes';
3
2
  import * as i0 from "@angular/core";
4
3
  export declare class MultiImagesStorageService {
5
4
  private storage;
6
- constructor(storage: AngularFireStorage);
7
5
  uploadImage(image: Blob, path: string): Promise<ImgStorageData>;
8
6
  uploadImage2(imageMulticrops: ImageMultipleCrops, path: string): Promise<ImgStorageData>;
9
7
  delete_directory(imagePath: string): Promise<void>;
@@ -0,0 +1,46 @@
1
+ import * as i0 from "@angular/core";
2
+ /**
3
+ * Represents the metadata of an object stored in Firebase Storage.
4
+ */
5
+ export interface ObjectStorageData {
6
+ /** The download URL of the stored object. */
7
+ url: string;
8
+ /** The full path of the object in the storage bucket (e.g., 'folder/subfolder/file.txt'). */
9
+ path: string;
10
+ /** The name of the Firebase Storage bucket where the object is stored. */
11
+ bucket: string;
12
+ /** The name of the object file (e.g., 'file.txt'). */
13
+ name?: string;
14
+ }
15
+ export declare class MultiObjectStorageService {
16
+ private storage;
17
+ /**
18
+ * Uploads a Blob or File object to a specified path in Firebase Storage.
19
+ * @param objectToUpload The Blob or File to upload.
20
+ * @param path The desired storage path (e.g., 'documents/report.pdf').
21
+ * @returns A promise that resolves with the storage metadata of the uploaded object.
22
+ * @throws Throws an error if the upload fails.
23
+ */
24
+ uploadObject(objectToUpload: Blob | File, path: string): Promise<ObjectStorageData>;
25
+ /**
26
+ * Deletes all objects within a specified directory path in Firebase Storage.
27
+ * WARNING: Use with extreme caution as this will permanently delete all files in the directory.
28
+ * @param directoryPath The path to the directory to delete (e.g., 'users/userId/files/').
29
+ * @returns A promise that resolves when the deletion attempt is complete.
30
+ */
31
+ deleteDirectory(directoryPath: string): Promise<void>;
32
+ /**
33
+ * Deletes a single object from Firebase Storage based on its full path.
34
+ * @param objectPath The full path of the object to delete (e.g., 'images/profile.jpg').
35
+ * @returns A promise that resolves when the deletion is complete.
36
+ */
37
+ deleteObjectByPath(objectPath: string): Promise<void>;
38
+ /**
39
+ * Private helper to get metadata after an upload task completes.
40
+ * @param task The AngularFireUploadTask.
41
+ * @returns A promise resolving with the object's storage metadata.
42
+ */
43
+ private uploadAndGetObjectMetadata;
44
+ static ɵfac: i0.ɵɵFactoryDeclaration<MultiObjectStorageService, never>;
45
+ static ɵprov: i0.ɵɵInjectableDeclaration<MultiObjectStorageService>;
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataclouder/ngx-cloud-storage",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "Angular component library for handling cloud storage uploads with image cropping capabilities",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/public-api.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from './lib/components/cropper/cropper.component';
2
2
  export * from './lib/components/cropper-modal/cropper-modal.component';
3
+ export * from './lib/components/image-storage-preview/image-storage-preview';
3
4
  export * from './lib/classes/cropper.classes';
4
5
  export * from './lib/services/multi-images-storage.service';
5
6
  export * from './lib/services/dc-files-cache.service';
7
+ export * from './lib/services/multi-object-storage.service';