@dsivd/prestations-ng 19.2.0-beta.6 → 19.2.0-beta.8

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,28 @@
8
8
 
9
9
  ## [19.2.0] - should be aligned with prestations-be 19.2.x
10
10
 
11
+ ### Added
12
+
13
+ - [foehn-bo-multi-upload.component.ts](projects/prestations-ng/src/foehn-upload/foehn-bo-multi-upload/foehn-bo-multi-upload.component.ts)
14
+ - New `localUpload` input. When set to `true`, selected files are kept purely local
15
+ (as `DocumentReferenceWithFile`, no `uploadUrl()` call) so they can be cancelled before
16
+ being sent. Files show up immediately in the list with a "pending" indicator (dictionary
17
+ key `foehn-uploader.pending-label`, French default provided) since they're not uploaded
18
+ yet. It is your responsibility to upload/delete them at save time,
19
+ e.g. via the new
20
+ [document-changes.helper.ts](projects/prestations-ng/src/foehn-upload/document-changes.helper.ts)
21
+ (`splitDocumentChanges`) which computes `filesToAdd`/`documentsToDelete` from the model.
22
+ - The default (direct upload) mode is unchanged.
23
+ - New `maxFileSizeInMo` input: a client-side, per-file size limit that doesn't depend on
24
+ the `fileMaxSizeInBytesByFormKey` server configuration (useful for consumers that don't
25
+ expose that config yet). Uses the new dictionary key
26
+ `foehn-uploader.file-too-big-error-message` (params: `filename`, `maxSizeInMo`), which
27
+ ships with a French default in
28
+ [default-dictionary.ts](projects/prestations-ng/src/sdk-dictionary/default-dictionary.ts)
29
+ like the rest of `foehn-uploader.*` — override it project-side only if you need to.
30
+ - New `chooseButtonStyleModifier` input, appended to the choose button's CSS classes
31
+ (e.g. `btn-sm`), mirroring the same input already available on other uploaders.
32
+
11
33
  ### Changed
12
34
 
13
35
  Library now runs as strict mode, which may cause some errors to appear in your project after updating.
@@ -122,6 +144,10 @@ Please check the [UPGRADING_V19.md](UPGRADING_V19.md) guide for more information
122
144
  - dynamic list: a model changed by the project (another value, `null`) is displayed again; once a value had been
123
145
  displayed, the display no longer followed the model. The elements loaded for the search of the user still do
124
146
  not replace what they type.
147
+ - `foehn-input-address` without zone.js: an address given by the parent right after the initialization of the
148
+ component (e.g. prefilled with `SessionInfoWithApplicationService.prefillForm()` for a connected user) is no
149
+ longer overwritten by the model with the default country only; the default country and the clean-up of the model
150
+ are applied after the next rendering, from the latest model.
125
151
  - `foehn-input-address`: the deferred clean-up of the model (hidden address lines and post office box) applies
126
152
  to the latest model, it could restore a previous value (e.g. remove the default country); nothing is
127
153
  updated anymore once the component is destroyed.
package/CONTRIBUTING.md CHANGED
@@ -94,9 +94,10 @@ This project uses a set of scripts to lint and format the code, along with pre-c
94
94
 
95
95
  Important scripts are :
96
96
 
97
- - `npm run lint` : run ESLint and Prettier on all files
97
+ - `npm run lint` : run ESLint and Prettier on all files, and check the types of the TypeScript files compiled by no
98
+ build (`lint:types`: `cypress/`, which Cypress only transpiles, and the configuration files of `tsconfig.config.json`)
98
99
  - `npm run format`: run ESLint and Prettier on all files and fix errors automatically
99
- - `npm run validate`: clean and run all tests
100
+ - `npm run validate`: clean, lint and run all tests
100
101
 
101
102
  **Husky** is used as a pre-commit hook to automatically output linting and formatting errors for staged files before committing.
102
103
  In the end, this utilitary calls `npm run lint-staged` which you can also call yourself of course. To have this pre-commit hook,
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { Injectable, inject, InjectionToken, model, input, viewChildren, viewChild, forwardRef, output, computed, linkedSignal, DestroyRef, signal, effect, untracked, PendingTasks, Directive, ChangeDetectorRef, Pipe, Component, contentChildren, EnvironmentInjector, runInInjectionContext, afterNextRender, ElementRef, Injector, makeEnvironmentProviders, ErrorHandler, provideBrowserGlobalErrorListeners, provideAppInitializer, importProvidersFrom, NgZone, contentChild, TemplateRef } from '@angular/core';
3
3
  import { takeUntilDestroyed, toSignal, toObservable, outputToObservable } from '@angular/core/rxjs-interop';
4
4
  import { Router, ActivatedRoute, RouterLink, NavigationStart, NavigationEnd } from '@angular/router';
5
- import { Subject, BehaviorSubject, combineLatest, of, filter as filter$1, tap as tap$1, throwError, switchMap as switchMap$1, forkJoin, from, concatMap, toArray, EMPTY, startWith, merge, noop, interval, withLatestFrom, Observable, map as map$1, concat } from 'rxjs';
5
+ import { Subject, BehaviorSubject, combineLatest, of, filter as filter$1, tap as tap$1, throwError, switchMap as switchMap$1, forkJoin, from, concatMap, toArray, EMPTY, startWith, merge, noop, interval, withLatestFrom, map as map$1, concat } from 'rxjs';
6
6
  import { filter, shareReplay, tap, map, debounceTime, catchError, switchMap, first, finalize, throttleTime, mergeMap, share, take, distinctUntilChanged, startWith as startWith$1, takeWhile, takeUntil } from 'rxjs/operators';
7
7
  import { HttpClient, HttpEventType, HttpResponse, HTTP_INTERCEPTORS, HttpStatusCode, HttpResponseBase, HttpErrorResponse, HttpParams, provideHttpClient, withInterceptorsFromDi, withInterceptors } from '@angular/common/http';
8
8
  import * as i1 from '@angular/forms';
@@ -1340,6 +1340,8 @@ const DEFAULT_DICTIONARY = {
1340
1340
  'foehn-uploader.delete-error-message': 'Une erreur est survenue lors de la suppression de votre document',
1341
1341
  'foehn-uploader.delete-readonly-error-message': 'Un document en lecture seule ne peut pas être supprimé',
1342
1342
  'foehn-uploader.unknown-error-message': 'Impossible de transmettre le fichier',
1343
+ 'foehn-uploader.pending-label': "en attente d'envoi",
1344
+ 'foehn-uploader.file-too-big-error-message': 'Votre pièce jointe {filename} a une taille supérieure ou égale à la limite autorisée : {maxSizeInMo} Mo',
1343
1345
  'foehn-picture-upload.choose-button-label': 'Choisissez une photo',
1344
1346
  'foehn-picture-upload.loading-label': 'Chargement...',
1345
1347
  'foehn-picture-upload.invalid-file-type': 'Le type de votre pièce jointe {filename} ne figure pas parmi ceux qui sont autorisés : "{acceptFormats}"',
@@ -9044,34 +9046,6 @@ class StreetNumber {
9044
9046
  }
9045
9047
  const isDefined$1 = (value) => value === true || value === false;
9046
9048
  const hasInputChanged$1 = (change) => change && !ObjectHelper.isEqual(change.previousValue, change.currentValue);
9047
- /**
9048
- * Same as `debounceTime(0)`, but the application is not stable (PendingTasks, e.g. `fixture.whenStable()`)
9049
- * while a value is waiting to be emitted and processed synchronously by the next operators.
9050
- */
9051
- const debounceTimeZeroAsPendingTask = (pendingTasks) => (source) => new Observable((subscriber) => {
9052
- let removeTask = null;
9053
- const subscription = source
9054
- .pipe(tap(() => (removeTask ??= pendingTasks.add())), debounceTime(0))
9055
- .subscribe({
9056
- next: (value) => {
9057
- const removeSettledTask = removeTask;
9058
- removeTask = null;
9059
- try {
9060
- subscriber.next(value);
9061
- }
9062
- finally {
9063
- removeSettledTask?.();
9064
- }
9065
- },
9066
- error: (error) => subscriber.error(error),
9067
- complete: () => subscriber.complete(),
9068
- });
9069
- return () => {
9070
- subscription.unsubscribe();
9071
- removeTask?.();
9072
- removeTask = null;
9073
- };
9074
- });
9075
9049
  class FoehnInputAddressComponent extends FoehnInputComponent {
9076
9050
  isOnlySwiss = input(true, ...(ngDevMode ? [{ debugName: "isOnlySwiss" }] : /* istanbul ignore next */ []));
9077
9051
  showPostOfficeBoxText = input(false, ...(ngDevMode ? [{ debugName: "showPostOfficeBoxText" }] : /* istanbul ignore next */ []));
@@ -9118,8 +9092,9 @@ class FoehnInputAddressComponent extends FoehnInputComponent {
9118
9092
  streetCustomErrors = signal({}, ...(ngDevMode ? [{ debugName: "streetCustomErrors" }] : /* istanbul ignore next */ []));
9119
9093
  httpClient = inject(HttpClient);
9120
9094
  dictionaryService = inject(SdkDictionaryService);
9121
- addressPendingTasks = inject(PendingTasks);
9095
+ addressInjector = inject(Injector);
9122
9096
  isSanitizationScheduled = false;
9097
+ isDefaultCountryScheduled = false;
9123
9098
  iso2IdSubject = new BehaviorSubject(null);
9124
9099
  zipCodeIdSubject = new BehaviorSubject(null);
9125
9100
  estrIdSubject = new BehaviorSubject(null);
@@ -9355,32 +9330,21 @@ class FoehnInputAddressComponent extends FoehnInputComponent {
9355
9330
  return ObjectHelper.isDifferent(value, sanitized) ? sanitized : null;
9356
9331
  }
9357
9332
  /**
9358
- * The sanitized model is set in a macrotask (not while the view is checked) and computed from the latest model
9359
- * (e.g. the default country may have been set in between). The application is not stable until it is done.
9333
+ * The sanitized model is set after the next rendering (not while the view is checked), from the latest model: the
9334
+ * model given by the parent in between (e.g. prefilled asynchronously) has been received, it is not overwritten.
9360
9335
  */
9361
9336
  scheduleModelSanitization() {
9362
9337
  if (this.isSanitizationScheduled) {
9363
9338
  return;
9364
9339
  }
9365
9340
  this.isSanitizationScheduled = true;
9366
- const removeTask = this.addressPendingTasks.add();
9367
- const timeoutId = setTimeout(() => {
9368
- unregisterOnDestroy();
9341
+ afterNextRender(() => {
9369
9342
  this.isSanitizationScheduled = false;
9370
- try {
9371
- const sanitized = this.getSanitizedModel(this.model());
9372
- if (sanitized) {
9373
- this.updateNgModel(sanitized);
9374
- }
9375
- }
9376
- finally {
9377
- removeTask();
9343
+ const sanitized = this.getSanitizedModel(this.model());
9344
+ if (sanitized) {
9345
+ this.updateNgModel(sanitized);
9378
9346
  }
9379
- });
9380
- const unregisterOnDestroy = this._destroyRef.onDestroy(() => {
9381
- clearTimeout(timeoutId);
9382
- removeTask();
9383
- });
9347
+ }, { injector: this.addressInjector });
9384
9348
  }
9385
9349
  replaceAtLeastOneNotNull(notNullErrorLabel) {
9386
9350
  if (!this.showPostOfficeBoxText()) {
@@ -9522,29 +9486,45 @@ class FoehnInputAddressComponent extends FoehnInputComponent {
9522
9486
  this.isEmpty(this.addressLine2()));
9523
9487
  }
9524
9488
  manageDefaultCountry() {
9525
- // The application is not stable until the debounced changes are processed (the model can be updated).
9526
9489
  combineLatest([
9527
- this.countryModelChangeSubject.asObservable().pipe(debounceTimeZeroAsPendingTask(this.addressPendingTasks), distinctUntilChanged((previous, current) => previous?.iso2Id === current?.iso2Id)),
9490
+ this.countryModelChangeSubject
9491
+ .asObservable()
9492
+ .pipe(distinctUntilChanged((previous, current) => previous?.iso2Id === current?.iso2Id)),
9528
9493
  this.isOnlySwissChangeSubject
9529
9494
  .asObservable()
9530
- .pipe(debounceTimeZeroAsPendingTask(this.addressPendingTasks), distinctUntilChanged()),
9495
+ .pipe(distinctUntilChanged()),
9531
9496
  ])
9532
- .pipe(tap(([country, isOnlySwiss]) => {
9533
- if (!isOnlySwiss &&
9534
- !country &&
9535
- !this.isCountryInputDirty()) {
9536
- this.setDefaultCountry();
9537
- return;
9538
- }
9539
- if (isOnlySwiss) {
9540
- // When there is a country, we need to check if it has to be cleaned and set to default
9541
- if (country && !ObjectHelper.isEmpty(country)) {
9542
- this.clearAutocompletesWhenCountryIsUnappropriatedToComponentConfiguration();
9543
- }
9544
- this.setDefaultCountry();
9497
+ .pipe(takeUntilDestroyed(this._destroyRef))
9498
+ .subscribe(() => this.scheduleDefaultCountry());
9499
+ }
9500
+ /**
9501
+ * The default country is applied after the next rendering (once for the changes of the same rendering), from the
9502
+ * latest state: without zone.js, a model given by the parent in between (e.g. prefilled asynchronously) is only
9503
+ * received with the next change detection, it must not be overwritten by the model with the default country only.
9504
+ */
9505
+ scheduleDefaultCountry() {
9506
+ if (this.isDefaultCountryScheduled) {
9507
+ return;
9508
+ }
9509
+ this.isDefaultCountryScheduled = true;
9510
+ afterNextRender(() => {
9511
+ this.isDefaultCountryScheduled = false;
9512
+ this.applyDefaultCountry();
9513
+ }, { injector: this.addressInjector });
9514
+ }
9515
+ applyDefaultCountry() {
9516
+ const country = this.country();
9517
+ if (!this.isOnlySwiss() && !country && !this.isCountryInputDirty()) {
9518
+ this.setDefaultCountry();
9519
+ return;
9520
+ }
9521
+ if (this.isOnlySwiss()) {
9522
+ // When there is a country, we need to check if it has to be cleaned and set to default
9523
+ if (country && !ObjectHelper.isEmpty(country)) {
9524
+ this.clearAutocompletesWhenCountryIsUnappropriatedToComponentConfiguration();
9545
9525
  }
9546
- }), takeUntilDestroyed(this._destroyRef))
9547
- .subscribe();
9526
+ this.setDefaultCountry();
9527
+ }
9548
9528
  }
9549
9529
  isCountryInputDirty() {
9550
9530
  const countryAutocomplete = this.countryAutocomplete();
@@ -13620,6 +13600,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
13620
13600
  }]
13621
13601
  }], ctorParameters: () => [], propDecorators: { showUploadButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUploadButton", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], hideGlobalInfos: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideGlobalInfos", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }], overrideAcceptedExtensions: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideAcceptedExtensions", required: false }] }], overrideMaxFileNameLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideMaxFileNameLength", required: false }] }], overrideIllegalCharacters: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideIllegalCharacters", required: false }] }], showDeleteConfirmationMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDeleteConfirmationMessage", required: false }] }], maxSimultaneousSelectedFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSimultaneousSelectedFiles", required: false }] }], maxFilesCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFilesCount", required: false }] }], maxFilesSizeInMo: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFilesSizeInMo", required: false }] }], dragAndDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragAndDrop", required: false }] }], shouldDisplayFileSavedConfirmation: [{ type: i0.Input, args: [{ isSignal: true, alias: "shouldDisplayFileSavedConfirmation", required: false }] }], chooseButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "chooseButtonLabel", required: false }] }], chooseButtonLabelMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "chooseButtonLabelMultiple", required: false }] }], dropZoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropZoneLabel", required: false }] }], dropZoneLabelMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropZoneLabelMultiple", required: false }] }], deleteConfirmationMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteConfirmationMessage", required: false }] }] } });
13622
13602
 
13603
+ /**
13604
+ * Computes what needs to be uploaded/deleted server-side by comparing a document list
13605
+ * currently held in a "local upload" model (mixing already persisted `DocumentReference`
13606
+ * and pending `DocumentReferenceWithFile`) against the list as it was originally loaded.
13607
+ */
13608
+ function splitDocumentChanges(current, original) {
13609
+ const filesToAdd = (current ?? [])
13610
+ .filter((doc) => doc instanceof DocumentReferenceWithFile)
13611
+ .map((doc) => doc.file)
13612
+ .filter((file) => !!file);
13613
+ const currentReferences = new Set((current ?? [])
13614
+ .map((doc) => doc.reference)
13615
+ .filter((reference) => !!reference));
13616
+ const documentsToDelete = (original ?? []).filter((doc) => !!doc.reference && !currentReferences.has(doc.reference));
13617
+ return { filesToAdd, documentsToDelete };
13618
+ }
13619
+
13623
13620
  class UploadProgressService extends AbstractUploadProgressService {
13624
13621
  _analysisProgressSubject = new BehaviorSubject(false);
13625
13622
  _uploadProgressSubject = new BehaviorSubject(null);
@@ -14304,14 +14301,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
14304
14301
  }]
14305
14302
  }], ctorParameters: () => [] });
14306
14303
 
14304
+ const BYTES_IN_MO = 1024 * 1024;
14307
14305
  class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14308
14306
  uploadUrl = input(...(ngDevMode ? [undefined, { debugName: "uploadUrl" }] : /* istanbul ignore next */ []));
14309
14307
  deleteUrl = input(...(ngDevMode ? [undefined, { debugName: "deleteUrl" }] : /* istanbul ignore next */ []));
14310
14308
  downloadUrl = input(...(ngDevMode ? [undefined, { debugName: "downloadUrl" }] : /* istanbul ignore next */ []));
14311
14309
  optionalLabelKey = input('foehn-input.optional', ...(ngDevMode ? [{ debugName: "optionalLabelKey" }] : /* istanbul ignore next */ []));
14310
+ localUpload = input(false, ...(ngDevMode ? [{ debugName: "localUpload" }] : /* istanbul ignore next */ []));
14311
+ maxFileSizeInMo = input(...(ngDevMode ? [undefined, { debugName: "maxFileSizeInMo" }] : /* istanbul ignore next */ []));
14312
+ chooseButtonStyleModifier = input(...(ngDevMode ? [undefined, { debugName: "chooseButtonStyleModifier" }] : /* istanbul ignore next */ []));
14312
14313
  documentDeleted = output();
14313
14314
  boMultiUploadService = inject(BoMultiUploadService);
14314
14315
  pageUploadLimitService = inject(PageUploadLimitService);
14316
+ blobUrls = new Map();
14317
+ localSequence = 0;
14315
14318
  get addedFiles() {
14316
14319
  return this.model()?.filter((e) => !e.readonly) ?? [];
14317
14320
  }
@@ -14359,6 +14362,23 @@ class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14359
14362
  }
14360
14363
  ngOnDestroy() {
14361
14364
  this.pageUploadLimitService.unregisterUploader(this);
14365
+ this.blobUrls.forEach((url) => URL.revokeObjectURL(url));
14366
+ this.blobUrls.clear();
14367
+ }
14368
+ isPending(document) {
14369
+ return document instanceof DocumentReferenceWithFile;
14370
+ }
14371
+ getDocumentDownloadUrl(document) {
14372
+ if (document instanceof DocumentReferenceWithFile) {
14373
+ const file = document.file;
14374
+ if (file) {
14375
+ if (!this.blobUrls.has(file)) {
14376
+ this.blobUrls.set(file, URL.createObjectURL(file));
14377
+ }
14378
+ return this.blobUrls.get(file) ?? '';
14379
+ }
14380
+ }
14381
+ return this.boMultiUploadService.getDownloadUrl(this.downloadUrl(), document);
14362
14382
  }
14363
14383
  getTotalFilesSize() {
14364
14384
  return (this.model()
@@ -14399,6 +14419,13 @@ class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14399
14419
  }
14400
14420
  }
14401
14421
  }
14422
+ removeFileOnConfirmation(document) {
14423
+ if (this.localUpload()) {
14424
+ this.removeDocumentLocally(document);
14425
+ return;
14426
+ }
14427
+ super.removeFileOnConfirmation(document);
14428
+ }
14402
14429
  populateFileItemList(fileList) {
14403
14430
  let files = Array.from(fileList);
14404
14431
  if (!files.length ||
@@ -14415,13 +14442,79 @@ class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14415
14442
  if (filesErrors.length) {
14416
14443
  return;
14417
14444
  }
14445
+ const tooBigErrors = this.tooBigErrors(files);
14446
+ if (tooBigErrors.length) {
14447
+ this.refreshErrors([tooBigErrors, true]);
14448
+ return;
14449
+ }
14418
14450
  // Initialize model if empty
14419
14451
  if (!this.model()?.length) {
14420
14452
  this.model.set([]);
14421
14453
  }
14454
+ if (this.localUpload()) {
14455
+ // The files stay purely local: no HTTP call is made, the consuming project is
14456
+ // responsible for uploading them at save time (see splitDocumentChanges()).
14457
+ this.addFilesLocally(files);
14458
+ return;
14459
+ }
14422
14460
  // we send files to server
14423
14461
  this.uploadFilesSubject.next(files);
14424
14462
  }
14463
+ tooBigErrors(files) {
14464
+ const maxFileSizeInMo = this.maxFileSizeInMo();
14465
+ if (!maxFileSizeInMo) {
14466
+ return [];
14467
+ }
14468
+ return files
14469
+ .filter((file) => file.size > maxFileSizeInMo * BYTES_IN_MO)
14470
+ .map((file, index) => ({
14471
+ name: this.name(),
14472
+ code: `FILE_TOO_BIG_${index}`,
14473
+ message: this.dictionaryService.getKeySync('foehn-uploader.file-too-big-error-message', {
14474
+ filename: getSafeFileNameForErrorMessage(file.name),
14475
+ maxSizeInMo: `${maxFileSizeInMo}`,
14476
+ }),
14477
+ }));
14478
+ }
14479
+ addFilesLocally(files) {
14480
+ const pendingDocuments = files.map((file) => this.toPendingDocument(file));
14481
+ this.model.update((current) => [
14482
+ ...(current ?? []),
14483
+ ...pendingDocuments,
14484
+ ]);
14485
+ this.markAsDirty();
14486
+ this.triggerUserInput(this.model());
14487
+ }
14488
+ toPendingDocument(file) {
14489
+ const document = new DocumentReferenceWithFile();
14490
+ document.reference = '';
14491
+ document.key = `${this.key() ?? this.name()}_local_${this.localSequence++}`;
14492
+ document.label = this.label();
14493
+ document.filename = file.name;
14494
+ document.mimeType = file.type;
14495
+ document.fileSize = file.size;
14496
+ document.file = file;
14497
+ return document;
14498
+ }
14499
+ removeDocumentLocally(document) {
14500
+ const current = this.model() ?? [];
14501
+ if (!current.includes(document)) {
14502
+ return;
14503
+ }
14504
+ this.model.set(current.filter((candidate) => candidate !== document));
14505
+ if (document instanceof DocumentReferenceWithFile && document.file) {
14506
+ this.revokeBlobUrl(document.file);
14507
+ }
14508
+ this.markAsDirty();
14509
+ this.triggerUserInput(this.model());
14510
+ }
14511
+ revokeBlobUrl(file) {
14512
+ const blobUrl = this.blobUrls.get(file);
14513
+ if (blobUrl) {
14514
+ URL.revokeObjectURL(blobUrl);
14515
+ this.blobUrls.delete(file);
14516
+ }
14517
+ }
14425
14518
  displayResultFromServer(documents, errors) {
14426
14519
  this.displayErrorsFromServer(errors);
14427
14520
  this.model.set([...(this.model() ?? []), ...(documents || [])]);
@@ -14459,7 +14552,7 @@ class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14459
14552
  return files.slice(0, 1);
14460
14553
  }
14461
14554
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: FoehnBoMultiUploadComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
14462
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: FoehnBoMultiUploadComponent, isStandalone: true, selector: "foehn-bo-multi-upload", inputs: { uploadUrl: { classPropertyName: "uploadUrl", publicName: "uploadUrl", isSignal: true, isRequired: false, transformFunction: null }, deleteUrl: { classPropertyName: "deleteUrl", publicName: "deleteUrl", isSignal: true, isRequired: false, transformFunction: null }, downloadUrl: { classPropertyName: "downloadUrl", publicName: "downloadUrl", isSignal: true, isRequired: false, transformFunction: null }, optionalLabelKey: { classPropertyName: "optionalLabelKey", publicName: "optionalLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { documentDeleted: "documentDeleted" }, providers: [
14555
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: FoehnBoMultiUploadComponent, isStandalone: true, selector: "foehn-bo-multi-upload", inputs: { uploadUrl: { classPropertyName: "uploadUrl", publicName: "uploadUrl", isSignal: true, isRequired: false, transformFunction: null }, deleteUrl: { classPropertyName: "deleteUrl", publicName: "deleteUrl", isSignal: true, isRequired: false, transformFunction: null }, downloadUrl: { classPropertyName: "downloadUrl", publicName: "downloadUrl", isSignal: true, isRequired: false, transformFunction: null }, optionalLabelKey: { classPropertyName: "optionalLabelKey", publicName: "optionalLabelKey", isSignal: true, isRequired: false, transformFunction: null }, localUpload: { classPropertyName: "localUpload", publicName: "localUpload", isSignal: true, isRequired: false, transformFunction: null }, maxFileSizeInMo: { classPropertyName: "maxFileSizeInMo", publicName: "maxFileSizeInMo", isSignal: true, isRequired: false, transformFunction: null }, chooseButtonStyleModifier: { classPropertyName: "chooseButtonStyleModifier", publicName: "chooseButtonStyleModifier", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { documentDeleted: "documentDeleted" }, providers: [
14463
14556
  {
14464
14557
  provide: FoehnInputComponent,
14465
14558
  useExisting: forwardRef(() => FoehnBoMultiUploadComponent),
@@ -14470,7 +14563,7 @@ class FoehnBoMultiUploadComponent extends AbstractFoehnUploaderComponent {
14470
14563
  provide: AbstractUploadProgressService,
14471
14564
  useExisting: UploadProgressService,
14472
14565
  },
14473
- ], usesInheritance: true, ngImport: i0, template: "<div\n class=\"form-group container-box\"\n [class.has-danger]=\"hasErrorsToDisplay()\"\n [class.vd-form-group-danger]=\"hasErrorsToDisplay()\"\n [class.drop-zone-highlight]=\"showDropZone\"\n [attr.id]=\"buildId('Container')\"\n tabindex=\"-1\"\n (drop)=\"onDrop($event)\"\n (dragenter)=\"onDragenter($event)\"\n (dragleave)=\"onDragleave($event)\"\n (dragover)=\"onDragover($event)\"\n #fallBackTrigger\n>\n @if (!!label()) {\n <label\n [class]=\"\n 'form-label ' +\n (isLabelSrOnly()\n ? 'visually-hidden'\n : (labelStyleModifier() ?? ''))\n \"\n [attr.for]=\"buildChildId()\"\n >\n <span [innerHTML]=\"label()\"></span>\n @if (!required() && !hideNotRequiredExtraLabel()) {\n <span aria-hidden=\"true\">\n {{ optionalLabelKey() | fromDictionary }}\n </span>\n }\n </label>\n }\n\n <foehn-validation-alerts\n [component]=\"this\"\n [shouldErrorsBeLive]=\"hasLiveUploadErrors()\"\n />\n\n @if (helpText()) {\n <small\n [attr.id]=\"buildChildId('Help')\"\n class=\"form-text text-secondary\"\n [innerHTML]=\"helpText()\"\n ></small>\n }\n\n <!-- PRESTAKIT-309: Fake input with NgModel to be registered into Form controls -->\n <input type=\"hidden\" [name]=\"name() || label() || ''\" [ngModel]=\"model()\" />\n\n <ng-content />\n\n @for (document of model(); track trackByDocument($index, document)) {\n <div class=\"file file-uploaded\">\n <!-- prettier-ignore -->\n <a [href]=\"boMultiUploadService.getDownloadUrl(downloadUrl(), document)\" target=\"_blank\">{{ document.filename }}</a>\n <span class=\"ms-1 me-1\">\n ({{ toMegaOctets(document.fileSize ?? 0) }}\n <abbr\n [title]=\"\n 'foehn-uploader.abbr-megaoctet-title' | fromDictionary\n \"\n >\n {{ 'foehn-uploader.abbr-megaoctet' | fromDictionary }}\n </abbr>\n )\n </span>\n @if (!readonly() && !document.readonly) {\n <button\n [disabled]=\"disabled()\"\n type=\"button\"\n class=\"btn btn-link icon-button delete-uploaded\"\n (click)=\"removeFile(document)\"\n >\n <foehn-icon-times\n [title]=\"\n 'foehn-uploader.delete-icon-title'\n | fromDictionary: { docName: document.filename }\n \"\n />\n </button>\n }\n </div>\n }\n\n @if (showGlobalInfos(model())) {\n <small\n class=\"form-text text-secondary uploaded-global-info\"\n [innerHTML]=\"getGlobalInfos(model())\"\n ></small>\n }\n\n @if (canAddMoreFiles()) {\n <input\n class=\"form-control actual-input\"\n type=\"file\"\n [name]=\"name() || label()\"\n [multiple]=\"multiple()\"\n [attr.accept]=\"\n overrideAcceptedExtensions()\n ? overrideAcceptedExtensions()\n : uploaderHelper.accept\n ? uploaderHelper.accept\n : null\n \"\n (change)=\"onFileChange($event)\"\n #inputFile\n />\n\n <button\n type=\"button\"\n class=\"btn btn-primary\"\n [disabled]=\"disabled()\"\n [class.visually-hidden]=\"!showUploadButton()\"\n [attr.id]=\"buildChildId()\"\n [attr.aria-invalid]=\"hasErrorsToDisplay() || null\"\n [attr.aria-describedby]=\"buildId('ErrorsContainer')\"\n (click)=\"inputFile.click()\"\n #entryComponent\n >\n {{\n multiple()\n ? resolvedChooseButtonLabelMultiple()\n : resolvedChooseButtonLabel()\n }}\n </button>\n\n @if (dragAndDrop() && !disabled()) {\n <div\n aria-hidden=\"true\"\n class=\"dropfile\"\n [class.dropfile-border-transparent]=\"showDropZone\"\n (click)=\"inputFile.click()\"\n >\n {{\n multiple()\n ? resolvedDropZoneLabelMultiple()\n : resolvedDropZoneLabel()\n }}\n </div>\n }\n }\n\n <foehn-upload-progress-bar\n [progressBarTriggerHtmlElement]=\"\n inputElement()?.nativeElement || fallBackTrigger\n \"\n />\n</div>\n", styles: [".dropfile{width:300px;border:3px dashed #bbb;text-align:center;margin-top:10px;cursor:pointer;padding:15px 3px}.dropfile-border-transparent{border-color:#fff}.actual-input{display:none}.file-list{margin-top:20px}.icon-button{border:0}.icon-button:hover{cursor:pointer}:host ::ng-deep .svg-inline--fa{color:#000!important}.drop-zone-highlight{outline:3px dashed #bbb}.container-box{border:1px solid #ededed;background-color:#fbfbfb;padding:.5rem}.container-box.vd-form-group-danger{border-left:5px solid var(--vd-danger);padding-left:1rem}\n"], dependencies: [{ kind: "component", type: FoehnValidationAlertsComponent, selector: "foehn-validation-alerts", inputs: ["component", "shouldErrorsBeLive"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FoehnIconTimesComponent, selector: "foehn-icon-times" }, { kind: "component", type: FoehnUploadProgressBarComponent, selector: "foehn-upload-progress-bar", inputs: ["progressBarTriggerHtmlElement"] }, { kind: "pipe", type: SdkDictionaryPipe, name: "fromDictionary" }] });
14566
+ ], usesInheritance: true, ngImport: i0, template: "<div\n class=\"form-group container-box\"\n [class.has-danger]=\"hasErrorsToDisplay()\"\n [class.vd-form-group-danger]=\"hasErrorsToDisplay()\"\n [class.drop-zone-highlight]=\"showDropZone\"\n [attr.id]=\"buildId('Container')\"\n tabindex=\"-1\"\n (drop)=\"onDrop($event)\"\n (dragenter)=\"onDragenter($event)\"\n (dragleave)=\"onDragleave($event)\"\n (dragover)=\"onDragover($event)\"\n #fallBackTrigger\n>\n @if (!!label()) {\n <label\n [class]=\"\n 'form-label ' +\n (isLabelSrOnly()\n ? 'visually-hidden'\n : (labelStyleModifier() ?? ''))\n \"\n [attr.for]=\"buildChildId()\"\n >\n <span [innerHTML]=\"label()\"></span>\n @if (!required() && !hideNotRequiredExtraLabel()) {\n <span aria-hidden=\"true\">\n {{ optionalLabelKey() | fromDictionary }}\n </span>\n }\n </label>\n }\n\n <foehn-validation-alerts\n [component]=\"this\"\n [shouldErrorsBeLive]=\"hasLiveUploadErrors()\"\n />\n\n @if (helpText()) {\n <small\n [attr.id]=\"buildChildId('Help')\"\n class=\"form-text text-secondary\"\n [innerHTML]=\"helpText()\"\n ></small>\n }\n\n <!-- PRESTAKIT-309: Fake input with NgModel to be registered into Form controls -->\n <input type=\"hidden\" [name]=\"name() || label() || ''\" [ngModel]=\"model()\" />\n\n <ng-content />\n\n @for (document of model(); track trackByDocument($index, document)) {\n <div class=\"file file-uploaded\">\n <!-- prettier-ignore -->\n <a [href]=\"getDocumentDownloadUrl(document)\" target=\"_blank\">{{ document.filename }}</a>\n <span class=\"ms-1 me-1\">\n ({{ toMegaOctets(document.fileSize ?? 0) }}\n <abbr\n [title]=\"\n 'foehn-uploader.abbr-megaoctet-title' | fromDictionary\n \"\n >\n {{ 'foehn-uploader.abbr-megaoctet' | fromDictionary }}\n </abbr>\n )\n </span>\n @if (isPending(document)) {\n <span class=\"fst-italic text-secondary\">\n ({{ 'foehn-uploader.pending-label' | fromDictionary }})\n </span>\n }\n @if (!readonly() && !document.readonly) {\n <button\n [disabled]=\"disabled()\"\n type=\"button\"\n class=\"btn btn-link icon-button delete-uploaded\"\n (click)=\"removeFile(document)\"\n >\n <foehn-icon-times\n [title]=\"\n 'foehn-uploader.delete-icon-title'\n | fromDictionary: { docName: document.filename }\n \"\n />\n </button>\n }\n </div>\n }\n\n @if (showGlobalInfos(model())) {\n <small\n class=\"form-text text-secondary uploaded-global-info\"\n [innerHTML]=\"getGlobalInfos(model())\"\n ></small>\n }\n\n @if (canAddMoreFiles()) {\n <input\n class=\"form-control actual-input\"\n type=\"file\"\n [name]=\"name() || label()\"\n [multiple]=\"multiple()\"\n [attr.accept]=\"\n overrideAcceptedExtensions()\n ? overrideAcceptedExtensions()\n : uploaderHelper.accept\n ? uploaderHelper.accept\n : null\n \"\n (change)=\"onFileChange($event)\"\n #inputFile\n />\n\n <button\n type=\"button\"\n [class]=\"'btn btn-primary ' + (chooseButtonStyleModifier() ?? '')\"\n [disabled]=\"disabled()\"\n [class.visually-hidden]=\"!showUploadButton()\"\n [attr.id]=\"buildChildId()\"\n [attr.aria-invalid]=\"hasErrorsToDisplay() || null\"\n [attr.aria-describedby]=\"buildId('ErrorsContainer')\"\n (click)=\"inputFile.click()\"\n #entryComponent\n >\n {{\n multiple()\n ? resolvedChooseButtonLabelMultiple()\n : resolvedChooseButtonLabel()\n }}\n </button>\n\n @if (dragAndDrop() && !disabled()) {\n <div\n aria-hidden=\"true\"\n class=\"dropfile\"\n [class.dropfile-border-transparent]=\"showDropZone\"\n (click)=\"inputFile.click()\"\n >\n {{\n multiple()\n ? resolvedDropZoneLabelMultiple()\n : resolvedDropZoneLabel()\n }}\n </div>\n }\n }\n\n <foehn-upload-progress-bar\n [progressBarTriggerHtmlElement]=\"\n inputElement()?.nativeElement || fallBackTrigger\n \"\n />\n</div>\n", styles: [".dropfile{width:300px;border:3px dashed #bbb;text-align:center;margin-top:10px;cursor:pointer;padding:15px 3px}.dropfile-border-transparent{border-color:#fff}.actual-input{display:none}.file-list{margin-top:20px}.icon-button{border:0}.icon-button:hover{cursor:pointer}:host ::ng-deep .svg-inline--fa{color:#000!important}.drop-zone-highlight{outline:3px dashed #bbb}.container-box{border:1px solid #ededed;background-color:#fbfbfb;padding:.5rem}.container-box.vd-form-group-danger{border-left:5px solid var(--vd-danger);padding-left:1rem}\n"], dependencies: [{ kind: "component", type: FoehnValidationAlertsComponent, selector: "foehn-validation-alerts", inputs: ["component", "shouldErrorsBeLive"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FoehnIconTimesComponent, selector: "foehn-icon-times" }, { kind: "component", type: FoehnUploadProgressBarComponent, selector: "foehn-upload-progress-bar", inputs: ["progressBarTriggerHtmlElement"] }, { kind: "pipe", type: SdkDictionaryPipe, name: "fromDictionary" }] });
14474
14567
  }
14475
14568
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: FoehnBoMultiUploadComponent, decorators: [{
14476
14569
  type: Component,
@@ -14491,8 +14584,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
14491
14584
  FoehnIconTimesComponent,
14492
14585
  FoehnUploadProgressBarComponent,
14493
14586
  SdkDictionaryPipe,
14494
- ], template: "<div\n class=\"form-group container-box\"\n [class.has-danger]=\"hasErrorsToDisplay()\"\n [class.vd-form-group-danger]=\"hasErrorsToDisplay()\"\n [class.drop-zone-highlight]=\"showDropZone\"\n [attr.id]=\"buildId('Container')\"\n tabindex=\"-1\"\n (drop)=\"onDrop($event)\"\n (dragenter)=\"onDragenter($event)\"\n (dragleave)=\"onDragleave($event)\"\n (dragover)=\"onDragover($event)\"\n #fallBackTrigger\n>\n @if (!!label()) {\n <label\n [class]=\"\n 'form-label ' +\n (isLabelSrOnly()\n ? 'visually-hidden'\n : (labelStyleModifier() ?? ''))\n \"\n [attr.for]=\"buildChildId()\"\n >\n <span [innerHTML]=\"label()\"></span>\n @if (!required() && !hideNotRequiredExtraLabel()) {\n <span aria-hidden=\"true\">\n {{ optionalLabelKey() | fromDictionary }}\n </span>\n }\n </label>\n }\n\n <foehn-validation-alerts\n [component]=\"this\"\n [shouldErrorsBeLive]=\"hasLiveUploadErrors()\"\n />\n\n @if (helpText()) {\n <small\n [attr.id]=\"buildChildId('Help')\"\n class=\"form-text text-secondary\"\n [innerHTML]=\"helpText()\"\n ></small>\n }\n\n <!-- PRESTAKIT-309: Fake input with NgModel to be registered into Form controls -->\n <input type=\"hidden\" [name]=\"name() || label() || ''\" [ngModel]=\"model()\" />\n\n <ng-content />\n\n @for (document of model(); track trackByDocument($index, document)) {\n <div class=\"file file-uploaded\">\n <!-- prettier-ignore -->\n <a [href]=\"boMultiUploadService.getDownloadUrl(downloadUrl(), document)\" target=\"_blank\">{{ document.filename }}</a>\n <span class=\"ms-1 me-1\">\n ({{ toMegaOctets(document.fileSize ?? 0) }}\n <abbr\n [title]=\"\n 'foehn-uploader.abbr-megaoctet-title' | fromDictionary\n \"\n >\n {{ 'foehn-uploader.abbr-megaoctet' | fromDictionary }}\n </abbr>\n )\n </span>\n @if (!readonly() && !document.readonly) {\n <button\n [disabled]=\"disabled()\"\n type=\"button\"\n class=\"btn btn-link icon-button delete-uploaded\"\n (click)=\"removeFile(document)\"\n >\n <foehn-icon-times\n [title]=\"\n 'foehn-uploader.delete-icon-title'\n | fromDictionary: { docName: document.filename }\n \"\n />\n </button>\n }\n </div>\n }\n\n @if (showGlobalInfos(model())) {\n <small\n class=\"form-text text-secondary uploaded-global-info\"\n [innerHTML]=\"getGlobalInfos(model())\"\n ></small>\n }\n\n @if (canAddMoreFiles()) {\n <input\n class=\"form-control actual-input\"\n type=\"file\"\n [name]=\"name() || label()\"\n [multiple]=\"multiple()\"\n [attr.accept]=\"\n overrideAcceptedExtensions()\n ? overrideAcceptedExtensions()\n : uploaderHelper.accept\n ? uploaderHelper.accept\n : null\n \"\n (change)=\"onFileChange($event)\"\n #inputFile\n />\n\n <button\n type=\"button\"\n class=\"btn btn-primary\"\n [disabled]=\"disabled()\"\n [class.visually-hidden]=\"!showUploadButton()\"\n [attr.id]=\"buildChildId()\"\n [attr.aria-invalid]=\"hasErrorsToDisplay() || null\"\n [attr.aria-describedby]=\"buildId('ErrorsContainer')\"\n (click)=\"inputFile.click()\"\n #entryComponent\n >\n {{\n multiple()\n ? resolvedChooseButtonLabelMultiple()\n : resolvedChooseButtonLabel()\n }}\n </button>\n\n @if (dragAndDrop() && !disabled()) {\n <div\n aria-hidden=\"true\"\n class=\"dropfile\"\n [class.dropfile-border-transparent]=\"showDropZone\"\n (click)=\"inputFile.click()\"\n >\n {{\n multiple()\n ? resolvedDropZoneLabelMultiple()\n : resolvedDropZoneLabel()\n }}\n </div>\n }\n }\n\n <foehn-upload-progress-bar\n [progressBarTriggerHtmlElement]=\"\n inputElement()?.nativeElement || fallBackTrigger\n \"\n />\n</div>\n", styles: [".dropfile{width:300px;border:3px dashed #bbb;text-align:center;margin-top:10px;cursor:pointer;padding:15px 3px}.dropfile-border-transparent{border-color:#fff}.actual-input{display:none}.file-list{margin-top:20px}.icon-button{border:0}.icon-button:hover{cursor:pointer}:host ::ng-deep .svg-inline--fa{color:#000!important}.drop-zone-highlight{outline:3px dashed #bbb}.container-box{border:1px solid #ededed;background-color:#fbfbfb;padding:.5rem}.container-box.vd-form-group-danger{border-left:5px solid var(--vd-danger);padding-left:1rem}\n"] }]
14495
- }], propDecorators: { uploadUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadUrl", required: false }] }], deleteUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteUrl", required: false }] }], downloadUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadUrl", required: false }] }], optionalLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabelKey", required: false }] }], documentDeleted: [{ type: i0.Output, args: ["documentDeleted"] }] } });
14587
+ ], template: "<div\n class=\"form-group container-box\"\n [class.has-danger]=\"hasErrorsToDisplay()\"\n [class.vd-form-group-danger]=\"hasErrorsToDisplay()\"\n [class.drop-zone-highlight]=\"showDropZone\"\n [attr.id]=\"buildId('Container')\"\n tabindex=\"-1\"\n (drop)=\"onDrop($event)\"\n (dragenter)=\"onDragenter($event)\"\n (dragleave)=\"onDragleave($event)\"\n (dragover)=\"onDragover($event)\"\n #fallBackTrigger\n>\n @if (!!label()) {\n <label\n [class]=\"\n 'form-label ' +\n (isLabelSrOnly()\n ? 'visually-hidden'\n : (labelStyleModifier() ?? ''))\n \"\n [attr.for]=\"buildChildId()\"\n >\n <span [innerHTML]=\"label()\"></span>\n @if (!required() && !hideNotRequiredExtraLabel()) {\n <span aria-hidden=\"true\">\n {{ optionalLabelKey() | fromDictionary }}\n </span>\n }\n </label>\n }\n\n <foehn-validation-alerts\n [component]=\"this\"\n [shouldErrorsBeLive]=\"hasLiveUploadErrors()\"\n />\n\n @if (helpText()) {\n <small\n [attr.id]=\"buildChildId('Help')\"\n class=\"form-text text-secondary\"\n [innerHTML]=\"helpText()\"\n ></small>\n }\n\n <!-- PRESTAKIT-309: Fake input with NgModel to be registered into Form controls -->\n <input type=\"hidden\" [name]=\"name() || label() || ''\" [ngModel]=\"model()\" />\n\n <ng-content />\n\n @for (document of model(); track trackByDocument($index, document)) {\n <div class=\"file file-uploaded\">\n <!-- prettier-ignore -->\n <a [href]=\"getDocumentDownloadUrl(document)\" target=\"_blank\">{{ document.filename }}</a>\n <span class=\"ms-1 me-1\">\n ({{ toMegaOctets(document.fileSize ?? 0) }}\n <abbr\n [title]=\"\n 'foehn-uploader.abbr-megaoctet-title' | fromDictionary\n \"\n >\n {{ 'foehn-uploader.abbr-megaoctet' | fromDictionary }}\n </abbr>\n )\n </span>\n @if (isPending(document)) {\n <span class=\"fst-italic text-secondary\">\n ({{ 'foehn-uploader.pending-label' | fromDictionary }})\n </span>\n }\n @if (!readonly() && !document.readonly) {\n <button\n [disabled]=\"disabled()\"\n type=\"button\"\n class=\"btn btn-link icon-button delete-uploaded\"\n (click)=\"removeFile(document)\"\n >\n <foehn-icon-times\n [title]=\"\n 'foehn-uploader.delete-icon-title'\n | fromDictionary: { docName: document.filename }\n \"\n />\n </button>\n }\n </div>\n }\n\n @if (showGlobalInfos(model())) {\n <small\n class=\"form-text text-secondary uploaded-global-info\"\n [innerHTML]=\"getGlobalInfos(model())\"\n ></small>\n }\n\n @if (canAddMoreFiles()) {\n <input\n class=\"form-control actual-input\"\n type=\"file\"\n [name]=\"name() || label()\"\n [multiple]=\"multiple()\"\n [attr.accept]=\"\n overrideAcceptedExtensions()\n ? overrideAcceptedExtensions()\n : uploaderHelper.accept\n ? uploaderHelper.accept\n : null\n \"\n (change)=\"onFileChange($event)\"\n #inputFile\n />\n\n <button\n type=\"button\"\n [class]=\"'btn btn-primary ' + (chooseButtonStyleModifier() ?? '')\"\n [disabled]=\"disabled()\"\n [class.visually-hidden]=\"!showUploadButton()\"\n [attr.id]=\"buildChildId()\"\n [attr.aria-invalid]=\"hasErrorsToDisplay() || null\"\n [attr.aria-describedby]=\"buildId('ErrorsContainer')\"\n (click)=\"inputFile.click()\"\n #entryComponent\n >\n {{\n multiple()\n ? resolvedChooseButtonLabelMultiple()\n : resolvedChooseButtonLabel()\n }}\n </button>\n\n @if (dragAndDrop() && !disabled()) {\n <div\n aria-hidden=\"true\"\n class=\"dropfile\"\n [class.dropfile-border-transparent]=\"showDropZone\"\n (click)=\"inputFile.click()\"\n >\n {{\n multiple()\n ? resolvedDropZoneLabelMultiple()\n : resolvedDropZoneLabel()\n }}\n </div>\n }\n }\n\n <foehn-upload-progress-bar\n [progressBarTriggerHtmlElement]=\"\n inputElement()?.nativeElement || fallBackTrigger\n \"\n />\n</div>\n", styles: [".dropfile{width:300px;border:3px dashed #bbb;text-align:center;margin-top:10px;cursor:pointer;padding:15px 3px}.dropfile-border-transparent{border-color:#fff}.actual-input{display:none}.file-list{margin-top:20px}.icon-button{border:0}.icon-button:hover{cursor:pointer}:host ::ng-deep .svg-inline--fa{color:#000!important}.drop-zone-highlight{outline:3px dashed #bbb}.container-box{border:1px solid #ededed;background-color:#fbfbfb;padding:.5rem}.container-box.vd-form-group-danger{border-left:5px solid var(--vd-danger);padding-left:1rem}\n"] }]
14588
+ }], propDecorators: { uploadUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadUrl", required: false }] }], deleteUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteUrl", required: false }] }], downloadUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadUrl", required: false }] }], optionalLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabelKey", required: false }] }], localUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "localUpload", required: false }] }], maxFileSizeInMo: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSizeInMo", required: false }] }], chooseButtonStyleModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "chooseButtonStyleModifier", required: false }] }], documentDeleted: [{ type: i0.Output, args: ["documentDeleted"] }] } });
14496
14589
 
14497
14590
  class FoehnPictureUploadComponent extends FoehnInputComponent {
14498
14591
  key = input(...(ngDevMode ? [undefined, { debugName: "key" }] : /* istanbul ignore next */ []));
@@ -16022,5 +16115,5 @@ class SdkLog {
16022
16115
  * Generated bundle index. Do not edit.
16023
16116
  */
16024
16117
 
16025
- export { APP_INFO_API_URL, AbstractFoehnUploaderComponent, AbstractListDetailPageComponent, AbstractMenuPageComponent, AbstractPageComponent, AbstractPageFromMenuComponent, ActionStatut, Address, AddressTypeLight, ApplicationInfo, ApplicationInfoService, BAD_PARAMS_HELP_TEXT, BoDocumentError, BoDocumentsWithErrors, BoMultiUploadService, Breadcrumb, BreadcrumbEventService, BreadcrumbItem, CAPTCHA_ERROR_NAME, CURRENCY_REGEXP, Calendar, Canton, Captcha, ChunkLoadErrorHandler, Configuration, Country, CurrencyHelper, CurrentWeek, DECIMALS_SEPARATOR, DEFAULT_INTERNATIONAL_FIX_AND_MOBILE, DEFAULT_INTERNATIONAL_FIX_ONLY, DEFAULT_INTERNATIONAL_MOBILE_ONLY, DEFAULT_PREFIX, DEFAULT_SWISS_FIX_AND_MOBILE, DEFAULT_SWISS_FIX_ONLY, DEFAULT_SWISS_MOBILE_ONLY, DICTIONARY_BASE_URL, DateHelper, DatePickerHelper, DatePickerNavigationHelper, DayMonth, DaySlots, DemandeExpirationService, DemandeHelper, DisplayCurrencyPipe, DisplayDatePipe, District, Document, DocumentError, DocumentReference, DocumentReferenceWithFile, DocumentsWithErrors, DropdownMenuGroup, DropdownMenuItem, EPaymentService, EtapeInfo, FEEDBACK_USAGERS_LOCAL_STORAGE_PREFIX, FORM_SUPPORT_CYBER_TITLE_FALLBACK, FocusedDay, FoehnAbbrComponent, FoehnAgendaComponent, FoehnAgendaNavigationComponent, FoehnAgendaTimeslotPanelComponent, FoehnAutocompleteComponent, FoehnBoMultiUploadComponent, FoehnBooleanCheckboxComponent, FoehnBooleanRadioComponent, FoehnBreadcrumbComponent, FoehnCheckableGroupComponent, FoehnCheckboxComponent, FoehnConfirmModalComponent, FoehnConfirmModalContent, FoehnConfirmModalService, FoehnDateComponent, FoehnDatePickerButtonComponent, FoehnDatePickerComponent, FoehnDateTimeComponent, FoehnDecisionElectroniqueComponent, FoehnDisplayAddressComponent, FoehnDropdownMenuComponent, FoehnErrorPillComponent, FoehnFeedbackNotificationComponent, FoehnFormComponent, FoehnGlobalUploadProgressBarComponent, FoehnHeaderComponent, FoehnHelpModalComponent, FoehnIconCalendarComponent, FoehnIconCheckComponent, FoehnIconCheckSquareOComponent, FoehnIconChevronDownComponent, FoehnIconChevronLeftComponent, FoehnIconChevronRightComponent, FoehnIconChevronUpComponent, FoehnIconClockComponent, FoehnIconCommentDotsComponent, FoehnIconEditComponent, FoehnIconExternalLinkAltComponent, FoehnIconFilePdfComponent, FoehnIconInfoCircleComponent, FoehnIconLockComponent, FoehnIconMapMarkerComponent, FoehnIconMinusCircleComponent, FoehnIconPencilComponent, FoehnIconPlusCircleComponent, FoehnIconPlusSquareComponent, FoehnIconSearchComponent, FoehnIconTimesComponent, FoehnIconTrashAltComponent, FoehnIconUnlockAltComponent, FoehnIconUserComponent, FoehnInputAddressComponent, FoehnInputComponent, FoehnInputEmailComponent, FoehnInputForeignLocalityComponent, FoehnInputForeignStreetComponent, FoehnInputHiddenComponent, FoehnInputNav13Component, FoehnInputNumberComponent, FoehnInputPasswordComponent, FoehnInputPhoneComponent, FoehnInputPrefixedTextComponent, FoehnInputStringComponent, FoehnInputTextComponent, FoehnInputTextareaComponent, FoehnListComponent, FoehnListItem, FoehnListSummaryComponent, FoehnMenuItemComponent, FoehnMenuItemTransmitComponent, FoehnModalComponent, FoehnMultiUploadComponent, FoehnMultiselectAutocompleteComponent, FoehnNavigationComponent, FoehnNavigationService, FoehnNotfoundComponent, FoehnPageComponent, FoehnPageCounterComponent, FoehnPageExpirationTimerComponent, FoehnPageModalComponent, FoehnPageService, FoehnPictureUploadComponent, FoehnRadioComponent, FoehnRecapSectionComponent, FoehnRemainingAlertsSummaryComponent, FoehnSelectComponent, FoehnSimpleNavigationComponent, FoehnSkipLinkComponent, FoehnStatusProgressBarComponent, FoehnTableColumnConfiguration, FoehnTableComponent, FoehnTablePageChangeEvent, FoehnTimeComponent, FoehnTransmitWaitingModalComponent, FoehnTransmitWaitingModalService, FoehnUploadProgressBarComponent, FoehnUserConnectedAsComponent, FoehnValidationAlertSummaryComponent, FoehnValidationAlertsComponent, FooterLink, FormMetadata, FormPostResponse, FormSelectOption, FormatAvsPipe, FormatIdePipe, GESDEM_MAX_DATA_LENGTH, GesdemActionRecoveryLoginComponent, GesdemActionRecoveryRegistrationComponent, GesdemConfirmationComponent, GesdemErrorComponent, GesdemEventService, GesdemHandlerService, GesdemStatutUtils, GlobalUploadProgressService, GrowlBrokerService, GrowlMessage, GrowlType, HTTP_LOADER_FILTERED_URL, I18nForm, IAM_ACV_OIDC_REDIRECT_LOCATION_REGEX, IAM_ACV_REDIRECT_LOCATION_REGEX, IbanFormatterDirective, IdeFormatterDirective, IntervalHelper, LineBreakAsHtmlPipe, Locality, MonthYear, MultiUploadService, Municipality, NDCFormatterDirective, NEVER_CONNECTED, NavigationDirection, NumberCurrencyFormatterDirective, OIDC_ENABLED, ObjectHelper, PORTAIL_BASE_URL_INT, PORTAIL_BASE_URL_PROD, PORTAIL_BASE_URL_VAL, PageChangeEvent, PageUploadLimitService, PaginationWeek, PendingFiles, PendingPaymentComponent, PendingUploadService, PlaceOfOrigin, Portail, PostalLocality, Preferences, RECAPTCHA_API_URL, RecaptchaService, RedirectComponent, RegisterNgModelService, RowElement, SESSION_INFO_API_URL, SWISS_ISO_ID, ScrollHelper, SdkDictionaryPipe, SdkDictionaryService, SdkEpaymentComponent, SdkEvent, SdkEventType, SdkEventsLoggerService, SdkLog, SdkLogLevel, SdkLogsService, SdkRecaptchaComponent, SdkStatisticsService, SelectedSlot, Session, SessionInfo, SessionInfoData, SessionInfoWithApplicationService, Street, StreetNumber, StringHelper, THOUSANDS_SEPARATOR, TRANSMIT_WAITING_MODAL_DELAY_IN_MILLISECONDS, TableSort, UploadProgress, UploadProgressService, UploaderHelper, ValidationHandlerService, formatDecimalCurrency, formatNonDecimalCurrency, formatNumberAsGiven, gesdemLoaderGuard, providePrestationsNgCore, replaceAll };
16118
+ export { APP_INFO_API_URL, AbstractFoehnUploaderComponent, AbstractListDetailPageComponent, AbstractMenuPageComponent, AbstractPageComponent, AbstractPageFromMenuComponent, ActionStatut, Address, AddressTypeLight, ApplicationInfo, ApplicationInfoService, BAD_PARAMS_HELP_TEXT, BoDocumentError, BoDocumentsWithErrors, BoMultiUploadService, Breadcrumb, BreadcrumbEventService, BreadcrumbItem, CAPTCHA_ERROR_NAME, CURRENCY_REGEXP, Calendar, Canton, Captcha, ChunkLoadErrorHandler, Configuration, Country, CurrencyHelper, CurrentWeek, DECIMALS_SEPARATOR, DEFAULT_INTERNATIONAL_FIX_AND_MOBILE, DEFAULT_INTERNATIONAL_FIX_ONLY, DEFAULT_INTERNATIONAL_MOBILE_ONLY, DEFAULT_PREFIX, DEFAULT_SWISS_FIX_AND_MOBILE, DEFAULT_SWISS_FIX_ONLY, DEFAULT_SWISS_MOBILE_ONLY, DICTIONARY_BASE_URL, DateHelper, DatePickerHelper, DatePickerNavigationHelper, DayMonth, DaySlots, DemandeExpirationService, DemandeHelper, DisplayCurrencyPipe, DisplayDatePipe, District, Document, DocumentError, DocumentReference, DocumentReferenceWithFile, DocumentsWithErrors, DropdownMenuGroup, DropdownMenuItem, EPaymentService, EtapeInfo, FEEDBACK_USAGERS_LOCAL_STORAGE_PREFIX, FORM_SUPPORT_CYBER_TITLE_FALLBACK, FocusedDay, FoehnAbbrComponent, FoehnAgendaComponent, FoehnAgendaNavigationComponent, FoehnAgendaTimeslotPanelComponent, FoehnAutocompleteComponent, FoehnBoMultiUploadComponent, FoehnBooleanCheckboxComponent, FoehnBooleanRadioComponent, FoehnBreadcrumbComponent, FoehnCheckableGroupComponent, FoehnCheckboxComponent, FoehnConfirmModalComponent, FoehnConfirmModalContent, FoehnConfirmModalService, FoehnDateComponent, FoehnDatePickerButtonComponent, FoehnDatePickerComponent, FoehnDateTimeComponent, FoehnDecisionElectroniqueComponent, FoehnDisplayAddressComponent, FoehnDropdownMenuComponent, FoehnErrorPillComponent, FoehnFeedbackNotificationComponent, FoehnFormComponent, FoehnGlobalUploadProgressBarComponent, FoehnHeaderComponent, FoehnHelpModalComponent, FoehnIconCalendarComponent, FoehnIconCheckComponent, FoehnIconCheckSquareOComponent, FoehnIconChevronDownComponent, FoehnIconChevronLeftComponent, FoehnIconChevronRightComponent, FoehnIconChevronUpComponent, FoehnIconClockComponent, FoehnIconCommentDotsComponent, FoehnIconEditComponent, FoehnIconExternalLinkAltComponent, FoehnIconFilePdfComponent, FoehnIconInfoCircleComponent, FoehnIconLockComponent, FoehnIconMapMarkerComponent, FoehnIconMinusCircleComponent, FoehnIconPencilComponent, FoehnIconPlusCircleComponent, FoehnIconPlusSquareComponent, FoehnIconSearchComponent, FoehnIconTimesComponent, FoehnIconTrashAltComponent, FoehnIconUnlockAltComponent, FoehnIconUserComponent, FoehnInputAddressComponent, FoehnInputComponent, FoehnInputEmailComponent, FoehnInputForeignLocalityComponent, FoehnInputForeignStreetComponent, FoehnInputHiddenComponent, FoehnInputNav13Component, FoehnInputNumberComponent, FoehnInputPasswordComponent, FoehnInputPhoneComponent, FoehnInputPrefixedTextComponent, FoehnInputStringComponent, FoehnInputTextComponent, FoehnInputTextareaComponent, FoehnListComponent, FoehnListItem, FoehnListSummaryComponent, FoehnMenuItemComponent, FoehnMenuItemTransmitComponent, FoehnModalComponent, FoehnMultiUploadComponent, FoehnMultiselectAutocompleteComponent, FoehnNavigationComponent, FoehnNavigationService, FoehnNotfoundComponent, FoehnPageComponent, FoehnPageCounterComponent, FoehnPageExpirationTimerComponent, FoehnPageModalComponent, FoehnPageService, FoehnPictureUploadComponent, FoehnRadioComponent, FoehnRecapSectionComponent, FoehnRemainingAlertsSummaryComponent, FoehnSelectComponent, FoehnSimpleNavigationComponent, FoehnSkipLinkComponent, FoehnStatusProgressBarComponent, FoehnTableColumnConfiguration, FoehnTableComponent, FoehnTablePageChangeEvent, FoehnTimeComponent, FoehnTransmitWaitingModalComponent, FoehnTransmitWaitingModalService, FoehnUploadProgressBarComponent, FoehnUserConnectedAsComponent, FoehnValidationAlertSummaryComponent, FoehnValidationAlertsComponent, FooterLink, FormMetadata, FormPostResponse, FormSelectOption, FormatAvsPipe, FormatIdePipe, GESDEM_MAX_DATA_LENGTH, GesdemActionRecoveryLoginComponent, GesdemActionRecoveryRegistrationComponent, GesdemConfirmationComponent, GesdemErrorComponent, GesdemEventService, GesdemHandlerService, GesdemStatutUtils, GlobalUploadProgressService, GrowlBrokerService, GrowlMessage, GrowlType, HTTP_LOADER_FILTERED_URL, I18nForm, IAM_ACV_OIDC_REDIRECT_LOCATION_REGEX, IAM_ACV_REDIRECT_LOCATION_REGEX, IbanFormatterDirective, IdeFormatterDirective, IntervalHelper, LineBreakAsHtmlPipe, Locality, MonthYear, MultiUploadService, Municipality, NDCFormatterDirective, NEVER_CONNECTED, NavigationDirection, NumberCurrencyFormatterDirective, OIDC_ENABLED, ObjectHelper, PORTAIL_BASE_URL_INT, PORTAIL_BASE_URL_PROD, PORTAIL_BASE_URL_VAL, PageChangeEvent, PageUploadLimitService, PaginationWeek, PendingFiles, PendingPaymentComponent, PendingUploadService, PlaceOfOrigin, Portail, PostalLocality, Preferences, RECAPTCHA_API_URL, RecaptchaService, RedirectComponent, RegisterNgModelService, RowElement, SESSION_INFO_API_URL, SWISS_ISO_ID, ScrollHelper, SdkDictionaryPipe, SdkDictionaryService, SdkEpaymentComponent, SdkEvent, SdkEventType, SdkEventsLoggerService, SdkLog, SdkLogLevel, SdkLogsService, SdkRecaptchaComponent, SdkStatisticsService, SelectedSlot, Session, SessionInfo, SessionInfoData, SessionInfoWithApplicationService, Street, StreetNumber, StringHelper, THOUSANDS_SEPARATOR, TRANSMIT_WAITING_MODAL_DELAY_IN_MILLISECONDS, TableSort, UploadProgress, UploadProgressService, UploaderHelper, ValidationHandlerService, formatDecimalCurrency, formatNonDecimalCurrency, formatNumberAsGiven, gesdemLoaderGuard, getSafeFileNameForErrorMessage, providePrestationsNgCore, replaceAll, splitDocumentChanges };
16026
16119
  //# sourceMappingURL=dsivd-prestations-ng.mjs.map