@optionfactory/ful 0.90.0 → 0.92.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 +243 -80
- 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 +243 -80
- 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,18 @@ 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
|
+
return this;
|
|
472
|
+
}
|
|
401
473
|
/**
|
|
402
474
|
* Sets a fetch options for the request.
|
|
403
475
|
* @param {Omit<RequestInit,"headers"|"method"|"body">} kvs
|
|
@@ -405,6 +477,7 @@ var ful = (function (exports) {
|
|
|
405
477
|
*/
|
|
406
478
|
options(kvs) {
|
|
407
479
|
for (const [k, v] of Object.entries(kvs)) {
|
|
480
|
+
// @ts-ignore
|
|
408
481
|
this.#options[k] = v;
|
|
409
482
|
}
|
|
410
483
|
return this;
|
|
@@ -471,11 +544,11 @@ var ful = (function (exports) {
|
|
|
471
544
|
throw await HttpClientError.fromResponse(response);
|
|
472
545
|
}
|
|
473
546
|
return response;
|
|
474
|
-
} catch (
|
|
475
|
-
if (
|
|
476
|
-
throw
|
|
547
|
+
} catch (ex) {
|
|
548
|
+
if (ex instanceof Failure) {
|
|
549
|
+
throw ex;
|
|
477
550
|
}
|
|
478
|
-
throw HttpClientError.of("CONNECTION_PROBLEM",
|
|
551
|
+
throw HttpClientError.of("CONNECTION_PROBLEM", ex);
|
|
479
552
|
}
|
|
480
553
|
}
|
|
481
554
|
/**
|
|
@@ -494,14 +567,6 @@ var ful = (function (exports) {
|
|
|
494
567
|
const response = await this.fetch();
|
|
495
568
|
return await unmarshal(response, 'json');
|
|
496
569
|
}
|
|
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
570
|
/**
|
|
506
571
|
* 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
572
|
* @returns {Promise<Blob>} the response body, as a Blob
|
|
@@ -520,6 +585,68 @@ var ful = (function (exports) {
|
|
|
520
585
|
}
|
|
521
586
|
}
|
|
522
587
|
|
|
588
|
+
|
|
589
|
+
class HttpMultipartRequestCustomizer {
|
|
590
|
+
#formData;
|
|
591
|
+
/**
|
|
592
|
+
*
|
|
593
|
+
* @param {FormData} formData
|
|
594
|
+
*/
|
|
595
|
+
constructor(formData){
|
|
596
|
+
this.#formData = formData;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Appends a value to the FormData.
|
|
600
|
+
* @param {string} name
|
|
601
|
+
* @param {*} value
|
|
602
|
+
* @returns this builder
|
|
603
|
+
*/
|
|
604
|
+
field(name, value){
|
|
605
|
+
this.#formData.append(name, value);
|
|
606
|
+
return this;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Appends a Blob to the FormData.
|
|
610
|
+
* If `filename` is omitted, FormData defaults are applied:
|
|
611
|
+
* The default filename for Blob objects is "blob";
|
|
612
|
+
* The default filename for File objects is the file's filename.
|
|
613
|
+
* @param {string} name
|
|
614
|
+
* @param {Blob} value
|
|
615
|
+
* @param {string|undefined} filename
|
|
616
|
+
* @returns this builder
|
|
617
|
+
*/
|
|
618
|
+
blob(name, value, filename){
|
|
619
|
+
this.#formData.append(name, value, filename);
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Appends multiple Blobs to the FormData with the same name.
|
|
624
|
+
* The default filename for Blob objects is "blob";
|
|
625
|
+
* The default filename for File objects is the file's filename.
|
|
626
|
+
* @param {string} name
|
|
627
|
+
* @param {Blob[]} values
|
|
628
|
+
* @returns this builder
|
|
629
|
+
*/
|
|
630
|
+
blobs(name, values){
|
|
631
|
+
for(let v of values){
|
|
632
|
+
this.#formData.append(name, v);
|
|
633
|
+
}
|
|
634
|
+
return this;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Appends a JSON serialized blob to the FormData.
|
|
638
|
+
* @param {string} name
|
|
639
|
+
* @param {any} value
|
|
640
|
+
* @param {string|undefined} filename
|
|
641
|
+
* @returns this builder
|
|
642
|
+
*/
|
|
643
|
+
json(name, value, filename){
|
|
644
|
+
const blob = new Blob([JSON.stringify(value)], {type: 'application/json'});
|
|
645
|
+
this.#formData.append(name, blob, filename);
|
|
646
|
+
return this;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
523
650
|
class Storage {
|
|
524
651
|
constructor(prefix, storage) {
|
|
525
652
|
this.prefix = prefix;
|
|
@@ -616,7 +743,7 @@ var ful = (function (exports) {
|
|
|
616
743
|
Object.entries(additionalParams || {}).forEach(kv => {
|
|
617
744
|
url.searchParams.set(kv[0], kv[1]);
|
|
618
745
|
});
|
|
619
|
-
window.location = url;
|
|
746
|
+
window.location.href = url.toString();
|
|
620
747
|
}
|
|
621
748
|
async registration(additionalParams){
|
|
622
749
|
await this.action(this.uri.registration, additionalParams);
|
|
@@ -626,7 +753,7 @@ var ful = (function (exports) {
|
|
|
626
753
|
kc_action: kcAction
|
|
627
754
|
});
|
|
628
755
|
}
|
|
629
|
-
async
|
|
756
|
+
async #tokenExchange(code, state) {
|
|
630
757
|
window.history.replaceState('', "", this.uri.redirect);
|
|
631
758
|
const stateAndVerifier = this.storage.pop(AuthorizationCodeFlow.PKCE_AND_STATE_KEY);
|
|
632
759
|
if (stateAndVerifier.state !== state) {
|
|
@@ -659,7 +786,7 @@ var ful = (function (exports) {
|
|
|
659
786
|
if (code && this.storage.load(AuthorizationCodeFlow.PKCE_AND_STATE_KEY)) {
|
|
660
787
|
//if callback from keycloak and we have our state still stored
|
|
661
788
|
const state = url.searchParams.get("state");
|
|
662
|
-
return await this
|
|
789
|
+
return await this.#tokenExchange(code, state);
|
|
663
790
|
}
|
|
664
791
|
//if not authorized
|
|
665
792
|
await this.action(this.uri.auth, {});
|
|
@@ -730,7 +857,7 @@ var ful = (function (exports) {
|
|
|
730
857
|
const url = new URL(this.uri.logout);
|
|
731
858
|
url.searchParams.set("post_logout_redirect_uri", this.uri.redirect);
|
|
732
859
|
url.searchParams.set("id_token_hint", this.token.id_token);
|
|
733
|
-
window.location = url;
|
|
860
|
+
window.location.href = url.toString();
|
|
734
861
|
}
|
|
735
862
|
|
|
736
863
|
bearerToken() {
|
|
@@ -789,7 +916,7 @@ var ful = (function (exports) {
|
|
|
789
916
|
};
|
|
790
917
|
|
|
791
918
|
return function () {
|
|
792
|
-
args = arguments;
|
|
919
|
+
args = [...arguments];
|
|
793
920
|
previousTimestamp = new Date().getTime();
|
|
794
921
|
if (tid === null) {
|
|
795
922
|
tid = setTimeout(later, timeoutMs);
|
|
@@ -823,7 +950,7 @@ var ful = (function (exports) {
|
|
|
823
950
|
previousTimestamp = now;
|
|
824
951
|
}
|
|
825
952
|
const remaining = timeoutMs - (now - previousTimestamp);
|
|
826
|
-
args = arguments;
|
|
953
|
+
args = [...arguments];
|
|
827
954
|
if (remaining <= 0 || remaining > timeoutMs) {
|
|
828
955
|
if (tid !== null) {
|
|
829
956
|
clearTimeout(tid);
|
|
@@ -929,16 +1056,18 @@ var ful = (function (exports) {
|
|
|
929
1056
|
.forEach(a => {
|
|
930
1057
|
const target = a.substring(prefix.length);
|
|
931
1058
|
if (target === 'class') {
|
|
932
|
-
|
|
1059
|
+
const classes = from.getAttribute(prefix + "class")?.split(" ").filter(a => a.length) ?? [];
|
|
1060
|
+
to.classList.add(...classes);
|
|
933
1061
|
return;
|
|
934
1062
|
}
|
|
1063
|
+
// @ts-ignore
|
|
935
1064
|
to.setAttribute(target, from.getAttribute(a));
|
|
936
1065
|
});
|
|
937
1066
|
}
|
|
938
1067
|
/**
|
|
939
1068
|
*
|
|
940
1069
|
* @param {HTMLElement} el
|
|
941
|
-
* @param {
|
|
1070
|
+
* @param {string} attr
|
|
942
1071
|
* @param {boolean} value
|
|
943
1072
|
*/
|
|
944
1073
|
static toggle(el, attr, value) {
|
|
@@ -965,19 +1094,21 @@ var ful = (function (exports) {
|
|
|
965
1094
|
* @returns the slots
|
|
966
1095
|
*/
|
|
967
1096
|
static from(el) {
|
|
1097
|
+
/** @type [string, Element][] */
|
|
968
1098
|
const namedSlots = Array.from(el.childNodes)
|
|
969
|
-
.filter(el => el
|
|
1099
|
+
.filter(el => el instanceof Element)
|
|
1100
|
+
.filter(el => el.matches('[slot]'))
|
|
970
1101
|
.map(el => {
|
|
971
1102
|
el.remove();
|
|
972
1103
|
const slot = el.getAttribute("slot");
|
|
973
1104
|
el.removeAttribute("slot");
|
|
974
|
-
return [slot, el];
|
|
1105
|
+
return [slot ?? 'unnamed', el];
|
|
975
1106
|
});
|
|
976
1107
|
const slots = {};
|
|
977
1108
|
slots.default = new DocumentFragment();
|
|
978
1109
|
slots.default.append(...el.childNodes);
|
|
979
|
-
for(const [name,el] of namedSlots){
|
|
980
|
-
if(!(name in slots)){
|
|
1110
|
+
for (const [name, el] of namedSlots) {
|
|
1111
|
+
if (!(name in slots)) {
|
|
981
1112
|
slots[name] = new DocumentFragment();
|
|
982
1113
|
}
|
|
983
1114
|
slots[name].append(el);
|
|
@@ -1003,7 +1134,8 @@ var ful = (function (exports) {
|
|
|
1003
1134
|
#ec;
|
|
1004
1135
|
put(k, fragment) {
|
|
1005
1136
|
if (this.#ec) {
|
|
1006
|
-
|
|
1137
|
+
// @ts-ignore
|
|
1138
|
+
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, this.#ec);
|
|
1007
1139
|
return;
|
|
1008
1140
|
}
|
|
1009
1141
|
this.#idToFragment[k] = fragment;
|
|
@@ -1022,6 +1154,7 @@ var ful = (function (exports) {
|
|
|
1022
1154
|
this.#ec = ec;
|
|
1023
1155
|
for (const [k, fragment] of Object.entries(this.#idToFragment)) {
|
|
1024
1156
|
delete this.#idToFragment[k];
|
|
1157
|
+
// @ts-ignore
|
|
1025
1158
|
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec, ...data);
|
|
1026
1159
|
}
|
|
1027
1160
|
}
|
|
@@ -1125,8 +1258,8 @@ var ful = (function (exports) {
|
|
|
1125
1258
|
#initialized;
|
|
1126
1259
|
#reflecting;
|
|
1127
1260
|
#internals;
|
|
1128
|
-
constructor(
|
|
1129
|
-
super(
|
|
1261
|
+
constructor() {
|
|
1262
|
+
super();
|
|
1130
1263
|
this.#internals = this.attachInternals();
|
|
1131
1264
|
}
|
|
1132
1265
|
get initialized() {
|
|
@@ -1154,6 +1287,7 @@ var ful = (function (exports) {
|
|
|
1154
1287
|
observer.disconnect();
|
|
1155
1288
|
upgradeQueue.enqueue(this);
|
|
1156
1289
|
});
|
|
1290
|
+
// @ts-ignore
|
|
1157
1291
|
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
1158
1292
|
}
|
|
1159
1293
|
attributeChangedCallback(attr, oldValue, newValue) {
|
|
@@ -1179,6 +1313,7 @@ var ful = (function (exports) {
|
|
|
1179
1313
|
return;
|
|
1180
1314
|
}
|
|
1181
1315
|
this.#parsed = true;
|
|
1316
|
+
// @ts-ignore
|
|
1182
1317
|
await this.render(elements.template(templateId), slots ? LightSlots.from(this) : undefined);
|
|
1183
1318
|
|
|
1184
1319
|
for (const [attr, mapper] of attrsAndMappers) {
|
|
@@ -1281,6 +1416,7 @@ var ful = (function (exports) {
|
|
|
1281
1416
|
static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';
|
|
1282
1417
|
static SCROLL_OFFSET = 50;
|
|
1283
1418
|
static INVALID_CLASS = 'is-invalid';
|
|
1419
|
+
submitter;
|
|
1284
1420
|
render() {
|
|
1285
1421
|
const form = document.createElement('form');
|
|
1286
1422
|
form.replaceChildren(...this.childNodes);
|
|
@@ -1293,8 +1429,14 @@ var ful = (function (exports) {
|
|
|
1293
1429
|
this.replaceChildren(form);
|
|
1294
1430
|
}
|
|
1295
1431
|
spinner(spin) {
|
|
1296
|
-
this.querySelectorAll('ful-spinner').forEach(el =>
|
|
1297
|
-
|
|
1432
|
+
this.querySelectorAll('ful-spinner').forEach(el => {
|
|
1433
|
+
const hel = /** @type HTMLElement} */ (el);
|
|
1434
|
+
hel.hidden = !spin;
|
|
1435
|
+
});
|
|
1436
|
+
this.querySelectorAll('[type=submit],[type=reset]').forEach(el => {
|
|
1437
|
+
const hel = /** @type HTMLButtonElement} */ (el);
|
|
1438
|
+
hel.disabled = spin;
|
|
1439
|
+
});
|
|
1298
1440
|
}
|
|
1299
1441
|
async remoting(fn) {
|
|
1300
1442
|
try {
|
|
@@ -1329,8 +1471,8 @@ var ful = (function (exports) {
|
|
|
1329
1471
|
}
|
|
1330
1472
|
}
|
|
1331
1473
|
get values() {
|
|
1332
|
-
return Array.from(this.querySelectorAll('[name]'))
|
|
1333
|
-
.filter(
|
|
1474
|
+
return Array.from(/** @type {NodeListOf<HTMLElement>} */ (this.querySelectorAll('[name]')))
|
|
1475
|
+
.filter(el => {
|
|
1334
1476
|
if (el.dataset['fulBindInclude'] === 'never') {
|
|
1335
1477
|
return false;
|
|
1336
1478
|
}
|
|
@@ -1341,22 +1483,26 @@ var ful = (function (exports) {
|
|
|
1341
1483
|
}, {});
|
|
1342
1484
|
}
|
|
1343
1485
|
set errors(es) {
|
|
1344
|
-
const fieldErrors = es.filter(
|
|
1345
|
-
const globalErrors = es.filter(
|
|
1486
|
+
const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');
|
|
1487
|
+
const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');
|
|
1346
1488
|
this.querySelectorAll(`.${Form.INVALID_CLASS}`).forEach(el => el.classList.remove(Form.INVALID_CLASS));
|
|
1347
1489
|
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1348
1490
|
el.replaceChildren();
|
|
1349
1491
|
el.setAttribute('hidden', '');
|
|
1350
1492
|
});
|
|
1351
|
-
fieldErrors.forEach(
|
|
1493
|
+
fieldErrors.forEach(e => {
|
|
1352
1494
|
const name = e.context.replace("[", ".").replace("].", ".");
|
|
1353
1495
|
const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;
|
|
1354
1496
|
this.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(Form.INVALID_CLASS));
|
|
1355
1497
|
const fieldErrorsSelector = `ful-field-error[field='${CSS.escape(name)}']`;
|
|
1356
|
-
this.querySelectorAll(fieldErrorsSelector).forEach(el =>
|
|
1498
|
+
this.querySelectorAll(fieldErrorsSelector).forEach(el => {
|
|
1499
|
+
const hel = /** @type HTMLElement} */ (el);
|
|
1500
|
+
hel.innerText = e.reason;
|
|
1501
|
+
});
|
|
1357
1502
|
});
|
|
1358
1503
|
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1359
|
-
|
|
1504
|
+
const hel = /** @type HTMLElement} */ (el);
|
|
1505
|
+
hel.innerText = globalErrors.map(e => e.reason).join("\n");
|
|
1360
1506
|
if (globalErrors.length !== 0) {
|
|
1361
1507
|
el.removeAttribute('hidden');
|
|
1362
1508
|
}
|
|
@@ -1419,6 +1565,7 @@ var ful = (function (exports) {
|
|
|
1419
1565
|
slots: true,
|
|
1420
1566
|
template: INPUT_TEMPLATE
|
|
1421
1567
|
}){
|
|
1568
|
+
input;
|
|
1422
1569
|
render(template, slots) {
|
|
1423
1570
|
const fragment = makeInputFragment(this, template, slots);
|
|
1424
1571
|
this.replaceChildren(fragment);
|
|
@@ -1454,6 +1601,8 @@ var ful = (function (exports) {
|
|
|
1454
1601
|
</div>
|
|
1455
1602
|
`
|
|
1456
1603
|
}) {
|
|
1604
|
+
shouldLoad;
|
|
1605
|
+
_unwrappedRemoteLoad;
|
|
1457
1606
|
constructor(tsConfig) {
|
|
1458
1607
|
super();
|
|
1459
1608
|
this.tsConfig = tsConfig;
|
|
@@ -1505,6 +1654,7 @@ var ful = (function (exports) {
|
|
|
1505
1654
|
}
|
|
1506
1655
|
callback(data);
|
|
1507
1656
|
};
|
|
1657
|
+
// @ts-ignore
|
|
1508
1658
|
this.ts = new TomSelect(input, Object.assign(remote ? {
|
|
1509
1659
|
preload: 'focus',
|
|
1510
1660
|
load: this._unwrappedRemoteLoad,
|
|
@@ -1589,27 +1739,40 @@ var ful = (function (exports) {
|
|
|
1589
1739
|
input.addEventListener('change', evt => {
|
|
1590
1740
|
evt.stopPropagation();
|
|
1591
1741
|
//change is not cancelable
|
|
1592
|
-
this.dispatchEvent(new CustomEvent('change', {
|
|
1593
|
-
bubbles: true,
|
|
1594
|
-
cancelable: false,
|
|
1742
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
1743
|
+
bubbles: true,
|
|
1744
|
+
cancelable: false,
|
|
1595
1745
|
detail: {
|
|
1596
1746
|
value: this.value
|
|
1597
1747
|
}
|
|
1598
|
-
}));
|
|
1599
|
-
});
|
|
1748
|
+
}));
|
|
1749
|
+
});
|
|
1600
1750
|
const label = Fragments.fromChildNodes(el);
|
|
1601
1751
|
return [input, label];
|
|
1602
1752
|
});
|
|
1603
1753
|
|
|
1604
1754
|
radioEls.forEach(el => el.remove());
|
|
1605
|
-
template.renderTo(this, {name, slots, inputsAndLabels});
|
|
1755
|
+
template.renderTo(this, { name, slots, inputsAndLabels });
|
|
1606
1756
|
}
|
|
1607
1757
|
get value() {
|
|
1758
|
+
/** @type {HTMLInputElement|null} */
|
|
1608
1759
|
const checked = this.querySelector('input[type=radio]:checked');
|
|
1609
1760
|
return checked ? checked.value : null;
|
|
1610
1761
|
}
|
|
1611
1762
|
set value(value) {
|
|
1612
|
-
|
|
1763
|
+
if (value === null) {
|
|
1764
|
+
/** @type {HTMLInputElement[]} */
|
|
1765
|
+
this.querySelectorAll(`input[type=radio]`).forEach(el => {
|
|
1766
|
+
// @ts-ignore
|
|
1767
|
+
el.checked = false;
|
|
1768
|
+
});
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
/** @type {HTMLInputElement|null} */
|
|
1772
|
+
const el = this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`);
|
|
1773
|
+
if (el) {
|
|
1774
|
+
el.checked = true;
|
|
1775
|
+
}
|
|
1613
1776
|
}
|
|
1614
1777
|
}
|
|
1615
1778
|
|