@arsedizioni/ars-utils 22.1.5 → 22.5.2

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.
Files changed (78) hide show
  1. package/README.md +158 -10
  2. package/clipper.ui/clipper.scss +564 -0
  3. package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +1 -1
  4. package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
  5. package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +11 -7
  6. package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
  7. package/fesm2022/arsedizioni-ars-utils-core.date.mjs +609 -0
  8. package/fesm2022/arsedizioni-ars-utils-core.date.mjs.map +1 -0
  9. package/fesm2022/arsedizioni-ars-utils-core.markdown.mjs +591 -0
  10. package/fesm2022/arsedizioni-ars-utils-core.markdown.mjs.map +1 -0
  11. package/fesm2022/arsedizioni-ars-utils-core.mjs +270 -1449
  12. package/fesm2022/arsedizioni-ars-utils-core.mjs.map +1 -1
  13. package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +1 -1
  14. package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
  15. package/fesm2022/arsedizioni-ars-utils-support.common.mjs +1 -1
  16. package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
  17. package/fesm2022/arsedizioni-ars-utils-ui.application.mjs +14 -4108
  18. package/fesm2022/arsedizioni-ars-utils-ui.application.mjs.map +1 -1
  19. package/fesm2022/arsedizioni-ars-utils-ui.controls.mjs +962 -0
  20. package/fesm2022/arsedizioni-ars-utils-ui.controls.mjs.map +1 -0
  21. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs +506 -0
  22. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs.map +1 -0
  23. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs +450 -0
  24. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs.map +1 -0
  25. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs +184 -0
  26. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs.map +1 -0
  27. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs +825 -0
  28. package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs.map +1 -0
  29. package/fesm2022/arsedizioni-ars-utils-ui.files.mjs +708 -0
  30. package/fesm2022/arsedizioni-ars-utils-ui.files.mjs.map +1 -0
  31. package/fesm2022/arsedizioni-ars-utils-ui.filters.mjs +426 -0
  32. package/fesm2022/arsedizioni-ars-utils-ui.filters.mjs.map +1 -0
  33. package/fesm2022/arsedizioni-ars-utils-ui.help.mjs +531 -0
  34. package/fesm2022/arsedizioni-ars-utils-ui.help.mjs.map +1 -0
  35. package/fesm2022/arsedizioni-ars-utils-ui.mjs +54 -1227
  36. package/fesm2022/arsedizioni-ars-utils-ui.mjs.map +1 -1
  37. package/fesm2022/arsedizioni-ars-utils-ui.navigation.mjs +1049 -0
  38. package/fesm2022/arsedizioni-ars-utils-ui.navigation.mjs.map +1 -0
  39. package/fesm2022/arsedizioni-ars-utils-ui.notifications.mjs +263 -0
  40. package/fesm2022/arsedizioni-ars-utils-ui.notifications.mjs.map +1 -0
  41. package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs +4 -3
  42. package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs.map +1 -1
  43. package/fesm2022/arsedizioni-ars-utils-ui.paginator.mjs +53 -0
  44. package/fesm2022/arsedizioni-ars-utils-ui.paginator.mjs.map +1 -0
  45. package/fesm2022/arsedizioni-ars-utils-ui.shell.mjs +517 -0
  46. package/fesm2022/arsedizioni-ars-utils-ui.shell.mjs.map +1 -0
  47. package/fesm2022/arsedizioni-ars-utils-ui.tinymce.mjs +246 -0
  48. package/fesm2022/arsedizioni-ars-utils-ui.tinymce.mjs.map +1 -0
  49. package/fesm2022/arsedizioni-ars-utils.mjs +13 -12
  50. package/fesm2022/arsedizioni-ars-utils.mjs.map +1 -1
  51. package/help/package.json +4 -0
  52. package/package.json +80 -14
  53. package/styles/ui.colors.scss +23 -0
  54. package/support.ui/package.json +4 -0
  55. package/tinymce/package.json +4 -0
  56. package/types/arsedizioni-ars-utils-clipper.common.d.ts +1 -2
  57. package/types/arsedizioni-ars-utils-clipper.ui.d.ts +4 -1
  58. package/types/arsedizioni-ars-utils-core.d.ts +684 -1004
  59. package/types/arsedizioni-ars-utils-core.date.d.ts +304 -0
  60. package/types/arsedizioni-ars-utils-core.markdown.d.ts +159 -0
  61. package/types/arsedizioni-ars-utils-ui.application.d.ts +10 -2022
  62. package/types/arsedizioni-ars-utils-ui.controls.d.ts +413 -0
  63. package/types/arsedizioni-ars-utils-ui.d.ts +183 -566
  64. package/types/arsedizioni-ars-utils-ui.dialogs.auth.d.ts +224 -0
  65. package/types/arsedizioni-ars-utils-ui.dialogs.d.ts +228 -0
  66. package/types/arsedizioni-ars-utils-ui.dialogs.prompt.d.ts +47 -0
  67. package/types/arsedizioni-ars-utils-ui.dialogs.select.d.ts +309 -0
  68. package/types/arsedizioni-ars-utils-ui.files.d.ts +271 -0
  69. package/types/arsedizioni-ars-utils-ui.filters.d.ts +163 -0
  70. package/types/arsedizioni-ars-utils-ui.help.d.ts +220 -0
  71. package/types/arsedizioni-ars-utils-ui.navigation.d.ts +650 -0
  72. package/types/arsedizioni-ars-utils-ui.notifications.d.ts +73 -0
  73. package/types/arsedizioni-ars-utils-ui.paginator.d.ts +23 -0
  74. package/types/arsedizioni-ars-utils-ui.shell.d.ts +345 -0
  75. package/types/arsedizioni-ars-utils-ui.tinymce.d.ts +63 -0
  76. package/types/arsedizioni-ars-utils.d.ts +4 -10
  77. package/ui.tinymce/README.md +12 -0
  78. package/ui.tinymce/langs/it.js +466 -0
@@ -0,0 +1,708 @@
1
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
+ import * as i0 from '@angular/core';
3
+ import { viewChild, inject, Renderer2, signal, model, input, output, afterNextRender, Input, Optional, Self, ChangeDetectionStrategy, Component, DestroyRef } from '@angular/core';
4
+ import * as i1 from '@angular/forms';
5
+ import { FormsModule } from '@angular/forms';
6
+ import * as i2 from '@angular/material/form-field';
7
+ import { MatFormFieldModule, MatFormFieldControl } from '@angular/material/form-field';
8
+ import { FileInfo, SystemUtils, FileSizeValidatorDirective, SafeUrlPipe, SafeHtmlPipe } from '@arsedizioni/ars-utils/core';
9
+ import { Subject } from 'rxjs';
10
+ import * as i6 from '@angular/material/tooltip';
11
+ import { MatTooltipModule } from '@angular/material/tooltip';
12
+ import * as i5 from '@angular/material/icon';
13
+ import { MatIconModule } from '@angular/material/icon';
14
+ import * as i2$1 from '@angular/material/button';
15
+ import { MatButtonModule } from '@angular/material/button';
16
+ import * as i3 from '@angular/material/input';
17
+ import { MatInputModule } from '@angular/material/input';
18
+ import * as i1$1 from '@arsedizioni/ars-utils/ui';
19
+ import { UIService, FlexLayoutModule } from '@arsedizioni/ars-utils/ui';
20
+ import { HttpClient, HttpHeaders } from '@angular/common/http';
21
+ import { DialogService } from '@arsedizioni/ars-utils/ui.dialogs';
22
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
23
+ import { MAT_DIALOG_DATA, MatDialogContent, MatDialogActions, MatDialogClose, MatDialogRef, MatDialogTitle } from '@angular/material/dialog';
24
+ import * as i3$1 from '@angular/material/checkbox';
25
+ import { MatCheckboxModule } from '@angular/material/checkbox';
26
+
27
+ class FileInputComponent {
28
+ // Initialize
29
+ static { this.nextId = 0; }
30
+ set value(value) {
31
+ this.setValue(value, true);
32
+ }
33
+ /**
34
+ * Updates the internal state. Form propagation is skipped for model->view
35
+ * writes (writeValue) to avoid the CVA echo loop, and performed for
36
+ * user-driven changes (selectFile/clearFile) and the public value setter.
37
+ * @param value - The new file info to store and display.
38
+ * @param propagate - When `true`, notifies the registered onChange callback.
39
+ */
40
+ setValue(value, propagate) {
41
+ this._value = value;
42
+ if (propagate) {
43
+ this.propagateChange(this._value);
44
+ }
45
+ this.stateChanges.next();
46
+ this.changed.emit(this._value);
47
+ }
48
+ get value() {
49
+ return this._value;
50
+ }
51
+ get size() {
52
+ return this._value?.file?.size;
53
+ }
54
+ get required() {
55
+ return this._required;
56
+ }
57
+ set required(value) {
58
+ this._required = coerceBooleanProperty(value);
59
+ this.stateChanges.next();
60
+ }
61
+ get disabled() {
62
+ if (this.ngControl && this.ngControl.disabled != null) {
63
+ return this.ngControl.disabled;
64
+ }
65
+ return this._disabled;
66
+ }
67
+ set disabled(value) {
68
+ this._disabled = coerceBooleanProperty(value);
69
+ if (this.focused) {
70
+ this.focused = false;
71
+ this.stateChanges.next();
72
+ }
73
+ }
74
+ get placeholder() {
75
+ return this._placeholder();
76
+ }
77
+ set placeholder(value) {
78
+ this._placeholder.set(value);
79
+ this.stateChanges.next();
80
+ }
81
+ get empty() {
82
+ return !this._value || !this._value.file;
83
+ }
84
+ /** True when the control has validation errors and has been touched. */
85
+ get errorState() {
86
+ return (this.ngControl?.errors != null) && (this.ngControl?.touched ?? false);
87
+ }
88
+ /** True when the label should float above the field. */
89
+ get shouldLabelFloat() {
90
+ return this.focused || !this.empty;
91
+ }
92
+ constructor(ngControl) {
93
+ this.ngControl = ngControl;
94
+ /** Reference to the hidden native file input element. */
95
+ this.__file = viewChild.required('__file', /* @ts-ignore */
96
+ ...(ngDevMode ? [{ debugName: "__file" }] : /* istanbul ignore next */ []));
97
+ this.renderer = inject(Renderer2);
98
+ this.uiService = inject(UIService);
99
+ this.stateChanges = new Subject();
100
+ this.controlType = 'file-input';
101
+ this.focused = false;
102
+ /** Whether the device supports camera capture. */
103
+ this.canCapture = signal(false, /* @ts-ignore */
104
+ ...(ngDevMode ? [{ debugName: "canCapture" }] : /* istanbul ignore next */ []));
105
+ /** Size in MB of the currently selected file. */
106
+ this.fileSize = signal(0, /* @ts-ignore */
107
+ ...(ngDevMode ? [{ debugName: "fileSize" }] : /* istanbul ignore next */ []));
108
+ this._placeholder = signal('', /* @ts-ignore */
109
+ ...(ngDevMode ? [{ debugName: "_placeholder" }] : /* istanbul ignore next */ []));
110
+ this._value = new FileInfo();
111
+ this._required = false;
112
+ this._disabled = false;
113
+ /** The currently displayed file name. Can be bound two-way from outside or updated on file selection. */
114
+ this.fileName = model(undefined, /* @ts-ignore */
115
+ ...(ngDevMode ? [{ debugName: "fileName" }] : /* istanbul ignore next */ []));
116
+ this.maxSizeMb = input(5, /* @ts-ignore */
117
+ ...(ngDevMode ? [{ debugName: "maxSizeMb" }] : /* istanbul ignore next */ []));
118
+ this.minSizeMb = input(0, /* @ts-ignore */
119
+ ...(ngDevMode ? [{ debugName: "minSizeMb" }] : /* istanbul ignore next */ []));
120
+ this.isNew = input(false, /* @ts-ignore */
121
+ ...(ngDevMode ? [{ debugName: "isNew" }] : /* istanbul ignore next */ []));
122
+ this.canPreview = input(false, /* @ts-ignore */
123
+ ...(ngDevMode ? [{ debugName: "canPreview" }] : /* istanbul ignore next */ []));
124
+ this.appearance = input(this.uiService.appearance(), /* @ts-ignore */
125
+ ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
126
+ this.accept = input(/* @ts-ignore */
127
+ ...(ngDevMode ? [undefined, { debugName: "accept" }] : /* istanbul ignore next */ []));
128
+ this.id = `${this.controlType}-${FileInputComponent.nextId++}`;
129
+ this.describedBy = '';
130
+ this.changed = output();
131
+ this.download = output();
132
+ this.preview = output();
133
+ this.propagateChange = (_) => { };
134
+ this.propagateTouched = () => { };
135
+ if (this.ngControl != null) {
136
+ this.ngControl.valueAccessor = this;
137
+ }
138
+ // Detect camera availability and set the default placeholder after the first render
139
+ afterNextRender(() => { this.setupDevices(); });
140
+ }
141
+ /**
142
+ * Detects camera availability and updates the placeholder accordingly.
143
+ */
144
+ async setupDevices() {
145
+ this.canCapture.set(false);
146
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
147
+ try {
148
+ const stream = await navigator.mediaDevices.getUserMedia({ video: true });
149
+ if (stream) {
150
+ this.canCapture.set(true);
151
+ }
152
+ }
153
+ catch { }
154
+ }
155
+ if (!this.placeholder || this.placeholder === 'Seleziona file') {
156
+ this._placeholder.set(this.canCapture()
157
+ ? 'Seleziona file o acquisisci con fotocamera'
158
+ : 'Seleziona file');
159
+ }
160
+ }
161
+ ngOnDestroy() {
162
+ this.stateChanges.complete();
163
+ }
164
+ ngDoCheck() {
165
+ this.updateInputDirtyCheck();
166
+ }
167
+ /**
168
+ * Writes a new value to the component (called by the form layer).
169
+ * @param value - The new file info to display.
170
+ */
171
+ writeValue(value) {
172
+ // Model -> view write: must NOT propagate back to the form (echo loop)
173
+ this.setValue(value, false);
174
+ }
175
+ /**
176
+ * Registers the on-change callback (called by the form layer).
177
+ * @param fn - Callback to invoke whenever the value changes.
178
+ */
179
+ registerOnChange(fn) {
180
+ this.propagateChange = fn;
181
+ }
182
+ /**
183
+ * Registers the on-touched callback (called by the form layer).
184
+ * @param fn - Callback to invoke when the control is touched.
185
+ */
186
+ registerOnTouched(fn) {
187
+ this.propagateTouched = fn;
188
+ }
189
+ /**
190
+ * Sets the ARIA describedby attribute from the given element IDs.
191
+ * @param ids - Array of element IDs that describe this control.
192
+ */
193
+ setDescribedByIds(ids) {
194
+ this.describedBy = ids.join(' ');
195
+ }
196
+ /**
197
+ * Updates the disabled state of the underlying native element.
198
+ * @param isDisabled - Whether the control should be disabled.
199
+ */
200
+ setDisabledState(isDisabled) {
201
+ if (!SystemUtils.isBrowser())
202
+ return;
203
+ const elem = document.getElementById(this.id);
204
+ if (elem) {
205
+ this.renderer.setProperty(elem, 'disabled', isDisabled);
206
+ }
207
+ }
208
+ /** Focuses the native input element and marks the control as touched. */
209
+ onContainerClick() {
210
+ if (!this.focused) {
211
+ if (!SystemUtils.isBrowser())
212
+ return;
213
+ const elem = document.getElementById(this.id);
214
+ if (elem) {
215
+ elem.focus();
216
+ this.propagateTouched();
217
+ }
218
+ }
219
+ }
220
+ /**
221
+ * Checks whether the value has changed since the last dirty check and emits `stateChanges` if needed.
222
+ */
223
+ updateInputDirtyCheck() {
224
+ const newValue = this._value;
225
+ if (this.previousNativeValue !== newValue) {
226
+ this.previousNativeValue = newValue;
227
+ this.stateChanges.next();
228
+ }
229
+ }
230
+ /**
231
+ * Handles file selection from the native input element.
232
+ * @param e - The DOM change event from the file input.
233
+ */
234
+ selectFile(e) {
235
+ const input = e.target;
236
+ if (input.files?.length) {
237
+ const f = input.files[0];
238
+ const fileInfo = new FileInfo();
239
+ const fileSizeMb = f.size / 1048576;
240
+ fileInfo.file = f;
241
+ fileInfo.valid =
242
+ (!this.maxSizeMb() || fileSizeMb <= this.maxSizeMb()) &&
243
+ (!this.minSizeMb() || fileSizeMb >= this.minSizeMb());
244
+ this.setValue(fileInfo, true);
245
+ this.fileName.set(f.name);
246
+ this.fileSize.set(Math.round(fileSizeMb));
247
+ }
248
+ }
249
+ /**
250
+ * Checks whether a file is currently selected.
251
+ * @returns `true` if a file is attached to the current value.
252
+ */
253
+ hasFile() {
254
+ return !!(this._value?.file);
255
+ }
256
+ /**
257
+ * Clears the currently selected file and resets the control.
258
+ */
259
+ clearFile() {
260
+ if (this.hasFile()) {
261
+ this.fileName.set(undefined);
262
+ this.fileSize.set(0);
263
+ const fi = new FileInfo();
264
+ fi.file = undefined;
265
+ fi.valid = !this.required;
266
+ this.setValue(fi, true);
267
+ this.__file().nativeElement.value = '';
268
+ }
269
+ }
270
+ /**
271
+ * Emits the `download` output event if the file is not newly added.
272
+ */
273
+ downloadFile() {
274
+ if (!this.isNew())
275
+ this.download.emit();
276
+ }
277
+ /**
278
+ * Emits the `preview` output event if the file is not new and preview is enabled.
279
+ */
280
+ previewFile() {
281
+ if (!this.isNew() && this.canPreview())
282
+ this.preview.emit();
283
+ }
284
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileInputComponent, deps: [{ token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component }); }
285
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: FileInputComponent, isStandalone: true, selector: "file-input", inputs: { required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, maxSizeMb: { classPropertyName: "maxSizeMb", publicName: "maxSizeMb", isSignal: true, isRequired: false, transformFunction: null }, minSizeMb: { classPropertyName: "minSizeMb", publicName: "minSizeMb", isSignal: true, isRequired: false, transformFunction: null }, isNew: { classPropertyName: "isNew", publicName: "isNew", isSignal: true, isRequired: false, transformFunction: null }, canPreview: { classPropertyName: "canPreview", publicName: "canPreview", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fileName: "fileNameChange", changed: "changed", download: "download", preview: "preview" }, host: { properties: { "id": "id", "class.floating": "shouldLabelFloat", "attr.aria-describedBy": "describedBy" } }, providers: [{ provide: MatFormFieldControl, useExisting: FileInputComponent }], viewQueries: [{ propertyName: "__file", first: true, predicate: ["__file"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field style=\"width:100%\" [appearance]=\"appearance()\">\r\n <mat-label>{{placeholder}}</mat-label>\r\n <input type=\"file\" [hidden]=\"true\" [accept]=\"accept()\" (change)=\"selectFile($event)\" #__file />\r\n <input name=\"_fileName\" #_fileName=\"ngModel\" [ngModel]=\"fileName()\" (ngModelChange)=\"fileName.set($event)\" [id]=\"id\" matInput readonly [required]=\"required\"\r\n fileSize [size]=\"fileSize()\" [maxSizeMb]=\"maxSizeMb()\" [minSizeMb]=\"minSizeMb()\" [disabled]=\"disabled\" />\r\n @if (hasFile()) {\r\n <button type=\"button\" tabindex=\"-1\" mat-icon-button matSuffix aria-label=\"Azzera\" (click)=\"clearFile()\" [disabled]=\"disabled\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n @if (!disabled) {\r\n <button type=\"button\" type=\"button\" mat-icon-button matSuffix (click)=\"__file.click()\" aria-label=\"Seleziona file\"\r\n matTooltip=\"Seleziona\" [disabled]=\"disabled\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n @if (!isNew() && canPreview()) {\r\n <button type=\"button\" mat-icon-button matSuffix (click)=\"previewFile()\" aria-label=\"Anteprima\" matTooltip=\"Anteprima\" [disabled]=\"disabled\">\r\n <mat-icon>preview</mat-icon>\r\n </button>\r\n }\r\n @if (!isNew()) {\r\n <button type=\"button\" mat-icon-button matSuffix (click)=\"downloadFile()\" aria-label=\"Scarica file\"\r\n matTooltip=\"Scarica\" [disabled]=\"disabled\">\r\n <mat-icon>save_alt</mat-icon>\r\n </button>\r\n }\r\n @if (hasFile() && fileSize() > 0) {\r\n <mat-hint align=\"start\">{{fileSize()}} MB</mat-hint>\r\n }\r\n @if (hasFile() && fileSize() == 0) {\r\n <mat-hint align=\"start\">\r\n &gt; 1 MB</mat-hint>\r\n } @if (maxSizeMb()) {\r\n <mat-hint align=\"end\">Massimo {{maxSizeMb()}} MB\r\n </mat-hint>\r\n }\r\n @if (_fileName.invalid && !hasFile()) {\r\n <mat-error>Obbligatorio.</mat-error>\r\n }\r\n @if (_fileName.invalid && hasFile()) {\r\n <mat-error>Dimensione non consentita.</mat-error>\r\n }\r\n</mat-form-field>", styles: [""], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: FileSizeValidatorDirective, selector: "[fileSize]", inputs: ["maxSizeMb", "minSizeMb", "size"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
286
+ }
287
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileInputComponent, decorators: [{
288
+ type: Component,
289
+ args: [{ selector: 'file-input', providers: [{ provide: MatFormFieldControl, useExisting: FileInputComponent }], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatFormFieldModule, MatInputModule, FormsModule, FileSizeValidatorDirective, MatButtonModule,
290
+ MatIconModule, MatTooltipModule], host: {
291
+ '[id]': 'id',
292
+ '[class.floating]': 'shouldLabelFloat',
293
+ '[attr.aria-describedBy]': 'describedBy',
294
+ }, template: "<mat-form-field style=\"width:100%\" [appearance]=\"appearance()\">\r\n <mat-label>{{placeholder}}</mat-label>\r\n <input type=\"file\" [hidden]=\"true\" [accept]=\"accept()\" (change)=\"selectFile($event)\" #__file />\r\n <input name=\"_fileName\" #_fileName=\"ngModel\" [ngModel]=\"fileName()\" (ngModelChange)=\"fileName.set($event)\" [id]=\"id\" matInput readonly [required]=\"required\"\r\n fileSize [size]=\"fileSize()\" [maxSizeMb]=\"maxSizeMb()\" [minSizeMb]=\"minSizeMb()\" [disabled]=\"disabled\" />\r\n @if (hasFile()) {\r\n <button type=\"button\" tabindex=\"-1\" mat-icon-button matSuffix aria-label=\"Azzera\" (click)=\"clearFile()\" [disabled]=\"disabled\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n }\r\n @if (!disabled) {\r\n <button type=\"button\" type=\"button\" mat-icon-button matSuffix (click)=\"__file.click()\" aria-label=\"Seleziona file\"\r\n matTooltip=\"Seleziona\" [disabled]=\"disabled\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n @if (!isNew() && canPreview()) {\r\n <button type=\"button\" mat-icon-button matSuffix (click)=\"previewFile()\" aria-label=\"Anteprima\" matTooltip=\"Anteprima\" [disabled]=\"disabled\">\r\n <mat-icon>preview</mat-icon>\r\n </button>\r\n }\r\n @if (!isNew()) {\r\n <button type=\"button\" mat-icon-button matSuffix (click)=\"downloadFile()\" aria-label=\"Scarica file\"\r\n matTooltip=\"Scarica\" [disabled]=\"disabled\">\r\n <mat-icon>save_alt</mat-icon>\r\n </button>\r\n }\r\n @if (hasFile() && fileSize() > 0) {\r\n <mat-hint align=\"start\">{{fileSize()}} MB</mat-hint>\r\n }\r\n @if (hasFile() && fileSize() == 0) {\r\n <mat-hint align=\"start\">\r\n &gt; 1 MB</mat-hint>\r\n } @if (maxSizeMb()) {\r\n <mat-hint align=\"end\">Massimo {{maxSizeMb()}} MB\r\n </mat-hint>\r\n }\r\n @if (_fileName.invalid && !hasFile()) {\r\n <mat-error>Obbligatorio.</mat-error>\r\n }\r\n @if (_fileName.invalid && hasFile()) {\r\n <mat-error>Dimensione non consentita.</mat-error>\r\n }\r\n</mat-form-field>" }]
295
+ }], ctorParameters: () => [{ type: i1.NgControl, decorators: [{
296
+ type: Optional
297
+ }, {
298
+ type: Self
299
+ }] }], propDecorators: { __file: [{ type: i0.ViewChild, args: ['__file', { isSignal: true }] }], required: [{
300
+ type: Input
301
+ }], disabled: [{
302
+ type: Input
303
+ }], placeholder: [{
304
+ type: Input
305
+ }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }, { type: i0.Output, args: ["fileNameChange"] }], maxSizeMb: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSizeMb", required: false }] }], minSizeMb: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSizeMb", required: false }] }], isNew: [{ type: i0.Input, args: [{ isSignal: true, alias: "isNew", required: false }] }], canPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "canPreview", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], download: [{ type: i0.Output, args: ["download"] }], preview: [{ type: i0.Output, args: ["preview"] }] } });
306
+
307
+ class FilePreviewComponent {
308
+ constructor() {
309
+ this.iframe = viewChild('iframe', /* @ts-ignore */
310
+ ...(ngDevMode ? [{ debugName: "iframe" }] : /* istanbul ignore next */ []));
311
+ this.httpClient = inject(HttpClient);
312
+ this.dialogService = inject(DialogService);
313
+ this.dialogData = inject(MAT_DIALOG_DATA) ?? {};
314
+ this.url = signal(null, /* @ts-ignore */
315
+ ...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
316
+ // Revoke the blob object URL on destroy: createObjectURL keeps the whole
317
+ // downloaded blob alive until revoked — repeated previews leaked memory.
318
+ inject(DestroyRef).onDestroy(() => {
319
+ const u = this.url();
320
+ if (u?.startsWith('blob:'))
321
+ URL.revokeObjectURL(u);
322
+ });
323
+ const data = this.dialogData;
324
+ if (!data?.url)
325
+ return;
326
+ if (!data.embed) {
327
+ this.dialogService.setBusy('Download in corso...');
328
+ this.httpClient.get(data.url, {
329
+ headers: data.authToken
330
+ ? new HttpHeaders().set('Authorization', data.authToken)
331
+ : new HttpHeaders(),
332
+ responseType: 'blob'
333
+ })
334
+ .pipe(takeUntilDestroyed())
335
+ .subscribe({
336
+ next: (res) => {
337
+ this.url.set(URL.createObjectURL(res));
338
+ this.dialogService.clearBusy();
339
+ },
340
+ error: () => {
341
+ this.dialogService.clearBusy();
342
+ }
343
+ });
344
+ }
345
+ else {
346
+ this.url.set('https://view.officeapps.live.com/op/embed.aspx?src=' + encodeURIComponent(data.url));
347
+ }
348
+ }
349
+ /**
350
+ * Handles the iframe load event: scrolls to the top and centers a single image when present.
351
+ */
352
+ loaded() {
353
+ const iframe = this.iframe()?.nativeElement;
354
+ if (!iframe) {
355
+ return;
356
+ }
357
+ try {
358
+ iframe.contentWindow?.scrollTo(0, 0);
359
+ // Resize and center single image
360
+ if (!this.dialogData?.embed && iframe.contentDocument) {
361
+ const images = iframe.contentDocument.querySelectorAll('img') || [];
362
+ if (images.length === 1) {
363
+ Object.assign(images[0].style, {
364
+ position: 'absolute',
365
+ top: '50%',
366
+ left: '50%',
367
+ transform: 'translate(-50%, -50%)',
368
+ maxWidth: images[0].style.maxWidth || '100%',
369
+ maxHeight: images[0].style.maxHeight || '100%'
370
+ });
371
+ const iframeBody = iframe.contentDocument.body;
372
+ if (iframeBody && !iframeBody.style.height) {
373
+ iframeBody.style.height = '100%';
374
+ }
375
+ }
376
+ }
377
+ }
378
+ catch (e) {
379
+ console.error('Impossibile accedere al contenuto dell\'iframe:', e);
380
+ }
381
+ }
382
+ /**
383
+ * Opens the current file URL in a new browser tab for manual download.
384
+ */
385
+ download() {
386
+ const currentUrl = this.url();
387
+ if (currentUrl) {
388
+ window.open(currentUrl, '_blank');
389
+ }
390
+ }
391
+ /**
392
+ * Displays a help dialog with browser-specific instructions for enabling PDF preview.
393
+ */
394
+ troubles() {
395
+ this.dialogService.info("<p>Se non riesci a visualizzare l'anteprima dei file PDF probabilmente devi abilitare un'impostazione del tuo browser.</p>" +
396
+ "<b>Per Google Chrome</b><br>" +
397
+ "<p class='small' style='padding-left:10px'><i>impostazioni > privacy e sicurezza > impostazioni sito > documenti PDF</i></p>" +
398
+ "<b>Per Microsoft Edge</b><br>" +
399
+ "<p class='small' style='padding-left:10px'><i>impostazioni > cookie e autorizzazioni sito > documenti PDF</i></p>" +
400
+ "<b>Per Mozilla Firefox</b><br>" +
401
+ "<p class='small' style='padding-left:10px'><i>impostazioni > generale > applicazioni</i></p>" +
402
+ "<b>Altri browser</b><br>" +
403
+ "<p class='small' style='padding-left:10px'>Fate riferimento alla documentazione specifica del vostro browser.</p>", "Problemi con le anteprime dei file PDF?");
404
+ }
405
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FilePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
406
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: FilePreviewComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "iframe", first: true, predicate: ["iframe"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-dialog-content class=\"file-preview\" id=\"file-preview-scrollable\">\r\n <div class=\"content\">\r\n @if (!url()) {\r\n <div class=\"loading\">Caricamento in corso...</div>\r\n } @else {\r\n <iframe class=\"iframe\" #iframe (load)=\"loaded()\" [src]=\"url() | safeUrl\"></iframe>\r\n }\r\n </div>\r\n</mat-dialog-content>\r\n<mat-dialog-actions id=\"file-preview-fixed\">\r\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\" fxLayoutGap=\"10px\" fxFill>\r\n <div fxFlex=\"50\">\r\n <button mat-stroked-button (click)=\"troubles()\"\r\n matTooltip=\"Fai click se non riesci a visualizzare l'anteprima dei file PDF\">Problemi con i PDF?</button>\r\n </div>\r\n <div fxFlex=\"50\" fxLayoutAlign=\"end\">\r\n <button mat-stroked-button (click)=\"download()\">Scarica</button>\r\n <button mat-stroked-button [mat-dialog-close]=\"true\" >Chiudi</button>\r\n </div>\r\n </div>\r\n</mat-dialog-actions>", styles: [".file-preview{padding:0}.file-preview .content{height:100%;width:100%;overflow:hidden;background-color:var(--ars-filepreview-content-background-color, #f7faf8)}.file-preview .content .loading{animation:blinker 2s linear infinite;font-size:x-large;color:var(--ars-color-text, #191c1b);width:100%;height:100%;padding:20px}.file-preview .content .iframe{width:100%;height:100%;border:0;background-color:var(--ars-filepreview-content-background-color, #f7faf8)!important}@keyframes blinker{50%{opacity:0}}.mat-mdc-dialog-content{max-height:unset!important;padding:0!important}\n"], dependencies: [{ kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: FlexLayoutModule }, { kind: "directive", type: i1$1.FxLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg] ", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg] ", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg] ", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg] ", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexFillDirective, selector: " [fxFlexFill], [fxFill], [fxFlexFill.xs], [fxFlexFill.sm], [fxFlexFill.md], [fxFlexFill.lg], [fxFlexFill.xl], [fxFlexFill.lt-sm], [fxFlexFill.lt-md], [fxFlexFill.lt-lg], [fxFlexFill.lt-xl], [fxFlexFill.gt-xs], [fxFlexFill.gt-sm], [fxFlexFill.gt-md], [fxFlexFill.gt-lg] ", inputs: ["fxFlexFill", "fxFill", "fxFlexFill.xs", "fxFlexFill.sm", "fxFlexFill.md", "fxFlexFill.lg", "fxFlexFill.xl", "fxFlexFill.lt-sm", "fxFlexFill.lt-md", "fxFlexFill.lt-lg", "fxFlexFill.lt-xl", "fxFlexFill.gt-xs", "fxFlexFill.gt-sm", "fxFlexFill.gt-md", "fxFlexFill.gt-lg"] }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "pipe", type: SafeUrlPipe, name: "safeUrl" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
407
+ }
408
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FilePreviewComponent, decorators: [{
409
+ type: Component,
410
+ args: [{ standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatDialogContent, FlexLayoutModule, MatDialogActions, MatButtonModule, MatTooltipModule,
411
+ MatDialogClose, SafeUrlPipe], template: "<mat-dialog-content class=\"file-preview\" id=\"file-preview-scrollable\">\r\n <div class=\"content\">\r\n @if (!url()) {\r\n <div class=\"loading\">Caricamento in corso...</div>\r\n } @else {\r\n <iframe class=\"iframe\" #iframe (load)=\"loaded()\" [src]=\"url() | safeUrl\"></iframe>\r\n }\r\n </div>\r\n</mat-dialog-content>\r\n<mat-dialog-actions id=\"file-preview-fixed\">\r\n <div fxLayout=\"row\" fxLayoutAlign=\"start center\" fxLayoutGap=\"10px\" fxFill>\r\n <div fxFlex=\"50\">\r\n <button mat-stroked-button (click)=\"troubles()\"\r\n matTooltip=\"Fai click se non riesci a visualizzare l'anteprima dei file PDF\">Problemi con i PDF?</button>\r\n </div>\r\n <div fxFlex=\"50\" fxLayoutAlign=\"end\">\r\n <button mat-stroked-button (click)=\"download()\">Scarica</button>\r\n <button mat-stroked-button [mat-dialog-close]=\"true\" >Chiudi</button>\r\n </div>\r\n </div>\r\n</mat-dialog-actions>", styles: [".file-preview{padding:0}.file-preview .content{height:100%;width:100%;overflow:hidden;background-color:var(--ars-filepreview-content-background-color, #f7faf8)}.file-preview .content .loading{animation:blinker 2s linear infinite;font-size:x-large;color:var(--ars-color-text, #191c1b);width:100%;height:100%;padding:20px}.file-preview .content .iframe{width:100%;height:100%;border:0;background-color:var(--ars-filepreview-content-background-color, #f7faf8)!important}@keyframes blinker{50%{opacity:0}}.mat-mdc-dialog-content{max-height:unset!important;padding:0!important}\n"] }]
412
+ }], ctorParameters: () => [], propDecorators: { iframe: [{ type: i0.ViewChild, args: ['iframe', { isSignal: true }] }] } });
413
+
414
+ class SelectFileDialogComponent {
415
+ constructor() {
416
+ this.done = output();
417
+ this.dialogService = inject(DialogService);
418
+ this.dialogRef = inject((MatDialogRef));
419
+ this.dialogData = signal(inject(MAT_DIALOG_DATA) ?? {}, /* @ts-ignore */
420
+ ...(ngDevMode ? [{ debugName: "dialogData" }] : /* istanbul ignore next */ []));
421
+ this.file = signal(undefined, /* @ts-ignore */
422
+ ...(ngDevMode ? [{ debugName: "file" }] : /* istanbul ignore next */ []));
423
+ this.fileClass = signal('selectfile-file', /* @ts-ignore */
424
+ ...(ngDevMode ? [{ debugName: "fileClass" }] : /* istanbul ignore next */ []));
425
+ }
426
+ /**
427
+ * Handles the native file input change event and delegates to `selectFile`.
428
+ * @param e - The DOM change event from the file input.
429
+ */
430
+ update(e) {
431
+ const input = e.target;
432
+ if (input.files?.length) {
433
+ this.selectFile(input.files[0]);
434
+ }
435
+ }
436
+ /**
437
+ * Validates and sets the selected file, showing an error if size or type constraints are violated.
438
+ * @param file - The `File` object to validate and store.
439
+ */
440
+ selectFile(file) {
441
+ const data = this.dialogData();
442
+ const maxSize = data.maxSize ?? 0;
443
+ if (maxSize > 0) {
444
+ const size = file.size / 1048576;
445
+ if (size > maxSize) {
446
+ this.dialogService.error(`File troppo grande (massimo ${SystemUtils.formatFileSize(maxSize * 1048576)})`);
447
+ return;
448
+ }
449
+ }
450
+ if (data.accept) {
451
+ const accept = data.accept.toLowerCase();
452
+ const a = file.name.split('.').pop()?.toLowerCase();
453
+ let b = file.type.toLowerCase();
454
+ if (b.startsWith('image/') && accept.includes('image/*')) {
455
+ b = 'image/*';
456
+ }
457
+ else if (b.startsWith('video/') && accept.includes('video/*')) {
458
+ b = 'video/*';
459
+ }
460
+ else if (b.startsWith('audio/') && accept.includes('audio/*')) {
461
+ b = 'audio/*';
462
+ }
463
+ if (!accept.includes(a ?? '') && !accept.includes(b)) {
464
+ this.dialogService.error(`Sono accettati solo questi tipi di file: ${accept}`);
465
+ return;
466
+ }
467
+ }
468
+ this.file.set(file);
469
+ }
470
+ /**
471
+ * Formats a byte count into a human-readable size string.
472
+ * @param size - File size in bytes.
473
+ * @returns A formatted size string (e.g. "1.2 MB").
474
+ */
475
+ size(size) {
476
+ return SystemUtils.formatFileSize(size);
477
+ }
478
+ /** Emits the selected file and options, then closes the dialog. */
479
+ ok() {
480
+ this.done.emit({ file: this.file(), options: this.dialogData().options });
481
+ setTimeout(() => {
482
+ this.dialogRef.close();
483
+ }, 500);
484
+ }
485
+ /** Highlights the drop zone when a drag enters the area.
486
+ * @param e - The drag event.
487
+ */
488
+ onDragOver(e) {
489
+ this.fileClass.set('selectfile-file-drop');
490
+ e.preventDefault();
491
+ }
492
+ /** Highlights the drop zone when a dragged item enters.
493
+ * @param e - The drag event.
494
+ */
495
+ onDragEnter(e) {
496
+ this.fileClass.set('selectfile-file-drop');
497
+ e.preventDefault();
498
+ }
499
+ /** Resets the drop zone style when dragging ends.
500
+ * @param e - The drag event.
501
+ */
502
+ onDragEnd(e) {
503
+ this.fileClass.set('selectfile-file');
504
+ e.preventDefault();
505
+ }
506
+ /** Resets the drop zone style when a dragged item leaves the area.
507
+ * @param e - The drag event.
508
+ */
509
+ onDragLeave(e) {
510
+ this.fileClass.set('selectfile-file');
511
+ e.preventDefault();
512
+ }
513
+ /**
514
+ * Handles a file drop event, extracting and processing the dropped files.
515
+ * @param e - The drop event.
516
+ */
517
+ onDrop(e) {
518
+ this.fileClass.set('selectfile-file');
519
+ e.preventDefault();
520
+ e.stopPropagation();
521
+ if (e.dataTransfer?.files?.length) {
522
+ this.addFiles(e.dataTransfer.files);
523
+ }
524
+ }
525
+ /**
526
+ * Picks the first file from the list and passes it to `selectFile`.
527
+ * @param files - The `FileList` from the drag-and-drop event.
528
+ */
529
+ addFiles(files) {
530
+ if (files.length > 0) {
531
+ this.selectFile(files[0]);
532
+ }
533
+ }
534
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SelectFileDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
535
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SelectFileDialogComponent, isStandalone: true, selector: "ng-component", outputs: { done: "done" }, ngImport: i0, template: "<div mat-dialog-title [innerHTML]=\"dialogData().title | safeHtml\"></div>\n@if (dialogData().description) {\n<div class=\"selectfile-description\" [innerHtml]=\"dialogData().description | safeHtml\"></div>\n}\n<mat-dialog-content class=\"dialog-content\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"*\" [class]=\"fileClass()\" (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" (dragenter)=\"onDragEnter($event)\" (dragend)=\"onDragEnd($event)\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"10px\" fxFlexAlign=\"start\" class=\"x-small secondary\"><i>Trascina qui il file o selezionalo</i></div>\n <div>\n <input #_file type=\"file\" [accept]=\"dialogData().accept\" [hidden]=\"true\" (change)=\"update($event)\" />\n <button type=\"button\" mat-stroked-button (click)=\"_file.click()\">Seleziona file...</button>\n </div>\n @if (file()) {\n <div style=\"padding:0 24px\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxFill>\n <div class=\"small accent bold\"><i>{{file().name}}</i></div>\n <div class=\"small\">Dimensioni: <i>{{size(file().size)}}</i></div>\n </div>\n </div>\n }\n </div>\n </div>\n @if (dialogData().options) {\n <div style=\"padding-bottom: 24px;\">\n @for (o of dialogData().options; track o; let i = $index) {\n <div>\n <mat-checkbox (change)=\"o.selected = $event.checked\" [checked]=\"o.selected === true\" name=\"opt_{{i}}\" >\n {{o.description}}\n </mat-checkbox>\n </div>\n }\n </div>\n }\n </div>\n</mat-dialog-content>\n<mat-dialog-actions>\n <div fxLayout=\"row\" fxLayoutGap=\"10px\" fxFill>\n <div fxFlex=\"50\">\n @if (dialogData().helpLink) {\n <a mat-stroked-button href=\"{{dialogData().helpLink}}\" target=\"_blank\">{{dialogData().helpCaption}}</a>\n }\n </div>\n <div fxFlex=\"50\" fxLayoutAlign=\"end\">\n <button mat-flat-button (click)=\"ok()\" [disabled]=\"!file()\">{{dialogData().okCaption}}</button>\n <button mat-stroked-button [mat-dialog-close]=\"true\">Annulla</button>\n </div>\n </div>\n</mat-dialog-actions>", styles: [".fill,.wide{min-width:100%!important;max-width:100%!important;width:100%!important}.dialog-info{font-size:x-small;font-weight:700;text-align:right;padding:10px}.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #388E3C)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #a80710)}.dialog-header{padding-bottom:20px}.dialog-toolbar{padding:0 5px 0 24px;height:48px;min-height:48px}.dialog-close{margin-right:5px;margin-top:0}.dialog-menu{margin-left:10px;margin-top:10px}.dialog-title{padding:0 24px}.section-title{font-size:large;font-weight:600;padding-top:10px;padding-bottom:8px}.center{text-align:center}.fill{min-height:100%!important;max-height:100%!important;height:100%!important}.scroll-auto{overflow:auto;height:100%}.scroll-hidden{overflow:hidden;height:100%}b{font-weight:700}.large{font-size:large!important;line-height:1.2!important}.smaller{font-size:smaller!important;line-height:1.2!important}.small{font-size:small!important;line-height:1.2!important}.small-icon-button{width:1.5rem!important;height:1.5rem!important;padding:0!important;display:inline-flex!important;align-items:center;justify-content:center}.small-icon-button .mat-mdc-button-touch-target{width:1.5rem!important;height:1.5rem!important}.x-small{font-size:x-small!important;line-height:1.2!important}.bold{font-weight:700}.uppercase{text-transform:uppercase!important}.lowercase{text-transform:lowercase!important}.truncated{min-width:0;max-width:100%}@supports (-webkit-line-clamp: 2){.truncated{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.truncated span,.truncated div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@supports (-webkit-line-clamp: 2){.truncated span,.truncated div{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.clipped{min-width:0;max-width:100%}.clipped span,.clipped div{white-space:nowrap;overflow:hidden;text-overflow:clip}.accent{color:var(--ars-color-accent, #7894ae)!important}.primary{color:var(--ars-color-primary, #00a293)!important}.secondary{color:var(--ars-color-secondary, #4a635f)!important}.error{color:var(--ars-color-error, #ff5449)!important}.success{color:var(--ars-color-ok, #388E3C)!important}.warning{color:var(--ars-color-warning, #FFC107)!important}.text{color:var(--ars-color-text, #191c1b)!important}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;background-color:var(--ars-color-overlay, rgba(255, 255, 255, .75))}.drawer-content{padding-top:10px}.drawer .title-container,.drawer .title-container-with-loader,.drawer-small .title-container,.drawer-small .title-container-with-loader{padding-right:5px;padding-bottom:20px;padding-left:0}.drawer .title-container,.drawer-small .title-container{padding-top:20px}.drawer .title-container-with-loader,.drawer-small .title-container-with-loader{padding-top:14px}.drawer .title,.drawer-small .title{font-size:19.2px!important;font-weight:600;padding-left:15px;min-width:150px;width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.drawer .accordion-panel,.drawer-small .accordion-panel{background-color:transparent!important}.drawer .accordion-header,.drawer-small .accordion-header{padding-left:10px;padding-right:10px;border-radius:var(--mat-expansion-container-shape)}.drawer .mat-expansion-panel-body,.drawer-small .mat-expansion-panel-body{padding-left:10px!important;padding-right:10px!important;padding-bottom:20px!important}@media screen and (min-width:0px)and (max-width:430px){.drawer,.drawer-small{border-radius:0!important;min-width:100%!important;max-width:100%!important}}@media screen and (min-width:431px){.drawer{min-width:420px!important;max-width:420px!important}.drawer .title{min-width:200px}.drawer .mat-expansion-panel-body{padding-left:15px!important;padding-right:15px!important;padding-bottom:20px!important}.drawer-small{min-width:360px!important;max-width:360px!important}}.drawer-with-loader{padding-top:0!important}.drawer-transparent{background-color:transparent}.fade-in{animation:fadein .5s linear}@keyframes fadein{0%{opacity:0}to{opacity:1}}.bright{filter:brightness(.7)!important}@media(prefers-color-scheme:dark){.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #4CAF50)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #ff5449)}b,.bold{font-weight:600}.bright{filter:brightness(1.5)!important}}.selectfile-file,.selectfile-file-drop{padding:4px 4px 24px;width:80%;border:5px dotted var(--ars-color-divider, #757d87)!important}.selectfile-file-drop{border:5px dotted var(--ars-color-accent, #7894ae)!important}.selectfile-description{padding:0 24px 24px}.dialog-content{padding:0 24px 24px!important}\n"], dependencies: [{ kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: FlexLayoutModule }, { kind: "directive", type: i1$1.FxLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg] ", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg] ", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg] ", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg] ", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexAlignDirective, selector: " [fxFlexAlign], [fxFlexAlign.xs], [fxFlexAlign.sm], [fxFlexAlign.md], [fxFlexAlign.lg], [fxFlexAlign.xl], [fxFlexAlign.lt-sm], [fxFlexAlign.lt-md], [fxFlexAlign.lt-lg], [fxFlexAlign.lt-xl], [fxFlexAlign.gt-xs], [fxFlexAlign.gt-sm], [fxFlexAlign.gt-md], [fxFlexAlign.gt-lg] ", inputs: ["fxFlexAlign", "fxFlexAlign.xs", "fxFlexAlign.sm", "fxFlexAlign.md", "fxFlexAlign.lg", "fxFlexAlign.xl", "fxFlexAlign.lt-sm", "fxFlexAlign.lt-md", "fxFlexAlign.lt-lg", "fxFlexAlign.lt-xl", "fxFlexAlign.gt-xs", "fxFlexAlign.gt-sm", "fxFlexAlign.gt-md", "fxFlexAlign.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexFillDirective, selector: " [fxFlexFill], [fxFill], [fxFlexFill.xs], [fxFlexFill.sm], [fxFlexFill.md], [fxFlexFill.lg], [fxFlexFill.xl], [fxFlexFill.lt-sm], [fxFlexFill.lt-md], [fxFlexFill.lt-lg], [fxFlexFill.lt-xl], [fxFlexFill.gt-xs], [fxFlexFill.gt-sm], [fxFlexFill.gt-md], [fxFlexFill.gt-lg] ", inputs: ["fxFlexFill", "fxFill", "fxFlexFill.xs", "fxFlexFill.sm", "fxFlexFill.md", "fxFlexFill.lg", "fxFlexFill.xl", "fxFlexFill.lt-sm", "fxFlexFill.lt-md", "fxFlexFill.lt-lg", "fxFlexFill.lt-xl", "fxFlexFill.gt-xs", "fxFlexFill.gt-sm", "fxFlexFill.gt-md", "fxFlexFill.gt-lg"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
536
+ }
537
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SelectFileDialogComponent, decorators: [{
538
+ type: Component,
539
+ args: [{ standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatDialogTitle, MatDialogContent, FlexLayoutModule, MatButtonModule, MatCheckboxModule, FormsModule,
540
+ MatDialogActions, MatDialogClose, SafeHtmlPipe], template: "<div mat-dialog-title [innerHTML]=\"dialogData().title | safeHtml\"></div>\n@if (dialogData().description) {\n<div class=\"selectfile-description\" [innerHtml]=\"dialogData().description | safeHtml\"></div>\n}\n<mat-dialog-content class=\"dialog-content\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"*\" [class]=\"fileClass()\" (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" (dragenter)=\"onDragEnter($event)\" (dragend)=\"onDragEnd($event)\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"10px\" fxFlexAlign=\"start\" class=\"x-small secondary\"><i>Trascina qui il file o selezionalo</i></div>\n <div>\n <input #_file type=\"file\" [accept]=\"dialogData().accept\" [hidden]=\"true\" (change)=\"update($event)\" />\n <button type=\"button\" mat-stroked-button (click)=\"_file.click()\">Seleziona file...</button>\n </div>\n @if (file()) {\n <div style=\"padding:0 24px\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxFill>\n <div class=\"small accent bold\"><i>{{file().name}}</i></div>\n <div class=\"small\">Dimensioni: <i>{{size(file().size)}}</i></div>\n </div>\n </div>\n }\n </div>\n </div>\n @if (dialogData().options) {\n <div style=\"padding-bottom: 24px;\">\n @for (o of dialogData().options; track o; let i = $index) {\n <div>\n <mat-checkbox (change)=\"o.selected = $event.checked\" [checked]=\"o.selected === true\" name=\"opt_{{i}}\" >\n {{o.description}}\n </mat-checkbox>\n </div>\n }\n </div>\n }\n </div>\n</mat-dialog-content>\n<mat-dialog-actions>\n <div fxLayout=\"row\" fxLayoutGap=\"10px\" fxFill>\n <div fxFlex=\"50\">\n @if (dialogData().helpLink) {\n <a mat-stroked-button href=\"{{dialogData().helpLink}}\" target=\"_blank\">{{dialogData().helpCaption}}</a>\n }\n </div>\n <div fxFlex=\"50\" fxLayoutAlign=\"end\">\n <button mat-flat-button (click)=\"ok()\" [disabled]=\"!file()\">{{dialogData().okCaption}}</button>\n <button mat-stroked-button [mat-dialog-close]=\"true\">Annulla</button>\n </div>\n </div>\n</mat-dialog-actions>", styles: [".fill,.wide{min-width:100%!important;max-width:100%!important;width:100%!important}.dialog-info{font-size:x-small;font-weight:700;text-align:right;padding:10px}.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #388E3C)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #a80710)}.dialog-header{padding-bottom:20px}.dialog-toolbar{padding:0 5px 0 24px;height:48px;min-height:48px}.dialog-close{margin-right:5px;margin-top:0}.dialog-menu{margin-left:10px;margin-top:10px}.dialog-title{padding:0 24px}.section-title{font-size:large;font-weight:600;padding-top:10px;padding-bottom:8px}.center{text-align:center}.fill{min-height:100%!important;max-height:100%!important;height:100%!important}.scroll-auto{overflow:auto;height:100%}.scroll-hidden{overflow:hidden;height:100%}b{font-weight:700}.large{font-size:large!important;line-height:1.2!important}.smaller{font-size:smaller!important;line-height:1.2!important}.small{font-size:small!important;line-height:1.2!important}.small-icon-button{width:1.5rem!important;height:1.5rem!important;padding:0!important;display:inline-flex!important;align-items:center;justify-content:center}.small-icon-button .mat-mdc-button-touch-target{width:1.5rem!important;height:1.5rem!important}.x-small{font-size:x-small!important;line-height:1.2!important}.bold{font-weight:700}.uppercase{text-transform:uppercase!important}.lowercase{text-transform:lowercase!important}.truncated{min-width:0;max-width:100%}@supports (-webkit-line-clamp: 2){.truncated{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.truncated span,.truncated div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@supports (-webkit-line-clamp: 2){.truncated span,.truncated div{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.clipped{min-width:0;max-width:100%}.clipped span,.clipped div{white-space:nowrap;overflow:hidden;text-overflow:clip}.accent{color:var(--ars-color-accent, #7894ae)!important}.primary{color:var(--ars-color-primary, #00a293)!important}.secondary{color:var(--ars-color-secondary, #4a635f)!important}.error{color:var(--ars-color-error, #ff5449)!important}.success{color:var(--ars-color-ok, #388E3C)!important}.warning{color:var(--ars-color-warning, #FFC107)!important}.text{color:var(--ars-color-text, #191c1b)!important}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;background-color:var(--ars-color-overlay, rgba(255, 255, 255, .75))}.drawer-content{padding-top:10px}.drawer .title-container,.drawer .title-container-with-loader,.drawer-small .title-container,.drawer-small .title-container-with-loader{padding-right:5px;padding-bottom:20px;padding-left:0}.drawer .title-container,.drawer-small .title-container{padding-top:20px}.drawer .title-container-with-loader,.drawer-small .title-container-with-loader{padding-top:14px}.drawer .title,.drawer-small .title{font-size:19.2px!important;font-weight:600;padding-left:15px;min-width:150px;width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.drawer .accordion-panel,.drawer-small .accordion-panel{background-color:transparent!important}.drawer .accordion-header,.drawer-small .accordion-header{padding-left:10px;padding-right:10px;border-radius:var(--mat-expansion-container-shape)}.drawer .mat-expansion-panel-body,.drawer-small .mat-expansion-panel-body{padding-left:10px!important;padding-right:10px!important;padding-bottom:20px!important}@media screen and (min-width:0px)and (max-width:430px){.drawer,.drawer-small{border-radius:0!important;min-width:100%!important;max-width:100%!important}}@media screen and (min-width:431px){.drawer{min-width:420px!important;max-width:420px!important}.drawer .title{min-width:200px}.drawer .mat-expansion-panel-body{padding-left:15px!important;padding-right:15px!important;padding-bottom:20px!important}.drawer-small{min-width:360px!important;max-width:360px!important}}.drawer-with-loader{padding-top:0!important}.drawer-transparent{background-color:transparent}.fade-in{animation:fadein .5s linear}@keyframes fadein{0%{opacity:0}to{opacity:1}}.bright{filter:brightness(.7)!important}@media(prefers-color-scheme:dark){.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #4CAF50)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #ff5449)}b,.bold{font-weight:600}.bright{filter:brightness(1.5)!important}}.selectfile-file,.selectfile-file-drop{padding:4px 4px 24px;width:80%;border:5px dotted var(--ars-color-divider, #757d87)!important}.selectfile-file-drop{border:5px dotted var(--ars-color-accent, #7894ae)!important}.selectfile-description{padding:0 24px 24px}.dialog-content{padding:0 24px 24px!important}\n"] }]
541
+ }], propDecorators: { done: [{ type: i0.Output, args: ["done"] }] } });
542
+
543
+ class SelectPictureDialogComponent {
544
+ constructor() {
545
+ this.done = output();
546
+ this.dialogService = inject(DialogService);
547
+ this.dialogRef = inject((MatDialogRef));
548
+ this.dialogData = signal(inject(MAT_DIALOG_DATA) ?? {}, /* @ts-ignore */
549
+ ...(ngDevMode ? [{ debugName: "dialogData" }] : /* istanbul ignore next */ []));
550
+ this.file = signal(undefined, /* @ts-ignore */
551
+ ...(ngDevMode ? [{ debugName: "file" }] : /* istanbul ignore next */ []));
552
+ this.fileClass = signal('selectpicture-file', /* @ts-ignore */
553
+ ...(ngDevMode ? [{ debugName: "fileClass" }] : /* istanbul ignore next */ []));
554
+ this.pictureWidth = signal(0, /* @ts-ignore */
555
+ ...(ngDevMode ? [{ debugName: "pictureWidth" }] : /* istanbul ignore next */ []));
556
+ this.pictureHeight = signal(0, /* @ts-ignore */
557
+ ...(ngDevMode ? [{ debugName: "pictureHeight" }] : /* istanbul ignore next */ []));
558
+ this.picturePreview = signal(undefined, /* @ts-ignore */
559
+ ...(ngDevMode ? [{ debugName: "picturePreview" }] : /* istanbul ignore next */ []));
560
+ }
561
+ /**
562
+ * Handles the native file input change event and delegates to `selectFile`.
563
+ * @param e - The DOM change event from the file input.
564
+ */
565
+ update(e) {
566
+ const input = e.target;
567
+ if (input.files?.length) {
568
+ this.selectFile(input.files[0]);
569
+ }
570
+ }
571
+ /**
572
+ * Validates the file size and type, then reads it as a data URL to generate a preview.
573
+ * @param file - The `File` object to validate and preview.
574
+ */
575
+ selectFile(file) {
576
+ const data = this.dialogData();
577
+ const maxSize = data.maxSize ?? 0;
578
+ if (maxSize > 0) {
579
+ const size = file.size / 1048576;
580
+ if (size > maxSize) {
581
+ this.dialogService.error(`File troppo grande (massimo ${SystemUtils.formatFileSize(maxSize * 1048576)})`);
582
+ return;
583
+ }
584
+ }
585
+ if (data.accept) {
586
+ const accept = data.accept.toLowerCase();
587
+ const a = file.name.split('.').pop()?.toLowerCase();
588
+ let b = file.type.toLowerCase();
589
+ if (b.startsWith('image/') && accept.includes('image/*')) {
590
+ b = 'image/*';
591
+ }
592
+ else if (b.startsWith('video/') && accept.includes('video/*')) {
593
+ b = 'video/*';
594
+ }
595
+ else if (b.startsWith('audio/') && accept.includes('audio/*')) {
596
+ b = 'audio/*';
597
+ }
598
+ if (!accept.includes(a ?? '') && !accept.includes(b)) {
599
+ this.dialogService.error(`Sono accettati solo questi tipi di file: ${accept}`);
600
+ return;
601
+ }
602
+ }
603
+ const reader = new FileReader();
604
+ reader.onload = (_e) => {
605
+ const img = new Image();
606
+ img.onload = () => {
607
+ const maxWidth = data.maxWidth ?? 0;
608
+ if (maxWidth > 0 && img.width > maxWidth) {
609
+ this.dialogService.error(`Immagine troppo larga (massimo ${maxWidth} pixel)`);
610
+ return;
611
+ }
612
+ const maxHeight = data.maxHeight ?? 0;
613
+ if (maxHeight > 0 && img.height > maxHeight) {
614
+ this.dialogService.error(`Immagine troppo alta (massimo ${maxHeight} pixel)`);
615
+ return;
616
+ }
617
+ this.pictureWidth.set(img.width);
618
+ this.pictureHeight.set(img.height);
619
+ this.picturePreview.set(_e.target.result);
620
+ this.file.set(file);
621
+ };
622
+ img.src = _e.target.result;
623
+ };
624
+ reader.readAsDataURL(file);
625
+ }
626
+ /**
627
+ * Formats a byte count into a human-readable size string.
628
+ * @param size - File size in bytes.
629
+ * @returns A formatted size string (e.g. "1.2 MB").
630
+ */
631
+ size(size) {
632
+ return SystemUtils.formatFileSize(size);
633
+ }
634
+ /** Emits the selected file and options, then closes the dialog. */
635
+ ok() {
636
+ this.done.emit({ file: this.file(), options: this.dialogData().options });
637
+ setTimeout(() => {
638
+ this.dialogRef.close();
639
+ }, 500);
640
+ }
641
+ /** Highlights the drop zone when a dragged item is over it.
642
+ * @param e - The drag event.
643
+ */
644
+ onDragOver(e) {
645
+ this.fileClass.set('selectpicture-file-drop');
646
+ e.preventDefault();
647
+ }
648
+ /** Highlights the drop zone when a dragged item enters.
649
+ * @param e - The drag event.
650
+ */
651
+ onDragEnter(e) {
652
+ this.fileClass.set('selectpicture-file-drop');
653
+ e.preventDefault();
654
+ }
655
+ /** Resets the drop zone style when dragging ends.
656
+ * @param e - The drag event.
657
+ */
658
+ onDragEnd(e) {
659
+ this.fileClass.set('selectpicture-file');
660
+ e.preventDefault();
661
+ }
662
+ /** Resets the drop zone style when a dragged item leaves.
663
+ * @param e - The drag event.
664
+ */
665
+ onDragLeave(e) {
666
+ this.fileClass.set('selectpicture-file');
667
+ e.preventDefault();
668
+ }
669
+ /**
670
+ * Handles a file drop event, extracting and processing the dropped image.
671
+ * @param e - The drop event.
672
+ */
673
+ onDrop(e) {
674
+ this.fileClass.set('selectpicture-file');
675
+ e.preventDefault();
676
+ e.stopPropagation();
677
+ if (e.dataTransfer?.files?.length) {
678
+ this.addFiles(e.dataTransfer.files);
679
+ }
680
+ }
681
+ /**
682
+ * Picks the first file from the list and passes it to `selectFile`.
683
+ * @param files - The `FileList` from the drag-and-drop event.
684
+ */
685
+ addFiles(files) {
686
+ if (files.length > 0) {
687
+ this.selectFile(files[0]);
688
+ }
689
+ }
690
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SelectPictureDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
691
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SelectPictureDialogComponent, isStandalone: true, selector: "ng-component", outputs: { done: "done" }, ngImport: i0, template: "<div mat-dialog-title [innerHTML]=\"dialogData().title | safeHtml\"></div>\n@if (dialogData().description) {\n<div class=\"selectpicture-description\" [innerHtml]=\"dialogData().description | safeHtml\"></div>\n}\n<mat-dialog-content class=\"dialog-content\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxLayoutGap=\"24px\" fxFill>\n <div fxFlex=\"*\" [class]=\"fileClass()\" (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" (dragenter)=\"onDragEnter($event)\" (dragend)=\"onDragEnd($event)\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"10px\" fxFlexAlign=\"start\" class=\"x-small secondary\"><i>Trascina qui l'immagine o selezionala</i></div>\n <div>\n <input #_file type=\"file\" [hidden]=\"true\" [accept]=\"dialogData().accept ?? 'image/*'\"\n (change)=\"update($event)\" />\n <button type=\"button\" mat-stroked-button (click)=\"_file.click()\">Seleziona file...</button>\n </div>\n @if (file()) {\n <div style=\"padding:0 24px\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxFill>\n <img [src]=\"picturePreview()\" class=\"selectpicture-preview\">\n <div class=\"small accent bold \"><i>{{file().name}}</i></div>\n <div class=\"small\">Dimensioni:<i>{{pictureWidth()}} x {{pictureHeight()}} ({{size(file().size)}})</i></div>\n </div>\n </div>\n }\n </div>\n </div>\n @if (dialogData().options) {\n <div style=\"padding-bottom: 24px;\">\n @for (o of dialogData().options; track o; let i = $index) {\n <div>\n <mat-checkbox (change)=\"o.selected = $event.checked\" [checked]=\"o.selected === true\" name=\"opt_{{i}}\" >\n {{o.description}}\n </mat-checkbox>\n </div>\n }\n </div>\n }\n </div>\n</mat-dialog-content>\n<mat-dialog-actions>\n <div fxLayout=\"row\" fxLayoutAlign=\"end\" fxFill>\n <button mat-flat-button (click)=\"ok()\" [disabled]=\"!file()\">{{dialogData().okCaption}}</button>\n <button mat-stroked-button mat-dialog-close >Annulla</button>\n </div>\n</mat-dialog-actions>\n", styles: [".fill,.wide{min-width:100%!important;max-width:100%!important;width:100%!important}.dialog-info{font-size:x-small;font-weight:700;text-align:right;padding:10px}.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #388E3C)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #a80710)}.dialog-header{padding-bottom:20px}.dialog-toolbar{padding:0 5px 0 24px;height:48px;min-height:48px}.dialog-close{margin-right:5px;margin-top:0}.dialog-menu{margin-left:10px;margin-top:10px}.dialog-title{padding:0 24px}.section-title{font-size:large;font-weight:600;padding-top:10px;padding-bottom:8px}.center{text-align:center}.fill{min-height:100%!important;max-height:100%!important;height:100%!important}.scroll-auto{overflow:auto;height:100%}.scroll-hidden{overflow:hidden;height:100%}b{font-weight:700}.large{font-size:large!important;line-height:1.2!important}.smaller{font-size:smaller!important;line-height:1.2!important}.small{font-size:small!important;line-height:1.2!important}.small-icon-button{width:1.5rem!important;height:1.5rem!important;padding:0!important;display:inline-flex!important;align-items:center;justify-content:center}.small-icon-button .mat-mdc-button-touch-target{width:1.5rem!important;height:1.5rem!important}.x-small{font-size:x-small!important;line-height:1.2!important}.bold{font-weight:700}.uppercase{text-transform:uppercase!important}.lowercase{text-transform:lowercase!important}.truncated{min-width:0;max-width:100%}@supports (-webkit-line-clamp: 2){.truncated{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.truncated span,.truncated div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@supports (-webkit-line-clamp: 2){.truncated span,.truncated div{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.clipped{min-width:0;max-width:100%}.clipped span,.clipped div{white-space:nowrap;overflow:hidden;text-overflow:clip}.accent{color:var(--ars-color-accent, #7894ae)!important}.primary{color:var(--ars-color-primary, #00a293)!important}.secondary{color:var(--ars-color-secondary, #4a635f)!important}.error{color:var(--ars-color-error, #ff5449)!important}.success{color:var(--ars-color-ok, #388E3C)!important}.warning{color:var(--ars-color-warning, #FFC107)!important}.text{color:var(--ars-color-text, #191c1b)!important}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;background-color:var(--ars-color-overlay, rgba(255, 255, 255, .75))}.drawer-content{padding-top:10px}.drawer .title-container,.drawer .title-container-with-loader,.drawer-small .title-container,.drawer-small .title-container-with-loader{padding-right:5px;padding-bottom:20px;padding-left:0}.drawer .title-container,.drawer-small .title-container{padding-top:20px}.drawer .title-container-with-loader,.drawer-small .title-container-with-loader{padding-top:14px}.drawer .title,.drawer-small .title{font-size:19.2px!important;font-weight:600;padding-left:15px;min-width:150px;width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.drawer .accordion-panel,.drawer-small .accordion-panel{background-color:transparent!important}.drawer .accordion-header,.drawer-small .accordion-header{padding-left:10px;padding-right:10px;border-radius:var(--mat-expansion-container-shape)}.drawer .mat-expansion-panel-body,.drawer-small .mat-expansion-panel-body{padding-left:10px!important;padding-right:10px!important;padding-bottom:20px!important}@media screen and (min-width:0px)and (max-width:430px){.drawer,.drawer-small{border-radius:0!important;min-width:100%!important;max-width:100%!important}}@media screen and (min-width:431px){.drawer{min-width:420px!important;max-width:420px!important}.drawer .title{min-width:200px}.drawer .mat-expansion-panel-body{padding-left:15px!important;padding-right:15px!important;padding-bottom:20px!important}.drawer-small{min-width:360px!important;max-width:360px!important}}.drawer-with-loader{padding-top:0!important}.drawer-transparent{background-color:transparent}.fade-in{animation:fadein .5s linear}@keyframes fadein{0%{opacity:0}to{opacity:1}}.bright{filter:brightness(.7)!important}@media(prefers-color-scheme:dark){.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #4CAF50)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #ff5449)}b,.bold{font-weight:600}.bright{filter:brightness(1.5)!important}}.selectpicture-file{padding:24px;width:320px;border:5px dotted #eee}.selectpicture-preview{max-height:300px;max-width:300px;margin-bottom:15px!important}.selectpicture-file,.selectpicture-file-drop{padding:4px 4px 24px;width:80%;border:5px dotted var(--ars-color-divider, #757d87)!important}.selectpicture-file-drop{border:5px dotted var(--ars-color-accent, #7894ae)!important}.selectpicture-description{padding:0 24px 24px}.dialog-content{padding:0 24px 24px!important}\n"], dependencies: [{ kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: FlexLayoutModule }, { kind: "directive", type: i1$1.FxLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg] ", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg] ", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg] ", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i1$1.FxLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg] ", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexAlignDirective, selector: " [fxFlexAlign], [fxFlexAlign.xs], [fxFlexAlign.sm], [fxFlexAlign.md], [fxFlexAlign.lg], [fxFlexAlign.xl], [fxFlexAlign.lt-sm], [fxFlexAlign.lt-md], [fxFlexAlign.lt-lg], [fxFlexAlign.lt-xl], [fxFlexAlign.gt-xs], [fxFlexAlign.gt-sm], [fxFlexAlign.gt-md], [fxFlexAlign.gt-lg] ", inputs: ["fxFlexAlign", "fxFlexAlign.xs", "fxFlexAlign.sm", "fxFlexAlign.md", "fxFlexAlign.lg", "fxFlexAlign.xl", "fxFlexAlign.lt-sm", "fxFlexAlign.lt-md", "fxFlexAlign.lt-lg", "fxFlexAlign.lt-xl", "fxFlexAlign.gt-xs", "fxFlexAlign.gt-sm", "fxFlexAlign.gt-md", "fxFlexAlign.gt-lg"] }, { kind: "directive", type: i1$1.FxFlexFillDirective, selector: " [fxFlexFill], [fxFill], [fxFlexFill.xs], [fxFlexFill.sm], [fxFlexFill.md], [fxFlexFill.lg], [fxFlexFill.xl], [fxFlexFill.lt-sm], [fxFlexFill.lt-md], [fxFlexFill.lt-lg], [fxFlexFill.lt-xl], [fxFlexFill.gt-xs], [fxFlexFill.gt-sm], [fxFlexFill.gt-md], [fxFlexFill.gt-lg] ", inputs: ["fxFlexFill", "fxFill", "fxFlexFill.xs", "fxFlexFill.sm", "fxFlexFill.md", "fxFlexFill.lg", "fxFlexFill.xl", "fxFlexFill.lt-sm", "fxFlexFill.lt-md", "fxFlexFill.lt-lg", "fxFlexFill.lt-xl", "fxFlexFill.gt-xs", "fxFlexFill.gt-sm", "fxFlexFill.gt-md", "fxFlexFill.gt-lg"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
692
+ }
693
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SelectPictureDialogComponent, decorators: [{
694
+ type: Component,
695
+ args: [{ standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatDialogTitle, MatDialogContent, FlexLayoutModule, MatButtonModule, MatCheckboxModule, FormsModule,
696
+ MatDialogActions, MatDialogClose, SafeHtmlPipe], template: "<div mat-dialog-title [innerHTML]=\"dialogData().title | safeHtml\"></div>\n@if (dialogData().description) {\n<div class=\"selectpicture-description\" [innerHtml]=\"dialogData().description | safeHtml\"></div>\n}\n<mat-dialog-content class=\"dialog-content\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxLayoutGap=\"24px\" fxFill>\n <div fxFlex=\"*\" [class]=\"fileClass()\" (drop)=\"onDrop($event)\" (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\" (dragenter)=\"onDragEnter($event)\" (dragend)=\"onDragEnd($event)\">\n <div fxLayout=\"column\" fxLayoutGap=\"24px\" fxLayoutAlign=\"center center\" fxFill>\n <div fxFlex=\"10px\" fxFlexAlign=\"start\" class=\"x-small secondary\"><i>Trascina qui l'immagine o selezionala</i></div>\n <div>\n <input #_file type=\"file\" [hidden]=\"true\" [accept]=\"dialogData().accept ?? 'image/*'\"\n (change)=\"update($event)\" />\n <button type=\"button\" mat-stroked-button (click)=\"_file.click()\">Seleziona file...</button>\n </div>\n @if (file()) {\n <div style=\"padding:0 24px\">\n <div fxLayout=\"column\" fxLayoutAlign=\"center center\" fxFill>\n <img [src]=\"picturePreview()\" class=\"selectpicture-preview\">\n <div class=\"small accent bold \"><i>{{file().name}}</i></div>\n <div class=\"small\">Dimensioni:<i>{{pictureWidth()}} x {{pictureHeight()}} ({{size(file().size)}})</i></div>\n </div>\n </div>\n }\n </div>\n </div>\n @if (dialogData().options) {\n <div style=\"padding-bottom: 24px;\">\n @for (o of dialogData().options; track o; let i = $index) {\n <div>\n <mat-checkbox (change)=\"o.selected = $event.checked\" [checked]=\"o.selected === true\" name=\"opt_{{i}}\" >\n {{o.description}}\n </mat-checkbox>\n </div>\n }\n </div>\n }\n </div>\n</mat-dialog-content>\n<mat-dialog-actions>\n <div fxLayout=\"row\" fxLayoutAlign=\"end\" fxFill>\n <button mat-flat-button (click)=\"ok()\" [disabled]=\"!file()\">{{dialogData().okCaption}}</button>\n <button mat-stroked-button mat-dialog-close >Annulla</button>\n </div>\n</mat-dialog-actions>\n", styles: [".fill,.wide{min-width:100%!important;max-width:100%!important;width:100%!important}.dialog-info{font-size:x-small;font-weight:700;text-align:right;padding:10px}.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #388E3C)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #a80710)}.dialog-header{padding-bottom:20px}.dialog-toolbar{padding:0 5px 0 24px;height:48px;min-height:48px}.dialog-close{margin-right:5px;margin-top:0}.dialog-menu{margin-left:10px;margin-top:10px}.dialog-title{padding:0 24px}.section-title{font-size:large;font-weight:600;padding-top:10px;padding-bottom:8px}.center{text-align:center}.fill{min-height:100%!important;max-height:100%!important;height:100%!important}.scroll-auto{overflow:auto;height:100%}.scroll-hidden{overflow:hidden;height:100%}b{font-weight:700}.large{font-size:large!important;line-height:1.2!important}.smaller{font-size:smaller!important;line-height:1.2!important}.small{font-size:small!important;line-height:1.2!important}.small-icon-button{width:1.5rem!important;height:1.5rem!important;padding:0!important;display:inline-flex!important;align-items:center;justify-content:center}.small-icon-button .mat-mdc-button-touch-target{width:1.5rem!important;height:1.5rem!important}.x-small{font-size:x-small!important;line-height:1.2!important}.bold{font-weight:700}.uppercase{text-transform:uppercase!important}.lowercase{text-transform:lowercase!important}.truncated{min-width:0;max-width:100%}@supports (-webkit-line-clamp: 2){.truncated{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.truncated span,.truncated div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@supports (-webkit-line-clamp: 2){.truncated span,.truncated div{overflow:hidden;text-overflow:ellipsis;white-space:initial;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}}.clipped{min-width:0;max-width:100%}.clipped span,.clipped div{white-space:nowrap;overflow:hidden;text-overflow:clip}.accent{color:var(--ars-color-accent, #7894ae)!important}.primary{color:var(--ars-color-primary, #00a293)!important}.secondary{color:var(--ars-color-secondary, #4a635f)!important}.error{color:var(--ars-color-error, #ff5449)!important}.success{color:var(--ars-color-ok, #388E3C)!important}.warning{color:var(--ars-color-warning, #FFC107)!important}.text{color:var(--ars-color-text, #191c1b)!important}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;background-color:var(--ars-color-overlay, rgba(255, 255, 255, .75))}.drawer-content{padding-top:10px}.drawer .title-container,.drawer .title-container-with-loader,.drawer-small .title-container,.drawer-small .title-container-with-loader{padding-right:5px;padding-bottom:20px;padding-left:0}.drawer .title-container,.drawer-small .title-container{padding-top:20px}.drawer .title-container-with-loader,.drawer-small .title-container-with-loader{padding-top:14px}.drawer .title,.drawer-small .title{font-size:19.2px!important;font-weight:600;padding-left:15px;min-width:150px;width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.drawer .accordion-panel,.drawer-small .accordion-panel{background-color:transparent!important}.drawer .accordion-header,.drawer-small .accordion-header{padding-left:10px;padding-right:10px;border-radius:var(--mat-expansion-container-shape)}.drawer .mat-expansion-panel-body,.drawer-small .mat-expansion-panel-body{padding-left:10px!important;padding-right:10px!important;padding-bottom:20px!important}@media screen and (min-width:0px)and (max-width:430px){.drawer,.drawer-small{border-radius:0!important;min-width:100%!important;max-width:100%!important}}@media screen and (min-width:431px){.drawer{min-width:420px!important;max-width:420px!important}.drawer .title{min-width:200px}.drawer .mat-expansion-panel-body{padding-left:15px!important;padding-right:15px!important;padding-bottom:20px!important}.drawer-small{min-width:360px!important;max-width:360px!important}}.drawer-with-loader{padding-top:0!important}.drawer-transparent{background-color:transparent}.fade-in{animation:fadein .5s linear}@keyframes fadein{0%{opacity:0}to{opacity:1}}.bright{filter:brightness(.7)!important}@media(prefers-color-scheme:dark){.dialog-info-green,.dialog-info-ok{color:var(--ars-color-ok, #4CAF50)}.dialog-info-red,.dialog-info-error{color:var(--mat-form-field-error-text-color, #ff5449)}b,.bold{font-weight:600}.bright{filter:brightness(1.5)!important}}.selectpicture-file{padding:24px;width:320px;border:5px dotted #eee}.selectpicture-preview{max-height:300px;max-width:300px;margin-bottom:15px!important}.selectpicture-file,.selectpicture-file-drop{padding:4px 4px 24px;width:80%;border:5px dotted var(--ars-color-divider, #757d87)!important}.selectpicture-file-drop{border:5px dotted var(--ars-color-accent, #7894ae)!important}.selectpicture-description{padding:0 24px 24px}.dialog-content{padding:0 24px 24px!important}\n"] }]
697
+ }], propDecorators: { done: [{ type: i0.Output, args: ["done"] }] } });
698
+
699
+ /*
700
+ * Public API Surface of @arsedizioni/ars-utils/ui.files
701
+ */
702
+
703
+ /**
704
+ * Generated bundle index. Do not edit.
705
+ */
706
+
707
+ export { FileInputComponent, FilePreviewComponent, SelectFileDialogComponent, SelectPictureDialogComponent };
708
+ //# sourceMappingURL=arsedizioni-ars-utils-ui.files.mjs.map