@solcre-org/core-ui 2.11.41 → 2.11.43

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.
@@ -989,6 +989,7 @@ class FileFieldComponent extends BaseFieldComponent {
989
989
  selectedFiles = signal([]);
990
990
  existingFiles = signal([]);
991
991
  previewUrls = signal([]);
992
+ newFilesPreviews = signal([]);
992
993
  previewBlobs = signal([]);
993
994
  previewFileIds = signal(new Map());
994
995
  errorMessage = signal('');
@@ -1005,10 +1006,18 @@ class FileFieldComponent extends BaseFieldComponent {
1005
1006
  const existing = this.existingFiles();
1006
1007
  const selected = this.selectedFiles();
1007
1008
  const blobs = this.previewBlobs();
1008
- if (blobs.length > 0) {
1009
- return [...selected, ...blobs];
1009
+ const hasPreviewUrls = this.getPreviewUrls().length > 0;
1010
+ if (hasPreviewUrls) {
1011
+ return [...blobs, ...selected];
1010
1012
  }
1011
- return [...existing, ...selected];
1013
+ else {
1014
+ return [...existing, ...selected];
1015
+ }
1016
+ });
1017
+ allPreviewUrls = computed(() => {
1018
+ const remoteUrls = this.previewUrls();
1019
+ const newFileUrls = this.newFilesPreviews();
1020
+ return [...remoteUrls, ...newFileUrls];
1012
1021
  });
1013
1022
  previewUrlsEffect = effect(() => {
1014
1023
  const previewUrls = this.getPreviewUrls();
@@ -1016,6 +1025,12 @@ class FileFieldComponent extends BaseFieldComponent {
1016
1025
  this.createBlobsFromUrls(previewUrls);
1017
1026
  }
1018
1027
  });
1028
+ valueChangeEffect = effect(() => {
1029
+ const currentValue = this.value();
1030
+ if (currentValue) {
1031
+ setTimeout(() => this.regeneratePreviewsIfNeeded(), 0);
1032
+ }
1033
+ });
1019
1034
  getPreviewUrls() {
1020
1035
  const field = this.field();
1021
1036
  const rowData = this.rowData();
@@ -1083,6 +1098,10 @@ class FileFieldComponent extends BaseFieldComponent {
1083
1098
  ngOnInit() {
1084
1099
  super.ngOnInit();
1085
1100
  this.initializeFiles();
1101
+ setTimeout(() => this.regeneratePreviewsIfNeeded(), 100);
1102
+ }
1103
+ ngAfterViewInit() {
1104
+ setTimeout(() => this.regeneratePreviewsIfNeeded(), 200);
1086
1105
  }
1087
1106
  initializeFormControl() {
1088
1107
  const modeConfig = this.field().modes?.[this.mode()];
@@ -1136,18 +1155,71 @@ class FileFieldComponent extends BaseFieldComponent {
1136
1155
  this.existingFiles.set([]);
1137
1156
  }
1138
1157
  }
1158
+ regeneratePreviewsIfNeeded() {
1159
+ const currentValue = this.value();
1160
+ const field = this.field();
1161
+ const hasPreviewUrls = field.previewUrls && ((Array.isArray(field.previewUrls) && field.previewUrls.length > 0) ||
1162
+ (typeof field.previewUrls === 'function'));
1163
+ if (currentValue) {
1164
+ const currentNewPreviews = this.newFilesPreviews();
1165
+ const currentSelected = this.selectedFiles();
1166
+ if (currentValue instanceof File) {
1167
+ if (!currentSelected.includes(currentValue) || currentNewPreviews.length === 0) {
1168
+ this.selectedFiles.set([currentValue]);
1169
+ this.generatePreviews([currentValue]);
1170
+ }
1171
+ }
1172
+ else if (Array.isArray(currentValue)) {
1173
+ const files = currentValue.filter(v => v instanceof File);
1174
+ const serverFiles = currentValue.filter(v => this.isServerFile(v));
1175
+ const filesMatch = files.length === currentSelected.length &&
1176
+ files.every(file => currentSelected.includes(file));
1177
+ if (!filesMatch || (files.length > 0 && currentNewPreviews.length === 0)) {
1178
+ this.selectedFiles.set(files);
1179
+ if (!hasPreviewUrls) {
1180
+ this.existingFiles.set(serverFiles);
1181
+ }
1182
+ this.generatePreviews(files);
1183
+ }
1184
+ else if (files.length === 0 && serverFiles.length > 0 && currentSelected.length > 0) {
1185
+ this.selectedFiles.set([]);
1186
+ if (!hasPreviewUrls) {
1187
+ this.existingFiles.set(serverFiles);
1188
+ }
1189
+ this.newFilesPreviews.set([]);
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1139
1194
  isServerFile(value) {
1140
1195
  return value && typeof value === 'object' && 'id' in value && 'filename' in value;
1141
1196
  }
1142
1197
  generatePreviews(files) {
1198
+ if (!files.length)
1199
+ return;
1143
1200
  const urls = [];
1144
- files.forEach(file => {
1201
+ let processedCount = 0;
1202
+ const totalFiles = files.filter(file => file.type.startsWith('image/')).length;
1203
+ if (totalFiles === 0)
1204
+ return;
1205
+ files.forEach((file, index) => {
1145
1206
  if (file.type.startsWith('image/')) {
1146
1207
  const reader = new FileReader();
1147
1208
  reader.onload = (e) => {
1148
1209
  if (e.target?.result) {
1149
- urls.push(e.target.result);
1150
- this.previewUrls.set([...urls]);
1210
+ urls[index] = e.target.result;
1211
+ processedCount++;
1212
+ if (processedCount === totalFiles) {
1213
+ const validUrls = urls.filter(url => url);
1214
+ this.newFilesPreviews.set(validUrls);
1215
+ }
1216
+ }
1217
+ };
1218
+ reader.onerror = () => {
1219
+ processedCount++;
1220
+ if (processedCount === totalFiles) {
1221
+ const validUrls = urls.filter(url => url);
1222
+ this.newFilesPreviews.set(validUrls);
1151
1223
  }
1152
1224
  };
1153
1225
  reader.readAsDataURL(file);
@@ -1362,6 +1434,31 @@ class FileFieldComponent extends BaseFieldComponent {
1362
1434
  return -1;
1363
1435
  return this.selectedFiles().indexOf(file);
1364
1436
  }
1437
+ getPreviewUrlForFile(file) {
1438
+ if (this.isPreviewFile(file)) {
1439
+ return this.getOriginalUrl(file);
1440
+ }
1441
+ if (!this.isServerFile(file)) {
1442
+ const fileIndex = this.selectedFiles().indexOf(file);
1443
+ if (fileIndex >= 0) {
1444
+ const newFilePreviews = this.newFilesPreviews();
1445
+ return newFilePreviews[fileIndex] || null;
1446
+ }
1447
+ }
1448
+ return null;
1449
+ }
1450
+ getPreviewUrl(file) {
1451
+ if (this.isServerFile(file))
1452
+ return null;
1453
+ if (this.isPreviewFile(file))
1454
+ return this.getOriginalUrl(file);
1455
+ const fileIndex = this.selectedFiles().indexOf(file);
1456
+ if (fileIndex >= 0) {
1457
+ const newFilePreviews = this.newFilesPreviews();
1458
+ return newFilePreviews[fileIndex] || null;
1459
+ }
1460
+ return null;
1461
+ }
1365
1462
  isPreviewFile(file) {
1366
1463
  return !this.isServerFile(file) && file.__isPreviewFile === true;
1367
1464
  }
@@ -1372,11 +1469,11 @@ class FileFieldComponent extends BaseFieldComponent {
1372
1469
  this.onBlur();
1373
1470
  }
1374
1471
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1375
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading"] }] });
1472
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewUrl(file)) {\n <core-image-preview\n [src]=\"getPreviewUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading"] }] });
1376
1473
  }
1377
1474
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, decorators: [{
1378
1475
  type: Component,
1379
- args: [{ selector: 'core-file-field', standalone: true, imports: [CommonModule, FormsModule, TranslateModule, ReactiveFormsModule, FieldErrorsComponent, IconCompatPipe, ImagePreviewComponent], hostDirectives: [CoreHostDirective], template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n" }]
1476
+ args: [{ selector: 'core-file-field', standalone: true, imports: [CommonModule, FormsModule, TranslateModule, ReactiveFormsModule, FieldErrorsComponent, IconCompatPipe, ImagePreviewComponent], hostDirectives: [CoreHostDirective], template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewUrl(file)) {\n <core-image-preview\n [src]=\"getPreviewUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n" }]
1380
1477
  }] });
1381
1478
 
1382
1479
  var NumberFieldConfigType;
@@ -10733,11 +10830,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
10733
10830
  // Este archivo es generado automáticamente por scripts/update-version.js
10734
10831
  // No edites manualmente este archivo
10735
10832
  const VERSION = {
10736
- full: '2.11.41',
10833
+ full: '2.11.43',
10737
10834
  major: 2,
10738
10835
  minor: 11,
10739
- patch: 41,
10740
- timestamp: '2025-09-02T16:19:28.934Z',
10836
+ patch: 43,
10837
+ timestamp: '2025-09-02T18:32:21.979Z',
10741
10838
  buildDate: '2/9/2025'
10742
10839
  };
10743
10840