@optionfactory/ful 0.80.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 +567 -158
- 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 +567 -153
- package/dist/ful.mjs.map +1 -1
- package/package.json +10 -7
package/dist/ful.mjs
CHANGED
|
@@ -70,171 +70,563 @@ class Hex {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
/**
|
|
74
|
+
* @typedef {{ type: string; context: string?; reason: string; details: any?; }} Problem
|
|
75
|
+
*/
|
|
76
|
+
class Failure extends Error {
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {string} message
|
|
80
|
+
* @param {Problem[]} problems
|
|
81
|
+
* @param {*} cause
|
|
82
|
+
*/
|
|
83
|
+
constructor(message, problems, cause) {
|
|
84
|
+
super(message, { cause });
|
|
85
|
+
this.name = 'Failure';
|
|
86
|
+
this.problems = problems;
|
|
77
87
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {Int8Array| Uint8Array| Uint8ClampedArray| Int16Array| Uint16Array| Int32Array| Uint32Array| Float32Array| Float64Array| BigInt64Array| BigUint64Array} TypedArray
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* @typedef HttpInterceptor
|
|
95
|
+
* @property {function(Request,HttpInterceptorChain):Promise<Response>} intercept
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
class HttpClientError extends Failure {
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} message
|
|
101
|
+
* @param {number} status
|
|
102
|
+
* @param {{ type: string; context: string?; reason: string; details: any?; }[]} problems
|
|
103
|
+
* @param {Error|undefined} [cause]
|
|
104
|
+
*/
|
|
105
|
+
constructor(message, status, problems, cause) {
|
|
106
|
+
super(message, problems, cause);
|
|
107
|
+
this.name = 'HttpClientError';
|
|
108
|
+
this.status = status;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
*
|
|
112
|
+
* @param {string} type
|
|
113
|
+
* @param {any} cause
|
|
114
|
+
* @returns
|
|
115
|
+
*/
|
|
116
|
+
static of(type, cause) {
|
|
117
|
+
return new HttpClientError(cause.message, 0, [{
|
|
118
|
+
type,
|
|
119
|
+
context: null,
|
|
120
|
+
reason: cause.message,
|
|
121
|
+
details: null
|
|
122
|
+
}], cause);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Creates an HttpClientError from a Response.
|
|
126
|
+
* @param {Response} response
|
|
127
|
+
* @returns an HttpClientError
|
|
128
|
+
*/
|
|
129
|
+
static async fromResponse(response) {
|
|
130
|
+
const text = await response.text();
|
|
131
|
+
const message = `${response.status} ${response.statusText}: ${text}`;
|
|
132
|
+
const fallback = [{
|
|
133
|
+
type: "GENERIC_PROBLEM",
|
|
134
|
+
context: null,
|
|
135
|
+
reason: message,
|
|
136
|
+
details: null
|
|
137
|
+
}];
|
|
138
|
+
try {
|
|
139
|
+
return new HttpClientError(message, response.status, text ? JSON.parse(text) : fallback);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
return new HttpClientError(message, response.status, fallback);
|
|
142
|
+
}
|
|
82
143
|
}
|
|
83
144
|
}
|
|
84
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @implements {HttpInterceptor}
|
|
148
|
+
*/
|
|
85
149
|
class CsrfTokenInterceptor {
|
|
150
|
+
#k; #v;
|
|
86
151
|
constructor() {
|
|
87
|
-
this
|
|
88
|
-
this
|
|
89
|
-
}
|
|
90
|
-
async intercept(request, chain){
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
152
|
+
this.#k = document.querySelector("meta[name='_csrf_header']")?.getAttribute("content");
|
|
153
|
+
this.#v = document.querySelector("meta[name='_csrf']")?.getAttribute("content");
|
|
154
|
+
}
|
|
155
|
+
async intercept(request, chain) {
|
|
156
|
+
if(this.#k && this.#v) {
|
|
157
|
+
request.headers.set(this.#k, this.#v);
|
|
158
|
+
}
|
|
94
159
|
return await chain.proceed(request);
|
|
95
160
|
}
|
|
96
161
|
}
|
|
97
|
-
|
|
162
|
+
/**
|
|
163
|
+
* @implements {HttpInterceptor}
|
|
164
|
+
*/
|
|
98
165
|
class RedirectOnUnauthorizedInterceptor {
|
|
166
|
+
#redirectUri;
|
|
167
|
+
/**
|
|
168
|
+
* @param {string} redirectUri
|
|
169
|
+
*/
|
|
99
170
|
constructor(redirectUri) {
|
|
100
|
-
this
|
|
171
|
+
this.#redirectUri = redirectUri;
|
|
101
172
|
}
|
|
102
|
-
async intercept(request, chain){
|
|
103
|
-
const response =
|
|
104
|
-
if (response.status
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
window.location.href = this.redirectUri;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
class Failure extends Error {
|
|
112
|
-
static parseProblems(status, text) {
|
|
113
|
-
const def = [{
|
|
114
|
-
type: "GENERIC_PROBLEM",
|
|
115
|
-
context: null,
|
|
116
|
-
reason: `${status}: ${text}`,
|
|
117
|
-
details: null
|
|
118
|
-
}];
|
|
119
|
-
try {
|
|
120
|
-
return text ? JSON.parse(text) : def;
|
|
121
|
-
} catch (e) {
|
|
122
|
-
return def;
|
|
173
|
+
async intercept(request, chain) {
|
|
174
|
+
const response = await chain.proceed(request);
|
|
175
|
+
if (response.status === 401) {
|
|
176
|
+
window.location.href = this.#redirectUri;
|
|
123
177
|
}
|
|
124
|
-
|
|
125
|
-
static fromResponse(status, text) {
|
|
126
|
-
return new Failure(status, Failure.parseProblems(status, text));
|
|
127
|
-
}
|
|
128
|
-
constructor(status, problems) {
|
|
129
|
-
super(JSON.stringify(problems));
|
|
130
|
-
this.name = `Failure:${status}`;
|
|
131
|
-
this.status = status;
|
|
132
|
-
this.problems = problems;
|
|
178
|
+
return response;
|
|
133
179
|
}
|
|
134
180
|
}
|
|
135
181
|
|
|
136
182
|
class HttpClientBuilder {
|
|
183
|
+
/**
|
|
184
|
+
* @type {HttpInterceptor[]}
|
|
185
|
+
*/
|
|
186
|
+
#interceptors;
|
|
137
187
|
constructor() {
|
|
138
|
-
this
|
|
139
|
-
}
|
|
140
|
-
withContext() {
|
|
141
|
-
this.interceptors.push(new ContextInterceptor());
|
|
142
|
-
return this;
|
|
188
|
+
this.#interceptors = [];
|
|
143
189
|
}
|
|
144
190
|
withCsrfToken() {
|
|
145
|
-
this
|
|
191
|
+
this.#interceptors.push(new CsrfTokenInterceptor());
|
|
146
192
|
return this;
|
|
147
193
|
}
|
|
148
194
|
withRedirectOnUnauthorized(redirectUri) {
|
|
149
|
-
this
|
|
195
|
+
this.#interceptors.push(new RedirectOnUnauthorizedInterceptor(redirectUri));
|
|
150
196
|
return this;
|
|
151
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* @param {...HttpInterceptor} interceptors
|
|
200
|
+
*/
|
|
152
201
|
withInterceptors(...interceptors) {
|
|
153
|
-
this
|
|
202
|
+
this.#interceptors.push(...interceptors);
|
|
154
203
|
return this;
|
|
155
204
|
}
|
|
156
205
|
build() {
|
|
157
|
-
|
|
158
|
-
return new HttpClient({interceptors});
|
|
206
|
+
return new HttpClient(this.#interceptors);
|
|
159
207
|
}
|
|
160
208
|
}
|
|
161
209
|
|
|
210
|
+
/**
|
|
211
|
+
* @implements {HttpInterceptor}
|
|
212
|
+
*/
|
|
162
213
|
class HttpCall {
|
|
163
|
-
async intercept(request, chain){
|
|
164
|
-
return await fetch(request
|
|
165
|
-
}
|
|
214
|
+
async intercept(request, chain) {
|
|
215
|
+
return await fetch(request);
|
|
216
|
+
}
|
|
166
217
|
}
|
|
167
218
|
|
|
168
219
|
class HttpInterceptorChain {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
220
|
+
#interceptors;
|
|
221
|
+
#current;
|
|
222
|
+
/**
|
|
223
|
+
*
|
|
224
|
+
* @param {HttpInterceptor[]} interceptors
|
|
225
|
+
* @param {number} current
|
|
226
|
+
*/
|
|
227
|
+
constructor(interceptors, current) {
|
|
228
|
+
this.#interceptors = interceptors;
|
|
229
|
+
this.#current = current;
|
|
172
230
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
231
|
+
/**
|
|
232
|
+
*
|
|
233
|
+
* @param {Request} request
|
|
234
|
+
* @returns {Promise<Response>} the response
|
|
235
|
+
*/
|
|
236
|
+
async proceed(request) {
|
|
237
|
+
const interceptor = this.#interceptors[this.#current];
|
|
238
|
+
return await interceptor.intercept(request, new HttpInterceptorChain(this.#interceptors, this.#current + 1));
|
|
176
239
|
}
|
|
177
240
|
}
|
|
178
241
|
|
|
179
|
-
|
|
180
242
|
class HttpClient {
|
|
243
|
+
#interceptors;
|
|
244
|
+
/**
|
|
245
|
+
* Creates a builder for an HttpClient.
|
|
246
|
+
* @returns {HttpClientBuilder} the client builder
|
|
247
|
+
*/
|
|
181
248
|
static builder() {
|
|
182
249
|
return new HttpClientBuilder();
|
|
183
250
|
}
|
|
184
|
-
|
|
185
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Creates an HttpClient.
|
|
253
|
+
* @param {HttpInterceptor[]|undefined} interceptors - a list of interceptors to be registered for every request performed by the created client.
|
|
254
|
+
*/
|
|
255
|
+
constructor(interceptors) {
|
|
256
|
+
this.#interceptors = interceptors || [];
|
|
186
257
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Performs an HTTP exchange.
|
|
260
|
+
* @async
|
|
261
|
+
* @param {string} uri - the (possibly relative) request url
|
|
262
|
+
* @param {RequestInit|undefined} options - fetch options
|
|
263
|
+
* @param {HttpInterceptor[]|undefined} interceptors - the HttpInterceptors to be registered for this exchange.
|
|
264
|
+
* @returns {Promise<Response>} the response
|
|
265
|
+
*/
|
|
266
|
+
async exchange(uri, options, interceptors) {
|
|
267
|
+
const is = [...this.#interceptors, ...interceptors || [], new HttpCall()];
|
|
268
|
+
const chain = new HttpInterceptorChain(is, 0);
|
|
269
|
+
return await chain.proceed(new Request(uri, options));
|
|
192
270
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Creates a request builder.
|
|
273
|
+
* @param {string} method - the HTTP method to be used
|
|
274
|
+
* @param {string} uri - the (possibly relative) request url
|
|
275
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
276
|
+
*/
|
|
277
|
+
request(method, uri) {
|
|
278
|
+
return HttpRequestBuilder.create(this, method, uri);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Creates a request builder.
|
|
282
|
+
* @param {string} uri - the (possibly relative) request url
|
|
283
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
284
|
+
*/
|
|
285
|
+
get(uri) {
|
|
286
|
+
return HttpRequestBuilder.create(this, 'GET', uri);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Creates a request builder.
|
|
290
|
+
* @param {string} uri - the (possibly relative) request url
|
|
291
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
292
|
+
*/
|
|
293
|
+
head(uri) {
|
|
294
|
+
return HttpRequestBuilder.create(this, 'HEAD', uri);
|
|
200
295
|
}
|
|
201
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Creates a request builder.
|
|
298
|
+
* @param {string} uri - the (possibly relative) request url
|
|
299
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
300
|
+
*/
|
|
301
|
+
post(uri) {
|
|
302
|
+
return HttpRequestBuilder.create(this, 'POST', uri);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Creates a request builder.
|
|
306
|
+
* @param {string} uri - the (possibly relative) request url
|
|
307
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
308
|
+
*/
|
|
309
|
+
put(uri) {
|
|
310
|
+
return HttpRequestBuilder.create(this, 'PUT', uri);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Creates a request builder.
|
|
314
|
+
* @param {string} uri - the (possibly relative) request url
|
|
315
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
316
|
+
*/
|
|
317
|
+
patch(uri) {
|
|
318
|
+
return HttpRequestBuilder.create(this, 'PATCH', uri);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Creates a request builder.
|
|
322
|
+
* @param {string} uri - the (possibly relative) request url
|
|
323
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
324
|
+
*/
|
|
325
|
+
delete(uri) {
|
|
326
|
+
return HttpRequestBuilder.create(this, 'DELETE', uri);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
*
|
|
332
|
+
* @param {Response} response
|
|
333
|
+
* @param {'text'|'json'|'blob'|'arrayBuffer'} type
|
|
334
|
+
* @returns
|
|
335
|
+
*/
|
|
336
|
+
const unmarshal = async (response, type) => {
|
|
337
|
+
try {
|
|
338
|
+
return await response[type]();
|
|
339
|
+
} catch (ex) {
|
|
340
|
+
throw HttpClientError.of("UNMARSHALING_PROBLEM", ex);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class HttpRequestBuilder {
|
|
346
|
+
#client;
|
|
347
|
+
#method;
|
|
348
|
+
#uri;
|
|
349
|
+
#params;
|
|
350
|
+
#headers;
|
|
351
|
+
#body;
|
|
352
|
+
#options;
|
|
353
|
+
#interceptors;
|
|
354
|
+
/**
|
|
355
|
+
* Creates an HttpRequestBuilder.
|
|
356
|
+
* @param {HttpClient} client
|
|
357
|
+
* @param {string} method - the HTTP method to be used
|
|
358
|
+
* @param {string} uri - the (possibly relative) request url
|
|
359
|
+
* @returns {HttpRequestBuilder} the builder
|
|
360
|
+
*/
|
|
361
|
+
static create(client, method, uri) {
|
|
362
|
+
return new HttpRequestBuilder(
|
|
363
|
+
client,
|
|
364
|
+
method,
|
|
365
|
+
uri,
|
|
366
|
+
new URLSearchParams(),
|
|
367
|
+
new Headers(),
|
|
368
|
+
undefined,
|
|
369
|
+
{},
|
|
370
|
+
[]
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Creates an HttpRequestBuilder.
|
|
375
|
+
* @param {HttpClient} client
|
|
376
|
+
* @param {string} method - the HTTP method to be used
|
|
377
|
+
* @param {string} uri - the (possibly relative) request url
|
|
378
|
+
* @param {URLSearchParams} params
|
|
379
|
+
* @param {Headers} headers
|
|
380
|
+
* @param {any} body
|
|
381
|
+
* @param {Omit<RequestInit,"headers"|"method"|"body">} options
|
|
382
|
+
* @param {HttpInterceptor[]} interceptors
|
|
383
|
+
*/
|
|
384
|
+
constructor(client, method, uri, params, headers, body, options, interceptors) {
|
|
385
|
+
this.#client = client;
|
|
386
|
+
this.#method = method;
|
|
387
|
+
this.#uri = uri;
|
|
388
|
+
this.#params = params;
|
|
389
|
+
this.#body = body;
|
|
390
|
+
this.#headers = headers;
|
|
391
|
+
this.#options = options;
|
|
392
|
+
this.#interceptors = interceptors;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Add all passed headers to the request, overriding existing ones if that key already exists.
|
|
396
|
+
* @param {HeadersInit} hs
|
|
397
|
+
* @returns {HttpRequestBuilder} this builder
|
|
398
|
+
*/
|
|
399
|
+
headers(hs) {
|
|
400
|
+
for (const [k, v] of new Headers(hs).entries()) {
|
|
401
|
+
this.#headers.set(k, v);
|
|
402
|
+
}
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Adds an header to the request, overriding it if it already exists.
|
|
407
|
+
* @param {string} k
|
|
408
|
+
* @param {string} v
|
|
409
|
+
* @returns {HttpRequestBuilder} this builder
|
|
410
|
+
*/
|
|
411
|
+
header(k, v) {
|
|
412
|
+
this.#headers.set(k, v);
|
|
413
|
+
return this;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Add all query parameters to the request, overriding existing ones if that key already exists.
|
|
417
|
+
* @param {URLSearchParams|Record<string,string>|string[][]|string} ps
|
|
418
|
+
* @returns {HttpRequestBuilder} this builder
|
|
419
|
+
*/
|
|
420
|
+
params(ps) {
|
|
421
|
+
for (const [k, v] of new URLSearchParams(ps).entries()) {
|
|
422
|
+
this.#params.set(k, v);
|
|
423
|
+
}
|
|
424
|
+
return this;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Adds a query parameter to the request, overriding it if it already exists.
|
|
428
|
+
* @param {string} k
|
|
429
|
+
* @param {string} v
|
|
430
|
+
* @returns {HttpRequestBuilder} this builder
|
|
431
|
+
*/
|
|
432
|
+
param(k, v) {
|
|
433
|
+
this.#params.set(k, v);
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Sets the request body.
|
|
438
|
+
* `Content-Type: multipart/form-data` header is automatically added by fetch when data is a FormData instance if not explicitly set.
|
|
439
|
+
* `Content-Type: application/x-www-form-urlencoded` header is automatically added by fetch when data is an URLSearchParams instance if not explicitly set.
|
|
440
|
+
* `Content-Type: text/plain` header is automatically added by fetch when data is a string instance if not explicitly set.
|
|
441
|
+
* @param {string|ArrayBuffer|Blob|DataView|File|FormData|TypedArray|URLSearchParams|ReadableStream} data
|
|
442
|
+
* @returns {HttpRequestBuilder} this builder
|
|
443
|
+
*/
|
|
444
|
+
body(data) {
|
|
445
|
+
this.#body = data;
|
|
446
|
+
return this;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Sets the request body that will be serialized as json. Calling this method adds the `Content-Type application/json` header for the request.
|
|
450
|
+
* @param {any} body - the body to be serialized as json
|
|
451
|
+
* @returns {HttpRequestBuilder} this builder
|
|
452
|
+
*/
|
|
453
|
+
json(body) {
|
|
454
|
+
this.#headers.set("Content-Type", "application/json");
|
|
455
|
+
this.#body = JSON.stringify(body);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Sets the request body as a FormData configured using the callback.
|
|
460
|
+
* `Content-Type: multipart/form-data` header is automatically added by fetch if not explicitly set.
|
|
461
|
+
* @param {function(HttpMultipartRequestCustomizer):void} callback
|
|
462
|
+
*/
|
|
463
|
+
multipart(callback) {
|
|
464
|
+
const formData = new FormData();
|
|
465
|
+
const builder = new HttpMultipartRequestCustomizer(formData);
|
|
466
|
+
callback(builder);
|
|
467
|
+
this.#body = formData;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Sets a fetch options for the request.
|
|
471
|
+
* @param {Omit<RequestInit,"headers"|"method"|"body">} kvs
|
|
472
|
+
* @returns {HttpRequestBuilder} this builder
|
|
473
|
+
*/
|
|
474
|
+
options(kvs) {
|
|
475
|
+
for (const [k, v] of Object.entries(kvs)) {
|
|
476
|
+
// @ts-ignore
|
|
477
|
+
this.#options[k] = v;
|
|
478
|
+
}
|
|
479
|
+
return this;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Sets a fetch option for the request.
|
|
483
|
+
* @param {keyof Omit<RequestInit,"headers"|"method"|"body">} k
|
|
484
|
+
* @param {*} v
|
|
485
|
+
* @returns {HttpRequestBuilder} this builder
|
|
486
|
+
*/
|
|
487
|
+
option(k, v) {
|
|
488
|
+
this.#options[k] = v;
|
|
489
|
+
return this;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Adds interceptors to the request.
|
|
493
|
+
* @param {[HttpInterceptor]} is - the interceptor to be regisered
|
|
494
|
+
* @returns {HttpRequestBuilder} this builder
|
|
495
|
+
*/
|
|
496
|
+
interceptors(is) {
|
|
497
|
+
for (const i of is) {
|
|
498
|
+
this.#interceptors.push(i);
|
|
499
|
+
}
|
|
500
|
+
return this;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Adds an interceptor to the request.
|
|
504
|
+
* @param {HttpInterceptor} i - the interceptor to be regisered
|
|
505
|
+
* @returns {HttpRequestBuilder} this builder
|
|
506
|
+
*/
|
|
507
|
+
interceptor(i) {
|
|
508
|
+
this.#interceptors.push(i);
|
|
509
|
+
return this;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Performs an HTTP exchange using the configured client, request and interceptors.
|
|
513
|
+
* @returns {Promise<Response>} the response
|
|
514
|
+
*/
|
|
515
|
+
async exchange() {
|
|
516
|
+
const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;
|
|
517
|
+
const opts = {
|
|
518
|
+
...this.#options,
|
|
519
|
+
headers: this.#headers,
|
|
520
|
+
method: this.#method,
|
|
521
|
+
body: this.#body,
|
|
522
|
+
};
|
|
523
|
+
return await this.#client.exchange(uri, opts, this.#interceptors);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
527
|
+
* @returns {Promise<Response>} the response
|
|
528
|
+
*/
|
|
529
|
+
async fetch() {
|
|
530
|
+
const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;
|
|
531
|
+
const opts = {
|
|
532
|
+
...this.#options,
|
|
533
|
+
headers: this.#headers,
|
|
534
|
+
method: this.#method,
|
|
535
|
+
body: this.#body,
|
|
536
|
+
};
|
|
202
537
|
try {
|
|
203
|
-
const response = await this.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
} catch (e) {
|
|
207
|
-
if (e instanceof Failure) {
|
|
208
|
-
throw e;
|
|
538
|
+
const response = await this.#client.exchange(uri, opts, this.#interceptors);
|
|
539
|
+
if (!response.ok) {
|
|
540
|
+
throw await HttpClientError.fromResponse(response);
|
|
209
541
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
542
|
+
return response;
|
|
543
|
+
} catch (ex) {
|
|
544
|
+
if (ex instanceof Failure) {
|
|
545
|
+
throw ex;
|
|
546
|
+
}
|
|
547
|
+
throw HttpClientError.of("CONNECTION_PROBLEM", ex);
|
|
216
548
|
}
|
|
217
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
552
|
+
* @returns {Promise<string>} the response body, as text
|
|
553
|
+
*/
|
|
554
|
+
async fetchText() {
|
|
555
|
+
const response = await this.fetch();
|
|
556
|
+
return await unmarshal(response, 'text');
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
560
|
+
* @returns {Promise<any>} the response body, deserialized as JSON
|
|
561
|
+
*/
|
|
562
|
+
async fetchJson() {
|
|
563
|
+
const response = await this.fetch();
|
|
564
|
+
return await unmarshal(response, 'json');
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
568
|
+
* @returns {Promise<Blob>} the response body, as a Blob
|
|
569
|
+
*/
|
|
570
|
+
async fetchBlob() {
|
|
571
|
+
const response = await this.fetch();
|
|
572
|
+
return await unmarshal(response, 'blob');
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
576
|
+
* @returns {Promise<ArrayBuffer>} the response body, as an ArrayBuffer
|
|
577
|
+
*/
|
|
578
|
+
async fetchArrayBuffer() {
|
|
579
|
+
const response = await this.fetch();
|
|
580
|
+
return await unmarshal(response, 'arrayBuffer');
|
|
581
|
+
}
|
|
218
582
|
}
|
|
219
583
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
584
|
+
|
|
585
|
+
class HttpMultipartRequestCustomizer {
|
|
586
|
+
#formData;
|
|
587
|
+
/**
|
|
588
|
+
*
|
|
589
|
+
* @param {FormData} formData
|
|
590
|
+
*/
|
|
591
|
+
constructor(formData){
|
|
592
|
+
this.#formData = formData;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Appends a value to the FormData.
|
|
596
|
+
* @param {string} name
|
|
597
|
+
* @param {*} value
|
|
598
|
+
* @returns this builder
|
|
599
|
+
*/
|
|
600
|
+
field(name, value){
|
|
601
|
+
this.#formData.append(name, value);
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Appends a Blob to the FormData.
|
|
606
|
+
* If `filename` is omitted, FormData defaults are applied:
|
|
607
|
+
* The default filename for Blob objects is "blob";
|
|
608
|
+
* The default filename for File objects is the file's filename.
|
|
609
|
+
* @param {string} name
|
|
610
|
+
* @param {Blob} value
|
|
611
|
+
* @param {string|undefined} filename
|
|
612
|
+
* @returns this builder
|
|
613
|
+
*/
|
|
614
|
+
blob(name, value, filename){
|
|
615
|
+
this.#formData.append(name, value, filename);
|
|
616
|
+
return this;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Appends a JSON serialized blob to the FormData.
|
|
620
|
+
* @param {string} name
|
|
621
|
+
* @param {any} value
|
|
622
|
+
* @param {string|undefined} filename
|
|
623
|
+
* @returns this builder
|
|
624
|
+
*/
|
|
625
|
+
json(name, value, filename){
|
|
626
|
+
const blob = new Blob([JSON.stringify(value)], {type: 'application/json'});
|
|
627
|
+
this.#formData.append(name, blob, filename);
|
|
628
|
+
return this;
|
|
228
629
|
}
|
|
229
|
-
}
|
|
230
|
-
function jsonPost(body, headers){
|
|
231
|
-
return jsonRequest('POST', body, headers);
|
|
232
|
-
}
|
|
233
|
-
function jsonPut(body, headers){
|
|
234
|
-
return jsonRequest('PUT', body, headers);
|
|
235
|
-
}
|
|
236
|
-
function jsonPatch(body, headers){
|
|
237
|
-
return jsonRequest('PATCH', body, headers);
|
|
238
630
|
}
|
|
239
631
|
|
|
240
632
|
class Storage {
|
|
@@ -333,7 +725,7 @@ class AuthorizationCodeFlow {
|
|
|
333
725
|
Object.entries(additionalParams || {}).forEach(kv => {
|
|
334
726
|
url.searchParams.set(kv[0], kv[1]);
|
|
335
727
|
});
|
|
336
|
-
window.location = url;
|
|
728
|
+
window.location.href = url.toString();
|
|
337
729
|
}
|
|
338
730
|
async registration(additionalParams){
|
|
339
731
|
await this.action(this.uri.registration, additionalParams);
|
|
@@ -343,7 +735,7 @@ class AuthorizationCodeFlow {
|
|
|
343
735
|
kc_action: kcAction
|
|
344
736
|
});
|
|
345
737
|
}
|
|
346
|
-
async
|
|
738
|
+
async #tokenExchange(code, state) {
|
|
347
739
|
window.history.replaceState('', "", this.uri.redirect);
|
|
348
740
|
const stateAndVerifier = this.storage.pop(AuthorizationCodeFlow.PKCE_AND_STATE_KEY);
|
|
349
741
|
if (stateAndVerifier.state !== state) {
|
|
@@ -376,7 +768,7 @@ class AuthorizationCodeFlow {
|
|
|
376
768
|
if (code && this.storage.load(AuthorizationCodeFlow.PKCE_AND_STATE_KEY)) {
|
|
377
769
|
//if callback from keycloak and we have our state still stored
|
|
378
770
|
const state = url.searchParams.get("state");
|
|
379
|
-
return await this
|
|
771
|
+
return await this.#tokenExchange(code, state);
|
|
380
772
|
}
|
|
381
773
|
//if not authorized
|
|
382
774
|
await this.action(this.uri.auth, {});
|
|
@@ -388,10 +780,10 @@ AuthorizationCodeFlow.PKCE_AND_STATE_KEY = "state-and-verifier";
|
|
|
388
780
|
class AuthorizationCodeFlowSession {
|
|
389
781
|
static parseToken(token) {
|
|
390
782
|
const [rawHeader, rawPayload, signature] = token.split(".");
|
|
391
|
-
const
|
|
783
|
+
const utf8decoder = new TextDecoder("utf-8");
|
|
392
784
|
return {
|
|
393
|
-
header: JSON.parse(
|
|
394
|
-
payload: JSON.parse(
|
|
785
|
+
header: JSON.parse(utf8decoder.decode(Base64.decode(rawHeader, Base64.STANDARD))),
|
|
786
|
+
payload: JSON.parse(utf8decoder.decode(Base64.decode(rawPayload, Base64.STANDARD))),
|
|
395
787
|
signature: signature
|
|
396
788
|
};
|
|
397
789
|
}
|
|
@@ -419,7 +811,8 @@ class AuthorizationCodeFlowSession {
|
|
|
419
811
|
])
|
|
420
812
|
});
|
|
421
813
|
if (!response.ok) {
|
|
422
|
-
|
|
814
|
+
const text = await response.text();
|
|
815
|
+
throw new Error("Error:" + response.status + ": " + text);
|
|
423
816
|
}
|
|
424
817
|
const token = await response.json();
|
|
425
818
|
this.token = token;
|
|
@@ -446,7 +839,7 @@ class AuthorizationCodeFlowSession {
|
|
|
446
839
|
const url = new URL(this.uri.logout);
|
|
447
840
|
url.searchParams.set("post_logout_redirect_uri", this.uri.redirect);
|
|
448
841
|
url.searchParams.set("id_token_hint", this.token.id_token);
|
|
449
|
-
window.location = url;
|
|
842
|
+
window.location.href = url.toString();
|
|
450
843
|
}
|
|
451
844
|
|
|
452
845
|
bearerToken() {
|
|
@@ -459,18 +852,19 @@ class AuthorizationCodeFlowSession {
|
|
|
459
852
|
}
|
|
460
853
|
|
|
461
854
|
class AuthorizationCodeFlowInterceptor {
|
|
855
|
+
#session;
|
|
856
|
+
#gracePeriodBefore;
|
|
857
|
+
#gracePeriodAfter;
|
|
462
858
|
constructor(session, gracePeriodBefore, gracePeriodAfter) {
|
|
463
|
-
this
|
|
464
|
-
this
|
|
465
|
-
this
|
|
859
|
+
this.#session = session;
|
|
860
|
+
this.#gracePeriodBefore = gracePeriodBefore || 2000;
|
|
861
|
+
this.#gracePeriodAfter = gracePeriodAfter || 30000;
|
|
466
862
|
}
|
|
467
863
|
async intercept(request, chain) {
|
|
468
|
-
await this
|
|
469
|
-
|
|
470
|
-
headers.set("Authorization", this.session.bearerToken());
|
|
471
|
-
request.options.headers = headers;
|
|
864
|
+
await this.#session.refreshIf(this.#gracePeriodBefore);
|
|
865
|
+
request.headers.set("Authorization", this.#session.bearerToken());
|
|
472
866
|
const response = await chain.proceed(request);
|
|
473
|
-
await this
|
|
867
|
+
await this.#session.refreshIf(this.#gracePeriodAfter);
|
|
474
868
|
return response;
|
|
475
869
|
}
|
|
476
870
|
}
|
|
@@ -504,7 +898,7 @@ const timing = {
|
|
|
504
898
|
};
|
|
505
899
|
|
|
506
900
|
return function () {
|
|
507
|
-
args = arguments;
|
|
901
|
+
args = [...arguments];
|
|
508
902
|
previousTimestamp = new Date().getTime();
|
|
509
903
|
if (tid === null) {
|
|
510
904
|
tid = setTimeout(later, timeoutMs);
|
|
@@ -538,7 +932,7 @@ const timing = {
|
|
|
538
932
|
previousTimestamp = now;
|
|
539
933
|
}
|
|
540
934
|
const remaining = timeoutMs - (now - previousTimestamp);
|
|
541
|
-
args = arguments;
|
|
935
|
+
args = [...arguments];
|
|
542
936
|
if (remaining <= 0 || remaining > timeoutMs) {
|
|
543
937
|
if (tid !== null) {
|
|
544
938
|
clearTimeout(tid);
|
|
@@ -644,16 +1038,18 @@ class Attributes {
|
|
|
644
1038
|
.forEach(a => {
|
|
645
1039
|
const target = a.substring(prefix.length);
|
|
646
1040
|
if (target === 'class') {
|
|
647
|
-
|
|
1041
|
+
const classes = from.getAttribute(prefix + "class")?.split(" ").filter(a => a.length) ?? [];
|
|
1042
|
+
to.classList.add(...classes);
|
|
648
1043
|
return;
|
|
649
1044
|
}
|
|
1045
|
+
// @ts-ignore
|
|
650
1046
|
to.setAttribute(target, from.getAttribute(a));
|
|
651
1047
|
});
|
|
652
1048
|
}
|
|
653
1049
|
/**
|
|
654
1050
|
*
|
|
655
1051
|
* @param {HTMLElement} el
|
|
656
|
-
* @param {
|
|
1052
|
+
* @param {string} attr
|
|
657
1053
|
* @param {boolean} value
|
|
658
1054
|
*/
|
|
659
1055
|
static toggle(el, attr, value) {
|
|
@@ -680,19 +1076,21 @@ class LightSlots {
|
|
|
680
1076
|
* @returns the slots
|
|
681
1077
|
*/
|
|
682
1078
|
static from(el) {
|
|
1079
|
+
/** @type [string, Element][] */
|
|
683
1080
|
const namedSlots = Array.from(el.childNodes)
|
|
684
|
-
.filter(el => el
|
|
1081
|
+
.filter(el => el instanceof Element)
|
|
1082
|
+
.filter(el => el.matches('[slot]'))
|
|
685
1083
|
.map(el => {
|
|
686
1084
|
el.remove();
|
|
687
1085
|
const slot = el.getAttribute("slot");
|
|
688
1086
|
el.removeAttribute("slot");
|
|
689
|
-
return [slot, el];
|
|
1087
|
+
return [slot ?? 'unnamed', el];
|
|
690
1088
|
});
|
|
691
1089
|
const slots = {};
|
|
692
1090
|
slots.default = new DocumentFragment();
|
|
693
1091
|
slots.default.append(...el.childNodes);
|
|
694
|
-
for(const [name,el] of namedSlots){
|
|
695
|
-
if(!(name in slots)){
|
|
1092
|
+
for (const [name, el] of namedSlots) {
|
|
1093
|
+
if (!(name in slots)) {
|
|
696
1094
|
slots[name] = new DocumentFragment();
|
|
697
1095
|
}
|
|
698
1096
|
slots[name].append(el);
|
|
@@ -718,7 +1116,8 @@ class TemplatesRegistry {
|
|
|
718
1116
|
#ec;
|
|
719
1117
|
put(k, fragment) {
|
|
720
1118
|
if (this.#ec) {
|
|
721
|
-
|
|
1119
|
+
// @ts-ignore
|
|
1120
|
+
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, this.#ec);
|
|
722
1121
|
return;
|
|
723
1122
|
}
|
|
724
1123
|
this.#idToFragment[k] = fragment;
|
|
@@ -737,6 +1136,7 @@ class TemplatesRegistry {
|
|
|
737
1136
|
this.#ec = ec;
|
|
738
1137
|
for (const [k, fragment] of Object.entries(this.#idToFragment)) {
|
|
739
1138
|
delete this.#idToFragment[k];
|
|
1139
|
+
// @ts-ignore
|
|
740
1140
|
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec, ...data);
|
|
741
1141
|
}
|
|
742
1142
|
}
|
|
@@ -840,8 +1240,8 @@ const ParsedElement = (conf) => {
|
|
|
840
1240
|
#initialized;
|
|
841
1241
|
#reflecting;
|
|
842
1242
|
#internals;
|
|
843
|
-
constructor(
|
|
844
|
-
super(
|
|
1243
|
+
constructor() {
|
|
1244
|
+
super();
|
|
845
1245
|
this.#internals = this.attachInternals();
|
|
846
1246
|
}
|
|
847
1247
|
get initialized() {
|
|
@@ -869,6 +1269,7 @@ const ParsedElement = (conf) => {
|
|
|
869
1269
|
observer.disconnect();
|
|
870
1270
|
upgradeQueue.enqueue(this);
|
|
871
1271
|
});
|
|
1272
|
+
// @ts-ignore
|
|
872
1273
|
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
873
1274
|
}
|
|
874
1275
|
attributeChangedCallback(attr, oldValue, newValue) {
|
|
@@ -894,6 +1295,7 @@ const ParsedElement = (conf) => {
|
|
|
894
1295
|
return;
|
|
895
1296
|
}
|
|
896
1297
|
this.#parsed = true;
|
|
1298
|
+
// @ts-ignore
|
|
897
1299
|
await this.render(elements.template(templateId), slots ? LightSlots.from(this) : undefined);
|
|
898
1300
|
|
|
899
1301
|
for (const [attr, mapper] of attrsAndMappers) {
|
|
@@ -922,8 +1324,6 @@ const ParsedElement = (conf) => {
|
|
|
922
1324
|
return k;
|
|
923
1325
|
};
|
|
924
1326
|
|
|
925
|
-
/* global Infinity, CSS */
|
|
926
|
-
|
|
927
1327
|
function flatten(obj, prefix) {
|
|
928
1328
|
return Object.keys(obj).reduce((acc, k) => {
|
|
929
1329
|
const pre = prefix.length ? prefix + '.' : '';
|
|
@@ -1047,7 +1447,7 @@ class Form extends ParsedElement() {
|
|
|
1047
1447
|
}
|
|
1048
1448
|
get values() {
|
|
1049
1449
|
return Array.from(this.querySelectorAll('[name]'))
|
|
1050
|
-
.filter(
|
|
1450
|
+
.filter(el => {
|
|
1051
1451
|
if (el.dataset['fulBindInclude'] === 'never') {
|
|
1052
1452
|
return false;
|
|
1053
1453
|
}
|
|
@@ -1058,14 +1458,14 @@ class Form extends ParsedElement() {
|
|
|
1058
1458
|
}, {});
|
|
1059
1459
|
}
|
|
1060
1460
|
set errors(es) {
|
|
1061
|
-
const fieldErrors = es.filter(
|
|
1062
|
-
const globalErrors = es.filter(
|
|
1461
|
+
const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');
|
|
1462
|
+
const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');
|
|
1063
1463
|
this.querySelectorAll(`.${Form.INVALID_CLASS}`).forEach(el => el.classList.remove(Form.INVALID_CLASS));
|
|
1064
1464
|
this.querySelectorAll("ful-errors").forEach(el => {
|
|
1065
1465
|
el.replaceChildren();
|
|
1066
1466
|
el.setAttribute('hidden', '');
|
|
1067
1467
|
});
|
|
1068
|
-
fieldErrors.forEach(
|
|
1468
|
+
fieldErrors.forEach(e => {
|
|
1069
1469
|
const name = e.context.replace("[", ".").replace("].", ".");
|
|
1070
1470
|
const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;
|
|
1071
1471
|
this.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(Form.INVALID_CLASS));
|
|
@@ -1081,7 +1481,7 @@ class Form extends ParsedElement() {
|
|
|
1081
1481
|
if (!this.hasAttribute('scroll-on-error')) {
|
|
1082
1482
|
return;
|
|
1083
1483
|
}
|
|
1084
|
-
const ys = Array.from(this.querySelectorAll(`[ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))
|
|
1484
|
+
const ys = Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))
|
|
1085
1485
|
.map(el => el.parentElement ? el.parentElement : el)
|
|
1086
1486
|
.map(el => el.getBoundingClientRect().y + window.scrollY);
|
|
1087
1487
|
const miny = Math.min(...ys);
|
|
@@ -1136,6 +1536,7 @@ class Input extends ParsedElement({
|
|
|
1136
1536
|
slots: true,
|
|
1137
1537
|
template: INPUT_TEMPLATE
|
|
1138
1538
|
}){
|
|
1539
|
+
input;
|
|
1139
1540
|
render(template, slots) {
|
|
1140
1541
|
const fragment = makeInputFragment(this, template, slots);
|
|
1141
1542
|
this.replaceChildren(fragment);
|
|
@@ -1306,27 +1707,40 @@ class RadioGroup extends ParsedElement({
|
|
|
1306
1707
|
input.addEventListener('change', evt => {
|
|
1307
1708
|
evt.stopPropagation();
|
|
1308
1709
|
//change is not cancelable
|
|
1309
|
-
this.dispatchEvent(new CustomEvent('change', {
|
|
1310
|
-
bubbles: true,
|
|
1311
|
-
cancelable: false,
|
|
1710
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
1711
|
+
bubbles: true,
|
|
1712
|
+
cancelable: false,
|
|
1312
1713
|
detail: {
|
|
1313
1714
|
value: this.value
|
|
1314
1715
|
}
|
|
1315
|
-
}));
|
|
1316
|
-
});
|
|
1716
|
+
}));
|
|
1717
|
+
});
|
|
1317
1718
|
const label = Fragments.fromChildNodes(el);
|
|
1318
1719
|
return [input, label];
|
|
1319
1720
|
});
|
|
1320
1721
|
|
|
1321
1722
|
radioEls.forEach(el => el.remove());
|
|
1322
|
-
template.renderTo(this, {name, slots, inputsAndLabels});
|
|
1723
|
+
template.renderTo(this, { name, slots, inputsAndLabels });
|
|
1323
1724
|
}
|
|
1324
1725
|
get value() {
|
|
1726
|
+
/** @type {HTMLInputElement|null} */
|
|
1325
1727
|
const checked = this.querySelector('input[type=radio]:checked');
|
|
1326
1728
|
return checked ? checked.value : null;
|
|
1327
1729
|
}
|
|
1328
1730
|
set value(value) {
|
|
1329
|
-
|
|
1731
|
+
if (value === null) {
|
|
1732
|
+
/** @type {HTMLInputElement[]} */
|
|
1733
|
+
this.querySelectorAll(`input[type=radio]`).forEach(el => {
|
|
1734
|
+
// @ts-ignore
|
|
1735
|
+
el.checked = false;
|
|
1736
|
+
});
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
/** @type {HTMLInputElement|null} */
|
|
1740
|
+
const el = this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`);
|
|
1741
|
+
if (el) {
|
|
1742
|
+
el.checked = true;
|
|
1743
|
+
}
|
|
1330
1744
|
}
|
|
1331
1745
|
}
|
|
1332
1746
|
|
|
@@ -1344,5 +1758,5 @@ class Spinner extends ParsedElement({
|
|
|
1344
1758
|
}
|
|
1345
1759
|
}
|
|
1346
1760
|
|
|
1347
|
-
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Deferred, ElementsRegistry, Failure, Form, Fragments, Hex, HttpClient, INPUT_TEMPLATE, Input, LightSlots, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Spinner, TemplatesRegistry, VersionedStorage, elements,
|
|
1761
|
+
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Deferred, ElementsRegistry, Failure, Form, Fragments, Hex, HttpClient, HttpClientError, INPUT_TEMPLATE, Input, LightSlots, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Spinner, TemplatesRegistry, VersionedStorage, elements, makeInputFragment, timing };
|
|
1348
1762
|
//# sourceMappingURL=ful.mjs.map
|