@optionfactory/ful 4.0.10 → 4.0.12
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 +268 -15
- 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 +267 -16
- package/dist/ful.mjs.map +1 -1
- package/package.json +1 -1
package/dist/ful.mjs
CHANGED
|
@@ -1683,6 +1683,246 @@ class InputInstant extends Input {
|
|
|
1683
1683
|
}
|
|
1684
1684
|
}
|
|
1685
1685
|
|
|
1686
|
+
class InputFile extends Input {
|
|
1687
|
+
static l10n = {
|
|
1688
|
+
en: {
|
|
1689
|
+
'dropzonelabel': 'Click or drop your files here',
|
|
1690
|
+
'unaccepptablefiletype': "Only files of type {0} are supported",
|
|
1691
|
+
'maxfilesizeexceeded': "Maximum supported file size is {0}",
|
|
1692
|
+
'maxtotalsizeexceeded': "Maximum supported total file size is {0}"
|
|
1693
|
+
},
|
|
1694
|
+
it: {
|
|
1695
|
+
'dropzonelabel': 'Clicca o trascina i file qui',
|
|
1696
|
+
'unaccepptablefiletype': "Solo i file di tipo {0} sono supportati",
|
|
1697
|
+
'maxfilesizeexceeded': "La dimensione massima di un file è di {0}",
|
|
1698
|
+
'maxtotalsizeexceeded': "La dimensione massima complessiva dei file è di {0}"
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
static observed = ['value', 'readonly:presence', "accept:csv", 'multiple:presence', "itemlist:presence", "dropzone:presence", "maxfilesize:number", "maxtotalsize:number"];
|
|
1702
|
+
#accept;
|
|
1703
|
+
#items;
|
|
1704
|
+
#dropzone;
|
|
1705
|
+
#warnings;
|
|
1706
|
+
_type() {
|
|
1707
|
+
return 'file';
|
|
1708
|
+
}
|
|
1709
|
+
static template = `
|
|
1710
|
+
<div class="form-label">
|
|
1711
|
+
<label>{{{{ slots.default }}}}</label>
|
|
1712
|
+
{{{{ slots.info }}}}
|
|
1713
|
+
</div>
|
|
1714
|
+
<div class="input-group">
|
|
1715
|
+
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1716
|
+
{{{{ slots.before }}}}
|
|
1717
|
+
<input class="form-control" data-tpl-type="type" placeholder=" " form="">
|
|
1718
|
+
{{{{ slots.after }}}}
|
|
1719
|
+
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1720
|
+
</div>
|
|
1721
|
+
<div data-ref="dropzone" class="dropzone" data-tpl-if="slots.dropzone">
|
|
1722
|
+
{{{{ slots.dropzone }}}}
|
|
1723
|
+
</div>
|
|
1724
|
+
<div data-ref="dropzone" class="dropzone" data-tpl-if="!slots.dropzone">
|
|
1725
|
+
{{ #l10n:t('dropzonelabel') }}
|
|
1726
|
+
</div>
|
|
1727
|
+
<div data-ref="items" class="items"></div>
|
|
1728
|
+
<ful-field-warnings></ful-field-warnings>
|
|
1729
|
+
<ful-field-error></ful-field-error>
|
|
1730
|
+
`;
|
|
1731
|
+
static templates = {
|
|
1732
|
+
items: `
|
|
1733
|
+
<div class="item" data-tpl-each="files" data-tpl-var="file" data-tpl-data-name="file.name">
|
|
1734
|
+
<div class="filename"><span>{{ file.name }}</span></div>
|
|
1735
|
+
<div class="size">{{ #bytes:format(file.size) }}</div>
|
|
1736
|
+
<button class="btn btn-sm btn-outline-danger"><i class="bi bi-x-lg"></i></button>
|
|
1737
|
+
</div>
|
|
1738
|
+
`,
|
|
1739
|
+
warning: `<ful-field-warning>{{ #l10n:t(key, args) }}</ful-field-warning>`
|
|
1740
|
+
}
|
|
1741
|
+
render(conf) {
|
|
1742
|
+
const { observed } = conf;
|
|
1743
|
+
super.render(conf);
|
|
1744
|
+
this.#items = this.querySelector("[data-ref=items]");
|
|
1745
|
+
this.#dropzone = this.querySelector("[data-ref=dropzone]");
|
|
1746
|
+
this.#warnings = this.querySelector("ful-field-warnings");
|
|
1747
|
+
this.accept = observed.accept;
|
|
1748
|
+
this.multiple = observed.multiple;
|
|
1749
|
+
this.itemlist = observed.itemlist;
|
|
1750
|
+
this.dropzone = observed.dropzone;
|
|
1751
|
+
this.maxfilesize = observed.maxfilesize;
|
|
1752
|
+
this.maxtotalsize = observed.maxtotalsize;
|
|
1753
|
+
this.#warnings.addEventListener('animationend', e => {
|
|
1754
|
+
e.target.remove();
|
|
1755
|
+
});
|
|
1756
|
+
this.#items.addEventListener('click', (e) => {
|
|
1757
|
+
if (!e.target.closest("button")) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
const fileName = e.target.closest(".item").dataset.name;
|
|
1761
|
+
const dt = new DataTransfer();
|
|
1762
|
+
[...this.files].filter(f => f.name !== fileName).forEach(f => dt.items.add(f));
|
|
1763
|
+
this.files = dt.files;
|
|
1764
|
+
this.#update();
|
|
1765
|
+
});
|
|
1766
|
+
this.#dropzone.addEventListener("click", (e) => {
|
|
1767
|
+
this.querySelector('input')?.click();
|
|
1768
|
+
});
|
|
1769
|
+
|
|
1770
|
+
this.#dropzone.addEventListener("dragover", (e) => {
|
|
1771
|
+
e.preventDefault();
|
|
1772
|
+
});
|
|
1773
|
+
this.#dropzone.addEventListener("drop", (e) => {
|
|
1774
|
+
e.preventDefault();
|
|
1775
|
+
const dt = new DataTransfer();
|
|
1776
|
+
[...e.dataTransfer.items].filter(i => i.kind === 'file').forEach(i => dt.items.add(i.getAsFile()));
|
|
1777
|
+
this.files = dt.files;
|
|
1778
|
+
this.#update();
|
|
1779
|
+
});
|
|
1780
|
+
this._input.addEventListener("change", (e) => {
|
|
1781
|
+
this.#update();
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
#formatByteSize(v) {
|
|
1785
|
+
return (v > 1024 * 1024) ? `${Math.round(v / 1024 / 1024 * 100) / 100}MiB` : (v > 1024 ? `${Math.round(v / 1024 * 100) / 100}KiB` : `${v}B`);
|
|
1786
|
+
}
|
|
1787
|
+
#update() {
|
|
1788
|
+
this.setCustomValidity();
|
|
1789
|
+
this.#ensureAcceptable();
|
|
1790
|
+
this.#ensureFileSizes();
|
|
1791
|
+
this.#ensureTotalSize();
|
|
1792
|
+
if(this.#useItemlist){
|
|
1793
|
+
this.template('items').withOverlay({ files: this.files }).withModule('bytes', { format: this.#formatByteSize }).renderTo(this.#items);
|
|
1794
|
+
}else {
|
|
1795
|
+
this.#items.replaceChildren();
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
warning(key, args) {
|
|
1799
|
+
this.template('warning').withOverlay({ key, args }).renderTo(this.#warnings);
|
|
1800
|
+
}
|
|
1801
|
+
#ensureAcceptable() {
|
|
1802
|
+
if (!this.#accept) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
const unacceptable = [...this.files]
|
|
1806
|
+
.filter(file => this.#accept.some(type => !file.name.toLowerCase().endsWith(type.toLowerCase())));
|
|
1807
|
+
|
|
1808
|
+
if (unacceptable.length === 0) {
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
this.warning('unaccepptablefiletype', this.#accept.join(","));
|
|
1812
|
+
const dt = new DataTransfer();
|
|
1813
|
+
[...this.files].filter(f => !unacceptable.includes(f)).forEach(f => dt.items.add(f));
|
|
1814
|
+
this.files = dt.files;
|
|
1815
|
+
}
|
|
1816
|
+
#ensureFileSizes() {
|
|
1817
|
+
if (this.#maxfilesize === null) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
const oversized = [...this.files]
|
|
1821
|
+
.filter(file => file.size > this.#maxfilesize);
|
|
1822
|
+
if (oversized.length === 0) {
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
this.warning('maxfilesizeexceeded', this.#formatByteSize(this.#maxfilesize));
|
|
1826
|
+
const dt = new DataTransfer();
|
|
1827
|
+
[...this.files].filter(f => !oversized.includes(f)).forEach(f => dt.items.add(f));
|
|
1828
|
+
this.files = dt.files;
|
|
1829
|
+
}
|
|
1830
|
+
#ensureTotalSize() {
|
|
1831
|
+
if (this.#maxtotalsize === null) {
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
const totalSize = [...this.files].reduce((acc, file) => acc + file.size, 0);
|
|
1835
|
+
if (totalSize <= this.#maxtotalsize) {
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
this.warning('maxtotalsizeexceeded', this.#formatByteSize(this.#maxtotalsize));
|
|
1839
|
+
this.files = new DataTransfer().files;
|
|
1840
|
+
}
|
|
1841
|
+
get accept() {
|
|
1842
|
+
return this.#accept;
|
|
1843
|
+
}
|
|
1844
|
+
set accept(vs) {
|
|
1845
|
+
this._input.accept = vs.join(",");
|
|
1846
|
+
this.#accept = vs;
|
|
1847
|
+
this.reflect(() => {
|
|
1848
|
+
this.setAttribute('accept', this._input.accept);
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
get multiple() {
|
|
1852
|
+
return this._input.multiple;
|
|
1853
|
+
}
|
|
1854
|
+
set multiple(v) {
|
|
1855
|
+
this._input.multiple = v;
|
|
1856
|
+
this.reflect(() => {
|
|
1857
|
+
this.setAttribute('multiple', this._input.multiple);
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
get files() {
|
|
1861
|
+
return this._input.files;
|
|
1862
|
+
}
|
|
1863
|
+
set files(vs) {
|
|
1864
|
+
this._input.files = vs;
|
|
1865
|
+
}
|
|
1866
|
+
get file() {
|
|
1867
|
+
return this.files[0] ?? null;
|
|
1868
|
+
}
|
|
1869
|
+
set file(v) {
|
|
1870
|
+
const dt = new DataTransfer();
|
|
1871
|
+
dt.items.add(v);
|
|
1872
|
+
this.files = dt.files;
|
|
1873
|
+
}
|
|
1874
|
+
get value() {
|
|
1875
|
+
const names = Array.from(this._input.files).map(f => f.name);
|
|
1876
|
+
return this.multiple ? names : (names[0] ?? null);
|
|
1877
|
+
}
|
|
1878
|
+
set value(v) {
|
|
1879
|
+
//TODO:
|
|
1880
|
+
}
|
|
1881
|
+
#maxfilesize;
|
|
1882
|
+
get maxfilesize() {
|
|
1883
|
+
return this.#maxfilesize;
|
|
1884
|
+
}
|
|
1885
|
+
set maxfilesize(v) {
|
|
1886
|
+
this.#maxfilesize = v;
|
|
1887
|
+
this.reflect(() => {
|
|
1888
|
+
this.setAttribute('maxfilesize', v);
|
|
1889
|
+
});
|
|
1890
|
+
|
|
1891
|
+
}
|
|
1892
|
+
#maxtotalsize;
|
|
1893
|
+
get maxtotalsize() {
|
|
1894
|
+
return this.#maxtotalsize;
|
|
1895
|
+
}
|
|
1896
|
+
set maxtotalsize(v) {
|
|
1897
|
+
this.#maxtotalsize = v;
|
|
1898
|
+
this.reflect(() => {
|
|
1899
|
+
this.setAttribute('maxtotalsize', v);
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
#useItemlist;
|
|
1903
|
+
get itemlist() {
|
|
1904
|
+
return this.#useItemlist;
|
|
1905
|
+
}
|
|
1906
|
+
set itemlist(v) {
|
|
1907
|
+
this.#useItemlist = v;
|
|
1908
|
+
Attributes.toggle(this.#items, "hidden", !v);
|
|
1909
|
+
this.reflect(() => {
|
|
1910
|
+
Attributes.toggle(this, "itemlist", v);
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
#useDropzone;
|
|
1914
|
+
get dropzone() {
|
|
1915
|
+
return this.#useDropzone;
|
|
1916
|
+
}
|
|
1917
|
+
set dropzone(v) {
|
|
1918
|
+
this.#useDropzone = v;
|
|
1919
|
+
Attributes.toggle(this.#dropzone, "hidden", !v);
|
|
1920
|
+
this.reflect(() => {
|
|
1921
|
+
Attributes.toggle(this, "dropzone", v);
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1686
1926
|
class RemoteLoader {
|
|
1687
1927
|
#http;
|
|
1688
1928
|
#url;
|
|
@@ -1995,7 +2235,9 @@ class Select extends ParsedElement {
|
|
|
1995
2235
|
this.#changed();
|
|
1996
2236
|
this.#syncBadges();
|
|
1997
2237
|
});
|
|
1998
|
-
|
|
2238
|
+
this.#input.addEventListener('change', e => {
|
|
2239
|
+
e.stopPropagation();
|
|
2240
|
+
});
|
|
1999
2241
|
this.#input.addEventListener('blur', e => {
|
|
2000
2242
|
e.stopPropagation();
|
|
2001
2243
|
if (e.relatedTarget && this.contains(e.relatedTarget)) {
|
|
@@ -2061,6 +2303,7 @@ class Select extends ParsedElement {
|
|
|
2061
2303
|
this.#syncBadges();
|
|
2062
2304
|
this.#input.focus();
|
|
2063
2305
|
this.#ddmenu.hide();
|
|
2306
|
+
this.#input.value = '';
|
|
2064
2307
|
});
|
|
2065
2308
|
this.replaceChildren(fragment);
|
|
2066
2309
|
}
|
|
@@ -2084,7 +2327,7 @@ class Select extends ParsedElement {
|
|
|
2084
2327
|
b.innerText = v[0];
|
|
2085
2328
|
return b;
|
|
2086
2329
|
});
|
|
2087
|
-
this.#badges.
|
|
2330
|
+
this.#badges.replaceChildren();
|
|
2088
2331
|
this.#badges.append(...badges);
|
|
2089
2332
|
}
|
|
2090
2333
|
set value(vs) {
|
|
@@ -2577,7 +2820,7 @@ class RemoteTableLoader {
|
|
|
2577
2820
|
return await this.#http.request(this.#method, this.#url)
|
|
2578
2821
|
.param("page", pageRequest.page)
|
|
2579
2822
|
.param("size", pageRequest.size)
|
|
2580
|
-
.param("sort", sortRequest
|
|
2823
|
+
.param("sort", sortRequest ? `${sortRequest.sorter},${sortRequest.order}` : null)
|
|
2581
2824
|
.param("filters", filters.length > 0 ? JSON.stringify(Object.fromEntries(filters)) : null)
|
|
2582
2825
|
.fetchJson();
|
|
2583
2826
|
}
|
|
@@ -2723,7 +2966,7 @@ class Table extends ParsedElement {
|
|
|
2723
2966
|
return await this.load(this.#latestRequest.pageRequest, this.#latestRequest.sortRequest, this.#latestRequest.filterRequest);
|
|
2724
2967
|
}
|
|
2725
2968
|
async load(pageRequest, sortRequest, filterRequest) {
|
|
2726
|
-
this.#body.
|
|
2969
|
+
this.#body.replaceChildren();
|
|
2727
2970
|
this.#loading.removeAttribute("hidden", "");
|
|
2728
2971
|
this.#feedback.setAttribute("hidden", "");
|
|
2729
2972
|
this.#noAutoload.setAttribute("hidden", "");
|
|
@@ -3042,6 +3285,23 @@ class TextFilter extends ParsedElement {
|
|
|
3042
3285
|
}
|
|
3043
3286
|
}
|
|
3044
3287
|
|
|
3288
|
+
class LocalizationModule {
|
|
3289
|
+
static t(k, ...args) {
|
|
3290
|
+
//@ts-ignore
|
|
3291
|
+
const format = this.l10n[this.language][k] ?? this.l10n['en'][k] ?? k;
|
|
3292
|
+
if (args.length === 0) {
|
|
3293
|
+
return format;
|
|
3294
|
+
}
|
|
3295
|
+
return format.replace(/{(\d+)}/g, (m, is) => {
|
|
3296
|
+
return args[Number(is)];
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3299
|
+
static tl(k, args) {
|
|
3300
|
+
return LocalizationModule.t(k, ...args);
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3045
3305
|
class Plugin {
|
|
3046
3306
|
configure(registry) {
|
|
3047
3307
|
const httpClient = HttpClient.builder()
|
|
@@ -3049,22 +3309,13 @@ class Plugin {
|
|
|
3049
3309
|
.withRedirectOnUnauthorized("/")
|
|
3050
3310
|
.build();
|
|
3051
3311
|
registry
|
|
3052
|
-
.defineModule("l10n",
|
|
3053
|
-
t: function (k, ...args) {
|
|
3054
|
-
const format = this.l10n[this.language][k] ?? this.l10n['en'][k] ?? k;
|
|
3055
|
-
if (args.length === 0) {
|
|
3056
|
-
return format;
|
|
3057
|
-
}
|
|
3058
|
-
return format.replace(/{(\d+)}/g, (m, is) => {
|
|
3059
|
-
return args[Number(is)];
|
|
3060
|
-
});
|
|
3061
|
-
}
|
|
3062
|
-
})
|
|
3312
|
+
.defineModule("l10n", LocalizationModule)
|
|
3063
3313
|
.defineComponent('http-client', httpClient)
|
|
3064
3314
|
.defineElement('ful-spinner', Spinner)
|
|
3065
3315
|
.defineElement('ful-form', Form)
|
|
3066
3316
|
.defineElement('ful-checkbox', Checkbox)
|
|
3067
3317
|
.defineElement('ful-input', Input)
|
|
3318
|
+
.defineElement('ful-input-file', InputFile)
|
|
3068
3319
|
.defineElement('ful-local-date', LocalDate)
|
|
3069
3320
|
.defineElement('ful-instant', Instant)
|
|
3070
3321
|
.defineElement('ful-input-local-date', InputLocalDate)
|
|
@@ -3088,5 +3339,5 @@ class Plugin {
|
|
|
3088
3339
|
}
|
|
3089
3340
|
}
|
|
3090
3341
|
|
|
3091
|
-
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InputInstant, InputLocalDate, InputLocalTime, Instant, InstantFilter, Loaders, LocalDate, LocalDateFilter, LocalStorage, MediaType, Pagination, Plugin, RadioGroup, Select, SelectLoader, SessionStorage, SortButton, Spinner, Table, TableSchemaParser, TextFilter, Timing, VersionedLocalStorage, VersionedSessionStorage };
|
|
3342
|
+
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InputFile, InputInstant, InputLocalDate, InputLocalTime, Instant, InstantFilter, Loaders, LocalDate, LocalDateFilter, LocalStorage, LocalizationModule, MediaType, Pagination, Plugin, RadioGroup, Select, SelectLoader, SessionStorage, SortButton, Spinner, Table, TableSchemaParser, TextFilter, Timing, VersionedLocalStorage, VersionedSessionStorage };
|
|
3092
3343
|
//# sourceMappingURL=ful.mjs.map
|