@eqproject/eqp-attachments 3.1.14 → 21.0.0

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,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, ViewChild, Output, Input, Component, NgModule } from '@angular/core';
2
+ import { Injectable, input, output, viewChild, signal, computed, effect, Input, Component, NgModule } from '@angular/core';
3
3
  import * as i2 from '@angular/forms';
4
4
  import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
5
5
  import imageCompression from 'browser-image-compression';
6
- import * as i14 from 'ngx-image-cropper';
7
- import { base64ToFile, ImageCropperComponent } from 'ngx-image-cropper';
6
+ import * as i13 from 'ngx-image-cropper';
7
+ import { ImageCropperComponent, base64ToFile } from 'ngx-image-cropper';
8
8
  import Swal from 'sweetalert2';
9
9
  import * as i1 from '@angular/material/dialog';
10
10
  import { MatDialogModule } from '@angular/material/dialog';
@@ -14,21 +14,20 @@ import * as i6 from '@angular/material/button';
14
14
  import { MatButtonModule } from '@angular/material/button';
15
15
  import * as i7 from '@angular/material/input';
16
16
  import { MatInputModule } from '@angular/material/input';
17
- import * as i8 from '@angular/material/form-field';
18
- import { MatFormFieldModule } from '@angular/material/form-field';
19
- import * as i9 from '@angular/material/menu';
17
+ import * as i8 from '@angular/material/menu';
20
18
  import { MatMenuModule } from '@angular/material/menu';
21
- import * as i10 from '@angular/material/button-toggle';
19
+ import * as i9 from '@angular/material/button-toggle';
22
20
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
23
- import * as i11 from '@angular/material/icon';
21
+ import * as i10 from '@angular/material/icon';
24
22
  import { MatIconModule } from '@angular/material/icon';
25
- import * as i12 from '@angular/material/tooltip';
23
+ import * as i11 from '@angular/material/tooltip';
26
24
  import { MatTooltipModule } from '@angular/material/tooltip';
27
- import * as i13 from '@angular/common';
25
+ import * as i12 from '@angular/common';
28
26
  import { CommonModule } from '@angular/common';
29
27
  import { MatCheckboxModule } from '@angular/material/checkbox';
30
28
  import { MatAutocompleteModule } from '@angular/material/autocomplete';
31
29
  import { MatDatepickerModule } from '@angular/material/datepicker';
30
+ import { MatFormFieldModule } from '@angular/material/form-field';
32
31
  import { MatRadioModule } from '@angular/material/radio';
33
32
  import { MatSelectModule } from '@angular/material/select';
34
33
  import { MatSliderModule } from '@angular/material/slider';
@@ -104,10 +103,10 @@ class AttachmentHelperService {
104
103
  let fileIcon = this.fileExtensionIcon[extension];
105
104
  return fileIcon ?? "fas fa-file";
106
105
  }
107
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttachmentHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
108
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttachmentHelperService, providedIn: 'root' });
106
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AttachmentHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
107
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AttachmentHelperService, providedIn: 'root' });
109
108
  }
110
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttachmentHelperService, decorators: [{
109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AttachmentHelperService, decorators: [{
111
110
  type: Injectable,
112
111
  args: [{
113
112
  providedIn: 'root'
@@ -222,10 +221,10 @@ class EqpAttachmentDialogService {
222
221
  Swal.fire(currentTitle, message, 'warning');
223
222
  }
224
223
  }
225
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
226
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentDialogService, providedIn: 'root' });
224
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
225
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentDialogService, providedIn: 'root' });
227
226
  }
228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentDialogService, decorators: [{
227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentDialogService, decorators: [{
229
228
  type: Injectable,
230
229
  args: [{
231
230
  providedIn: 'root'
@@ -242,10 +241,10 @@ class EqpAttachmentService {
242
241
  script.dataset.appKey = AttachmentHelperService.dropboxCredentials.apiKey;
243
242
  document.body.appendChild(script);
244
243
  }
245
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
246
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentService, providedIn: "root" });
244
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
245
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentService, providedIn: "root" });
247
246
  }
248
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentService, decorators: [{
247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentService, decorators: [{
249
248
  type: Injectable,
250
249
  args: [{
251
250
  providedIn: "root"
@@ -268,11 +267,11 @@ class EqpAttachmentsComponent {
268
267
  /**
269
268
  * Se TRUE allora nasconde la colonna per le azioni sull'allegato (nel caso "multipleAttachment" è TRUE).
270
269
  */
271
- disableAction = false;
270
+ disableAction = input(false, ...(ngDevMode ? [{ debugName: "disableAction" }] : /* istanbul ignore next */ []));
272
271
  /**
273
272
  * Se TRUE mostra il titolo nell'header nel caso in cui "multipleAttachment" è TRUE ("Elenco allegati" di default).
274
273
  */
275
- showHeader = true;
274
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
276
275
  /**
277
276
  * Sorgente dati da visualizzare. Nel caso si vuole gestire un singolo allegato va passato in ogni caso come Array.
278
277
  */
@@ -280,31 +279,31 @@ class EqpAttachmentsComponent {
280
279
  /**
281
280
  * Nel caso si vuole gestire un solo elemento senza passarlo come array, lo passo come singolo allegato e gestisco nella libreria l'array.
282
281
  */
283
- singleAttachment = null;
282
+ singleAttachment = input(null, ...(ngDevMode ? [{ debugName: "singleAttachment" }] : /* istanbul ignore next */ []));
284
283
  /**
285
284
  * Se TRUE non mostra la MatCard (nel caso in cui "multipleAttachment" è TRUE).
286
285
  */
287
- showMatCard = true;
286
+ showMatCard = input(true, ...(ngDevMode ? [{ debugName: "showMatCard" }] : /* istanbul ignore next */ []));
288
287
  /**
289
288
  * Se FALSE allora il componente mostra solo il pulsante di caricamento di un singolo file, una volta caricato il file invoca l'evento di output "localEditedAttachments".
290
289
  * Se TRUE allora il componente mostra l'elenco di tutti gli allegati ricevuto nel parametro "attachmentsList".
291
290
  */
292
- multipleAttachment = true;
291
+ multipleAttachment = input(true, ...(ngDevMode ? [{ debugName: "multipleAttachment" }] : /* istanbul ignore next */ []));
293
292
  /**
294
293
  * Se assume il valore TRUE allora sarà possibile caricare più file per volta. Questa funzionalità è attiva
295
294
  * SOLO se si gestiscono allegati multipli, quindi se l'input 'multipleAttachment' assume il valore TRUE, altrimenti è sempre disabilitata.
296
295
  */
297
- loadMultipleFiles = false;
296
+ loadMultipleFiles = input(false, ...(ngDevMode ? [{ debugName: "loadMultipleFiles" }] : /* istanbul ignore next */ []));
298
297
  /**
299
298
  * Imposta il messaggio da visualizzare nel caso in cui la tabella degli allegati (nel caso in cui "multipleAttachment" è TRUE) è vuota.
300
299
  */
301
- emptyTableMessage = "Nessun dato trovato";
300
+ emptyTableMessage = input("Nessun dato trovato", ...(ngDevMode ? [{ debugName: "emptyTableMessage" }] : /* istanbul ignore next */ []));
302
301
  /**
303
302
  * Se TRUE allora permette di selezionare soltanto file di tipo immagine, avente uno dei mimetype
304
303
  * specificati dentro AttachmentHelperService.
305
304
  * Se FALSE permette di selezionare qualsiasi tipo di file
306
305
  */
307
- allowOnlyImages = false;
306
+ allowOnlyImages = input(false, ...(ngDevMode ? [{ debugName: "allowOnlyImages" }] : /* istanbul ignore next */ []));
308
307
  /**
309
308
  * Specifica i tipi di file che è possibile caricare
310
309
  */
@@ -312,57 +311,60 @@ class EqpAttachmentsComponent {
312
311
  /**
313
312
  * Se TRUE disabilita il pulsante di Aggiunta allegato (a prescindere dal valore del parametro "multipleAttachment").
314
313
  */
315
- isDisabled = false;
314
+ isDisabled = input(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
316
315
  /**
317
316
  * Mostra/nasconde la colonna per visualizzare l'anteprima dei file nella tabella (caso multipleAtatchments = true).
318
317
  */
319
- showInlinePreview = false;
318
+ showInlinePreview = input(false, ...(ngDevMode ? [{ debugName: "showInlinePreview" }] : /* istanbul ignore next */ []));
320
319
  /**
321
320
  * Endpoint da chiamare per recueprare l'IAttachmentDTO completo da vedere nell'anteprima. La chiamata sarà in POST e nel body
322
321
  * conterrà l'IAttachmentDTO selezionato dall'utente.
323
322
  * La chiamata viene eseguita solo per l'anteprima delle immagini essendo necessario il base64 completo dell'immagine a dimensione reale.
324
323
  * Per documenti/link basta che sia popolata la proprietà FilePath di IAttachmentDTO.
325
324
  */
326
- getAttachmentEndpoint = null;
325
+ getAttachmentEndpoint = input(null, ...(ngDevMode ? [{ debugName: "getAttachmentEndpoint" }] : /* istanbul ignore next */ []));
327
326
  /**
328
327
  * Hostname dell'ambiente di produzione dell'applicativo. Necessario per visualizzare l'anteprima dei documenti
329
328
  * tramite il viewer di google.
330
329
  * NOTA: Per visualizzare l'anteprima è necessario che la prorietà FilePath dell'IAttachmentDTO sia popolata e che
331
330
  * sia abilitato l'accesso alla cartella sul server tramite hostname.
332
331
  */
333
- productionBaseUrl = null;
332
+ productionBaseUrl = input(null, ...(ngDevMode ? [{ debugName: "productionBaseUrl" }] : /* istanbul ignore next */ []));
334
333
  /**
335
334
  * Opzioni per la compressione delle immagini caricate.
336
335
  */
337
- compressionOptions = {
336
+ compressionOptions = input({
338
337
  maxSizeMB: 0.5,
339
338
  maxWidthOrHeight: 1920,
340
- useWebWorker: true
341
- };
339
+ useWebWorker: true,
340
+ }, ...(ngDevMode ? [{ debugName: "compressionOptions" }] : /* istanbul ignore next */ []));
342
341
  /**
343
342
  * Array di AttachmentType che si possono aggiungere
344
343
  */
345
- allowedTypes = [AttachmentType.FILE, AttachmentType.LINK];
344
+ allowedTypes = [
345
+ AttachmentType.FILE,
346
+ AttachmentType.LINK,
347
+ ];
346
348
  /**
347
349
  * Permette di stabilire se la eqp-table contenente l'elenco degli allegati utilizza
348
350
  * il multilingua oppure no
349
351
  */
350
- isEqpTableMultiLanguage = false;
352
+ isEqpTableMultiLanguage = input(false, ...(ngDevMode ? [{ debugName: "isEqpTableMultiLanguage" }] : /* istanbul ignore next */ []));
351
353
  /**
352
354
  * Permette di stabilire, in caso di gestione allegati multipli, se la tabella contenente l'elenco
353
355
  * degli allegati deve essere paginata oppure no
354
356
  */
355
- tablePaginatorVisible = true;
357
+ tablePaginatorVisible = input(true, ...(ngDevMode ? [{ debugName: "tablePaginatorVisible" }] : /* istanbul ignore next */ []));
356
358
  /**
357
359
  * Permette di stabilire, in caso di gestione allegati multipli, se la tabella contenente l'elenco
358
360
  * degli allegati deve contenere il campo di ricerca oppure no
359
361
  */
360
- isTableSearcheable = true;
362
+ isTableSearcheable = input(true, ...(ngDevMode ? [{ debugName: "isTableSearcheable" }] : /* istanbul ignore next */ []));
361
363
  /**
362
364
  * In caso di gestione allegati multipli, permette di stabilire la dimensione pagina di default
363
365
  * per la tabella contenente l'elenco degli allegati
364
366
  */
365
- tablePaginatorSize = null;
367
+ tablePaginatorSize = input(null, ...(ngDevMode ? [{ debugName: "tablePaginatorSize" }] : /* istanbul ignore next */ []));
366
368
  /**
367
369
  * Permette di scegliere il modo in cui i file devono essere caricati
368
370
  */
@@ -370,127 +372,124 @@ class EqpAttachmentsComponent {
370
372
  /**
371
373
  * Permette di stabilire se i pulsanti per il caricamento dei file sono separati o in un menù a tendina
372
374
  */
373
- separatedUploadButtons = false;
375
+ separatedUploadButtons = input(false, ...(ngDevMode ? [{ debugName: "separatedUploadButtons" }] : /* istanbul ignore next */ []));
374
376
  /**
375
377
  * Permette di scegliere se dare la possibilità di vedere o no l'anteprima
376
378
  */
377
- showPreview = true;
379
+ showPreview = input(true, ...(ngDevMode ? [{ debugName: "showPreview" }] : /* istanbul ignore next */ []));
378
380
  /**
379
381
  * In caso di allegato singolo, permette di scegliere se aggiungere file tramite drag and drop
380
382
  */
381
- singleAttachmentDragAndDrop = true;
383
+ singleAttachmentDragAndDrop = input(true, ...(ngDevMode ? [{ debugName: "singleAttachmentDragAndDrop" }] : /* istanbul ignore next */ []));
382
384
  /**
383
385
  * Array di opzioni che si possono utilizzare per il crop
384
386
  */
385
- cropOptions = [1, 2];
387
+ cropOptions = input([1, 2], ...(ngDevMode ? [{ debugName: "cropOptions" }] : /* istanbul ignore next */ []));
386
388
  /**
387
389
  * Classe custom da assegnare al dialog del crop immagini
388
390
  */
389
- cropDialogClass;
390
- maxFileSizeMB = 500; // Default max size of 100 MB
391
- cardSize = 'small'; // Default
392
- customCardWidthPx = 200; // Larghezza custom in px
393
- customCardHeightPx = 180; // Altezza custom in px
394
- layout = 'compact';
391
+ cropDialogClass = input(undefined, ...(ngDevMode ? [{ debugName: "cropDialogClass" }] : /* istanbul ignore next */ []));
392
+ maxFileSizeMB = input(500, ...(ngDevMode ? [{ debugName: "maxFileSizeMB" }] : /* istanbul ignore next */ [])); // Default max size of 100 MB
393
+ cardSize = input("small", ...(ngDevMode ? [{ debugName: "cardSize" }] : /* istanbul ignore next */ [])); // Default
394
+ customCardWidthPx = input(200, ...(ngDevMode ? [{ debugName: "customCardWidthPx" }] : /* istanbul ignore next */ [])); // Larghezza custom in px
395
+ customCardHeightPx = input(180, ...(ngDevMode ? [{ debugName: "customCardHeightPx" }] : /* istanbul ignore next */ [])); // Altezza custom in px
396
+ layout = input("compact", ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
395
397
  /**
396
398
  * Input per definire le label da usare nel componente
397
399
  */
398
- openLinkLabel = "Apri link";
399
- addButtonLabel = "Aggiungi";
400
- downloadLabel = "Download";
401
- deleteLabel = "Elimina";
402
- fileNameLabel = "Nome file";
403
- previewLabel = "Anteprima";
404
- uploadFileLabel = "Carica file";
405
- confirmLabel = "Conferma";
406
- abortLabel = "Annulla";
407
- saveLabel = "Salva";
408
- exitLabel = "Esci";
409
- uploadWithDropboxLabel = "Carica con Dropbox";
410
- cropLabel = "Scegli le dimensioni dell'immagine";
411
- deleteDialogTitle = null;
412
- deleteDialogMessage = "Sei sicuro di voler cancellare quest'allegato?";
413
- noImageSelectedErrorMessage = "Non è possibile selezionare un file che non sia un'immagine.";
414
- wrongTypeSelectedErrorMessage = "Non è possibile caricare il file selezionato.";
415
- videoPreviewErrorMessage = "Impossibile aprire l'anteprima di un file video.";
416
- audioPreviewErrorMessage = "Impossibile aprire l'anteprima di un file audio.";
417
- flipHorinzontalLabel = "Capovolgi orizzontalmente";
418
- flipVerticalLabel = "Capovolgi verticalmente";
419
- rotateRightLabel = "Ruota a destra";
420
- rotateLeftLabel = "Ruota a sinistra";
421
- base64LimitMB = 100;
422
- uploadTitle = 'Upload file';
423
- uploadSubtitle = 'Drag & drop files o click';
424
- dropHereLabel = 'Rilascia i file qui';
425
- supportedFormatsLabel = 'Formati supportati: JPEG, PNG, PDF (Max 100MB)';
426
- browseFilesLabel = 'Cerca i file';
427
- uploadSummaryLabel = 'Lista allegati';
428
- filesLabel = 'Files';
429
- totalSizeLabel = 'Dimensione totale';
430
- emptyStateLabel = 'Non sono presenti file caricati';
431
- addedSuccessfullyLabel = 'file(s) caricati con successo.';
432
- removedLabel = 'File rimosso';
400
+ openLinkLabel = input("Apri link", ...(ngDevMode ? [{ debugName: "openLinkLabel" }] : /* istanbul ignore next */ []));
401
+ addButtonLabel = input("Aggiungi", ...(ngDevMode ? [{ debugName: "addButtonLabel" }] : /* istanbul ignore next */ []));
402
+ downloadLabel = input("Download", ...(ngDevMode ? [{ debugName: "downloadLabel" }] : /* istanbul ignore next */ []));
403
+ deleteLabel = input("Elimina", ...(ngDevMode ? [{ debugName: "deleteLabel" }] : /* istanbul ignore next */ []));
404
+ fileNameLabel = input("Nome file", ...(ngDevMode ? [{ debugName: "fileNameLabel" }] : /* istanbul ignore next */ []));
405
+ previewLabel = input("Anteprima", ...(ngDevMode ? [{ debugName: "previewLabel" }] : /* istanbul ignore next */ []));
406
+ uploadFileLabel = input("Carica file", ...(ngDevMode ? [{ debugName: "uploadFileLabel" }] : /* istanbul ignore next */ []));
407
+ confirmLabel = input("Conferma", ...(ngDevMode ? [{ debugName: "confirmLabel" }] : /* istanbul ignore next */ []));
408
+ abortLabel = input("Annulla", ...(ngDevMode ? [{ debugName: "abortLabel" }] : /* istanbul ignore next */ []));
409
+ saveLabel = input("Salva", ...(ngDevMode ? [{ debugName: "saveLabel" }] : /* istanbul ignore next */ []));
410
+ exitLabel = input("Esci", ...(ngDevMode ? [{ debugName: "exitLabel" }] : /* istanbul ignore next */ []));
411
+ uploadWithDropboxLabel = input("Carica con Dropbox", ...(ngDevMode ? [{ debugName: "uploadWithDropboxLabel" }] : /* istanbul ignore next */ []));
412
+ cropLabel = input("Scegli le dimensioni dell'immagine", ...(ngDevMode ? [{ debugName: "cropLabel" }] : /* istanbul ignore next */ []));
413
+ deleteDialogTitle = input(null, ...(ngDevMode ? [{ debugName: "deleteDialogTitle" }] : /* istanbul ignore next */ []));
414
+ deleteDialogMessage = input("Sei sicuro di voler cancellare quest'allegato?", ...(ngDevMode ? [{ debugName: "deleteDialogMessage" }] : /* istanbul ignore next */ []));
415
+ noImageSelectedErrorMessage = input("Non è possibile selezionare un file che non sia un'immagine.", ...(ngDevMode ? [{ debugName: "noImageSelectedErrorMessage" }] : /* istanbul ignore next */ []));
416
+ wrongTypeSelectedErrorMessage = input("Non è possibile caricare il file selezionato.", ...(ngDevMode ? [{ debugName: "wrongTypeSelectedErrorMessage" }] : /* istanbul ignore next */ []));
417
+ videoPreviewErrorMessage = input("Impossibile aprire l'anteprima di un file video.", ...(ngDevMode ? [{ debugName: "videoPreviewErrorMessage" }] : /* istanbul ignore next */ []));
418
+ audioPreviewErrorMessage = input("Impossibile aprire l'anteprima di un file audio.", { ...(ngDevMode ? { debugName: "audioPreviewErrorMessage" } : /* istanbul ignore next */ {}), alias: "videoPreviewErrorMessage" });
419
+ flipHorinzontalLabel = input("Capovolgi orizzontalmente", ...(ngDevMode ? [{ debugName: "flipHorinzontalLabel" }] : /* istanbul ignore next */ []));
420
+ flipVerticalLabel = input("Capovolgi verticalmente", ...(ngDevMode ? [{ debugName: "flipVerticalLabel" }] : /* istanbul ignore next */ []));
421
+ rotateRightLabel = input("Ruota a destra", ...(ngDevMode ? [{ debugName: "rotateRightLabel" }] : /* istanbul ignore next */ []));
422
+ rotateLeftLabel = input("Ruota a sinistra", ...(ngDevMode ? [{ debugName: "rotateLeftLabel" }] : /* istanbul ignore next */ []));
423
+ base64LimitMB = input(100, ...(ngDevMode ? [{ debugName: "base64LimitMB" }] : /* istanbul ignore next */ []));
424
+ uploadTitle = input("Upload file", ...(ngDevMode ? [{ debugName: "uploadTitle" }] : /* istanbul ignore next */ []));
425
+ uploadSubtitle = input("Drag & drop files o click", ...(ngDevMode ? [{ debugName: "uploadSubtitle" }] : /* istanbul ignore next */ []));
426
+ dropHereLabel = input("Rilascia i file qui", ...(ngDevMode ? [{ debugName: "dropHereLabel" }] : /* istanbul ignore next */ []));
427
+ supportedFormatsLabel = input("Formati supportati: JPEG, PNG, PDF (Max 100MB)", ...(ngDevMode ? [{ debugName: "supportedFormatsLabel" }] : /* istanbul ignore next */ []));
428
+ browseFilesLabel = input("Cerca i file", ...(ngDevMode ? [{ debugName: "browseFilesLabel" }] : /* istanbul ignore next */ []));
429
+ uploadSummaryLabel = input("Lista allegati", ...(ngDevMode ? [{ debugName: "uploadSummaryLabel" }] : /* istanbul ignore next */ []));
430
+ filesLabel = input("Files", ...(ngDevMode ? [{ debugName: "filesLabel" }] : /* istanbul ignore next */ []));
431
+ totalSizeLabel = input("Dimensione totale", ...(ngDevMode ? [{ debugName: "totalSizeLabel" }] : /* istanbul ignore next */ []));
432
+ emptyStateLabel = input("Non sono presenti file caricati", ...(ngDevMode ? [{ debugName: "emptyStateLabel" }] : /* istanbul ignore next */ []));
433
+ addedSuccessfullyLabel = input("file(s) caricati con successo.", ...(ngDevMode ? [{ debugName: "addedSuccessfullyLabel" }] : /* istanbul ignore next */ []));
434
+ removedLabel = input("File rimosso", ...(ngDevMode ? [{ debugName: "removedLabel" }] : /* istanbul ignore next */ []));
433
435
  // @Input() removeLabel = 'Rimuovi file';
434
- chooseView = true;
435
- showSummary = false;
436
- viewMode = 'table';
437
- showUploadTitle = true;
438
- showDropArea = true;
439
- hiddenColumns = [];
440
- hiddenActions = [];
441
- showActionButtons = false;
436
+ chooseView = input(true, ...(ngDevMode ? [{ debugName: "chooseView" }] : /* istanbul ignore next */ []));
437
+ showSummary = input(false, ...(ngDevMode ? [{ debugName: "showSummary" }] : /* istanbul ignore next */ []));
438
+ viewMode = "table";
439
+ showUploadTitle = input(true, ...(ngDevMode ? [{ debugName: "showUploadTitle" }] : /* istanbul ignore next */ []));
440
+ showDropArea = input(true, ...(ngDevMode ? [{ debugName: "showDropArea" }] : /* istanbul ignore next */ []));
441
+ hiddenColumns = input([], ...(ngDevMode ? [{ debugName: "hiddenColumns" }] : /* istanbul ignore next */ []));
442
+ hiddenActions = input([], ...(ngDevMode ? [{ debugName: "hiddenActions" }] : /* istanbul ignore next */ []));
443
+ showActionButtons = input(false, ...(ngDevMode ? [{ debugName: "showActionButtons" }] : /* istanbul ignore next */ []));
442
444
  /**
443
445
  * Se TRUE allora mostra il dialog di crop per le immagini singole.
444
446
  * Se FALSE carica l'immagine direttamente (applicando comunque la compressione se attiva).
445
447
  */
446
- enableImageCrop = true;
448
+ enableImageCrop = input(true, ...(ngDevMode ? [{ debugName: "enableImageCrop" }] : /* istanbul ignore next */ []));
447
449
  /**
448
450
  * Hook globale: decide se nascondere un’azione per quello specifico allegato.
449
451
  */
450
- actionHiddenFn;
452
+ actionHiddenFn = input(undefined, ...(ngDevMode ? [{ debugName: "actionHiddenFn" }] : /* istanbul ignore next */ []));
451
453
  /**
452
454
  * Hook globale: decide se disabilitare un’azione per quello specifico allegato.
453
455
  */
454
- actionDisabledFn;
455
- videoCompression = { enabled: false, maxWidth: 1280, crf: 23, preset: 'veryfast', maxFps: 30, audioBitrate: 128000 };
456
- _customMenuActions = [];
456
+ actionDisabledFn = input(undefined, ...(ngDevMode ? [{ debugName: "actionDisabledFn" }] : /* istanbul ignore next */ []));
457
+ videoCompression = input({
458
+ enabled: false,
459
+ maxWidth: 1280,
460
+ crf: 23,
461
+ preset: "veryfast",
462
+ maxFps: 30,
463
+ audioBitrate: 128000,
464
+ }, ...(ngDevMode ? [{ debugName: "videoCompression" }] : /* istanbul ignore next */ []));
465
+ customMenuActions = input([], ...(ngDevMode ? [{ debugName: "customMenuActions" }] : /* istanbul ignore next */ []));
457
466
  _sortedMenuActions = [];
458
- set customMenuActions(value) {
459
- this._customMenuActions = value || [];
460
- this.setupMenuActions();
461
- }
462
- get customMenuActions() {
463
- return this._customMenuActions;
464
- }
465
- _customColumns = [];
466
467
  /**
467
468
  * SOLO quando [customColumns]="..." cambia.
468
469
  */
469
- set customColumns(value) {
470
- this._customColumns = value || [];
471
- this.setupTableColumns();
472
- }
473
- get customColumns() {
474
- return this._customColumns;
475
- }
470
+ customColumns = input([], ...(ngDevMode ? [{ debugName: "customColumns" }] : /* istanbul ignore next */ []));
476
471
  //#endregion
477
472
  //#region @Output del componente
478
473
  /**
479
474
  * Restituisce la lista aggiornata degli allegati.
480
475
  */
481
- localEditedAttachments = new EventEmitter();
476
+ localEditedAttachments = output();
482
477
  /**
483
478
  * Evento scatenato alla pressione del pulsante ESCI della modale di caricamento file.
484
479
  */
485
- abortAddAttachment = new EventEmitter();
480
+ abortAddAttachment = output();
486
481
  /**
487
482
  * Evento di output che restituisce l'IAttachmentDTO selezionato per il download nel caso FileDataBase64, FileContentType o FileName non fossero specificati.
488
483
  */
489
- downloadAttachment = new EventEmitter();
484
+ downloadAttachment = output({
485
+ alias: "downloadAttachment",
486
+ });
490
487
  /**
491
488
  * Evento di output che restituisce l'elemento eliminato prima che questo venga effettivamente rismosso dalla lista.
492
489
  */
493
- onDeleteAttachment = new EventEmitter();
490
+ onDeleteAttachment = output({
491
+ alias: "onDeleteAttachment",
492
+ });
494
493
  //#endregion
495
494
  //#region Proprietà per gestione caricamento nuovo allegato
496
495
  newAttachment = {};
@@ -501,20 +500,20 @@ class EqpAttachmentsComponent {
501
500
  selectedFile = null;
502
501
  selectedFiles = null;
503
502
  showCropImage = false;
504
- dialogAddAttachment;
503
+ dialogAddAttachment = viewChild("dialogAddAttachment", ...(ngDevMode ? [{ debugName: "dialogAddAttachment" }] : /* istanbul ignore next */ []));
505
504
  dialogRefAddAttachment;
506
- dialogAddMultipleAttachment;
505
+ dialogAddMultipleAttachment = viewChild("dialogAddMultipleAttachment", ...(ngDevMode ? [{ debugName: "dialogAddMultipleAttachment" }] : /* istanbul ignore next */ []));
507
506
  dialogRefCropImage;
508
- dialogCropImage;
509
- addingLinkTemplate;
507
+ dialogCropImage = viewChild("dialogCropImage", ...(ngDevMode ? [{ debugName: "dialogCropImage" }] : /* istanbul ignore next */ []));
508
+ addingLinkTemplate = viewChild("addingLinkTemplate", ...(ngDevMode ? [{ debugName: "addingLinkTemplate" }] : /* istanbul ignore next */ []));
510
509
  //#endregion
511
510
  //#region Proprietà per gestione ridimensionamento file di tipo image
512
511
  imageChangedEvent = "";
513
512
  croppedImage = "";
514
513
  transform = {};
515
514
  canvasRotation = 0;
516
- imageCropper;
517
- imageInput;
515
+ imageCropper = viewChild(ImageCropperComponent, ...(ngDevMode ? [{ debugName: "imageCropper" }] : /* istanbul ignore next */ []));
516
+ imageInput = viewChild("imageInput", ...(ngDevMode ? [{ debugName: "imageInput" }] : /* istanbul ignore next */ []));
518
517
  //#endregion
519
518
  AttachmentType = AttachmentType;
520
519
  selectedAttachment;
@@ -522,37 +521,37 @@ class EqpAttachmentsComponent {
522
521
  originalHeight;
523
522
  customWidth;
524
523
  customHeight;
525
- inlinePreviewTemplate;
526
- dialogPreview;
524
+ inlinePreviewTemplate = viewChild("inlinePreviewTemplate", ...(ngDevMode ? [{ debugName: "inlinePreviewTemplate" }] : /* istanbul ignore next */ []));
525
+ dialogPreview = viewChild("dialogPreview", ...(ngDevMode ? [{ debugName: "dialogPreview" }] : /* istanbul ignore next */ []));
527
526
  imageFile;
528
- addingLinkMode = false;
527
+ addingLinkMode = signal(false, ...(ngDevMode ? [{ debugName: "addingLinkMode" }] : /* istanbul ignore next */ []));
529
528
  //#region Sezione nuova refactoring
530
529
  // Proprietà interna che conterrà l'array finale di colonne ordinate
531
530
  _tableColumns = [];
532
- defaultFileTemplate;
533
- defaultActionsTemplate;
531
+ defaultFileTemplate = viewChild("defaultFileTemplate", ...(ngDevMode ? [{ debugName: "defaultFileTemplate" }] : /* istanbul ignore next */ []));
532
+ defaultActionsTemplate = viewChild("defaultActionsTemplate", ...(ngDevMode ? [{ debugName: "defaultActionsTemplate" }] : /* istanbul ignore next */ []));
534
533
  // Stato drag & drop e toast
535
534
  dragOver = false;
536
535
  toast = {
537
536
  visible: false,
538
- type: 'success',
539
- text: '',
540
- timeoutId: 0
537
+ type: "success",
538
+ text: "",
539
+ timeoutId: 0,
541
540
  };
542
- progressPercent = 0;
543
- totalSizeBytes = 0;
544
- get totalSizeFormatted() { return this.formatFileSize(this.totalSizeBytes); }
541
+ progressPercent = signal(0, ...(ngDevMode ? [{ debugName: "progressPercent" }] : /* istanbul ignore next */ []));
542
+ totalSizeBytes = signal(0, ...(ngDevMode ? [{ debugName: "totalSizeBytes" }] : /* istanbul ignore next */ []));
543
+ totalSizeFormatted = computed(() => this.formatFileSize(this.totalSizeBytes()), ...(ngDevMode ? [{ debugName: "totalSizeFormatted" }] : /* istanbul ignore next */ []));
545
544
  // Utility per formattare bytes (2 decimali)
546
545
  formatFileSize(bytes) {
547
546
  if (!bytes || bytes <= 0)
548
- return '0 Bytes';
547
+ return "0 Bytes";
549
548
  const k = 1024;
550
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
549
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
551
550
  const i = Math.floor(Math.log(bytes) / Math.log(k));
552
551
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
553
552
  }
554
553
  // Mostra toast con auto‑hide e reset progress bar CSS
555
- showToast(message, type = 'success', durationMs = 3000) {
554
+ showToast(message, type = "success", durationMs = 3000) {
556
555
  if (this.toast.visible && this.toast.text === message) {
557
556
  return;
558
557
  }
@@ -577,46 +576,61 @@ class EqpAttachmentsComponent {
577
576
  this.sanitizer = sanitizer;
578
577
  this.http = http;
579
578
  this.eqpAttachmentService = eqpAttachmentService;
579
+ effect(() => {
580
+ this.setupMenuActions();
581
+ });
582
+ effect(() => {
583
+ this.setupTableColumns();
584
+ });
580
585
  }
581
586
  ngOnInit() {
582
587
  // Inizializza metriche e progress in base allo stato iniziale
583
588
  this.recomputeTotalsAndProgress();
584
589
  //Se è stata richiesta la gestione delle sole immagini allora imposta il filtro per le estensioni possibili da caricare
585
590
  if (!this.acceptedFileTypes)
586
- if (this.allowOnlyImages == true)
591
+ if (this.allowOnlyImages() == true)
587
592
  this.acceptedFileTypes = "image/*";
588
593
  else
589
594
  this.acceptedFileTypes = "*";
590
595
  // Se non sono stati specificati i tipi da gestire ma è stato passato null o un array vuoto imposto i tipi di default.
591
596
  if (!this.allowedTypes || this.allowedTypes.length == 0)
592
- this.allowedTypes = [AttachmentType.FILE, AttachmentType.LINK, AttachmentType.DROPBOX];
593
- else if (this.allowedTypes.find((t) => t != AttachmentType.FILE && t != AttachmentType.LINK && t != AttachmentType.DROPBOX)) {
597
+ this.allowedTypes = [
598
+ AttachmentType.FILE,
599
+ AttachmentType.LINK,
600
+ AttachmentType.DROPBOX,
601
+ ];
602
+ else if (this.allowedTypes.find((t) => t != AttachmentType.FILE &&
603
+ t != AttachmentType.LINK &&
604
+ t != AttachmentType.DROPBOX)) {
594
605
  EqpAttachmentDialogService.Warning('Almeno uno degli AttachmentType selezionati nel parametro "allowedTypes" non esiste.');
595
- this.allowedTypes = [AttachmentType.FILE, AttachmentType.LINK, AttachmentType.DROPBOX];
606
+ this.allowedTypes = [
607
+ AttachmentType.FILE,
608
+ AttachmentType.LINK,
609
+ AttachmentType.DROPBOX,
610
+ ];
596
611
  }
597
612
  if (this.attachmentsList == null)
598
613
  this.attachmentsList = new Array();
599
614
  // Se è stato passato un singolo allegato lo aggiungo alla lista
600
- if (this.singleAttachment != null && this.attachmentsList.length == 0) {
601
- this.attachmentsList.push(this.singleAttachment);
615
+ if (this.singleAttachment() != null && this.attachmentsList.length == 0) {
616
+ this.attachmentsList.push(this.singleAttachment());
602
617
  }
603
618
  this.checkAttachmentImage();
604
619
  if (this.allowedTypes.includes(3)) {
605
620
  this.eqpAttachmentService.loadDropboxScript();
606
621
  }
607
- this.setupTableColumns();
608
- this.setupMenuActions();
609
622
  }
610
623
  setViewMode(mode) {
611
624
  this.viewMode = mode;
612
625
  }
613
626
  // Ricalcola la somma pesata sugli allegati presenti
614
627
  recomputeTotalsAndProgress() {
615
- this.totalSizeBytes = (this.attachmentsList || [])
616
- .filter(a => !!a)
617
- .reduce((sum, a) => sum + this.bytesFromBase64(a.FileDataBase64 || a.FileThumbnailBase64 || ''), 0);
628
+ this.totalSizeBytes.set((this.attachmentsList || [])
629
+ .filter((a) => !!a)
630
+ .reduce((sum, a) => sum +
631
+ this.bytesFromBase64(a.FileDataBase64 || a.FileThumbnailBase64 || ""), 0));
618
632
  // Progress fittizio: 100% se presenti file, 0 se vuoto
619
- this.progressPercent = (this.attachmentsList && this.attachmentsList.length > 0) ? 100 : 0;
633
+ this.progressPercent.set(this.attachmentsList && this.attachmentsList.length > 0 ? 100 : 0);
620
634
  }
621
635
  ngOnDestroy() {
622
636
  if (this.toast.timeoutId)
@@ -627,17 +641,17 @@ class EqpAttachmentsComponent {
627
641
  if (!base64)
628
642
  return 0;
629
643
  // Rimuovi eventuale prefisso data URL
630
- const commaIdx = base64.indexOf(',');
644
+ const commaIdx = base64.indexOf(",");
631
645
  const b64 = commaIdx >= 0 ? base64.substring(commaIdx + 1) : base64;
632
646
  // Conta padding
633
647
  let padding = 0;
634
- if (b64.endsWith('=='))
648
+ if (b64.endsWith("=="))
635
649
  padding = 2;
636
- else if (b64.endsWith('='))
650
+ else if (b64.endsWith("="))
637
651
  padding = 1;
638
652
  // Formula esatta: (3 * (len / 4)) - padding
639
653
  const len = b64.length;
640
- return Math.max(0, (3 * Math.floor(len / 4)) - padding);
654
+ return Math.max(0, 3 * Math.floor(len / 4) - padding);
641
655
  }
642
656
  checkAttachmentImage() {
643
657
  this.attachmentsList.forEach((a) => {
@@ -650,9 +664,9 @@ class EqpAttachmentsComponent {
650
664
  * @param element IAttachmentDTO da cancellare
651
665
  */
652
666
  deleteAttachment(element) {
653
- EqpAttachmentDialogService.Confirm(this.deleteDialogMessage, () => {
667
+ EqpAttachmentDialogService.Confirm(this.deleteDialogMessage(), () => {
654
668
  this.removeAttachmentFromList(this.attachmentsList.indexOf(element));
655
- }, true, this.deleteDialogTitle);
669
+ }, true, this.deleteDialogTitle());
656
670
  }
657
671
  /**
658
672
  * Rimuove l'allegato selezionato dalla lista "attachmentsList" e invoca l'evento di output che restituisce la lista aggiornata.
@@ -663,16 +677,16 @@ class EqpAttachmentsComponent {
663
677
  this.attachmentsList.splice(attachmentIndex, 1);
664
678
  this.localEditedAttachments.emit(this.attachmentsList);
665
679
  this.recomputeTotalsAndProgress();
666
- this.showToast(this.removedLabel || 'File removed', 'success');
680
+ this.showToast(this.removedLabel() || "File removed", "success");
667
681
  }
668
682
  simulateProgress() {
669
- this.progressPercent = 0;
683
+ this.progressPercent.set(0);
670
684
  setTimeout(() => {
671
- this.progressPercent = 30;
685
+ this.progressPercent.set(30);
672
686
  setTimeout(() => {
673
- this.progressPercent = 60;
687
+ this.progressPercent.set(60);
674
688
  setTimeout(() => {
675
- this.progressPercent = 100;
689
+ this.progressPercent.set(100);
676
690
  }, 200);
677
691
  }, 200);
678
692
  }, 100);
@@ -696,7 +710,9 @@ class EqpAttachmentsComponent {
696
710
  setTimeout(() => URL.revokeObjectURL(url), 1000);
697
711
  return;
698
712
  }
699
- if (attachment.FileDataBase64 && attachment.FileContentType && attachment.FileName) {
713
+ if (attachment.FileDataBase64 &&
714
+ attachment.FileContentType &&
715
+ attachment.FileName) {
700
716
  let source = `data:${attachment.FileContentType};base64,${attachment.FileDataBase64}`;
701
717
  const link = document.createElement("a");
702
718
  link.href = source;
@@ -740,7 +756,7 @@ class EqpAttachmentsComponent {
740
756
  name: [this.newAttachment.FileName],
741
757
  path: [this.newAttachment.FilePath],
742
758
  customHeight: [this.customHeight],
743
- customWidth: [this.customWidth]
759
+ customWidth: [this.customWidth],
744
760
  });
745
761
  }
746
762
  close(emitCloseEvent = true) {
@@ -760,32 +776,39 @@ class EqpAttachmentsComponent {
760
776
  * @returns
761
777
  */
762
778
  disableSave() {
763
- if (this.loadMultipleFiles != true) {
779
+ if (this.loadMultipleFiles() != true) {
764
780
  if (this.newAttachment.AttachmentType == AttachmentType.FILE) {
765
- return !this.newAttachment.FileDataBase64 && !this.newAttachment.LargeFile;
781
+ return (!this.newAttachment.FileDataBase64 && !this.newAttachment.LargeFile);
766
782
  }
767
783
  else {
768
784
  return !this.newAttachment.FilePath;
769
785
  }
770
786
  }
771
787
  else {
772
- return (this.newMultipleAttachments.filter((p) => (p.AttachmentType == AttachmentType.FILE && !p.FileDataBase64 && !p.LargeFile) ||
788
+ return (this.newMultipleAttachments.filter((p) => (p.AttachmentType == AttachmentType.FILE &&
789
+ !p.FileDataBase64 &&
790
+ !p.LargeFile) ||
773
791
  (p.AttachmentType == AttachmentType.LINK && !p.FilePath)).length > 0);
774
792
  }
775
793
  }
776
794
  confirmAddAttachment() {
777
- if (this.newAttachment.IsImage && this.imageCropper) {
778
- this.newAttachment.FileDataBase64 = this.imageCropper.crop().base64.split(";base64,")[1];
795
+ const imageCropper = this.imageCropper();
796
+ if (this.newAttachment.IsImage && imageCropper) {
797
+ this.newAttachment.FileDataBase64 = imageCropper
798
+ .crop()
799
+ .base64.split(";base64,")[1];
779
800
  }
780
- if (this.loadMultipleFiles != true) {
781
- if (this.newAttachment.AttachmentType == AttachmentType.LINK && !this.newAttachment.FileName)
801
+ if (this.loadMultipleFiles() != true) {
802
+ if (this.newAttachment.AttachmentType == AttachmentType.LINK &&
803
+ !this.newAttachment.FileName)
782
804
  this.newAttachment.FileName = this.newAttachment.FilePath;
783
805
  if (this.attachmentsList == null)
784
806
  this.attachmentsList = new Array();
785
807
  this.attachmentsList.push(this.newAttachment);
786
808
  }
787
809
  else {
788
- if (this.newMultipleAttachments == null || this.newMultipleAttachments.length == 0)
810
+ if (this.newMultipleAttachments == null ||
811
+ this.newMultipleAttachments.length == 0)
789
812
  return;
790
813
  if (this.attachmentsList == null)
791
814
  this.attachmentsList = new Array();
@@ -803,7 +826,7 @@ class EqpAttachmentsComponent {
803
826
  }
804
827
  this.resetSelectedFiles();
805
828
  }
806
- // 2. RESET TOTALE: Svuotiamo le proprietà di classe per evitare che
829
+ // 2. RESET TOTALE: Svuotiamo le proprietà di classe per evitare che
807
830
  // residui di upload precedenti (singoli o multipli) vengano trascinati.
808
831
  resetSelectedFiles() {
809
832
  this.newAttachment = {};
@@ -818,7 +841,9 @@ class EqpAttachmentsComponent {
818
841
  */
819
842
  async openPreviewDialog(row) {
820
843
  this.selectedAttachment = { ...row };
821
- if (this.getAttachmentEndpoint && this.selectedAttachment.IsImage && !this.selectedAttachment.FileDataBase64) {
844
+ if (this.getAttachmentEndpoint() &&
845
+ this.selectedAttachment.IsImage &&
846
+ !this.selectedAttachment.FileDataBase64) {
822
847
  await this.getAttachmentByID()
823
848
  .then((res) => {
824
849
  this.selectedAttachment.FileDataBase64 = res.FileDataBase64;
@@ -828,12 +853,15 @@ class EqpAttachmentsComponent {
828
853
  });
829
854
  }
830
855
  if (this.selectedAttachment.AttachmentType == AttachmentType.LINK) {
831
- this.selectedAttachment.TrustedUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.selectedAttachment.FilePath);
856
+ this.selectedAttachment.TrustedUrl =
857
+ this.sanitizer.bypassSecurityTrustResourceUrl(this.selectedAttachment.FilePath);
832
858
  }
833
- else if (this.selectedAttachment.FileContentType?.startsWith("video/") && this.selectedAttachment.LargeFile) {
859
+ else if (this.selectedAttachment.FileContentType?.startsWith("video/") &&
860
+ this.selectedAttachment.LargeFile) {
834
861
  const videoUrl = URL.createObjectURL(this.selectedAttachment.LargeFile);
835
862
  // Usiamo bypassSecurityTrustUrl per la sorgente del video
836
- this.selectedAttachment.TrustedUrl = this.sanitizer.bypassSecurityTrustUrl(videoUrl);
863
+ this.selectedAttachment.TrustedUrl =
864
+ this.sanitizer.bypassSecurityTrustUrl(videoUrl);
837
865
  }
838
866
  else if (this.selectedAttachment.IsImage &&
839
867
  !this.selectedAttachment.FileDataBase64 &&
@@ -841,26 +869,32 @@ class EqpAttachmentsComponent {
841
869
  EqpAttachmentDialogService.Info("Impossibile aprire l'anteprima dell'allegato, file mancante.");
842
870
  return;
843
871
  }
844
- else if (this.selectedAttachment.FileContentType === 'application/pdf' && this.selectedAttachment.FileDataBase64) {
845
- this.selectedAttachment.TrustedUrl = this.sanitizer.bypassSecurityTrustResourceUrl(`data:application/pdf;base64,${this.selectedAttachment.FileDataBase64}`);
872
+ else if (this.selectedAttachment.FileContentType === "application/pdf" &&
873
+ this.selectedAttachment.FileDataBase64) {
874
+ this.selectedAttachment.TrustedUrl =
875
+ this.sanitizer.bypassSecurityTrustResourceUrl(`data:application/pdf;base64,${this.selectedAttachment.FileDataBase64}`);
846
876
  }
847
877
  else if (!this.selectedAttachment.IsImage) {
848
- if (this.selectedAttachment.FilePath && this.productionBaseUrl) {
849
- this.selectedAttachment.TrustedUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://docs.google.com/gview?url=" +
850
- this.productionBaseUrl +
851
- "/" +
852
- this.selectedAttachment.FilePath +
853
- "&embedded=true");
878
+ const productionBaseUrl = this.productionBaseUrl();
879
+ if (this.selectedAttachment.FilePath && productionBaseUrl) {
880
+ this.selectedAttachment.TrustedUrl =
881
+ this.sanitizer.bypassSecurityTrustResourceUrl("https://docs.google.com/gview?url=" +
882
+ productionBaseUrl +
883
+ "/" +
884
+ this.selectedAttachment.FilePath +
885
+ "&embedded=true");
854
886
  }
855
887
  else {
856
888
  EqpAttachmentDialogService.Info("Impossibile aprire l'anteprima del documento!");
857
889
  return;
858
890
  }
859
891
  }
860
- const dialogRef = this.dialog.open(this.dialogPreview, {
861
- panelClass: 'eqp-attachments-preview-dialog',
862
- maxWidth: '95vw',
863
- width: row.IsImage || row.FileContentType?.startsWith('video/') ? 'auto' : '1100px',
892
+ const dialogRef = this.dialog.open(this.dialogPreview(), {
893
+ panelClass: "eqp-attachments-preview-dialog",
894
+ maxWidth: "95vw",
895
+ width: row.IsImage || row.FileContentType?.startsWith("video/")
896
+ ? "auto"
897
+ : "1100px",
864
898
  });
865
899
  // Pulizia della memoria quando il dialog si chiude
866
900
  dialogRef.afterClosed().subscribe(() => {
@@ -870,7 +904,9 @@ class EqpAttachmentsComponent {
870
904
  });
871
905
  }
872
906
  async getAttachmentByID() {
873
- return this.http.post(this.getAttachmentEndpoint, this.selectedAttachment).toPromise();
907
+ return this.http
908
+ .post(this.getAttachmentEndpoint(), this.selectedAttachment)
909
+ .toPromise();
874
910
  }
875
911
  //#region Gestione caricamento file
876
912
  /**
@@ -882,7 +918,7 @@ class EqpAttachmentsComponent {
882
918
  * immagine per il croppie (in caso di caricamento multiplo le funzionalità del croppie sono disabilitate).
883
919
  */
884
920
  async onFileAdded(event, isFileDropped = false) {
885
- if (this.isDisabled) {
921
+ if (this.isDisabled()) {
886
922
  EqpAttachmentDialogService.Info("Caricamento allegati non disponibile.");
887
923
  event.preventDefault();
888
924
  return;
@@ -895,13 +931,13 @@ class EqpAttachmentsComponent {
895
931
  const { validFiles, oversizedFiles } = this.validationFile(filesOnInput);
896
932
  if (!validFiles || validFiles.length === 0) {
897
933
  if (!isFileDropped && event?.target instanceof HTMLInputElement) {
898
- event.target.value = '';
934
+ event.target.value = "";
899
935
  }
900
936
  return;
901
937
  }
902
938
  //Se è stato richiesto il caricamento SINGOLO oppure se il caricamento è MULTIPLO ma è stato selezionato un solo file
903
939
  //allora verifica se il file è un immagine (per mostrare il CROPPIE)
904
- if ([...validFiles].length == 1 || this.loadMultipleFiles != true) {
940
+ if ([...validFiles].length == 1 || this.loadMultipleFiles() != true) {
905
941
  this.selectedFile = validFiles[0];
906
942
  this.selectedFiles = validFiles;
907
943
  if (!this.selectedFile)
@@ -917,7 +953,7 @@ class EqpAttachmentsComponent {
917
953
  this.createAttachmentForm();
918
954
  //Verifica se il file caricato è un'immagine oppure no. Se è un immagine, prima di caricarla mostra il croppie per il resize.
919
955
  //Se non è un immagine allora genera il Base64
920
- if (this.newAttachment.IsImage == true && this.enableImageCrop) {
956
+ if (this.newAttachment.IsImage == true && this.enableImageCrop()) {
921
957
  this.getImageDimensions(validFiles[0]);
922
958
  //Mostra il croppie e disabilita la form finchè non termina la modifica dell'immagine
923
959
  this.newAttachmentForm.disable();
@@ -926,13 +962,13 @@ class EqpAttachmentsComponent {
926
962
  setTimeout(() => {
927
963
  this.showCropImage = true;
928
964
  this.imageFile = event;
929
- this.dialogRefCropImage = this.dialog.open(this.dialogCropImage, {
965
+ this.dialogRefCropImage = this.dialog.open(this.dialogCropImage(), {
930
966
  disableClose: true,
931
967
  hasBackdrop: true,
932
- width: "95vw",
933
- maxWidth: "800px",
934
- maxHeight: "90vh",
935
- panelClass: ['eqp-attachments-dialog', 'crop-dialog']
968
+ width: "60%",
969
+ maxHeight: "80%",
970
+ maxWidth: "70vh",
971
+ panelClass: ["eqp-attachments-dialog", "crop-dialog"],
936
972
  });
937
973
  });
938
974
  }
@@ -964,15 +1000,15 @@ class EqpAttachmentsComponent {
964
1000
  this.simulateProgress();
965
1001
  // Caso 1: Successo Parziale (alcuni file validi, altri no)
966
1002
  if (oversizedFiles.length > 0 && validFiles.length > 0) {
967
- const fileNames = oversizedFiles.join(', ');
968
- this.showToast(`${validFiles.length} file aggiunti. ${oversizedFiles.length} non caricati perché troppo grandi (${fileNames}).`, 'error');
1003
+ const fileNames = oversizedFiles.join(", ");
1004
+ this.showToast(`${validFiles.length} file aggiunti. ${oversizedFiles.length} non caricati perché troppo grandi (${fileNames}).`, "error");
969
1005
  }
970
1006
  // Caso 2: Nessun file valido
971
1007
  else if (oversizedFiles.length > 0 && validFiles.length === 0) {
972
1008
  }
973
1009
  // Caso 3: Tutti i file validi
974
1010
  else if (oversizedFiles.length === 0 && validFiles.length > 0) {
975
- this.showToast(`${validFiles.length} ${this.addedSuccessfullyLabel || 'file(s) aggiunti con successo.'}`, 'success');
1011
+ this.showToast(`${validFiles.length} ${this.addedSuccessfullyLabel() || "file(s) aggiunti con successo."}`, "success");
976
1012
  }
977
1013
  //Resetto il valore del file input in modo da scatenare il change anche se si dovesse caricare lo stesso file
978
1014
  if (!isFileDropped)
@@ -983,7 +1019,7 @@ class EqpAttachmentsComponent {
983
1019
  const oversizedFiles = [];
984
1020
  for (const file of filesOnInput) {
985
1021
  const fileSizeMB = file.size / 1024 / 1024;
986
- if (fileSizeMB > this.maxFileSizeMB) {
1022
+ if (fileSizeMB > this.maxFileSizeMB()) {
987
1023
  oversizedFiles.push(file.name);
988
1024
  }
989
1025
  else {
@@ -991,8 +1027,8 @@ class EqpAttachmentsComponent {
991
1027
  }
992
1028
  }
993
1029
  if (oversizedFiles.length > 0) {
994
- const fileNames = oversizedFiles.join(', ');
995
- this.showToast(`File(s) troppo grandi: ${fileNames}. Limite: ${this.maxFileSizeMB}MB`, 'error');
1030
+ const fileNames = oversizedFiles.join(", ");
1031
+ this.showToast(`File(s) troppo grandi: ${fileNames}. Limite: ${this.maxFileSizeMB()}MB`, "error");
996
1032
  }
997
1033
  return { validFiles, oversizedFiles };
998
1034
  }
@@ -1013,22 +1049,25 @@ class EqpAttachmentsComponent {
1013
1049
  newAttachment.FileExtension = currentFile.name.substr(currentFile.name.lastIndexOf(".") + 1);
1014
1050
  newAttachment.IsImage = AttachmentHelperService.checkImageFromMimeType(currentFile.type);
1015
1051
  const fileSizeMB = currentFile.size / 1024 / 1024;
1016
- const isLargeFile = fileSizeMB > this.base64LimitMB;
1017
- const isVideo = currentFile.type.startsWith('video');
1052
+ const isLargeFile = fileSizeMB > this.base64LimitMB();
1053
+ const isVideo = currentFile.type.startsWith("video");
1018
1054
  if (isVideo) {
1019
1055
  let finalFile = currentFile;
1020
1056
  // 1. Genera la miniatura (rimane lato client perché è un'operazione istantanea)
1021
1057
  newAttachment.FileThumbnailBase64 = await this.generateVideoThumbnail(currentFile);
1022
1058
  // 2. Se la compressione è abilitata, inviamo il file all'API C#
1023
- if (this.videoCompression.enabled) {
1059
+ const videoCompression = this.videoCompression();
1060
+ if (videoCompression.enabled) {
1024
1061
  this.showToast("Compressione video in corso... L'operazione potrebbe richiedere alcuni minuti.", "info");
1025
1062
  try {
1026
1063
  // Chiamata al microservizio C# (metodo ristrutturato precedentemente)
1027
- const compressedBlob = await this.compressVideoApi(currentFile, this.videoCompression);
1064
+ const compressedBlob = await this.compressVideoApi(currentFile, videoCompression);
1028
1065
  // Creiamo il nuovo nome file con estensione .mp4
1029
1066
  const newFileName = currentFile.name.replace(/\.[^/.]+$/, "") + ".mp4";
1030
1067
  // Trasformiamo il Blob ricevuto in un File per mantenere la coerenza nell'oggetto DTO
1031
- finalFile = new File([compressedBlob], newFileName, { type: "video/mp4" });
1068
+ finalFile = new File([compressedBlob], newFileName, {
1069
+ type: "video/mp4",
1070
+ });
1032
1071
  // Aggiorniamo i metadati dell'allegato
1033
1072
  newAttachment.FileName = newFileName;
1034
1073
  newAttachment.FileContentType = "video/mp4";
@@ -1072,10 +1111,10 @@ class EqpAttachmentsComponent {
1072
1111
  */
1073
1112
  async getBase64FromFile(currentFile) {
1074
1113
  const fileSizeMB = currentFile.size / 1024 / 1024;
1075
- if (fileSizeMB > this.base64LimitMB) {
1114
+ if (fileSizeMB > this.base64LimitMB()) {
1076
1115
  return {
1077
1116
  Base64File: null,
1078
- ContentType: currentFile.type
1117
+ ContentType: currentFile.type,
1079
1118
  };
1080
1119
  }
1081
1120
  // Procedura standard
@@ -1088,7 +1127,7 @@ class EqpAttachmentsComponent {
1088
1127
  }
1089
1128
  return {
1090
1129
  Base64File: base64File,
1091
- ContentType: contentType
1130
+ ContentType: contentType,
1092
1131
  };
1093
1132
  }
1094
1133
  catch (ex) {
@@ -1109,7 +1148,9 @@ class EqpAttachmentsComponent {
1109
1148
  // Controllo corrispondenza esatta (es. image/png)
1110
1149
  if (this.acceptedFileTypes.includes(mimeType))
1111
1150
  return true;
1112
- const wildcards = this.acceptedFileTypes.split(",").filter(t => t.includes("*"));
1151
+ const wildcards = this.acceptedFileTypes
1152
+ .split(",")
1153
+ .filter((t) => t.includes("*"));
1113
1154
  for (let t of wildcards) {
1114
1155
  const prefix = t.split("*")[0]; // Prende "image/" da "image/*"
1115
1156
  if (mimeType.startsWith(prefix))
@@ -1117,13 +1158,13 @@ class EqpAttachmentsComponent {
1117
1158
  }
1118
1159
  return false;
1119
1160
  };
1120
- if (this.loadMultipleFiles !== true) {
1161
+ if (this.loadMultipleFiles() !== true) {
1121
1162
  // Caso Singolo
1122
1163
  return isTypeValid(this.selectedFile.type);
1123
1164
  }
1124
1165
  else {
1125
1166
  // Caso Multiplo: TUTTI i file selezionati devono essere validi
1126
- return Array.from(this.selectedFiles).every(file => isTypeValid(file.type));
1167
+ return Array.from(this.selectedFiles).every((file) => isTypeValid(file.type));
1127
1168
  }
1128
1169
  }
1129
1170
  /**
@@ -1132,13 +1173,13 @@ class EqpAttachmentsComponent {
1132
1173
  * Se il controllo va a buon fine restituisce TRUE altrimenti mostra un messaggio d'errore e restituisce FALSE
1133
1174
  */
1134
1175
  checkAllowOnlyImageFile(newAttachment) {
1135
- if (this.allowOnlyImages == true && newAttachment.IsImage != true) {
1136
- EqpAttachmentDialogService.Error(this.noImageSelectedErrorMessage);
1176
+ if (this.allowOnlyImages() == true && newAttachment.IsImage != true) {
1177
+ EqpAttachmentDialogService.Error(this.noImageSelectedErrorMessage());
1137
1178
  this.abortFile();
1138
1179
  return false;
1139
1180
  }
1140
1181
  else if (!this.checkAcceptedFiles()) {
1141
- EqpAttachmentDialogService.Error(this.wrongTypeSelectedErrorMessage);
1182
+ EqpAttachmentDialogService.Error(this.wrongTypeSelectedErrorMessage());
1142
1183
  this.abortFile();
1143
1184
  return false;
1144
1185
  }
@@ -1186,7 +1227,7 @@ class EqpAttachmentsComponent {
1186
1227
  getCroppedAndUpload(file, newAttachment) {
1187
1228
  var self = this;
1188
1229
  var file = base64ToFile(file);
1189
- const options = this.compressionOptions;
1230
+ const options = this.compressionOptions();
1190
1231
  /**
1191
1232
  * Comprime l'immagine passando come parametri le options create nell'oggetto sopra, e il file dal reader principale
1192
1233
  */
@@ -1219,19 +1260,19 @@ class EqpAttachmentsComponent {
1219
1260
  this.transform = {
1220
1261
  ...this.transform,
1221
1262
  flipH: flippedV,
1222
- flipV: flippedH
1263
+ flipV: flippedH,
1223
1264
  };
1224
1265
  }
1225
1266
  flipHorizontal() {
1226
1267
  this.transform = {
1227
1268
  ...this.transform,
1228
- flipH: !this.transform.flipH
1269
+ flipH: !this.transform.flipH,
1229
1270
  };
1230
1271
  }
1231
1272
  flipVertical() {
1232
1273
  this.transform = {
1233
1274
  ...this.transform,
1234
- flipV: !this.transform.flipV
1275
+ flipV: !this.transform.flipV,
1235
1276
  };
1236
1277
  }
1237
1278
  //#endregion
@@ -1239,8 +1280,9 @@ class EqpAttachmentsComponent {
1239
1280
  * Annulla la selezione del file, svuotando l'input e resettando tutte le proprietà dell'IAttachmentDTO
1240
1281
  */
1241
1282
  abortFile() {
1242
- if (this.imageInput)
1243
- this.imageInput.nativeElement.value = "";
1283
+ const imageInput = this.imageInput();
1284
+ if (imageInput)
1285
+ imageInput.nativeElement.value = "";
1244
1286
  this.selectedFile = null;
1245
1287
  this.selectedFiles = null;
1246
1288
  this.showCropImage = false;
@@ -1270,7 +1312,7 @@ class EqpAttachmentsComponent {
1270
1312
  // Se il caricamento del file dropbox va a buon fine, la funzione di callback restituisce un array di oggetti.
1271
1313
  // Viene poi fatta una XMLHttpRequest con responseType 'blob' per convertire il primo elemento della response in un Blob.
1272
1314
  chooseDropboxFile() {
1273
- if (this.isDisabled)
1315
+ if (this.isDisabled())
1274
1316
  return;
1275
1317
  var options = {
1276
1318
  success: (files) => {
@@ -1288,7 +1330,7 @@ class EqpAttachmentsComponent {
1288
1330
  },
1289
1331
  linkType: "direct",
1290
1332
  multiselect: false,
1291
- extensions: [".jpg", ".png", ".pdf", ".doc", ".docx", ".txt"]
1333
+ extensions: [".jpg", ".png", ".pdf", ".doc", ".docx", ".txt"],
1292
1334
  };
1293
1335
  Dropbox.choose(options);
1294
1336
  }
@@ -1296,7 +1338,7 @@ class EqpAttachmentsComponent {
1296
1338
  onSelectFile(event, fileInput) {
1297
1339
  if (event.target.tagName === "BUTTON" ||
1298
1340
  event.target.tagName === "INPUT" ||
1299
- this.addingLinkMode == true) {
1341
+ this.addingLinkMode() == true) {
1300
1342
  return;
1301
1343
  }
1302
1344
  fileInput.click();
@@ -1305,17 +1347,17 @@ class EqpAttachmentsComponent {
1305
1347
  * Apre il dialogo per l'inserimento del link.
1306
1348
  */
1307
1349
  switchToAddingLinkMode() {
1308
- if (this.isDisabled)
1350
+ if (this.isDisabled())
1309
1351
  return;
1310
1352
  this.newAttachmentForm = this.formBuilder.group({
1311
- fileName: [''],
1312
- filePath: ['', [Validators.required, Validators.pattern('https?://.+')]]
1353
+ fileName: [""],
1354
+ filePath: ["", [Validators.required, Validators.pattern("https?://.+")]],
1313
1355
  });
1314
- const dialogRef = this.dialog.open(this.addingLinkTemplate, {
1315
- width: '500px',
1316
- panelClass: 'eqp-attachments-dialog'
1356
+ const dialogRef = this.dialog.open(this.addingLinkTemplate(), {
1357
+ width: "500px",
1358
+ panelClass: "eqp-attachments-dialog",
1317
1359
  });
1318
- dialogRef.afterClosed().subscribe(result => {
1360
+ dialogRef.afterClosed().subscribe((result) => {
1319
1361
  if (result) {
1320
1362
  // Crea l'oggetto per il nuovo link dai dati del form
1321
1363
  const newLinkObject = {
@@ -1323,7 +1365,7 @@ class EqpAttachmentsComponent {
1323
1365
  AttachmentType: AttachmentType.LINK,
1324
1366
  FileName: result.fileName,
1325
1367
  FilePath: result.filePath,
1326
- IsImage: false
1368
+ IsImage: false,
1327
1369
  };
1328
1370
  this.newAttachment = newLinkObject;
1329
1371
  this.newMultipleAttachments = [newLinkObject];
@@ -1334,26 +1376,27 @@ class EqpAttachmentsComponent {
1334
1376
  // Metodo per ottenere le classi CSS dinamiche
1335
1377
  getCardClass(att) {
1336
1378
  return {
1337
- 'file-preview': true,
1338
- 'uploading': !!att.isUploading,
1339
- 'card-small': this.cardSize === 'small',
1340
- 'card-medium': this.cardSize === 'medium',
1341
- 'card-large': this.cardSize === 'large',
1379
+ "file-preview": true,
1380
+ uploading: !!att.isUploading,
1381
+ "card-small": this.cardSize() === "small",
1382
+ "card-medium": this.cardSize() === "medium",
1383
+ "card-large": this.cardSize() === "large",
1342
1384
  };
1343
1385
  }
1344
1386
  // Questa funzione ora si applica al contenitore, non alla singola card.
1345
1387
  getPreviewsContainerStyle() {
1346
- let minWidth = '200px'; // Dimensione di default per 'medium'
1347
- if (this.cardSize === 'small') {
1348
- minWidth = '140px';
1388
+ let minWidth = "200px"; // Dimensione di default per 'medium'
1389
+ const cardSize = this.cardSize();
1390
+ if (cardSize === "small") {
1391
+ minWidth = "140px";
1349
1392
  }
1350
- else if (this.cardSize === 'large') {
1351
- minWidth = '280px';
1393
+ else if (cardSize === "large") {
1394
+ minWidth = "280px";
1352
1395
  }
1353
- else if (this.cardSize === 'custom') {
1354
- minWidth = `${this.customCardWidthPx}px`;
1396
+ else if (cardSize === "custom") {
1397
+ minWidth = `${this.customCardWidthPx()}px`;
1355
1398
  }
1356
- return { '--card-min-width': minWidth };
1399
+ return { "--card-min-width": minWidth };
1357
1400
  }
1358
1401
  handlePrimaryAction(attachment) {
1359
1402
  // Se il file può essere visualizzato in anteprima, apri il dialog
@@ -1366,10 +1409,10 @@ class EqpAttachmentsComponent {
1366
1409
  }
1367
1410
  }
1368
1411
  /**
1369
- * Determines if an attachment can be previewed in the dialog.
1370
- * @param att The attachment to check.
1371
- * @returns `true` if a preview is available, otherwise `false`.
1372
- */
1412
+ * Determines if an attachment can be previewed in the dialog.
1413
+ * @param att The attachment to check.
1414
+ * @returns `true` if a preview is available, otherwise `false`.
1415
+ */
1373
1416
  canBePreviewed(att) {
1374
1417
  if (!att) {
1375
1418
  return false;
@@ -1377,56 +1420,60 @@ class EqpAttachmentsComponent {
1377
1420
  // Case 1: It's an image with Base64 data.
1378
1421
  const isPreviewableImage = att.IsImage && !!att.FileDataBase64;
1379
1422
  // Case 2: It's a PDF with Base64 data.
1380
- const isPreviewablePdf = att.FileContentType === 'application/pdf' && !!att.FileDataBase64;
1423
+ const isPreviewablePdf = att.FileContentType === "application/pdf" && !!att.FileDataBase64;
1381
1424
  // Case 3: It's a remote document with a URL (for Google Viewer).
1382
- const isRemoteDocument = !att.IsImage && !!att.FilePath && !!this.productionBaseUrl;
1425
+ const isRemoteDocument = !att.IsImage && !!att.FilePath && !!this.productionBaseUrl();
1383
1426
  //Case 4: Video - È un video e abbiamo il file binario salvato in LargeFile
1384
- const isPreviewableVideo = att.FileContentType?.startsWith('video/') && !!att.LargeFile;
1427
+ const isPreviewableVideo = att.FileContentType?.startsWith("video/") && !!att.LargeFile;
1385
1428
  // A preview is possible if any of these conditions are true.
1386
- return isPreviewableImage || isPreviewablePdf || isRemoteDocument || isPreviewableVideo;
1429
+ return (isPreviewableImage ||
1430
+ isPreviewablePdf ||
1431
+ isRemoteDocument ||
1432
+ isPreviewableVideo);
1387
1433
  }
1388
1434
  isColumnHidden(col) {
1389
1435
  // 1) hiddenColumns
1390
- if (this.hiddenColumns?.includes(col.key))
1436
+ if (this.hiddenColumns()?.includes(col.key))
1391
1437
  return true;
1392
1438
  // 2) hidden definito sulla colonna (boolean o funzione senza args)
1393
- if (typeof col.hidden === 'function')
1439
+ if (typeof col.hidden === "function")
1394
1440
  return !!col.hidden();
1395
1441
  return !!col.hidden;
1396
1442
  }
1397
1443
  isActionHidden(action, att) {
1398
- if (this.hiddenActions?.includes(action.key))
1444
+ if (this.hiddenActions()?.includes(action.key))
1399
1445
  return true;
1400
- if (this.actionHiddenFn?.(action.key, att))
1446
+ if (this.actionHiddenFn()?.(action.key, att))
1401
1447
  return true;
1402
- if (typeof action.hidden === 'function')
1448
+ if (typeof action.hidden === "function")
1403
1449
  return !!action.hidden(att);
1404
1450
  return !!action.hidden;
1405
1451
  }
1406
1452
  isActionDisabled(action, att) {
1407
- if (this.actionDisabledFn?.(action.key, att))
1453
+ if (this.actionDisabledFn()?.(action.key, att))
1408
1454
  return true;
1409
- if (typeof action.disabled === 'function')
1455
+ if (typeof action.disabled === "function")
1410
1456
  return !!action.disabled(att);
1411
1457
  return !!action.disabled;
1412
1458
  }
1413
1459
  isDeleteHidden(att) {
1414
- return this.actionHiddenFn?.('delete', att) || this.hiddenActions?.includes('delete');
1460
+ return (this.actionHiddenFn()?.("delete", att) ||
1461
+ this.hiddenActions()?.includes("delete"));
1415
1462
  }
1416
1463
  isDeleteDisabled(att) {
1417
- return this.disableAction || !!this.actionDisabledFn?.('delete', att);
1464
+ return this.disableAction() || !!this.actionDisabledFn()?.("delete", att);
1418
1465
  }
1419
1466
  isPrimaryActionHidden(att) {
1420
- if (this.hiddenActions?.includes('download') || this.hiddenActions?.includes('preview') || this.hiddenActions?.includes('primaryAction'))
1467
+ if (this.hiddenActions()?.includes('download') || this.hiddenActions()?.includes('preview') || this.hiddenActions()?.includes('primaryAction'))
1421
1468
  return true;
1422
- if (this.hiddenColumns?.includes('download') || this.hiddenColumns?.includes('preview') || this.hiddenColumns?.includes('primaryAction'))
1469
+ if (this.hiddenColumns()?.includes('download') || this.hiddenColumns()?.includes('preview') || this.hiddenColumns()?.includes('primaryAction'))
1423
1470
  return true;
1424
- if (this.actionHiddenFn?.('primaryAction', att) || this.actionHiddenFn?.('download', att) || this.actionHiddenFn?.('preview', att))
1471
+ if (this.actionHiddenFn()?.('primaryAction', att) || this.actionHiddenFn()?.('download', att) || this.actionHiddenFn()?.('preview', att))
1425
1472
  return true;
1426
1473
  return false;
1427
1474
  }
1428
1475
  isPrimaryActionDisabled(att) {
1429
- if (this.actionDisabledFn?.('primaryAction', att) || this.actionDisabledFn?.('download', att) || this.actionDisabledFn?.('preview', att))
1476
+ if (this.actionDisabledFn()?.('primaryAction', att) || this.actionDisabledFn()?.('download', att) || this.actionDisabledFn()?.('preview', att))
1430
1477
  return true;
1431
1478
  return false;
1432
1479
  }
@@ -1436,28 +1483,28 @@ class EqpAttachmentsComponent {
1436
1483
  setupTableColumns() {
1437
1484
  // Definiamo le colonne standard con una posizione
1438
1485
  const defaultFileColumn = {
1439
- key: 'file',
1440
- display: 'File',
1486
+ key: "file",
1487
+ display: "File",
1441
1488
  type: TypeAttachmentColumn.TEMPLATE,
1442
- externalTemplate: this.defaultFileTemplate,
1443
- styles: { flex: '1 1 0%' },
1444
- position: 10
1489
+ externalTemplate: this.defaultFileTemplate(),
1490
+ styles: { flex: "1 1 0%" },
1491
+ position: 10,
1445
1492
  };
1446
1493
  const defaultActionsColumn = {
1447
- key: 'actions',
1448
- display: 'Azioni',
1494
+ key: "actions",
1495
+ display: "Azioni",
1449
1496
  type: TypeAttachmentColumn.TEMPLATE,
1450
- externalTemplate: this.defaultActionsTemplate,
1497
+ externalTemplate: this.defaultActionsTemplate(),
1451
1498
  position: 100,
1452
- class: 'col-actions',
1453
- styles: { flex: '0 0 150px' }
1499
+ class: "col-actions",
1500
+ styles: { flex: "0 0 150px" },
1454
1501
  };
1455
- const processedCustomColumns = this._customColumns.map(col => {
1502
+ const processedCustomColumns = this.customColumns().map((col) => {
1456
1503
  // Flex di default
1457
1504
  if (!col.styles || !col.styles.flex) {
1458
1505
  return {
1459
1506
  ...col,
1460
- styles: { ...col.styles, flex: '1 1 0%' }
1507
+ styles: { ...col.styles, flex: "1 1 0%" },
1461
1508
  };
1462
1509
  }
1463
1510
  return col;
@@ -1465,10 +1512,11 @@ class EqpAttachmentsComponent {
1465
1512
  const allColumns = [
1466
1513
  defaultFileColumn,
1467
1514
  defaultActionsColumn,
1468
- ...processedCustomColumns
1515
+ ...processedCustomColumns,
1469
1516
  ];
1470
1517
  // Ordiniamo l'array finale in base alla proprietà 'position'
1471
- this._tableColumns = allColumns.filter(col => !this.isColumnHidden(col))
1518
+ this._tableColumns = allColumns
1519
+ .filter((col) => !this.isColumnHidden(col))
1472
1520
  .sort((a, b) => {
1473
1521
  const posA = a.position || 99;
1474
1522
  const posB = b.position || 99;
@@ -1477,25 +1525,25 @@ class EqpAttachmentsComponent {
1477
1525
  }
1478
1526
  setupMenuActions() {
1479
1527
  const defaultPreviewAction = {
1480
- key: 'preview',
1481
- icon: 'visibility',
1482
- name: 'Anteprima',
1528
+ key: "preview",
1529
+ icon: "visibility",
1530
+ name: "Anteprima",
1483
1531
  fn: (att) => this.openPreviewDialog(att),
1484
1532
  disabled: (att) => !this.canBePreviewed(att),
1485
- position: 10
1533
+ position: 10,
1486
1534
  };
1487
1535
  const defaultDeleteAction = {
1488
- key: 'delete',
1489
- icon: 'delete',
1490
- name: 'Elimina',
1536
+ key: "delete",
1537
+ icon: "delete",
1538
+ name: "Elimina",
1491
1539
  fn: (att) => this.deleteAttachment(att),
1492
- disabled: () => this.disableAction,
1493
- position: 100
1540
+ disabled: () => this.disableAction(),
1541
+ position: 100,
1494
1542
  };
1495
1543
  const allActions = [
1496
1544
  defaultPreviewAction,
1497
1545
  defaultDeleteAction,
1498
- ...this._customMenuActions
1546
+ ...this.customMenuActions(),
1499
1547
  ];
1500
1548
  // Ordiniamo l'array finale in base alla proprietà 'position'
1501
1549
  this._sortedMenuActions = allActions.sort((a, b) => {
@@ -1506,13 +1554,13 @@ class EqpAttachmentsComponent {
1506
1554
  }
1507
1555
  generateVideoThumbnail(file) {
1508
1556
  return new Promise((resolve, reject) => {
1509
- const video = document.createElement('video');
1510
- const canvas = document.createElement('canvas');
1511
- const context = canvas.getContext('2d');
1557
+ const video = document.createElement("video");
1558
+ const canvas = document.createElement("canvas");
1559
+ const context = canvas.getContext("2d");
1512
1560
  // Crea un URL temporaneo per il file video
1513
1561
  const videoUrl = URL.createObjectURL(file);
1514
1562
  video.src = videoUrl;
1515
- video.preload = 'metadata';
1563
+ video.preload = "metadata";
1516
1564
  video.muted = true;
1517
1565
  video.playsInline = true;
1518
1566
  video.onloadedmetadata = () => {
@@ -1526,10 +1574,10 @@ class EqpAttachmentsComponent {
1526
1574
  // Disegna il fotogramma sul canvas
1527
1575
  context.drawImage(video, 0, 0, canvas.width, canvas.height);
1528
1576
  // Estrai il Base64 (qualità 0.7 per risparmiare spazio)
1529
- const thumbnail = canvas.toDataURL('image/jpeg', 0.7);
1577
+ const thumbnail = canvas.toDataURL("image/jpeg", 0.7);
1530
1578
  // Pulisci la memoria
1531
1579
  URL.revokeObjectURL(videoUrl);
1532
- resolve(thumbnail.split(',')[1]); // Restituiamo solo la parte Base64
1580
+ resolve(thumbnail.split(",")[1]); // Restituiamo solo la parte Base64
1533
1581
  };
1534
1582
  video.onerror = (err) => {
1535
1583
  URL.revokeObjectURL(videoUrl);
@@ -1540,25 +1588,25 @@ class EqpAttachmentsComponent {
1540
1588
  async compressVideoApi(file, config) {
1541
1589
  // Prepariamo il FormData per inviare il file binario e i parametri di configurazione
1542
1590
  const formData = new FormData();
1543
- formData.append('video', file);
1544
- formData.append('maxWidth', String(config.maxWidth ?? 1280));
1591
+ formData.append("video", file);
1592
+ formData.append("maxWidth", String(config.maxWidth ?? 1280));
1545
1593
  if (config.crf != null)
1546
- formData.append('crf', String(config.crf));
1594
+ formData.append("crf", String(config.crf));
1547
1595
  if (config.preset)
1548
- formData.append('preset', config.preset);
1596
+ formData.append("preset", config.preset);
1549
1597
  if (config.crf == null) {
1550
- formData.append('bitrate', String(config.bitrate ?? 2500000));
1598
+ formData.append("bitrate", String(config.bitrate ?? 2500000));
1551
1599
  }
1552
1600
  if (config.maxFps != null)
1553
- formData.append('maxFps', String(config.maxFps));
1601
+ formData.append("maxFps", String(config.maxFps));
1554
1602
  if (config.audioBitrate != null)
1555
- formData.append('audioBitrate', String(config.audioBitrate));
1603
+ formData.append("audioBitrate", String(config.audioBitrate));
1556
1604
  // URL della tua API C#
1557
- const apiUrl = 'https://tuo-servizio-api.it/api/video/compress';
1605
+ const apiUrl = "https://tuo-servizio-api.it/api/video/compress";
1558
1606
  try {
1559
1607
  // Effettuiamo la chiamata. Usiamo 'fetch' per semplicità o HttpClient di Angular
1560
1608
  const response = await fetch(apiUrl, {
1561
- method: 'POST',
1609
+ method: "POST",
1562
1610
  body: formData,
1563
1611
  // Nota: Non impostare Content-Type, il browser lo farà correttamente includendo il boundary
1564
1612
  });
@@ -1573,268 +1621,29 @@ class EqpAttachmentsComponent {
1573
1621
  throw error;
1574
1622
  }
1575
1623
  }
1576
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsComponent, deps: [{ token: i1.MatDialog }, { token: i2.FormBuilder }, { token: i3.DomSanitizer }, { token: i4.HttpClient }, { token: EqpAttachmentService }], target: i0.ɵɵFactoryTarget.Component });
1577
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EqpAttachmentsComponent, selector: "eqp-attachments", inputs: { disableAction: "disableAction", showHeader: "showHeader", attachmentsList: "attachmentsList", singleAttachment: "singleAttachment", showMatCard: "showMatCard", multipleAttachment: "multipleAttachment", loadMultipleFiles: "loadMultipleFiles", emptyTableMessage: "emptyTableMessage", allowOnlyImages: "allowOnlyImages", acceptedFileTypes: "acceptedFileTypes", isDisabled: "isDisabled", showInlinePreview: "showInlinePreview", getAttachmentEndpoint: "getAttachmentEndpoint", productionBaseUrl: "productionBaseUrl", compressionOptions: "compressionOptions", allowedTypes: "allowedTypes", isEqpTableMultiLanguage: "isEqpTableMultiLanguage", tablePaginatorVisible: "tablePaginatorVisible", isTableSearcheable: "isTableSearcheable", tablePaginatorSize: "tablePaginatorSize", separatedUploadButtons: "separatedUploadButtons", showPreview: "showPreview", singleAttachmentDragAndDrop: "singleAttachmentDragAndDrop", cropOptions: "cropOptions", cropDialogClass: "cropDialogClass", maxFileSizeMB: "maxFileSizeMB", cardSize: "cardSize", customCardWidthPx: "customCardWidthPx", customCardHeightPx: "customCardHeightPx", layout: "layout", openLinkLabel: "openLinkLabel", addButtonLabel: "addButtonLabel", downloadLabel: "downloadLabel", deleteLabel: "deleteLabel", fileNameLabel: "fileNameLabel", previewLabel: "previewLabel", uploadFileLabel: "uploadFileLabel", confirmLabel: "confirmLabel", abortLabel: "abortLabel", saveLabel: "saveLabel", exitLabel: "exitLabel", uploadWithDropboxLabel: "uploadWithDropboxLabel", cropLabel: "cropLabel", deleteDialogTitle: "deleteDialogTitle", deleteDialogMessage: "deleteDialogMessage", noImageSelectedErrorMessage: "noImageSelectedErrorMessage", wrongTypeSelectedErrorMessage: "wrongTypeSelectedErrorMessage", videoPreviewErrorMessage: "videoPreviewErrorMessage", audioPreviewErrorMessage: ["videoPreviewErrorMessage", "audioPreviewErrorMessage"], flipHorinzontalLabel: "flipHorinzontalLabel", flipVerticalLabel: "flipVerticalLabel", rotateRightLabel: "rotateRightLabel", rotateLeftLabel: "rotateLeftLabel", base64LimitMB: "base64LimitMB", uploadTitle: "uploadTitle", uploadSubtitle: "uploadSubtitle", dropHereLabel: "dropHereLabel", supportedFormatsLabel: "supportedFormatsLabel", browseFilesLabel: "browseFilesLabel", uploadSummaryLabel: "uploadSummaryLabel", filesLabel: "filesLabel", totalSizeLabel: "totalSizeLabel", emptyStateLabel: "emptyStateLabel", addedSuccessfullyLabel: "addedSuccessfullyLabel", removedLabel: "removedLabel", chooseView: "chooseView", showSummary: "showSummary", viewMode: "viewMode", showUploadTitle: "showUploadTitle", showDropArea: "showDropArea", hiddenColumns: "hiddenColumns", hiddenActions: "hiddenActions", showActionButtons: "showActionButtons", enableImageCrop: "enableImageCrop", actionHiddenFn: "actionHiddenFn", actionDisabledFn: "actionDisabledFn", videoCompression: "videoCompression", customMenuActions: "customMenuActions", customColumns: "customColumns" }, outputs: { localEditedAttachments: "localEditedAttachments", abortAddAttachment: "abortAddAttachment", downloadAttachment: "downloadAttachment", onDeleteAttachment: "onDeleteAttachment" }, viewQueries: [{ propertyName: "dialogAddAttachment", first: true, predicate: ["dialogAddAttachment"], descendants: true, static: true }, { propertyName: "dialogAddMultipleAttachment", first: true, predicate: ["dialogAddMultipleAttachment"], descendants: true, static: true }, { propertyName: "dialogCropImage", first: true, predicate: ["dialogCropImage"], descendants: true, static: true }, { propertyName: "addingLinkTemplate", first: true, predicate: ["addingLinkTemplate"], descendants: true }, { propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true }, { propertyName: "imageInput", first: true, predicate: ["imageInput"], descendants: true }, { propertyName: "inlinePreviewTemplate", first: true, predicate: ["inlinePreviewTemplate"], descendants: true, static: true }, { propertyName: "dialogPreview", first: true, predicate: ["dialogPreview"], descendants: true, static: true }, { propertyName: "defaultFileTemplate", first: true, predicate: ["defaultFileTemplate"], descendants: true, static: true }, { propertyName: "defaultActionsTemplate", first: true, predicate: ["defaultActionsTemplate"], descendants: true, static: true }], ngImport: i0, template: "<!-- Se richiesta la gestione singola mostra il pulsante di caricamento di un singolo file -->\r\n@if(showUploadTitle == true || chooseView == true){\r\n<div class=\"header\">\r\n @if(showUploadTitle == true){\r\n <h4>{{ uploadTitle }}</h4>\r\n }\r\n @if(chooseView == true){\r\n <mat-button-toggle-group [value]=\"viewMode\" (change)=\"setViewMode($event.value)\"\r\n aria-label=\"Modalit\u00E0 di visualizzazione\">\r\n <mat-button-toggle value=\"card\"><mat-icon>grid_view</mat-icon></mat-button-toggle>\r\n <mat-button-toggle value=\"table\"><mat-icon>view_list</mat-icon></mat-button-toggle>\r\n </mat-button-toggle-group>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione singolo -->\r\n@if (multipleAttachment != true) {\r\n@if (!singleAttachmentDragAndDrop) {\r\n@if (!addingLinkMode) {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addAttachmentButton\"></ng-container>\r\n</div>\r\n} @else {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addingLinkTemplate\"></ng-container>\r\n</div>\r\n}\r\n} @else {\r\n<input #fileInput id=\"file_attachment\" name=\"file_attachment\" type=\"file\" hidden (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n@if (allowedTypes && allowedTypes.includes(1) && (!attachmentsList || attachmentsList.length == 0 ||\r\n(attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n\r\n@if (showDropArea == true) {\r\n<!-- FULL -->\r\n@if (layout === 'full') {\r\n\r\n<div class=\"dropbox\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\"\r\n (click)=\"!isDisabled && onSelectFile($event, fileInput)\" role=\"button\" [attr.tabindex]=\"isDisabled ? -1 : 0\"\r\n (keydown.enter)=\"!isDisabled && fileInput.click()\" (keydown.space)=\"!isDisabled && fileInput.click()\">\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel }}\r\n </div>\r\n <button class=\"browse-btn\" type=\"button\" (click)=\"$event.stopPropagation(); fileInput.click()\">\r\n {{ browseFilesLabel }}\r\n </button>\r\n <div class=\"secondary-action\">\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n @if (allowedTypes.includes(2) && allowedTypes.includes(3)) {\r\n <a class=\"secondary-action-link\" [matMenuTriggerFor]=\"isDisabled ? null : linkMenu\"\r\n [class.disabled-link]=\"isDisabled\" (click)=\"$event.stopPropagation()\">\r\n o aggiungi da web\r\n </a>\r\n <mat-menu #linkMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"switchToAddingLinkMode()\">\r\n <mat-icon>link</mat-icon>\r\n <span>Aggiungi da link</span>\r\n </button>\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\">\r\n <mat-icon>cloud_queue</mat-icon>\r\n <span>Carica da Dropbox</span>\r\n </button>\r\n </mat-menu>\r\n }\r\n\r\n @else if (allowedTypes.includes(2)) {\r\n <a [class.disabled-link]=\"isDisabled\" class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\">\r\n aggiungi un link\r\n </a>\r\n }\r\n\r\n @else if (allowedTypes.includes(3)) {\r\n <a [class.disabled-link]=\"isDisabled\" class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); chooseDropboxFile()\">\r\n carica da Dropbox\r\n </a>\r\n }\r\n }\r\n </div>\r\n</div>\r\n}@else {\r\n<div class=\"compact-uploader\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\">\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"!isDisabled && onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button mat-stroked-button color=\"primary\" [disabled]=\"isDisabled\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\">Sfoglia</button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button mat-stroked-button [disabled]=\"isDisabled\" [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\">Link</button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) { <button mat-menu-item [disabled]=\"isDisabled\"\r\n (click)=\"switchToAddingLinkMode()\">{{ openLinkLabel }}</button> }\r\n @if (allowedTypes.includes(3)) { <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"chooseDropboxFile()\">{{\r\n uploadWithDropboxLabel }}</button> }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n}\r\n}\r\n}\r\n}\r\n\r\n<!-- Azioni singolo elemento (come prima) -->\r\n<div class=\"text-center\">\r\n @if (attachmentsList && attachmentsList.length > 0 && attachmentsList[0] && showActionButtons == true) {\r\n @if (!isPrimaryActionHidden(attachmentsList[0])) {\r\n <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button color=\"primary\">\r\n @if (attachmentsList[0].AttachmentType == AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n {{ attachmentsList[0].AttachmentType == AttachmentType.FILE ? downloadLabel : openLinkLabel }}\r\n </button>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(attachmentsList[0]) && showPreview && (!attachmentsList[0].FileContentType || (!attachmentsList[0].FileContentType.startsWith('video')\r\n && !attachmentsList[0].FileContentType.startsWith('audio'))) && attachmentsList[0].IsImage == true) {\r\n <button class=\"mb-2 me-2 eqp-attachments-preview-btn\" (click)=\"openPreviewDialog(attachmentsList[0])\" type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button color=\"primary\">\r\n <mat-icon>visibility</mat-icon> {{ previewLabel }}\r\n </button>\r\n }\r\n\r\n <button [disabled]=\"disableAction\" class=\"mb-2 eqp-attachments-delete-btn\"\r\n (click)=\"deleteAttachment(attachmentsList[0])\" type=\"button\" mat-raised-button [disabled]=\"isDisabled\">\r\n <mat-icon>delete</mat-icon> {{ deleteLabel }}\r\n </button>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione multipla -->\r\n@if (multipleAttachment == true && showDropArea == true) {\r\n<input #fileInput id=\"file_attachment_multi\" name=\"file_attachment_multi\" type=\"file\" hidden\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n@if (layout === 'full') {\r\n<div class=\"dropbox\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\"\r\n (click)=\"!isDisabled && onSelectFile($event, fileInput)\" role=\"button\" [attr.tabindex]=\"isDisabled ? -1 : 0\"\r\n (keydown.enter)=\"!isDisabled && fileInput.click()\" (keydown.space)=\"!isDisabled && fileInput.click()\">\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel }}\r\n </div>\r\n <button class=\"browse-btn\" type=\"button\" (click)=\"$event.stopPropagation(); fileInput.click()\">\r\n {{ browseFilesLabel }}\r\n </button>\r\n @if (allowedTypes.includes(2)) {\r\n <div class=\"secondary-action-link\">\r\n o <a (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\">aggiungi un link</a>\r\n </div>\r\n }\r\n</div>\r\n}@else{\r\n<div class=\"compact-uploader\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\">\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"!isDisabled && onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button mat-stroked-button [disabled]=\"isDisabled\" color=\"primary\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\">Sfoglia</button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button mat-stroked-button [disabled]=\"isDisabled\" [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\">Link</button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) { <button mat-menu-item [disabled]=\"isDisabled\"\r\n (click)=\"switchToAddingLinkMode()\">{{ openLinkLabel }}</button> }\r\n @if (allowedTypes.includes(3)) { <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"chooseDropboxFile()\">{{\r\n uploadWithDropboxLabel }}</button> }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n}\r\n}\r\n\r\n@if (attachmentsList?.length > 0 && showSummary) {\r\n<div class=\"upload-stats\">\r\n\r\n <div class=\"stats-info\">\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ attachmentsList?.length }}</div>\r\n <div class=\"stat-label\">{{ filesLabel }}</div>\r\n </div>\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ totalSizeFormatted }}</div>\r\n <div class=\"stat-label\">{{ totalSizeLabel }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"progressPercent\"></div>\r\n </div>\r\n\r\n</div>\r\n} @else if(attachmentsList?.length == 0){\r\n<div class=\"empty-state\">{{ emptyStateLabel }}</div>\r\n}\r\n\r\n<!-- Griglia anteprime card (vale per singolo e multiplo) -->\r\n@if (viewMode === 'card') {\r\n\r\n<div class=\"file-previews\" [ngStyle]=\"getPreviewsContainerStyle()\">\r\n @for (att of attachmentsList; track att.ID) {\r\n <div [ngClass]=\"getCardClass(att)\">\r\n <div class=\"preview-img-container\" (click)=\"!att.isUploading && !isPrimaryActionHidden(att) && !isPrimaryActionDisabled(att) && handlePrimaryAction(att)\">\r\n\r\n @if (att.IsImage || att.FileThumbnailBase64) {\r\n <img class=\"preview-img\" [src]=\"'data:image/jpeg;base64,' + (att.FileThumbnailBase64 || att.FileDataBase64)\"\r\n [alt]=\"att.FileName\" />\r\n } @else {\r\n <div class=\"file-icon\"><i [ngClass]=\"getAttachmentIcon(att)\"></i></div>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(att)) {\r\n <div class=\"preview-action-overlay\">\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n <mat-icon>play_arrow</mat-icon>\r\n }\r\n @else if (att.IsImage && canBePreviewed(att)) {\r\n <mat-icon>visibility</mat-icon>\r\n }\r\n @else if (att.FileContentType === 'application/pdf' && canBePreviewed(att)) {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n @else if (att.AttachmentType === AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n }\r\n @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n </div>\r\n }\r\n\r\n </div>\r\n\r\n <div class=\"file-info\">\r\n <div class=\"file-name\" [title]=\"att.FileName\">{{ att.FileName }}</div>\r\n </div>\r\n\r\n @if(!isDeleteHidden(att)){\r\n <button mat-icon-button class=\"remove-btn\" (click)=\"deleteAttachment(att)\"\r\n [disabled]=\"att.isUploading || isDeleteDisabled(att)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n }\r\n\r\n @if (att.isUploading) {\r\n <div class=\"upload-spinner\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n} @else if(viewMode === 'table' && attachmentsList?.length > 0) {\r\n\r\n\r\n<div class=\"table-view-container\">\r\n\r\n <div class=\"table-header\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div class=\"table-cell\" [style.flex]=\"col.styles?.flex\" [ngClass]=\"col.class\">\r\n {{ col.display }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @for (att of attachmentsList; track att.ID) {\r\n <div class=\"table-row\">\r\n\r\n @for (col of _tableColumns; track col.key) {\r\n <div class=\"table-cell\" [style.flex]=\"col.styles?.flex\" [ngClass]=\"col.class\">\r\n\r\n @switch (col.type) {\r\n\r\n @case ('template') {\r\n <div class=\"template-wrapper\">\r\n <ng-container [ngTemplateOutlet]=\"col.externalTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: att }\"></ng-container>\r\n </div>\r\n }\r\n @case ('date') {\r\n <span class=\"metadata-value\">{{ att[col.key] | date:'dd/MM/yyyy' }}</span>\r\n }\r\n @default {\r\n <span class=\"metadata-value\">{{ att[col.key] }}</span>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Notifica toast -->\r\n<div class=\"upload-notification\" [class.show]=\"toast?.visible\" [class.success]=\"toast?.type === 'success'\"\r\n [class.error]=\"toast?.type === 'error'\">\r\n <span>{{ toast?.text }}</span>\r\n <div class=\"notification-progress\"></div>\r\n</div>\r\n\r\n<ng-template #defaultFileTemplate let-att>\r\n <i class=\"file-icon-small\" [ngClass]=\"getAttachmentIcon(att)\"></i>\r\n <div class=\"file-info-text\">\r\n <span class=\"file-name-table\">{{ att.FileName }}</span>\r\n <span class=\"file-type-table\">{{ att.FileExtension || 'Link' }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #defaultActionsTemplate let-att>\r\n @if (!isPrimaryActionHidden(att)) {\r\n <button mat-icon-button (click)=\"handlePrimaryAction(att)\" [disabled]=\"isPrimaryActionDisabled(att)\"\r\n [matTooltip]=\"att.FileContentType?.startsWith('video/') ? 'Riproduci video' : 'Visualizza/Scarica'\">\r\n\r\n <mat-icon>\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n play_arrow\r\n } @else {\r\n {{ att.AttachmentType === AttachmentType.FILE ? 'download' : 'open_in_new' }}\r\n }\r\n </mat-icon>\r\n </button>\r\n }\r\n\r\n @if (!hiddenActions.includes('actionsMenu')) {\r\n <button mat-icon-button [matMenuTriggerFor]=\"actionsMenu\" matTooltip=\"Altre opzioni\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n\r\n <mat-menu #actionsMenu=\"matMenu\">\r\n @for (action of _sortedMenuActions; track action.name) {\r\n @if (!isActionHidden(action, att)) {\r\n <button mat-menu-item (click)=\"action.fn(att)\" [disabled]=\"isActionDisabled(action, att)\">\r\n <mat-icon [color]=\"action.icon === 'delete' ? 'warn' : undefined\">\r\n {{ action.icon }}\r\n </mat-icon>\r\n <span>{{ action.name }}</span>\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n</ng-template>\r\n\r\n\r\n<ng-template #dialogCropImage>\r\n <div style=\"overflow-x: hidden; display: flex; flex-direction: column; height: 100%; min-height: 0; flex: 1 1 auto;\"\r\n [ngClass]=\"cropDialogClass\">\r\n <!-- @if (showCropImage == true) { -->\r\n <ng-container [ngTemplateOutlet]=\"croppieTemplate\" [ngTemplateOutletContext]=\"{ form: newAttachmentForm }\">\r\n </ng-container>\r\n <!-- } -->\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<ng-template #inlinePreviewTemplate let-row=\"row\">\r\n @if (row.AttachmentType != AttachmentType.LINK && row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <img [src]=\"'data:image/png;base64,' + (row.FileThumbnailBase64 ? row.FileThumbnailBase64 : row.FileDataBase64)\" />\r\n </div>\r\n } @else if (row.AttachmentType != AttachmentType.LINK && !row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <i [ngClass]=\"getAttachmentIcon(row)\"></i>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n\r\n<ng-template #dialogPreview>\r\n <div class=\"modern-dialog-container\"> @if (selectedAttachment) {\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ previewLabel }}</span>\r\n <span class=\"file-t\">{{ selectedAttachment.FileName }}</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"media-viewer-wrapper\">\r\n @if (selectedAttachment.IsImage) {\r\n <img class=\"main-preview-media\"\r\n [src]=\"'data:image/png;base64,' + (selectedAttachment.FileDataBase64 || selectedAttachment.FileThumbnailBase64)\"\r\n [alt]=\"selectedAttachment.FileName\" />\r\n }\r\n @else if (selectedAttachment.FileContentType?.startsWith('video/')) {\r\n <video controls autoplay playsinline class=\"main-preview-media video-player\">\r\n <source [src]=\"selectedAttachment.TrustedUrl\" [type]=\"selectedAttachment.FileContentType\">\r\n Il tuo browser non supporta il video.\r\n </video>\r\n }\r\n @else {\r\n <div class=\"iframe-container\">\r\n <iframe class=\"preview-iframe-modern\" [src]=\"selectedAttachment.TrustedUrl\"\r\n [title]=\"selectedAttachment.FileName\"></iframe>\r\n </div>\r\n }\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Chiudi</button>\r\n @if (selectedAttachment.AttachmentType !== AttachmentType.LINK) {\r\n <button mat-raised-button color=\"primary\" (click)=\"viewAttachment(selectedAttachment)\" class=\"btn-download\">\r\n <mat-icon>download</mat-icon> <span>{{ downloadLabel }}</span>\r\n </button>\r\n }\r\n </mat-dialog-actions>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<!-- TEMPLATE PER IL PULSANTE DI AGGIUNTA NUOVO ALLEGATO -->\r\n<ng-template #addAttachmentButton>\r\n <input #fileInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n @if (allowedTypes && allowedTypes.length == 1 && (multipleAttachment == true || !attachmentsList ||\r\n attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\" mat-raised-button color=\"primary\" type=\"button\"\r\n (click)=\"addFile(allowedTypes[0], fileInput)\" [disabled]=\"isDisabled\">\r\n @if (allowedTypes[0] == 1) { <mat-icon>cloud_upload</mat-icon> }\r\n @if (allowedTypes[0] == 2) { <i class=\"fas fa-link\"></i> }\r\n @if (allowedTypes[0] == 3) { <i class=\"fa-brands fa-dropbox\"></i> }\r\n <span style=\"margin-left: 10px\">\r\n {{ allowedTypes[0] == 1 ? (addButtonLabel + \" file\") : allowedTypes[0] == 2 ? (addButtonLabel + \" link\") :\r\n uploadWithDropboxLabel }}\r\n </span>\r\n </button>\r\n }\r\n\r\n @if (!separatedUploadButtons && allowedTypes && allowedTypes.length > 1 && (multipleAttachment == true ||\r\n !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\" mat-raised-button color=\"primary\" type=\"button\"\r\n [matMenuTriggerFor]=\"attachmentTypeMenu\" [disabled]=\"isDisabled\">\r\n @if (multipleAttachment != true) { <mat-icon>cloud_upload</mat-icon> } @else { <mat-icon>add</mat-icon> }\r\n <span style=\"margin-left: 0px\">{{ addButtonLabel }}</span>\r\n </button>\r\n\r\n <mat-menu #attachmentTypeMenu=\"matMenu\">\r\n <input #imageInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n @if (allowedTypes.includes(1)) {\r\n <button mat-menu-item (click)=\"imageInput.click()\" class=\"eqp-attachments-file-btn\">\r\n <i class=\"fas fa-file\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(2)) {\r\n <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"switchToAddingLinkMode()\" class=\"eqp-attachments-link-btn\">\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(3)) {\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\" class=\"eqp-attachments-link-btn\">\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n\r\n @if (separatedUploadButtons && allowedTypes && allowedTypes.length > 1 && (multipleAttachment == true ||\r\n !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <div class=\"btn-group\">\r\n @if (allowedTypes.includes(1)) {\r\n <button (click)=\"imageInput.click()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fa-solid fa-cloud-upload\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n <input #imageInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n @if (allowedTypes.includes(2)) {\r\n <button (click)=\"switchToAddingLinkMode()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(3)) {\r\n <button (click)=\"chooseDropboxFile()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n\r\n<ng-template #croppieTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ cropLabel }}</span>\r\n <span class=\"file-t\">Regola le dimensioni e l'orientamento</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button type=\"button\" (click)=\"abortFile()\" class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"crop-toolbar\">\r\n @if (cropOptions.includes(1)) {\r\n <button mat-icon-button [matTooltip]=\"rotateLeftLabel\"\r\n (click)=\"rotateLeft()\"><mat-icon>rotate_left</mat-icon></button>\r\n <button mat-icon-button [matTooltip]=\"rotateRightLabel\"\r\n (click)=\"rotateRight()\"><mat-icon>rotate_right</mat-icon></button>\r\n }\r\n @if (cropOptions.includes(2)) {\r\n <button mat-icon-button [matTooltip]=\"flipHorinzontalLabel\"\r\n (click)=\"flipHorizontal()\"><mat-icon>flip_horizontal</mat-icon></button>\r\n <button mat-icon-button [matTooltip]=\"flipVerticalLabel\"\r\n (click)=\"flipVertical()\"><mat-icon>flip_vertical</mat-icon></button>\r\n }\r\n <button mat-icon-button matTooltip=\"Reset\"\r\n (click)=\"restoreOriginalDimensions()\"><mat-icon>replay</mat-icon></button>\r\n </div>\r\n\r\n <div class=\"media-viewer-wrapper\">\r\n <div class=\"crop-container-modern\">\r\n <image-cropper [imageFile]=\"selectedFile\" [maintainAspectRatio]=\"false\" [canvasRotation]=\"canvasRotation\"\r\n [transform]=\"transform\" format=\"png\" (imageCropped)=\"imageCropped($event)\" [resizeToWidth]=\"customWidth\"\r\n [resizeToHeight]=\"customHeight\" [output]=\"'base64'\" [containWithinAspectRatio]=\"true\" [onlyScaleDown]=\"true\"\r\n [alignImage]=\"'center'\">\r\n </image-cropper>\r\n </div>\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button (click)=\"abortFile()\" class=\"btn-close\">{{ abortLabel }}</button>\r\n <button mat-raised-button color=\"primary\" (click)=\"confirmAddAttachment()\" class=\"btn-download\">\r\n <mat-icon>check</mat-icon> {{ confirmLabel }}\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n\r\n<!-- TEMPLATE PER FORM DI AGGIUNTA DI UN LINK -->\r\n<ng-template #addingLinkTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"type-icon-wrapper\">\r\n <mat-icon>link</mat-icon>\r\n </div>\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">Aggiungi un link</span>\r\n <span class=\"file-t\">Inserisci l'URL della risorsa web</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"add-link-modern-content\">\r\n <form [formGroup]=\"newAttachmentForm\" class=\"add-link-form\">\r\n <mat-form-field appearance=\"outline\" class=\"w-100 mt-3\">\r\n <mat-label>URL del collegamento</mat-label>\r\n <input matInput formControlName=\"filePath\" placeholder=\"https://...\" required>\r\n <mat-icon matSuffix>language</mat-icon>\r\n </mat-form-field>\r\n\r\n <mat-form-field appearance=\"outline\" class=\"w-100\">\r\n <mat-label>Titolo (opzionale)</mat-label>\r\n <input matInput formControlName=\"fileName\" placeholder=\"Es. Documento Progetto\">\r\n <mat-icon matSuffix>title</mat-icon>\r\n </mat-form-field>\r\n </form>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Annulla</button>\r\n <button mat-raised-button color=\"primary\" [mat-dialog-close]=\"newAttachmentForm.value\"\r\n [disabled]=\"newAttachmentForm.invalid\" class=\"btn-download\">\r\n <mat-icon>add</mat-icon> Aggiungi\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{--primary-color: #6a5af9;--primary-color-dark: #5441f8;--success-color: #1ce593;--error-color: #ff5b5b;--background-light: #f7f9fc;--background-card: rgba(255, 255, 255, .7);--text-color: #1e293b;--text-color-light: #64748b;--border-color: rgba(203, 213, 225, .5);--shadow-color: rgba(99, 102, 241, .2);--border-radius: 16px;--transition-speed: .3s}@keyframes fadeIn{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--primary-color)}70%{box-shadow:0 0 0 10px #6a5af900}to{box-shadow:0 0 #6a5af900}}.container{width:100%;max-width:700px;margin:2rem auto;font-family:Inter,sans-serif}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border-color)}.header h1{color:var(--text-color);font-size:1.8rem;font-weight:700;margin:0}.dropbox{width:100%;border:2px dashed var(--border-color);border-radius:var(--border-radius);padding:2.5rem;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;cursor:pointer;background-color:var(--background-card);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:all var(--transition-speed) ease}.dropbox:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color);border-color:var(--primary-color)}.dropbox.dragover{border-style:solid;border-color:var(--primary-color);transform:scale(1.02);box-shadow:0 0 25px var(--shadow-color);animation:pulse 1.5s infinite}.dropbox .dropbox-icon{font-size:3.5rem;color:var(--primary-color)}.dropbox .dropbox-text{font-size:1.1rem;font-weight:600;color:var(--text-color);margin-top:1rem}.dropbox .dropbox-subtext{color:var(--text-color-light);margin-top:.5rem}.dropbox .browse-btn{margin-top:1.5rem;padding:.75rem 1.5rem;background-color:var(--primary-color);color:#fff;border:none;border-radius:10px;font-weight:600;transition:all var(--transition-speed) ease}.dropbox .browse-btn:hover{background-color:var(--primary-color-dark);transform:translateY(-2px)}.file-previews{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1.5rem;margin-top:2rem}.file-previews{display:grid;gap:16px;padding:16px;grid-template-columns:repeat(auto-fill,minmax(var(--card-min-width, 200px),1fr))}.file-preview{background-color:var(--background-card);border-radius:var(--border-radius);box-shadow:0 4px 15px #0000000d;border:1px solid var(--border-color);overflow:hidden;display:flex;flex-direction:column;position:relative;opacity:0;animation:fadeIn .5s ease-out forwards;transition:transform var(--transition-speed) ease,box-shadow var(--transition-speed) ease}.file-preview.uploading{cursor:wait}.file-preview.uploading .preview-img-container:after{content:\"\";position:absolute;inset:0;background:#ffffffb3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);pointer-events:none}.file-preview .preview-action-overlay{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;background-color:#0006;color:#fff;opacity:1;transition:opacity .3s ease}.file-preview .preview-action-overlay .mat-icon{font-size:36px;width:36px;height:36px}.file-preview .remove-btn{position:absolute;top:8px;right:8px;z-index:2;background-color:#0000004d;color:#fff;width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;transition:all var(--transition-speed) ease}.file-preview .remove-btn:hover{background-color:#ff5b5b}.file-preview .remove-btn .mat-icon{font-size:18px}@media (hover: hover){.file-preview .remove-btn .file-preview .preview-action-overlay{opacity:0}.file-preview .remove-btn .file-preview:hover .preview-action-overlay,.file-preview .remove-btn .file-preview:hover .remove-btn{opacity:1}.file-preview .remove-btn .file-preview .remove-btn{opacity:0}}@media (hover: hover) and (min-width: 769px){.file-preview .remove-btn{opacity:0;transform:scale(.8)}.file-preview:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color)}.file-preview:hover .remove-btn{opacity:1;transform:scale(1)}}.file-preview .preview-img-container{aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;background-color:#f0f2f5}.file-preview .preview-img{width:100%;height:100%;object-fit:cover}.file-preview .file-icon{font-size:4rem;color:var(--primary-color)}.file-preview .file-info{padding:12px;border-top:1px solid var(--border-color);flex-grow:1;display:flex;align-items:center}.file-preview .file-name{font-weight:600;font-size:.9rem;color:var(--text-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-preview .upload-spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;border:4px solid rgba(0,0,0,.1);border-left-color:var(--primary-color);border-radius:50%;animation:spin 1s linear infinite;pointer-events:none}.file-preview.card-small{width:140px}.file-preview.card-small .preview-img-container{height:80px}.file-preview.card-small .file-info{padding:8px}.file-preview.card-small .file-name{font-size:.8rem}.file-preview.card-small .file-icon{font-size:3rem}.file-preview.card-small .remove-btn{width:28px;height:28px}.file-preview.card-small .remove-btn .mat-icon{font-size:16px}.file-preview.card-large{width:280px}.file-preview.card-large .preview-img-container{height:180px}.file-preview.card-large .file-info{padding:16px}.file-preview.card-large .file-name{font-size:1rem}.file-preview.card-large .file-icon{font-size:5rem}.file-preview.card-large .remove-btn{width:36px;height:36px}.file-preview.card-large .remove-btn .mat-icon{font-size:20px}.file-preview[style*=--eqp-card-width]{width:var(--eqp-card-width)}.file-preview[style*=--eqp-card-width] .preview-img-container{height:calc(var(--eqp-card-width) * .65)}@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}.upload-stats{background-color:var(--background-card);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid var(--border-color);border-radius:var(--border-radius);padding:1.5rem;margin-top:2rem;animation:fadeIn .5s ease-out}.upload-stats .stats-info{display:flex;justify-content:space-around}.upload-stats .progress-bar{height:10px;background-color:var(--border-color);border-radius:5px;overflow:hidden;margin-top:1rem}.upload-stats .progress-fill{height:100%;background:linear-gradient(90deg,var(--primary-color),var(--success-color));transition:width var(--transition-speed) ease-out;border-radius:5px}.upload-notification{position:fixed;bottom:20px;left:50%;transform:translate(-50%,100px);padding:1rem 1.5rem;border-radius:var(--border-radius);color:#fff;font-weight:600;box-shadow:0 10px 30px #0003;transition:transform var(--transition-speed) cubic-bezier(.175,.885,.32,1.275)}.upload-notification.show{transform:translate(-50%)}.upload-notification.success{background-color:var(--success-color)}.upload-notification.error{background-color:var(--error-color)}::ng-deep .cdk-overlay-pane.eqp-crop-dialog{transform:translateY(-4vh)}@media (max-width: 600px){::ng-deep .cdk-overlay-pane.crop-dialog{width:auto!important}}::ng-deep .eqp-attachments-dialog{display:flex!important;flex-direction:column!important}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__container{display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__container .mdc-dialog__surface{border-radius:20px!important;padding:0!important;overflow:hidden!important;width:fit-content!important;min-width:350px!important;max-width:95vw!important;max-height:90vh!important;margin:0 auto;background-color:#fff!important;display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden!important}.modern-dialog-container{display:flex;flex-direction:column;width:100%;max-width:100%;flex:1 1 auto;min-height:0;height:100%;max-height:100%;background:#fff;--preview-header-h: 66px;--preview-footer-h: 66px;--preview-padding-y: 30px}.modern-dialog-container .main-preview-media{display:block;max-width:100%;max-height:var(--media-max-h);width:auto;height:auto;object-fit:contain;border-radius:12px;background:#fff;padding:4px;box-shadow:0 10px 30px #00000014}.modern-dialog-container video.main-preview-media{width:min(100%,1100px);background:#000}.modern-dialog-container .iframe-container{width:min(100%,1100px);height:var(--media-max-h);display:flex;width:100%;max-width:1100px}.modern-dialog-container .preview-iframe-modern{width:100%;height:100%;border:0;border-radius:12px;background:#f8fafc}.modern-dialog-container .preview-header{flex:0 0 auto;flex-shrink:0;padding:14px 20px;display:flex;align-items:center;justify-content:flex-start;border-bottom:1px solid var(--border-color);background:#f8fafc;z-index:10;width:100%}.modern-dialog-container .preview-header .close-btn{display:inline-flex!important;align-items:center!important;justify-content:center!important;padding:0!important;width:40px!important;height:40px!important}.modern-dialog-container .preview-header .close-btn ::ng-deep mat-icon{display:flex!important;align-items:center!important;justify-content:center!important;margin:0!important;padding:0!important;line-height:1!important}.modern-dialog-container .preview-header .header-info{display:flex;align-items:center;justify-content:flex-start;gap:12px;flex:1 1 auto;min-width:0;text-align:left}.modern-dialog-container .preview-header .header-info .type-icon-wrapper{background:var(--primary-color);color:#fff;width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 10px var(--shadow-color)}.modern-dialog-container .preview-header .header-info .title-group{display:flex;flex-direction:column;align-items:flex-start;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .main-t{font-weight:800;color:var(--text-color);font-size:.95rem;line-height:1.2;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .file-t{font-size:.75rem;color:var(--text-color-light);max-width:250px;overflow:hidden;text-overflow:ellipsis;text-align:left}.modern-dialog-container .preview-content-area{flex:1 1 auto;background:#fff!important;display:flex;flex-direction:column;padding:15px 15px 22px!important;overflow:hidden!important;min-height:0;width:100%;--media-max-h: calc(90vh - var(--preview-header-h) - var(--preview-footer-h) - var(--preview-padding-y))}.modern-dialog-container .preview-content-area .crop-toolbar{flex-shrink:0;z-index:20;background:#0f172a14;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:6px 16px;border-radius:30px;margin:0 auto 15px;display:flex;gap:8px;box-shadow:0 4px 12px #0000000d}.modern-dialog-container .preview-content-area .crop-toolbar button{color:var(--text-color)!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper{flex:1 1 auto;width:100%;height:100%;display:flex;flex-direction:column;align-items:stretch;min-height:0;overflow:hidden}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;align-items:center;background:transparent;border-radius:12px;padding:0;overflow:hidden;min-height:0;width:100%;height:100%}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern image-cropper{flex:1 1 auto;width:100%;height:100%;max-width:100%!important;max-height:100%!important;display:block;min-height:0}.modern-dialog-container .add-link-modern-content{flex:1;background:#fff;padding:24px!important}.modern-dialog-container .add-link-modern-content .add-link-form{display:flex;flex-direction:column;gap:10px}.modern-dialog-container .preview-actions{flex-shrink:0;padding:12px 24px;background:#f8fafc;border-top:1px solid #e2e8f0;margin:0}.modern-dialog-container .preview-actions .btn-download{border-radius:12px;font-weight:600;box-shadow:0 4px 12px var(--shadow-color)}@media (max-width: 600px){.modern-dialog-container{max-height:95vh}.modern-dialog-container .preview-content-area{padding:10px!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper video.main-preview-media{width:100%!important;max-height:55vh!important;border-radius:4px;box-shadow:none}.modern-dialog-container .preview-content-area .media-viewer-wrapper .iframe-container{height:50vh}.modern-dialog-container .preview-content-area .crop-toolbar{width:calc(100% - 20px);max-width:400px;margin-bottom:10px;padding:4px 8px;gap:4px;overflow-x:auto;justify-content:center;-webkit-overflow-scrolling:touch;scrollbar-width:none}.modern-dialog-container .preview-content-area .crop-toolbar::-webkit-scrollbar{display:none}.modern-dialog-container .preview-content-area .crop-toolbar button{flex-shrink:0;transform:scale(.85);width:40px;height:40px}.modern-dialog-container .preview-actions{padding:10px 15px;flex-direction:column-reverse;gap:8px}.modern-dialog-container .preview-actions button{width:100%;margin:0!important}}@media (max-width: 360px){.modern-dialog-container .preview-content-area .crop-toolbar{gap:2px}.modern-dialog-container .preview-content-area .crop-toolbar button{transform:scale(.75)}}.control-icon{font-size:28px;cursor:pointer}image-cropper{display:flex!important;max-width:100%!important;max-height:100%!important;height:100%;width:100%}image-cropper canvas,image-cropper img{max-width:100%!important;max-height:100%!important}.crop-large{display:flex}.crop-small{display:none}@media (max-width: 600px){.dialog-content{max-height:55vh}.crop-container{max-width:100%;aspect-ratio:auto}.crop-large{display:none}.crop-small{display:flex;justify-content:center;gap:14px}.control-icon{font-size:24px}}.stats-header{display:flex;justify-content:space-between;align-items:center;width:100%}.table-view-container{margin-top:1.5rem;background-color:var(--background-card);border-radius:var(--border-radius);border:1px solid var(--border-color);overflow:hidden;animation:fadeIn .5s ease-out}.table-header,.table-row{display:flex;align-items:center;padding:0 1rem;transition:background-color var(--transition-speed) ease}.table-header{background-color:#f8f9fa;font-weight:600;color:var(--text-color-light);font-size:.8rem;text-transform:uppercase;border-bottom:2px solid var(--border-color)}.table-row{border-bottom:1px solid var(--border-color)}.table-row:last-child{border-bottom:none}.table-row:hover{background-color:#00000005}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem}.name-col{flex:4}.size-col,.date-col{flex:2}.actions-col{flex:1;justify-content:flex-end;min-width:150px}.file-icon-small{font-size:1.5rem;color:var(--primary-color)}.file-info-text{display:flex;flex-direction:column}.file-name-table{font-weight:600;color:var(--text-color)}.file-type-table{font-size:.8rem;color:var(--text-color-light)}@media (max-width: 768px){.date-col{display:none}.name-col{flex:3}.size-col{flex:2}.actions-col{flex:2;min-width:120px}}.secondary-action-link{color:var(--primary-color);text-decoration:none;border-bottom:1px solid var(--primary-color);cursor:pointer;font-weight:500}.secondary-action-link:hover{color:var(--primary-color-dark);border-bottom-color:var(--primary-color-dark)}h2[mat-dialog-title]+mat-dialog-content.add-link-dialog-content{padding-top:20px}mat-dialog-content.add-link-dialog-content{padding-left:24px;padding-right:24px;padding-bottom:20px}.add-link-form{display:flex;flex-direction:column;gap:16px}::ng-deep .eqp-attachments-preview-dialog{--mdc-dialog-subhead-line-height: normal}::ng-deep .eqp-attachments-preview-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;background:#fff!important}:host ::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{--mdc-dialog-subhead-size: 1.25rem;--mdc-dialog-subhead-line-height: 1.5;--mdc-dialog-subhead-weight: 600;--mdc-dialog-supporting-text-size: 1rem}.empty-state{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:1.5rem 1rem;margin-top:1.5rem;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#f8f9fa;text-align:center;color:var(--text-color-light);animation:fadeIn .5s ease-out}.empty-state:before{content:\"\\1f4ed\";font-size:2.5rem;margin-bottom:1rem;opacity:.7}.secondary-action-link.disabled-link{color:#adb5bd;cursor:not-allowed;border-bottom-color:transparent}.secondary-action-link.disabled-link:hover{color:#adb5bd;border-bottom-color:transparent}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem;min-width:0;overflow:hidden}.table-cell.col-actions{flex:0 0 150px;justify-content:flex-end;overflow:visible}.compact-uploader{display:flex;align-items:center;gap:16px;padding:16px;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#fcfdff;transition:all .3s ease}.compact-uploader .compact-text{flex:1 1 auto;min-width:0;cursor:pointer}.compact-uploader .compact-text:hover .compact-title{color:var(--primary-color)}.compact-uploader .compact-title{font-weight:600;color:var(--text-color);transition:color .3s ease}.compact-uploader .compact-subtitle{font-size:.8rem;color:var(--text-color-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.compact-uploader .compact-icon mat-icon{font-size:36px;width:36px;height:36px;color:var(--primary-color)}.compact-uploader .compact-actions{display:flex;gap:8px;flex-shrink:0}.compact-uploader.dragover{background-color:#f4f8ff;border-color:var(--primary-color);box-shadow:0 0 10px var(--shadow-color)}.disabled-dropzone{opacity:.5;cursor:not-allowed!important;background-color:#f5f5f5;border-color:#d1d5db}.disabled-dropzone *{pointer-events:none}.disabled-dropzone .browse-btn,.disabled-dropzone button{cursor:not-allowed!important;background-color:#e5e7eb;color:#9ca3af;border:none}.disabled-dropzone .secondary-action-link,.disabled-dropzone a{color:#9ca3af;text-decoration:none}\n"], dependencies: [{ kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatLabel, selector: "mat-label" }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i9.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i9.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i9.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: i10.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i10.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i11.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i12.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i13.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i13.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i13.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i14.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: "pipe", type: i13.DatePipe, name: "date" }] });
1624
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsComponent, deps: [{ token: i1.MatDialog }, { token: i2.FormBuilder }, { token: i3.DomSanitizer }, { token: i4.HttpClient }, { token: EqpAttachmentService }], target: i0.ɵɵFactoryTarget.Component });
1625
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: EqpAttachmentsComponent, isStandalone: false, selector: "eqp-attachments", inputs: { disableAction: { classPropertyName: "disableAction", publicName: "disableAction", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, attachmentsList: { classPropertyName: "attachmentsList", publicName: "attachmentsList", isSignal: false, isRequired: false, transformFunction: null }, singleAttachment: { classPropertyName: "singleAttachment", publicName: "singleAttachment", isSignal: true, isRequired: false, transformFunction: null }, showMatCard: { classPropertyName: "showMatCard", publicName: "showMatCard", isSignal: true, isRequired: false, transformFunction: null }, multipleAttachment: { classPropertyName: "multipleAttachment", publicName: "multipleAttachment", isSignal: true, isRequired: false, transformFunction: null }, loadMultipleFiles: { classPropertyName: "loadMultipleFiles", publicName: "loadMultipleFiles", isSignal: true, isRequired: false, transformFunction: null }, emptyTableMessage: { classPropertyName: "emptyTableMessage", publicName: "emptyTableMessage", isSignal: true, isRequired: false, transformFunction: null }, allowOnlyImages: { classPropertyName: "allowOnlyImages", publicName: "allowOnlyImages", isSignal: true, isRequired: false, transformFunction: null }, acceptedFileTypes: { classPropertyName: "acceptedFileTypes", publicName: "acceptedFileTypes", isSignal: false, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, showInlinePreview: { classPropertyName: "showInlinePreview", publicName: "showInlinePreview", isSignal: true, isRequired: false, transformFunction: null }, getAttachmentEndpoint: { classPropertyName: "getAttachmentEndpoint", publicName: "getAttachmentEndpoint", isSignal: true, isRequired: false, transformFunction: null }, productionBaseUrl: { classPropertyName: "productionBaseUrl", publicName: "productionBaseUrl", isSignal: true, isRequired: false, transformFunction: null }, compressionOptions: { classPropertyName: "compressionOptions", publicName: "compressionOptions", isSignal: true, isRequired: false, transformFunction: null }, allowedTypes: { classPropertyName: "allowedTypes", publicName: "allowedTypes", isSignal: false, isRequired: false, transformFunction: null }, isEqpTableMultiLanguage: { classPropertyName: "isEqpTableMultiLanguage", publicName: "isEqpTableMultiLanguage", isSignal: true, isRequired: false, transformFunction: null }, tablePaginatorVisible: { classPropertyName: "tablePaginatorVisible", publicName: "tablePaginatorVisible", isSignal: true, isRequired: false, transformFunction: null }, isTableSearcheable: { classPropertyName: "isTableSearcheable", publicName: "isTableSearcheable", isSignal: true, isRequired: false, transformFunction: null }, tablePaginatorSize: { classPropertyName: "tablePaginatorSize", publicName: "tablePaginatorSize", isSignal: true, isRequired: false, transformFunction: null }, separatedUploadButtons: { classPropertyName: "separatedUploadButtons", publicName: "separatedUploadButtons", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null }, singleAttachmentDragAndDrop: { classPropertyName: "singleAttachmentDragAndDrop", publicName: "singleAttachmentDragAndDrop", isSignal: true, isRequired: false, transformFunction: null }, cropOptions: { classPropertyName: "cropOptions", publicName: "cropOptions", isSignal: true, isRequired: false, transformFunction: null }, cropDialogClass: { classPropertyName: "cropDialogClass", publicName: "cropDialogClass", isSignal: true, isRequired: false, transformFunction: null }, maxFileSizeMB: { classPropertyName: "maxFileSizeMB", publicName: "maxFileSizeMB", isSignal: true, isRequired: false, transformFunction: null }, cardSize: { classPropertyName: "cardSize", publicName: "cardSize", isSignal: true, isRequired: false, transformFunction: null }, customCardWidthPx: { classPropertyName: "customCardWidthPx", publicName: "customCardWidthPx", isSignal: true, isRequired: false, transformFunction: null }, customCardHeightPx: { classPropertyName: "customCardHeightPx", publicName: "customCardHeightPx", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, openLinkLabel: { classPropertyName: "openLinkLabel", publicName: "openLinkLabel", isSignal: true, isRequired: false, transformFunction: null }, addButtonLabel: { classPropertyName: "addButtonLabel", publicName: "addButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, downloadLabel: { classPropertyName: "downloadLabel", publicName: "downloadLabel", isSignal: true, isRequired: false, transformFunction: null }, deleteLabel: { classPropertyName: "deleteLabel", publicName: "deleteLabel", isSignal: true, isRequired: false, transformFunction: null }, fileNameLabel: { classPropertyName: "fileNameLabel", publicName: "fileNameLabel", isSignal: true, isRequired: false, transformFunction: null }, previewLabel: { classPropertyName: "previewLabel", publicName: "previewLabel", isSignal: true, isRequired: false, transformFunction: null }, uploadFileLabel: { classPropertyName: "uploadFileLabel", publicName: "uploadFileLabel", isSignal: true, isRequired: false, transformFunction: null }, confirmLabel: { classPropertyName: "confirmLabel", publicName: "confirmLabel", isSignal: true, isRequired: false, transformFunction: null }, abortLabel: { classPropertyName: "abortLabel", publicName: "abortLabel", isSignal: true, isRequired: false, transformFunction: null }, saveLabel: { classPropertyName: "saveLabel", publicName: "saveLabel", isSignal: true, isRequired: false, transformFunction: null }, exitLabel: { classPropertyName: "exitLabel", publicName: "exitLabel", isSignal: true, isRequired: false, transformFunction: null }, uploadWithDropboxLabel: { classPropertyName: "uploadWithDropboxLabel", publicName: "uploadWithDropboxLabel", isSignal: true, isRequired: false, transformFunction: null }, cropLabel: { classPropertyName: "cropLabel", publicName: "cropLabel", isSignal: true, isRequired: false, transformFunction: null }, deleteDialogTitle: { classPropertyName: "deleteDialogTitle", publicName: "deleteDialogTitle", isSignal: true, isRequired: false, transformFunction: null }, deleteDialogMessage: { classPropertyName: "deleteDialogMessage", publicName: "deleteDialogMessage", isSignal: true, isRequired: false, transformFunction: null }, noImageSelectedErrorMessage: { classPropertyName: "noImageSelectedErrorMessage", publicName: "noImageSelectedErrorMessage", isSignal: true, isRequired: false, transformFunction: null }, wrongTypeSelectedErrorMessage: { classPropertyName: "wrongTypeSelectedErrorMessage", publicName: "wrongTypeSelectedErrorMessage", isSignal: true, isRequired: false, transformFunction: null }, videoPreviewErrorMessage: { classPropertyName: "videoPreviewErrorMessage", publicName: "videoPreviewErrorMessage", isSignal: true, isRequired: false, transformFunction: null }, audioPreviewErrorMessage: { classPropertyName: "audioPreviewErrorMessage", publicName: "videoPreviewErrorMessage", isSignal: true, isRequired: false, transformFunction: null }, flipHorinzontalLabel: { classPropertyName: "flipHorinzontalLabel", publicName: "flipHorinzontalLabel", isSignal: true, isRequired: false, transformFunction: null }, flipVerticalLabel: { classPropertyName: "flipVerticalLabel", publicName: "flipVerticalLabel", isSignal: true, isRequired: false, transformFunction: null }, rotateRightLabel: { classPropertyName: "rotateRightLabel", publicName: "rotateRightLabel", isSignal: true, isRequired: false, transformFunction: null }, rotateLeftLabel: { classPropertyName: "rotateLeftLabel", publicName: "rotateLeftLabel", isSignal: true, isRequired: false, transformFunction: null }, base64LimitMB: { classPropertyName: "base64LimitMB", publicName: "base64LimitMB", isSignal: true, isRequired: false, transformFunction: null }, uploadTitle: { classPropertyName: "uploadTitle", publicName: "uploadTitle", isSignal: true, isRequired: false, transformFunction: null }, uploadSubtitle: { classPropertyName: "uploadSubtitle", publicName: "uploadSubtitle", isSignal: true, isRequired: false, transformFunction: null }, dropHereLabel: { classPropertyName: "dropHereLabel", publicName: "dropHereLabel", isSignal: true, isRequired: false, transformFunction: null }, supportedFormatsLabel: { classPropertyName: "supportedFormatsLabel", publicName: "supportedFormatsLabel", isSignal: true, isRequired: false, transformFunction: null }, browseFilesLabel: { classPropertyName: "browseFilesLabel", publicName: "browseFilesLabel", isSignal: true, isRequired: false, transformFunction: null }, uploadSummaryLabel: { classPropertyName: "uploadSummaryLabel", publicName: "uploadSummaryLabel", isSignal: true, isRequired: false, transformFunction: null }, filesLabel: { classPropertyName: "filesLabel", publicName: "filesLabel", isSignal: true, isRequired: false, transformFunction: null }, totalSizeLabel: { classPropertyName: "totalSizeLabel", publicName: "totalSizeLabel", isSignal: true, isRequired: false, transformFunction: null }, emptyStateLabel: { classPropertyName: "emptyStateLabel", publicName: "emptyStateLabel", isSignal: true, isRequired: false, transformFunction: null }, addedSuccessfullyLabel: { classPropertyName: "addedSuccessfullyLabel", publicName: "addedSuccessfullyLabel", isSignal: true, isRequired: false, transformFunction: null }, removedLabel: { classPropertyName: "removedLabel", publicName: "removedLabel", isSignal: true, isRequired: false, transformFunction: null }, chooseView: { classPropertyName: "chooseView", publicName: "chooseView", isSignal: true, isRequired: false, transformFunction: null }, showSummary: { classPropertyName: "showSummary", publicName: "showSummary", isSignal: true, isRequired: false, transformFunction: null }, viewMode: { classPropertyName: "viewMode", publicName: "viewMode", isSignal: false, isRequired: false, transformFunction: null }, showUploadTitle: { classPropertyName: "showUploadTitle", publicName: "showUploadTitle", isSignal: true, isRequired: false, transformFunction: null }, showDropArea: { classPropertyName: "showDropArea", publicName: "showDropArea", isSignal: true, isRequired: false, transformFunction: null }, hiddenColumns: { classPropertyName: "hiddenColumns", publicName: "hiddenColumns", isSignal: true, isRequired: false, transformFunction: null }, hiddenActions: { classPropertyName: "hiddenActions", publicName: "hiddenActions", isSignal: true, isRequired: false, transformFunction: null }, showActionButtons: { classPropertyName: "showActionButtons", publicName: "showActionButtons", isSignal: true, isRequired: false, transformFunction: null }, enableImageCrop: { classPropertyName: "enableImageCrop", publicName: "enableImageCrop", isSignal: true, isRequired: false, transformFunction: null }, actionHiddenFn: { classPropertyName: "actionHiddenFn", publicName: "actionHiddenFn", isSignal: true, isRequired: false, transformFunction: null }, actionDisabledFn: { classPropertyName: "actionDisabledFn", publicName: "actionDisabledFn", isSignal: true, isRequired: false, transformFunction: null }, videoCompression: { classPropertyName: "videoCompression", publicName: "videoCompression", isSignal: true, isRequired: false, transformFunction: null }, customMenuActions: { classPropertyName: "customMenuActions", publicName: "customMenuActions", isSignal: true, isRequired: false, transformFunction: null }, customColumns: { classPropertyName: "customColumns", publicName: "customColumns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { localEditedAttachments: "localEditedAttachments", abortAddAttachment: "abortAddAttachment", downloadAttachment: "downloadAttachment", onDeleteAttachment: "onDeleteAttachment" }, viewQueries: [{ propertyName: "dialogAddAttachment", first: true, predicate: ["dialogAddAttachment"], descendants: true, isSignal: true }, { propertyName: "dialogAddMultipleAttachment", first: true, predicate: ["dialogAddMultipleAttachment"], descendants: true, isSignal: true }, { propertyName: "dialogCropImage", first: true, predicate: ["dialogCropImage"], descendants: true, isSignal: true }, { propertyName: "addingLinkTemplate", first: true, predicate: ["addingLinkTemplate"], descendants: true, isSignal: true }, { propertyName: "imageCropper", first: true, predicate: ImageCropperComponent, descendants: true, isSignal: true }, { propertyName: "imageInput", first: true, predicate: ["imageInput"], descendants: true, isSignal: true }, { propertyName: "inlinePreviewTemplate", first: true, predicate: ["inlinePreviewTemplate"], descendants: true, isSignal: true }, { propertyName: "dialogPreview", first: true, predicate: ["dialogPreview"], descendants: true, isSignal: true }, { propertyName: "defaultFileTemplate", first: true, predicate: ["defaultFileTemplate"], descendants: true, isSignal: true }, { propertyName: "defaultActionsTemplate", first: true, predicate: ["defaultActionsTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Se richiesta la gestione singola mostra il pulsante di caricamento di un singolo file -->\r\n@if(showUploadTitle() == true || chooseView() == true){\r\n<div class=\"header\">\r\n @if(showUploadTitle() == true){\r\n <h4>{{ uploadTitle() }}</h4>\r\n } @if(chooseView() == true){\r\n <mat-button-toggle-group\r\n [value]=\"viewMode\"\r\n (change)=\"setViewMode($event.value)\"\r\n aria-label=\"Modalit\u00E0 di visualizzazione\"\r\n >\r\n <mat-button-toggle value=\"card\"\r\n ><mat-icon>grid_view</mat-icon></mat-button-toggle\r\n >\r\n <mat-button-toggle value=\"table\"\r\n ><mat-icon>view_list</mat-icon></mat-button-toggle\r\n >\r\n </mat-button-toggle-group>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione singolo -->\r\n@if (multipleAttachment() != true) { @if (!singleAttachmentDragAndDrop()) { @if\r\n(!addingLinkMode()) {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addAttachmentButton\"></ng-container>\r\n</div>\r\n} @else {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addingLinkTemplate\"></ng-container>\r\n</div>\r\n} } @else {\r\n<input\r\n #fileInput\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n hidden\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n/>\r\n\r\n@if (allowedTypes && allowedTypes.includes(1) && (!attachmentsList ||\r\nattachmentsList.length == 0 || (attachmentsList.length > 0 &&\r\n!attachmentsList[0]))) { @if (showDropArea() == true) {\r\n<!-- FULL -->\r\n@if (layout() === 'full') {\r\n\r\n<div\r\n class=\"dropbox\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"fileInput.click()\"\r\n>\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel() }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel() }}\r\n </div>\r\n <button\r\n class=\"browse-btn\"\r\n type=\"button\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n {{ browseFilesLabel() }}\r\n </button>\r\n <div class=\"secondary-action\">\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) { @if\r\n (allowedTypes.includes(2) && allowedTypes.includes(3)) {\r\n <a\r\n class=\"secondary-action-link\"\r\n [matMenuTriggerFor]=\"isDisabled() ? null : linkMenu\"\r\n [class.disabled-link]=\"isDisabled()\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n o aggiungi da web\r\n </a>\r\n <mat-menu #linkMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"switchToAddingLinkMode()\">\r\n <mat-icon>link</mat-icon>\r\n <span>Aggiungi da link</span>\r\n </button>\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\">\r\n <mat-icon>cloud_queue</mat-icon>\r\n <span>Carica da Dropbox</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (allowedTypes.includes(2)) {\r\n <a\r\n [class.disabled-link]=\"isDisabled()\"\r\n class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\"\r\n >\r\n aggiungi un link\r\n </a>\r\n } @else if (allowedTypes.includes(3)) {\r\n <a\r\n [class.disabled-link]=\"isDisabled()\"\r\n class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); chooseDropboxFile()\"\r\n >\r\n carica da Dropbox\r\n </a>\r\n } }\r\n </div>\r\n</div>\r\n}@else {\r\n<div\r\n class=\"compact-uploader\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n>\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel() }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button\r\n mat-stroked-button\r\n color=\"primary\"\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n Sfoglia\r\n </button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n Link\r\n </button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n >\r\n {{ openLinkLabel() }}\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"chooseDropboxFile()\"\r\n >\r\n {{ uploadWithDropboxLabel() }}\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n} } } }\r\n\r\n<!-- Azioni singolo elemento (come prima) -->\r\n<div class=\"text-center\">\r\n @if (attachmentsList && attachmentsList.length > 0 && attachmentsList[0] &&\r\n showActionButtons() == true) {\r\n @if (!isPrimaryActionHidden(attachmentsList[0])) {\r\n <button\r\n class=\"mb-2 me-2 eqp-attachments-download-btn\"\r\n (click)=\"viewAttachment(attachmentsList[0])\"\r\n type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button\r\n color=\"primary\"\r\n >\r\n @if (attachmentsList[0].AttachmentType == AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n {{\r\n attachmentsList[0].AttachmentType == AttachmentType.FILE\r\n ? downloadLabel()\r\n : openLinkLabel()\r\n }}\r\n </button>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(attachmentsList[0]) && showPreview() && (!attachmentsList[0].FileContentType ||\r\n (!attachmentsList[0].FileContentType.startsWith('video') &&\r\n !attachmentsList[0].FileContentType.startsWith('audio'))) &&\r\n attachmentsList[0].IsImage == true) {\r\n <button\r\n class=\"mb-2 me-2 eqp-attachments-preview-btn\"\r\n (click)=\"openPreviewDialog(attachmentsList[0])\"\r\n type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button\r\n color=\"primary\"\r\n >\r\n <mat-icon>visibility</mat-icon> {{ previewLabel() }}\r\n </button>\r\n }\r\n\r\n <button\r\n [disabled]=\"disableAction()\"\r\n class=\"mb-2 eqp-attachments-delete-btn\"\r\n (click)=\"deleteAttachment(attachmentsList[0])\"\r\n type=\"button\"\r\n mat-raised-button\r\n [disabled]=\"isDisabled()\"\r\n >\r\n <mat-icon>delete</mat-icon> {{ deleteLabel() }}\r\n </button>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione multipla -->\r\n@if (multipleAttachment() == true && showDropArea() == true) {\r\n<input\r\n #fileInput\r\n id=\"file_attachment_multi\"\r\n name=\"file_attachment_multi\"\r\n type=\"file\"\r\n hidden\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n/>\r\n\r\n@if (layout() === 'full') {\r\n<div\r\n class=\"dropbox\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"fileInput.click()\"\r\n>\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel() }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel() }}\r\n </div>\r\n <button\r\n class=\"browse-btn\"\r\n type=\"button\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n {{ browseFilesLabel() }}\r\n </button>\r\n @if (allowedTypes.includes(2)) {\r\n <div class=\"secondary-action-link\">\r\n o\r\n <a (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\"\r\n >aggiungi un link</a\r\n >\r\n </div>\r\n }\r\n</div>\r\n}@else{\r\n<div\r\n class=\"compact-uploader\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n>\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel() }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n color=\"primary\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n Sfoglia\r\n </button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n Link\r\n </button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n >\r\n {{ openLinkLabel() }}\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"chooseDropboxFile()\"\r\n >\r\n {{ uploadWithDropboxLabel() }}\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n} } @if (attachmentsList?.length > 0 && showSummary()) {\r\n<div class=\"upload-stats\">\r\n <div class=\"stats-info\">\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ attachmentsList?.length }}</div>\r\n <div class=\"stat-label\">{{ filesLabel() }}</div>\r\n </div>\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ totalSizeFormatted() }}</div>\r\n <div class=\"stat-label\">{{ totalSizeLabel() }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"progressPercent()\"></div>\r\n </div>\r\n</div>\r\n} @else if(attachmentsList?.length == 0){\r\n<div class=\"empty-state\">{{ emptyStateLabel() }}</div>\r\n}\r\n\r\n<!-- Griglia anteprime card (vale per singolo e multiplo) -->\r\n@if (viewMode === 'card') {\r\n\r\n<div class=\"file-previews\" [ngStyle]=\"getPreviewsContainerStyle()\">\r\n @for (att of attachmentsList; track att.ID) {\r\n <div [ngClass]=\"getCardClass(att)\">\r\n <div\r\n class=\"preview-img-container\"\r\n (click)=\"!att.isUploading && handlePrimaryAction(att)\"\r\n >\r\n @if (att.IsImage || att.FileThumbnailBase64) {\r\n <img\r\n class=\"preview-img\"\r\n [src]=\"\r\n 'data:image/jpeg;base64,' +\r\n (att.FileThumbnailBase64 || att.FileDataBase64)\r\n \"\r\n [alt]=\"att.FileName\"\r\n />\r\n } @else {\r\n <div class=\"file-icon\"><i [ngClass]=\"getAttachmentIcon(att)\"></i></div>\r\n }\r\n\r\n <div class=\"preview-action-overlay\">\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n <mat-icon>play_arrow</mat-icon>\r\n } @else if (att.IsImage && canBePreviewed(att)) {\r\n <mat-icon>visibility</mat-icon>\r\n } @else if (att.FileContentType === 'application/pdf' &&\r\n canBePreviewed(att)) {\r\n <mat-icon>open_in_new</mat-icon>\r\n } @else if (att.AttachmentType === AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-info\">\r\n <div class=\"file-name\" [title]=\"att.FileName\">{{ att.FileName }}</div>\r\n </div>\r\n\r\n @if(!isDeleteHidden(att)){\r\n <button\r\n mat-icon-button\r\n class=\"remove-btn\"\r\n (click)=\"deleteAttachment(att)\"\r\n [disabled]=\"att.isUploading || isDeleteDisabled(att)\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n } @if (att.isUploading) {\r\n <div class=\"upload-spinner\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n} @else if(viewMode === 'table' && attachmentsList?.length > 0) {\r\n\r\n<div class=\"table-view-container\">\r\n <div class=\"table-header\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div\r\n class=\"table-cell\"\r\n [style.flex]=\"col.styles?.flex\"\r\n [ngClass]=\"col.class\"\r\n >\r\n {{ col.display }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @for (att of attachmentsList; track att.ID) {\r\n <div class=\"table-row\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div\r\n class=\"table-cell\"\r\n [style.flex]=\"col.styles?.flex\"\r\n [ngClass]=\"col.class\"\r\n >\r\n @switch (col.type) { @case ('template') {\r\n <div class=\"template-wrapper\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"col.externalTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: att }\"\r\n ></ng-container>\r\n </div>\r\n } @case ('date') {\r\n <span class=\"metadata-value\">{{\r\n att[col.key] | date : \"dd/MM/yyyy\"\r\n }}</span>\r\n } @default {\r\n <span class=\"metadata-value\">{{ att[col.key] }}</span>\r\n } }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Notifica toast -->\r\n<div\r\n class=\"upload-notification\"\r\n [class.show]=\"toast?.visible\"\r\n [class.success]=\"toast?.type === 'success'\"\r\n [class.error]=\"toast?.type === 'error'\"\r\n>\r\n <span>{{ toast?.text }}</span>\r\n <div class=\"notification-progress\"></div>\r\n</div>\r\n\r\n<ng-template #defaultFileTemplate let-att>\r\n <i class=\"file-icon-small\" [ngClass]=\"getAttachmentIcon(att)\"></i>\r\n <div class=\"file-info-text\">\r\n <span class=\"file-name-table\">{{ att.FileName }}</span>\r\n <span class=\"file-type-table\">{{ att.FileExtension || \"Link\" }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #defaultActionsTemplate let-att>\r\n <button\r\n mat-icon-button\r\n (click)=\"handlePrimaryAction(att)\"\r\n [matTooltip]=\"\r\n att.FileContentType?.startsWith('video/')\r\n ? 'Riproduci video'\r\n : 'Visualizza/Scarica'\r\n \"\r\n >\r\n <mat-icon>\r\n @if (att.FileContentType?.startsWith('video/')) { play_arrow } @else {\r\n {{\r\n att.AttachmentType === AttachmentType.FILE ? \"download\" : \"open_in_new\"\r\n }}\r\n }\r\n </mat-icon>\r\n </button>\r\n\r\n @if (!hiddenActions().includes('actionsMenu')) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"actionsMenu\"\r\n matTooltip=\"Altre opzioni\"\r\n >\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n\r\n <mat-menu #actionsMenu=\"matMenu\">\r\n @for (action of _sortedMenuActions; track action.name) { @if\r\n (!isActionHidden(action, att)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"action.fn(att)\"\r\n [disabled]=\"isActionDisabled(action, att)\"\r\n >\r\n <mat-icon [color]=\"action.icon === 'delete' ? 'warn' : undefined\">\r\n {{ action.icon }}\r\n </mat-icon>\r\n <span>{{ action.name }}</span>\r\n </button>\r\n } }\r\n </mat-menu>\r\n</ng-template>\r\n\r\n<ng-template #dialogCropImage>\r\n <div style=\"overflow-x: hidden\" [ngClass]=\"cropDialogClass()\">\r\n <!-- @if (showCropImage == true) { -->\r\n <ng-container\r\n [ngTemplateOutlet]=\"croppieTemplate\"\r\n [ngTemplateOutletContext]=\"{ form: newAttachmentForm }\"\r\n >\r\n </ng-container>\r\n <!-- } -->\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #inlinePreviewTemplate let-row=\"row\">\r\n @if (row.AttachmentType != AttachmentType.LINK && row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <img\r\n [src]=\"\r\n 'data:image/png;base64,' +\r\n (row.FileThumbnailBase64 ? row.FileThumbnailBase64 : row.FileDataBase64)\r\n \"\r\n />\r\n </div>\r\n } @else if (row.AttachmentType != AttachmentType.LINK && !row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <i [ngClass]=\"getAttachmentIcon(row)\"></i>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #dialogPreview>\r\n <div class=\"modern-dialog-container\">\r\n @if (selectedAttachment) {\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ previewLabel() }}</span>\r\n <span class=\"file-t\">{{ selectedAttachment.FileName }}</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"media-viewer-wrapper\">\r\n @if (selectedAttachment.IsImage) {\r\n <img\r\n class=\"main-preview-media\"\r\n [src]=\"\r\n 'data:image/png;base64,' +\r\n (selectedAttachment.FileDataBase64 ||\r\n selectedAttachment.FileThumbnailBase64)\r\n \"\r\n [alt]=\"selectedAttachment.FileName\"\r\n />\r\n } @else if (selectedAttachment.FileContentType?.startsWith('video/')) {\r\n <video\r\n controls\r\n autoplay\r\n playsinline\r\n class=\"main-preview-media video-player\"\r\n >\r\n <source\r\n [src]=\"selectedAttachment.TrustedUrl\"\r\n [type]=\"selectedAttachment.FileContentType\"\r\n />\r\n Il tuo browser non supporta il video.\r\n </video>\r\n } @else {\r\n <div class=\"iframe-container\">\r\n <iframe\r\n class=\"preview-iframe-modern\"\r\n [src]=\"selectedAttachment.TrustedUrl\"\r\n [title]=\"selectedAttachment.FileName\"\r\n ></iframe>\r\n </div>\r\n }\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Chiudi</button>\r\n @if (selectedAttachment.AttachmentType !== AttachmentType.LINK) {\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"viewAttachment(selectedAttachment)\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>download</mat-icon> <span>{{ downloadLabel() }}</span>\r\n </button>\r\n }\r\n </mat-dialog-actions>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- TEMPLATE PER IL PULSANTE DI AGGIUNTA NUOVO ALLEGATO -->\r\n<ng-template #addAttachmentButton>\r\n <input\r\n #fileInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n\r\n @if (allowedTypes && allowedTypes.length == 1 && (multipleAttachment() == true\r\n || !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length\r\n > 0 && !attachmentsList[0]))) {\r\n <button\r\n class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"addFile(allowedTypes[0], fileInput)\"\r\n [disabled]=\"isDisabled()\"\r\n >\r\n @if (allowedTypes[0] == 1) { <mat-icon>cloud_upload</mat-icon> } @if\r\n (allowedTypes[0] == 2) { <i class=\"fas fa-link\"></i> } @if (allowedTypes[0]\r\n == 3) { <i class=\"fa-brands fa-dropbox\"></i> }\r\n <span style=\"margin-left: 10px\">\r\n {{\r\n allowedTypes[0] == 1\r\n ? addButtonLabel() + \" file\"\r\n : allowedTypes[0] == 2\r\n ? addButtonLabel() + \" link\"\r\n : uploadWithDropboxLabel()\r\n }}\r\n </span>\r\n </button>\r\n } @if (!separatedUploadButtons() && allowedTypes && allowedTypes.length > 1 &&\r\n (multipleAttachment() == true || !attachmentsList || attachmentsList.length == 0\r\n || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button\r\n class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n [matMenuTriggerFor]=\"attachmentTypeMenu\"\r\n [disabled]=\"isDisabled()\"\r\n >\r\n @if (multipleAttachment() != true) { <mat-icon>cloud_upload</mat-icon> } @else\r\n { <mat-icon>add</mat-icon> }\r\n <span style=\"margin-left: 0px\">{{ addButtonLabel() }}</span>\r\n </button>\r\n\r\n <mat-menu #attachmentTypeMenu=\"matMenu\">\r\n <input\r\n #imageInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n @if (allowedTypes.includes(1)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"imageInput.click()\"\r\n class=\"eqp-attachments-file-btn\"\r\n >\r\n <i class=\"fas fa-file\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n } @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n class=\"eqp-attachments-link-btn\"\r\n >\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"chooseDropboxFile()\"\r\n class=\"eqp-attachments-link-btn\"\r\n >\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n } @if (separatedUploadButtons() && allowedTypes && allowedTypes.length > 1 &&\r\n (multipleAttachment() == true || !attachmentsList || attachmentsList.length == 0\r\n || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <div class=\"btn-group\">\r\n @if (allowedTypes.includes(1)) {\r\n <button\r\n (click)=\"imageInput.click()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fa-solid fa-cloud-upload\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n <input\r\n #imageInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n (click)=\"switchToAddingLinkMode()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n (click)=\"chooseDropboxFile()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #croppieTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ cropLabel() }}</span>\r\n <span class=\"file-t\">Regola le dimensioni e l'orientamento</span>\r\n </div>\r\n </div>\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"abortFile()\"\r\n class=\"close-btn\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"crop-toolbar\">\r\n @if (cropOptions().includes(1)) {\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"rotateLeftLabel()\"\r\n (click)=\"rotateLeft()\"\r\n >\r\n <mat-icon>rotate_left</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"rotateRightLabel()\"\r\n (click)=\"rotateRight()\"\r\n >\r\n <mat-icon>rotate_right</mat-icon>\r\n </button>\r\n } @if (cropOptions().includes(2)) {\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"flipHorinzontalLabel()\"\r\n (click)=\"flipHorizontal()\"\r\n >\r\n <mat-icon>flip_horizontal</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"flipVerticalLabel()\"\r\n (click)=\"flipVertical()\"\r\n >\r\n <mat-icon>flip_vertical</mat-icon>\r\n </button>\r\n }\r\n <button\r\n mat-icon-button\r\n matTooltip=\"Reset\"\r\n (click)=\"restoreOriginalDimensions()\"\r\n >\r\n <mat-icon>replay</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"media-viewer-wrapper\">\r\n <div class=\"crop-container-modern\">\r\n <image-cropper\r\n [imageFile]=\"selectedFile\"\r\n [maintainAspectRatio]=\"false\"\r\n [canvasRotation]=\"canvasRotation\"\r\n [transform]=\"transform\"\r\n format=\"png\"\r\n (imageCropped)=\"imageCropped($event)\"\r\n [resizeToWidth]=\"customWidth\"\r\n [resizeToHeight]=\"customHeight\"\r\n [output]=\"'base64'\"\r\n [containWithinAspectRatio]=\"true\"\r\n [onlyScaleDown]=\"true\"\r\n [alignImage]=\"'center'\"\r\n >\r\n </image-cropper>\r\n </div>\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button (click)=\"abortFile()\" class=\"btn-close\">\r\n {{ abortLabel() }}\r\n </button>\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"confirmAddAttachment()\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>check</mat-icon> {{ confirmLabel() }}\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- TEMPLATE PER FORM DI AGGIUNTA DI UN LINK -->\r\n<ng-template #addingLinkTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"type-icon-wrapper\">\r\n <mat-icon>link</mat-icon>\r\n </div>\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">Aggiungi un link</span>\r\n <span class=\"file-t\">Inserisci l'URL della risorsa web</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"add-link-modern-content\">\r\n <form [formGroup]=\"newAttachmentForm\" class=\"add-link-form\">\r\n <mat-form-field appearance=\"outline\" class=\"w-100 mt-3\">\r\n <mat-label>URL del collegamento</mat-label>\r\n <input\r\n matInput\r\n formControlName=\"filePath\"\r\n placeholder=\"https://...\"\r\n required\r\n />\r\n <mat-icon matSuffix>language</mat-icon>\r\n </mat-form-field>\r\n\r\n <mat-form-field appearance=\"outline\" class=\"w-100\">\r\n <mat-label>Titolo (opzionale)</mat-label>\r\n <input\r\n matInput\r\n formControlName=\"fileName\"\r\n placeholder=\"Es. Documento Progetto\"\r\n />\r\n <mat-icon matSuffix>title</mat-icon>\r\n </mat-form-field>\r\n </form>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Annulla</button>\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n [mat-dialog-close]=\"newAttachmentForm.value\"\r\n [disabled]=\"newAttachmentForm.invalid\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>add</mat-icon> Aggiungi\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{--primary-color: #6a5af9;--primary-color-dark: rgb(83.7807017544, 65.3947368421, 248.1052631579);--success-color: #1ce593;--error-color: #ff5b5b;--background-light: #f7f9fc;--background-card: rgba(255, 255, 255, .7);--text-color: #1e293b;--text-color-light: #64748b;--border-color: rgba(203, 213, 225, .5);--shadow-color: rgba(99, 102, 241, .2);--border-radius: 16px;--transition-speed: .3s}@keyframes fadeIn{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--primary-color)}70%{box-shadow:0 0 0 10px #6a5af900}to{box-shadow:0 0 #6a5af900}}.container{width:100%;max-width:700px;margin:2rem auto;font-family:Inter,sans-serif}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border-color)}.header h1{color:var(--text-color);font-size:1.8rem;font-weight:700;margin:0}.dropbox{width:100%;border:2px dashed var(--border-color);border-radius:var(--border-radius);padding:2.5rem;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;cursor:pointer;background-color:var(--background-card);backdrop-filter:blur(10px);transition:all var(--transition-speed) ease}.dropbox:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color);border-color:var(--primary-color)}.dropbox.dragover{border-style:solid;border-color:var(--primary-color);transform:scale(1.02);box-shadow:0 0 25px var(--shadow-color);animation:pulse 1.5s infinite}.dropbox .dropbox-icon{font-size:3.5rem;color:var(--primary-color)}.dropbox .dropbox-text{font-size:1.1rem;font-weight:600;color:var(--text-color);margin-top:1rem}.dropbox .dropbox-subtext{color:var(--text-color-light);margin-top:.5rem}.dropbox .browse-btn{margin-top:1.5rem;padding:.75rem 1.5rem;background-color:var(--primary-color);color:#fff;border:none;border-radius:10px;font-weight:600;transition:all var(--transition-speed) ease}.dropbox .browse-btn:hover{background-color:var(--primary-color-dark);transform:translateY(-2px)}.file-previews{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1.5rem;margin-top:2rem}.file-previews{display:grid;gap:16px;padding:16px;grid-template-columns:repeat(auto-fill,minmax(var(--card-min-width, 200px),1fr))}.file-preview{background-color:var(--background-card);border-radius:var(--border-radius);box-shadow:0 4px 15px #0000000d;border:1px solid var(--border-color);overflow:hidden;display:flex;flex-direction:column;position:relative;opacity:0;animation:fadeIn .5s ease-out forwards;transition:transform var(--transition-speed) ease,box-shadow var(--transition-speed) ease}.file-preview.uploading{cursor:wait}.file-preview.uploading .preview-img-container:after{content:\"\";position:absolute;inset:0;background:#ffffffb3;backdrop-filter:blur(5px);pointer-events:none}.file-preview .preview-action-overlay{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;background-color:#0006;color:#fff;opacity:1;transition:opacity .3s ease}.file-preview .preview-action-overlay .mat-icon{font-size:36px;width:36px;height:36px}.file-preview .remove-btn{position:absolute;top:8px;right:8px;z-index:2;background-color:#0000004d;color:#fff;width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;transition:all var(--transition-speed) ease}.file-preview .remove-btn:hover{background-color:#ff5b5b}.file-preview .remove-btn .mat-icon{font-size:18px}@media(hover:hover){.file-preview .remove-btn .file-preview .preview-action-overlay{opacity:0}.file-preview .remove-btn .file-preview:hover .preview-action-overlay,.file-preview .remove-btn .file-preview:hover .remove-btn{opacity:1}.file-preview .remove-btn .file-preview .remove-btn{opacity:0}}@media(hover:hover)and (min-width:769px){.file-preview .remove-btn{opacity:0;transform:scale(.8)}.file-preview:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color)}.file-preview:hover .remove-btn{opacity:1;transform:scale(1)}}.file-preview .preview-img-container{aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;background-color:#f0f2f5}.file-preview .preview-img{width:100%;height:100%;object-fit:cover}.file-preview .file-icon{font-size:4rem;color:var(--primary-color)}.file-preview .file-info{padding:12px;border-top:1px solid var(--border-color);flex-grow:1;display:flex;align-items:center}.file-preview .file-name{font-weight:600;font-size:.9rem;color:var(--text-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-preview .upload-spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;border:4px solid rgba(0,0,0,.1);border-left-color:var(--primary-color);border-radius:50%;animation:spin 1s linear infinite;pointer-events:none}.file-preview.card-small{width:140px}.file-preview.card-small .preview-img-container{height:80px}.file-preview.card-small .file-info{padding:8px}.file-preview.card-small .file-name{font-size:.8rem}.file-preview.card-small .file-icon{font-size:3rem}.file-preview.card-small .remove-btn{width:28px;height:28px}.file-preview.card-small .remove-btn .mat-icon{font-size:16px}.file-preview.card-large{width:280px}.file-preview.card-large .preview-img-container{height:180px}.file-preview.card-large .file-info{padding:16px}.file-preview.card-large .file-name{font-size:1rem}.file-preview.card-large .file-icon{font-size:5rem}.file-preview.card-large .remove-btn{width:36px;height:36px}.file-preview.card-large .remove-btn .mat-icon{font-size:20px}.file-preview[style*=--eqp-card-width]{width:var(--eqp-card-width)}.file-preview[style*=--eqp-card-width] .preview-img-container{height:calc(var(--eqp-card-width) * .65)}@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}.upload-stats{background-color:var(--background-card);backdrop-filter:blur(10px);border:1px solid var(--border-color);border-radius:var(--border-radius);padding:1.5rem;margin-top:2rem;animation:fadeIn .5s ease-out}.upload-stats .stats-info{display:flex;justify-content:space-around}.upload-stats .progress-bar{height:10px;background-color:var(--border-color);border-radius:5px;overflow:hidden;margin-top:1rem}.upload-stats .progress-fill{height:100%;background:linear-gradient(90deg,var(--primary-color),var(--success-color));transition:width var(--transition-speed) ease-out;border-radius:5px}.upload-notification{position:fixed;bottom:20px;left:50%;transform:translate(-50%,100px);padding:1rem 1.5rem;border-radius:var(--border-radius);color:#fff;font-weight:600;box-shadow:0 10px 30px #0003;transition:transform var(--transition-speed) cubic-bezier(.175,.885,.32,1.275)}.upload-notification.show{transform:translate(-50%)}.upload-notification.success{background-color:var(--success-color)}.upload-notification.error{background-color:var(--error-color)}::ng-deep .cdk-overlay-pane.eqp-crop-dialog{transform:translateY(-4vh)}@media(max-width:600px){::ng-deep .cdk-overlay-pane.crop-dialog{width:auto!important}}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__surface{border-radius:20px!important;padding:0!important;overflow:hidden!important;width:fit-content!important;min-width:350px!important;max-width:95vw!important;margin:0 auto;background-color:#fff!important}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;display:flex;flex-direction:column}.modern-dialog-container{display:flex;flex-direction:column;width:100%;max-width:100%;height:100%;max-height:90vh;background:#fff;--preview-header-h: 66px;--preview-footer-h: 66px;--preview-padding-y: 30px}.modern-dialog-container .main-preview-media{display:block;max-width:100%;max-height:var(--media-max-h);width:auto;height:auto;object-fit:contain;border-radius:12px;background:#fff;padding:4px;box-shadow:0 10px 30px #00000014}.modern-dialog-container video.main-preview-media{width:min(100%,1100px);background:#000}.modern-dialog-container .iframe-container{width:min(100%,1100px);height:var(--media-max-h);display:flex;width:100%;max-width:1100px}.modern-dialog-container .preview-iframe-modern{width:100%;height:100%;border:0;border-radius:12px;background:#f8fafc}.modern-dialog-container .preview-header{flex:0 0 auto;flex-shrink:0;padding:14px 20px;display:flex;align-items:center;justify-content:flex-start;border-bottom:1px solid var(--border-color);background:#f8fafc;z-index:10;width:100%}.modern-dialog-container .preview-header .header-info{display:flex;align-items:center;justify-content:flex-start;gap:12px;flex:1 1 auto;min-width:0;text-align:left}.modern-dialog-container .preview-header .header-info .type-icon-wrapper{background:var(--primary-color);color:#fff;width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 10px var(--shadow-color)}.modern-dialog-container .preview-header .header-info .title-group{display:flex;flex-direction:column;align-items:flex-start;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .main-t{font-weight:800;color:var(--text-color);font-size:.95rem;line-height:1.2;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .file-t{font-size:.75rem;color:var(--text-color-light);max-width:250px;overflow:hidden;text-overflow:ellipsis;text-align:left}.modern-dialog-container .preview-content-area{flex:1;background:#fff!important;display:flex;flex-direction:column;padding:15px 15px 22px!important;overflow:hidden!important;min-height:0;width:auto;--media-max-h: calc(90vh - var(--preview-header-h) - var(--preview-footer-h) - var(--preview-padding-y));width:100%}.modern-dialog-container .preview-content-area .crop-toolbar{flex-shrink:0;z-index:20;background:#0f172a14;backdrop-filter:blur(10px);padding:6px 16px;border-radius:30px;margin:0 auto 15px;display:flex;gap:8px;box-shadow:0 4px 12px #0000000d}.modern-dialog-container .preview-content-area .crop-toolbar button{color:var(--text-color)!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper{flex:1;width:100%;display:flex;justify-content:center;align-items:center;min-height:0;overflow:visible}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background:transparent;border-radius:12px;padding:0}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern image-cropper{max-width:100%;max-height:100%;display:block}.modern-dialog-container .add-link-modern-content{flex:1;background:#fff;padding:24px!important}.modern-dialog-container .add-link-modern-content .add-link-form{display:flex;flex-direction:column;gap:10px}.modern-dialog-container .preview-actions{flex-shrink:0;padding:12px 24px;background:#f8fafc;border-top:1px solid #e2e8f0;margin:0}.modern-dialog-container .preview-actions .btn-download{border-radius:12px;font-weight:600;box-shadow:0 4px 12px var(--shadow-color)}@media(max-width:600px){.modern-dialog-container{max-height:95vh}.modern-dialog-container .preview-content-area{padding:10px!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper video.main-preview-media{width:100%!important;max-height:55vh!important;border-radius:4px;box-shadow:none}.modern-dialog-container .preview-content-area .media-viewer-wrapper .iframe-container{height:50vh}.modern-dialog-container .preview-content-area .crop-toolbar{width:calc(100% - 20px);max-width:400px;margin-bottom:10px;padding:4px 8px;gap:4px;overflow-x:auto;justify-content:center;-webkit-overflow-scrolling:touch}.modern-dialog-container .preview-content-area .crop-toolbar::-webkit-scrollbar{display:none}.modern-dialog-container .preview-content-area .crop-toolbar{scrollbar-width:none}.modern-dialog-container .preview-content-area .crop-toolbar button{flex-shrink:0;transform:scale(.85);width:40px;height:40px}.modern-dialog-container .preview-actions{padding:10px 15px;flex-direction:column-reverse;gap:8px}.modern-dialog-container .preview-actions button{width:100%;margin:0!important}}@media(max-width:360px){.modern-dialog-container .preview-content-area .crop-toolbar{gap:2px}.modern-dialog-container .preview-content-area .crop-toolbar button{transform:scale(.75)}}.control-icon{font-size:28px;cursor:pointer}image-cropper,image-cropper canvas,image-cropper img{max-width:100%!important;max-height:100%!important}.crop-large{display:flex}.crop-small{display:none}@media(max-width:600px){.dialog-content{max-height:55vh}.crop-container{max-width:100%;aspect-ratio:auto}.crop-large{display:none}.crop-small{display:flex;justify-content:center;gap:14px}.control-icon{font-size:24px}}.stats-header{display:flex;justify-content:space-between;align-items:center;width:100%}.table-view-container{margin-top:1.5rem;background-color:var(--background-card);border-radius:var(--border-radius);border:1px solid var(--border-color);overflow:hidden;animation:fadeIn .5s ease-out}.table-header,.table-row{display:flex;align-items:center;padding:0 1rem;transition:background-color var(--transition-speed) ease}.table-header{background-color:#f8f9fa;font-weight:600;color:var(--text-color-light);font-size:.8rem;text-transform:uppercase;border-bottom:2px solid var(--border-color)}.table-row{border-bottom:1px solid var(--border-color)}.table-row:last-child{border-bottom:none}.table-row:hover{background-color:#00000005}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem}.name-col{flex:4}.size-col,.date-col{flex:2}.actions-col{flex:1;justify-content:flex-end;min-width:150px}.file-icon-small{font-size:1.5rem;color:var(--primary-color)}.file-info-text{display:flex;flex-direction:column}.file-name-table{font-weight:600;color:var(--text-color)}.file-type-table{font-size:.8rem;color:var(--text-color-light)}@media(max-width:768px){.date-col{display:none}.name-col{flex:3}.size-col{flex:2}.actions-col{flex:2;min-width:120px}}.secondary-action-link{color:var(--primary-color);text-decoration:none;border-bottom:1px solid var(--primary-color);cursor:pointer;font-weight:500}.secondary-action-link:hover{color:var(--primary-color-dark);border-bottom-color:var(--primary-color-dark)}h2[mat-dialog-title]+mat-dialog-content.add-link-dialog-content{padding-top:20px}mat-dialog-content.add-link-dialog-content{padding-left:24px;padding-right:24px;padding-bottom:20px}.add-link-form{display:flex;flex-direction:column;gap:16px}::ng-deep .eqp-attachments-preview-dialog{--mat-dialog-subhead-line-height: normal}::ng-deep .eqp-attachments-preview-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;background:#fff!important}:host ::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{--mat-dialog-subhead-size: 1.25rem;--mat-dialog-subhead-line-height: 1.5;--mat-dialog-subhead-weight: 600;--mat-dialog-supporting-text-size: 1rem}.empty-state{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:1.5rem 1rem;margin-top:1.5rem;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#f8f9fa;text-align:center;color:var(--text-color-light);animation:fadeIn .5s ease-out}.empty-state:before{content:\"\\1f4ed\";font-size:2.5rem;margin-bottom:1rem;opacity:.7}.secondary-action-link.disabled-link{color:#adb5bd;cursor:not-allowed;border-bottom-color:transparent}.secondary-action-link.disabled-link:hover{color:#adb5bd;border-bottom-color:transparent}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem;min-width:0;overflow:hidden}.table-cell.col-actions{flex:0 0 150px;justify-content:flex-end;overflow:visible}.compact-uploader{display:flex;align-items:center;gap:16px;padding:16px;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#fcfdff;transition:all .3s ease}.compact-uploader .compact-text{flex:1 1 auto;min-width:0;cursor:pointer}.compact-uploader .compact-text:hover .compact-title{color:var(--primary-color)}.compact-uploader .compact-title{font-weight:600;color:var(--text-color);transition:color .3s ease}.compact-uploader .compact-subtitle{font-size:.8rem;color:var(--text-color-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.compact-uploader .compact-icon mat-icon{font-size:36px;width:36px;height:36px;color:var(--primary-color)}.compact-uploader .compact-actions{display:flex;gap:8px;flex-shrink:0}.compact-uploader.dragover{background-color:#f4f8ff;border-color:var(--primary-color);box-shadow:0 0 10px var(--shadow-color)}\n"], dependencies: [{ kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i7.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i7.MatLabel, selector: "mat-label" }, { kind: "directive", type: i7.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i8.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: i9.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i9.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i12.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i12.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i12.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i13.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: "pipe", type: i12.DatePipe, name: "date" }] });
1578
1626
  }
1579
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsComponent, decorators: [{
1627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsComponent, decorators: [{
1580
1628
  type: Component,
1581
- args: [{ selector: "eqp-attachments", template: "<!-- Se richiesta la gestione singola mostra il pulsante di caricamento di un singolo file -->\r\n@if(showUploadTitle == true || chooseView == true){\r\n<div class=\"header\">\r\n @if(showUploadTitle == true){\r\n <h4>{{ uploadTitle }}</h4>\r\n }\r\n @if(chooseView == true){\r\n <mat-button-toggle-group [value]=\"viewMode\" (change)=\"setViewMode($event.value)\"\r\n aria-label=\"Modalit\u00E0 di visualizzazione\">\r\n <mat-button-toggle value=\"card\"><mat-icon>grid_view</mat-icon></mat-button-toggle>\r\n <mat-button-toggle value=\"table\"><mat-icon>view_list</mat-icon></mat-button-toggle>\r\n </mat-button-toggle-group>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione singolo -->\r\n@if (multipleAttachment != true) {\r\n@if (!singleAttachmentDragAndDrop) {\r\n@if (!addingLinkMode) {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addAttachmentButton\"></ng-container>\r\n</div>\r\n} @else {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addingLinkTemplate\"></ng-container>\r\n</div>\r\n}\r\n} @else {\r\n<input #fileInput id=\"file_attachment\" name=\"file_attachment\" type=\"file\" hidden (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n@if (allowedTypes && allowedTypes.includes(1) && (!attachmentsList || attachmentsList.length == 0 ||\r\n(attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n\r\n@if (showDropArea == true) {\r\n<!-- FULL -->\r\n@if (layout === 'full') {\r\n\r\n<div class=\"dropbox\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\"\r\n (click)=\"!isDisabled && onSelectFile($event, fileInput)\" role=\"button\" [attr.tabindex]=\"isDisabled ? -1 : 0\"\r\n (keydown.enter)=\"!isDisabled && fileInput.click()\" (keydown.space)=\"!isDisabled && fileInput.click()\">\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel }}\r\n </div>\r\n <button class=\"browse-btn\" type=\"button\" (click)=\"$event.stopPropagation(); fileInput.click()\">\r\n {{ browseFilesLabel }}\r\n </button>\r\n <div class=\"secondary-action\">\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n @if (allowedTypes.includes(2) && allowedTypes.includes(3)) {\r\n <a class=\"secondary-action-link\" [matMenuTriggerFor]=\"isDisabled ? null : linkMenu\"\r\n [class.disabled-link]=\"isDisabled\" (click)=\"$event.stopPropagation()\">\r\n o aggiungi da web\r\n </a>\r\n <mat-menu #linkMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"switchToAddingLinkMode()\">\r\n <mat-icon>link</mat-icon>\r\n <span>Aggiungi da link</span>\r\n </button>\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\">\r\n <mat-icon>cloud_queue</mat-icon>\r\n <span>Carica da Dropbox</span>\r\n </button>\r\n </mat-menu>\r\n }\r\n\r\n @else if (allowedTypes.includes(2)) {\r\n <a [class.disabled-link]=\"isDisabled\" class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\">\r\n aggiungi un link\r\n </a>\r\n }\r\n\r\n @else if (allowedTypes.includes(3)) {\r\n <a [class.disabled-link]=\"isDisabled\" class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); chooseDropboxFile()\">\r\n carica da Dropbox\r\n </a>\r\n }\r\n }\r\n </div>\r\n</div>\r\n}@else {\r\n<div class=\"compact-uploader\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\">\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"!isDisabled && onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button mat-stroked-button color=\"primary\" [disabled]=\"isDisabled\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\">Sfoglia</button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button mat-stroked-button [disabled]=\"isDisabled\" [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\">Link</button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) { <button mat-menu-item [disabled]=\"isDisabled\"\r\n (click)=\"switchToAddingLinkMode()\">{{ openLinkLabel }}</button> }\r\n @if (allowedTypes.includes(3)) { <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"chooseDropboxFile()\">{{\r\n uploadWithDropboxLabel }}</button> }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n}\r\n}\r\n}\r\n}\r\n\r\n<!-- Azioni singolo elemento (come prima) -->\r\n<div class=\"text-center\">\r\n @if (attachmentsList && attachmentsList.length > 0 && attachmentsList[0] && showActionButtons == true) {\r\n @if (!isPrimaryActionHidden(attachmentsList[0])) {\r\n <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button color=\"primary\">\r\n @if (attachmentsList[0].AttachmentType == AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n {{ attachmentsList[0].AttachmentType == AttachmentType.FILE ? downloadLabel : openLinkLabel }}\r\n </button>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(attachmentsList[0]) && showPreview && (!attachmentsList[0].FileContentType || (!attachmentsList[0].FileContentType.startsWith('video')\r\n && !attachmentsList[0].FileContentType.startsWith('audio'))) && attachmentsList[0].IsImage == true) {\r\n <button class=\"mb-2 me-2 eqp-attachments-preview-btn\" (click)=\"openPreviewDialog(attachmentsList[0])\" type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button color=\"primary\">\r\n <mat-icon>visibility</mat-icon> {{ previewLabel }}\r\n </button>\r\n }\r\n\r\n <button [disabled]=\"disableAction\" class=\"mb-2 eqp-attachments-delete-btn\"\r\n (click)=\"deleteAttachment(attachmentsList[0])\" type=\"button\" mat-raised-button [disabled]=\"isDisabled\">\r\n <mat-icon>delete</mat-icon> {{ deleteLabel }}\r\n </button>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione multipla -->\r\n@if (multipleAttachment == true && showDropArea == true) {\r\n<input #fileInput id=\"file_attachment_multi\" name=\"file_attachment_multi\" type=\"file\" hidden\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n@if (layout === 'full') {\r\n<div class=\"dropbox\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\"\r\n (click)=\"!isDisabled && onSelectFile($event, fileInput)\" role=\"button\" [attr.tabindex]=\"isDisabled ? -1 : 0\"\r\n (keydown.enter)=\"!isDisabled && fileInput.click()\" (keydown.space)=\"!isDisabled && fileInput.click()\">\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel }}\r\n </div>\r\n <button class=\"browse-btn\" type=\"button\" (click)=\"$event.stopPropagation(); fileInput.click()\">\r\n {{ browseFilesLabel }}\r\n </button>\r\n @if (allowedTypes.includes(2)) {\r\n <div class=\"secondary-action-link\">\r\n o <a (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\">aggiungi un link</a>\r\n </div>\r\n }\r\n</div>\r\n}@else{\r\n<div class=\"compact-uploader\" [class.dragover]=\"dragOver && !isDisabled\" [class.disabled-dropzone]=\"isDisabled\"\r\n (dragover)=\"!isDisabled ? dragOver = true : null; $event.preventDefault()\" (dragleave)=\"dragOver = false\"\r\n (drop)=\"!isDisabled ? (dragOver = false) : null; fileDropped($event)\">\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"!isDisabled && onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button mat-stroked-button [disabled]=\"isDisabled\" color=\"primary\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\">Sfoglia</button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button mat-stroked-button [disabled]=\"isDisabled\" [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\">Link</button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) { <button mat-menu-item [disabled]=\"isDisabled\"\r\n (click)=\"switchToAddingLinkMode()\">{{ openLinkLabel }}</button> }\r\n @if (allowedTypes.includes(3)) { <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"chooseDropboxFile()\">{{\r\n uploadWithDropboxLabel }}</button> }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n}\r\n}\r\n\r\n@if (attachmentsList?.length > 0 && showSummary) {\r\n<div class=\"upload-stats\">\r\n\r\n <div class=\"stats-info\">\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ attachmentsList?.length }}</div>\r\n <div class=\"stat-label\">{{ filesLabel }}</div>\r\n </div>\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ totalSizeFormatted }}</div>\r\n <div class=\"stat-label\">{{ totalSizeLabel }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"progressPercent\"></div>\r\n </div>\r\n\r\n</div>\r\n} @else if(attachmentsList?.length == 0){\r\n<div class=\"empty-state\">{{ emptyStateLabel }}</div>\r\n}\r\n\r\n<!-- Griglia anteprime card (vale per singolo e multiplo) -->\r\n@if (viewMode === 'card') {\r\n\r\n<div class=\"file-previews\" [ngStyle]=\"getPreviewsContainerStyle()\">\r\n @for (att of attachmentsList; track att.ID) {\r\n <div [ngClass]=\"getCardClass(att)\">\r\n <div class=\"preview-img-container\" (click)=\"!att.isUploading && !isPrimaryActionHidden(att) && !isPrimaryActionDisabled(att) && handlePrimaryAction(att)\">\r\n\r\n @if (att.IsImage || att.FileThumbnailBase64) {\r\n <img class=\"preview-img\" [src]=\"'data:image/jpeg;base64,' + (att.FileThumbnailBase64 || att.FileDataBase64)\"\r\n [alt]=\"att.FileName\" />\r\n } @else {\r\n <div class=\"file-icon\"><i [ngClass]=\"getAttachmentIcon(att)\"></i></div>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(att)) {\r\n <div class=\"preview-action-overlay\">\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n <mat-icon>play_arrow</mat-icon>\r\n }\r\n @else if (att.IsImage && canBePreviewed(att)) {\r\n <mat-icon>visibility</mat-icon>\r\n }\r\n @else if (att.FileContentType === 'application/pdf' && canBePreviewed(att)) {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n @else if (att.AttachmentType === AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n }\r\n @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n </div>\r\n }\r\n\r\n </div>\r\n\r\n <div class=\"file-info\">\r\n <div class=\"file-name\" [title]=\"att.FileName\">{{ att.FileName }}</div>\r\n </div>\r\n\r\n @if(!isDeleteHidden(att)){\r\n <button mat-icon-button class=\"remove-btn\" (click)=\"deleteAttachment(att)\"\r\n [disabled]=\"att.isUploading || isDeleteDisabled(att)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n }\r\n\r\n @if (att.isUploading) {\r\n <div class=\"upload-spinner\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n} @else if(viewMode === 'table' && attachmentsList?.length > 0) {\r\n\r\n\r\n<div class=\"table-view-container\">\r\n\r\n <div class=\"table-header\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div class=\"table-cell\" [style.flex]=\"col.styles?.flex\" [ngClass]=\"col.class\">\r\n {{ col.display }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @for (att of attachmentsList; track att.ID) {\r\n <div class=\"table-row\">\r\n\r\n @for (col of _tableColumns; track col.key) {\r\n <div class=\"table-cell\" [style.flex]=\"col.styles?.flex\" [ngClass]=\"col.class\">\r\n\r\n @switch (col.type) {\r\n\r\n @case ('template') {\r\n <div class=\"template-wrapper\">\r\n <ng-container [ngTemplateOutlet]=\"col.externalTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: att }\"></ng-container>\r\n </div>\r\n }\r\n @case ('date') {\r\n <span class=\"metadata-value\">{{ att[col.key] | date:'dd/MM/yyyy' }}</span>\r\n }\r\n @default {\r\n <span class=\"metadata-value\">{{ att[col.key] }}</span>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Notifica toast -->\r\n<div class=\"upload-notification\" [class.show]=\"toast?.visible\" [class.success]=\"toast?.type === 'success'\"\r\n [class.error]=\"toast?.type === 'error'\">\r\n <span>{{ toast?.text }}</span>\r\n <div class=\"notification-progress\"></div>\r\n</div>\r\n\r\n<ng-template #defaultFileTemplate let-att>\r\n <i class=\"file-icon-small\" [ngClass]=\"getAttachmentIcon(att)\"></i>\r\n <div class=\"file-info-text\">\r\n <span class=\"file-name-table\">{{ att.FileName }}</span>\r\n <span class=\"file-type-table\">{{ att.FileExtension || 'Link' }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #defaultActionsTemplate let-att>\r\n @if (!isPrimaryActionHidden(att)) {\r\n <button mat-icon-button (click)=\"handlePrimaryAction(att)\" [disabled]=\"isPrimaryActionDisabled(att)\"\r\n [matTooltip]=\"att.FileContentType?.startsWith('video/') ? 'Riproduci video' : 'Visualizza/Scarica'\">\r\n\r\n <mat-icon>\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n play_arrow\r\n } @else {\r\n {{ att.AttachmentType === AttachmentType.FILE ? 'download' : 'open_in_new' }}\r\n }\r\n </mat-icon>\r\n </button>\r\n }\r\n\r\n @if (!hiddenActions.includes('actionsMenu')) {\r\n <button mat-icon-button [matMenuTriggerFor]=\"actionsMenu\" matTooltip=\"Altre opzioni\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n\r\n <mat-menu #actionsMenu=\"matMenu\">\r\n @for (action of _sortedMenuActions; track action.name) {\r\n @if (!isActionHidden(action, att)) {\r\n <button mat-menu-item (click)=\"action.fn(att)\" [disabled]=\"isActionDisabled(action, att)\">\r\n <mat-icon [color]=\"action.icon === 'delete' ? 'warn' : undefined\">\r\n {{ action.icon }}\r\n </mat-icon>\r\n <span>{{ action.name }}</span>\r\n </button>\r\n }\r\n }\r\n </mat-menu>\r\n</ng-template>\r\n\r\n\r\n<ng-template #dialogCropImage>\r\n <div style=\"overflow-x: hidden; display: flex; flex-direction: column; height: 100%; min-height: 0; flex: 1 1 auto;\"\r\n [ngClass]=\"cropDialogClass\">\r\n <!-- @if (showCropImage == true) { -->\r\n <ng-container [ngTemplateOutlet]=\"croppieTemplate\" [ngTemplateOutletContext]=\"{ form: newAttachmentForm }\">\r\n </ng-container>\r\n <!-- } -->\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<ng-template #inlinePreviewTemplate let-row=\"row\">\r\n @if (row.AttachmentType != AttachmentType.LINK && row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <img [src]=\"'data:image/png;base64,' + (row.FileThumbnailBase64 ? row.FileThumbnailBase64 : row.FileDataBase64)\" />\r\n </div>\r\n } @else if (row.AttachmentType != AttachmentType.LINK && !row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <i [ngClass]=\"getAttachmentIcon(row)\"></i>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n\r\n<ng-template #dialogPreview>\r\n <div class=\"modern-dialog-container\"> @if (selectedAttachment) {\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ previewLabel }}</span>\r\n <span class=\"file-t\">{{ selectedAttachment.FileName }}</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"media-viewer-wrapper\">\r\n @if (selectedAttachment.IsImage) {\r\n <img class=\"main-preview-media\"\r\n [src]=\"'data:image/png;base64,' + (selectedAttachment.FileDataBase64 || selectedAttachment.FileThumbnailBase64)\"\r\n [alt]=\"selectedAttachment.FileName\" />\r\n }\r\n @else if (selectedAttachment.FileContentType?.startsWith('video/')) {\r\n <video controls autoplay playsinline class=\"main-preview-media video-player\">\r\n <source [src]=\"selectedAttachment.TrustedUrl\" [type]=\"selectedAttachment.FileContentType\">\r\n Il tuo browser non supporta il video.\r\n </video>\r\n }\r\n @else {\r\n <div class=\"iframe-container\">\r\n <iframe class=\"preview-iframe-modern\" [src]=\"selectedAttachment.TrustedUrl\"\r\n [title]=\"selectedAttachment.FileName\"></iframe>\r\n </div>\r\n }\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Chiudi</button>\r\n @if (selectedAttachment.AttachmentType !== AttachmentType.LINK) {\r\n <button mat-raised-button color=\"primary\" (click)=\"viewAttachment(selectedAttachment)\" class=\"btn-download\">\r\n <mat-icon>download</mat-icon> <span>{{ downloadLabel }}</span>\r\n </button>\r\n }\r\n </mat-dialog-actions>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n\r\n<!-- TEMPLATE PER IL PULSANTE DI AGGIUNTA NUOVO ALLEGATO -->\r\n<ng-template #addAttachmentButton>\r\n <input #fileInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n\r\n @if (allowedTypes && allowedTypes.length == 1 && (multipleAttachment == true || !attachmentsList ||\r\n attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\" mat-raised-button color=\"primary\" type=\"button\"\r\n (click)=\"addFile(allowedTypes[0], fileInput)\" [disabled]=\"isDisabled\">\r\n @if (allowedTypes[0] == 1) { <mat-icon>cloud_upload</mat-icon> }\r\n @if (allowedTypes[0] == 2) { <i class=\"fas fa-link\"></i> }\r\n @if (allowedTypes[0] == 3) { <i class=\"fa-brands fa-dropbox\"></i> }\r\n <span style=\"margin-left: 10px\">\r\n {{ allowedTypes[0] == 1 ? (addButtonLabel + \" file\") : allowedTypes[0] == 2 ? (addButtonLabel + \" link\") :\r\n uploadWithDropboxLabel }}\r\n </span>\r\n </button>\r\n }\r\n\r\n @if (!separatedUploadButtons && allowedTypes && allowedTypes.length > 1 && (multipleAttachment == true ||\r\n !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\" mat-raised-button color=\"primary\" type=\"button\"\r\n [matMenuTriggerFor]=\"attachmentTypeMenu\" [disabled]=\"isDisabled\">\r\n @if (multipleAttachment != true) { <mat-icon>cloud_upload</mat-icon> } @else { <mat-icon>add</mat-icon> }\r\n <span style=\"margin-left: 0px\">{{ addButtonLabel }}</span>\r\n </button>\r\n\r\n <mat-menu #attachmentTypeMenu=\"matMenu\">\r\n <input #imageInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n @if (allowedTypes.includes(1)) {\r\n <button mat-menu-item (click)=\"imageInput.click()\" class=\"eqp-attachments-file-btn\">\r\n <i class=\"fas fa-file\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(2)) {\r\n <button mat-menu-item [disabled]=\"isDisabled\" (click)=\"switchToAddingLinkMode()\" class=\"eqp-attachments-link-btn\">\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(3)) {\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\" class=\"eqp-attachments-link-btn\">\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n\r\n @if (separatedUploadButtons && allowedTypes && allowedTypes.length > 1 && (multipleAttachment == true ||\r\n !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <div class=\"btn-group\">\r\n @if (allowedTypes.includes(1)) {\r\n <button (click)=\"imageInput.click()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fa-solid fa-cloud-upload\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n <input #imageInput style=\"display: none\" id=\"file_attachment\" name=\"file_attachment\" type=\"file\"\r\n (change)=\"onFileAdded($event)\" [accept]=\"acceptedFileTypes\" [multiple]=\"loadMultipleFiles\" />\r\n @if (allowedTypes.includes(2)) {\r\n <button (click)=\"switchToAddingLinkMode()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n }\r\n @if (allowedTypes.includes(3)) {\r\n <button (click)=\"chooseDropboxFile()\" class=\"btn btn-secondary eqp-attachments-add-btn\" mat-raised-button\r\n color=\"secondary\" type=\"button\">\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n\r\n<ng-template #croppieTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ cropLabel }}</span>\r\n <span class=\"file-t\">Regola le dimensioni e l'orientamento</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button type=\"button\" (click)=\"abortFile()\" class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"crop-toolbar\">\r\n @if (cropOptions.includes(1)) {\r\n <button mat-icon-button [matTooltip]=\"rotateLeftLabel\"\r\n (click)=\"rotateLeft()\"><mat-icon>rotate_left</mat-icon></button>\r\n <button mat-icon-button [matTooltip]=\"rotateRightLabel\"\r\n (click)=\"rotateRight()\"><mat-icon>rotate_right</mat-icon></button>\r\n }\r\n @if (cropOptions.includes(2)) {\r\n <button mat-icon-button [matTooltip]=\"flipHorinzontalLabel\"\r\n (click)=\"flipHorizontal()\"><mat-icon>flip_horizontal</mat-icon></button>\r\n <button mat-icon-button [matTooltip]=\"flipVerticalLabel\"\r\n (click)=\"flipVertical()\"><mat-icon>flip_vertical</mat-icon></button>\r\n }\r\n <button mat-icon-button matTooltip=\"Reset\"\r\n (click)=\"restoreOriginalDimensions()\"><mat-icon>replay</mat-icon></button>\r\n </div>\r\n\r\n <div class=\"media-viewer-wrapper\">\r\n <div class=\"crop-container-modern\">\r\n <image-cropper [imageFile]=\"selectedFile\" [maintainAspectRatio]=\"false\" [canvasRotation]=\"canvasRotation\"\r\n [transform]=\"transform\" format=\"png\" (imageCropped)=\"imageCropped($event)\" [resizeToWidth]=\"customWidth\"\r\n [resizeToHeight]=\"customHeight\" [output]=\"'base64'\" [containWithinAspectRatio]=\"true\" [onlyScaleDown]=\"true\"\r\n [alignImage]=\"'center'\">\r\n </image-cropper>\r\n </div>\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button (click)=\"abortFile()\" class=\"btn-close\">{{ abortLabel }}</button>\r\n <button mat-raised-button color=\"primary\" (click)=\"confirmAddAttachment()\" class=\"btn-download\">\r\n <mat-icon>check</mat-icon> {{ confirmLabel }}\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n\r\n\r\n\r\n<!-- TEMPLATE PER FORM DI AGGIUNTA DI UN LINK -->\r\n<ng-template #addingLinkTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"type-icon-wrapper\">\r\n <mat-icon>link</mat-icon>\r\n </div>\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">Aggiungi un link</span>\r\n <span class=\"file-t\">Inserisci l'URL della risorsa web</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\"><mat-icon>close</mat-icon></button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"add-link-modern-content\">\r\n <form [formGroup]=\"newAttachmentForm\" class=\"add-link-form\">\r\n <mat-form-field appearance=\"outline\" class=\"w-100 mt-3\">\r\n <mat-label>URL del collegamento</mat-label>\r\n <input matInput formControlName=\"filePath\" placeholder=\"https://...\" required>\r\n <mat-icon matSuffix>language</mat-icon>\r\n </mat-form-field>\r\n\r\n <mat-form-field appearance=\"outline\" class=\"w-100\">\r\n <mat-label>Titolo (opzionale)</mat-label>\r\n <input matInput formControlName=\"fileName\" placeholder=\"Es. Documento Progetto\">\r\n <mat-icon matSuffix>title</mat-icon>\r\n </mat-form-field>\r\n </form>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Annulla</button>\r\n <button mat-raised-button color=\"primary\" [mat-dialog-close]=\"newAttachmentForm.value\"\r\n [disabled]=\"newAttachmentForm.invalid\" class=\"btn-download\">\r\n <mat-icon>add</mat-icon> Aggiungi\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>", styles: ["@charset \"UTF-8\";:host{--primary-color: #6a5af9;--primary-color-dark: #5441f8;--success-color: #1ce593;--error-color: #ff5b5b;--background-light: #f7f9fc;--background-card: rgba(255, 255, 255, .7);--text-color: #1e293b;--text-color-light: #64748b;--border-color: rgba(203, 213, 225, .5);--shadow-color: rgba(99, 102, 241, .2);--border-radius: 16px;--transition-speed: .3s}@keyframes fadeIn{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--primary-color)}70%{box-shadow:0 0 0 10px #6a5af900}to{box-shadow:0 0 #6a5af900}}.container{width:100%;max-width:700px;margin:2rem auto;font-family:Inter,sans-serif}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border-color)}.header h1{color:var(--text-color);font-size:1.8rem;font-weight:700;margin:0}.dropbox{width:100%;border:2px dashed var(--border-color);border-radius:var(--border-radius);padding:2.5rem;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;cursor:pointer;background-color:var(--background-card);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:all var(--transition-speed) ease}.dropbox:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color);border-color:var(--primary-color)}.dropbox.dragover{border-style:solid;border-color:var(--primary-color);transform:scale(1.02);box-shadow:0 0 25px var(--shadow-color);animation:pulse 1.5s infinite}.dropbox .dropbox-icon{font-size:3.5rem;color:var(--primary-color)}.dropbox .dropbox-text{font-size:1.1rem;font-weight:600;color:var(--text-color);margin-top:1rem}.dropbox .dropbox-subtext{color:var(--text-color-light);margin-top:.5rem}.dropbox .browse-btn{margin-top:1.5rem;padding:.75rem 1.5rem;background-color:var(--primary-color);color:#fff;border:none;border-radius:10px;font-weight:600;transition:all var(--transition-speed) ease}.dropbox .browse-btn:hover{background-color:var(--primary-color-dark);transform:translateY(-2px)}.file-previews{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1.5rem;margin-top:2rem}.file-previews{display:grid;gap:16px;padding:16px;grid-template-columns:repeat(auto-fill,minmax(var(--card-min-width, 200px),1fr))}.file-preview{background-color:var(--background-card);border-radius:var(--border-radius);box-shadow:0 4px 15px #0000000d;border:1px solid var(--border-color);overflow:hidden;display:flex;flex-direction:column;position:relative;opacity:0;animation:fadeIn .5s ease-out forwards;transition:transform var(--transition-speed) ease,box-shadow var(--transition-speed) ease}.file-preview.uploading{cursor:wait}.file-preview.uploading .preview-img-container:after{content:\"\";position:absolute;inset:0;background:#ffffffb3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);pointer-events:none}.file-preview .preview-action-overlay{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;background-color:#0006;color:#fff;opacity:1;transition:opacity .3s ease}.file-preview .preview-action-overlay .mat-icon{font-size:36px;width:36px;height:36px}.file-preview .remove-btn{position:absolute;top:8px;right:8px;z-index:2;background-color:#0000004d;color:#fff;width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;transition:all var(--transition-speed) ease}.file-preview .remove-btn:hover{background-color:#ff5b5b}.file-preview .remove-btn .mat-icon{font-size:18px}@media (hover: hover){.file-preview .remove-btn .file-preview .preview-action-overlay{opacity:0}.file-preview .remove-btn .file-preview:hover .preview-action-overlay,.file-preview .remove-btn .file-preview:hover .remove-btn{opacity:1}.file-preview .remove-btn .file-preview .remove-btn{opacity:0}}@media (hover: hover) and (min-width: 769px){.file-preview .remove-btn{opacity:0;transform:scale(.8)}.file-preview:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color)}.file-preview:hover .remove-btn{opacity:1;transform:scale(1)}}.file-preview .preview-img-container{aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;background-color:#f0f2f5}.file-preview .preview-img{width:100%;height:100%;object-fit:cover}.file-preview .file-icon{font-size:4rem;color:var(--primary-color)}.file-preview .file-info{padding:12px;border-top:1px solid var(--border-color);flex-grow:1;display:flex;align-items:center}.file-preview .file-name{font-weight:600;font-size:.9rem;color:var(--text-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-preview .upload-spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;border:4px solid rgba(0,0,0,.1);border-left-color:var(--primary-color);border-radius:50%;animation:spin 1s linear infinite;pointer-events:none}.file-preview.card-small{width:140px}.file-preview.card-small .preview-img-container{height:80px}.file-preview.card-small .file-info{padding:8px}.file-preview.card-small .file-name{font-size:.8rem}.file-preview.card-small .file-icon{font-size:3rem}.file-preview.card-small .remove-btn{width:28px;height:28px}.file-preview.card-small .remove-btn .mat-icon{font-size:16px}.file-preview.card-large{width:280px}.file-preview.card-large .preview-img-container{height:180px}.file-preview.card-large .file-info{padding:16px}.file-preview.card-large .file-name{font-size:1rem}.file-preview.card-large .file-icon{font-size:5rem}.file-preview.card-large .remove-btn{width:36px;height:36px}.file-preview.card-large .remove-btn .mat-icon{font-size:20px}.file-preview[style*=--eqp-card-width]{width:var(--eqp-card-width)}.file-preview[style*=--eqp-card-width] .preview-img-container{height:calc(var(--eqp-card-width) * .65)}@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}.upload-stats{background-color:var(--background-card);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid var(--border-color);border-radius:var(--border-radius);padding:1.5rem;margin-top:2rem;animation:fadeIn .5s ease-out}.upload-stats .stats-info{display:flex;justify-content:space-around}.upload-stats .progress-bar{height:10px;background-color:var(--border-color);border-radius:5px;overflow:hidden;margin-top:1rem}.upload-stats .progress-fill{height:100%;background:linear-gradient(90deg,var(--primary-color),var(--success-color));transition:width var(--transition-speed) ease-out;border-radius:5px}.upload-notification{position:fixed;bottom:20px;left:50%;transform:translate(-50%,100px);padding:1rem 1.5rem;border-radius:var(--border-radius);color:#fff;font-weight:600;box-shadow:0 10px 30px #0003;transition:transform var(--transition-speed) cubic-bezier(.175,.885,.32,1.275)}.upload-notification.show{transform:translate(-50%)}.upload-notification.success{background-color:var(--success-color)}.upload-notification.error{background-color:var(--error-color)}::ng-deep .cdk-overlay-pane.eqp-crop-dialog{transform:translateY(-4vh)}@media (max-width: 600px){::ng-deep .cdk-overlay-pane.crop-dialog{width:auto!important}}::ng-deep .eqp-attachments-dialog{display:flex!important;flex-direction:column!important}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__container{display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__container .mdc-dialog__surface{border-radius:20px!important;padding:0!important;overflow:hidden!important;width:fit-content!important;min-width:350px!important;max-width:95vw!important;max-height:90vh!important;margin:0 auto;background-color:#fff!important;display:flex!important;flex-direction:column!important;flex:1 1 auto;min-height:0}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden!important}.modern-dialog-container{display:flex;flex-direction:column;width:100%;max-width:100%;flex:1 1 auto;min-height:0;height:100%;max-height:100%;background:#fff;--preview-header-h: 66px;--preview-footer-h: 66px;--preview-padding-y: 30px}.modern-dialog-container .main-preview-media{display:block;max-width:100%;max-height:var(--media-max-h);width:auto;height:auto;object-fit:contain;border-radius:12px;background:#fff;padding:4px;box-shadow:0 10px 30px #00000014}.modern-dialog-container video.main-preview-media{width:min(100%,1100px);background:#000}.modern-dialog-container .iframe-container{width:min(100%,1100px);height:var(--media-max-h);display:flex;width:100%;max-width:1100px}.modern-dialog-container .preview-iframe-modern{width:100%;height:100%;border:0;border-radius:12px;background:#f8fafc}.modern-dialog-container .preview-header{flex:0 0 auto;flex-shrink:0;padding:14px 20px;display:flex;align-items:center;justify-content:flex-start;border-bottom:1px solid var(--border-color);background:#f8fafc;z-index:10;width:100%}.modern-dialog-container .preview-header .close-btn{display:inline-flex!important;align-items:center!important;justify-content:center!important;padding:0!important;width:40px!important;height:40px!important}.modern-dialog-container .preview-header .close-btn ::ng-deep mat-icon{display:flex!important;align-items:center!important;justify-content:center!important;margin:0!important;padding:0!important;line-height:1!important}.modern-dialog-container .preview-header .header-info{display:flex;align-items:center;justify-content:flex-start;gap:12px;flex:1 1 auto;min-width:0;text-align:left}.modern-dialog-container .preview-header .header-info .type-icon-wrapper{background:var(--primary-color);color:#fff;width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 10px var(--shadow-color)}.modern-dialog-container .preview-header .header-info .title-group{display:flex;flex-direction:column;align-items:flex-start;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .main-t{font-weight:800;color:var(--text-color);font-size:.95rem;line-height:1.2;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .file-t{font-size:.75rem;color:var(--text-color-light);max-width:250px;overflow:hidden;text-overflow:ellipsis;text-align:left}.modern-dialog-container .preview-content-area{flex:1 1 auto;background:#fff!important;display:flex;flex-direction:column;padding:15px 15px 22px!important;overflow:hidden!important;min-height:0;width:100%;--media-max-h: calc(90vh - var(--preview-header-h) - var(--preview-footer-h) - var(--preview-padding-y))}.modern-dialog-container .preview-content-area .crop-toolbar{flex-shrink:0;z-index:20;background:#0f172a14;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:6px 16px;border-radius:30px;margin:0 auto 15px;display:flex;gap:8px;box-shadow:0 4px 12px #0000000d}.modern-dialog-container .preview-content-area .crop-toolbar button{color:var(--text-color)!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper{flex:1 1 auto;width:100%;height:100%;display:flex;flex-direction:column;align-items:stretch;min-height:0;overflow:hidden}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;align-items:center;background:transparent;border-radius:12px;padding:0;overflow:hidden;min-height:0;width:100%;height:100%}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern image-cropper{flex:1 1 auto;width:100%;height:100%;max-width:100%!important;max-height:100%!important;display:block;min-height:0}.modern-dialog-container .add-link-modern-content{flex:1;background:#fff;padding:24px!important}.modern-dialog-container .add-link-modern-content .add-link-form{display:flex;flex-direction:column;gap:10px}.modern-dialog-container .preview-actions{flex-shrink:0;padding:12px 24px;background:#f8fafc;border-top:1px solid #e2e8f0;margin:0}.modern-dialog-container .preview-actions .btn-download{border-radius:12px;font-weight:600;box-shadow:0 4px 12px var(--shadow-color)}@media (max-width: 600px){.modern-dialog-container{max-height:95vh}.modern-dialog-container .preview-content-area{padding:10px!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper video.main-preview-media{width:100%!important;max-height:55vh!important;border-radius:4px;box-shadow:none}.modern-dialog-container .preview-content-area .media-viewer-wrapper .iframe-container{height:50vh}.modern-dialog-container .preview-content-area .crop-toolbar{width:calc(100% - 20px);max-width:400px;margin-bottom:10px;padding:4px 8px;gap:4px;overflow-x:auto;justify-content:center;-webkit-overflow-scrolling:touch;scrollbar-width:none}.modern-dialog-container .preview-content-area .crop-toolbar::-webkit-scrollbar{display:none}.modern-dialog-container .preview-content-area .crop-toolbar button{flex-shrink:0;transform:scale(.85);width:40px;height:40px}.modern-dialog-container .preview-actions{padding:10px 15px;flex-direction:column-reverse;gap:8px}.modern-dialog-container .preview-actions button{width:100%;margin:0!important}}@media (max-width: 360px){.modern-dialog-container .preview-content-area .crop-toolbar{gap:2px}.modern-dialog-container .preview-content-area .crop-toolbar button{transform:scale(.75)}}.control-icon{font-size:28px;cursor:pointer}image-cropper{display:flex!important;max-width:100%!important;max-height:100%!important;height:100%;width:100%}image-cropper canvas,image-cropper img{max-width:100%!important;max-height:100%!important}.crop-large{display:flex}.crop-small{display:none}@media (max-width: 600px){.dialog-content{max-height:55vh}.crop-container{max-width:100%;aspect-ratio:auto}.crop-large{display:none}.crop-small{display:flex;justify-content:center;gap:14px}.control-icon{font-size:24px}}.stats-header{display:flex;justify-content:space-between;align-items:center;width:100%}.table-view-container{margin-top:1.5rem;background-color:var(--background-card);border-radius:var(--border-radius);border:1px solid var(--border-color);overflow:hidden;animation:fadeIn .5s ease-out}.table-header,.table-row{display:flex;align-items:center;padding:0 1rem;transition:background-color var(--transition-speed) ease}.table-header{background-color:#f8f9fa;font-weight:600;color:var(--text-color-light);font-size:.8rem;text-transform:uppercase;border-bottom:2px solid var(--border-color)}.table-row{border-bottom:1px solid var(--border-color)}.table-row:last-child{border-bottom:none}.table-row:hover{background-color:#00000005}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem}.name-col{flex:4}.size-col,.date-col{flex:2}.actions-col{flex:1;justify-content:flex-end;min-width:150px}.file-icon-small{font-size:1.5rem;color:var(--primary-color)}.file-info-text{display:flex;flex-direction:column}.file-name-table{font-weight:600;color:var(--text-color)}.file-type-table{font-size:.8rem;color:var(--text-color-light)}@media (max-width: 768px){.date-col{display:none}.name-col{flex:3}.size-col{flex:2}.actions-col{flex:2;min-width:120px}}.secondary-action-link{color:var(--primary-color);text-decoration:none;border-bottom:1px solid var(--primary-color);cursor:pointer;font-weight:500}.secondary-action-link:hover{color:var(--primary-color-dark);border-bottom-color:var(--primary-color-dark)}h2[mat-dialog-title]+mat-dialog-content.add-link-dialog-content{padding-top:20px}mat-dialog-content.add-link-dialog-content{padding-left:24px;padding-right:24px;padding-bottom:20px}.add-link-form{display:flex;flex-direction:column;gap:16px}::ng-deep .eqp-attachments-preview-dialog{--mdc-dialog-subhead-line-height: normal}::ng-deep .eqp-attachments-preview-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;background:#fff!important}:host ::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{--mdc-dialog-subhead-size: 1.25rem;--mdc-dialog-subhead-line-height: 1.5;--mdc-dialog-subhead-weight: 600;--mdc-dialog-supporting-text-size: 1rem}.empty-state{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:1.5rem 1rem;margin-top:1.5rem;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#f8f9fa;text-align:center;color:var(--text-color-light);animation:fadeIn .5s ease-out}.empty-state:before{content:\"\\1f4ed\";font-size:2.5rem;margin-bottom:1rem;opacity:.7}.secondary-action-link.disabled-link{color:#adb5bd;cursor:not-allowed;border-bottom-color:transparent}.secondary-action-link.disabled-link:hover{color:#adb5bd;border-bottom-color:transparent}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem;min-width:0;overflow:hidden}.table-cell.col-actions{flex:0 0 150px;justify-content:flex-end;overflow:visible}.compact-uploader{display:flex;align-items:center;gap:16px;padding:16px;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#fcfdff;transition:all .3s ease}.compact-uploader .compact-text{flex:1 1 auto;min-width:0;cursor:pointer}.compact-uploader .compact-text:hover .compact-title{color:var(--primary-color)}.compact-uploader .compact-title{font-weight:600;color:var(--text-color);transition:color .3s ease}.compact-uploader .compact-subtitle{font-size:.8rem;color:var(--text-color-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.compact-uploader .compact-icon mat-icon{font-size:36px;width:36px;height:36px;color:var(--primary-color)}.compact-uploader .compact-actions{display:flex;gap:8px;flex-shrink:0}.compact-uploader.dragover{background-color:#f4f8ff;border-color:var(--primary-color);box-shadow:0 0 10px var(--shadow-color)}.disabled-dropzone{opacity:.5;cursor:not-allowed!important;background-color:#f5f5f5;border-color:#d1d5db}.disabled-dropzone *{pointer-events:none}.disabled-dropzone .browse-btn,.disabled-dropzone button{cursor:not-allowed!important;background-color:#e5e7eb;color:#9ca3af;border:none}.disabled-dropzone .secondary-action-link,.disabled-dropzone a{color:#9ca3af;text-decoration:none}\n"] }]
1582
- }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.FormBuilder }, { type: i3.DomSanitizer }, { type: i4.HttpClient }, { type: EqpAttachmentService }], propDecorators: { disableAction: [{
1583
- type: Input,
1584
- args: ["disableAction"]
1585
- }], showHeader: [{
1586
- type: Input,
1587
- args: ["showHeader"]
1588
- }], attachmentsList: [{
1629
+ args: [{ selector: "eqp-attachments", standalone: false, template: "<!-- Se richiesta la gestione singola mostra il pulsante di caricamento di un singolo file -->\r\n@if(showUploadTitle() == true || chooseView() == true){\r\n<div class=\"header\">\r\n @if(showUploadTitle() == true){\r\n <h4>{{ uploadTitle() }}</h4>\r\n } @if(chooseView() == true){\r\n <mat-button-toggle-group\r\n [value]=\"viewMode\"\r\n (change)=\"setViewMode($event.value)\"\r\n aria-label=\"Modalit\u00E0 di visualizzazione\"\r\n >\r\n <mat-button-toggle value=\"card\"\r\n ><mat-icon>grid_view</mat-icon></mat-button-toggle\r\n >\r\n <mat-button-toggle value=\"table\"\r\n ><mat-icon>view_list</mat-icon></mat-button-toggle\r\n >\r\n </mat-button-toggle-group>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione singolo -->\r\n@if (multipleAttachment() != true) { @if (!singleAttachmentDragAndDrop()) { @if\r\n(!addingLinkMode()) {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addAttachmentButton\"></ng-container>\r\n</div>\r\n} @else {\r\n<div class=\"text-center\">\r\n <ng-container [ngTemplateOutlet]=\"addingLinkTemplate\"></ng-container>\r\n</div>\r\n} } @else {\r\n<input\r\n #fileInput\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n hidden\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n/>\r\n\r\n@if (allowedTypes && allowedTypes.includes(1) && (!attachmentsList ||\r\nattachmentsList.length == 0 || (attachmentsList.length > 0 &&\r\n!attachmentsList[0]))) { @if (showDropArea() == true) {\r\n<!-- FULL -->\r\n@if (layout() === 'full') {\r\n\r\n<div\r\n class=\"dropbox\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"fileInput.click()\"\r\n>\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel() }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel() }}\r\n </div>\r\n <button\r\n class=\"browse-btn\"\r\n type=\"button\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n {{ browseFilesLabel() }}\r\n </button>\r\n <div class=\"secondary-action\">\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) { @if\r\n (allowedTypes.includes(2) && allowedTypes.includes(3)) {\r\n <a\r\n class=\"secondary-action-link\"\r\n [matMenuTriggerFor]=\"isDisabled() ? null : linkMenu\"\r\n [class.disabled-link]=\"isDisabled()\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n o aggiungi da web\r\n </a>\r\n <mat-menu #linkMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"switchToAddingLinkMode()\">\r\n <mat-icon>link</mat-icon>\r\n <span>Aggiungi da link</span>\r\n </button>\r\n <button mat-menu-item (click)=\"chooseDropboxFile()\">\r\n <mat-icon>cloud_queue</mat-icon>\r\n <span>Carica da Dropbox</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (allowedTypes.includes(2)) {\r\n <a\r\n [class.disabled-link]=\"isDisabled()\"\r\n class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\"\r\n >\r\n aggiungi un link\r\n </a>\r\n } @else if (allowedTypes.includes(3)) {\r\n <a\r\n [class.disabled-link]=\"isDisabled()\"\r\n class=\"secondary-action-link\"\r\n (click)=\"$event.stopPropagation(); chooseDropboxFile()\"\r\n >\r\n carica da Dropbox\r\n </a>\r\n } }\r\n </div>\r\n</div>\r\n}@else {\r\n<div\r\n class=\"compact-uploader\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n>\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel() }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button\r\n mat-stroked-button\r\n color=\"primary\"\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n Sfoglia\r\n </button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n Link\r\n </button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n >\r\n {{ openLinkLabel() }}\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"chooseDropboxFile()\"\r\n >\r\n {{ uploadWithDropboxLabel() }}\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n} } } }\r\n\r\n<!-- Azioni singolo elemento (come prima) -->\r\n<div class=\"text-center\">\r\n @if (attachmentsList && attachmentsList.length > 0 && attachmentsList[0] &&\r\n showActionButtons() == true) {\r\n @if (!isPrimaryActionHidden(attachmentsList[0])) {\r\n <button\r\n class=\"mb-2 me-2 eqp-attachments-download-btn\"\r\n (click)=\"viewAttachment(attachmentsList[0])\"\r\n type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button\r\n color=\"primary\"\r\n >\r\n @if (attachmentsList[0].AttachmentType == AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n {{\r\n attachmentsList[0].AttachmentType == AttachmentType.FILE\r\n ? downloadLabel()\r\n : openLinkLabel()\r\n }}\r\n </button>\r\n }\r\n\r\n @if (!isPrimaryActionHidden(attachmentsList[0]) && showPreview() && (!attachmentsList[0].FileContentType ||\r\n (!attachmentsList[0].FileContentType.startsWith('video') &&\r\n !attachmentsList[0].FileContentType.startsWith('audio'))) &&\r\n attachmentsList[0].IsImage == true) {\r\n <button\r\n class=\"mb-2 me-2 eqp-attachments-preview-btn\"\r\n (click)=\"openPreviewDialog(attachmentsList[0])\"\r\n type=\"button\"\r\n [disabled]=\"isPrimaryActionDisabled(attachmentsList[0])\"\r\n mat-raised-button\r\n color=\"primary\"\r\n >\r\n <mat-icon>visibility</mat-icon> {{ previewLabel() }}\r\n </button>\r\n }\r\n\r\n <button\r\n [disabled]=\"disableAction()\"\r\n class=\"mb-2 eqp-attachments-delete-btn\"\r\n (click)=\"deleteAttachment(attachmentsList[0])\"\r\n type=\"button\"\r\n mat-raised-button\r\n [disabled]=\"isDisabled()\"\r\n >\r\n <mat-icon>delete</mat-icon> {{ deleteLabel() }}\r\n </button>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Gestione multipla -->\r\n@if (multipleAttachment() == true && showDropArea() == true) {\r\n<input\r\n #fileInput\r\n id=\"file_attachment_multi\"\r\n name=\"file_attachment_multi\"\r\n type=\"file\"\r\n hidden\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n/>\r\n\r\n@if (layout() === 'full') {\r\n<div\r\n class=\"dropbox\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"fileInput.click()\"\r\n>\r\n <div class=\"dropbox-icon\">\uD83D\uDCC1</div>\r\n <div class=\"dropbox-text\">{{ dropHereLabel() }}</div>\r\n <div class=\"dropbox-subtext\">\r\n {{ supportedFormatsLabel() }}\r\n </div>\r\n <button\r\n class=\"browse-btn\"\r\n type=\"button\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n {{ browseFilesLabel() }}\r\n </button>\r\n @if (allowedTypes.includes(2)) {\r\n <div class=\"secondary-action-link\">\r\n o\r\n <a (click)=\"$event.stopPropagation(); switchToAddingLinkMode()\"\r\n >aggiungi un link</a\r\n >\r\n </div>\r\n }\r\n</div>\r\n}@else{\r\n<div\r\n class=\"compact-uploader\"\r\n [class.dragover]=\"dragOver\"\r\n (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\"\r\n (drop)=\"dragOver = false; fileDropped($event)\"\r\n>\r\n <div class=\"compact-icon\"><mat-icon>folder_open</mat-icon></div>\r\n <div class=\"compact-text\" (click)=\"onSelectFile($event, fileInput)\">\r\n <div class=\"compact-title\">Trascina i file o seleziona dal computer</div>\r\n <div class=\"compact-subtitle\">{{ supportedFormatsLabel() }}</div>\r\n </div>\r\n <div class=\"compact-actions\">\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n color=\"primary\"\r\n (click)=\"$event.stopPropagation(); fileInput.click()\"\r\n >\r\n Sfoglia\r\n </button>\r\n @if (allowedTypes.includes(2) || allowedTypes.includes(3)) {\r\n <button\r\n mat-stroked-button\r\n [disabled]=\"isDisabled()\"\r\n [matMenuTriggerFor]=\"compactLinkMenu\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n Link\r\n </button>\r\n <mat-menu #compactLinkMenu=\"matMenu\">\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n >\r\n {{ openLinkLabel() }}\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"chooseDropboxFile()\"\r\n >\r\n {{ uploadWithDropboxLabel() }}\r\n </button>\r\n }\r\n </mat-menu>\r\n }\r\n </div>\r\n</div>\r\n} } @if (attachmentsList?.length > 0 && showSummary()) {\r\n<div class=\"upload-stats\">\r\n <div class=\"stats-info\">\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ attachmentsList?.length }}</div>\r\n <div class=\"stat-label\">{{ filesLabel() }}</div>\r\n </div>\r\n <div class=\"stat-item\">\r\n <div class=\"stat-value\">{{ totalSizeFormatted() }}</div>\r\n <div class=\"stat-label\">{{ totalSizeLabel() }}</div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress-bar\">\r\n <div class=\"progress-fill\" [style.width.%]=\"progressPercent()\"></div>\r\n </div>\r\n</div>\r\n} @else if(attachmentsList?.length == 0){\r\n<div class=\"empty-state\">{{ emptyStateLabel() }}</div>\r\n}\r\n\r\n<!-- Griglia anteprime card (vale per singolo e multiplo) -->\r\n@if (viewMode === 'card') {\r\n\r\n<div class=\"file-previews\" [ngStyle]=\"getPreviewsContainerStyle()\">\r\n @for (att of attachmentsList; track att.ID) {\r\n <div [ngClass]=\"getCardClass(att)\">\r\n <div\r\n class=\"preview-img-container\"\r\n (click)=\"!att.isUploading && handlePrimaryAction(att)\"\r\n >\r\n @if (att.IsImage || att.FileThumbnailBase64) {\r\n <img\r\n class=\"preview-img\"\r\n [src]=\"\r\n 'data:image/jpeg;base64,' +\r\n (att.FileThumbnailBase64 || att.FileDataBase64)\r\n \"\r\n [alt]=\"att.FileName\"\r\n />\r\n } @else {\r\n <div class=\"file-icon\"><i [ngClass]=\"getAttachmentIcon(att)\"></i></div>\r\n }\r\n\r\n <div class=\"preview-action-overlay\">\r\n @if (att.FileContentType?.startsWith('video/')) {\r\n <mat-icon>play_arrow</mat-icon>\r\n } @else if (att.IsImage && canBePreviewed(att)) {\r\n <mat-icon>visibility</mat-icon>\r\n } @else if (att.FileContentType === 'application/pdf' &&\r\n canBePreviewed(att)) {\r\n <mat-icon>open_in_new</mat-icon>\r\n } @else if (att.AttachmentType === AttachmentType.FILE) {\r\n <mat-icon>download</mat-icon>\r\n } @else {\r\n <mat-icon>open_in_new</mat-icon>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-info\">\r\n <div class=\"file-name\" [title]=\"att.FileName\">{{ att.FileName }}</div>\r\n </div>\r\n\r\n @if(!isDeleteHidden(att)){\r\n <button\r\n mat-icon-button\r\n class=\"remove-btn\"\r\n (click)=\"deleteAttachment(att)\"\r\n [disabled]=\"att.isUploading || isDeleteDisabled(att)\"\r\n >\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n } @if (att.isUploading) {\r\n <div class=\"upload-spinner\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n} @else if(viewMode === 'table' && attachmentsList?.length > 0) {\r\n\r\n<div class=\"table-view-container\">\r\n <div class=\"table-header\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div\r\n class=\"table-cell\"\r\n [style.flex]=\"col.styles?.flex\"\r\n [ngClass]=\"col.class\"\r\n >\r\n {{ col.display }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @for (att of attachmentsList; track att.ID) {\r\n <div class=\"table-row\">\r\n @for (col of _tableColumns; track col.key) {\r\n <div\r\n class=\"table-cell\"\r\n [style.flex]=\"col.styles?.flex\"\r\n [ngClass]=\"col.class\"\r\n >\r\n @switch (col.type) { @case ('template') {\r\n <div class=\"template-wrapper\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"col.externalTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: att }\"\r\n ></ng-container>\r\n </div>\r\n } @case ('date') {\r\n <span class=\"metadata-value\">{{\r\n att[col.key] | date : \"dd/MM/yyyy\"\r\n }}</span>\r\n } @default {\r\n <span class=\"metadata-value\">{{ att[col.key] }}</span>\r\n } }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n}\r\n\r\n<!-- Notifica toast -->\r\n<div\r\n class=\"upload-notification\"\r\n [class.show]=\"toast?.visible\"\r\n [class.success]=\"toast?.type === 'success'\"\r\n [class.error]=\"toast?.type === 'error'\"\r\n>\r\n <span>{{ toast?.text }}</span>\r\n <div class=\"notification-progress\"></div>\r\n</div>\r\n\r\n<ng-template #defaultFileTemplate let-att>\r\n <i class=\"file-icon-small\" [ngClass]=\"getAttachmentIcon(att)\"></i>\r\n <div class=\"file-info-text\">\r\n <span class=\"file-name-table\">{{ att.FileName }}</span>\r\n <span class=\"file-type-table\">{{ att.FileExtension || \"Link\" }}</span>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #defaultActionsTemplate let-att>\r\n <button\r\n mat-icon-button\r\n (click)=\"handlePrimaryAction(att)\"\r\n [matTooltip]=\"\r\n att.FileContentType?.startsWith('video/')\r\n ? 'Riproduci video'\r\n : 'Visualizza/Scarica'\r\n \"\r\n >\r\n <mat-icon>\r\n @if (att.FileContentType?.startsWith('video/')) { play_arrow } @else {\r\n {{\r\n att.AttachmentType === AttachmentType.FILE ? \"download\" : \"open_in_new\"\r\n }}\r\n }\r\n </mat-icon>\r\n </button>\r\n\r\n @if (!hiddenActions().includes('actionsMenu')) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerFor]=\"actionsMenu\"\r\n matTooltip=\"Altre opzioni\"\r\n >\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n\r\n <mat-menu #actionsMenu=\"matMenu\">\r\n @for (action of _sortedMenuActions; track action.name) { @if\r\n (!isActionHidden(action, att)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"action.fn(att)\"\r\n [disabled]=\"isActionDisabled(action, att)\"\r\n >\r\n <mat-icon [color]=\"action.icon === 'delete' ? 'warn' : undefined\">\r\n {{ action.icon }}\r\n </mat-icon>\r\n <span>{{ action.name }}</span>\r\n </button>\r\n } }\r\n </mat-menu>\r\n</ng-template>\r\n\r\n<ng-template #dialogCropImage>\r\n <div style=\"overflow-x: hidden\" [ngClass]=\"cropDialogClass()\">\r\n <!-- @if (showCropImage == true) { -->\r\n <ng-container\r\n [ngTemplateOutlet]=\"croppieTemplate\"\r\n [ngTemplateOutletContext]=\"{ form: newAttachmentForm }\"\r\n >\r\n </ng-container>\r\n <!-- } -->\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #inlinePreviewTemplate let-row=\"row\">\r\n @if (row.AttachmentType != AttachmentType.LINK && row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <img\r\n [src]=\"\r\n 'data:image/png;base64,' +\r\n (row.FileThumbnailBase64 ? row.FileThumbnailBase64 : row.FileDataBase64)\r\n \"\r\n />\r\n </div>\r\n } @else if (row.AttachmentType != AttachmentType.LINK && !row.IsImage) {\r\n <div class=\"inline-preview-container\" (click)=\"openPreviewDialog(row)\">\r\n <i [ngClass]=\"getAttachmentIcon(row)\"></i>\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #dialogPreview>\r\n <div class=\"modern-dialog-container\">\r\n @if (selectedAttachment) {\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ previewLabel() }}</span>\r\n <span class=\"file-t\">{{ selectedAttachment.FileName }}</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"media-viewer-wrapper\">\r\n @if (selectedAttachment.IsImage) {\r\n <img\r\n class=\"main-preview-media\"\r\n [src]=\"\r\n 'data:image/png;base64,' +\r\n (selectedAttachment.FileDataBase64 ||\r\n selectedAttachment.FileThumbnailBase64)\r\n \"\r\n [alt]=\"selectedAttachment.FileName\"\r\n />\r\n } @else if (selectedAttachment.FileContentType?.startsWith('video/')) {\r\n <video\r\n controls\r\n autoplay\r\n playsinline\r\n class=\"main-preview-media video-player\"\r\n >\r\n <source\r\n [src]=\"selectedAttachment.TrustedUrl\"\r\n [type]=\"selectedAttachment.FileContentType\"\r\n />\r\n Il tuo browser non supporta il video.\r\n </video>\r\n } @else {\r\n <div class=\"iframe-container\">\r\n <iframe\r\n class=\"preview-iframe-modern\"\r\n [src]=\"selectedAttachment.TrustedUrl\"\r\n [title]=\"selectedAttachment.FileName\"\r\n ></iframe>\r\n </div>\r\n }\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Chiudi</button>\r\n @if (selectedAttachment.AttachmentType !== AttachmentType.LINK) {\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"viewAttachment(selectedAttachment)\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>download</mat-icon> <span>{{ downloadLabel() }}</span>\r\n </button>\r\n }\r\n </mat-dialog-actions>\r\n }\r\n </div>\r\n</ng-template>\r\n\r\n<!-- TEMPLATE PER IL PULSANTE DI AGGIUNTA NUOVO ALLEGATO -->\r\n<ng-template #addAttachmentButton>\r\n <input\r\n #fileInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n\r\n @if (allowedTypes && allowedTypes.length == 1 && (multipleAttachment() == true\r\n || !attachmentsList || attachmentsList.length == 0 || (attachmentsList.length\r\n > 0 && !attachmentsList[0]))) {\r\n <button\r\n class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"addFile(allowedTypes[0], fileInput)\"\r\n [disabled]=\"isDisabled()\"\r\n >\r\n @if (allowedTypes[0] == 1) { <mat-icon>cloud_upload</mat-icon> } @if\r\n (allowedTypes[0] == 2) { <i class=\"fas fa-link\"></i> } @if (allowedTypes[0]\r\n == 3) { <i class=\"fa-brands fa-dropbox\"></i> }\r\n <span style=\"margin-left: 10px\">\r\n {{\r\n allowedTypes[0] == 1\r\n ? addButtonLabel() + \" file\"\r\n : allowedTypes[0] == 2\r\n ? addButtonLabel() + \" link\"\r\n : uploadWithDropboxLabel()\r\n }}\r\n </span>\r\n </button>\r\n } @if (!separatedUploadButtons() && allowedTypes && allowedTypes.length > 1 &&\r\n (multipleAttachment() == true || !attachmentsList || attachmentsList.length == 0\r\n || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <button\r\n class=\"btn btn-primary mb-4 me-5 eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n [matMenuTriggerFor]=\"attachmentTypeMenu\"\r\n [disabled]=\"isDisabled()\"\r\n >\r\n @if (multipleAttachment() != true) { <mat-icon>cloud_upload</mat-icon> } @else\r\n { <mat-icon>add</mat-icon> }\r\n <span style=\"margin-left: 0px\">{{ addButtonLabel() }}</span>\r\n </button>\r\n\r\n <mat-menu #attachmentTypeMenu=\"matMenu\">\r\n <input\r\n #imageInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n @if (allowedTypes.includes(1)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"imageInput.click()\"\r\n class=\"eqp-attachments-file-btn\"\r\n >\r\n <i class=\"fas fa-file\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n } @if (allowedTypes.includes(2)) {\r\n <button\r\n mat-menu-item\r\n [disabled]=\"isDisabled()\"\r\n (click)=\"switchToAddingLinkMode()\"\r\n class=\"eqp-attachments-link-btn\"\r\n >\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n mat-menu-item\r\n (click)=\"chooseDropboxFile()\"\r\n class=\"eqp-attachments-link-btn\"\r\n >\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </mat-menu>\r\n } @if (separatedUploadButtons() && allowedTypes && allowedTypes.length > 1 &&\r\n (multipleAttachment() == true || !attachmentsList || attachmentsList.length == 0\r\n || (attachmentsList.length > 0 && !attachmentsList[0]))) {\r\n <div class=\"btn-group\">\r\n @if (allowedTypes.includes(1)) {\r\n <button\r\n (click)=\"imageInput.click()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fa-solid fa-cloud-upload\"></i>\r\n <span style=\"margin-left: 10px\">File</span>\r\n </button>\r\n }\r\n <input\r\n #imageInput\r\n style=\"display: none\"\r\n id=\"file_attachment\"\r\n name=\"file_attachment\"\r\n type=\"file\"\r\n (change)=\"onFileAdded($event)\"\r\n [accept]=\"acceptedFileTypes\"\r\n [multiple]=\"loadMultipleFiles()\"\r\n />\r\n @if (allowedTypes.includes(2)) {\r\n <button\r\n (click)=\"switchToAddingLinkMode()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fas fa-link\"></i>\r\n <span style=\"margin-left: 10px\">Link</span>\r\n </button>\r\n } @if (allowedTypes.includes(3)) {\r\n <button\r\n (click)=\"chooseDropboxFile()\"\r\n class=\"btn btn-secondary eqp-attachments-add-btn\"\r\n mat-raised-button\r\n color=\"secondary\"\r\n type=\"button\"\r\n >\r\n <i class=\"fa-brands fa-dropbox\"></i>\r\n <span style=\"margin-left: 10px\">Dropbox</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #croppieTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">{{ cropLabel() }}</span>\r\n <span class=\"file-t\">Regola le dimensioni e l'orientamento</span>\r\n </div>\r\n </div>\r\n <button\r\n mat-icon-button\r\n type=\"button\"\r\n (click)=\"abortFile()\"\r\n class=\"close-btn\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"preview-content-area\">\r\n <div class=\"crop-toolbar\">\r\n @if (cropOptions().includes(1)) {\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"rotateLeftLabel()\"\r\n (click)=\"rotateLeft()\"\r\n >\r\n <mat-icon>rotate_left</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"rotateRightLabel()\"\r\n (click)=\"rotateRight()\"\r\n >\r\n <mat-icon>rotate_right</mat-icon>\r\n </button>\r\n } @if (cropOptions().includes(2)) {\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"flipHorinzontalLabel()\"\r\n (click)=\"flipHorizontal()\"\r\n >\r\n <mat-icon>flip_horizontal</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n [matTooltip]=\"flipVerticalLabel()\"\r\n (click)=\"flipVertical()\"\r\n >\r\n <mat-icon>flip_vertical</mat-icon>\r\n </button>\r\n }\r\n <button\r\n mat-icon-button\r\n matTooltip=\"Reset\"\r\n (click)=\"restoreOriginalDimensions()\"\r\n >\r\n <mat-icon>replay</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"media-viewer-wrapper\">\r\n <div class=\"crop-container-modern\">\r\n <image-cropper\r\n [imageFile]=\"selectedFile\"\r\n [maintainAspectRatio]=\"false\"\r\n [canvasRotation]=\"canvasRotation\"\r\n [transform]=\"transform\"\r\n format=\"png\"\r\n (imageCropped)=\"imageCropped($event)\"\r\n [resizeToWidth]=\"customWidth\"\r\n [resizeToHeight]=\"customHeight\"\r\n [output]=\"'base64'\"\r\n [containWithinAspectRatio]=\"true\"\r\n [onlyScaleDown]=\"true\"\r\n [alignImage]=\"'center'\"\r\n >\r\n </image-cropper>\r\n </div>\r\n </div>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button (click)=\"abortFile()\" class=\"btn-close\">\r\n {{ abortLabel() }}\r\n </button>\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"confirmAddAttachment()\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>check</mat-icon> {{ confirmLabel() }}\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n\r\n<!-- TEMPLATE PER FORM DI AGGIUNTA DI UN LINK -->\r\n<ng-template #addingLinkTemplate>\r\n <div class=\"modern-dialog-container\">\r\n <div mat-dialog-title class=\"preview-header\">\r\n <div class=\"header-info\">\r\n <div class=\"type-icon-wrapper\">\r\n <mat-icon>link</mat-icon>\r\n </div>\r\n <div class=\"title-group\">\r\n <span class=\"main-t\">Aggiungi un link</span>\r\n <span class=\"file-t\">Inserisci l'URL della risorsa web</span>\r\n </div>\r\n </div>\r\n <button mat-icon-button mat-dialog-close class=\"close-btn\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <mat-dialog-content class=\"add-link-modern-content\">\r\n <form [formGroup]=\"newAttachmentForm\" class=\"add-link-form\">\r\n <mat-form-field appearance=\"outline\" class=\"w-100 mt-3\">\r\n <mat-label>URL del collegamento</mat-label>\r\n <input\r\n matInput\r\n formControlName=\"filePath\"\r\n placeholder=\"https://...\"\r\n required\r\n />\r\n <mat-icon matSuffix>language</mat-icon>\r\n </mat-form-field>\r\n\r\n <mat-form-field appearance=\"outline\" class=\"w-100\">\r\n <mat-label>Titolo (opzionale)</mat-label>\r\n <input\r\n matInput\r\n formControlName=\"fileName\"\r\n placeholder=\"Es. Documento Progetto\"\r\n />\r\n <mat-icon matSuffix>title</mat-icon>\r\n </mat-form-field>\r\n </form>\r\n </mat-dialog-content>\r\n\r\n <mat-dialog-actions align=\"end\" class=\"preview-actions\">\r\n <button mat-button mat-dialog-close class=\"btn-close\">Annulla</button>\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n [mat-dialog-close]=\"newAttachmentForm.value\"\r\n [disabled]=\"newAttachmentForm.invalid\"\r\n class=\"btn-download\"\r\n >\r\n <mat-icon>add</mat-icon> Aggiungi\r\n </button>\r\n </mat-dialog-actions>\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{--primary-color: #6a5af9;--primary-color-dark: rgb(83.7807017544, 65.3947368421, 248.1052631579);--success-color: #1ce593;--error-color: #ff5b5b;--background-light: #f7f9fc;--background-card: rgba(255, 255, 255, .7);--text-color: #1e293b;--text-color-light: #64748b;--border-color: rgba(203, 213, 225, .5);--shadow-color: rgba(99, 102, 241, .2);--border-radius: 16px;--transition-speed: .3s}@keyframes fadeIn{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--primary-color)}70%{box-shadow:0 0 0 10px #6a5af900}to{box-shadow:0 0 #6a5af900}}.container{width:100%;max-width:700px;margin:2rem auto;font-family:Inter,sans-serif}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid var(--border-color)}.header h1{color:var(--text-color);font-size:1.8rem;font-weight:700;margin:0}.dropbox{width:100%;border:2px dashed var(--border-color);border-radius:var(--border-radius);padding:2.5rem;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;cursor:pointer;background-color:var(--background-card);backdrop-filter:blur(10px);transition:all var(--transition-speed) ease}.dropbox:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color);border-color:var(--primary-color)}.dropbox.dragover{border-style:solid;border-color:var(--primary-color);transform:scale(1.02);box-shadow:0 0 25px var(--shadow-color);animation:pulse 1.5s infinite}.dropbox .dropbox-icon{font-size:3.5rem;color:var(--primary-color)}.dropbox .dropbox-text{font-size:1.1rem;font-weight:600;color:var(--text-color);margin-top:1rem}.dropbox .dropbox-subtext{color:var(--text-color-light);margin-top:.5rem}.dropbox .browse-btn{margin-top:1.5rem;padding:.75rem 1.5rem;background-color:var(--primary-color);color:#fff;border:none;border-radius:10px;font-weight:600;transition:all var(--transition-speed) ease}.dropbox .browse-btn:hover{background-color:var(--primary-color-dark);transform:translateY(-2px)}.file-previews{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1.5rem;margin-top:2rem}.file-previews{display:grid;gap:16px;padding:16px;grid-template-columns:repeat(auto-fill,minmax(var(--card-min-width, 200px),1fr))}.file-preview{background-color:var(--background-card);border-radius:var(--border-radius);box-shadow:0 4px 15px #0000000d;border:1px solid var(--border-color);overflow:hidden;display:flex;flex-direction:column;position:relative;opacity:0;animation:fadeIn .5s ease-out forwards;transition:transform var(--transition-speed) ease,box-shadow var(--transition-speed) ease}.file-preview.uploading{cursor:wait}.file-preview.uploading .preview-img-container:after{content:\"\";position:absolute;inset:0;background:#ffffffb3;backdrop-filter:blur(5px);pointer-events:none}.file-preview .preview-action-overlay{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;background-color:#0006;color:#fff;opacity:1;transition:opacity .3s ease}.file-preview .preview-action-overlay .mat-icon{font-size:36px;width:36px;height:36px}.file-preview .remove-btn{position:absolute;top:8px;right:8px;z-index:2;background-color:#0000004d;color:#fff;width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;transition:all var(--transition-speed) ease}.file-preview .remove-btn:hover{background-color:#ff5b5b}.file-preview .remove-btn .mat-icon{font-size:18px}@media(hover:hover){.file-preview .remove-btn .file-preview .preview-action-overlay{opacity:0}.file-preview .remove-btn .file-preview:hover .preview-action-overlay,.file-preview .remove-btn .file-preview:hover .remove-btn{opacity:1}.file-preview .remove-btn .file-preview .remove-btn{opacity:0}}@media(hover:hover)and (min-width:769px){.file-preview .remove-btn{opacity:0;transform:scale(.8)}.file-preview:hover{transform:translateY(-5px);box-shadow:0 10px 25px var(--shadow-color)}.file-preview:hover .remove-btn{opacity:1;transform:scale(1)}}.file-preview .preview-img-container{aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;background-color:#f0f2f5}.file-preview .preview-img{width:100%;height:100%;object-fit:cover}.file-preview .file-icon{font-size:4rem;color:var(--primary-color)}.file-preview .file-info{padding:12px;border-top:1px solid var(--border-color);flex-grow:1;display:flex;align-items:center}.file-preview .file-name{font-weight:600;font-size:.9rem;color:var(--text-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-preview .upload-spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;border:4px solid rgba(0,0,0,.1);border-left-color:var(--primary-color);border-radius:50%;animation:spin 1s linear infinite;pointer-events:none}.file-preview.card-small{width:140px}.file-preview.card-small .preview-img-container{height:80px}.file-preview.card-small .file-info{padding:8px}.file-preview.card-small .file-name{font-size:.8rem}.file-preview.card-small .file-icon{font-size:3rem}.file-preview.card-small .remove-btn{width:28px;height:28px}.file-preview.card-small .remove-btn .mat-icon{font-size:16px}.file-preview.card-large{width:280px}.file-preview.card-large .preview-img-container{height:180px}.file-preview.card-large .file-info{padding:16px}.file-preview.card-large .file-name{font-size:1rem}.file-preview.card-large .file-icon{font-size:5rem}.file-preview.card-large .remove-btn{width:36px;height:36px}.file-preview.card-large .remove-btn .mat-icon{font-size:20px}.file-preview[style*=--eqp-card-width]{width:var(--eqp-card-width)}.file-preview[style*=--eqp-card-width] .preview-img-container{height:calc(var(--eqp-card-width) * .65)}@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}.upload-stats{background-color:var(--background-card);backdrop-filter:blur(10px);border:1px solid var(--border-color);border-radius:var(--border-radius);padding:1.5rem;margin-top:2rem;animation:fadeIn .5s ease-out}.upload-stats .stats-info{display:flex;justify-content:space-around}.upload-stats .progress-bar{height:10px;background-color:var(--border-color);border-radius:5px;overflow:hidden;margin-top:1rem}.upload-stats .progress-fill{height:100%;background:linear-gradient(90deg,var(--primary-color),var(--success-color));transition:width var(--transition-speed) ease-out;border-radius:5px}.upload-notification{position:fixed;bottom:20px;left:50%;transform:translate(-50%,100px);padding:1rem 1.5rem;border-radius:var(--border-radius);color:#fff;font-weight:600;box-shadow:0 10px 30px #0003;transition:transform var(--transition-speed) cubic-bezier(.175,.885,.32,1.275)}.upload-notification.show{transform:translate(-50%)}.upload-notification.success{background-color:var(--success-color)}.upload-notification.error{background-color:var(--error-color)}::ng-deep .cdk-overlay-pane.eqp-crop-dialog{transform:translateY(-4vh)}@media(max-width:600px){::ng-deep .cdk-overlay-pane.crop-dialog{width:auto!important}}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container .mdc-dialog__surface{border-radius:20px!important;padding:0!important;overflow:hidden!important;width:fit-content!important;min-width:350px!important;max-width:95vw!important;margin:0 auto;background-color:#fff!important}::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;display:flex;flex-direction:column}.modern-dialog-container{display:flex;flex-direction:column;width:100%;max-width:100%;height:100%;max-height:90vh;background:#fff;--preview-header-h: 66px;--preview-footer-h: 66px;--preview-padding-y: 30px}.modern-dialog-container .main-preview-media{display:block;max-width:100%;max-height:var(--media-max-h);width:auto;height:auto;object-fit:contain;border-radius:12px;background:#fff;padding:4px;box-shadow:0 10px 30px #00000014}.modern-dialog-container video.main-preview-media{width:min(100%,1100px);background:#000}.modern-dialog-container .iframe-container{width:min(100%,1100px);height:var(--media-max-h);display:flex;width:100%;max-width:1100px}.modern-dialog-container .preview-iframe-modern{width:100%;height:100%;border:0;border-radius:12px;background:#f8fafc}.modern-dialog-container .preview-header{flex:0 0 auto;flex-shrink:0;padding:14px 20px;display:flex;align-items:center;justify-content:flex-start;border-bottom:1px solid var(--border-color);background:#f8fafc;z-index:10;width:100%}.modern-dialog-container .preview-header .header-info{display:flex;align-items:center;justify-content:flex-start;gap:12px;flex:1 1 auto;min-width:0;text-align:left}.modern-dialog-container .preview-header .header-info .type-icon-wrapper{background:var(--primary-color);color:#fff;width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 10px var(--shadow-color)}.modern-dialog-container .preview-header .header-info .title-group{display:flex;flex-direction:column;align-items:flex-start;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .main-t{font-weight:800;color:var(--text-color);font-size:.95rem;line-height:1.2;text-align:left}.modern-dialog-container .preview-header .header-info .title-group .file-t{font-size:.75rem;color:var(--text-color-light);max-width:250px;overflow:hidden;text-overflow:ellipsis;text-align:left}.modern-dialog-container .preview-content-area{flex:1;background:#fff!important;display:flex;flex-direction:column;padding:15px 15px 22px!important;overflow:hidden!important;min-height:0;width:auto;--media-max-h: calc(90vh - var(--preview-header-h) - var(--preview-footer-h) - var(--preview-padding-y));width:100%}.modern-dialog-container .preview-content-area .crop-toolbar{flex-shrink:0;z-index:20;background:#0f172a14;backdrop-filter:blur(10px);padding:6px 16px;border-radius:30px;margin:0 auto 15px;display:flex;gap:8px;box-shadow:0 4px 12px #0000000d}.modern-dialog-container .preview-content-area .crop-toolbar button{color:var(--text-color)!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper{flex:1;width:100%;display:flex;justify-content:center;align-items:center;min-height:0;overflow:visible}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background:transparent;border-radius:12px;padding:0}.modern-dialog-container .preview-content-area .media-viewer-wrapper .crop-container-modern image-cropper{max-width:100%;max-height:100%;display:block}.modern-dialog-container .add-link-modern-content{flex:1;background:#fff;padding:24px!important}.modern-dialog-container .add-link-modern-content .add-link-form{display:flex;flex-direction:column;gap:10px}.modern-dialog-container .preview-actions{flex-shrink:0;padding:12px 24px;background:#f8fafc;border-top:1px solid #e2e8f0;margin:0}.modern-dialog-container .preview-actions .btn-download{border-radius:12px;font-weight:600;box-shadow:0 4px 12px var(--shadow-color)}@media(max-width:600px){.modern-dialog-container{max-height:95vh}.modern-dialog-container .preview-content-area{padding:10px!important}.modern-dialog-container .preview-content-area .media-viewer-wrapper video.main-preview-media{width:100%!important;max-height:55vh!important;border-radius:4px;box-shadow:none}.modern-dialog-container .preview-content-area .media-viewer-wrapper .iframe-container{height:50vh}.modern-dialog-container .preview-content-area .crop-toolbar{width:calc(100% - 20px);max-width:400px;margin-bottom:10px;padding:4px 8px;gap:4px;overflow-x:auto;justify-content:center;-webkit-overflow-scrolling:touch}.modern-dialog-container .preview-content-area .crop-toolbar::-webkit-scrollbar{display:none}.modern-dialog-container .preview-content-area .crop-toolbar{scrollbar-width:none}.modern-dialog-container .preview-content-area .crop-toolbar button{flex-shrink:0;transform:scale(.85);width:40px;height:40px}.modern-dialog-container .preview-actions{padding:10px 15px;flex-direction:column-reverse;gap:8px}.modern-dialog-container .preview-actions button{width:100%;margin:0!important}}@media(max-width:360px){.modern-dialog-container .preview-content-area .crop-toolbar{gap:2px}.modern-dialog-container .preview-content-area .crop-toolbar button{transform:scale(.75)}}.control-icon{font-size:28px;cursor:pointer}image-cropper,image-cropper canvas,image-cropper img{max-width:100%!important;max-height:100%!important}.crop-large{display:flex}.crop-small{display:none}@media(max-width:600px){.dialog-content{max-height:55vh}.crop-container{max-width:100%;aspect-ratio:auto}.crop-large{display:none}.crop-small{display:flex;justify-content:center;gap:14px}.control-icon{font-size:24px}}.stats-header{display:flex;justify-content:space-between;align-items:center;width:100%}.table-view-container{margin-top:1.5rem;background-color:var(--background-card);border-radius:var(--border-radius);border:1px solid var(--border-color);overflow:hidden;animation:fadeIn .5s ease-out}.table-header,.table-row{display:flex;align-items:center;padding:0 1rem;transition:background-color var(--transition-speed) ease}.table-header{background-color:#f8f9fa;font-weight:600;color:var(--text-color-light);font-size:.8rem;text-transform:uppercase;border-bottom:2px solid var(--border-color)}.table-row{border-bottom:1px solid var(--border-color)}.table-row:last-child{border-bottom:none}.table-row:hover{background-color:#00000005}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem}.name-col{flex:4}.size-col,.date-col{flex:2}.actions-col{flex:1;justify-content:flex-end;min-width:150px}.file-icon-small{font-size:1.5rem;color:var(--primary-color)}.file-info-text{display:flex;flex-direction:column}.file-name-table{font-weight:600;color:var(--text-color)}.file-type-table{font-size:.8rem;color:var(--text-color-light)}@media(max-width:768px){.date-col{display:none}.name-col{flex:3}.size-col{flex:2}.actions-col{flex:2;min-width:120px}}.secondary-action-link{color:var(--primary-color);text-decoration:none;border-bottom:1px solid var(--primary-color);cursor:pointer;font-weight:500}.secondary-action-link:hover{color:var(--primary-color-dark);border-bottom-color:var(--primary-color-dark)}h2[mat-dialog-title]+mat-dialog-content.add-link-dialog-content{padding-top:20px}mat-dialog-content.add-link-dialog-content{padding-left:24px;padding-right:24px;padding-bottom:20px}.add-link-form{display:flex;flex-direction:column;gap:16px}::ng-deep .eqp-attachments-preview-dialog{--mat-dialog-subhead-line-height: normal}::ng-deep .eqp-attachments-preview-dialog .mat-mdc-dialog-content{padding:0!important;margin:0!important;max-height:none!important;background:#fff!important}:host ::ng-deep .eqp-attachments-dialog .mat-mdc-dialog-container{--mat-dialog-subhead-size: 1.25rem;--mat-dialog-subhead-line-height: 1.5;--mat-dialog-subhead-weight: 600;--mat-dialog-supporting-text-size: 1rem}.empty-state{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:1.5rem 1rem;margin-top:1.5rem;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#f8f9fa;text-align:center;color:var(--text-color-light);animation:fadeIn .5s ease-out}.empty-state:before{content:\"\\1f4ed\";font-size:2.5rem;margin-bottom:1rem;opacity:.7}.secondary-action-link.disabled-link{color:#adb5bd;cursor:not-allowed;border-bottom-color:transparent}.secondary-action-link.disabled-link:hover{color:#adb5bd;border-bottom-color:transparent}.table-cell{padding:1rem .5rem;display:flex;align-items:center;gap:1rem;min-width:0;overflow:hidden}.table-cell.col-actions{flex:0 0 150px;justify-content:flex-end;overflow:visible}.compact-uploader{display:flex;align-items:center;gap:16px;padding:16px;border:2px dashed var(--border-color);border-radius:var(--border-radius);background-color:#fcfdff;transition:all .3s ease}.compact-uploader .compact-text{flex:1 1 auto;min-width:0;cursor:pointer}.compact-uploader .compact-text:hover .compact-title{color:var(--primary-color)}.compact-uploader .compact-title{font-weight:600;color:var(--text-color);transition:color .3s ease}.compact-uploader .compact-subtitle{font-size:.8rem;color:var(--text-color-light);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.compact-uploader .compact-icon mat-icon{font-size:36px;width:36px;height:36px;color:var(--primary-color)}.compact-uploader .compact-actions{display:flex;gap:8px;flex-shrink:0}.compact-uploader.dragover{background-color:#f4f8ff;border-color:var(--primary-color);box-shadow:0 0 10px var(--shadow-color)}\n"] }]
1630
+ }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.FormBuilder }, { type: i3.DomSanitizer }, { type: i4.HttpClient }, { type: EqpAttachmentService }], propDecorators: { disableAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableAction", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], attachmentsList: [{
1589
1631
  type: Input,
1590
1632
  args: ["attachmentsList"]
1591
- }], singleAttachment: [{
1592
- type: Input,
1593
- args: ["singleAttachment"]
1594
- }], showMatCard: [{
1595
- type: Input,
1596
- args: ["showMatCard"]
1597
- }], multipleAttachment: [{
1598
- type: Input,
1599
- args: ["multipleAttachment"]
1600
- }], loadMultipleFiles: [{
1601
- type: Input,
1602
- args: ["loadMultipleFiles"]
1603
- }], emptyTableMessage: [{
1604
- type: Input,
1605
- args: ["emptyTableMessage"]
1606
- }], allowOnlyImages: [{
1607
- type: Input,
1608
- args: ["allowOnlyImages"]
1609
- }], acceptedFileTypes: [{
1633
+ }], singleAttachment: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleAttachment", required: false }] }], showMatCard: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMatCard", required: false }] }], multipleAttachment: [{ type: i0.Input, args: [{ isSignal: true, alias: "multipleAttachment", required: false }] }], loadMultipleFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadMultipleFiles", required: false }] }], emptyTableMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyTableMessage", required: false }] }], allowOnlyImages: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowOnlyImages", required: false }] }], acceptedFileTypes: [{
1610
1634
  type: Input,
1611
1635
  args: ["acceptedFileTypes"]
1612
- }], isDisabled: [{
1613
- type: Input,
1614
- args: ["isDisabled"]
1615
- }], showInlinePreview: [{
1616
- type: Input,
1617
- args: ["showInlinePreview"]
1618
- }], getAttachmentEndpoint: [{
1619
- type: Input,
1620
- args: ["getAttachmentEndpoint"]
1621
- }], productionBaseUrl: [{
1622
- type: Input,
1623
- args: ["productionBaseUrl"]
1624
- }], compressionOptions: [{
1625
- type: Input,
1626
- args: ["compressionOptions"]
1627
- }], allowedTypes: [{
1636
+ }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], showInlinePreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInlinePreview", required: false }] }], getAttachmentEndpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "getAttachmentEndpoint", required: false }] }], productionBaseUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "productionBaseUrl", required: false }] }], compressionOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "compressionOptions", required: false }] }], allowedTypes: [{
1628
1637
  type: Input,
1629
1638
  args: ["allowedTypes"]
1630
- }], isEqpTableMultiLanguage: [{
1631
- type: Input,
1632
- args: ["isEqpTableMultiLanguage"]
1633
- }], tablePaginatorVisible: [{
1634
- type: Input,
1635
- args: ["tablePaginatorVisible"]
1636
- }], isTableSearcheable: [{
1637
- type: Input,
1638
- args: ["isTableSearcheable"]
1639
- }], tablePaginatorSize: [{
1640
- type: Input,
1641
- args: ["tablePaginatorSize"]
1642
- }], separatedUploadButtons: [{
1643
- type: Input,
1644
- args: ["separatedUploadButtons"]
1645
- }], showPreview: [{
1646
- type: Input,
1647
- args: ["showPreview"]
1648
- }], singleAttachmentDragAndDrop: [{
1649
- type: Input,
1650
- args: ["singleAttachmentDragAndDrop"]
1651
- }], cropOptions: [{
1652
- type: Input,
1653
- args: ["cropOptions"]
1654
- }], cropDialogClass: [{
1655
- type: Input,
1656
- args: ["cropDialogClass"]
1657
- }], maxFileSizeMB: [{
1658
- type: Input
1659
- }], cardSize: [{
1660
- type: Input
1661
- }], customCardWidthPx: [{
1662
- type: Input
1663
- }], customCardHeightPx: [{
1664
- type: Input
1665
- }], layout: [{
1666
- type: Input
1667
- }], openLinkLabel: [{
1668
- type: Input,
1669
- args: ["openLinkLabel"]
1670
- }], addButtonLabel: [{
1671
- type: Input,
1672
- args: ["addButtonLabel"]
1673
- }], downloadLabel: [{
1674
- type: Input,
1675
- args: ["downloadLabel"]
1676
- }], deleteLabel: [{
1677
- type: Input,
1678
- args: ["deleteLabel"]
1679
- }], fileNameLabel: [{
1680
- type: Input,
1681
- args: ["fileNameLabel"]
1682
- }], previewLabel: [{
1683
- type: Input,
1684
- args: ["previewLabel"]
1685
- }], uploadFileLabel: [{
1686
- type: Input,
1687
- args: ["uploadFileLabel"]
1688
- }], confirmLabel: [{
1689
- type: Input,
1690
- args: ["confirmLabel"]
1691
- }], abortLabel: [{
1692
- type: Input,
1693
- args: ["abortLabel"]
1694
- }], saveLabel: [{
1695
- type: Input,
1696
- args: ["saveLabel"]
1697
- }], exitLabel: [{
1698
- type: Input,
1699
- args: ["exitLabel"]
1700
- }], uploadWithDropboxLabel: [{
1701
- type: Input,
1702
- args: ["uploadWithDropboxLabel"]
1703
- }], cropLabel: [{
1704
- type: Input,
1705
- args: ["cropLabel"]
1706
- }], deleteDialogTitle: [{
1707
- type: Input,
1708
- args: ["deleteDialogTitle"]
1709
- }], deleteDialogMessage: [{
1710
- type: Input,
1711
- args: ["deleteDialogMessage"]
1712
- }], noImageSelectedErrorMessage: [{
1713
- type: Input,
1714
- args: ["noImageSelectedErrorMessage"]
1715
- }], wrongTypeSelectedErrorMessage: [{
1716
- type: Input,
1717
- args: ["wrongTypeSelectedErrorMessage"]
1718
- }], videoPreviewErrorMessage: [{
1719
- type: Input,
1720
- args: ["videoPreviewErrorMessage"]
1721
- }], audioPreviewErrorMessage: [{
1722
- type: Input,
1723
- args: ["videoPreviewErrorMessage"]
1724
- }], flipHorinzontalLabel: [{
1725
- type: Input,
1726
- args: ["flipHorinzontalLabel"]
1727
- }], flipVerticalLabel: [{
1728
- type: Input,
1729
- args: ["flipVerticalLabel"]
1730
- }], rotateRightLabel: [{
1731
- type: Input,
1732
- args: ["rotateRightLabel"]
1733
- }], rotateLeftLabel: [{
1734
- type: Input,
1735
- args: ["rotateLeftLabel"]
1736
- }], base64LimitMB: [{
1737
- type: Input,
1738
- args: ["base64LimitMB"]
1739
- }], uploadTitle: [{
1740
- type: Input
1741
- }], uploadSubtitle: [{
1742
- type: Input
1743
- }], dropHereLabel: [{
1744
- type: Input
1745
- }], supportedFormatsLabel: [{
1746
- type: Input
1747
- }], browseFilesLabel: [{
1748
- type: Input
1749
- }], uploadSummaryLabel: [{
1750
- type: Input
1751
- }], filesLabel: [{
1752
- type: Input
1753
- }], totalSizeLabel: [{
1754
- type: Input
1755
- }], emptyStateLabel: [{
1756
- type: Input
1757
- }], addedSuccessfullyLabel: [{
1758
- type: Input
1759
- }], removedLabel: [{
1760
- type: Input
1761
- }], chooseView: [{
1762
- type: Input
1763
- }], showSummary: [{
1764
- type: Input
1765
- }], viewMode: [{
1639
+ }], isEqpTableMultiLanguage: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEqpTableMultiLanguage", required: false }] }], tablePaginatorVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "tablePaginatorVisible", required: false }] }], isTableSearcheable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTableSearcheable", required: false }] }], tablePaginatorSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "tablePaginatorSize", required: false }] }], separatedUploadButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatedUploadButtons", required: false }] }], showPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPreview", required: false }] }], singleAttachmentDragAndDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleAttachmentDragAndDrop", required: false }] }], cropOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropOptions", required: false }] }], cropDialogClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropDialogClass", required: false }] }], maxFileSizeMB: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSizeMB", required: false }] }], cardSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "cardSize", required: false }] }], customCardWidthPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "customCardWidthPx", required: false }] }], customCardHeightPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "customCardHeightPx", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], openLinkLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "openLinkLabel", required: false }] }], addButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addButtonLabel", required: false }] }], downloadLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadLabel", required: false }] }], deleteLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteLabel", required: false }] }], fileNameLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileNameLabel", required: false }] }], previewLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewLabel", required: false }] }], uploadFileLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadFileLabel", required: false }] }], confirmLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmLabel", required: false }] }], abortLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "abortLabel", required: false }] }], saveLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "saveLabel", required: false }] }], exitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "exitLabel", required: false }] }], uploadWithDropboxLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadWithDropboxLabel", required: false }] }], cropLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropLabel", required: false }] }], deleteDialogTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteDialogTitle", required: false }] }], deleteDialogMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteDialogMessage", required: false }] }], noImageSelectedErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noImageSelectedErrorMessage", required: false }] }], wrongTypeSelectedErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrongTypeSelectedErrorMessage", required: false }] }], videoPreviewErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "videoPreviewErrorMessage", required: false }] }], audioPreviewErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "videoPreviewErrorMessage", required: false }] }], flipHorinzontalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "flipHorinzontalLabel", required: false }] }], flipVerticalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "flipVerticalLabel", required: false }] }], rotateRightLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotateRightLabel", required: false }] }], rotateLeftLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotateLeftLabel", required: false }] }], base64LimitMB: [{ type: i0.Input, args: [{ isSignal: true, alias: "base64LimitMB", required: false }] }], uploadTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadTitle", required: false }] }], uploadSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadSubtitle", required: false }] }], dropHereLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropHereLabel", required: false }] }], supportedFormatsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "supportedFormatsLabel", required: false }] }], browseFilesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "browseFilesLabel", required: false }] }], uploadSummaryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadSummaryLabel", required: false }] }], filesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filesLabel", required: false }] }], totalSizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalSizeLabel", required: false }] }], emptyStateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyStateLabel", required: false }] }], addedSuccessfullyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addedSuccessfullyLabel", required: false }] }], removedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removedLabel", required: false }] }], chooseView: [{ type: i0.Input, args: [{ isSignal: true, alias: "chooseView", required: false }] }], showSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSummary", required: false }] }], viewMode: [{
1766
1640
  type: Input,
1767
1641
  args: ["viewMode"]
1768
- }], showUploadTitle: [{
1769
- type: Input,
1770
- args: ["showUploadTitle"]
1771
- }], showDropArea: [{
1772
- type: Input,
1773
- args: ["showDropArea"]
1774
- }], hiddenColumns: [{
1775
- type: Input
1776
- }], hiddenActions: [{
1777
- type: Input
1778
- }], showActionButtons: [{
1779
- type: Input
1780
- }], enableImageCrop: [{
1781
- type: Input,
1782
- args: ["enableImageCrop"]
1783
- }], actionHiddenFn: [{
1784
- type: Input
1785
- }], actionDisabledFn: [{
1786
- type: Input
1787
- }], videoCompression: [{
1788
- type: Input
1789
- }], customMenuActions: [{
1790
- type: Input
1791
- }], customColumns: [{
1792
- type: Input
1793
- }], localEditedAttachments: [{
1794
- type: Output
1795
- }], abortAddAttachment: [{
1796
- type: Output
1797
- }], downloadAttachment: [{
1798
- type: Output,
1799
- args: ["downloadAttachment"]
1800
- }], onDeleteAttachment: [{
1801
- type: Output,
1802
- args: ["onDeleteAttachment"]
1803
- }], dialogAddAttachment: [{
1804
- type: ViewChild,
1805
- args: ["dialogAddAttachment", { static: true }]
1806
- }], dialogAddMultipleAttachment: [{
1807
- type: ViewChild,
1808
- args: ["dialogAddMultipleAttachment", { static: true }]
1809
- }], dialogCropImage: [{
1810
- type: ViewChild,
1811
- args: ["dialogCropImage", { static: true }]
1812
- }], addingLinkTemplate: [{
1813
- type: ViewChild,
1814
- args: ['addingLinkTemplate']
1815
- }], imageCropper: [{
1816
- type: ViewChild,
1817
- args: [ImageCropperComponent]
1818
- }], imageInput: [{
1819
- type: ViewChild,
1820
- args: ["imageInput"]
1821
- }], inlinePreviewTemplate: [{
1822
- type: ViewChild,
1823
- args: ["inlinePreviewTemplate", { static: true }]
1824
- }], dialogPreview: [{
1825
- type: ViewChild,
1826
- args: ["dialogPreview", { static: true }]
1827
- }], defaultFileTemplate: [{
1828
- type: ViewChild,
1829
- args: ['defaultFileTemplate', { static: true }]
1830
- }], defaultActionsTemplate: [{
1831
- type: ViewChild,
1832
- args: ['defaultActionsTemplate', { static: true }]
1833
- }] } });
1642
+ }], showUploadTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUploadTitle", required: false }] }], showDropArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropArea", required: false }] }], hiddenColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenColumns", required: false }] }], hiddenActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenActions", required: false }] }], showActionButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActionButtons", required: false }] }], enableImageCrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableImageCrop", required: false }] }], actionHiddenFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionHiddenFn", required: false }] }], actionDisabledFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionDisabledFn", required: false }] }], videoCompression: [{ type: i0.Input, args: [{ isSignal: true, alias: "videoCompression", required: false }] }], customMenuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "customMenuActions", required: false }] }], customColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "customColumns", required: false }] }], localEditedAttachments: [{ type: i0.Output, args: ["localEditedAttachments"] }], abortAddAttachment: [{ type: i0.Output, args: ["abortAddAttachment"] }], downloadAttachment: [{ type: i0.Output, args: ["downloadAttachment"] }], onDeleteAttachment: [{ type: i0.Output, args: ["onDeleteAttachment"] }], dialogAddAttachment: [{ type: i0.ViewChild, args: ["dialogAddAttachment", { isSignal: true }] }], dialogAddMultipleAttachment: [{ type: i0.ViewChild, args: ["dialogAddMultipleAttachment", { isSignal: true }] }], dialogCropImage: [{ type: i0.ViewChild, args: ["dialogCropImage", { isSignal: true }] }], addingLinkTemplate: [{ type: i0.ViewChild, args: ["addingLinkTemplate", { isSignal: true }] }], imageCropper: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ImageCropperComponent), { isSignal: true }] }], imageInput: [{ type: i0.ViewChild, args: ["imageInput", { isSignal: true }] }], inlinePreviewTemplate: [{ type: i0.ViewChild, args: ["inlinePreviewTemplate", { isSignal: true }] }], dialogPreview: [{ type: i0.ViewChild, args: ["dialogPreview", { isSignal: true }] }], defaultFileTemplate: [{ type: i0.ViewChild, args: ["defaultFileTemplate", { isSignal: true }] }], defaultActionsTemplate: [{ type: i0.ViewChild, args: ["defaultActionsTemplate", { isSignal: true }] }] } });
1834
1643
 
1835
1644
  class MaterialModule {
1836
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1837
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: MaterialModule, imports: [MatCheckboxModule,
1645
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1646
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.5", ngImport: i0, type: MaterialModule, imports: [MatCheckboxModule,
1838
1647
  MatButtonModule,
1839
1648
  MatInputModule,
1840
1649
  MatAutocompleteModule,
@@ -1895,7 +1704,7 @@ class MaterialModule {
1895
1704
  MatTableModule,
1896
1705
  MatSortModule,
1897
1706
  MatPaginatorModule] });
1898
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MaterialModule, imports: [MatCheckboxModule,
1707
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MaterialModule, imports: [MatCheckboxModule,
1899
1708
  MatButtonModule,
1900
1709
  MatInputModule,
1901
1710
  MatAutocompleteModule,
@@ -1957,7 +1766,7 @@ class MaterialModule {
1957
1766
  MatSortModule,
1958
1767
  MatPaginatorModule] });
1959
1768
  }
1960
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MaterialModule, decorators: [{
1769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MaterialModule, decorators: [{
1961
1770
  type: NgModule,
1962
1771
  args: [{
1963
1772
  imports: [
@@ -2030,19 +1839,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2030
1839
  }] });
2031
1840
 
2032
1841
  class EqpAttachmentsModule {
2033
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2034
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsModule, declarations: [EqpAttachmentsComponent], imports: [MaterialModule,
1842
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1843
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsModule, declarations: [EqpAttachmentsComponent], imports: [MaterialModule,
2035
1844
  FormsModule,
2036
1845
  CommonModule,
2037
1846
  ReactiveFormsModule,
2038
1847
  ImageCropperComponent], exports: [EqpAttachmentsComponent] });
2039
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsModule, imports: [MaterialModule,
1848
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsModule, imports: [MaterialModule,
2040
1849
  FormsModule,
2041
1850
  CommonModule,
2042
1851
  ReactiveFormsModule,
2043
1852
  ImageCropperComponent] });
2044
1853
  }
2045
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsModule, decorators: [{
1854
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: EqpAttachmentsModule, decorators: [{
2046
1855
  type: NgModule,
2047
1856
  args: [{
2048
1857
  declarations: [EqpAttachmentsComponent],