@arsedizioni/ars-utils 22.6.86 → 22.6.89
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/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +3158 -3344
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +7616 -4772
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.date.mjs +321 -702
- package/fesm2022/arsedizioni-ars-utils-core.date.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.markdown.mjs +445 -590
- package/fesm2022/arsedizioni-ars-utils-core.markdown.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.mjs +1735 -2370
- package/fesm2022/arsedizioni-ars-utils-core.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.validators.mjs +1280 -1470
- package/fesm2022/arsedizioni-ars-utils-core.validators.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +1097 -1528
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs +198 -294
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.controls.date.mjs +115 -117
- package/fesm2022/arsedizioni-ars-utils-ui.controls.date.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.controls.mjs +1607 -613
- package/fesm2022/arsedizioni-ars-utils-ui.controls.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.controls.tree.mjs +840 -367
- package/fesm2022/arsedizioni-ars-utils-ui.controls.tree.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs +1634 -651
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs +1255 -792
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs +1410 -357
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs +2401 -944
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.files.mjs +1553 -741
- package/fesm2022/arsedizioni-ars-utils-ui.files.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.filters.mjs +901 -430
- package/fesm2022/arsedizioni-ars-utils-ui.filters.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.help.mjs +737 -530
- package/fesm2022/arsedizioni-ars-utils-ui.help.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.mjs +6638 -1755
- package/fesm2022/arsedizioni-ars-utils-ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.navigation.mjs +1479 -1207
- package/fesm2022/arsedizioni-ars-utils-ui.navigation.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.notifications.mjs +1003 -270
- package/fesm2022/arsedizioni-ars-utils-ui.notifications.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs +497 -278
- package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.paginator.mjs +48 -52
- package/fesm2022/arsedizioni-ars-utils-ui.paginator.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.shell.mjs +464 -704
- package/fesm2022/arsedizioni-ars-utils-ui.shell.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.tinymce.mjs +724 -657
- package/fesm2022/arsedizioni-ars-utils-ui.tinymce.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils.mjs +3 -19
- package/fesm2022/arsedizioni-ars-utils.mjs.map +1 -1
- package/package.json +1 -1
- package/types/arsedizioni-ars-utils-clipper.common.d.ts +1151 -1163
- package/types/arsedizioni-ars-utils-clipper.ui.d.ts +1588 -1426
- package/types/arsedizioni-ars-utils-core.d.ts +1169 -1172
- package/types/arsedizioni-ars-utils-core.date.d.ts +204 -208
- package/types/arsedizioni-ars-utils-core.markdown.d.ts +128 -126
- package/types/arsedizioni-ars-utils-core.validators.d.ts +270 -236
- package/types/arsedizioni-ars-utils-evolution.common.d.ts +1054 -1067
- package/types/arsedizioni-ars-utils-support.common.d.ts +225 -234
- package/types/arsedizioni-ars-utils-ui.controls.d.ts +440 -278
- package/types/arsedizioni-ars-utils-ui.controls.date.d.ts +24 -28
- package/types/arsedizioni-ars-utils-ui.controls.tree.d.ts +172 -136
- package/types/arsedizioni-ars-utils-ui.d.ts +2035 -821
- package/types/arsedizioni-ars-utils-ui.dialogs.auth.d.ts +327 -322
- package/types/arsedizioni-ars-utils-ui.dialogs.d.ts +343 -347
- package/types/arsedizioni-ars-utils-ui.dialogs.prompt.d.ts +167 -167
- package/types/arsedizioni-ars-utils-ui.dialogs.select.d.ts +373 -367
- package/types/arsedizioni-ars-utils-ui.files.d.ts +335 -283
- package/types/arsedizioni-ars-utils-ui.filters.d.ts +232 -160
- package/types/arsedizioni-ars-utils-ui.help.d.ts +204 -211
- package/types/arsedizioni-ars-utils-ui.navigation.d.ts +811 -646
- package/types/arsedizioni-ars-utils-ui.notifications.d.ts +74 -78
- package/types/arsedizioni-ars-utils-ui.oauth.d.ts +102 -62
- package/types/arsedizioni-ars-utils-ui.paginator.d.ts +19 -22
- package/types/arsedizioni-ars-utils-ui.shell.d.ts +376 -382
- package/types/arsedizioni-ars-utils-ui.tinymce.d.ts +244 -231
- package/types/arsedizioni-ars-utils.d.ts +1 -3
|
@@ -1,2376 +1,1741 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import { SelectionModel } from
|
|
4
|
-
import {
|
|
5
|
-
import { it } from
|
|
6
|
-
import { TZDate } from
|
|
7
|
-
import { takeUntilDestroyed } from
|
|
8
|
-
import { Subject, filter
|
|
9
|
-
import { debounceTime, filter, map } from
|
|
10
|
-
import { DomSanitizer } from
|
|
11
|
-
import { isPlatformBrowser } from
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
class
|
|
19
|
-
}
|
|
20
|
-
class
|
|
21
|
-
}
|
|
22
|
-
class
|
|
23
|
-
}
|
|
24
|
-
class DeleteModel extends GroupModel {
|
|
25
|
-
}
|
|
26
|
-
class RelationModel {
|
|
27
|
-
}
|
|
28
|
-
class UpdateRelationsModel {
|
|
29
|
-
}
|
|
30
|
-
/** Identifies the external identity provider used for an OAuth login. */
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { DestroyRef, Directive, ElementRef, EventEmitter, HostListener, PLATFORM_ID, Pipe, RendererFactory2, Service, afterNextRender, computed, inject, input, output, signal } from "@angular/core";
|
|
3
|
+
import { SelectionModel } from "@angular/cdk/collections";
|
|
4
|
+
import { format, parse, parseISO } from "date-fns";
|
|
5
|
+
import { it } from "date-fns/locale";
|
|
6
|
+
import { TZDate } from "@date-fns/tz";
|
|
7
|
+
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
8
|
+
import { BehaviorSubject, Subject, filter, map } from "rxjs";
|
|
9
|
+
import { debounceTime, filter as filter$1, map as map$1 } from "rxjs/operators";
|
|
10
|
+
import { DomSanitizer } from "@angular/platform-browser";
|
|
11
|
+
import { isPlatformBrowser } from "@angular/common";
|
|
12
|
+
var FileInfo = class {
|
|
13
|
+
isValid() {
|
|
14
|
+
return this.valid;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var ValueModel = class {};
|
|
18
|
+
var IDModel = class {};
|
|
19
|
+
var GroupModel = class {};
|
|
20
|
+
var DeleteModel = class extends GroupModel {};
|
|
21
|
+
var RelationModel = class {};
|
|
22
|
+
var UpdateRelationsModel = class {};
|
|
31
23
|
var LoginOAuthType;
|
|
32
|
-
(function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
(function(LoginOAuthType) {
|
|
25
|
+
LoginOAuthType[LoginOAuthType["None"] = 0] = "None";
|
|
26
|
+
LoginOAuthType[LoginOAuthType["Microsoft"] = 1] = "Microsoft";
|
|
27
|
+
LoginOAuthType[LoginOAuthType["Google"] = 2] = "Google";
|
|
36
28
|
})(LoginOAuthType || (LoginOAuthType = {}));
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
class
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
constructor(from, to) {
|
|
65
|
-
this.from = from;
|
|
66
|
-
this.to = to;
|
|
67
|
-
}
|
|
68
|
-
clear() {
|
|
69
|
-
this.from = undefined;
|
|
70
|
-
this.to = undefined;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Conversions between the objects the API speaks (DTOs) and the models a signal form works with.
|
|
76
|
-
*
|
|
77
|
-
* The two shapes differ in one systematic way. A DTO leaves out what it does not have: a place
|
|
78
|
-
* with no phone number simply has no `phone`. A form model cannot afford that — signal forms only
|
|
79
|
-
* build a child field for a key whose value is defined, and the string validators need a `string`
|
|
80
|
-
* rather than `string | undefined` — so every editable field is present, holding its empty value.
|
|
81
|
-
*
|
|
82
|
-
* Doing that conversion by hand means a `?? ''` per field on the way in and a `|| undefined` per
|
|
83
|
-
* field on the way out, twice per form, kept in sync forever. {@link DtoUtils.toForm} and
|
|
84
|
-
* {@link DtoUtils.toPayload} do it once, driven by a single "empty model" constant that also serves as
|
|
85
|
-
* the initial value of the form and as what a "clear" button restores.
|
|
86
|
-
*
|
|
87
|
-
* ## The convention
|
|
88
|
-
*
|
|
89
|
-
* 1. **A component that edits a DTO owns a form model of its own.** `ProfileEditComponent`
|
|
90
|
-
* receiving a `ProfileModel` declares a `ProfileForm`, derived from it — never binds the DTO
|
|
91
|
-
* to the form directly. The DTO stays free to say "absent"; the form is not.
|
|
92
|
-
* 2. **What is optional in the DTO becomes `| null` in the form model.** `phone?: string` becomes
|
|
93
|
-
* `phone: string` holding `''`, `level?: Level` becomes `level: Level | null`. The optionality
|
|
94
|
-
* is not lost, it moves into the empty value, and {@link Dto} gives it back on the way out.
|
|
95
|
-
* 3. **A date field is `Date | null`.** Always a `Date`, never a `Date | string`; `null` is its
|
|
96
|
-
* empty value, because that is what Material's date accessors — the single datepicker and both
|
|
97
|
-
* boxes of a `mat-date-range-picker` — write when an input is cleared.
|
|
98
|
-
* 4. **The empty model is named `_EMPTY_ITEM`.** One constant per form, next to its interface.
|
|
99
|
-
* 5. **The two conversions are called `toForm()` and `toPayload()`, and are written one after the
|
|
100
|
-
* other.** When a component builds more than one payload, the others are `toPayloadXxx()` and
|
|
101
|
-
* the main one keeps the bare name.
|
|
102
|
-
* 6. **A payload always goes through `toPayload()` before it reaches the API.** When the payload
|
|
103
|
-
* needs adjustments the generic conversion cannot make — a bitmask to rebuild, dates to
|
|
104
|
-
* normalize, a number to coerce, fields the model does not own — the component declares its own
|
|
105
|
-
* `toPayload()` and calls {@link DtoUtils.toPayload} inside it for the field-by-field part.
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* ```ts
|
|
109
|
-
* interface ProfileForm {
|
|
110
|
-
* name: string; // name?: string in ProfileModel
|
|
111
|
-
* level: Level | null; // level?: Level
|
|
112
|
-
* from: Date | null; // fromDate?: Date, bound to a mat-date-range-picker
|
|
113
|
-
* to: Date | null; // toDate?: Date
|
|
114
|
-
* active: boolean;
|
|
115
|
-
* }
|
|
116
|
-
*
|
|
117
|
-
* const _EMPTY_ITEM: ProfileForm = { name: '', level: null, from: null, to: null, active: false };
|
|
118
|
-
*
|
|
119
|
-
* private toForm(dto?: ProfileModel): ProfileForm {
|
|
120
|
-
* return DtoUtils.toForm(_EMPTY_ITEM, dto as Partial<ProfileForm>);
|
|
121
|
-
* }
|
|
122
|
-
*
|
|
123
|
-
* private toPayload(): ProfileModel {
|
|
124
|
-
* const { from, to, ...rest } = this.model();
|
|
125
|
-
* return { ...DtoUtils.toPayload(rest), fromDate: from ?? undefined, toDate: to ?? undefined };
|
|
126
|
-
* }
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
/** The two conversions between an API DTO and the model a signal form works with. */
|
|
130
|
-
class DtoUtils {
|
|
131
|
-
/**
|
|
132
|
-
* Builds a form model from the object returned by the API.
|
|
133
|
-
*
|
|
134
|
-
* The shape of the result is decided by `empty`, never by the DTO: every key of `empty` is in
|
|
135
|
-
* the result, taken from the DTO when it carries a usable value and left at its empty value
|
|
136
|
-
* otherwise. A DTO field that is absent and one that is explicitly `null` are treated the same,
|
|
137
|
-
* because both mean "the record has no value here" and the form wants its empty value for both.
|
|
138
|
-
*
|
|
139
|
-
* Keys that exist only in the model (a multi-select decomposed from a bitmask, a checkbox
|
|
140
|
-
* extracted from a flags value) simply keep their empty value: fill them in around the call.
|
|
141
|
-
*
|
|
142
|
-
* @param empty - The neutral model: it declares every field the form owns, and the value each
|
|
143
|
-
* one takes when the DTO does not carry it.
|
|
144
|
-
* @param dto - The object coming from the API, or `undefined` when creating a new record.
|
|
145
|
-
* @returns A new model, never the same reference as `empty` nor as `dto`.
|
|
146
|
-
*/
|
|
147
|
-
static toForm(empty, dto) {
|
|
148
|
-
const model = { ...empty };
|
|
149
|
-
if (!dto)
|
|
150
|
-
return model;
|
|
151
|
-
for (const key of Object.keys(empty)) {
|
|
152
|
-
const value = dto[key];
|
|
153
|
-
if (value !== undefined && value !== null) {
|
|
154
|
-
model[key] = value;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return model;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Builds the payload for the API from the current form model.
|
|
161
|
-
*
|
|
162
|
-
* Every empty value — `''`, `null` or `undefined` — is dropped, so a field the user never filled
|
|
163
|
-
* in travels as absent instead of reaching the backend as an empty string that would blank the
|
|
164
|
-
* record. `0` and `false` are NOT empty: an amount of zero and a switch left off are data, and a
|
|
165
|
-
* filter that wants an unticked box to mean "no filter" has to say so where it builds its query.
|
|
166
|
-
*
|
|
167
|
-
* The conversion is shallow: nested objects and arrays are passed through as they are, so a
|
|
168
|
-
* composite field (a bitmask to rebuild, a nested block to normalize) is handled around the call
|
|
169
|
-
* — usually by destructuring it out of the model first.
|
|
170
|
-
*
|
|
171
|
-
* The return type is {@link Dto}, the model without its empty values, so what the compiler sees
|
|
172
|
-
* matches what travels: a `coachLevel: CoachLevel | null` field arrives as `CoachLevel` and fits
|
|
173
|
-
* the optional `coachLevel?: CoachLevel` of the API model. At runtime the empty keys are simply
|
|
174
|
-
* not there, which is what `HttpClient` serializes anyway.
|
|
175
|
-
*
|
|
176
|
-
* @param model - The current form model.
|
|
177
|
-
* @returns A shallow copy without the empty fields.
|
|
178
|
-
*/
|
|
179
|
-
static toPayload(model) {
|
|
180
|
-
const dto = {};
|
|
181
|
-
for (const [key, value] of Object.entries(model)) {
|
|
182
|
-
if (value === '' || value === null || value === undefined)
|
|
183
|
-
continue;
|
|
184
|
-
dto[key] = value;
|
|
185
|
-
}
|
|
186
|
-
return dto;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const UtilsMessages = {
|
|
191
|
-
/**
|
|
192
|
-
* Messages
|
|
193
|
-
*/
|
|
194
|
-
// Select dialog
|
|
195
|
-
UTILS_DIALOGS_SELECT_OPTIONS_CHANGED: '§utils-dialogs-select-options-changed'
|
|
29
|
+
var QueryModel = class {};
|
|
30
|
+
var ImportModel = class {};
|
|
31
|
+
var DateInterval = class {
|
|
32
|
+
get fromAsDate() {
|
|
33
|
+
if (this.from) {
|
|
34
|
+
if (!(this.from instanceof Date)) this.from = new Date(this.from);
|
|
35
|
+
if (this.from) return new Date(this.from.getFullYear(), this.from.getMonth(), this.from.getDate(), 2, 0, 0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
get toAsDate() {
|
|
39
|
+
if (this.to) {
|
|
40
|
+
if (!(this.to instanceof Date)) this.to = new Date(this.to);
|
|
41
|
+
if (this.to) return new Date(this.to.getFullYear(), this.to.getMonth(), this.to.getDate(), 2, 0, 0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
constructor(from, to) {
|
|
45
|
+
this.from = from;
|
|
46
|
+
this.to = to;
|
|
47
|
+
}
|
|
48
|
+
clear() {
|
|
49
|
+
this.from = void 0;
|
|
50
|
+
this.to = void 0;
|
|
51
|
+
}
|
|
196
52
|
};
|
|
197
|
-
|
|
53
|
+
var DtoUtils = class {
|
|
54
|
+
static toForm(empty, dto) {
|
|
55
|
+
const model = { ...empty };
|
|
56
|
+
if (!dto) return model;
|
|
57
|
+
for (const key of Object.keys(empty)) {
|
|
58
|
+
const value = dto[key];
|
|
59
|
+
if (value !== void 0 && value !== null) model[key] = value;
|
|
60
|
+
}
|
|
61
|
+
return model;
|
|
62
|
+
}
|
|
63
|
+
static toPayload(model) {
|
|
64
|
+
const dto = {};
|
|
65
|
+
for (const [key, value] of Object.entries(model)) {
|
|
66
|
+
if (value === "" || value === null || value === void 0) continue;
|
|
67
|
+
dto[key] = value;
|
|
68
|
+
}
|
|
69
|
+
return dto;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const UtilsMessages = { UTILS_DIALOGS_SELECT_OPTIONS_CHANGED: "§utils-dialogs-select-options-changed" };
|
|
198
73
|
var DateFormat;
|
|
199
|
-
(function
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
74
|
+
(function(DateFormat) {
|
|
75
|
+
DateFormat[DateFormat["Short"] = 1] = "Short";
|
|
76
|
+
DateFormat[DateFormat["Long"] = 2] = "Long";
|
|
77
|
+
DateFormat[DateFormat["LongWithShortMonth"] = 3] = "LongWithShortMonth";
|
|
78
|
+
DateFormat[DateFormat["LongWithWeekDay"] = 4] = "LongWithWeekDay";
|
|
79
|
+
DateFormat[DateFormat["LongWithShortWeekDay"] = 5] = "LongWithShortWeekDay";
|
|
80
|
+
DateFormat[DateFormat["MonthAndYear"] = 6] = "MonthAndYear";
|
|
81
|
+
DateFormat[DateFormat["LongMonthAndYear"] = 7] = "LongMonthAndYear";
|
|
82
|
+
DateFormat[DateFormat["WeekDay"] = 8] = "WeekDay";
|
|
83
|
+
DateFormat[DateFormat["LongWeekDay"] = 9] = "LongWeekDay";
|
|
84
|
+
DateFormat[DateFormat["DayAndMonth"] = 10] = "DayAndMonth";
|
|
85
|
+
DateFormat[DateFormat["ShortUS"] = 11] = "ShortUS";
|
|
86
|
+
DateFormat[DateFormat["ShortISO8601"] = 12] = "ShortISO8601";
|
|
212
87
|
})(DateFormat || (DateFormat = {}));
|
|
213
|
-
class SystemUtils {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
}
|
|
1611
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
i0.ɵɵ
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
*/
|
|
1865
|
-
/**
|
|
1866
|
-
* Wrapper around the native Web `BroadcastChannel` API that adds typed messaging,
|
|
1867
|
-
* multiple named subscriptions, and a graceful disposal mechanism.
|
|
1868
|
-
*
|
|
1869
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel
|
|
1870
|
-
*/
|
|
1871
|
-
class BroadcastChannelManager {
|
|
1872
|
-
/**
|
|
1873
|
-
* The name of the underlying `BroadcastChannel`, or `undefined` when the API
|
|
1874
|
-
* is not supported by the current browser.
|
|
1875
|
-
*/
|
|
1876
|
-
get currentBus() {
|
|
1877
|
-
return this.channel?.name;
|
|
1878
|
-
}
|
|
1879
|
-
/**
|
|
1880
|
-
* Observable that emits EVERY message bag received on the channel,
|
|
1881
|
-
* regardless of `messageId`. Completed by {@link dispose}.
|
|
1882
|
-
* Prefer {@link observe} to listen for a single message type.
|
|
1883
|
-
*/
|
|
1884
|
-
get messages() {
|
|
1885
|
-
return this.subject.asObservable();
|
|
1886
|
-
}
|
|
1887
|
-
/**
|
|
1888
|
-
* Returns a typed Observable that emits only the messages with the given `messageId`.
|
|
1889
|
-
*
|
|
1890
|
-
* Unlike {@link subscribe} (one callback per id, replaced on re-registration),
|
|
1891
|
-
* this supports any number of concurrent subscribers and integrates with the
|
|
1892
|
-
* RxJS lifecycle (`takeUntilDestroyed`, `async` pipe, ...). Completed by {@link dispose}.
|
|
1893
|
-
*
|
|
1894
|
-
* @param messageId - The message type identifier to listen for.
|
|
1895
|
-
* @returns An Observable of the matching typed message bags.
|
|
1896
|
-
*/
|
|
1897
|
-
observe(messageId) {
|
|
1898
|
-
return this.subject.pipe(filter(bag => bag.messageId === messageId), map(bag => bag));
|
|
1899
|
-
}
|
|
1900
|
-
/**
|
|
1901
|
-
* Opens a `BroadcastChannel` with the given name (when the API is available).
|
|
1902
|
-
* @param bus - The channel name to open (default: `'ARS-CHANNEL'`).
|
|
1903
|
-
*/
|
|
1904
|
-
constructor(bus = 'ARS-CHANNEL') {
|
|
1905
|
-
this.subject = new Subject();
|
|
1906
|
-
this.subscriptions = [];
|
|
1907
|
-
if (typeof window !== 'undefined' && 'BroadcastChannel' in window) {
|
|
1908
|
-
this.channel = new BroadcastChannel(bus);
|
|
1909
|
-
this.channel.onmessageerror = (e) => {
|
|
1910
|
-
console.error('[BroadcastChannelManager] Message receive error', e);
|
|
1911
|
-
};
|
|
1912
|
-
this.channel.onmessage = (e) => {
|
|
1913
|
-
const bag = e.data;
|
|
1914
|
-
if (!bag)
|
|
1915
|
-
return;
|
|
1916
|
-
this.subject.next(bag);
|
|
1917
|
-
const info = this.subscriptions.find(m => m.messageId === bag.messageId);
|
|
1918
|
-
info?.action(bag);
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
1921
|
-
else {
|
|
1922
|
-
console.error('[BroadcastChannelManager] BroadcastChannel API is not supported in this browser');
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
/**
|
|
1926
|
-
* Closes the underlying channel and completes the internal subject after a short delay
|
|
1927
|
-
* to allow any in-flight messages to be delivered.
|
|
1928
|
-
*/
|
|
1929
|
-
dispose() {
|
|
1930
|
-
setTimeout(() => {
|
|
1931
|
-
this.subscriptions = [];
|
|
1932
|
-
this.channel?.close();
|
|
1933
|
-
this.channel = undefined;
|
|
1934
|
-
this.subject.complete();
|
|
1935
|
-
}, 1000);
|
|
1936
|
-
}
|
|
1937
|
-
/** @internal Implementation that handles all overloads. */
|
|
1938
|
-
sendMessage(messageIdOrBag, dataOrDelay, delay) {
|
|
1939
|
-
// Disambiguate overloads based on the first argument:
|
|
1940
|
-
// - string => (messageId, data?, delay?)
|
|
1941
|
-
// - object => (bag, delay?)
|
|
1942
|
-
let bag;
|
|
1943
|
-
let effectiveDelay;
|
|
1944
|
-
if (typeof messageIdOrBag === 'string') {
|
|
1945
|
-
bag = { messageId: messageIdOrBag, data: dataOrDelay };
|
|
1946
|
-
effectiveDelay = delay ?? 0;
|
|
1947
|
-
}
|
|
1948
|
-
else {
|
|
1949
|
-
bag = messageIdOrBag;
|
|
1950
|
-
effectiveDelay = (typeof dataOrDelay === 'number' ? dataOrDelay : 0);
|
|
1951
|
-
}
|
|
1952
|
-
const post = () => this.channel?.postMessage(bag);
|
|
1953
|
-
if (effectiveDelay > 0) {
|
|
1954
|
-
setTimeout(post, effectiveDelay);
|
|
1955
|
-
}
|
|
1956
|
-
else {
|
|
1957
|
-
post();
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
/**
|
|
1961
|
-
* Registers a handler for messages with the given `messageId`.
|
|
1962
|
-
* If a handler for the same `messageId` is already registered it is replaced.
|
|
1963
|
-
* @param args - The subscription descriptor containing the message ID and handler.
|
|
1964
|
-
*/
|
|
1965
|
-
subscribe(args) {
|
|
1966
|
-
const i = this.subscriptions.findIndex(m => m.messageId === args.messageId);
|
|
1967
|
-
if (i === -1) {
|
|
1968
|
-
this.subscriptions.push(args);
|
|
1969
|
-
}
|
|
1970
|
-
else {
|
|
1971
|
-
this.subscriptions[i].action = args.action;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
/**
|
|
1975
|
-
* Removes the subscription for the given message ID, if one exists.
|
|
1976
|
-
* @param messageId - The message type identifier whose subscription should be removed.
|
|
1977
|
-
*/
|
|
1978
|
-
unsubscribe(messageId) {
|
|
1979
|
-
const i = this.subscriptions.findIndex(m => m.messageId === messageId);
|
|
1980
|
-
if (i !== -1) {
|
|
1981
|
-
this.subscriptions.splice(i, 1);
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
/**
|
|
1985
|
-
* Removes all registered subscriptions.
|
|
1986
|
-
*/
|
|
1987
|
-
unsubscribeAll() {
|
|
1988
|
-
this.subscriptions = [];
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
const CHANNEL_NAME = 'D2693418-B18F-41BB-BAE9-41BB5407957A-CHANNEL';
|
|
1993
|
-
/**
|
|
1994
|
-
* Application-level messaging service that combines two transports:
|
|
1995
|
-
* - An in-process RxJS `Subject` for same-tab communication (`sendMessage` / `getMessage`).
|
|
1996
|
-
* - A native `BroadcastChannel` for cross-tab communication (`sendChannelMessage` / `subscribeChannelMessage`).
|
|
1997
|
-
*/
|
|
1998
|
-
class BroadcastService {
|
|
1999
|
-
constructor() {
|
|
2000
|
-
this.subject = new Subject();
|
|
2001
|
-
this.channel = new BroadcastChannelManager(CHANNEL_NAME);
|
|
2002
|
-
}
|
|
2003
|
-
/**
|
|
2004
|
-
* Creates a new standalone `BroadcastChannelManager` instance bound to the shared ARS channel.
|
|
2005
|
-
* Useful when a caller needs direct channel access outside the service.
|
|
2006
|
-
* @returns A new `BroadcastChannelManager` connected to the shared channel.
|
|
2007
|
-
*/
|
|
2008
|
-
static createChannel() {
|
|
2009
|
-
return new BroadcastChannelManager(CHANNEL_NAME);
|
|
2010
|
-
}
|
|
2011
|
-
ngOnDestroy() {
|
|
2012
|
-
this.channel?.dispose();
|
|
2013
|
-
this.subject.complete();
|
|
2014
|
-
}
|
|
2015
|
-
/**
|
|
2016
|
-
* Publishes a message to the in-process subject, optionally after a delay.
|
|
2017
|
-
* @param id - The message type identifier.
|
|
2018
|
-
* @param data - Optional payload to attach to the message.
|
|
2019
|
-
* @param delay - Milliseconds to wait before publishing (default: `0`).
|
|
2020
|
-
*/
|
|
2021
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2022
|
-
sendMessage(id, data, delay = 0) {
|
|
2023
|
-
if (delay > 0) {
|
|
2024
|
-
setTimeout(() => this.subject.next({ id, data }), delay);
|
|
2025
|
-
}
|
|
2026
|
-
else {
|
|
2027
|
-
this.subject.next({ id, data });
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
/**
|
|
2031
|
-
* Publishes a typed message over the native `BroadcastChannel` (cross-tab), optionally after a delay.
|
|
2032
|
-
* @param id - The message type identifier.
|
|
2033
|
-
* @param data - Optional typed payload to send.
|
|
2034
|
-
* @param delay - Milliseconds to wait before sending (forwarded to the channel manager).
|
|
2035
|
-
*/
|
|
2036
|
-
sendChannelMessage(id, data, delay) {
|
|
2037
|
-
this.channel.sendMessage(id, data, delay);
|
|
2038
|
-
}
|
|
2039
|
-
/**
|
|
2040
|
-
* Registers a handler that is invoked whenever a channel message with the given `id` is received.
|
|
2041
|
-
* @param id - The message type identifier to listen for.
|
|
2042
|
-
* @param action - Callback invoked with the full `BroadcastChannelMessageBag` when a matching message arrives.
|
|
2043
|
-
*/
|
|
2044
|
-
subscribeChannelMessage(id, action) {
|
|
2045
|
-
this.channel.subscribe({ messageId: id, action });
|
|
2046
|
-
}
|
|
2047
|
-
/**
|
|
2048
|
-
* Removes the channel subscription previously registered for the given `id`, if any.
|
|
2049
|
-
* @param id - The message type identifier whose subscription should be removed.
|
|
2050
|
-
*/
|
|
2051
|
-
unsubscribeChannelMessage(id) {
|
|
2052
|
-
this.channel.unsubscribe(id);
|
|
2053
|
-
}
|
|
2054
|
-
/**
|
|
2055
|
-
* Returns a typed Observable of the cross-tab channel messages with the given `id`.
|
|
2056
|
-
* Supports multiple concurrent subscribers and the RxJS lifecycle operators,
|
|
2057
|
-
* unlike `subscribeChannelMessage` (single callback per id).
|
|
2058
|
-
* @param id - The message type identifier to listen for.
|
|
2059
|
-
* @returns An Observable of the matching typed message bags.
|
|
2060
|
-
*/
|
|
2061
|
-
observeChannelMessage(id) {
|
|
2062
|
-
return this.channel.observe(id);
|
|
2063
|
-
}
|
|
2064
|
-
/**
|
|
2065
|
-
* Returns an `Observable` that emits every in-process message published via `sendMessage`.
|
|
2066
|
-
* @returns An observable stream of `BroadcastMessageInfo` objects.
|
|
2067
|
-
*/
|
|
2068
|
-
getMessage() {
|
|
2069
|
-
return this.subject.asObservable();
|
|
2070
|
-
}
|
|
2071
|
-
/**
|
|
2072
|
-
* Returns a typed `Observable` of the in-process messages with the given `id`.
|
|
2073
|
-
* @param id - The message type identifier to listen for.
|
|
2074
|
-
* @returns An Observable emitting the typed `data` payload of each matching message.
|
|
2075
|
-
*/
|
|
2076
|
-
observeMessage(id) {
|
|
2077
|
-
return this.subject.pipe(filter$1(info => info.id === id), map$1(info => info.data));
|
|
2078
|
-
}
|
|
2079
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: BroadcastService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2080
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: BroadcastService }); }
|
|
2081
|
-
}
|
|
2082
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: BroadcastService, decorators: [{
|
|
2083
|
-
type: Service
|
|
2084
|
-
}] });
|
|
2085
|
-
|
|
2086
|
-
/**
|
|
2087
|
-
* Application-wide environment configuration service.
|
|
2088
|
-
* Exposes writable signals for the base URIs used throughout the application.
|
|
2089
|
-
* Values should be set once during application bootstrap (e.g. in `APP_INITIALIZER`).
|
|
2090
|
-
*/
|
|
2091
|
-
class EnvironmentService {
|
|
2092
|
-
constructor() {
|
|
2093
|
-
/** Writable signal holding the base URI of the frontend application (e.g. `https://app.example.com`). */
|
|
2094
|
-
this.appUriSignal = signal('', /* @ts-ignore */
|
|
2095
|
-
...(ngDevMode ? [{ debugName: "appUriSignal" }] : /* istanbul ignore next */ []));
|
|
2096
|
-
/** Writable signal holding the base URI of the backend API service (e.g. `https://api.example.com`). */
|
|
2097
|
-
this.appServiceUriSignal = signal('', /* @ts-ignore */
|
|
2098
|
-
...(ngDevMode ? [{ debugName: "appServiceUriSignal" }] : /* istanbul ignore next */ []));
|
|
2099
|
-
/**
|
|
2100
|
-
* Writable signal holding the redirect URI used after login.
|
|
2101
|
-
* When empty, `appLoginRedirectUri` falls back to `appUri`.
|
|
2102
|
-
*/
|
|
2103
|
-
this.appLoginRedirectUriSignal = signal('', /* @ts-ignore */
|
|
2104
|
-
...(ngDevMode ? [{ debugName: "appLoginRedirectUriSignal" }] : /* istanbul ignore next */ []));
|
|
2105
|
-
/**
|
|
2106
|
-
* Writable signal holding the login endpoint URI of the backend service.
|
|
2107
|
-
* When empty, `appServiceLoginUri` falls back to `appServiceUri`.
|
|
2108
|
-
*/
|
|
2109
|
-
this.appServiceLoginUriSignal = signal('', /* @ts-ignore */
|
|
2110
|
-
...(ngDevMode ? [{ debugName: "appServiceLoginUriSignal" }] : /* istanbul ignore next */ []));
|
|
2111
|
-
// ── Computed: fallback logic ──────────────────────────────────────────────
|
|
2112
|
-
this._effectiveLoginRedirectUri = computed(() => this.appLoginRedirectUriSignal() || this.appUriSignal(), /* @ts-ignore */
|
|
2113
|
-
...(ngDevMode ? [{ debugName: "_effectiveLoginRedirectUri" }] : /* istanbul ignore next */ []));
|
|
2114
|
-
this._effectiveServiceLoginUri = computed(() => this.appServiceLoginUriSignal() || this.appServiceUriSignal(), /* @ts-ignore */
|
|
2115
|
-
...(ngDevMode ? [{ debugName: "_effectiveServiceLoginUri" }] : /* istanbul ignore next */ []));
|
|
2116
|
-
}
|
|
2117
|
-
// ── Getter / setter API (kept for backward compatibility) ─────────────────
|
|
2118
|
-
/** Base URI of the frontend application. */
|
|
2119
|
-
get appUri() { return this.appUriSignal(); }
|
|
2120
|
-
/** @param value - The base URI of the frontend application. */
|
|
2121
|
-
set appUri(value) { this.appUriSignal.set(value); }
|
|
2122
|
-
/** Base URI of the backend API service. */
|
|
2123
|
-
get appServiceUri() { return this.appServiceUriSignal(); }
|
|
2124
|
-
/** @param value - The base URI of the backend API service. */
|
|
2125
|
-
set appServiceUri(value) { this.appServiceUriSignal.set(value); }
|
|
2126
|
-
/**
|
|
2127
|
-
* Effective login redirect URI.
|
|
2128
|
-
* Returns the explicitly set value, or falls back to `appUri` when empty.
|
|
2129
|
-
*/
|
|
2130
|
-
get appLoginRedirectUri() { return this._effectiveLoginRedirectUri(); }
|
|
2131
|
-
/** @param value - The redirect URI to use after login. */
|
|
2132
|
-
set appLoginRedirectUri(value) { this.appLoginRedirectUriSignal.set(value); }
|
|
2133
|
-
/**
|
|
2134
|
-
* Effective service login URI.
|
|
2135
|
-
* Returns the explicitly set value, or falls back to `appServiceUri` when empty.
|
|
2136
|
-
*/
|
|
2137
|
-
get appServiceLoginUri() { return this._effectiveServiceLoginUri(); }
|
|
2138
|
-
/** @param value - The login endpoint URI of the backend service. */
|
|
2139
|
-
set appServiceLoginUri(value) { this.appServiceLoginUriSignal.set(value); }
|
|
2140
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: EnvironmentService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2141
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: EnvironmentService }); }
|
|
2142
|
-
}
|
|
2143
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: EnvironmentService, decorators: [{
|
|
2144
|
-
type: Service
|
|
2145
|
-
}] });
|
|
2146
|
-
|
|
2147
|
-
/**
|
|
2148
|
-
* Service that exposes reactive screen and device-capability information.
|
|
2149
|
-
*/
|
|
2150
|
-
class ScreenService {
|
|
2151
|
-
constructor() {
|
|
2152
|
-
/**
|
|
2153
|
-
* Writable signal that holds the current Material breakpoint alias
|
|
2154
|
-
* (e.g. `'xs'`, `'sm'`, `'md'`, `'lg'`, `'xl'`).
|
|
2155
|
-
* Updated externally by the breakpoint observer in the consuming component or module.
|
|
2156
|
-
*/
|
|
2157
|
-
this.mq = signal('', /* @ts-ignore */
|
|
2158
|
-
...(ngDevMode ? [{ debugName: "mq" }] : /* istanbul ignore next */ []));
|
|
2159
|
-
}
|
|
2160
|
-
/**
|
|
2161
|
-
* Returns `true` when the primary input mechanism can hover over elements
|
|
2162
|
-
* with coarse pointer precision (i.e. a touch screen).
|
|
2163
|
-
*/
|
|
2164
|
-
get isTouchable() {
|
|
2165
|
-
return SystemUtils.isTouchable();
|
|
2166
|
-
}
|
|
2167
|
-
/**
|
|
2168
|
-
* Returns `true` when the current browser is Internet Explorer or the legacy Edge (EdgeHTML).
|
|
2169
|
-
* Modern Chromium-based Edge reports a different user-agent and will return `false`.
|
|
2170
|
-
*/
|
|
2171
|
-
get isIEOrEdge() {
|
|
2172
|
-
return SystemUtils.isBrowser() && /msie\s|trident\/|edge\//i.test(window.navigator.userAgent);
|
|
2173
|
-
}
|
|
2174
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ScreenService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2175
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: ScreenService }); }
|
|
2176
|
-
}
|
|
2177
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ScreenService, decorators: [{
|
|
2178
|
-
type: Service
|
|
2179
|
-
}] });
|
|
2180
|
-
|
|
2181
|
-
class SplashService {
|
|
2182
|
-
constructor() {
|
|
2183
|
-
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
2184
|
-
}
|
|
2185
|
-
/**
|
|
2186
|
-
* Resolve the global splash API exposed by index.html.
|
|
2187
|
-
* @returns The API object, or `undefined` when the splash has already
|
|
2188
|
-
* been removed or when running in SSR.
|
|
2189
|
-
*/
|
|
2190
|
-
get api() {
|
|
2191
|
-
return this.isBrowser ? window.splash : undefined;
|
|
2192
|
-
}
|
|
2193
|
-
/**
|
|
2194
|
-
* Update the splash message (e.g. "Accesso in corso...").
|
|
2195
|
-
* No-op when the splash is gone or in SSR.
|
|
2196
|
-
* @param text - The new message to display.
|
|
2197
|
-
*/
|
|
2198
|
-
setMessage(text) { this.api?.setMessage(text); }
|
|
2199
|
-
/**
|
|
2200
|
-
* Defuse the watchdog: Angular bootstrap succeeded,
|
|
2201
|
-
* no automatic reload will ever fire.
|
|
2202
|
-
*/
|
|
2203
|
-
bootstrapped() { this.api?.disarm(); }
|
|
2204
|
-
/** Fade out and remove the splash overlay from the DOM. */
|
|
2205
|
-
hide() { this.api?.hide(); }
|
|
2206
|
-
/**
|
|
2207
|
-
* Give up on loading, without taking the splash away.
|
|
2208
|
-
*
|
|
2209
|
-
* The splash stays where it is but stops pretending something is still happening: the progress
|
|
2210
|
-
* bar goes and a reload button appears, so a user who would otherwise sit in front of an endless
|
|
2211
|
-
* animation has something to do. Uncovering the page instead would be worse — whatever is
|
|
2212
|
-
* underneath is, by definition, not ready.
|
|
2213
|
-
*
|
|
2214
|
-
* Falls back to {@link setMessage} where `index.html` does not publish `fail`: the user still
|
|
2215
|
-
* reads what happened, only without the button.
|
|
2216
|
-
* @param text - What to tell the user.
|
|
2217
|
-
*/
|
|
2218
|
-
fail(text) {
|
|
2219
|
-
const api = this.api;
|
|
2220
|
-
if (!api)
|
|
2221
|
-
return;
|
|
2222
|
-
if (api.fail) {
|
|
2223
|
-
api.fail(text);
|
|
2224
|
-
}
|
|
2225
|
-
else {
|
|
2226
|
-
api.setMessage(text);
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SplashService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2230
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: SplashService }); }
|
|
2231
|
-
}
|
|
2232
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SplashService, decorators: [{
|
|
2233
|
-
type: Service
|
|
2234
|
-
}] });
|
|
2235
|
-
|
|
2236
|
-
/**
|
|
2237
|
-
* Application-level theme management service.
|
|
2238
|
-
*
|
|
2239
|
-
* Responsibilities:
|
|
2240
|
-
* - Persists the user's preferred theme in `localStorage`.
|
|
2241
|
-
* - Applies `'light'` or `'dark'` CSS class to `<body>`.
|
|
2242
|
-
* - Reacts to OS-level colour-scheme changes when the theme is set to `'auto'`.
|
|
2243
|
-
* - Synchronises theme changes across browser tabs via `BroadcastChannel`.
|
|
2244
|
-
* - Exposes reactive signals (`themeIcon`, `themeName`, `toggleTooltip`) for the UI.
|
|
2245
|
-
*/
|
|
2246
|
-
class ThemeService {
|
|
2247
|
-
constructor() {
|
|
2248
|
-
this.broadcastChannel = new BroadcastChannelManager('THEME-SERVICE');
|
|
2249
|
-
this.broadcastMessage = '$theme-changed';
|
|
2250
|
-
this.prefersColorSchemeMediaQueryList = typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
|
2251
|
-
? window.matchMedia('(prefers-color-scheme: dark)')
|
|
2252
|
-
: undefined;
|
|
2253
|
-
this.themeChanged = new BehaviorSubject('auto');
|
|
2254
|
-
this.renderFactory2 = inject(RendererFactory2);
|
|
2255
|
-
this.renderer = this.renderFactory2.createRenderer(null, null);
|
|
2256
|
-
/** The currently selected `ThemeType` (may be `'auto'`). */
|
|
2257
|
-
this.theme = signal('light', /* @ts-ignore */
|
|
2258
|
-
...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
2259
|
-
/** `true` when the theme is set to follow the system preference. */
|
|
2260
|
-
this.auto = computed(() => this.theme() === 'auto', /* @ts-ignore */
|
|
2261
|
-
...(ngDevMode ? [{ debugName: "auto" }] : /* istanbul ignore next */ []));
|
|
2262
|
-
this.themeInfo = {
|
|
2263
|
-
auto: { icon: 'routine', name: 'Tema di sistema', next: 'light', tooltip: 'Passa a tema chiaro' },
|
|
2264
|
-
light: { icon: 'light_mode', name: 'Tema chiaro', next: 'dark', tooltip: 'Passa a tema scuro' },
|
|
2265
|
-
dark: { icon: 'dark_mode', name: 'Tema scuro', next: 'auto', tooltip: 'Passa a tema di sistema' },
|
|
2266
|
-
};
|
|
2267
|
-
/** Reactive Material icon code for the current theme (use with `<mat-icon>`). */
|
|
2268
|
-
this.themeIcon = computed(() => this.themeInfo[this.theme()].icon, /* @ts-ignore */
|
|
2269
|
-
...(ngDevMode ? [{ debugName: "themeIcon" }] : /* istanbul ignore next */ []));
|
|
2270
|
-
/** Reactive human-readable name of the current theme. */
|
|
2271
|
-
this.themeName = computed(() => this.themeInfo[this.theme()].name, /* @ts-ignore */
|
|
2272
|
-
...(ngDevMode ? [{ debugName: "themeName" }] : /* istanbul ignore next */ []));
|
|
2273
|
-
/** Reactive tooltip text for the theme toggle button. */
|
|
2274
|
-
this.toggleTooltip = computed(() => this.themeInfo[this.theme()].tooltip, /* @ts-ignore */
|
|
2275
|
-
...(ngDevMode ? [{ debugName: "toggleTooltip" }] : /* istanbul ignore next */ []));
|
|
2276
|
-
this.changed = this.themeChanged.asObservable();
|
|
2277
|
-
}
|
|
2278
|
-
/**
|
|
2279
|
-
* Initialises the service: loads the preferred theme, registers OS-change listener,
|
|
2280
|
-
* and subscribes to cross-tab broadcast messages.
|
|
2281
|
-
* Call this once during application bootstrap (e.g. in `APP_INITIALIZER`).
|
|
2282
|
-
* @param theme - The initial theme to apply (defaults to the value stored in `localStorage`).
|
|
2283
|
-
*/
|
|
2284
|
-
initialize(theme = this.getPreferredTheme()) {
|
|
2285
|
-
if (this.prefersColorSchemeMediaQueryList) {
|
|
2286
|
-
this.prefersColorSchemeMediaQueryList.onchange = () => {
|
|
2287
|
-
if (this.auto())
|
|
2288
|
-
this.setTheme(this.theme());
|
|
2289
|
-
};
|
|
2290
|
-
}
|
|
2291
|
-
this.broadcastChannel.subscribe({
|
|
2292
|
-
messageId: this.broadcastMessage,
|
|
2293
|
-
action: (bag) => {
|
|
2294
|
-
if (bag.data && this.theme() !== bag.data) {
|
|
2295
|
-
this.setTheme(bag.data);
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
|
-
});
|
|
2299
|
-
this.setTheme(theme);
|
|
2300
|
-
}
|
|
2301
|
-
ngOnDestroy() {
|
|
2302
|
-
this.broadcastChannel.dispose();
|
|
2303
|
-
}
|
|
2304
|
-
/**
|
|
2305
|
-
* Advances the theme through the cycle: `auto` → `light` → `dark` → `auto`.
|
|
2306
|
-
*/
|
|
2307
|
-
toggleTheme() {
|
|
2308
|
-
this.setTheme(this.themeInfo[this.theme()].next);
|
|
2309
|
-
}
|
|
2310
|
-
/**
|
|
2311
|
-
* Returns the resolved effective theme (`'light'` or `'dark'`), taking the OS preference
|
|
2312
|
-
* into account when the current mode is `'auto'`.
|
|
2313
|
-
* @returns `'light'` or `'dark'` — never `'auto'`.
|
|
2314
|
-
*/
|
|
2315
|
-
getTheme() {
|
|
2316
|
-
const current = this.theme();
|
|
2317
|
-
if (current === 'auto') {
|
|
2318
|
-
return this.prefersColorSchemeMediaQueryList?.matches ? 'dark' : 'light';
|
|
2319
|
-
}
|
|
2320
|
-
return current;
|
|
2321
|
-
}
|
|
2322
|
-
/**
|
|
2323
|
-
* Reads the theme stored in `localStorage` and validates it.
|
|
2324
|
-
* Falls back to `'auto'` when the stored value is missing or invalid.
|
|
2325
|
-
* @returns The persisted `ThemeType`, or `'auto'` as default.
|
|
2326
|
-
*/
|
|
2327
|
-
getPreferredTheme() {
|
|
2328
|
-
if (typeof localStorage === 'undefined')
|
|
2329
|
-
return 'auto';
|
|
2330
|
-
const stored = localStorage.getItem('preferred-theme');
|
|
2331
|
-
return stored && this.isTheme(stored) ? stored : 'auto';
|
|
2332
|
-
}
|
|
2333
|
-
/**
|
|
2334
|
-
* Returns `true` when `value` is a valid `ThemeType` string.
|
|
2335
|
-
* Acts as a TypeScript type guard.
|
|
2336
|
-
* @param value - The string to check.
|
|
2337
|
-
*/
|
|
2338
|
-
isTheme(value) {
|
|
2339
|
-
return value === 'auto' || value === 'light' || value === 'dark';
|
|
2340
|
-
}
|
|
2341
|
-
/**
|
|
2342
|
-
* Applies the given theme to `<body>` (CSS class), persists it to `localStorage`,
|
|
2343
|
-
* notifies the `changed` observable, and broadcasts the change to other tabs.
|
|
2344
|
-
* @param theme - The `ThemeType` to apply (defaults to `'auto'`).
|
|
2345
|
-
*/
|
|
2346
|
-
setTheme(theme = 'auto') {
|
|
2347
|
-
this.renderer.removeClass(document.body, 'light');
|
|
2348
|
-
this.renderer.removeClass(document.body, 'dark');
|
|
2349
|
-
this.theme.set(theme);
|
|
2350
|
-
if (typeof localStorage !== 'undefined') {
|
|
2351
|
-
localStorage.setItem('preferred-theme', theme);
|
|
2352
|
-
}
|
|
2353
|
-
const effectiveClass = this.auto()
|
|
2354
|
-
? (this.prefersColorSchemeMediaQueryList?.matches ? 'dark' : 'light')
|
|
2355
|
-
: theme;
|
|
2356
|
-
this.renderer.addClass(document.body, effectiveClass);
|
|
2357
|
-
this.themeChanged.next(this.getTheme());
|
|
2358
|
-
this.broadcastChannel.sendMessage(this.broadcastMessage, theme);
|
|
2359
|
-
}
|
|
2360
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
2361
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: ThemeService }); }
|
|
2362
|
-
}
|
|
2363
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: ThemeService, decorators: [{
|
|
2364
|
-
type: Service
|
|
2365
|
-
}], ctorParameters: () => [] });
|
|
2366
|
-
|
|
2367
|
-
/*
|
|
2368
|
-
* Public API Surface of @arsedizioni/ars-utils/core
|
|
2369
|
-
*/
|
|
2370
|
-
|
|
2371
|
-
/**
|
|
2372
|
-
* Generated bundle index. Do not edit.
|
|
2373
|
-
*/
|
|
2374
|
-
|
|
88
|
+
var SystemUtils = class SystemUtils {
|
|
89
|
+
static {
|
|
90
|
+
this.collator = new Intl.Collator("it", {
|
|
91
|
+
sensitivity: "base",
|
|
92
|
+
numeric: true
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
static arrayFindByKey(array, key, value) {
|
|
96
|
+
if (!array) return void 0;
|
|
97
|
+
for (const item of array) if (item[key] === value) return item;
|
|
98
|
+
}
|
|
99
|
+
static arrayFindIndexByKey(array, key, value) {
|
|
100
|
+
if (!array) return -1;
|
|
101
|
+
for (let i = 0; i < array.length; i++) if (array[i][key] === value) return i;
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
static arrayGetValue(array, value) {
|
|
105
|
+
if (!array) return void 0;
|
|
106
|
+
for (const item of array) {
|
|
107
|
+
const i = item;
|
|
108
|
+
if (i["value"] === value) return i["name"] ?? i["id"];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
static arrayToNodes(items, parent) {
|
|
112
|
+
const nodes = [];
|
|
113
|
+
items.forEach((n) => {
|
|
114
|
+
const node = {
|
|
115
|
+
id: n.id.toString(),
|
|
116
|
+
name: n.name,
|
|
117
|
+
count: n.count ? n.count : 0,
|
|
118
|
+
children: void 0,
|
|
119
|
+
parent,
|
|
120
|
+
bag: n
|
|
121
|
+
};
|
|
122
|
+
nodes.push(node);
|
|
123
|
+
node.children = n.children && n.children.length > 0 ? this.arrayToNodes(n.children, node) : [];
|
|
124
|
+
});
|
|
125
|
+
return nodes;
|
|
126
|
+
}
|
|
127
|
+
static arraySortCompare(key, order = "asc") {
|
|
128
|
+
const dir = order === "desc" ? -1 : 1;
|
|
129
|
+
return (a, b) => {
|
|
130
|
+
const varA = a[key];
|
|
131
|
+
const varB = b[key];
|
|
132
|
+
if (varA === varB) return 0;
|
|
133
|
+
if (varA === void 0 || varA === null) return -1 * dir;
|
|
134
|
+
if (varB === void 0 || varB === null) return 1 * dir;
|
|
135
|
+
if (typeof varA === "string" && typeof varB === "string") return SystemUtils.collator.compare(varA, varB) * dir;
|
|
136
|
+
return (varA > varB ? 1 : varA < varB ? -1 : 0) * dir;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
static formatWeight(gr) {
|
|
140
|
+
if (gr > 1e6) return `${(gr / 1e6).toFixed(2)} t`;
|
|
141
|
+
else if (gr > 1e5) return `${(gr / 1e5).toFixed(2)} q`;
|
|
142
|
+
else if (gr > 1e3) return `${(gr / 1e3).toFixed(2)} kg`;
|
|
143
|
+
else return `${gr} gr`;
|
|
144
|
+
}
|
|
145
|
+
static formatFileSize(bytes) {
|
|
146
|
+
const MB = 1048576;
|
|
147
|
+
if (bytes >= MB) return `${(bytes / MB).toFixed(1)} MB`;
|
|
148
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
149
|
+
return `${bytes} byte`;
|
|
150
|
+
}
|
|
151
|
+
static compareString(a, b) {
|
|
152
|
+
return this.collator.compare(a ?? "", b ?? "");
|
|
153
|
+
}
|
|
154
|
+
static capitalize(s) {
|
|
155
|
+
if (!s) return void 0;
|
|
156
|
+
let b = "";
|
|
157
|
+
let cap = true;
|
|
158
|
+
for (const char of s) if (char === " ") {
|
|
159
|
+
b += char;
|
|
160
|
+
cap = true;
|
|
161
|
+
} else if (cap) {
|
|
162
|
+
b += char.toUpperCase();
|
|
163
|
+
cap = false;
|
|
164
|
+
} else b += char.toLowerCase();
|
|
165
|
+
return b;
|
|
166
|
+
}
|
|
167
|
+
static truncate(s, max = 500) {
|
|
168
|
+
if (!s) return void 0;
|
|
169
|
+
if (s.length <= max) return s;
|
|
170
|
+
const i = s.lastIndexOf(" ", max - 1);
|
|
171
|
+
return i > 0 ? s.slice(0, i) : s;
|
|
172
|
+
}
|
|
173
|
+
static join(items, sep = " ", max = 350) {
|
|
174
|
+
if (!items || items.length === 0) return void 0;
|
|
175
|
+
if (items.length > 1) {
|
|
176
|
+
let l = 0;
|
|
177
|
+
let s = "";
|
|
178
|
+
while (s.length < max && items.length > l) {
|
|
179
|
+
if (l > 0) s += sep;
|
|
180
|
+
s += items[l++];
|
|
181
|
+
}
|
|
182
|
+
if (items.length > l) s += "...";
|
|
183
|
+
return s;
|
|
184
|
+
}
|
|
185
|
+
return items[0];
|
|
186
|
+
}
|
|
187
|
+
static normalizeDisplay(s) {
|
|
188
|
+
if (!s) return s;
|
|
189
|
+
return s.split(" ").map((word, wordIndex) => {
|
|
190
|
+
if (!word) return word;
|
|
191
|
+
if (word === word.toUpperCase() && /[A-Z]/.test(word)) return word;
|
|
192
|
+
const chars = word.split("");
|
|
193
|
+
return chars.map((char, charIndex) => {
|
|
194
|
+
if (charIndex === 0 && wordIndex === 0) {
|
|
195
|
+
const secondChar = chars[1] ?? "";
|
|
196
|
+
return char === char.toUpperCase() && secondChar === secondChar.toUpperCase() && /[A-Z]/.test(char) && /[A-Z]/.test(secondChar) ? char : char.toLowerCase();
|
|
197
|
+
}
|
|
198
|
+
return char.toLowerCase();
|
|
199
|
+
}).join("");
|
|
200
|
+
}).join(" ");
|
|
201
|
+
}
|
|
202
|
+
static replaceAsHtml(s) {
|
|
203
|
+
if (!s) return "";
|
|
204
|
+
return s.replace(/https?:\/\/[^\s<]+/gi, (v) => `<a href="${v}" target="_blank" rel="noopener">${v}</a>`);
|
|
205
|
+
}
|
|
206
|
+
static compareNames(a, b) {
|
|
207
|
+
if (a) a = a.trim();
|
|
208
|
+
if (b) b = b.trim();
|
|
209
|
+
if (a && b && a.length !== b.length) return false;
|
|
210
|
+
if (this.compareString(a, b) === 0) return true;
|
|
211
|
+
const p1 = (a ?? "").split(" ");
|
|
212
|
+
const p2 = (b ?? "").split(" ");
|
|
213
|
+
if (p1.length !== p2.length) return false;
|
|
214
|
+
let matches = p1.length;
|
|
215
|
+
const used = new Array(p2.length).fill(false);
|
|
216
|
+
for (const s1 of p1) for (let j = 0; j < p2.length; j++) if (!used[j] && this.compareString(s1, p2[j]) === 0) {
|
|
217
|
+
used[j] = true;
|
|
218
|
+
matches--;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
return matches === 0;
|
|
222
|
+
}
|
|
223
|
+
static cipher(text, key, reverse = false) {
|
|
224
|
+
if (!text || !key) return void 0;
|
|
225
|
+
const SURROGATE_START = 55296;
|
|
226
|
+
const SURROGATE_SIZE = 2048;
|
|
227
|
+
const SPACE = 1112064;
|
|
228
|
+
const toIndex = (cp) => cp < SURROGATE_START ? cp : cp - SURROGATE_SIZE;
|
|
229
|
+
const toCodePoint = (i) => i < SURROGATE_START ? i : i + SURROGATE_SIZE;
|
|
230
|
+
const keyLen = key.length;
|
|
231
|
+
let result = "";
|
|
232
|
+
let i = 0;
|
|
233
|
+
for (const ch of text) {
|
|
234
|
+
let rotation = key.charCodeAt(i % keyLen);
|
|
235
|
+
if (reverse) rotation = -rotation;
|
|
236
|
+
const rotated = ((toIndex(ch.codePointAt(0)) + rotation) % SPACE + SPACE) % SPACE;
|
|
237
|
+
result += String.fromCodePoint(toCodePoint(rotated));
|
|
238
|
+
i++;
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
static {
|
|
243
|
+
this.CIPHER_VERSION = 1;
|
|
244
|
+
}
|
|
245
|
+
static {
|
|
246
|
+
this.CIPHER_SALT_LENGTH = 16;
|
|
247
|
+
}
|
|
248
|
+
static {
|
|
249
|
+
this.CIPHER_IV_LENGTH = 12;
|
|
250
|
+
}
|
|
251
|
+
static {
|
|
252
|
+
this.CIPHER_ITERATIONS = 6e5;
|
|
253
|
+
}
|
|
254
|
+
static async deriveKey(password, salt) {
|
|
255
|
+
const material = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "PBKDF2", false, ["deriveKey"]);
|
|
256
|
+
return crypto.subtle.deriveKey({
|
|
257
|
+
name: "PBKDF2",
|
|
258
|
+
salt,
|
|
259
|
+
iterations: this.CIPHER_ITERATIONS,
|
|
260
|
+
hash: "SHA-256"
|
|
261
|
+
}, material, {
|
|
262
|
+
name: "AES-GCM",
|
|
263
|
+
length: 256
|
|
264
|
+
}, false, ["encrypt", "decrypt"]);
|
|
265
|
+
}
|
|
266
|
+
static toBase64Url(bytes) {
|
|
267
|
+
let binary = "";
|
|
268
|
+
const CHUNK = 32768;
|
|
269
|
+
for (let i = 0; i < bytes.length; i += CHUNK) binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
270
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
271
|
+
}
|
|
272
|
+
static fromBase64Url(value) {
|
|
273
|
+
const b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
274
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
275
|
+
const binary = atob(padded);
|
|
276
|
+
const bytes = new Uint8Array(binary.length);
|
|
277
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
278
|
+
return bytes;
|
|
279
|
+
}
|
|
280
|
+
static async encrypt(text, password) {
|
|
281
|
+
if (!text || !password) return void 0;
|
|
282
|
+
if (typeof crypto === "undefined" || !crypto.subtle) return void 0;
|
|
283
|
+
try {
|
|
284
|
+
const salt = crypto.getRandomValues(new Uint8Array(this.CIPHER_SALT_LENGTH));
|
|
285
|
+
const iv = crypto.getRandomValues(new Uint8Array(this.CIPHER_IV_LENGTH));
|
|
286
|
+
const key = await this.deriveKey(password, salt);
|
|
287
|
+
const cipherText = new Uint8Array(await crypto.subtle.encrypt({
|
|
288
|
+
name: "AES-GCM",
|
|
289
|
+
iv
|
|
290
|
+
}, key, new TextEncoder().encode(text)));
|
|
291
|
+
const payload = new Uint8Array(1 + salt.length + iv.length + cipherText.length);
|
|
292
|
+
payload[0] = this.CIPHER_VERSION;
|
|
293
|
+
payload.set(salt, 1);
|
|
294
|
+
payload.set(iv, 1 + salt.length);
|
|
295
|
+
payload.set(cipherText, 1 + salt.length + iv.length);
|
|
296
|
+
return this.toBase64Url(payload);
|
|
297
|
+
} catch {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
static async decrypt(payload, password) {
|
|
302
|
+
if (!payload || !password) return void 0;
|
|
303
|
+
if (typeof crypto === "undefined" || !crypto.subtle) return void 0;
|
|
304
|
+
try {
|
|
305
|
+
const bytes = this.fromBase64Url(payload);
|
|
306
|
+
const headerLength = 1 + this.CIPHER_SALT_LENGTH + this.CIPHER_IV_LENGTH;
|
|
307
|
+
if (bytes.length <= headerLength || bytes[0] !== this.CIPHER_VERSION) return void 0;
|
|
308
|
+
const salt = bytes.subarray(1, 1 + this.CIPHER_SALT_LENGTH);
|
|
309
|
+
const iv = bytes.subarray(1 + this.CIPHER_SALT_LENGTH, headerLength);
|
|
310
|
+
const cipherText = bytes.subarray(headerLength);
|
|
311
|
+
const key = await this.deriveKey(password, salt);
|
|
312
|
+
const plain = await crypto.subtle.decrypt({
|
|
313
|
+
name: "AES-GCM",
|
|
314
|
+
iv
|
|
315
|
+
}, key, cipherText);
|
|
316
|
+
return new TextDecoder().decode(plain);
|
|
317
|
+
} catch {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
static clone(obj) {
|
|
322
|
+
if (obj === null || obj === void 0) return obj;
|
|
323
|
+
return structuredClone(obj);
|
|
324
|
+
}
|
|
325
|
+
static deepClone(obj, dest) {
|
|
326
|
+
const cloned = structuredClone(obj);
|
|
327
|
+
if (dest) {
|
|
328
|
+
Object.assign(dest, cloned);
|
|
329
|
+
return dest;
|
|
330
|
+
}
|
|
331
|
+
return cloned;
|
|
332
|
+
}
|
|
333
|
+
static parseUUID(value) {
|
|
334
|
+
if (!value) return false;
|
|
335
|
+
let s = value.trim();
|
|
336
|
+
if (s.startsWith("{") && s.endsWith("}") || s.startsWith("(") && s.endsWith(")")) s = s.slice(1, -1);
|
|
337
|
+
return /^[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$/.test(s);
|
|
338
|
+
}
|
|
339
|
+
static parseUUIDNotEmpty(value) {
|
|
340
|
+
return this.parseUUID(value) && !/^[{(]?0{8}-(?:0{4}-){3}0{12}[)}]?$/.test((value ?? "").trim());
|
|
341
|
+
}
|
|
342
|
+
static emptyUUID() {
|
|
343
|
+
return "00000000-0000-0000-0000-000000000000";
|
|
344
|
+
}
|
|
345
|
+
static generateUUID() {
|
|
346
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
347
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
348
|
+
const r = Math.random() * 16 | 0;
|
|
349
|
+
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
static inflateUUID(value) {
|
|
353
|
+
const s = value.trim();
|
|
354
|
+
if (s.length !== 32) return s;
|
|
355
|
+
return `${s.slice(0, 8)}-${s.slice(8, 12)}-${s.slice(12, 16)}-${s.slice(16, 20)}-${s.slice(20)}`;
|
|
356
|
+
}
|
|
357
|
+
static {
|
|
358
|
+
this.emailRegex = /^(?:[a-z0-9+!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
|
|
359
|
+
}
|
|
360
|
+
static {
|
|
361
|
+
this.urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,12})(:\d{1,5})?([/\w .%-]*)?(\?[^\s#]*)?(#\S*)?$/i;
|
|
362
|
+
}
|
|
363
|
+
static parseEmail(value) {
|
|
364
|
+
if (!value) return true;
|
|
365
|
+
return this.emailRegex.test(value.trim().toLowerCase());
|
|
366
|
+
}
|
|
367
|
+
static parseEmails(value) {
|
|
368
|
+
if (!value || value.trim().length === 0) return true;
|
|
369
|
+
const items = value.split(/[;,]/).map((e) => e.trim().toLowerCase()).filter((e) => e.length > 0);
|
|
370
|
+
if (items.length === 0) return false;
|
|
371
|
+
return items.every((e) => this.emailRegex.test(e));
|
|
372
|
+
}
|
|
373
|
+
static parseUrl(value) {
|
|
374
|
+
if (!value) return true;
|
|
375
|
+
return this.urlRegex.test(value.trim().toLowerCase());
|
|
376
|
+
}
|
|
377
|
+
static getDateParts(value) {
|
|
378
|
+
if (!value) return void 0;
|
|
379
|
+
let parts = [];
|
|
380
|
+
if (value.indexOf("-") !== -1) {
|
|
381
|
+
const p = value.split("-");
|
|
382
|
+
if (p.length !== 3) return void 0;
|
|
383
|
+
parts = [
|
|
384
|
+
parseInt(p[0]),
|
|
385
|
+
parseInt(p[1]) - 1,
|
|
386
|
+
parseInt(p[2])
|
|
387
|
+
];
|
|
388
|
+
} else if (value.indexOf("/") !== -1) {
|
|
389
|
+
const p = value.split("/");
|
|
390
|
+
if (p.length !== 3) return void 0;
|
|
391
|
+
parts = [
|
|
392
|
+
parseInt(p[2]),
|
|
393
|
+
parseInt(p[1]) - 1,
|
|
394
|
+
parseInt(p[0])
|
|
395
|
+
];
|
|
396
|
+
} else return;
|
|
397
|
+
return parts;
|
|
398
|
+
}
|
|
399
|
+
static isValidDate(d) {
|
|
400
|
+
return d instanceof Date && !isNaN(d.getTime());
|
|
401
|
+
}
|
|
402
|
+
static parseDate(value, locale = it) {
|
|
403
|
+
if (!value) return void 0;
|
|
404
|
+
if (value instanceof Date) return this.isValidDate(value) ? value : void 0;
|
|
405
|
+
let d = parseISO(value);
|
|
406
|
+
if (this.isValidDate(d) && d.getFullYear() > 1750) return d;
|
|
407
|
+
d = parse(value, "dd/MM/yyyy", /* @__PURE__ */ new Date(), { locale });
|
|
408
|
+
if (this.isValidDate(d) && d.getFullYear() > 1750) return d;
|
|
409
|
+
d = parse(value, "yyyy-MM-dd", /* @__PURE__ */ new Date(), { locale });
|
|
410
|
+
if (this.isValidDate(d) && d.getFullYear() > 1750) return d;
|
|
411
|
+
const parts = this.getDateParts(value);
|
|
412
|
+
if (!parts) return void 0;
|
|
413
|
+
if (parts[0] < 100) parts[0] += 2e3;
|
|
414
|
+
if (isNaN(parts[0]) || parts[0] < 0 || parts[0] < 1750) return void 0;
|
|
415
|
+
if (isNaN(parts[1]) || parts[1] < 0) return void 0;
|
|
416
|
+
if (isNaN(parts[2]) || parts[2] < 0) return void 0;
|
|
417
|
+
if (parts[1] > 11) return void 0;
|
|
418
|
+
if (parts[1] === 1 && parts[2] > 29) return void 0;
|
|
419
|
+
else if (parts[1] !== 1 && parts[2] > 31) return void 0;
|
|
420
|
+
return new TZDate(parts[0], parts[1], parts[2], 12);
|
|
421
|
+
}
|
|
422
|
+
static toLocalDate(value) {
|
|
423
|
+
if (value == null || value === "") return void 0;
|
|
424
|
+
const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : new Date(value).getTime();
|
|
425
|
+
if (isNaN(ms)) return void 0;
|
|
426
|
+
const t = new TZDate(ms, "Europe/Rome");
|
|
427
|
+
Object.defineProperty(t, "toJSON", {
|
|
428
|
+
value: () => format(t, "yyyy-MM-dd'T'HH:mm:ss"),
|
|
429
|
+
enumerable: false,
|
|
430
|
+
configurable: true,
|
|
431
|
+
writable: true
|
|
432
|
+
});
|
|
433
|
+
return t;
|
|
434
|
+
}
|
|
435
|
+
static formatDate(value, fmt = DateFormat.Short, locale = it) {
|
|
436
|
+
if (!value) return "";
|
|
437
|
+
if (typeof value === "string" || value instanceof String) value = this.parseDate(value);
|
|
438
|
+
if (!this.isValidDate(value)) return "";
|
|
439
|
+
switch (fmt) {
|
|
440
|
+
case DateFormat.Short: return format(value, "dd/MM/yyyy", { locale });
|
|
441
|
+
case DateFormat.Long: return format(value, "d MMMM yyyy", { locale });
|
|
442
|
+
case DateFormat.LongWithShortMonth: return format(value, "d MMM yyyy", { locale });
|
|
443
|
+
case DateFormat.LongWithWeekDay: return format(value, "EEEE, d MMMM yyyy", { locale });
|
|
444
|
+
case DateFormat.LongWithShortWeekDay: return format(value, "EEE, d MMMM yyyy", { locale });
|
|
445
|
+
case DateFormat.MonthAndYear: return format(value, "MMM yyyy", { locale });
|
|
446
|
+
case DateFormat.LongMonthAndYear: return format(value, "MMMM yyyy", { locale });
|
|
447
|
+
case DateFormat.WeekDay: return format(value, "EEE, d", { locale });
|
|
448
|
+
case DateFormat.LongWeekDay: return format(value, "EEEE, d", { locale });
|
|
449
|
+
case DateFormat.DayAndMonth: return format(value, "d MMMM", { locale });
|
|
450
|
+
case DateFormat.ShortUS: return format(value, "MM/dd/yyyy", { locale });
|
|
451
|
+
case DateFormat.ShortISO8601: return format(value, "yyyy-MM-dd", { locale });
|
|
452
|
+
default: return format(value, fmt, { locale });
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
static changeDateInterval(value, interval, end = false, copy = false) {
|
|
456
|
+
if (value) {
|
|
457
|
+
let year = -1;
|
|
458
|
+
if (value.length === 4 && (year = parseInt(value)) > 1750) {
|
|
459
|
+
if (!end) {
|
|
460
|
+
interval.from = new TZDate(new Date(year, 0, 1), "Europe/Rome");
|
|
461
|
+
interval.to = new TZDate(new Date(year, 11, 31), "Europe/Rome");
|
|
462
|
+
} else interval.to = new Date(year, 11, 31);
|
|
463
|
+
} else {
|
|
464
|
+
const parts = this.getDateParts(value);
|
|
465
|
+
if (!parts || parts.length !== 3) return;
|
|
466
|
+
if (isNaN(parts[0]) || parts[0] < 1750) return;
|
|
467
|
+
if (isNaN(parts[1]) || parts[1] < 0 || parts[1] > 11) return;
|
|
468
|
+
if (isNaN(parts[2]) || parts[2] < 1 || parts[2] > 31) return;
|
|
469
|
+
const d = new TZDate(new Date(parts[0], parts[1], parts[2]), "Europe/Rome");
|
|
470
|
+
if (end) interval.to = d;
|
|
471
|
+
else if (copy) {
|
|
472
|
+
interval.from = d;
|
|
473
|
+
interval.to = d;
|
|
474
|
+
} else interval.from = d;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
static {
|
|
479
|
+
this.numberFormatCache = /* @__PURE__ */ new Map();
|
|
480
|
+
}
|
|
481
|
+
static getNumberFormat(locale, options) {
|
|
482
|
+
const key = `${locale}|${options.style}|${options.currency ?? ""}|${options.minimumFractionDigits}|${options.maximumFractionDigits}`;
|
|
483
|
+
let fmt = this.numberFormatCache.get(key);
|
|
484
|
+
if (!fmt) {
|
|
485
|
+
fmt = new Intl.NumberFormat(locale, options);
|
|
486
|
+
this.numberFormatCache.set(key, fmt);
|
|
487
|
+
}
|
|
488
|
+
return fmt;
|
|
489
|
+
}
|
|
490
|
+
static formatNumber(value, decimals = 2, locale = "it-IT") {
|
|
491
|
+
return this.getNumberFormat(locale, {
|
|
492
|
+
style: "decimal",
|
|
493
|
+
minimumFractionDigits: 0,
|
|
494
|
+
maximumFractionDigits: decimals
|
|
495
|
+
}).format(value);
|
|
496
|
+
}
|
|
497
|
+
static formatCurrency(value, currency = "EUR", decimals = 2, locale = "it-IT") {
|
|
498
|
+
return this.getNumberFormat(locale, {
|
|
499
|
+
style: "currency",
|
|
500
|
+
currency,
|
|
501
|
+
minimumFractionDigits: 0,
|
|
502
|
+
maximumFractionDigits: decimals
|
|
503
|
+
}).format(value);
|
|
504
|
+
}
|
|
505
|
+
static urlEncode(value) {
|
|
506
|
+
return value.length > 0 ? encodeURIComponent(value) : void 0;
|
|
507
|
+
}
|
|
508
|
+
static urlDecode(value) {
|
|
509
|
+
return value && value.length > 0 ? decodeURIComponent(value.replace(/\+/g, "%20")) : void 0;
|
|
510
|
+
}
|
|
511
|
+
static getQueryStringValueByName(name) {
|
|
512
|
+
if (!this.isBrowser()) return void 0;
|
|
513
|
+
const v = new URLSearchParams(window.location.search).get(name);
|
|
514
|
+
return v && v !== "null" ? v : void 0;
|
|
515
|
+
}
|
|
516
|
+
static generatePassword(length = 12) {
|
|
517
|
+
const lower = "abcdefghijkmnopqrstuvwxyz";
|
|
518
|
+
const upper = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
519
|
+
const digits = "23456789";
|
|
520
|
+
const symbols = "$!#%&*+-";
|
|
521
|
+
const all = lower + upper + digits + symbols;
|
|
522
|
+
const rnd = (max) => {
|
|
523
|
+
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
524
|
+
const buf = /* @__PURE__ */ new Uint32Array(1);
|
|
525
|
+
crypto.getRandomValues(buf);
|
|
526
|
+
return buf[0] % max;
|
|
527
|
+
}
|
|
528
|
+
return Math.floor(Math.random() * max);
|
|
529
|
+
};
|
|
530
|
+
const chars = [
|
|
531
|
+
lower[rnd(25)],
|
|
532
|
+
upper[rnd(24)],
|
|
533
|
+
digits[rnd(8)],
|
|
534
|
+
symbols[rnd(8)]
|
|
535
|
+
];
|
|
536
|
+
while (chars.length < Math.max(length, 8)) chars.push(all[rnd(65)]);
|
|
537
|
+
for (let i = chars.length - 1; i > 0; i--) {
|
|
538
|
+
const j = rnd(i + 1);
|
|
539
|
+
[chars[i], chars[j]] = [chars[j], chars[i]];
|
|
540
|
+
}
|
|
541
|
+
return chars.join("");
|
|
542
|
+
}
|
|
543
|
+
static calculatePasswordStrength(password) {
|
|
544
|
+
if (password && password.length > 0) {
|
|
545
|
+
let score = 0;
|
|
546
|
+
const suggestions = [];
|
|
547
|
+
if (password.length >= 10) score++;
|
|
548
|
+
else suggestions.push("Usa almeno 10 caratteri.");
|
|
549
|
+
if (password.length >= 12) score++;
|
|
550
|
+
else if (password.length >= 10) suggestions.push("Considera di usare più di 12 caratteri.");
|
|
551
|
+
if (/[a-z]/.test(password)) score++;
|
|
552
|
+
else suggestions.push("Aggiungi lettere minuscole.");
|
|
553
|
+
if (/[A-Z]/.test(password)) score++;
|
|
554
|
+
else suggestions.push("Aggiungi lettere maiuscole.");
|
|
555
|
+
if (/\d/.test(password)) score++;
|
|
556
|
+
else suggestions.push("Aggiungi numeri.");
|
|
557
|
+
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) score++;
|
|
558
|
+
else suggestions.push("Aggiungi caratteri speciali (!@#$%^&*).");
|
|
559
|
+
if (/(.)\1{2,}/.test(password)) {
|
|
560
|
+
score = Math.max(0, score - 1);
|
|
561
|
+
suggestions.push("Evita di ripetere lo stesso carattere.");
|
|
562
|
+
}
|
|
563
|
+
if (/123|abc|qwe/i.test(password)) {
|
|
564
|
+
score = Math.max(0, score - 1);
|
|
565
|
+
suggestions.push("Evita sequenze comuni (123, abc, qwe).");
|
|
566
|
+
}
|
|
567
|
+
let label;
|
|
568
|
+
let color;
|
|
569
|
+
let isValid;
|
|
570
|
+
if (score <= 2) {
|
|
571
|
+
label = "Molto debole";
|
|
572
|
+
color = "#f44336";
|
|
573
|
+
isValid = false;
|
|
574
|
+
} else if (score <= 3) {
|
|
575
|
+
label = "Debole";
|
|
576
|
+
color = "#ff9800";
|
|
577
|
+
isValid = false;
|
|
578
|
+
} else if (score <= 4) {
|
|
579
|
+
label = "Media";
|
|
580
|
+
color = "#ffc107";
|
|
581
|
+
isValid = true;
|
|
582
|
+
} else if (score <= 5) {
|
|
583
|
+
label = "Forte";
|
|
584
|
+
color = "#8bc34a";
|
|
585
|
+
isValid = true;
|
|
586
|
+
} else {
|
|
587
|
+
label = "Molto forte";
|
|
588
|
+
color = "#4caf50";
|
|
589
|
+
isValid = true;
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
score,
|
|
593
|
+
label,
|
|
594
|
+
color,
|
|
595
|
+
suggestions,
|
|
596
|
+
isValid
|
|
597
|
+
};
|
|
598
|
+
} else return {
|
|
599
|
+
score: 0,
|
|
600
|
+
isValid: false,
|
|
601
|
+
suggestions: []
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
static isTouchable() {
|
|
605
|
+
return this.isBrowser() && ("ontouchstart" in window || navigator.maxTouchPoints > 0);
|
|
606
|
+
}
|
|
607
|
+
static isBrowser() {
|
|
608
|
+
return typeof window !== "undefined";
|
|
609
|
+
}
|
|
610
|
+
static toNodes(folders) {
|
|
611
|
+
return this._toNodes(folders, void 0);
|
|
612
|
+
}
|
|
613
|
+
static _toNodes(folders, parent) {
|
|
614
|
+
const nodes = [];
|
|
615
|
+
folders.forEach((n) => {
|
|
616
|
+
const node = {
|
|
617
|
+
id: n.id,
|
|
618
|
+
name: n.name,
|
|
619
|
+
count: n.count,
|
|
620
|
+
parent,
|
|
621
|
+
children: void 0,
|
|
622
|
+
bag: n
|
|
623
|
+
};
|
|
624
|
+
const children = n.children ?? n.subFolders ?? [];
|
|
625
|
+
if (children.length > 0) node.children = this._toNodes(children, node);
|
|
626
|
+
nodes.push(node);
|
|
627
|
+
});
|
|
628
|
+
return nodes;
|
|
629
|
+
}
|
|
630
|
+
static getFlags(value, max = 30) {
|
|
631
|
+
if (value !== 0) {
|
|
632
|
+
const items = [];
|
|
633
|
+
const top = Math.min(max, 30);
|
|
634
|
+
for (let exp = 0; exp <= top; exp++) {
|
|
635
|
+
const v = 1 << exp;
|
|
636
|
+
if ((value & v) === v) items.push(v);
|
|
637
|
+
}
|
|
638
|
+
return items;
|
|
639
|
+
} else return [];
|
|
640
|
+
}
|
|
641
|
+
static {
|
|
642
|
+
this.colorLightCache = /* @__PURE__ */ new Map();
|
|
643
|
+
}
|
|
644
|
+
static isColorLight(color, minimumLuminance = 186) {
|
|
645
|
+
if (!this.isBrowser()) return true;
|
|
646
|
+
const cacheKey = `${color}|${minimumLuminance}`;
|
|
647
|
+
const cached = this.colorLightCache.get(cacheKey);
|
|
648
|
+
if (cached !== void 0) return cached;
|
|
649
|
+
const tempDiv = document.createElement("div");
|
|
650
|
+
tempDiv.style.color = color;
|
|
651
|
+
document.body.appendChild(tempDiv);
|
|
652
|
+
const rgb = getComputedStyle(tempDiv).color;
|
|
653
|
+
document.body.removeChild(tempDiv);
|
|
654
|
+
const result = rgb.match(/\d+/g);
|
|
655
|
+
let light = true;
|
|
656
|
+
if (result && result.length >= 3) {
|
|
657
|
+
const r = parseInt(result[0], 10);
|
|
658
|
+
const g = parseInt(result[1], 10);
|
|
659
|
+
const b = parseInt(result[2], 10);
|
|
660
|
+
light = .299 * r + .587 * g + .114 * b > minimumLuminance;
|
|
661
|
+
}
|
|
662
|
+
this.colorLightCache.set(cacheKey, light);
|
|
663
|
+
return light;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var SelectableModel = class {
|
|
667
|
+
get all() {
|
|
668
|
+
return this._all();
|
|
669
|
+
}
|
|
670
|
+
get current() {
|
|
671
|
+
return this._current;
|
|
672
|
+
}
|
|
673
|
+
constructor(allowMultiSelect = true, lookupFieldName = "id") {
|
|
674
|
+
this.changed = new EventEmitter();
|
|
675
|
+
this._all = signal([], ...ngDevMode ? [{ debugName: "_all" }] : /* istanbul ignore next */ []);
|
|
676
|
+
this.hasValue = computed(() => this._all().length > 0, ...ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []);
|
|
677
|
+
this.count = computed(() => this._all().length, ...ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []);
|
|
678
|
+
this.selectedOne = computed(() => this._all().length === 1, ...ngDevMode ? [{ debugName: "selectedOne" }] : /* istanbul ignore next */ []);
|
|
679
|
+
this.selectedMany = computed(() => this._all().length > 1, ...ngDevMode ? [{ debugName: "selectedMany" }] : /* istanbul ignore next */ []);
|
|
680
|
+
this.selectedAny = computed(() => this._all().length > 0, ...ngDevMode ? [{ debugName: "selectedAny" }] : /* istanbul ignore next */ []);
|
|
681
|
+
this.selectedNone = computed(() => this._all().length === 0, ...ngDevMode ? [{ debugName: "selectedNone" }] : /* istanbul ignore next */ []);
|
|
682
|
+
this.first = computed(() => this._all()[0], ...ngDevMode ? [{ debugName: "first" }] : /* istanbul ignore next */ []);
|
|
683
|
+
this._current = new SelectionModel(allowMultiSelect, [], true, (a, b) => a[lookupFieldName] === b[lookupFieldName]);
|
|
684
|
+
this._lookupFieldName = lookupFieldName;
|
|
685
|
+
}
|
|
686
|
+
updateCurrent(item, lookupValue) {
|
|
687
|
+
if (SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, lookupValue) !== -1) {
|
|
688
|
+
this._current.toggle(item);
|
|
689
|
+
this.changed.emit(item);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
toggle(item, lookupValue) {
|
|
693
|
+
if (lookupValue === void 0) return;
|
|
694
|
+
const p = SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, lookupValue);
|
|
695
|
+
if (p === -1) this._all.update((arr) => [...arr, item]);
|
|
696
|
+
else this._all.update((arr) => arr.filter((_, i) => i !== p));
|
|
697
|
+
this._current.toggle(item);
|
|
698
|
+
this.changed.emit(item);
|
|
699
|
+
}
|
|
700
|
+
select(item, lookupValue) {
|
|
701
|
+
if (lookupValue === void 0) return;
|
|
702
|
+
if (SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, lookupValue) === -1) this._all.update((arr) => [...arr, item]);
|
|
703
|
+
this._current.select(item);
|
|
704
|
+
this.changed.emit(item);
|
|
705
|
+
}
|
|
706
|
+
deselect(item, lookupValue) {
|
|
707
|
+
if (lookupValue === void 0) return;
|
|
708
|
+
const p = SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, lookupValue);
|
|
709
|
+
if (p !== -1) {
|
|
710
|
+
this._all.update((arr) => arr.filter((_, i) => i !== p));
|
|
711
|
+
this._current.deselect(item);
|
|
712
|
+
this.changed.emit(item);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
deselectByValues(lookupValues) {
|
|
716
|
+
if (lookupValues.length === 0) return;
|
|
717
|
+
for (const key of lookupValues) {
|
|
718
|
+
const p = SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, key);
|
|
719
|
+
if (p !== -1) {
|
|
720
|
+
const item = this._all()[p];
|
|
721
|
+
this._all.update((arr) => arr.filter((_, i) => i !== p));
|
|
722
|
+
this._current.deselect(item);
|
|
723
|
+
this.changed.emit(item);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
clearCurrent(clearFunc) {
|
|
728
|
+
for (const item of this._current.selected) clearFunc(item);
|
|
729
|
+
this._current.clear();
|
|
730
|
+
this.changed.emit(void 0);
|
|
731
|
+
}
|
|
732
|
+
clear() {
|
|
733
|
+
this._all.set([]);
|
|
734
|
+
this._current.clear();
|
|
735
|
+
this.changed.emit(void 0);
|
|
736
|
+
}
|
|
737
|
+
isSelected(lookupValue) {
|
|
738
|
+
return lookupValue !== void 0 && SystemUtils.arrayFindIndexByKey(this._all(), this._lookupFieldName, lookupValue) !== -1;
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
var AutoFocusDirective = class AutoFocusDirective {
|
|
742
|
+
constructor() {
|
|
743
|
+
this.elementRef = inject(ElementRef);
|
|
744
|
+
afterNextRender(() => {
|
|
745
|
+
this.elementRef.nativeElement?.focus();
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
static {
|
|
749
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
750
|
+
minVersion: "12.0.0",
|
|
751
|
+
version: "22.2.1",
|
|
752
|
+
ngImport: i0,
|
|
753
|
+
type: AutoFocusDirective,
|
|
754
|
+
deps: [],
|
|
755
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
static {
|
|
759
|
+
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
760
|
+
minVersion: "14.0.0",
|
|
761
|
+
version: "22.2.1",
|
|
762
|
+
type: AutoFocusDirective,
|
|
763
|
+
isStandalone: true,
|
|
764
|
+
selector: "[autoFocus]",
|
|
765
|
+
ngImport: i0
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
770
|
+
minVersion: "12.0.0",
|
|
771
|
+
version: "22.2.1",
|
|
772
|
+
ngImport: i0,
|
|
773
|
+
type: AutoFocusDirective,
|
|
774
|
+
decorators: [{
|
|
775
|
+
type: Directive,
|
|
776
|
+
args: [{
|
|
777
|
+
selector: "[autoFocus]",
|
|
778
|
+
standalone: true
|
|
779
|
+
}]
|
|
780
|
+
}],
|
|
781
|
+
ctorParameters: () => []
|
|
782
|
+
});
|
|
783
|
+
var DateIntervalChangeDirective = class DateIntervalChangeDirective {
|
|
784
|
+
constructor() {
|
|
785
|
+
this.dateIntervalChange = input(new DateInterval(), ...ngDevMode ? [{ debugName: "dateIntervalChange" }] : /* istanbul ignore next */ []);
|
|
786
|
+
this.end = input(false, ...ngDevMode ? [{ debugName: "end" }] : /* istanbul ignore next */ []);
|
|
787
|
+
this.subject = new Subject();
|
|
788
|
+
this.destroyRef = inject(DestroyRef);
|
|
789
|
+
this.subject.pipe(debounceTime(100), takeUntilDestroyed(this.destroyRef)).subscribe((e) => {
|
|
790
|
+
const value = e.target?.value;
|
|
791
|
+
if (value !== void 0) SystemUtils.changeDateInterval(value, this.dateIntervalChange(), this.end(), e.key === " ");
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
onKeydown(e) {
|
|
795
|
+
if (e.key === " ") {
|
|
796
|
+
e.preventDefault();
|
|
797
|
+
e.stopPropagation();
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
onKeyup(e) {
|
|
801
|
+
this.subject.next(e);
|
|
802
|
+
}
|
|
803
|
+
static {
|
|
804
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
805
|
+
minVersion: "12.0.0",
|
|
806
|
+
version: "22.2.1",
|
|
807
|
+
ngImport: i0,
|
|
808
|
+
type: DateIntervalChangeDirective,
|
|
809
|
+
deps: [],
|
|
810
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
static {
|
|
814
|
+
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
815
|
+
minVersion: "17.1.0",
|
|
816
|
+
version: "22.2.1",
|
|
817
|
+
type: DateIntervalChangeDirective,
|
|
818
|
+
isStandalone: true,
|
|
819
|
+
selector: "[dateIntervalChange]",
|
|
820
|
+
inputs: {
|
|
821
|
+
dateIntervalChange: {
|
|
822
|
+
classPropertyName: "dateIntervalChange",
|
|
823
|
+
publicName: "dateIntervalChange",
|
|
824
|
+
isSignal: true,
|
|
825
|
+
isRequired: false,
|
|
826
|
+
transformFunction: null
|
|
827
|
+
},
|
|
828
|
+
end: {
|
|
829
|
+
classPropertyName: "end",
|
|
830
|
+
publicName: "end",
|
|
831
|
+
isSignal: true,
|
|
832
|
+
isRequired: false,
|
|
833
|
+
transformFunction: null
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
host: { listeners: {
|
|
837
|
+
"keydown": "onKeydown($event)",
|
|
838
|
+
"keyup": "onKeyup($event)"
|
|
839
|
+
} },
|
|
840
|
+
ngImport: i0
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
845
|
+
minVersion: "12.0.0",
|
|
846
|
+
version: "22.2.1",
|
|
847
|
+
ngImport: i0,
|
|
848
|
+
type: DateIntervalChangeDirective,
|
|
849
|
+
decorators: [{
|
|
850
|
+
type: Directive,
|
|
851
|
+
args: [{
|
|
852
|
+
selector: "[dateIntervalChange]",
|
|
853
|
+
standalone: true
|
|
854
|
+
}]
|
|
855
|
+
}],
|
|
856
|
+
ctorParameters: () => [],
|
|
857
|
+
propDecorators: {
|
|
858
|
+
dateIntervalChange: [{
|
|
859
|
+
type: i0.Input,
|
|
860
|
+
args: [{
|
|
861
|
+
isSignal: true,
|
|
862
|
+
alias: "dateIntervalChange",
|
|
863
|
+
required: false
|
|
864
|
+
}]
|
|
865
|
+
}],
|
|
866
|
+
end: [{
|
|
867
|
+
type: i0.Input,
|
|
868
|
+
args: [{
|
|
869
|
+
isSignal: true,
|
|
870
|
+
alias: "end",
|
|
871
|
+
required: false
|
|
872
|
+
}]
|
|
873
|
+
}],
|
|
874
|
+
onKeydown: [{
|
|
875
|
+
type: HostListener,
|
|
876
|
+
args: ["keydown", ["$event"]]
|
|
877
|
+
}],
|
|
878
|
+
onKeyup: [{
|
|
879
|
+
type: HostListener,
|
|
880
|
+
args: ["keyup", ["$event"]]
|
|
881
|
+
}]
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
var CopyClipboardDirective = class CopyClipboardDirective {
|
|
885
|
+
constructor() {
|
|
886
|
+
this.payload = input(void 0, {
|
|
887
|
+
...ngDevMode ? { debugName: "payload" } : /* istanbul ignore next */ {},
|
|
888
|
+
alias: "copyClipboard"
|
|
889
|
+
});
|
|
890
|
+
this.copied = output({ alias: "copied" });
|
|
891
|
+
}
|
|
892
|
+
onClick(e) {
|
|
893
|
+
e.preventDefault();
|
|
894
|
+
const payload = this.payload();
|
|
895
|
+
if (!payload) return;
|
|
896
|
+
if (SystemUtils.isBrowser()) {
|
|
897
|
+
const listener = (clipEvent) => {
|
|
898
|
+
clipEvent.clipboardData?.setData("text/html", payload);
|
|
899
|
+
clipEvent.clipboardData?.setData("text/plain", payload);
|
|
900
|
+
clipEvent.preventDefault();
|
|
901
|
+
this.copied.emit(payload);
|
|
902
|
+
};
|
|
903
|
+
document.addEventListener("copy", listener, false);
|
|
904
|
+
document.execCommand("copy");
|
|
905
|
+
document.removeEventListener("copy", listener, false);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
static {
|
|
909
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
910
|
+
minVersion: "12.0.0",
|
|
911
|
+
version: "22.2.1",
|
|
912
|
+
ngImport: i0,
|
|
913
|
+
type: CopyClipboardDirective,
|
|
914
|
+
deps: [],
|
|
915
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
static {
|
|
919
|
+
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
920
|
+
minVersion: "17.1.0",
|
|
921
|
+
version: "22.2.1",
|
|
922
|
+
type: CopyClipboardDirective,
|
|
923
|
+
isStandalone: true,
|
|
924
|
+
selector: "[copyClipboard]",
|
|
925
|
+
inputs: { payload: {
|
|
926
|
+
classPropertyName: "payload",
|
|
927
|
+
publicName: "copyClipboard",
|
|
928
|
+
isSignal: true,
|
|
929
|
+
isRequired: false,
|
|
930
|
+
transformFunction: null
|
|
931
|
+
} },
|
|
932
|
+
outputs: { copied: "copied" },
|
|
933
|
+
host: { listeners: { "click": "onClick($event)" } },
|
|
934
|
+
ngImport: i0
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
939
|
+
minVersion: "12.0.0",
|
|
940
|
+
version: "22.2.1",
|
|
941
|
+
ngImport: i0,
|
|
942
|
+
type: CopyClipboardDirective,
|
|
943
|
+
decorators: [{
|
|
944
|
+
type: Directive,
|
|
945
|
+
args: [{
|
|
946
|
+
selector: "[copyClipboard]",
|
|
947
|
+
standalone: true
|
|
948
|
+
}]
|
|
949
|
+
}],
|
|
950
|
+
propDecorators: {
|
|
951
|
+
payload: [{
|
|
952
|
+
type: i0.Input,
|
|
953
|
+
args: [{
|
|
954
|
+
isSignal: true,
|
|
955
|
+
alias: "copyClipboard",
|
|
956
|
+
required: false
|
|
957
|
+
}]
|
|
958
|
+
}],
|
|
959
|
+
copied: [{
|
|
960
|
+
type: i0.Output,
|
|
961
|
+
args: ["copied"]
|
|
962
|
+
}],
|
|
963
|
+
onClick: [{
|
|
964
|
+
type: HostListener,
|
|
965
|
+
args: ["click", ["$event"]]
|
|
966
|
+
}]
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
var RemoveFocusDirective = class RemoveFocusDirective {
|
|
970
|
+
constructor() {
|
|
971
|
+
this.elementRef = inject(ElementRef);
|
|
972
|
+
}
|
|
973
|
+
onClick() {
|
|
974
|
+
const el = this.elementRef.nativeElement;
|
|
975
|
+
if (el && typeof el.blur === "function") setTimeout(() => el.blur(), 0);
|
|
976
|
+
}
|
|
977
|
+
static {
|
|
978
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
979
|
+
minVersion: "12.0.0",
|
|
980
|
+
version: "22.2.1",
|
|
981
|
+
ngImport: i0,
|
|
982
|
+
type: RemoveFocusDirective,
|
|
983
|
+
deps: [],
|
|
984
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
static {
|
|
988
|
+
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
989
|
+
minVersion: "14.0.0",
|
|
990
|
+
version: "22.2.1",
|
|
991
|
+
type: RemoveFocusDirective,
|
|
992
|
+
isStandalone: true,
|
|
993
|
+
selector: "[removeFocus]",
|
|
994
|
+
host: { listeners: { "click": "onClick()" } },
|
|
995
|
+
ngImport: i0
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1000
|
+
minVersion: "12.0.0",
|
|
1001
|
+
version: "22.2.1",
|
|
1002
|
+
ngImport: i0,
|
|
1003
|
+
type: RemoveFocusDirective,
|
|
1004
|
+
decorators: [{
|
|
1005
|
+
type: Directive,
|
|
1006
|
+
args: [{
|
|
1007
|
+
selector: "[removeFocus]",
|
|
1008
|
+
standalone: true
|
|
1009
|
+
}]
|
|
1010
|
+
}],
|
|
1011
|
+
propDecorators: { onClick: [{
|
|
1012
|
+
type: HostListener,
|
|
1013
|
+
args: ["click"]
|
|
1014
|
+
}] }
|
|
1015
|
+
});
|
|
1016
|
+
var FormatHtmlPipe = class FormatHtmlPipe {
|
|
1017
|
+
constructor() {
|
|
1018
|
+
this.sanitizer = inject(DomSanitizer);
|
|
1019
|
+
}
|
|
1020
|
+
transform(value) {
|
|
1021
|
+
const escaped = (value ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
1022
|
+
return this.sanitizer.bypassSecurityTrustHtml(escaped.replaceAll(/(?:\r\n|\r|\n)/g, "<br>"));
|
|
1023
|
+
}
|
|
1024
|
+
static {
|
|
1025
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1026
|
+
minVersion: "12.0.0",
|
|
1027
|
+
version: "22.2.1",
|
|
1028
|
+
ngImport: i0,
|
|
1029
|
+
type: FormatHtmlPipe,
|
|
1030
|
+
deps: [],
|
|
1031
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
static {
|
|
1035
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1036
|
+
minVersion: "14.0.0",
|
|
1037
|
+
version: "22.2.1",
|
|
1038
|
+
ngImport: i0,
|
|
1039
|
+
type: FormatHtmlPipe,
|
|
1040
|
+
isStandalone: true,
|
|
1041
|
+
name: "formatHtml"
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1046
|
+
minVersion: "12.0.0",
|
|
1047
|
+
version: "22.2.1",
|
|
1048
|
+
ngImport: i0,
|
|
1049
|
+
type: FormatHtmlPipe,
|
|
1050
|
+
decorators: [{
|
|
1051
|
+
type: Pipe,
|
|
1052
|
+
args: [{
|
|
1053
|
+
name: "formatHtml",
|
|
1054
|
+
standalone: true
|
|
1055
|
+
}]
|
|
1056
|
+
}]
|
|
1057
|
+
});
|
|
1058
|
+
var FormatPipe = class FormatPipe {
|
|
1059
|
+
static {
|
|
1060
|
+
this.currencyFormat = new Intl.NumberFormat("it-IT", {
|
|
1061
|
+
style: "currency",
|
|
1062
|
+
currency: "EUR"
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
static {
|
|
1066
|
+
this.numberFormat = new Intl.NumberFormat("it-IT", {
|
|
1067
|
+
style: "decimal",
|
|
1068
|
+
minimumFractionDigits: 0,
|
|
1069
|
+
maximumFractionDigits: 2
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
static {
|
|
1073
|
+
this.number0Format = new Intl.NumberFormat("it-IT", {
|
|
1074
|
+
style: "decimal",
|
|
1075
|
+
minimumFractionDigits: 0,
|
|
1076
|
+
maximumFractionDigits: 0
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
static {
|
|
1080
|
+
this.percentFormat = new Intl.NumberFormat("it-IT", {
|
|
1081
|
+
style: "percent",
|
|
1082
|
+
minimumFractionDigits: 0,
|
|
1083
|
+
maximumFractionDigits: 0
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
transform(value, type = "date", pattern = "dd/MM/yyyy") {
|
|
1087
|
+
if (value === void 0 || value === null) return void 0;
|
|
1088
|
+
switch (type) {
|
|
1089
|
+
case "D":
|
|
1090
|
+
case "date": {
|
|
1091
|
+
const d = SystemUtils.parseDate(value, it);
|
|
1092
|
+
if (d) return format(d, pattern, { locale: it });
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
case "C":
|
|
1096
|
+
case "currency": return FormatPipe.currencyFormat.format(value);
|
|
1097
|
+
case "N":
|
|
1098
|
+
case "number": return FormatPipe.numberFormat.format(value);
|
|
1099
|
+
case "N0":
|
|
1100
|
+
case "number0": return FormatPipe.number0Format.format(value);
|
|
1101
|
+
case "P":
|
|
1102
|
+
case "percentage": return FormatPipe.percentFormat.format(value);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
static {
|
|
1106
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1107
|
+
minVersion: "12.0.0",
|
|
1108
|
+
version: "22.2.1",
|
|
1109
|
+
ngImport: i0,
|
|
1110
|
+
type: FormatPipe,
|
|
1111
|
+
deps: [],
|
|
1112
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
static {
|
|
1116
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1117
|
+
minVersion: "14.0.0",
|
|
1118
|
+
version: "22.2.1",
|
|
1119
|
+
ngImport: i0,
|
|
1120
|
+
type: FormatPipe,
|
|
1121
|
+
isStandalone: true,
|
|
1122
|
+
name: "format"
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1127
|
+
minVersion: "12.0.0",
|
|
1128
|
+
version: "22.2.1",
|
|
1129
|
+
ngImport: i0,
|
|
1130
|
+
type: FormatPipe,
|
|
1131
|
+
decorators: [{
|
|
1132
|
+
type: Pipe,
|
|
1133
|
+
args: [{
|
|
1134
|
+
name: "format",
|
|
1135
|
+
standalone: true
|
|
1136
|
+
}]
|
|
1137
|
+
}]
|
|
1138
|
+
});
|
|
1139
|
+
var ReplacePipe = class ReplacePipe {
|
|
1140
|
+
constructor() {
|
|
1141
|
+
this.sanitizer = inject(DomSanitizer);
|
|
1142
|
+
}
|
|
1143
|
+
transform(value, regexValue, replaceValue) {
|
|
1144
|
+
if (!value) return void 0;
|
|
1145
|
+
const replacement = regexValue === "\n" && !replaceValue ? "<br>" : replaceValue ?? "";
|
|
1146
|
+
return this.sanitizer.bypassSecurityTrustHtml(value.replace(new RegExp(regexValue, "g"), replacement));
|
|
1147
|
+
}
|
|
1148
|
+
static {
|
|
1149
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1150
|
+
minVersion: "12.0.0",
|
|
1151
|
+
version: "22.2.1",
|
|
1152
|
+
ngImport: i0,
|
|
1153
|
+
type: ReplacePipe,
|
|
1154
|
+
deps: [],
|
|
1155
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
static {
|
|
1159
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1160
|
+
minVersion: "14.0.0",
|
|
1161
|
+
version: "22.2.1",
|
|
1162
|
+
ngImport: i0,
|
|
1163
|
+
type: ReplacePipe,
|
|
1164
|
+
isStandalone: true,
|
|
1165
|
+
name: "replace"
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1170
|
+
minVersion: "12.0.0",
|
|
1171
|
+
version: "22.2.1",
|
|
1172
|
+
ngImport: i0,
|
|
1173
|
+
type: ReplacePipe,
|
|
1174
|
+
decorators: [{
|
|
1175
|
+
type: Pipe,
|
|
1176
|
+
args: [{
|
|
1177
|
+
name: "replace",
|
|
1178
|
+
standalone: true
|
|
1179
|
+
}]
|
|
1180
|
+
}]
|
|
1181
|
+
});
|
|
1182
|
+
var SafeHtmlPipe = class SafeHtmlPipe {
|
|
1183
|
+
constructor() {
|
|
1184
|
+
this.sanitizer = inject(DomSanitizer);
|
|
1185
|
+
}
|
|
1186
|
+
transform(value) {
|
|
1187
|
+
return this.sanitizer.bypassSecurityTrustHtml(value ?? "");
|
|
1188
|
+
}
|
|
1189
|
+
static {
|
|
1190
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1191
|
+
minVersion: "12.0.0",
|
|
1192
|
+
version: "22.2.1",
|
|
1193
|
+
ngImport: i0,
|
|
1194
|
+
type: SafeHtmlPipe,
|
|
1195
|
+
deps: [],
|
|
1196
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
static {
|
|
1200
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1201
|
+
minVersion: "14.0.0",
|
|
1202
|
+
version: "22.2.1",
|
|
1203
|
+
ngImport: i0,
|
|
1204
|
+
type: SafeHtmlPipe,
|
|
1205
|
+
isStandalone: true,
|
|
1206
|
+
name: "safeHtml"
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1211
|
+
minVersion: "12.0.0",
|
|
1212
|
+
version: "22.2.1",
|
|
1213
|
+
ngImport: i0,
|
|
1214
|
+
type: SafeHtmlPipe,
|
|
1215
|
+
decorators: [{
|
|
1216
|
+
type: Pipe,
|
|
1217
|
+
args: [{
|
|
1218
|
+
name: "safeHtml",
|
|
1219
|
+
standalone: true
|
|
1220
|
+
}]
|
|
1221
|
+
}]
|
|
1222
|
+
});
|
|
1223
|
+
var SafeUrlPipe = class SafeUrlPipe {
|
|
1224
|
+
constructor() {
|
|
1225
|
+
this.sanitizer = inject(DomSanitizer);
|
|
1226
|
+
}
|
|
1227
|
+
transform(value) {
|
|
1228
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(value ?? "");
|
|
1229
|
+
}
|
|
1230
|
+
static {
|
|
1231
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1232
|
+
minVersion: "12.0.0",
|
|
1233
|
+
version: "22.2.1",
|
|
1234
|
+
ngImport: i0,
|
|
1235
|
+
type: SafeUrlPipe,
|
|
1236
|
+
deps: [],
|
|
1237
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
static {
|
|
1241
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1242
|
+
minVersion: "14.0.0",
|
|
1243
|
+
version: "22.2.1",
|
|
1244
|
+
ngImport: i0,
|
|
1245
|
+
type: SafeUrlPipe,
|
|
1246
|
+
isStandalone: true,
|
|
1247
|
+
name: "safeUrl"
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1252
|
+
minVersion: "12.0.0",
|
|
1253
|
+
version: "22.2.1",
|
|
1254
|
+
ngImport: i0,
|
|
1255
|
+
type: SafeUrlPipe,
|
|
1256
|
+
decorators: [{
|
|
1257
|
+
type: Pipe,
|
|
1258
|
+
args: [{
|
|
1259
|
+
name: "safeUrl",
|
|
1260
|
+
standalone: true
|
|
1261
|
+
}]
|
|
1262
|
+
}]
|
|
1263
|
+
});
|
|
1264
|
+
var SearchCallbackPipe = class SearchCallbackPipe {
|
|
1265
|
+
transform(items, callback) {
|
|
1266
|
+
if (!items || !callback) return items;
|
|
1267
|
+
return items.filter((item) => callback(item));
|
|
1268
|
+
}
|
|
1269
|
+
static {
|
|
1270
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1271
|
+
minVersion: "12.0.0",
|
|
1272
|
+
version: "22.2.1",
|
|
1273
|
+
ngImport: i0,
|
|
1274
|
+
type: SearchCallbackPipe,
|
|
1275
|
+
deps: [],
|
|
1276
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
static {
|
|
1280
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1281
|
+
minVersion: "14.0.0",
|
|
1282
|
+
version: "22.2.1",
|
|
1283
|
+
ngImport: i0,
|
|
1284
|
+
type: SearchCallbackPipe,
|
|
1285
|
+
isStandalone: true,
|
|
1286
|
+
name: "callback",
|
|
1287
|
+
pure: false
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1292
|
+
minVersion: "12.0.0",
|
|
1293
|
+
version: "22.2.1",
|
|
1294
|
+
ngImport: i0,
|
|
1295
|
+
type: SearchCallbackPipe,
|
|
1296
|
+
decorators: [{
|
|
1297
|
+
type: Pipe,
|
|
1298
|
+
args: [{
|
|
1299
|
+
name: "callback",
|
|
1300
|
+
pure: false,
|
|
1301
|
+
standalone: true
|
|
1302
|
+
}]
|
|
1303
|
+
}]
|
|
1304
|
+
});
|
|
1305
|
+
var SearchFilterPipe = class SearchFilterPipe {
|
|
1306
|
+
transform(items, value, metadata) {
|
|
1307
|
+
metadata ??= {
|
|
1308
|
+
total: 0,
|
|
1309
|
+
count: 0
|
|
1310
|
+
};
|
|
1311
|
+
if (!items || !value) {
|
|
1312
|
+
metadata.total = items?.length ?? 0;
|
|
1313
|
+
metadata.count = metadata.total;
|
|
1314
|
+
return items;
|
|
1315
|
+
}
|
|
1316
|
+
const query = value.toLowerCase();
|
|
1317
|
+
const result = items.filter((item) => {
|
|
1318
|
+
if (!item) return false;
|
|
1319
|
+
return (item.searchBag?.name ?? (typeof item === "string" ? item : void 0))?.toLowerCase().includes(query) ?? false;
|
|
1320
|
+
});
|
|
1321
|
+
metadata.total = items.length;
|
|
1322
|
+
metadata.count = result.length;
|
|
1323
|
+
return result;
|
|
1324
|
+
}
|
|
1325
|
+
static {
|
|
1326
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1327
|
+
minVersion: "12.0.0",
|
|
1328
|
+
version: "22.2.1",
|
|
1329
|
+
ngImport: i0,
|
|
1330
|
+
type: SearchFilterPipe,
|
|
1331
|
+
deps: [],
|
|
1332
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
static {
|
|
1336
|
+
this.ɵpipe = i0.ɵɵngDeclarePipe({
|
|
1337
|
+
minVersion: "14.0.0",
|
|
1338
|
+
version: "22.2.1",
|
|
1339
|
+
ngImport: i0,
|
|
1340
|
+
type: SearchFilterPipe,
|
|
1341
|
+
isStandalone: true,
|
|
1342
|
+
name: "search"
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1347
|
+
minVersion: "12.0.0",
|
|
1348
|
+
version: "22.2.1",
|
|
1349
|
+
ngImport: i0,
|
|
1350
|
+
type: SearchFilterPipe,
|
|
1351
|
+
decorators: [{
|
|
1352
|
+
type: Pipe,
|
|
1353
|
+
args: [{
|
|
1354
|
+
name: "search",
|
|
1355
|
+
standalone: true
|
|
1356
|
+
}]
|
|
1357
|
+
}]
|
|
1358
|
+
});
|
|
1359
|
+
var BroadcastChannelManager = class {
|
|
1360
|
+
get currentBus() {
|
|
1361
|
+
return this.channel?.name;
|
|
1362
|
+
}
|
|
1363
|
+
get messages() {
|
|
1364
|
+
return this.subject.asObservable();
|
|
1365
|
+
}
|
|
1366
|
+
observe(messageId) {
|
|
1367
|
+
return this.subject.pipe(filter$1((bag) => bag.messageId === messageId), map$1((bag) => bag));
|
|
1368
|
+
}
|
|
1369
|
+
constructor(bus = "ARS-CHANNEL") {
|
|
1370
|
+
this.subject = new Subject();
|
|
1371
|
+
this.subscriptions = [];
|
|
1372
|
+
if (typeof window !== "undefined" && "BroadcastChannel" in window) {
|
|
1373
|
+
this.channel = new BroadcastChannel(bus);
|
|
1374
|
+
this.channel.onmessageerror = (e) => {
|
|
1375
|
+
console.error("[BroadcastChannelManager] Message receive error", e);
|
|
1376
|
+
};
|
|
1377
|
+
this.channel.onmessage = (e) => {
|
|
1378
|
+
const bag = e.data;
|
|
1379
|
+
if (!bag) return;
|
|
1380
|
+
this.subject.next(bag);
|
|
1381
|
+
this.subscriptions.find((m) => m.messageId === bag.messageId)?.action(bag);
|
|
1382
|
+
};
|
|
1383
|
+
} else console.error("[BroadcastChannelManager] BroadcastChannel API is not supported in this browser");
|
|
1384
|
+
}
|
|
1385
|
+
dispose() {
|
|
1386
|
+
setTimeout(() => {
|
|
1387
|
+
this.subscriptions = [];
|
|
1388
|
+
this.channel?.close();
|
|
1389
|
+
this.channel = void 0;
|
|
1390
|
+
this.subject.complete();
|
|
1391
|
+
}, 1e3);
|
|
1392
|
+
}
|
|
1393
|
+
sendMessage(messageIdOrBag, dataOrDelay, delay) {
|
|
1394
|
+
let bag;
|
|
1395
|
+
let effectiveDelay;
|
|
1396
|
+
if (typeof messageIdOrBag === "string") {
|
|
1397
|
+
bag = {
|
|
1398
|
+
messageId: messageIdOrBag,
|
|
1399
|
+
data: dataOrDelay
|
|
1400
|
+
};
|
|
1401
|
+
effectiveDelay = delay ?? 0;
|
|
1402
|
+
} else {
|
|
1403
|
+
bag = messageIdOrBag;
|
|
1404
|
+
effectiveDelay = typeof dataOrDelay === "number" ? dataOrDelay : 0;
|
|
1405
|
+
}
|
|
1406
|
+
const post = () => this.channel?.postMessage(bag);
|
|
1407
|
+
if (effectiveDelay > 0) setTimeout(post, effectiveDelay);
|
|
1408
|
+
else post();
|
|
1409
|
+
}
|
|
1410
|
+
subscribe(args) {
|
|
1411
|
+
const i = this.subscriptions.findIndex((m) => m.messageId === args.messageId);
|
|
1412
|
+
if (i === -1) this.subscriptions.push(args);
|
|
1413
|
+
else this.subscriptions[i].action = args.action;
|
|
1414
|
+
}
|
|
1415
|
+
unsubscribe(messageId) {
|
|
1416
|
+
const i = this.subscriptions.findIndex((m) => m.messageId === messageId);
|
|
1417
|
+
if (i !== -1) this.subscriptions.splice(i, 1);
|
|
1418
|
+
}
|
|
1419
|
+
unsubscribeAll() {
|
|
1420
|
+
this.subscriptions = [];
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
const CHANNEL_NAME = "D2693418-B18F-41BB-BAE9-41BB5407957A-CHANNEL";
|
|
1424
|
+
var BroadcastService = class BroadcastService {
|
|
1425
|
+
constructor() {
|
|
1426
|
+
this.subject = new Subject();
|
|
1427
|
+
this.channel = new BroadcastChannelManager(CHANNEL_NAME);
|
|
1428
|
+
}
|
|
1429
|
+
static createChannel() {
|
|
1430
|
+
return new BroadcastChannelManager(CHANNEL_NAME);
|
|
1431
|
+
}
|
|
1432
|
+
ngOnDestroy() {
|
|
1433
|
+
this.channel?.dispose();
|
|
1434
|
+
this.subject.complete();
|
|
1435
|
+
}
|
|
1436
|
+
sendMessage(id, data, delay = 0) {
|
|
1437
|
+
if (delay > 0) setTimeout(() => this.subject.next({
|
|
1438
|
+
id,
|
|
1439
|
+
data
|
|
1440
|
+
}), delay);
|
|
1441
|
+
else this.subject.next({
|
|
1442
|
+
id,
|
|
1443
|
+
data
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
sendChannelMessage(id, data, delay) {
|
|
1447
|
+
this.channel.sendMessage(id, data, delay);
|
|
1448
|
+
}
|
|
1449
|
+
subscribeChannelMessage(id, action) {
|
|
1450
|
+
this.channel.subscribe({
|
|
1451
|
+
messageId: id,
|
|
1452
|
+
action
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
unsubscribeChannelMessage(id) {
|
|
1456
|
+
this.channel.unsubscribe(id);
|
|
1457
|
+
}
|
|
1458
|
+
observeChannelMessage(id) {
|
|
1459
|
+
return this.channel.observe(id);
|
|
1460
|
+
}
|
|
1461
|
+
getMessage() {
|
|
1462
|
+
return this.subject.asObservable();
|
|
1463
|
+
}
|
|
1464
|
+
observeMessage(id) {
|
|
1465
|
+
return this.subject.pipe(filter((info) => info.id === id), map((info) => info.data));
|
|
1466
|
+
}
|
|
1467
|
+
static {
|
|
1468
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1469
|
+
minVersion: "12.0.0",
|
|
1470
|
+
version: "22.2.1",
|
|
1471
|
+
ngImport: i0,
|
|
1472
|
+
type: BroadcastService,
|
|
1473
|
+
deps: [],
|
|
1474
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
static {
|
|
1478
|
+
this.ɵprov = i0.ɵɵngDeclareService({
|
|
1479
|
+
minVersion: "22.0.0",
|
|
1480
|
+
version: "22.2.1",
|
|
1481
|
+
ngImport: i0,
|
|
1482
|
+
type: BroadcastService
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1487
|
+
minVersion: "12.0.0",
|
|
1488
|
+
version: "22.2.1",
|
|
1489
|
+
ngImport: i0,
|
|
1490
|
+
type: BroadcastService,
|
|
1491
|
+
decorators: [{ type: Service }]
|
|
1492
|
+
});
|
|
1493
|
+
var EnvironmentService = class EnvironmentService {
|
|
1494
|
+
constructor() {
|
|
1495
|
+
this.appUriSignal = signal("", ...ngDevMode ? [{ debugName: "appUriSignal" }] : /* istanbul ignore next */ []);
|
|
1496
|
+
this.appServiceUriSignal = signal("", ...ngDevMode ? [{ debugName: "appServiceUriSignal" }] : /* istanbul ignore next */ []);
|
|
1497
|
+
this.appLoginRedirectUriSignal = signal("", ...ngDevMode ? [{ debugName: "appLoginRedirectUriSignal" }] : /* istanbul ignore next */ []);
|
|
1498
|
+
this.appServiceLoginUriSignal = signal("", ...ngDevMode ? [{ debugName: "appServiceLoginUriSignal" }] : /* istanbul ignore next */ []);
|
|
1499
|
+
this._effectiveLoginRedirectUri = computed(() => this.appLoginRedirectUriSignal() || this.appUriSignal(), ...ngDevMode ? [{ debugName: "_effectiveLoginRedirectUri" }] : /* istanbul ignore next */ []);
|
|
1500
|
+
this._effectiveServiceLoginUri = computed(() => this.appServiceLoginUriSignal() || this.appServiceUriSignal(), ...ngDevMode ? [{ debugName: "_effectiveServiceLoginUri" }] : /* istanbul ignore next */ []);
|
|
1501
|
+
}
|
|
1502
|
+
get appUri() {
|
|
1503
|
+
return this.appUriSignal();
|
|
1504
|
+
}
|
|
1505
|
+
set appUri(value) {
|
|
1506
|
+
this.appUriSignal.set(value);
|
|
1507
|
+
}
|
|
1508
|
+
get appServiceUri() {
|
|
1509
|
+
return this.appServiceUriSignal();
|
|
1510
|
+
}
|
|
1511
|
+
set appServiceUri(value) {
|
|
1512
|
+
this.appServiceUriSignal.set(value);
|
|
1513
|
+
}
|
|
1514
|
+
get appLoginRedirectUri() {
|
|
1515
|
+
return this._effectiveLoginRedirectUri();
|
|
1516
|
+
}
|
|
1517
|
+
set appLoginRedirectUri(value) {
|
|
1518
|
+
this.appLoginRedirectUriSignal.set(value);
|
|
1519
|
+
}
|
|
1520
|
+
get appServiceLoginUri() {
|
|
1521
|
+
return this._effectiveServiceLoginUri();
|
|
1522
|
+
}
|
|
1523
|
+
set appServiceLoginUri(value) {
|
|
1524
|
+
this.appServiceLoginUriSignal.set(value);
|
|
1525
|
+
}
|
|
1526
|
+
static {
|
|
1527
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1528
|
+
minVersion: "12.0.0",
|
|
1529
|
+
version: "22.2.1",
|
|
1530
|
+
ngImport: i0,
|
|
1531
|
+
type: EnvironmentService,
|
|
1532
|
+
deps: [],
|
|
1533
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
static {
|
|
1537
|
+
this.ɵprov = i0.ɵɵngDeclareService({
|
|
1538
|
+
minVersion: "22.0.0",
|
|
1539
|
+
version: "22.2.1",
|
|
1540
|
+
ngImport: i0,
|
|
1541
|
+
type: EnvironmentService
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1545
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1546
|
+
minVersion: "12.0.0",
|
|
1547
|
+
version: "22.2.1",
|
|
1548
|
+
ngImport: i0,
|
|
1549
|
+
type: EnvironmentService,
|
|
1550
|
+
decorators: [{ type: Service }]
|
|
1551
|
+
});
|
|
1552
|
+
var ScreenService = class ScreenService {
|
|
1553
|
+
constructor() {
|
|
1554
|
+
this.mq = signal("", ...ngDevMode ? [{ debugName: "mq" }] : /* istanbul ignore next */ []);
|
|
1555
|
+
}
|
|
1556
|
+
get isTouchable() {
|
|
1557
|
+
return SystemUtils.isTouchable();
|
|
1558
|
+
}
|
|
1559
|
+
get isIEOrEdge() {
|
|
1560
|
+
return SystemUtils.isBrowser() && /msie\s|trident\/|edge\//i.test(window.navigator.userAgent);
|
|
1561
|
+
}
|
|
1562
|
+
static {
|
|
1563
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1564
|
+
minVersion: "12.0.0",
|
|
1565
|
+
version: "22.2.1",
|
|
1566
|
+
ngImport: i0,
|
|
1567
|
+
type: ScreenService,
|
|
1568
|
+
deps: [],
|
|
1569
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
static {
|
|
1573
|
+
this.ɵprov = i0.ɵɵngDeclareService({
|
|
1574
|
+
minVersion: "22.0.0",
|
|
1575
|
+
version: "22.2.1",
|
|
1576
|
+
ngImport: i0,
|
|
1577
|
+
type: ScreenService
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1582
|
+
minVersion: "12.0.0",
|
|
1583
|
+
version: "22.2.1",
|
|
1584
|
+
ngImport: i0,
|
|
1585
|
+
type: ScreenService,
|
|
1586
|
+
decorators: [{ type: Service }]
|
|
1587
|
+
});
|
|
1588
|
+
var SplashService = class SplashService {
|
|
1589
|
+
constructor() {
|
|
1590
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
1591
|
+
}
|
|
1592
|
+
get api() {
|
|
1593
|
+
return this.isBrowser ? window.splash : void 0;
|
|
1594
|
+
}
|
|
1595
|
+
setMessage(text) {
|
|
1596
|
+
this.api?.setMessage(text);
|
|
1597
|
+
}
|
|
1598
|
+
bootstrapped() {
|
|
1599
|
+
this.api?.disarm();
|
|
1600
|
+
}
|
|
1601
|
+
hide() {
|
|
1602
|
+
this.api?.hide();
|
|
1603
|
+
}
|
|
1604
|
+
fail(text) {
|
|
1605
|
+
const api = this.api;
|
|
1606
|
+
if (!api) return;
|
|
1607
|
+
if (api.fail) api.fail(text);
|
|
1608
|
+
else api.setMessage(text);
|
|
1609
|
+
}
|
|
1610
|
+
static {
|
|
1611
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1612
|
+
minVersion: "12.0.0",
|
|
1613
|
+
version: "22.2.1",
|
|
1614
|
+
ngImport: i0,
|
|
1615
|
+
type: SplashService,
|
|
1616
|
+
deps: [],
|
|
1617
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
static {
|
|
1621
|
+
this.ɵprov = i0.ɵɵngDeclareService({
|
|
1622
|
+
minVersion: "22.0.0",
|
|
1623
|
+
version: "22.2.1",
|
|
1624
|
+
ngImport: i0,
|
|
1625
|
+
type: SplashService
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1630
|
+
minVersion: "12.0.0",
|
|
1631
|
+
version: "22.2.1",
|
|
1632
|
+
ngImport: i0,
|
|
1633
|
+
type: SplashService,
|
|
1634
|
+
decorators: [{ type: Service }]
|
|
1635
|
+
});
|
|
1636
|
+
var ThemeService = class ThemeService {
|
|
1637
|
+
constructor() {
|
|
1638
|
+
this.broadcastChannel = new BroadcastChannelManager("THEME-SERVICE");
|
|
1639
|
+
this.broadcastMessage = "$theme-changed";
|
|
1640
|
+
this.prefersColorSchemeMediaQueryList = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : void 0;
|
|
1641
|
+
this.themeChanged = new BehaviorSubject("auto");
|
|
1642
|
+
this.renderFactory2 = inject(RendererFactory2);
|
|
1643
|
+
this.renderer = this.renderFactory2.createRenderer(null, null);
|
|
1644
|
+
this.theme = signal("light", ...ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []);
|
|
1645
|
+
this.auto = computed(() => this.theme() === "auto", ...ngDevMode ? [{ debugName: "auto" }] : /* istanbul ignore next */ []);
|
|
1646
|
+
this.themeInfo = {
|
|
1647
|
+
auto: {
|
|
1648
|
+
icon: "routine",
|
|
1649
|
+
name: "Tema di sistema",
|
|
1650
|
+
next: "light",
|
|
1651
|
+
tooltip: "Passa a tema chiaro"
|
|
1652
|
+
},
|
|
1653
|
+
light: {
|
|
1654
|
+
icon: "light_mode",
|
|
1655
|
+
name: "Tema chiaro",
|
|
1656
|
+
next: "dark",
|
|
1657
|
+
tooltip: "Passa a tema scuro"
|
|
1658
|
+
},
|
|
1659
|
+
dark: {
|
|
1660
|
+
icon: "dark_mode",
|
|
1661
|
+
name: "Tema scuro",
|
|
1662
|
+
next: "auto",
|
|
1663
|
+
tooltip: "Passa a tema di sistema"
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
this.themeIcon = computed(() => this.themeInfo[this.theme()].icon, ...ngDevMode ? [{ debugName: "themeIcon" }] : /* istanbul ignore next */ []);
|
|
1667
|
+
this.themeName = computed(() => this.themeInfo[this.theme()].name, ...ngDevMode ? [{ debugName: "themeName" }] : /* istanbul ignore next */ []);
|
|
1668
|
+
this.toggleTooltip = computed(() => this.themeInfo[this.theme()].tooltip, ...ngDevMode ? [{ debugName: "toggleTooltip" }] : /* istanbul ignore next */ []);
|
|
1669
|
+
this.changed = this.themeChanged.asObservable();
|
|
1670
|
+
}
|
|
1671
|
+
initialize(theme = this.getPreferredTheme()) {
|
|
1672
|
+
if (this.prefersColorSchemeMediaQueryList) this.prefersColorSchemeMediaQueryList.onchange = () => {
|
|
1673
|
+
if (this.auto()) this.setTheme(this.theme());
|
|
1674
|
+
};
|
|
1675
|
+
this.broadcastChannel.subscribe({
|
|
1676
|
+
messageId: this.broadcastMessage,
|
|
1677
|
+
action: (bag) => {
|
|
1678
|
+
if (bag.data && this.theme() !== bag.data) this.setTheme(bag.data);
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
this.setTheme(theme);
|
|
1682
|
+
}
|
|
1683
|
+
ngOnDestroy() {
|
|
1684
|
+
this.broadcastChannel.dispose();
|
|
1685
|
+
}
|
|
1686
|
+
toggleTheme() {
|
|
1687
|
+
this.setTheme(this.themeInfo[this.theme()].next);
|
|
1688
|
+
}
|
|
1689
|
+
getTheme() {
|
|
1690
|
+
const current = this.theme();
|
|
1691
|
+
if (current === "auto") return this.prefersColorSchemeMediaQueryList?.matches ? "dark" : "light";
|
|
1692
|
+
return current;
|
|
1693
|
+
}
|
|
1694
|
+
getPreferredTheme() {
|
|
1695
|
+
if (typeof localStorage === "undefined") return "auto";
|
|
1696
|
+
const stored = localStorage.getItem("preferred-theme");
|
|
1697
|
+
return stored && this.isTheme(stored) ? stored : "auto";
|
|
1698
|
+
}
|
|
1699
|
+
isTheme(value) {
|
|
1700
|
+
return value === "auto" || value === "light" || value === "dark";
|
|
1701
|
+
}
|
|
1702
|
+
setTheme(theme = "auto") {
|
|
1703
|
+
this.renderer.removeClass(document.body, "light");
|
|
1704
|
+
this.renderer.removeClass(document.body, "dark");
|
|
1705
|
+
this.theme.set(theme);
|
|
1706
|
+
if (typeof localStorage !== "undefined") localStorage.setItem("preferred-theme", theme);
|
|
1707
|
+
const effectiveClass = this.auto() ? this.prefersColorSchemeMediaQueryList?.matches ? "dark" : "light" : theme;
|
|
1708
|
+
this.renderer.addClass(document.body, effectiveClass);
|
|
1709
|
+
this.themeChanged.next(this.getTheme());
|
|
1710
|
+
this.broadcastChannel.sendMessage(this.broadcastMessage, theme);
|
|
1711
|
+
}
|
|
1712
|
+
static {
|
|
1713
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
1714
|
+
minVersion: "12.0.0",
|
|
1715
|
+
version: "22.2.1",
|
|
1716
|
+
ngImport: i0,
|
|
1717
|
+
type: ThemeService,
|
|
1718
|
+
deps: [],
|
|
1719
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
static {
|
|
1723
|
+
this.ɵprov = i0.ɵɵngDeclareService({
|
|
1724
|
+
minVersion: "22.0.0",
|
|
1725
|
+
version: "22.2.1",
|
|
1726
|
+
ngImport: i0,
|
|
1727
|
+
type: ThemeService
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1732
|
+
minVersion: "12.0.0",
|
|
1733
|
+
version: "22.2.1",
|
|
1734
|
+
ngImport: i0,
|
|
1735
|
+
type: ThemeService,
|
|
1736
|
+
decorators: [{ type: Service }],
|
|
1737
|
+
ctorParameters: () => []
|
|
1738
|
+
});
|
|
2375
1739
|
export { AutoFocusDirective, BroadcastChannelManager, BroadcastService, CHANNEL_NAME, CopyClipboardDirective, DateFormat, DateInterval, DateIntervalChangeDirective, DeleteModel, DtoUtils, EnvironmentService, FileInfo, FormatHtmlPipe, FormatPipe, GroupModel, IDModel, ImportModel, LoginOAuthType, QueryModel, RelationModel, RemoveFocusDirective, ReplacePipe, SafeHtmlPipe, SafeUrlPipe, ScreenService, SearchCallbackPipe, SearchFilterPipe, SelectableModel, SplashService, SystemUtils, ThemeService, UpdateRelationsModel, UtilsMessages, ValueModel };
|
|
2376
|
-
|
|
1740
|
+
|
|
1741
|
+
//# sourceMappingURL=arsedizioni-ars-utils-core.mjs.map
|