@optionfactory/ful 0.90.0 → 0.91.0
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/dist/ful.iife.js +209 -75
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +209 -75
- package/dist/ful.mjs.map +1 -1
- package/package.json +7 -4
package/dist/ful.iife.js
CHANGED
|
@@ -73,21 +73,51 @@ var ful = (function (exports) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* @typedef {{ type: string; context: string?; reason: string; details: any?; }} Problem
|
|
78
|
+
*/
|
|
76
79
|
class Failure extends Error {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param {string} message
|
|
83
|
+
* @param {Problem[]} problems
|
|
84
|
+
* @param {*} cause
|
|
85
|
+
*/
|
|
86
|
+
constructor(message, problems, cause) {
|
|
87
|
+
super(message, { cause });
|
|
88
|
+
this.name = 'Failure';
|
|
80
89
|
this.problems = problems;
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
/**
|
|
94
|
+
* @typedef {Int8Array| Uint8Array| Uint8ClampedArray| Int16Array| Uint16Array| Int32Array| Uint32Array| Float32Array| Float64Array| BigInt64Array| BigUint64Array} TypedArray
|
|
95
|
+
*/
|
|
96
|
+
/**
|
|
97
|
+
* @typedef HttpInterceptor
|
|
98
|
+
* @property {function(Request,HttpInterceptorChain):Promise<Response>} intercept
|
|
99
|
+
*/
|
|
100
|
+
|
|
84
101
|
class HttpClientError extends Failure {
|
|
85
|
-
|
|
86
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @param {string} message
|
|
104
|
+
* @param {number} status
|
|
105
|
+
* @param {{ type: string; context: string?; reason: string; details: any?; }[]} problems
|
|
106
|
+
* @param {Error|undefined} [cause]
|
|
107
|
+
*/
|
|
108
|
+
constructor(message, status, problems, cause) {
|
|
109
|
+
super(message, problems, cause);
|
|
110
|
+
this.name = 'HttpClientError';
|
|
87
111
|
this.status = status;
|
|
88
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
*
|
|
115
|
+
* @param {string} type
|
|
116
|
+
* @param {any} cause
|
|
117
|
+
* @returns
|
|
118
|
+
*/
|
|
89
119
|
static of(type, cause) {
|
|
90
|
-
return new HttpClientError(0, [{
|
|
120
|
+
return new HttpClientError(cause.message, 0, [{
|
|
91
121
|
type,
|
|
92
122
|
context: null,
|
|
93
123
|
reason: cause.message,
|
|
@@ -101,47 +131,61 @@ var ful = (function (exports) {
|
|
|
101
131
|
*/
|
|
102
132
|
static async fromResponse(response) {
|
|
103
133
|
const text = await response.text();
|
|
104
|
-
const
|
|
134
|
+
const message = `${response.status} ${response.statusText}: ${text}`;
|
|
135
|
+
const fallback = [{
|
|
105
136
|
type: "GENERIC_PROBLEM",
|
|
106
137
|
context: null,
|
|
107
|
-
reason:
|
|
138
|
+
reason: message,
|
|
108
139
|
details: null
|
|
109
140
|
}];
|
|
110
141
|
try {
|
|
111
|
-
return new HttpClientError(response.status, text ? JSON.parse(text) :
|
|
142
|
+
return new HttpClientError(message, response.status, text ? JSON.parse(text) : fallback);
|
|
112
143
|
} catch (e) {
|
|
113
|
-
return new HttpClientError(response.status,
|
|
144
|
+
return new HttpClientError(message, response.status, fallback);
|
|
114
145
|
}
|
|
115
146
|
}
|
|
116
147
|
}
|
|
117
148
|
|
|
149
|
+
/**
|
|
150
|
+
* @implements {HttpInterceptor}
|
|
151
|
+
*/
|
|
118
152
|
class CsrfTokenInterceptor {
|
|
119
153
|
#k; #v;
|
|
120
154
|
constructor() {
|
|
121
|
-
this.#k = document.querySelector("meta[name='_csrf_header']")
|
|
122
|
-
this.#v = document.querySelector("meta[name='_csrf']")
|
|
123
|
-
}
|
|
155
|
+
this.#k = document.querySelector("meta[name='_csrf_header']")?.getAttribute("content");
|
|
156
|
+
this.#v = document.querySelector("meta[name='_csrf']")?.getAttribute("content");
|
|
157
|
+
}
|
|
124
158
|
async intercept(request, chain) {
|
|
125
|
-
|
|
159
|
+
if(this.#k && this.#v) {
|
|
160
|
+
request.headers.set(this.#k, this.#v);
|
|
161
|
+
}
|
|
126
162
|
return await chain.proceed(request);
|
|
127
163
|
}
|
|
128
164
|
}
|
|
129
|
-
|
|
165
|
+
/**
|
|
166
|
+
* @implements {HttpInterceptor}
|
|
167
|
+
*/
|
|
130
168
|
class RedirectOnUnauthorizedInterceptor {
|
|
131
169
|
#redirectUri;
|
|
170
|
+
/**
|
|
171
|
+
* @param {string} redirectUri
|
|
172
|
+
*/
|
|
132
173
|
constructor(redirectUri) {
|
|
133
174
|
this.#redirectUri = redirectUri;
|
|
134
175
|
}
|
|
135
176
|
async intercept(request, chain) {
|
|
136
177
|
const response = await chain.proceed(request);
|
|
137
|
-
if (response.status
|
|
138
|
-
|
|
178
|
+
if (response.status === 401) {
|
|
179
|
+
window.location.href = this.#redirectUri;
|
|
139
180
|
}
|
|
140
|
-
|
|
181
|
+
return response;
|
|
141
182
|
}
|
|
142
183
|
}
|
|
143
184
|
|
|
144
185
|
class HttpClientBuilder {
|
|
186
|
+
/**
|
|
187
|
+
* @type {HttpInterceptor[]}
|
|
188
|
+
*/
|
|
145
189
|
#interceptors;
|
|
146
190
|
constructor() {
|
|
147
191
|
this.#interceptors = [];
|
|
@@ -154,6 +198,9 @@ var ful = (function (exports) {
|
|
|
154
198
|
this.#interceptors.push(new RedirectOnUnauthorizedInterceptor(redirectUri));
|
|
155
199
|
return this;
|
|
156
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* @param {...HttpInterceptor} interceptors
|
|
203
|
+
*/
|
|
157
204
|
withInterceptors(...interceptors) {
|
|
158
205
|
this.#interceptors.push(...interceptors);
|
|
159
206
|
return this;
|
|
@@ -163,27 +210,35 @@ var ful = (function (exports) {
|
|
|
163
210
|
}
|
|
164
211
|
}
|
|
165
212
|
|
|
213
|
+
/**
|
|
214
|
+
* @implements {HttpInterceptor}
|
|
215
|
+
*/
|
|
166
216
|
class HttpCall {
|
|
167
|
-
/**
|
|
168
|
-
*
|
|
169
|
-
* @async
|
|
170
|
-
* @param {Request} request
|
|
171
|
-
* @param {HttpInterceptorChain} chain
|
|
172
|
-
* @returns {Promise<Response>} the response
|
|
173
|
-
*/
|
|
174
217
|
async intercept(request, chain) {
|
|
175
218
|
return await fetch(request);
|
|
176
219
|
}
|
|
177
220
|
}
|
|
178
221
|
|
|
179
222
|
class HttpInterceptorChain {
|
|
223
|
+
#interceptors;
|
|
224
|
+
#current;
|
|
225
|
+
/**
|
|
226
|
+
*
|
|
227
|
+
* @param {HttpInterceptor[]} interceptors
|
|
228
|
+
* @param {number} current
|
|
229
|
+
*/
|
|
180
230
|
constructor(interceptors, current) {
|
|
181
|
-
this
|
|
182
|
-
this
|
|
231
|
+
this.#interceptors = interceptors;
|
|
232
|
+
this.#current = current;
|
|
183
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
*
|
|
236
|
+
* @param {Request} request
|
|
237
|
+
* @returns {Promise<Response>} the response
|
|
238
|
+
*/
|
|
184
239
|
async proceed(request) {
|
|
185
|
-
const interceptor = this
|
|
186
|
-
return await interceptor.intercept(request, new HttpInterceptorChain(this
|
|
240
|
+
const interceptor = this.#interceptors[this.#current];
|
|
241
|
+
return await interceptor.intercept(request, new HttpInterceptorChain(this.#interceptors, this.#current + 1));
|
|
187
242
|
}
|
|
188
243
|
}
|
|
189
244
|
|
|
@@ -191,14 +246,14 @@ var ful = (function (exports) {
|
|
|
191
246
|
#interceptors;
|
|
192
247
|
/**
|
|
193
248
|
* Creates a builder for an HttpClient.
|
|
194
|
-
* @returns {
|
|
249
|
+
* @returns {HttpClientBuilder} the client builder
|
|
195
250
|
*/
|
|
196
251
|
static builder() {
|
|
197
252
|
return new HttpClientBuilder();
|
|
198
253
|
}
|
|
199
254
|
/**
|
|
200
255
|
* Creates an HttpClient.
|
|
201
|
-
* @
|
|
256
|
+
* @param {HttpInterceptor[]|undefined} interceptors - a list of interceptors to be registered for every request performed by the created client.
|
|
202
257
|
*/
|
|
203
258
|
constructor(interceptors) {
|
|
204
259
|
this.#interceptors = interceptors || [];
|
|
@@ -208,7 +263,7 @@ var ful = (function (exports) {
|
|
|
208
263
|
* @async
|
|
209
264
|
* @param {string} uri - the (possibly relative) request url
|
|
210
265
|
* @param {RequestInit|undefined} options - fetch options
|
|
211
|
-
* @param {[
|
|
266
|
+
* @param {HttpInterceptor[]|undefined} interceptors - the HttpInterceptors to be registered for this exchange.
|
|
212
267
|
* @returns {Promise<Response>} the response
|
|
213
268
|
*/
|
|
214
269
|
async exchange(uri, options, interceptors) {
|
|
@@ -275,12 +330,17 @@ var ful = (function (exports) {
|
|
|
275
330
|
}
|
|
276
331
|
}
|
|
277
332
|
|
|
278
|
-
|
|
333
|
+
/**
|
|
334
|
+
*
|
|
335
|
+
* @param {Response} response
|
|
336
|
+
* @param {'text'|'json'|'blob'|'arrayBuffer'} type
|
|
337
|
+
* @returns
|
|
338
|
+
*/
|
|
279
339
|
const unmarshal = async (response, type) => {
|
|
280
340
|
try {
|
|
281
341
|
return await response[type]();
|
|
282
|
-
} catch (
|
|
283
|
-
throw HttpClientError.of("UNMARSHALING_PROBLEM",
|
|
342
|
+
} catch (ex) {
|
|
343
|
+
throw HttpClientError.of("UNMARSHALING_PROBLEM", ex);
|
|
284
344
|
}
|
|
285
345
|
};
|
|
286
346
|
|
|
@@ -322,7 +382,7 @@ var ful = (function (exports) {
|
|
|
322
382
|
* @param {Headers} headers
|
|
323
383
|
* @param {any} body
|
|
324
384
|
* @param {Omit<RequestInit,"headers"|"method"|"body">} options
|
|
325
|
-
* @param {[
|
|
385
|
+
* @param {HttpInterceptor[]} interceptors
|
|
326
386
|
*/
|
|
327
387
|
constructor(client, method, uri, params, headers, body, options, interceptors) {
|
|
328
388
|
this.#client = client;
|
|
@@ -336,7 +396,7 @@ var ful = (function (exports) {
|
|
|
336
396
|
}
|
|
337
397
|
/**
|
|
338
398
|
* Add all passed headers to the request, overriding existing ones if that key already exists.
|
|
339
|
-
* @param {
|
|
399
|
+
* @param {HeadersInit} hs
|
|
340
400
|
* @returns {HttpRequestBuilder} this builder
|
|
341
401
|
*/
|
|
342
402
|
headers(hs) {
|
|
@@ -398,6 +458,17 @@ var ful = (function (exports) {
|
|
|
398
458
|
this.#body = JSON.stringify(body);
|
|
399
459
|
return this;
|
|
400
460
|
}
|
|
461
|
+
/**
|
|
462
|
+
* Sets the request body as a FormData configured using the callback.
|
|
463
|
+
* `Content-Type: multipart/form-data` header is automatically added by fetch if not explicitly set.
|
|
464
|
+
* @param {function(HttpMultipartRequestCustomizer):void} callback
|
|
465
|
+
*/
|
|
466
|
+
multipart(callback) {
|
|
467
|
+
const formData = new FormData();
|
|
468
|
+
const builder = new HttpMultipartRequestCustomizer(formData);
|
|
469
|
+
callback(builder);
|
|
470
|
+
this.#body = formData;
|
|
471
|
+
}
|
|
401
472
|
/**
|
|
402
473
|
* Sets a fetch options for the request.
|
|
403
474
|
* @param {Omit<RequestInit,"headers"|"method"|"body">} kvs
|
|
@@ -405,6 +476,7 @@ var ful = (function (exports) {
|
|
|
405
476
|
*/
|
|
406
477
|
options(kvs) {
|
|
407
478
|
for (const [k, v] of Object.entries(kvs)) {
|
|
479
|
+
// @ts-ignore
|
|
408
480
|
this.#options[k] = v;
|
|
409
481
|
}
|
|
410
482
|
return this;
|
|
@@ -471,11 +543,11 @@ var ful = (function (exports) {
|
|
|
471
543
|
throw await HttpClientError.fromResponse(response);
|
|
472
544
|
}
|
|
473
545
|
return response;
|
|
474
|
-
} catch (
|
|
475
|
-
if (
|
|
476
|
-
throw
|
|
546
|
+
} catch (ex) {
|
|
547
|
+
if (ex instanceof Failure) {
|
|
548
|
+
throw ex;
|
|
477
549
|
}
|
|
478
|
-
throw HttpClientError.of("CONNECTION_PROBLEM",
|
|
550
|
+
throw HttpClientError.of("CONNECTION_PROBLEM", ex);
|
|
479
551
|
}
|
|
480
552
|
}
|
|
481
553
|
/**
|
|
@@ -494,14 +566,6 @@ var ful = (function (exports) {
|
|
|
494
566
|
const response = await this.fetch();
|
|
495
567
|
return await unmarshal(response, 'json');
|
|
496
568
|
}
|
|
497
|
-
/**
|
|
498
|
-
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
499
|
-
* @returns {Promise<Uint8Array>} the response body, as an Uint8Array
|
|
500
|
-
*/
|
|
501
|
-
async fetchBytes() {
|
|
502
|
-
const response = await this.fetch();
|
|
503
|
-
return await unmarshal(response, 'bytes');
|
|
504
|
-
}
|
|
505
569
|
/**
|
|
506
570
|
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
507
571
|
* @returns {Promise<Blob>} the response body, as a Blob
|
|
@@ -520,6 +584,54 @@ var ful = (function (exports) {
|
|
|
520
584
|
}
|
|
521
585
|
}
|
|
522
586
|
|
|
587
|
+
|
|
588
|
+
class HttpMultipartRequestCustomizer {
|
|
589
|
+
#formData;
|
|
590
|
+
/**
|
|
591
|
+
*
|
|
592
|
+
* @param {FormData} formData
|
|
593
|
+
*/
|
|
594
|
+
constructor(formData){
|
|
595
|
+
this.#formData = formData;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Appends a value to the FormData.
|
|
599
|
+
* @param {string} name
|
|
600
|
+
* @param {*} value
|
|
601
|
+
* @returns this builder
|
|
602
|
+
*/
|
|
603
|
+
field(name, value){
|
|
604
|
+
this.#formData.append(name, value);
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Appends a Blob to the FormData.
|
|
609
|
+
* If `filename` is omitted, FormData defaults are applied:
|
|
610
|
+
* The default filename for Blob objects is "blob";
|
|
611
|
+
* The default filename for File objects is the file's filename.
|
|
612
|
+
* @param {string} name
|
|
613
|
+
* @param {Blob} value
|
|
614
|
+
* @param {string|undefined} filename
|
|
615
|
+
* @returns this builder
|
|
616
|
+
*/
|
|
617
|
+
blob(name, value, filename){
|
|
618
|
+
this.#formData.append(name, value, filename);
|
|
619
|
+
return this;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Appends a JSON serialized blob to the FormData.
|
|
623
|
+
* @param {string} name
|
|
624
|
+
* @param {any} value
|
|
625
|
+
* @param {string|undefined} filename
|
|
626
|
+
* @returns this builder
|
|
627
|
+
*/
|
|
628
|
+
json(name, value, filename){
|
|
629
|
+
const blob = new Blob([JSON.stringify(value)], {type: 'application/json'});
|
|
630
|
+
this.#formData.append(name, blob, filename);
|
|
631
|
+
return this;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
523
635
|
class Storage {
|
|
524
636
|
constructor(prefix, storage) {
|
|
525
637
|
this.prefix = prefix;
|
|
@@ -616,7 +728,7 @@ var ful = (function (exports) {
|
|
|
616
728
|
Object.entries(additionalParams || {}).forEach(kv => {
|
|
617
729
|
url.searchParams.set(kv[0], kv[1]);
|
|
618
730
|
});
|
|
619
|
-
window.location = url;
|
|
731
|
+
window.location.href = url.toString();
|
|
620
732
|
}
|
|
621
733
|
async registration(additionalParams){
|
|
622
734
|
await this.action(this.uri.registration, additionalParams);
|
|
@@ -626,7 +738,7 @@ var ful = (function (exports) {
|
|
|
626
738
|
kc_action: kcAction
|
|
627
739
|
});
|
|
628
740
|
}
|
|
629
|
-
async
|
|
741
|
+
async #tokenExchange(code, state) {
|
|
630
742
|
window.history.replaceState('', "", this.uri.redirect);
|
|
631
743
|
const stateAndVerifier = this.storage.pop(AuthorizationCodeFlow.PKCE_AND_STATE_KEY);
|
|
632
744
|
if (stateAndVerifier.state !== state) {
|
|
@@ -659,7 +771,7 @@ var ful = (function (exports) {
|
|
|
659
771
|
if (code && this.storage.load(AuthorizationCodeFlow.PKCE_AND_STATE_KEY)) {
|
|
660
772
|
//if callback from keycloak and we have our state still stored
|
|
661
773
|
const state = url.searchParams.get("state");
|
|
662
|
-
return await this
|
|
774
|
+
return await this.#tokenExchange(code, state);
|
|
663
775
|
}
|
|
664
776
|
//if not authorized
|
|
665
777
|
await this.action(this.uri.auth, {});
|
|
@@ -730,7 +842,7 @@ var ful = (function (exports) {
|
|
|
730
842
|
const url = new URL(this.uri.logout);
|
|
731
843
|
url.searchParams.set("post_logout_redirect_uri", this.uri.redirect);
|
|
732
844
|
url.searchParams.set("id_token_hint", this.token.id_token);
|
|
733
|
-
window.location = url;
|
|
845
|
+
window.location.href = url.toString();
|
|
734
846
|
}
|
|
735
847
|
|
|
736
848
|
bearerToken() {
|
|
@@ -789,7 +901,7 @@ var ful = (function (exports) {
|
|
|
789
901
|
};
|
|
790
902
|
|
|
791
903
|
return function () {
|
|
792
|
-
args = arguments;
|
|
904
|
+
args = [...arguments];
|
|
793
905
|
previousTimestamp = new Date().getTime();
|
|
794
906
|
if (tid === null) {
|
|
795
907
|
tid = setTimeout(later, timeoutMs);
|
|
@@ -823,7 +935,7 @@ var ful = (function (exports) {
|
|
|
823
935
|
previousTimestamp = now;
|
|
824
936
|
}
|
|
825
937
|
const remaining = timeoutMs - (now - previousTimestamp);
|
|
826
|
-
args = arguments;
|
|
938
|
+
args = [...arguments];
|
|
827
939
|
if (remaining <= 0 || remaining > timeoutMs) {
|
|
828
940
|
if (tid !== null) {
|
|
829
941
|
clearTimeout(tid);
|
|
@@ -929,16 +1041,18 @@ var ful = (function (exports) {
|
|
|
929
1041
|
.forEach(a => {
|
|
930
1042
|
const target = a.substring(prefix.length);
|
|
931
1043
|
if (target === 'class') {
|
|
932
|
-
|
|
1044
|
+
const classes = from.getAttribute(prefix + "class")?.split(" ").filter(a => a.length) ?? [];
|
|
1045
|
+
to.classList.add(...classes);
|
|
933
1046
|
return;
|
|
934
1047
|
}
|
|
1048
|
+
// @ts-ignore
|
|
935
1049
|
to.setAttribute(target, from.getAttribute(a));
|
|
936
1050
|
});
|
|
937
1051
|
}
|
|
938
1052
|
/**
|
|
939
1053
|
*
|
|
940
1054
|
* @param {HTMLElement} el
|
|
941
|
-
* @param {
|
|
1055
|
+
* @param {string} attr
|
|
942
1056
|
* @param {boolean} value
|
|
943
1057
|
*/
|
|
944
1058
|
static toggle(el, attr, value) {
|
|
@@ -965,19 +1079,21 @@ var ful = (function (exports) {
|
|
|
965
1079
|
* @returns the slots
|
|
966
1080
|
*/
|
|
967
1081
|
static from(el) {
|
|
1082
|
+
/** @type [string, Element][] */
|
|
968
1083
|
const namedSlots = Array.from(el.childNodes)
|
|
969
|
-
.filter(el => el
|
|
1084
|
+
.filter(el => el instanceof Element)
|
|
1085
|
+
.filter(el => el.matches('[slot]'))
|
|
970
1086
|
.map(el => {
|
|
971
1087
|
el.remove();
|
|
972
1088
|
const slot = el.getAttribute("slot");
|
|
973
1089
|
el.removeAttribute("slot");
|
|
974
|
-
return [slot, el];
|
|
1090
|
+
return [slot ?? 'unnamed', el];
|
|
975
1091
|
});
|
|
976
1092
|
const slots = {};
|
|
977
1093
|
slots.default = new DocumentFragment();
|
|
978
1094
|
slots.default.append(...el.childNodes);
|
|
979
|
-
for(const [name,el] of namedSlots){
|
|
980
|
-
if(!(name in slots)){
|
|
1095
|
+
for (const [name, el] of namedSlots) {
|
|
1096
|
+
if (!(name in slots)) {
|
|
981
1097
|
slots[name] = new DocumentFragment();
|
|
982
1098
|
}
|
|
983
1099
|
slots[name].append(el);
|
|
@@ -1003,7 +1119,8 @@ var ful = (function (exports) {
|
|
|
1003
1119
|
#ec;
|
|
1004
1120
|
put(k, fragment) {
|
|
1005
1121
|
if (this.#ec) {
|
|
1006
|
-
|
|
1122
|
+
// @ts-ignore
|
|
1123
|
+
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, this.#ec);
|
|
1007
1124
|
return;
|
|
1008
1125
|
}
|
|
1009
1126
|
this.#idToFragment[k] = fragment;
|
|
@@ -1022,6 +1139,7 @@ var ful = (function (exports) {
|
|
|
1022
1139
|
this.#ec = ec;
|
|
1023
1140
|
for (const [k, fragment] of Object.entries(this.#idToFragment)) {
|
|
1024
1141
|
delete this.#idToFragment[k];
|
|
1142
|
+
// @ts-ignore
|
|
1025
1143
|
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec, ...data);
|
|
1026
1144
|
}
|
|
1027
1145
|
}
|
|
@@ -1125,8 +1243,8 @@ var ful = (function (exports) {
|
|
|
1125
1243
|
#initialized;
|
|
1126
1244
|
#reflecting;
|
|
1127
1245
|
#internals;
|
|
1128
|
-
constructor(
|
|
1129
|
-
super(
|
|
1246
|
+
constructor() {
|
|
1247
|
+
super();
|
|
1130
1248
|
this.#internals = this.attachInternals();
|
|
1131
1249
|
}
|
|
1132
1250
|
get initialized() {
|
|
@@ -1154,6 +1272,7 @@ var ful = (function (exports) {
|
|
|
1154
1272
|
observer.disconnect();
|
|
1155
1273
|
upgradeQueue.enqueue(this);
|
|
1156
1274
|
});
|
|
1275
|
+
// @ts-ignore
|
|
1157
1276
|
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
1158
1277
|
}
|
|
1159
1278
|
attributeChangedCallback(attr, oldValue, newValue) {
|
|
@@ -1179,6 +1298,7 @@ var ful = (function (exports) {
|
|
|
1179
1298
|
return;
|
|
1180
1299
|
}
|
|
1181
1300
|
this.#parsed = true;
|
|
1301
|
+
// @ts-ignore
|
|
1182
1302
|
await this.render(elements.template(templateId), slots ? LightSlots.from(this) : undefined);
|
|
1183
1303
|
|
|
1184
1304
|
for (const [attr, mapper] of attrsAndMappers) {
|
|
@@ -1330,7 +1450,7 @@ var ful = (function (exports) {
|
|
|
1330
1450
|
}
|
|
1331
1451
|
get values() {
|
|
1332
1452
|
return Array.from(this.querySelectorAll('[name]'))
|
|
1333
|
-
.filter(
|
|
1453
|
+
.filter(el => {
|
|
1334
1454
|
if (el.dataset['fulBindInclude'] === 'never') {
|
|
1335
1455
|
return false;
|
|
1336
1456
|
}
|
|
@@ -1341,14 +1461,14 @@ var ful = (function (exports) {
|
|
|
1341
1461
|
}, {});
|
|
1342
1462
|
}
|
|
1343
1463
|
set errors(es) {
|
|
1344
|
-
const fieldErrors = es.filter(
|
|
1345
|
-
const globalErrors = es.filter(
|
|
1464
|
+
const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');
|
|
1465
|
+
const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');
|
|
1346
1466
|
this.querySelectorAll(`.${Form.INVALID_CLASS}`).forEach(el => el.classList.remove(Form.INVALID_CLASS));
|
|
1347
1467
|
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1348
1468
|
el.replaceChildren();
|
|
1349
1469
|
el.setAttribute('hidden', '');
|
|
1350
1470
|
});
|
|
1351
|
-
fieldErrors.forEach(
|
|
1471
|
+
fieldErrors.forEach(e => {
|
|
1352
1472
|
const name = e.context.replace("[", ".").replace("].", ".");
|
|
1353
1473
|
const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;
|
|
1354
1474
|
this.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(Form.INVALID_CLASS));
|
|
@@ -1419,6 +1539,7 @@ var ful = (function (exports) {
|
|
|
1419
1539
|
slots: true,
|
|
1420
1540
|
template: INPUT_TEMPLATE
|
|
1421
1541
|
}){
|
|
1542
|
+
input;
|
|
1422
1543
|
render(template, slots) {
|
|
1423
1544
|
const fragment = makeInputFragment(this, template, slots);
|
|
1424
1545
|
this.replaceChildren(fragment);
|
|
@@ -1589,27 +1710,40 @@ var ful = (function (exports) {
|
|
|
1589
1710
|
input.addEventListener('change', evt => {
|
|
1590
1711
|
evt.stopPropagation();
|
|
1591
1712
|
//change is not cancelable
|
|
1592
|
-
this.dispatchEvent(new CustomEvent('change', {
|
|
1593
|
-
bubbles: true,
|
|
1594
|
-
cancelable: false,
|
|
1713
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
1714
|
+
bubbles: true,
|
|
1715
|
+
cancelable: false,
|
|
1595
1716
|
detail: {
|
|
1596
1717
|
value: this.value
|
|
1597
1718
|
}
|
|
1598
|
-
}));
|
|
1599
|
-
});
|
|
1719
|
+
}));
|
|
1720
|
+
});
|
|
1600
1721
|
const label = Fragments.fromChildNodes(el);
|
|
1601
1722
|
return [input, label];
|
|
1602
1723
|
});
|
|
1603
1724
|
|
|
1604
1725
|
radioEls.forEach(el => el.remove());
|
|
1605
|
-
template.renderTo(this, {name, slots, inputsAndLabels});
|
|
1726
|
+
template.renderTo(this, { name, slots, inputsAndLabels });
|
|
1606
1727
|
}
|
|
1607
1728
|
get value() {
|
|
1729
|
+
/** @type {HTMLInputElement|null} */
|
|
1608
1730
|
const checked = this.querySelector('input[type=radio]:checked');
|
|
1609
1731
|
return checked ? checked.value : null;
|
|
1610
1732
|
}
|
|
1611
1733
|
set value(value) {
|
|
1612
|
-
|
|
1734
|
+
if (value === null) {
|
|
1735
|
+
/** @type {HTMLInputElement[]} */
|
|
1736
|
+
this.querySelectorAll(`input[type=radio]`).forEach(el => {
|
|
1737
|
+
// @ts-ignore
|
|
1738
|
+
el.checked = false;
|
|
1739
|
+
});
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
/** @type {HTMLInputElement|null} */
|
|
1743
|
+
const el = this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`);
|
|
1744
|
+
if (el) {
|
|
1745
|
+
el.checked = true;
|
|
1746
|
+
}
|
|
1613
1747
|
}
|
|
1614
1748
|
}
|
|
1615
1749
|
|