@eqproject/eqp-attachments 3.1.9 → 3.1.11

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.
@@ -444,12 +444,17 @@ class EqpAttachmentsComponent {
444
444
  * Se FALSE carica l'immagine direttamente (applicando comunque la compressione se attiva).
445
445
  */
446
446
  enableImageCrop = true;
447
- videoCompression = { enabled: false, maxWidth: 1280, bitrate: 2500000 };
447
+ /**
448
+ * Hook globale: decide se nascondere un’azione per quello specifico allegato.
449
+ */
450
+ actionHiddenFn;
451
+ /**
452
+ * Hook globale: decide se disabilitare un’azione per quello specifico allegato.
453
+ */
454
+ actionDisabledFn;
455
+ videoCompression = { enabled: false, maxWidth: 1280, crf: 23, preset: 'veryfast', maxFps: 30, audioBitrate: 128000 };
448
456
  _customMenuActions = [];
449
457
  _sortedMenuActions = [];
450
- /**
451
- * SOLO quando [customMenuActions]="..." cambia.
452
- */
453
458
  set customMenuActions(value) {
454
459
  this._customMenuActions = value || [];
455
460
  this.setupMenuActions();
@@ -1012,16 +1017,29 @@ class EqpAttachmentsComponent {
1012
1017
  const isVideo = currentFile.type.startsWith('video');
1013
1018
  if (isVideo) {
1014
1019
  let finalFile = currentFile;
1015
- // Miniatura del video
1020
+ // 1. Genera la miniatura (rimane lato client perché è un'operazione istantanea)
1016
1021
  newAttachment.FileThumbnailBase64 = await this.generateVideoThumbnail(currentFile);
1017
- // Se la compressione è abilitata, elaboriamo il video
1022
+ // 2. Se la compressione è abilitata, inviamo il file all'API C#
1018
1023
  if (this.videoCompression.enabled) {
1019
- // this.showToast("Compressione video in corso...", "info");
1020
- finalFile = await this.compressVideoNative(currentFile, this.videoCompression);
1021
- // Aggiorniamo i dati dell'allegato con il nuovo file compresso
1022
- newAttachment.FileName = currentFile.name.replace(/\.[^/.]+$/, "") + ".webm";
1023
- newAttachment.FileContentType = "video/webm";
1024
+ this.showToast("Compressione video in corso... L'operazione potrebbe richiedere alcuni minuti.", "info");
1025
+ try {
1026
+ // Chiamata al microservizio C# (metodo ristrutturato precedentemente)
1027
+ const compressedBlob = await this.compressVideoApi(currentFile, this.videoCompression);
1028
+ // Creiamo il nuovo nome file con estensione .mp4
1029
+ const newFileName = currentFile.name.replace(/\.[^/.]+$/, "") + ".mp4";
1030
+ // Trasformiamo il Blob ricevuto in un File per mantenere la coerenza nell'oggetto DTO
1031
+ finalFile = new File([compressedBlob], newFileName, { type: "video/mp4" });
1032
+ // Aggiorniamo i metadati dell'allegato
1033
+ newAttachment.FileName = newFileName;
1034
+ newAttachment.FileContentType = "video/mp4";
1035
+ }
1036
+ catch (error) {
1037
+ EqpAttachmentDialogService.Error("Errore durante la compressione remota del video. Verrà caricato il file originale.");
1038
+ console.error("Video API Error:", error);
1039
+ // In caso di errore dell'API, finalFile rimane il currentFile originale
1040
+ }
1024
1041
  }
1042
+ // Impostiamo il file (compresso o originale) come LargeFile
1025
1043
  newAttachment.LargeFile = finalFile;
1026
1044
  newAttachment.IsLargeFile = true;
1027
1045
  return newAttachment;
@@ -1379,10 +1397,25 @@ class EqpAttachmentsComponent {
1379
1397
  isActionHidden(action, att) {
1380
1398
  if (this.hiddenActions?.includes(action.key))
1381
1399
  return true;
1400
+ if (this.actionHiddenFn?.(action.key, att))
1401
+ return true;
1382
1402
  if (typeof action.hidden === 'function')
1383
1403
  return !!action.hidden(att);
1384
1404
  return !!action.hidden;
1385
1405
  }
1406
+ isActionDisabled(action, att) {
1407
+ if (this.actionDisabledFn?.(action.key, att))
1408
+ return true;
1409
+ if (typeof action.disabled === 'function')
1410
+ return !!action.disabled(att);
1411
+ return !!action.disabled;
1412
+ }
1413
+ isDeleteHidden(att) {
1414
+ return this.actionHiddenFn?.('delete', att) || this.hiddenActions?.includes('delete');
1415
+ }
1416
+ isDeleteDisabled(att) {
1417
+ return this.disableAction || !!this.actionDisabledFn?.('delete', att);
1418
+ }
1386
1419
  /**
1387
1420
  * Unisce le colonne di default con quelle custom e le ordina.
1388
1421
  */
@@ -1490,59 +1523,48 @@ class EqpAttachmentsComponent {
1490
1523
  };
1491
1524
  });
1492
1525
  }
1493
- compressVideoNative(file, config) {
1494
- return new Promise((resolve, reject) => {
1495
- const video = document.createElement('video');
1496
- const canvas = document.createElement('canvas');
1497
- const ctx = canvas.getContext('2d');
1498
- const videoUrl = URL.createObjectURL(file);
1499
- video.src = videoUrl;
1500
- video.muted = true;
1501
- video.play();
1502
- video.onloadeddata = () => {
1503
- // Calcoliamo le nuove dimensioni mantenendo l'aspect ratio
1504
- let width = video.videoWidth;
1505
- let height = video.videoHeight;
1506
- if (width > config.maxWidth) {
1507
- height = Math.round((config.maxWidth * height) / width);
1508
- width = config.maxWidth;
1509
- }
1510
- canvas.width = width;
1511
- canvas.height = height;
1512
- // Catturiamo lo stream dal canvas a 30fps
1513
- const stream = canvas.captureStream(30);
1514
- const recorder = new MediaRecorder(stream, {
1515
- mimeType: 'video/webm;codecs=vp8',
1516
- videoBitsPerSecond: config.bitrate
1517
- });
1518
- const chunks = [];
1519
- recorder.ondataavailable = (e) => chunks.push(e.data);
1520
- recorder.onstop = () => {
1521
- const compressedBlob = new Blob(chunks, { type: 'video/webm' });
1522
- URL.revokeObjectURL(videoUrl);
1523
- resolve(compressedBlob);
1524
- };
1525
- recorder.start();
1526
- // Funzione che disegna ogni frame sul canvas
1527
- const drawFrame = () => {
1528
- if (video.paused || video.ended) {
1529
- recorder.stop();
1530
- return;
1531
- }
1532
- ctx.drawImage(video, 0, 0, width, height);
1533
- requestAnimationFrame(drawFrame);
1534
- };
1535
- drawFrame();
1536
- };
1537
- video.onerror = reject;
1538
- });
1526
+ async compressVideoApi(file, config) {
1527
+ // Prepariamo il FormData per inviare il file binario e i parametri di configurazione
1528
+ const formData = new FormData();
1529
+ formData.append('video', file);
1530
+ formData.append('maxWidth', String(config.maxWidth ?? 1280));
1531
+ if (config.crf != null)
1532
+ formData.append('crf', String(config.crf));
1533
+ if (config.preset)
1534
+ formData.append('preset', config.preset);
1535
+ if (config.crf == null) {
1536
+ formData.append('bitrate', String(config.bitrate ?? 2500000));
1537
+ }
1538
+ if (config.maxFps != null)
1539
+ formData.append('maxFps', String(config.maxFps));
1540
+ if (config.audioBitrate != null)
1541
+ formData.append('audioBitrate', String(config.audioBitrate));
1542
+ // URL della tua API C#
1543
+ const apiUrl = 'https://tuo-servizio-api.it/api/video/compress';
1544
+ try {
1545
+ // Effettuiamo la chiamata. Usiamo 'fetch' per semplicità o HttpClient di Angular
1546
+ const response = await fetch(apiUrl, {
1547
+ method: 'POST',
1548
+ body: formData,
1549
+ // Nota: Non impostare Content-Type, il browser lo farà correttamente includendo il boundary
1550
+ });
1551
+ if (!response.ok) {
1552
+ throw new Error(`Errore server: ${response.statusText}`);
1553
+ }
1554
+ // Riceviamo il file compresso come Blob
1555
+ return await response.blob();
1556
+ }
1557
+ catch (error) {
1558
+ console.error("Errore durante la compressione remota:", error);
1559
+ throw error;
1560
+ }
1539
1561
  }
1540
1562
  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 });
1541
- 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", 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\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 @if (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 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 && 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 <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 </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(!disableAction){\r\n <button mat-icon-button class=\"remove-btn\" type=\"button\" aria-label=\"Rimuovi allegato\"\r\n (click)=\"deleteAttachment(att)\" [disabled]=\"att.isUploading\">\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 <button mat-icon-button (click)=\"handlePrimaryAction(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 <button mat-icon-button [matMenuTriggerFor]=\"actionsMenu\" matTooltip=\"Altre opzioni\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\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]=\"action.disabled ? action.disabled(att) : false\">\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\" [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 .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;-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;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;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,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)}\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" }] });
1563
+ 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\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 @if (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 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 && 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 <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 </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 <button mat-icon-button (click)=\"handlePrimaryAction(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 @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\" [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 .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;-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;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;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,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)}\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" }] });
1542
1564
  }
1543
1565
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EqpAttachmentsComponent, decorators: [{
1544
1566
  type: Component,
1545
- 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\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 @if (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 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 && 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 <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 </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(!disableAction){\r\n <button mat-icon-button class=\"remove-btn\" type=\"button\" aria-label=\"Rimuovi allegato\"\r\n (click)=\"deleteAttachment(att)\" [disabled]=\"att.isUploading\">\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 <button mat-icon-button (click)=\"handlePrimaryAction(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 <button mat-icon-button [matMenuTriggerFor]=\"actionsMenu\" matTooltip=\"Altre opzioni\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\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]=\"action.disabled ? action.disabled(att) : false\">\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\" [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 .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;-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;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;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,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)}\n"] }]
1567
+ 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 <button class=\"mb-2 me-2 eqp-attachments-download-btn\" (click)=\"viewAttachment(attachmentsList[0])\" type=\"button\"\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 @if (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 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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\"\r\n (click)=\"onSelectFile($event, fileInput)\" role=\"button\" tabindex=\"0\" (keydown.enter)=\"fileInput.click()\"\r\n (keydown.space)=\"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\" (dragover)=\"dragOver = true; $event.preventDefault()\"\r\n (dragleave)=\"dragOver = false\" (drop)=\"dragOver = false; fileDropped($event)\">\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 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 && 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 <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 </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 <button mat-icon-button (click)=\"handlePrimaryAction(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 @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\" [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 .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;-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;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;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,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)}\n"] }]
1546
1568
  }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.FormBuilder }, { type: i3.DomSanitizer }, { type: i4.HttpClient }, { type: EqpAttachmentService }], propDecorators: { disableAction: [{
1547
1569
  type: Input,
1548
1570
  args: ["disableAction"]
@@ -1744,6 +1766,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1744
1766
  }], enableImageCrop: [{
1745
1767
  type: Input,
1746
1768
  args: ["enableImageCrop"]
1769
+ }], actionHiddenFn: [{
1770
+ type: Input
1771
+ }], actionDisabledFn: [{
1772
+ type: Input
1747
1773
  }], videoCompression: [{
1748
1774
  type: Input
1749
1775
  }], customMenuActions: [{