@optionfactory/ful 4.0.15 → 5.0.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.css +1 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.iife.js +173 -111
- 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 +174 -111
- package/dist/ful.mjs.map +1 -1
- package/package.json +3 -3
package/dist/ful.mjs
CHANGED
|
@@ -460,7 +460,7 @@ class HttpRequestBuilder {
|
|
|
460
460
|
*/
|
|
461
461
|
headers(hs) {
|
|
462
462
|
for (const [k, v] of new Headers(hs).entries()) {
|
|
463
|
-
if (v
|
|
463
|
+
if (v == null) {
|
|
464
464
|
this.#headers.delete(k);
|
|
465
465
|
} else {
|
|
466
466
|
this.#headers.set(k, v);
|
|
@@ -475,7 +475,7 @@ class HttpRequestBuilder {
|
|
|
475
475
|
* @returns {HttpRequestBuilder} this builder
|
|
476
476
|
*/
|
|
477
477
|
header(k, v) {
|
|
478
|
-
if (v
|
|
478
|
+
if (v == null) {
|
|
479
479
|
this.#headers.delete(k);
|
|
480
480
|
} else {
|
|
481
481
|
this.#headers.set(k, v);
|
|
@@ -489,7 +489,7 @@ class HttpRequestBuilder {
|
|
|
489
489
|
*/
|
|
490
490
|
params(ps) {
|
|
491
491
|
for (const [k, v] of new URLSearchParams(ps).entries()) {
|
|
492
|
-
if (v
|
|
492
|
+
if (v == null) {
|
|
493
493
|
this.#params.delete(k);
|
|
494
494
|
} else {
|
|
495
495
|
this.#params.set(k, v);
|
|
@@ -504,7 +504,7 @@ class HttpRequestBuilder {
|
|
|
504
504
|
* @returns {HttpRequestBuilder} this builder
|
|
505
505
|
*/
|
|
506
506
|
param(k, ...vs) {
|
|
507
|
-
if (vs.length === 0 || vs[0]
|
|
507
|
+
if (vs.length === 0 || vs[0] == null) {
|
|
508
508
|
this.#params.delete(k);
|
|
509
509
|
return this;
|
|
510
510
|
}
|
|
@@ -1135,22 +1135,6 @@ class Timing {
|
|
|
1135
1135
|
}
|
|
1136
1136
|
}
|
|
1137
1137
|
|
|
1138
|
-
class Loaders {
|
|
1139
|
-
static fromAttributes(el, defaultLoader, options) {
|
|
1140
|
-
const http = registry.component("http-client");
|
|
1141
|
-
const requestMapper = el.hasAttribute("request-mapper") ? registry.component(el.getAttribute("request-mapper")) : v => v;
|
|
1142
|
-
const responseMapper = el.hasAttribute("response-mapper") ? registry.component(el.getAttribute("response-mapper")) : v => v;
|
|
1143
|
-
const loaderClass = registry.component(el.getAttribute("loader") ?? defaultLoader);
|
|
1144
|
-
return loaderClass.create({
|
|
1145
|
-
el,
|
|
1146
|
-
http,
|
|
1147
|
-
requestMapper,
|
|
1148
|
-
responseMapper,
|
|
1149
|
-
options: options ?? {}
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
1138
|
class Bindings {
|
|
1155
1139
|
|
|
1156
1140
|
/**
|
|
@@ -1347,7 +1331,10 @@ class LocalFormLoader {
|
|
|
1347
1331
|
}
|
|
1348
1332
|
|
|
1349
1333
|
class FormLoader {
|
|
1350
|
-
static create(
|
|
1334
|
+
static create(el, conf) {
|
|
1335
|
+
const http = registry.component("http-client");
|
|
1336
|
+
const requestMapper = el.hasAttribute("request-mapper") ? registry.component(el.getAttribute("request-mapper")) : v => v;
|
|
1337
|
+
const responseMapper = el.hasAttribute("response-mapper") ? registry.component(el.getAttribute("response-mapper")) : v => v;
|
|
1351
1338
|
const url = el.getAttribute("action");
|
|
1352
1339
|
if (!url) {
|
|
1353
1340
|
return new LocalFormLoader(requestMapper, responseMapper);
|
|
@@ -1379,7 +1366,7 @@ class Form extends ParsedElement {
|
|
|
1379
1366
|
async submit() {
|
|
1380
1367
|
this.spinner(true);
|
|
1381
1368
|
try {
|
|
1382
|
-
const loader =
|
|
1369
|
+
const loader = registry.component(this.getAttribute("loader") ?? 'loaders:form').create(this);
|
|
1383
1370
|
const values = this.values;
|
|
1384
1371
|
let request = await loader.prepare(values, this);
|
|
1385
1372
|
try {
|
|
@@ -1430,7 +1417,7 @@ class Form extends ParsedElement {
|
|
|
1430
1417
|
}
|
|
1431
1418
|
|
|
1432
1419
|
class Input extends ParsedElement {
|
|
1433
|
-
static observed = ['value', 'readonly:presence'];
|
|
1420
|
+
static observed = ['value', 'readonly:presence', 'required:presence'];
|
|
1434
1421
|
static slots = true;
|
|
1435
1422
|
static template = `
|
|
1436
1423
|
<div class="form-label">
|
|
@@ -1461,15 +1448,16 @@ class Input extends ParsedElement {
|
|
|
1461
1448
|
_fragment(type, slots) {
|
|
1462
1449
|
return this.template().withOverlay({ type, slots }).render();
|
|
1463
1450
|
}
|
|
1464
|
-
render({ slots, observed, disabled,
|
|
1451
|
+
render({ slots, observed, disabled, skipObservedSetup }) {
|
|
1465
1452
|
const type = this._type();
|
|
1466
1453
|
const fragment = this._fragment(type, slots);
|
|
1467
1454
|
this._input = fragment.querySelector("input,textarea");
|
|
1468
1455
|
|
|
1469
1456
|
Attributes.forward('input-', this, this._input);
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1457
|
+
if (!skipObservedSetup) {
|
|
1458
|
+
this.disabled = disabled;
|
|
1459
|
+
this.readonly = observed.readonly;
|
|
1460
|
+
this.required = observed.required;
|
|
1473
1461
|
this.value = observed.value;
|
|
1474
1462
|
}
|
|
1475
1463
|
|
|
@@ -1512,6 +1500,15 @@ class Input extends ParsedElement {
|
|
|
1512
1500
|
set disabled(d) {
|
|
1513
1501
|
Attributes.toggle(this._input, 'disabled', d);
|
|
1514
1502
|
}
|
|
1503
|
+
get required() {
|
|
1504
|
+
return this._input.getAttribute('aria-required') === 'true';
|
|
1505
|
+
}
|
|
1506
|
+
set required(d) {
|
|
1507
|
+
Attributes.set(this._input, "aria-required", d ? "true" : null);
|
|
1508
|
+
this.reflect(() => {
|
|
1509
|
+
Attributes.toggle(this, 'required', d);
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1515
1512
|
focus(options) {
|
|
1516
1513
|
this._input.focus(options);
|
|
1517
1514
|
}
|
|
@@ -1525,7 +1522,7 @@ class Input extends ParsedElement {
|
|
|
1525
1522
|
this._fieldError.innerText = error;
|
|
1526
1523
|
}
|
|
1527
1524
|
formResetCallback() {
|
|
1528
|
-
this.value = this.getAttribute("value");
|
|
1525
|
+
this.value = this.unmarshal('value', this.getAttribute("value"));
|
|
1529
1526
|
}
|
|
1530
1527
|
}
|
|
1531
1528
|
|
|
@@ -1569,22 +1566,22 @@ class Instant extends ParsedElement {
|
|
|
1569
1566
|
const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;
|
|
1570
1567
|
const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;
|
|
1571
1568
|
return `${date}T${time}`
|
|
1572
|
-
}
|
|
1569
|
+
}
|
|
1573
1570
|
}
|
|
1574
1571
|
|
|
1575
1572
|
|
|
1576
1573
|
class InputLocalDate extends Input {
|
|
1577
|
-
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1574
|
+
static observed = ['value', 'readonly:presence', 'required:presence', 'min', 'max', 'step'];
|
|
1578
1575
|
_type() {
|
|
1579
1576
|
return 'date';
|
|
1580
1577
|
}
|
|
1581
|
-
render(conf){
|
|
1582
|
-
const {observed} = conf;
|
|
1578
|
+
render(conf) {
|
|
1579
|
+
const { observed } = conf;
|
|
1583
1580
|
super.render(conf);
|
|
1584
1581
|
this.min = observed.min;
|
|
1585
1582
|
this.max = observed.max;
|
|
1586
1583
|
this.step = observed.step;
|
|
1587
|
-
}
|
|
1584
|
+
}
|
|
1588
1585
|
get min() {
|
|
1589
1586
|
const v = this._input.min;
|
|
1590
1587
|
return v === '' ? null : v;
|
|
@@ -1644,12 +1641,12 @@ class InputLocalTime extends InputLocalDate {
|
|
|
1644
1641
|
|
|
1645
1642
|
|
|
1646
1643
|
class InputInstant extends Input {
|
|
1647
|
-
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1644
|
+
static observed = ['value', 'readonly:presence', 'required:presence', 'min', 'max', 'step'];
|
|
1648
1645
|
_type() {
|
|
1649
1646
|
return 'datetime-local';
|
|
1650
1647
|
}
|
|
1651
|
-
render(conf){
|
|
1652
|
-
const {observed} = conf;
|
|
1648
|
+
render(conf) {
|
|
1649
|
+
const { observed } = conf;
|
|
1653
1650
|
super.render(conf);
|
|
1654
1651
|
this.min = observed.min;
|
|
1655
1652
|
this.max = observed.min;
|
|
@@ -1700,7 +1697,7 @@ class InputFile extends Input {
|
|
|
1700
1697
|
'maxtotalsizeexceeded': "La dimensione massima complessiva dei file è di {0}"
|
|
1701
1698
|
}
|
|
1702
1699
|
}
|
|
1703
|
-
static observed = ['value', 'readonly:presence', "accept:csv", 'multiple:presence', "itemlist:presence", "dropzone:presence", "maxfilesize:number", "maxtotalsize:number"];
|
|
1700
|
+
static observed = ['value', 'readonly:presence', 'required:presence', "accept:csv", 'multiple:presence', "itemlist:presence", "dropzone:presence", "maxfilesize:number", "maxtotalsize:number"];
|
|
1704
1701
|
#accept;
|
|
1705
1702
|
#items;
|
|
1706
1703
|
#dropzone;
|
|
@@ -1926,17 +1923,7 @@ class RemoteLoader {
|
|
|
1926
1923
|
#prefetch;
|
|
1927
1924
|
#revision;
|
|
1928
1925
|
#data;
|
|
1929
|
-
|
|
1930
|
-
return new RemoteLoader({
|
|
1931
|
-
http,
|
|
1932
|
-
url: el.getAttribute("src"),
|
|
1933
|
-
method: el.getAttribute("method") ?? 'POST',
|
|
1934
|
-
responseMapper,
|
|
1935
|
-
prefetch: el.hasAttribute("preload"),
|
|
1936
|
-
revision: el.getAttribute("revision")
|
|
1937
|
-
});
|
|
1938
|
-
}
|
|
1939
|
-
constructor({http, url, method, responseMapper, prefetch, revision}) {
|
|
1926
|
+
constructor({ http, url, method, responseMapper, prefetch, revision }) {
|
|
1940
1927
|
this.#http = http;
|
|
1941
1928
|
this.#url = url;
|
|
1942
1929
|
this.#method = method;
|
|
@@ -1959,7 +1946,7 @@ class RemoteLoader {
|
|
|
1959
1946
|
await this.#ensureFetched();
|
|
1960
1947
|
return this.#data.filter(([k, v]) => (v ?? '').toLowerCase().includes(needle?.toLowerCase()));
|
|
1961
1948
|
}
|
|
1962
|
-
async reconfigureUrl(url){
|
|
1949
|
+
async reconfigureUrl(url) {
|
|
1963
1950
|
this.#data = null;
|
|
1964
1951
|
this.#url = url;
|
|
1965
1952
|
}
|
|
@@ -1968,9 +1955,9 @@ class RemoteLoader {
|
|
|
1968
1955
|
return
|
|
1969
1956
|
}
|
|
1970
1957
|
const storageKey = `${this.#method}@${this.#url}`;
|
|
1971
|
-
if(this.#revision !== null){
|
|
1958
|
+
if (this.#revision !== null) {
|
|
1972
1959
|
const data = VersionedLocalStorage.load(storageKey, this.#revision);
|
|
1973
|
-
if(data !== undefined){
|
|
1960
|
+
if (data !== undefined) {
|
|
1974
1961
|
this.#data = data;
|
|
1975
1962
|
return;
|
|
1976
1963
|
}
|
|
@@ -1978,7 +1965,7 @@ class RemoteLoader {
|
|
|
1978
1965
|
const data = await this.#http.request(this.#method, this.#url)
|
|
1979
1966
|
.fetchJson();
|
|
1980
1967
|
this.#data = this.#responseMapper(data);
|
|
1981
|
-
if(this.#revision !== null){
|
|
1968
|
+
if (this.#revision !== null) {
|
|
1982
1969
|
VersionedLocalStorage.save(storageKey, this.#revision, this.#data);
|
|
1983
1970
|
}
|
|
1984
1971
|
}
|
|
@@ -1989,15 +1976,7 @@ class PartialRemoteLoader {
|
|
|
1989
1976
|
#url;
|
|
1990
1977
|
#method;
|
|
1991
1978
|
#responseMapper;
|
|
1992
|
-
|
|
1993
|
-
return new PartialRemoteLoader({
|
|
1994
|
-
http,
|
|
1995
|
-
url: el.getAttribute("src"),
|
|
1996
|
-
method: el.getAttribute("method") ?? 'POST',
|
|
1997
|
-
responseMapper
|
|
1998
|
-
});
|
|
1999
|
-
}
|
|
2000
|
-
constructor({http, url, method, responseMapper}) {
|
|
1979
|
+
constructor({ http, url, method, responseMapper }) {
|
|
2001
1980
|
this.#http = http;
|
|
2002
1981
|
this.#url = url;
|
|
2003
1982
|
this.#method = method;
|
|
@@ -2035,16 +2014,49 @@ class InMemoryLoader {
|
|
|
2035
2014
|
|
|
2036
2015
|
|
|
2037
2016
|
class SelectLoader {
|
|
2038
|
-
static create(conf) {
|
|
2039
|
-
if (!
|
|
2040
|
-
const els = Array.from(conf.options
|
|
2017
|
+
static create(el, conf) {
|
|
2018
|
+
if (!el.hasAttribute("src")) {
|
|
2019
|
+
const els = Array.from(conf.options?.querySelectorAll('option') ?? []);
|
|
2041
2020
|
const data = els.map(e => {
|
|
2042
2021
|
return [e.getAttribute("value") ?? e.innerText.trim(), e.innerText.trim()];
|
|
2043
2022
|
});
|
|
2044
2023
|
return new InMemoryLoader(data);
|
|
2045
2024
|
}
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2025
|
+
const http = registry.component("http-client");
|
|
2026
|
+
const responseMapper = SelectLoader.#responseMapperFrom(el);
|
|
2027
|
+
|
|
2028
|
+
if ("chunked" == el.getAttribute("mode")) {
|
|
2029
|
+
return new PartialRemoteLoader({
|
|
2030
|
+
http,
|
|
2031
|
+
url: el.getAttribute("src"),
|
|
2032
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
2033
|
+
responseMapper
|
|
2034
|
+
})
|
|
2035
|
+
}
|
|
2036
|
+
return new RemoteLoader({
|
|
2037
|
+
http,
|
|
2038
|
+
url: el.getAttribute("src"),
|
|
2039
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
2040
|
+
responseMapper,
|
|
2041
|
+
prefetch: el.hasAttribute("preload"),
|
|
2042
|
+
revision: el.getAttribute("revision")
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
static #responseMapperFrom(el) {
|
|
2046
|
+
if (el.hasAttribute("k-expr") && el.hasAttribute("l-expr")) {
|
|
2047
|
+
return v => {
|
|
2048
|
+
const evaluator = registry.evaluator().withOverlay(v);
|
|
2049
|
+
return [
|
|
2050
|
+
evaluator.evaluateExpression(el.getAttribute("k-expr")),
|
|
2051
|
+
evaluator.evaluateExpression(el.getAttribute("l-expr")),
|
|
2052
|
+
evaluator.evaluateExpression(el.getAttribute("m-expr") ?? 'self'),
|
|
2053
|
+
];
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
if (el.hasAttribute("response-mapper")) {
|
|
2057
|
+
return registry.component(el.getAttribute("response-mapper"));
|
|
2058
|
+
}
|
|
2059
|
+
return v => v;
|
|
2048
2060
|
}
|
|
2049
2061
|
}
|
|
2050
2062
|
|
|
@@ -2079,7 +2091,7 @@ class Dropdown extends ParsedElement {
|
|
|
2079
2091
|
if (values === undefined) {
|
|
2080
2092
|
throw new Error("null data");
|
|
2081
2093
|
}
|
|
2082
|
-
this.#options = new Map(values.map((v,i) => [String(i), v]));
|
|
2094
|
+
this.#options = new Map(values.map((v, i) => [String(i), v]));
|
|
2083
2095
|
if (values.length === 0) {
|
|
2084
2096
|
const el = document.createElement('div');
|
|
2085
2097
|
el.classList.add('text-center', 'py-2', 'bi', 'bi-database-slash');
|
|
@@ -2131,7 +2143,7 @@ class Dropdown extends ParsedElement {
|
|
|
2131
2143
|
if (candidate) {
|
|
2132
2144
|
selected.removeAttribute('selected');
|
|
2133
2145
|
candidate.setAttribute("selected", "");
|
|
2134
|
-
candidate.scrollIntoView({block: "nearest", behavior: "smooth"});
|
|
2146
|
+
candidate.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
2135
2147
|
}
|
|
2136
2148
|
return;
|
|
2137
2149
|
}
|
|
@@ -2140,7 +2152,7 @@ class Dropdown extends ParsedElement {
|
|
|
2140
2152
|
}
|
|
2141
2153
|
|
|
2142
2154
|
class Select extends ParsedElement {
|
|
2143
|
-
static observed = ['value:csvm', 'readonly:presence', 'itemlist:presence']
|
|
2155
|
+
static observed = ['value:csvm', 'readonly:presence', "required:presence", 'itemlist:presence']
|
|
2144
2156
|
static slots = true
|
|
2145
2157
|
static template = `
|
|
2146
2158
|
<div class="form-label">
|
|
@@ -2170,15 +2182,7 @@ class Select extends ParsedElement {
|
|
|
2170
2182
|
<button type="button" class="btn btn-sm btn-outline-danger bi bi-x-lg"></button>
|
|
2171
2183
|
</ful-item>
|
|
2172
2184
|
`
|
|
2173
|
-
}
|
|
2174
|
-
static mappers = {
|
|
2175
|
-
"csvm": (v, name, el) => {
|
|
2176
|
-
if (el.hasAttribute("multiple")) {
|
|
2177
|
-
return v === null ? [] : v.split(",").map(e => e.trim()).filter(e => e)
|
|
2178
|
-
}
|
|
2179
|
-
return v === null || v === '' ? null : v
|
|
2180
|
-
}
|
|
2181
|
-
};
|
|
2185
|
+
}
|
|
2182
2186
|
static formAssociated = true
|
|
2183
2187
|
internals
|
|
2184
2188
|
#loader
|
|
@@ -2196,7 +2200,8 @@ class Select extends ParsedElement {
|
|
|
2196
2200
|
}
|
|
2197
2201
|
async render({ slots, observed, disabled }) {
|
|
2198
2202
|
const name = this.getAttribute("name");
|
|
2199
|
-
this.#loader =
|
|
2203
|
+
this.#loader = registry.component(this.getAttribute("loader") ?? 'loaders:select').create(this, {options: slots.options});
|
|
2204
|
+
|
|
2200
2205
|
this.#multiple = this.hasAttribute("multiple");
|
|
2201
2206
|
await this.#loader.prefetch?.();
|
|
2202
2207
|
const fragment = this.template().withOverlay({ slots, name }).render();
|
|
@@ -2208,6 +2213,7 @@ class Select extends ParsedElement {
|
|
|
2208
2213
|
this.value = observed.value;
|
|
2209
2214
|
this.disabled = disabled;
|
|
2210
2215
|
this.readonly = observed.readonly;
|
|
2216
|
+
this.required = observed.required;
|
|
2211
2217
|
this.itemlist = observed.itemlist;
|
|
2212
2218
|
|
|
2213
2219
|
this.#ddmenu = fragment.querySelector('ful-dropdown');
|
|
@@ -2223,7 +2229,7 @@ class Select extends ParsedElement {
|
|
|
2223
2229
|
if (e.target.matches('input')) {
|
|
2224
2230
|
return;
|
|
2225
2231
|
}
|
|
2226
|
-
if(this.disabled || this.readonly){
|
|
2232
|
+
if (this.disabled || this.readonly) {
|
|
2227
2233
|
return;
|
|
2228
2234
|
}
|
|
2229
2235
|
if (this.#ddmenu.shown) {
|
|
@@ -2238,9 +2244,9 @@ class Select extends ParsedElement {
|
|
|
2238
2244
|
if (!e.target.closest("button")) {
|
|
2239
2245
|
return;
|
|
2240
2246
|
}
|
|
2241
|
-
if(this.disabled || this.readonly){
|
|
2247
|
+
if (this.disabled || this.readonly) {
|
|
2242
2248
|
return;
|
|
2243
|
-
}
|
|
2249
|
+
}
|
|
2244
2250
|
const idx = [...this.#items.children].indexOf(e.target.closest('ful-item'));
|
|
2245
2251
|
if (idx === -1) {
|
|
2246
2252
|
return;
|
|
@@ -2251,7 +2257,7 @@ class Select extends ParsedElement {
|
|
|
2251
2257
|
});
|
|
2252
2258
|
this.#badges.addEventListener('click', (e) => {
|
|
2253
2259
|
e.stopPropagation();
|
|
2254
|
-
if(this.disabled || this.readonly){
|
|
2260
|
+
if (this.disabled || this.readonly) {
|
|
2255
2261
|
return;
|
|
2256
2262
|
}
|
|
2257
2263
|
const idx = [...this.#badges.children].indexOf(e.target);
|
|
@@ -2276,7 +2282,7 @@ class Select extends ParsedElement {
|
|
|
2276
2282
|
});
|
|
2277
2283
|
this.#input.addEventListener('keydown', e => {
|
|
2278
2284
|
e.stopPropagation();
|
|
2279
|
-
if(this.disabled || this.readonly){
|
|
2285
|
+
if (this.disabled || this.readonly) {
|
|
2280
2286
|
return;
|
|
2281
2287
|
}
|
|
2282
2288
|
switch (e.code) {
|
|
@@ -2315,7 +2321,7 @@ class Select extends ParsedElement {
|
|
|
2315
2321
|
});
|
|
2316
2322
|
this.#input.addEventListener('input', e => {
|
|
2317
2323
|
e.stopPropagation();
|
|
2318
|
-
if(this.disabled || this.readonly){
|
|
2324
|
+
if (this.disabled || this.readonly) {
|
|
2319
2325
|
return;
|
|
2320
2326
|
}
|
|
2321
2327
|
dload();
|
|
@@ -2338,7 +2344,7 @@ class Select extends ParsedElement {
|
|
|
2338
2344
|
await fn(this.#loader);
|
|
2339
2345
|
}
|
|
2340
2346
|
#changed() {
|
|
2341
|
-
const selection = [...this.#values.entries()].map(e => ({key: e[0], label: e[1][0], metadata: e[1].slice(1)}));
|
|
2347
|
+
const selection = [...this.#values.entries()].map(e => ({ key: e[0], label: e[1][0], metadata: e[1].slice(1) }));
|
|
2342
2348
|
const value = this.#multiple ? selection : (selection[0] ?? null);
|
|
2343
2349
|
this.dispatchEvent(new CustomEvent('change', {
|
|
2344
2350
|
bubbles: true,
|
|
@@ -2360,10 +2366,10 @@ class Select extends ParsedElement {
|
|
|
2360
2366
|
this.template('items').withOverlay({ entries: this.#values.entries() }).renderTo(this.#items);
|
|
2361
2367
|
}
|
|
2362
2368
|
set value(vs) {
|
|
2363
|
-
if(vs === null){
|
|
2369
|
+
if (vs === null) {
|
|
2364
2370
|
this.#values = new Map();
|
|
2365
2371
|
this.#syncBadges();
|
|
2366
|
-
return;
|
|
2372
|
+
return;
|
|
2367
2373
|
}
|
|
2368
2374
|
(async () => {
|
|
2369
2375
|
const entries = await (this.#multiple ? this.#loader.exact(...vs) : this.#loader.exact(vs));
|
|
@@ -2384,14 +2390,14 @@ class Select extends ParsedElement {
|
|
|
2384
2390
|
return [...this.#values.entries()][0] ?? null;
|
|
2385
2391
|
}
|
|
2386
2392
|
//@ts-ignore
|
|
2387
|
-
get disabled(){
|
|
2393
|
+
get disabled() {
|
|
2388
2394
|
return this.#input.hasAttribute('disabled');
|
|
2389
2395
|
}
|
|
2390
|
-
set disabled(d){
|
|
2396
|
+
set disabled(d) {
|
|
2391
2397
|
Attributes.toggle(this.#input, 'disabled', d);
|
|
2392
|
-
}
|
|
2393
|
-
get readonly(){
|
|
2394
|
-
return this.#input.readOnly;
|
|
2398
|
+
}
|
|
2399
|
+
get readonly() {
|
|
2400
|
+
return this.#input.readOnly;
|
|
2395
2401
|
}
|
|
2396
2402
|
set readonly(v) {
|
|
2397
2403
|
this.#input.readOnly = v;
|
|
@@ -2399,6 +2405,15 @@ class Select extends ParsedElement {
|
|
|
2399
2405
|
Attributes.toggle(this, 'readonly', v);
|
|
2400
2406
|
});
|
|
2401
2407
|
}
|
|
2408
|
+
get required() {
|
|
2409
|
+
return this.#input.getAttribute('aria-required') === 'true';
|
|
2410
|
+
}
|
|
2411
|
+
set required(d) {
|
|
2412
|
+
Attributes.set(this.#input, "aria-required", d ? "true" : null);
|
|
2413
|
+
this.reflect(() => {
|
|
2414
|
+
Attributes.toggle(this, 'required', d);
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2402
2417
|
#useItemlist;
|
|
2403
2418
|
get itemlist() {
|
|
2404
2419
|
return this.#useItemlist;
|
|
@@ -2424,7 +2439,7 @@ class Select extends ParsedElement {
|
|
|
2424
2439
|
}
|
|
2425
2440
|
|
|
2426
2441
|
class RadioGroup extends ParsedElement {
|
|
2427
|
-
static observed = ['value', 'readonly:presence'];
|
|
2442
|
+
static observed = ['value', 'readonly:presence', "required:presence"];
|
|
2428
2443
|
static slots = true;
|
|
2429
2444
|
static template = `
|
|
2430
2445
|
<fieldset>
|
|
@@ -2488,6 +2503,7 @@ class RadioGroup extends ParsedElement {
|
|
|
2488
2503
|
this.#fieldset = this.firstElementChild;
|
|
2489
2504
|
this.disabled = disabled;
|
|
2490
2505
|
this.readonly = observed.readonly;
|
|
2506
|
+
this.required = observed.required;
|
|
2491
2507
|
this.value = observed.value;
|
|
2492
2508
|
this.#fieldError = this.querySelector('ful-field-error');
|
|
2493
2509
|
this.ariaDescribedByElements = [this.#fieldError];
|
|
@@ -2528,6 +2544,15 @@ class RadioGroup extends ParsedElement {
|
|
|
2528
2544
|
set disabled(d){
|
|
2529
2545
|
Attributes.toggle(this.#fieldset, 'disabled', d);
|
|
2530
2546
|
}
|
|
2547
|
+
get required() {
|
|
2548
|
+
return this.#fieldset.getAttribute('aria-required') === 'true';
|
|
2549
|
+
}
|
|
2550
|
+
set required(d) {
|
|
2551
|
+
Attributes.set(this.#fieldset, "aria-required", d ? "true" : null);
|
|
2552
|
+
this.reflect(() => {
|
|
2553
|
+
Attributes.toggle(this, 'required', d);
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2531
2556
|
focus(options) {
|
|
2532
2557
|
this.#firstRadio.focus(options);
|
|
2533
2558
|
}
|
|
@@ -2543,7 +2568,7 @@ class RadioGroup extends ParsedElement {
|
|
|
2543
2568
|
}
|
|
2544
2569
|
|
|
2545
2570
|
class Checkbox extends ParsedElement {
|
|
2546
|
-
static observed = ['value:bool', 'readonly:presence'];
|
|
2571
|
+
static observed = ['value:bool', 'readonly:presence', "required:presence"];
|
|
2547
2572
|
static slots = true;
|
|
2548
2573
|
static template = `
|
|
2549
2574
|
<div data-tpl-class="klass">
|
|
@@ -2574,6 +2599,7 @@ class Checkbox extends ParsedElement {
|
|
|
2574
2599
|
Attributes.forward('input-', this, this.#input);
|
|
2575
2600
|
this.disabled = disabled;
|
|
2576
2601
|
this.readonly = observed.readonly;
|
|
2602
|
+
this.required = observed.required;
|
|
2577
2603
|
this.value = observed.value;
|
|
2578
2604
|
this.#input.addEventListener('change', (evt) => {
|
|
2579
2605
|
evt.stopPropagation();
|
|
@@ -2620,6 +2646,15 @@ class Checkbox extends ParsedElement {
|
|
|
2620
2646
|
set disabled(d) {
|
|
2621
2647
|
Attributes.toggle(this.#input, 'disabled', d);
|
|
2622
2648
|
}
|
|
2649
|
+
get required() {
|
|
2650
|
+
return this.#input.getAttribute('aria-required') === 'true';
|
|
2651
|
+
}
|
|
2652
|
+
set required(d) {
|
|
2653
|
+
Attributes.set(this.#input, "aria-required", d ? "true" : null);
|
|
2654
|
+
this.reflect(() => {
|
|
2655
|
+
Attributes.toggle(this, 'required', d);
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2623
2658
|
focus(options) {
|
|
2624
2659
|
this.#input.focus(options);
|
|
2625
2660
|
}
|
|
@@ -2867,7 +2902,8 @@ class RemoteTableLoader {
|
|
|
2867
2902
|
|
|
2868
2903
|
|
|
2869
2904
|
class TableLoader {
|
|
2870
|
-
static create(
|
|
2905
|
+
static create(el, conf) {
|
|
2906
|
+
const http = registry.component("http-client");
|
|
2871
2907
|
const url = el.getAttribute("src");
|
|
2872
2908
|
const method = el.getAttribute("method") ?? 'GET';
|
|
2873
2909
|
return new RemoteTableLoader(http, url, method);
|
|
@@ -2992,7 +3028,8 @@ class Table extends ParsedElement {
|
|
|
2992
3028
|
}, this.#latestRequest.sortRequest, this.#latestRequest.filterRequest);
|
|
2993
3029
|
});
|
|
2994
3030
|
this.addEventListener('sort-requested', async (/** @type any */e) => {
|
|
2995
|
-
|
|
3031
|
+
const sortRequest = e.detail.value.order ? e.detail.value : null;
|
|
3032
|
+
await this.load(this.#latestRequest.pageRequest, sortRequest, this.#latestRequest.filterRequest);
|
|
2996
3033
|
this.#sorters.forEach(s => s.order = null);
|
|
2997
3034
|
e.target.order = e.detail.value.order;
|
|
2998
3035
|
});
|
|
@@ -3010,7 +3047,7 @@ class Table extends ParsedElement {
|
|
|
3010
3047
|
this.#feedback.setAttribute("hidden", "");
|
|
3011
3048
|
this.#noAutoload.setAttribute("hidden", "");
|
|
3012
3049
|
try {
|
|
3013
|
-
const loader =
|
|
3050
|
+
const loader = registry.component(this.getAttribute("loader") ?? 'loaders:table').create(this);
|
|
3014
3051
|
const pageResponse = await loader.load(pageRequest, sortRequest, filterRequest);
|
|
3015
3052
|
this.#latestRequest = { pageRequest, sortRequest, filterRequest };
|
|
3016
3053
|
this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
|
|
@@ -3047,7 +3084,7 @@ class Table extends ParsedElement {
|
|
|
3047
3084
|
}
|
|
3048
3085
|
|
|
3049
3086
|
class InstantFilter extends Input {
|
|
3050
|
-
static observed = ['value:json', 'readonly:presence'];
|
|
3087
|
+
static observed = ['value:json', 'readonly:presence', 'required:presence'];
|
|
3051
3088
|
static template = `
|
|
3052
3089
|
<div class="form-label">
|
|
3053
3090
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3077,10 +3114,14 @@ class InstantFilter extends Input {
|
|
|
3077
3114
|
#value1;
|
|
3078
3115
|
#value2;
|
|
3079
3116
|
render(conf) {
|
|
3080
|
-
super.render({...conf,
|
|
3117
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3081
3118
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3082
3119
|
this.#value1 = this.querySelector('[data-ref=value1]');
|
|
3083
3120
|
this.#value2 = this.querySelector('[data-ref=value2]');
|
|
3121
|
+
|
|
3122
|
+
this.disabled = conf.disabled;
|
|
3123
|
+
this.readonly = conf.observed.readonly;
|
|
3124
|
+
this.required = conf.observed.required;
|
|
3084
3125
|
this.value = conf.observed.value;
|
|
3085
3126
|
|
|
3086
3127
|
this.addEventListener('click', (evt) => {
|
|
@@ -3102,7 +3143,7 @@ class InstantFilter extends Input {
|
|
|
3102
3143
|
return values.some(v => v === '') ? undefined : [operator, ...values.map(v => new Date(v).toISOString())];
|
|
3103
3144
|
}
|
|
3104
3145
|
set value(v) {
|
|
3105
|
-
if (v
|
|
3146
|
+
if (v == null) {
|
|
3106
3147
|
this.#value1.value = '';
|
|
3107
3148
|
this.#value2.value = '';
|
|
3108
3149
|
return;
|
|
@@ -3112,10 +3153,18 @@ class InstantFilter extends Input {
|
|
|
3112
3153
|
this.#value1.value = values[0] ? Instant.isoToLocal(values[0]) : values[0];
|
|
3113
3154
|
this.#value2.value = values[1] ? Instant.isoToLocal(values[1]) : values[1];
|
|
3114
3155
|
}
|
|
3156
|
+
set readonly(v) {
|
|
3157
|
+
this.#value2.readOnly = v;
|
|
3158
|
+
super.readonly = v;
|
|
3159
|
+
}
|
|
3160
|
+
set disabled(d) {
|
|
3161
|
+
Attributes.toggle(this.#value2, 'disabled', d);
|
|
3162
|
+
super.disabled = d;
|
|
3163
|
+
}
|
|
3115
3164
|
}
|
|
3116
3165
|
|
|
3117
3166
|
class LocalDateFilter extends Input {
|
|
3118
|
-
static observed = ["value:json", 'readonly:presence'];
|
|
3167
|
+
static observed = ["value:json", 'readonly:presence', 'required:presence'];
|
|
3119
3168
|
static template = `
|
|
3120
3169
|
<div class="form-label">
|
|
3121
3170
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3145,13 +3194,17 @@ class LocalDateFilter extends Input {
|
|
|
3145
3194
|
#value1;
|
|
3146
3195
|
#value2;
|
|
3147
3196
|
render(conf) {
|
|
3148
|
-
super.render({...conf,
|
|
3197
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3149
3198
|
|
|
3150
3199
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3151
3200
|
this.#value1 = this.querySelector('[data-ref=value1]');
|
|
3152
3201
|
this.#value2 = this.querySelector('[data-ref=value2]');
|
|
3202
|
+
|
|
3203
|
+
this.disabled = conf.disabled;
|
|
3204
|
+
this.readonly = conf.observed.readonly;
|
|
3205
|
+
this.required = conf.observed.required;
|
|
3153
3206
|
this.value = conf.observed.value;
|
|
3154
|
-
|
|
3207
|
+
|
|
3155
3208
|
this.addEventListener('click', (evt) => {
|
|
3156
3209
|
const target = /** @type HTMLElement */(evt.target);
|
|
3157
3210
|
if (!target.matches('ul > li > a')) {
|
|
@@ -3170,7 +3223,7 @@ class LocalDateFilter extends Input {
|
|
|
3170
3223
|
return values.some(v => v === '') ? undefined : [operator, ...values];
|
|
3171
3224
|
}
|
|
3172
3225
|
set value(v) {
|
|
3173
|
-
if (v
|
|
3226
|
+
if (v == null) {
|
|
3174
3227
|
this.#value1.value = '';
|
|
3175
3228
|
this.#value2.value = '';
|
|
3176
3229
|
return;
|
|
@@ -3180,10 +3233,18 @@ class LocalDateFilter extends Input {
|
|
|
3180
3233
|
this.#value1.value = values[0];
|
|
3181
3234
|
this.#value2.value = values[1];
|
|
3182
3235
|
}
|
|
3236
|
+
set readonly(v) {
|
|
3237
|
+
this.#value2.readOnly = v;
|
|
3238
|
+
super.readonly = v;
|
|
3239
|
+
}
|
|
3240
|
+
set disabled(d) {
|
|
3241
|
+
Attributes.toggle(this.#value2, 'disabled', d);
|
|
3242
|
+
super.disabled = d;
|
|
3243
|
+
}
|
|
3183
3244
|
}
|
|
3184
3245
|
|
|
3185
3246
|
class TextFilter extends Input {
|
|
3186
|
-
static observed = ["value:json", 'readonly:presence'];
|
|
3247
|
+
static observed = ["value:json", 'readonly:presence', 'required:presence'];
|
|
3187
3248
|
static template = `
|
|
3188
3249
|
<div class="form-label">
|
|
3189
3250
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3208,10 +3269,14 @@ class TextFilter extends Input {
|
|
|
3208
3269
|
#operator;
|
|
3209
3270
|
#value;
|
|
3210
3271
|
render(conf) {
|
|
3211
|
-
super.render({...conf,
|
|
3272
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3212
3273
|
|
|
3213
3274
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3214
3275
|
this.#value = this.querySelector('[data-ref=value]');
|
|
3276
|
+
|
|
3277
|
+
this.disabled = conf.disabled;
|
|
3278
|
+
this.readonly = conf.observed.readonly;
|
|
3279
|
+
this.required = conf.observed.required;
|
|
3215
3280
|
this.value = conf.observed.value;
|
|
3216
3281
|
|
|
3217
3282
|
this.addEventListener('click', (evt) => {
|
|
@@ -3225,14 +3290,12 @@ class TextFilter extends Input {
|
|
|
3225
3290
|
btn.innerHTML = target.innerHTML;
|
|
3226
3291
|
});
|
|
3227
3292
|
}
|
|
3228
|
-
|
|
3229
3293
|
get value() {
|
|
3230
3294
|
const operator = this.#operator.getAttribute('value');
|
|
3231
3295
|
return this.#value.value === '' ? undefined : [operator, 'IGNORE_CASE', this.#value.value];
|
|
3232
3296
|
}
|
|
3233
|
-
|
|
3234
3297
|
set value(v) {
|
|
3235
|
-
if (v
|
|
3298
|
+
if (v == null) {
|
|
3236
3299
|
this.#value.value = '';
|
|
3237
3300
|
return;
|
|
3238
3301
|
}
|
|
@@ -3296,5 +3359,5 @@ class Plugin {
|
|
|
3296
3359
|
}
|
|
3297
3360
|
}
|
|
3298
3361
|
|
|
3299
|
-
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InputFile, InputInstant, InputLocalDate, InputLocalTime, Instant, InstantFilter,
|
|
3362
|
+
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InputFile, InputInstant, InputLocalDate, InputLocalTime, Instant, InstantFilter, LocalDate, LocalDateFilter, LocalStorage, LocalizationModule, MediaType, Pagination, Plugin, RadioGroup, Select, SelectLoader, SessionStorage, SortButton, Spinner, Table, TableSchemaParser, TextFilter, Timing, VersionedLocalStorage, VersionedSessionStorage };
|
|
3300
3363
|
//# sourceMappingURL=ful.mjs.map
|