@optionfactory/ful 4.0.16 → 5.0.1
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 +143 -118
- 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 +144 -118
- 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">
|
|
@@ -1470,6 +1457,7 @@ class Input extends ParsedElement {
|
|
|
1470
1457
|
if (!skipObservedSetup) {
|
|
1471
1458
|
this.disabled = disabled;
|
|
1472
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;
|
|
@@ -1801,7 +1798,7 @@ class InputFile extends Input {
|
|
|
1801
1798
|
return;
|
|
1802
1799
|
}
|
|
1803
1800
|
const unacceptable = [...this.files]
|
|
1804
|
-
.filter(file => this.#accept.some(type =>
|
|
1801
|
+
.filter(file => !this.#accept.some(type => file.name.toLowerCase().endsWith(type.toLowerCase())));
|
|
1805
1802
|
|
|
1806
1803
|
if (unacceptable.length === 0) {
|
|
1807
1804
|
return;
|
|
@@ -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);
|
|
@@ -3011,7 +3047,7 @@ class Table extends ParsedElement {
|
|
|
3011
3047
|
this.#feedback.setAttribute("hidden", "");
|
|
3012
3048
|
this.#noAutoload.setAttribute("hidden", "");
|
|
3013
3049
|
try {
|
|
3014
|
-
const loader =
|
|
3050
|
+
const loader = registry.component(this.getAttribute("loader") ?? 'loaders:table').create(this);
|
|
3015
3051
|
const pageResponse = await loader.load(pageRequest, sortRequest, filterRequest);
|
|
3016
3052
|
this.#latestRequest = { pageRequest, sortRequest, filterRequest };
|
|
3017
3053
|
this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
|
|
@@ -3048,7 +3084,7 @@ class Table extends ParsedElement {
|
|
|
3048
3084
|
}
|
|
3049
3085
|
|
|
3050
3086
|
class InstantFilter extends Input {
|
|
3051
|
-
static observed = ['value:json', 'readonly:presence'];
|
|
3087
|
+
static observed = ['value:json', 'readonly:presence', 'required:presence'];
|
|
3052
3088
|
static template = `
|
|
3053
3089
|
<div class="form-label">
|
|
3054
3090
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3078,13 +3114,14 @@ class InstantFilter extends Input {
|
|
|
3078
3114
|
#value1;
|
|
3079
3115
|
#value2;
|
|
3080
3116
|
render(conf) {
|
|
3081
|
-
super.render({...conf, skipObservedSetup: true});
|
|
3117
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3082
3118
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3083
3119
|
this.#value1 = this.querySelector('[data-ref=value1]');
|
|
3084
3120
|
this.#value2 = this.querySelector('[data-ref=value2]');
|
|
3085
3121
|
|
|
3086
3122
|
this.disabled = conf.disabled;
|
|
3087
3123
|
this.readonly = conf.observed.readonly;
|
|
3124
|
+
this.required = conf.observed.required;
|
|
3088
3125
|
this.value = conf.observed.value;
|
|
3089
3126
|
|
|
3090
3127
|
this.addEventListener('click', (evt) => {
|
|
@@ -3106,7 +3143,7 @@ class InstantFilter extends Input {
|
|
|
3106
3143
|
return values.some(v => v === '') ? undefined : [operator, ...values.map(v => new Date(v).toISOString())];
|
|
3107
3144
|
}
|
|
3108
3145
|
set value(v) {
|
|
3109
|
-
if (v
|
|
3146
|
+
if (v == null) {
|
|
3110
3147
|
this.#value1.value = '';
|
|
3111
3148
|
this.#value2.value = '';
|
|
3112
3149
|
return;
|
|
@@ -3119,20 +3156,15 @@ class InstantFilter extends Input {
|
|
|
3119
3156
|
set readonly(v) {
|
|
3120
3157
|
this.#value2.readOnly = v;
|
|
3121
3158
|
super.readonly = v;
|
|
3122
|
-
}
|
|
3159
|
+
}
|
|
3123
3160
|
set disabled(d) {
|
|
3124
3161
|
Attributes.toggle(this.#value2, 'disabled', d);
|
|
3125
3162
|
super.disabled = d;
|
|
3126
3163
|
}
|
|
3127
|
-
formResetCallback() {
|
|
3128
|
-
const v = this.getAttribute("value");
|
|
3129
|
-
this.value = v === null ? null : JSON.parse(v);
|
|
3130
|
-
}
|
|
3131
|
-
|
|
3132
3164
|
}
|
|
3133
3165
|
|
|
3134
3166
|
class LocalDateFilter extends Input {
|
|
3135
|
-
static observed = ["value:json", 'readonly:presence'];
|
|
3167
|
+
static observed = ["value:json", 'readonly:presence', 'required:presence'];
|
|
3136
3168
|
static template = `
|
|
3137
3169
|
<div class="form-label">
|
|
3138
3170
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3162,7 +3194,7 @@ class LocalDateFilter extends Input {
|
|
|
3162
3194
|
#value1;
|
|
3163
3195
|
#value2;
|
|
3164
3196
|
render(conf) {
|
|
3165
|
-
super.render({...conf, skipObservedSetup: true});
|
|
3197
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3166
3198
|
|
|
3167
3199
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3168
3200
|
this.#value1 = this.querySelector('[data-ref=value1]');
|
|
@@ -3170,6 +3202,7 @@ class LocalDateFilter extends Input {
|
|
|
3170
3202
|
|
|
3171
3203
|
this.disabled = conf.disabled;
|
|
3172
3204
|
this.readonly = conf.observed.readonly;
|
|
3205
|
+
this.required = conf.observed.required;
|
|
3173
3206
|
this.value = conf.observed.value;
|
|
3174
3207
|
|
|
3175
3208
|
this.addEventListener('click', (evt) => {
|
|
@@ -3190,7 +3223,7 @@ class LocalDateFilter extends Input {
|
|
|
3190
3223
|
return values.some(v => v === '') ? undefined : [operator, ...values];
|
|
3191
3224
|
}
|
|
3192
3225
|
set value(v) {
|
|
3193
|
-
if (v
|
|
3226
|
+
if (v == null) {
|
|
3194
3227
|
this.#value1.value = '';
|
|
3195
3228
|
this.#value2.value = '';
|
|
3196
3229
|
return;
|
|
@@ -3208,14 +3241,10 @@ class LocalDateFilter extends Input {
|
|
|
3208
3241
|
Attributes.toggle(this.#value2, 'disabled', d);
|
|
3209
3242
|
super.disabled = d;
|
|
3210
3243
|
}
|
|
3211
|
-
formResetCallback() {
|
|
3212
|
-
const v = this.getAttribute("value");
|
|
3213
|
-
this.value = v === null ? null : JSON.parse(v);
|
|
3214
|
-
}
|
|
3215
3244
|
}
|
|
3216
3245
|
|
|
3217
3246
|
class TextFilter extends Input {
|
|
3218
|
-
static observed = ["value:json", 'readonly:presence'];
|
|
3247
|
+
static observed = ["value:json", 'readonly:presence', 'required:presence'];
|
|
3219
3248
|
static template = `
|
|
3220
3249
|
<div class="form-label">
|
|
3221
3250
|
<label>{{{{ slots.default }}}}</label>
|
|
@@ -3240,13 +3269,14 @@ class TextFilter extends Input {
|
|
|
3240
3269
|
#operator;
|
|
3241
3270
|
#value;
|
|
3242
3271
|
render(conf) {
|
|
3243
|
-
super.render({...conf, skipObservedSetup: true});
|
|
3272
|
+
super.render({ ...conf, skipObservedSetup: true });
|
|
3244
3273
|
|
|
3245
3274
|
this.#operator = this.querySelector('[data-ref=operator]');
|
|
3246
3275
|
this.#value = this.querySelector('[data-ref=value]');
|
|
3247
3276
|
|
|
3248
3277
|
this.disabled = conf.disabled;
|
|
3249
3278
|
this.readonly = conf.observed.readonly;
|
|
3279
|
+
this.required = conf.observed.required;
|
|
3250
3280
|
this.value = conf.observed.value;
|
|
3251
3281
|
|
|
3252
3282
|
this.addEventListener('click', (evt) => {
|
|
@@ -3265,7 +3295,7 @@ class TextFilter extends Input {
|
|
|
3265
3295
|
return this.#value.value === '' ? undefined : [operator, 'IGNORE_CASE', this.#value.value];
|
|
3266
3296
|
}
|
|
3267
3297
|
set value(v) {
|
|
3268
|
-
if (v
|
|
3298
|
+
if (v == null) {
|
|
3269
3299
|
this.#value.value = '';
|
|
3270
3300
|
return;
|
|
3271
3301
|
}
|
|
@@ -3273,10 +3303,6 @@ class TextFilter extends Input {
|
|
|
3273
3303
|
this.#operator.setAttribute('value', operator);
|
|
3274
3304
|
this.#value.value = value;
|
|
3275
3305
|
}
|
|
3276
|
-
formResetCallback() {
|
|
3277
|
-
const v = this.getAttribute("value");
|
|
3278
|
-
this.value = v === null ? null : JSON.parse(v);
|
|
3279
|
-
}
|
|
3280
3306
|
}
|
|
3281
3307
|
|
|
3282
3308
|
class LocalizationModule {
|
|
@@ -3333,5 +3359,5 @@ class Plugin {
|
|
|
3333
3359
|
}
|
|
3334
3360
|
}
|
|
3335
3361
|
|
|
3336
|
-
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 };
|
|
3337
3363
|
//# sourceMappingURL=ful.mjs.map
|