@optionfactory/ful 3.0.2 → 4.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 +350 -147
- 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 +343 -146
- package/dist/ful.mjs.map +1 -1
- package/package.json +2 -2
package/dist/ful.iife.js
CHANGED
|
@@ -722,69 +722,82 @@ var ful = (function (exports, ftl) {
|
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
class Storage {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
this.storage = storage;
|
|
729
|
-
}
|
|
730
|
-
save(k, v) {
|
|
731
|
-
this.storage.setItem(`${this.prefix}-${k}`, JSON.stringify(v));
|
|
725
|
+
class LocalStorage extends Storage {
|
|
726
|
+
static save(k, v) {
|
|
727
|
+
localStorage.setItem(k, JSON.stringify(v));
|
|
732
728
|
}
|
|
733
|
-
load(k) {
|
|
734
|
-
const got =
|
|
735
|
-
return got ===
|
|
729
|
+
static load(k) {
|
|
730
|
+
const got = localStorage.getItem(k);
|
|
731
|
+
return got === null ? undefined : JSON.parse(got);
|
|
736
732
|
}
|
|
737
|
-
remove(k) {
|
|
738
|
-
|
|
733
|
+
static remove(k) {
|
|
734
|
+
localStorage.removeItem(k);
|
|
739
735
|
}
|
|
740
|
-
pop(k) {
|
|
741
|
-
const decoded =
|
|
742
|
-
|
|
736
|
+
static pop(k) {
|
|
737
|
+
const decoded = LocalStorage.load(k);
|
|
738
|
+
LocalStorage.remove(k);
|
|
743
739
|
return decoded;
|
|
744
740
|
}
|
|
745
|
-
}
|
|
746
741
|
|
|
747
|
-
class LocalStorage extends Storage {
|
|
748
|
-
constructor(prefix) {
|
|
749
|
-
super(prefix, localStorage);
|
|
750
|
-
}
|
|
751
742
|
}
|
|
752
743
|
|
|
744
|
+
|
|
745
|
+
|
|
753
746
|
class SessionStorage extends Storage {
|
|
754
|
-
|
|
755
|
-
|
|
747
|
+
static save(k, v) {
|
|
748
|
+
sessionStorage.setItem(k, JSON.stringify(v));
|
|
749
|
+
}
|
|
750
|
+
static load(k) {
|
|
751
|
+
const got = sessionStorage.getItem(k);
|
|
752
|
+
return got === null ? undefined : JSON.parse(got);
|
|
753
|
+
}
|
|
754
|
+
static remove(k) {
|
|
755
|
+
sessionStorage.removeItem(k);
|
|
756
|
+
}
|
|
757
|
+
static pop(k) {
|
|
758
|
+
const decoded = SessionStorage.load(k);
|
|
759
|
+
SessionStorage.remove(k);
|
|
760
|
+
return decoded;
|
|
756
761
|
}
|
|
757
762
|
}
|
|
758
763
|
|
|
759
|
-
class
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
async load(revision) {
|
|
768
|
-
const saved = this.storage.load(this.key);
|
|
769
|
-
if (!!saved && saved.revision === revision) {
|
|
770
|
-
this.cache = saved.value;
|
|
771
|
-
return;
|
|
764
|
+
class VersionedLocalStorage {
|
|
765
|
+
static save(key, revision, data){
|
|
766
|
+
LocalStorage.save(key, {revision, data});
|
|
767
|
+
}
|
|
768
|
+
static load(key, revision){
|
|
769
|
+
const stored = LocalStorage.load(key);
|
|
770
|
+
if(stored === undefined){
|
|
771
|
+
return undefined;
|
|
772
772
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
this.cache = freshData;
|
|
773
|
+
if(stored.revision !== revision){
|
|
774
|
+
localStorage.removeItem(key);
|
|
775
|
+
return undefined;
|
|
776
|
+
}
|
|
777
|
+
return stored.data;
|
|
779
778
|
}
|
|
780
|
-
|
|
781
|
-
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
class VersionedSessionStorage {
|
|
782
|
+
static save(key, revision, data){
|
|
783
|
+
SessionStorage.save(key, {revision, data});
|
|
784
|
+
}
|
|
785
|
+
static load(key, revision){
|
|
786
|
+
const stored = SessionStorage.load(key);
|
|
787
|
+
if(stored === undefined){
|
|
788
|
+
return undefined;
|
|
789
|
+
}
|
|
790
|
+
if(stored.revision !== revision){
|
|
791
|
+
localStorage.removeItem(key);
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
return stored.data;
|
|
782
795
|
}
|
|
783
796
|
}
|
|
784
797
|
|
|
785
798
|
class AuthorizationCodeFlow {
|
|
786
|
-
static forKeycloak(clientId, realmBaseUrl, redirectUri) {
|
|
787
|
-
const scope = "openid profile";
|
|
799
|
+
static forKeycloak(clientId, realmBaseUrl, redirectUri, maybeScope) {
|
|
800
|
+
const scope = maybeScope ?? "openid profile";
|
|
788
801
|
return new AuthorizationCodeFlow(clientId, scope, {
|
|
789
802
|
auth: new URL("protocol/openid-connect/auth", realmBaseUrl),
|
|
790
803
|
token: new URL("protocol/openid-connect/token", realmBaseUrl),
|
|
@@ -794,7 +807,6 @@ var ful = (function (exports, ftl) {
|
|
|
794
807
|
});
|
|
795
808
|
}
|
|
796
809
|
constructor(clientId, scope, { auth, token, registration, logout, redirect }) {
|
|
797
|
-
this.storage = new SessionStorage(clientId);
|
|
798
810
|
this.clientId = clientId;
|
|
799
811
|
this.scope = scope;
|
|
800
812
|
this.uri = { auth, token, registration, logout, redirect };
|
|
@@ -803,7 +815,7 @@ var ful = (function (exports, ftl) {
|
|
|
803
815
|
const pkceVerifier = Base64.encode(crypto.getRandomValues(new Uint8Array(32)).buffer);
|
|
804
816
|
const pkceChallenge = Base64.encode(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(pkceVerifier)));
|
|
805
817
|
const state = this.clientId + Base64.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);
|
|
806
|
-
|
|
818
|
+
SessionStorage.save(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`, {
|
|
807
819
|
state: state,
|
|
808
820
|
verifier: pkceVerifier
|
|
809
821
|
});
|
|
@@ -831,7 +843,7 @@ var ful = (function (exports, ftl) {
|
|
|
831
843
|
}
|
|
832
844
|
async #tokenExchange(code, state) {
|
|
833
845
|
window.history.replaceState('', "", this.uri.redirect);
|
|
834
|
-
const stateAndVerifier =
|
|
846
|
+
const stateAndVerifier = SessionStorage.pop(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`);
|
|
835
847
|
if (stateAndVerifier.state !== state) {
|
|
836
848
|
throw new Error("State mismatch");
|
|
837
849
|
}
|
|
@@ -859,7 +871,7 @@ var ful = (function (exports, ftl) {
|
|
|
859
871
|
async ensureLoggedIn() {
|
|
860
872
|
const url = new URL(window.location.href);
|
|
861
873
|
const code = url.searchParams.get("code");
|
|
862
|
-
if (code &&
|
|
874
|
+
if (code && SessionStorage.load(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`)) {
|
|
863
875
|
//if callback from keycloak and we have our state still stored
|
|
864
876
|
const state = url.searchParams.get("state");
|
|
865
877
|
return await this.#tokenExchange(code, state);
|
|
@@ -1024,24 +1036,22 @@ var ful = (function (exports, ftl) {
|
|
|
1024
1036
|
}
|
|
1025
1037
|
}
|
|
1026
1038
|
|
|
1027
|
-
|
|
1028
|
-
sleep(ms) {
|
|
1039
|
+
class Timing {
|
|
1040
|
+
static sleep(ms) {
|
|
1029
1041
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1030
|
-
}
|
|
1031
|
-
DEBOUNCE_DEFAULT
|
|
1032
|
-
DEBOUNCE_IMMEDIATE
|
|
1042
|
+
}
|
|
1043
|
+
static DEBOUNCE_DEFAULT = 0;
|
|
1044
|
+
static DEBOUNCE_IMMEDIATE = 1;
|
|
1033
1045
|
/**
|
|
1034
1046
|
* Executes only after a period of inactivity (pause in events).
|
|
1035
|
-
* Delays execution until events stop for a set duration.
|
|
1036
|
-
* Consolidates multiple rapid events into a single execution.
|
|
1037
1047
|
* Respond to the "end" of a series of events.
|
|
1038
1048
|
* @param {*} timeoutMs
|
|
1039
1049
|
* @param {*} func
|
|
1040
1050
|
* @param {*} [options]
|
|
1041
1051
|
* @returns {[function, function]}
|
|
1042
1052
|
*/
|
|
1043
|
-
debounce(timeoutMs, func, options) {
|
|
1044
|
-
const opts = options ??
|
|
1053
|
+
static debounce(timeoutMs, func, options) {
|
|
1054
|
+
const opts = options ?? Timing.DEBOUNCE_DEFAULT;
|
|
1045
1055
|
let tid = null;
|
|
1046
1056
|
let args = [];
|
|
1047
1057
|
let previousTimestamp = 0;
|
|
@@ -1053,7 +1063,7 @@ var ful = (function (exports, ftl) {
|
|
|
1053
1063
|
return;
|
|
1054
1064
|
}
|
|
1055
1065
|
tid = null;
|
|
1056
|
-
if (opts !==
|
|
1066
|
+
if (opts !== Timing.DEBOUNCE_IMMEDIATE) {
|
|
1057
1067
|
func(...args);
|
|
1058
1068
|
}
|
|
1059
1069
|
// This check is needed because `func` can recursively invoke `debounced`.
|
|
@@ -1067,31 +1077,32 @@ var ful = (function (exports, ftl) {
|
|
|
1067
1077
|
previousTimestamp = new Date().getTime();
|
|
1068
1078
|
if (tid === null) {
|
|
1069
1079
|
tid = setTimeout(later, timeoutMs);
|
|
1070
|
-
if (opts ===
|
|
1080
|
+
if (opts === Timing.DEBOUNCE_IMMEDIATE) {
|
|
1071
1081
|
func(...args);
|
|
1072
1082
|
}
|
|
1073
1083
|
}
|
|
1074
1084
|
};
|
|
1075
1085
|
const abort = () => clearTimeout(tid);
|
|
1076
1086
|
return [debounced, abort];
|
|
1077
|
-
}
|
|
1078
|
-
THROTTLE_DEFAULT
|
|
1079
|
-
THROTTLE_NO_LEADING
|
|
1080
|
-
THROTTLE_NO_TRAILING
|
|
1087
|
+
}
|
|
1088
|
+
static THROTTLE_DEFAULT = 0;
|
|
1089
|
+
static THROTTLE_NO_LEADING = 1;
|
|
1090
|
+
static THROTTLE_NO_TRAILING = 2;
|
|
1081
1091
|
/**
|
|
1082
1092
|
* Executes at most once per specified time interval, regardless of ongoing events.
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1093
|
+
* @param {*} timeoutMs
|
|
1094
|
+
* @param {*} func
|
|
1095
|
+
* @param {*} [options]
|
|
1096
|
+
* @returns {[function, function]}
|
|
1086
1097
|
*/
|
|
1087
|
-
throttle(timeoutMs, func, options) {
|
|
1088
|
-
const opts = options ??
|
|
1098
|
+
static throttle(timeoutMs, func, options) {
|
|
1099
|
+
const opts = options ?? Timing.THROTTLE_DEFAULT;
|
|
1089
1100
|
let tid = null;
|
|
1090
1101
|
let args = [];
|
|
1091
1102
|
let previousTimestamp = 0;
|
|
1092
1103
|
|
|
1093
1104
|
const later = () => {
|
|
1094
|
-
previousTimestamp = (opts &
|
|
1105
|
+
previousTimestamp = (opts & Timing.THROTTLE_NO_LEADING) ? 0 : new Date().getTime();
|
|
1095
1106
|
tid = null;
|
|
1096
1107
|
func(...args);
|
|
1097
1108
|
if (tid === null) {
|
|
@@ -1100,7 +1111,7 @@ var ful = (function (exports, ftl) {
|
|
|
1100
1111
|
};
|
|
1101
1112
|
const throttled = function () {
|
|
1102
1113
|
const now = new Date().getTime();
|
|
1103
|
-
if (!previousTimestamp && (opts &
|
|
1114
|
+
if (!previousTimestamp && (opts & Timing.THROTTLE_NO_LEADING)) {
|
|
1104
1115
|
previousTimestamp = now;
|
|
1105
1116
|
}
|
|
1106
1117
|
const remaining = timeoutMs - (now - previousTimestamp);
|
|
@@ -1115,14 +1126,14 @@ var ful = (function (exports, ftl) {
|
|
|
1115
1126
|
if (tid === null) {
|
|
1116
1127
|
args = [];
|
|
1117
1128
|
}
|
|
1118
|
-
} else if (tid === null && !(opts &
|
|
1129
|
+
} else if (tid === null && !(opts & Timing.THROTTLE_NO_TRAILING)) {
|
|
1119
1130
|
tid = setTimeout(later, remaining);
|
|
1120
1131
|
}
|
|
1121
1132
|
};
|
|
1122
1133
|
const abort = () => clearTimeout(tid);
|
|
1123
1134
|
return [throttled, abort];
|
|
1124
1135
|
}
|
|
1125
|
-
}
|
|
1136
|
+
}
|
|
1126
1137
|
|
|
1127
1138
|
class Loaders {
|
|
1128
1139
|
static fromAttributes(el, defaultLoader, options) {
|
|
@@ -1444,14 +1455,15 @@ var ful = (function (exports, ftl) {
|
|
|
1444
1455
|
this.internals = this.attachInternals();
|
|
1445
1456
|
this.internals.role = 'presentation';
|
|
1446
1457
|
}
|
|
1447
|
-
_type(){
|
|
1448
|
-
return this.getAttribute("type") ?? 'text';
|
|
1449
|
-
|
|
1450
|
-
|
|
1458
|
+
_type() {
|
|
1459
|
+
return this.getAttribute("type") ?? 'text';
|
|
1460
|
+
}
|
|
1461
|
+
_fragment(type, slots) {
|
|
1462
|
+
return this.template().withOverlay({ type, slots }).render();
|
|
1451
1463
|
}
|
|
1452
1464
|
render({ slots, observed, disabled }) {
|
|
1453
1465
|
const type = this._type();
|
|
1454
|
-
const fragment = this._fragment(type, slots
|
|
1466
|
+
const fragment = this._fragment(type, slots);
|
|
1455
1467
|
this._input = fragment.querySelector("input,textarea");
|
|
1456
1468
|
|
|
1457
1469
|
ftl.Attributes.forward('input-', this, this._input);
|
|
@@ -1482,16 +1494,17 @@ var ful = (function (exports, ftl) {
|
|
|
1482
1494
|
set value(value) {
|
|
1483
1495
|
this._input.value = value === '' ? null : value;
|
|
1484
1496
|
}
|
|
1485
|
-
get readonly(){
|
|
1497
|
+
get readonly() {
|
|
1486
1498
|
return this._input.readOnly;
|
|
1487
1499
|
}
|
|
1488
1500
|
set readonly(v) {
|
|
1489
1501
|
this._input.readOnly = v;
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1502
|
+
}
|
|
1503
|
+
//@ts-ignore
|
|
1504
|
+
get disabled() {
|
|
1492
1505
|
return this._input.hasAttribute('disabled');
|
|
1493
1506
|
}
|
|
1494
|
-
set disabled(d){
|
|
1507
|
+
set disabled(d) {
|
|
1495
1508
|
ftl.Attributes.toggle(this._input, 'disabled', d);
|
|
1496
1509
|
}
|
|
1497
1510
|
focus(options) {
|
|
@@ -1506,24 +1519,151 @@ var ful = (function (exports, ftl) {
|
|
|
1506
1519
|
this.internals.setValidity({ customError: true }, " ");
|
|
1507
1520
|
this._fieldError.innerText = error;
|
|
1508
1521
|
}
|
|
1509
|
-
formResetCallback(){
|
|
1522
|
+
formResetCallback() {
|
|
1510
1523
|
this.value = this.getAttribute("value");
|
|
1511
1524
|
}
|
|
1512
1525
|
}
|
|
1513
1526
|
|
|
1514
|
-
class
|
|
1527
|
+
class LocalDate extends ftl.ParsedElement {
|
|
1528
|
+
render() {
|
|
1529
|
+
const content = this.innerHTML.trim();
|
|
1530
|
+
if (content === '') {
|
|
1531
|
+
this.innerHTML = this.getAttribute('default') ?? '';
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const locale = this.getAttribute("locale") ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
1535
|
+
const formatter = new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'numeric', day: 'numeric' });
|
|
1536
|
+
const [y, m, d] = content.split('-').map(Number);
|
|
1537
|
+
this.innerHTML = formatter.format(new Date(y, m - 1, d));
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
class Instant extends ftl.ParsedElement {
|
|
1542
|
+
render() {
|
|
1543
|
+
const content = this.innerHTML.trim();
|
|
1544
|
+
if (content === '') {
|
|
1545
|
+
this.innerHTML = this.getAttribute('default') ?? '';
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
const locale = this.getAttribute("locale") ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
1549
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
1550
|
+
year: 'numeric',
|
|
1551
|
+
month: 'numeric',
|
|
1552
|
+
day: 'numeric',
|
|
1553
|
+
hour: 'numeric',
|
|
1554
|
+
minute: 'numeric',
|
|
1555
|
+
second: 'numeric',
|
|
1556
|
+
hour12: false
|
|
1557
|
+
});
|
|
1558
|
+
this.innerHTML = format.format(new Date(Instant.isoToLocal(content)));
|
|
1559
|
+
}
|
|
1560
|
+
static isoToLocal(iso) {
|
|
1561
|
+
//this is so sad
|
|
1562
|
+
const d = new Date(iso);
|
|
1563
|
+
const pad = (n, v) => String(v).padStart(n, '0');
|
|
1564
|
+
const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;
|
|
1565
|
+
const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;
|
|
1566
|
+
return `${date}T${time}`
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
|
|
1571
|
+
class InputLocalDate extends Input {
|
|
1572
|
+
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1573
|
+
_type() {
|
|
1574
|
+
return 'date';
|
|
1575
|
+
}
|
|
1576
|
+
get min() {
|
|
1577
|
+
const v = this._input.min;
|
|
1578
|
+
return v === '' ? null : v;
|
|
1579
|
+
}
|
|
1580
|
+
set min(v) {
|
|
1581
|
+
this._input.min = v;
|
|
1582
|
+
}
|
|
1583
|
+
get max() {
|
|
1584
|
+
const v = this._input.max;
|
|
1585
|
+
return v === '' ? null : v;
|
|
1586
|
+
}
|
|
1587
|
+
set max(v) {
|
|
1588
|
+
this._input.max = v;
|
|
1589
|
+
}
|
|
1590
|
+
get step() {
|
|
1591
|
+
const v = this._input.step;
|
|
1592
|
+
return v === '' ? null : v;
|
|
1593
|
+
}
|
|
1594
|
+
set step(v) {
|
|
1595
|
+
this._input.step = (v ?? '');
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
class InputLocalTime extends InputLocalDate {
|
|
1601
|
+
_type() {
|
|
1602
|
+
return 'time';
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
class InputInstant extends Input {
|
|
1608
|
+
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1609
|
+
_type() {
|
|
1610
|
+
return 'datetime-local';
|
|
1611
|
+
}
|
|
1612
|
+
get value() {
|
|
1613
|
+
const v = this._input.value;
|
|
1614
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1615
|
+
}
|
|
1616
|
+
set value(v) {
|
|
1617
|
+
this._input.value = v ? Instant.isoToLocal(v) : '';
|
|
1618
|
+
}
|
|
1619
|
+
get min() {
|
|
1620
|
+
const v = this._input.min;
|
|
1621
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1622
|
+
}
|
|
1623
|
+
set min(v) {
|
|
1624
|
+
this._input.min = v ? Instant.isoToLocal(v) : '';
|
|
1625
|
+
}
|
|
1626
|
+
get max() {
|
|
1627
|
+
const v = this._input.max;
|
|
1628
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1629
|
+
}
|
|
1630
|
+
set max(v) {
|
|
1631
|
+
this._input.max = v ? Instant.isoToLocal(v) : '';
|
|
1632
|
+
}
|
|
1633
|
+
get step() {
|
|
1634
|
+
const v = this._input.step;
|
|
1635
|
+
return v === '' ? null : v;
|
|
1636
|
+
}
|
|
1637
|
+
set step(v) {
|
|
1638
|
+
this._input.step = (v ?? '');
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
class RemoteLoader {
|
|
1515
1643
|
#http;
|
|
1516
1644
|
#url;
|
|
1517
1645
|
#method;
|
|
1518
1646
|
#responseMapper;
|
|
1519
1647
|
#prefetch;
|
|
1648
|
+
#revision;
|
|
1520
1649
|
#data;
|
|
1521
|
-
|
|
1650
|
+
static create({ el, http, responseMapper }) {
|
|
1651
|
+
return new RemoteLoader({
|
|
1652
|
+
http,
|
|
1653
|
+
url: el.getAttribute("src"),
|
|
1654
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
1655
|
+
responseMapper,
|
|
1656
|
+
prefetch: el.hasAttribute("preload"),
|
|
1657
|
+
revision: el.getAttribute("revision")
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
constructor({http, url, method, responseMapper, prefetch, revision}) {
|
|
1522
1661
|
this.#http = http;
|
|
1523
1662
|
this.#url = url;
|
|
1524
1663
|
this.#method = method;
|
|
1525
1664
|
this.#responseMapper = responseMapper;
|
|
1526
1665
|
this.#prefetch = prefetch;
|
|
1666
|
+
this.#revision = revision;
|
|
1527
1667
|
this.#data = null;
|
|
1528
1668
|
}
|
|
1529
1669
|
async prefetch() {
|
|
@@ -1534,37 +1674,47 @@ var ful = (function (exports, ftl) {
|
|
|
1534
1674
|
}
|
|
1535
1675
|
async exact(...keys) {
|
|
1536
1676
|
await this.#ensureFetched();
|
|
1537
|
-
return this.#data.filter(([k, v]) => keys.
|
|
1677
|
+
return this.#data.filter(([k, v]) => keys.some(r => r == k));
|
|
1538
1678
|
}
|
|
1539
1679
|
async load(needle) {
|
|
1540
1680
|
await this.#ensureFetched();
|
|
1541
|
-
return this.#data.filter(([k, v]) => v.includes(needle?.toLowerCase()));
|
|
1681
|
+
return this.#data.filter(([k, v]) => (v ?? '').includes(needle?.toLowerCase()));
|
|
1542
1682
|
}
|
|
1543
1683
|
async #ensureFetched() {
|
|
1544
1684
|
if (this.#data !== null) {
|
|
1545
1685
|
return
|
|
1546
1686
|
}
|
|
1687
|
+
const storageKey = `${this.#method}@${this.#url}`;
|
|
1688
|
+
if(this.#revision !== null){
|
|
1689
|
+
const data = VersionedLocalStorage.load(storageKey, this.#revision);
|
|
1690
|
+
if(data !== undefined){
|
|
1691
|
+
this.#data = data;
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1547
1695
|
const data = await this.#http.request(this.#method, this.#url)
|
|
1548
1696
|
.fetchJson();
|
|
1549
1697
|
this.#data = this.#responseMapper(data);
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
http,
|
|
1554
|
-
el.getAttribute("src"),
|
|
1555
|
-
el.getAttribute("method") ?? 'POST',
|
|
1556
|
-
responseMapper,
|
|
1557
|
-
el.hasAttribute("preload")
|
|
1558
|
-
);
|
|
1698
|
+
if(this.#revision !== null){
|
|
1699
|
+
VersionedLocalStorage.save(storageKey, this.#revision, this.#data);
|
|
1700
|
+
}
|
|
1559
1701
|
}
|
|
1560
1702
|
}
|
|
1561
1703
|
|
|
1562
|
-
class
|
|
1704
|
+
class PartialRemoteLoader {
|
|
1563
1705
|
#http;
|
|
1564
1706
|
#url;
|
|
1565
1707
|
#method;
|
|
1566
1708
|
#responseMapper;
|
|
1567
|
-
|
|
1709
|
+
static create({ el, http, responseMapper }) {
|
|
1710
|
+
return new PartialRemoteLoader({
|
|
1711
|
+
http,
|
|
1712
|
+
url: el.getAttribute("src"),
|
|
1713
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
1714
|
+
responseMapper
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
constructor({http, url, method, responseMapper}) {
|
|
1568
1718
|
this.#http = http;
|
|
1569
1719
|
this.#url = url;
|
|
1570
1720
|
this.#method = method;
|
|
@@ -1582,26 +1732,21 @@ var ful = (function (exports, ftl) {
|
|
|
1582
1732
|
.fetchJson();
|
|
1583
1733
|
return this.#responseMapper(data);
|
|
1584
1734
|
}
|
|
1585
|
-
static create({ el, http, responseMapper }) {
|
|
1586
|
-
return new ChunkedSelectLoader(
|
|
1587
|
-
http,
|
|
1588
|
-
el.getAttribute("src"),
|
|
1589
|
-
el.getAttribute("method") ?? 'POST',
|
|
1590
|
-
responseMapper
|
|
1591
|
-
);
|
|
1592
|
-
}
|
|
1593
1735
|
}
|
|
1594
1736
|
|
|
1595
|
-
class
|
|
1737
|
+
class InMemoryLoader {
|
|
1596
1738
|
#data
|
|
1597
1739
|
constructor(data) {
|
|
1598
1740
|
this.#data = data;
|
|
1599
1741
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1742
|
+
update(data) {
|
|
1743
|
+
this.#data = data;
|
|
1602
1744
|
}
|
|
1603
|
-
|
|
1604
|
-
return this.#data.filter(([k, v]) =>
|
|
1745
|
+
exact(...keys) {
|
|
1746
|
+
return this.#data.filter(([k, v]) => keys.some(r => r == k));
|
|
1747
|
+
}
|
|
1748
|
+
load(needle) {
|
|
1749
|
+
return this.#data.filter(([k, v]) => (v ?? '').includes(needle?.toLowerCase()));
|
|
1605
1750
|
}
|
|
1606
1751
|
}
|
|
1607
1752
|
|
|
@@ -1613,10 +1758,10 @@ var ful = (function (exports, ftl) {
|
|
|
1613
1758
|
const data = els.map(e => {
|
|
1614
1759
|
return [e.getAttribute("value") ?? e.innerText.trim(), e.innerText.trim()];
|
|
1615
1760
|
});
|
|
1616
|
-
return new
|
|
1761
|
+
return new InMemoryLoader(data);
|
|
1617
1762
|
}
|
|
1618
1763
|
const chunked = "chunked" == conf.el.getAttribute("mode");
|
|
1619
|
-
return chunked ?
|
|
1764
|
+
return chunked ? PartialRemoteLoader.create(conf) : RemoteLoader.create(conf);
|
|
1620
1765
|
}
|
|
1621
1766
|
}
|
|
1622
1767
|
|
|
@@ -1626,8 +1771,9 @@ var ful = (function (exports, ftl) {
|
|
|
1626
1771
|
<ful-spinner class="centered" hidden></ful-spinner>
|
|
1627
1772
|
<menu tabindex="-1" hidden></menu>
|
|
1628
1773
|
`;
|
|
1629
|
-
#spinner
|
|
1630
|
-
#menu
|
|
1774
|
+
#spinner;
|
|
1775
|
+
#menu;
|
|
1776
|
+
#options = new Map();
|
|
1631
1777
|
render({ slots }) {
|
|
1632
1778
|
const fragment = this.template().render();
|
|
1633
1779
|
this.#spinner = fragment.querySelector("ful-spinner");
|
|
@@ -1650,30 +1796,31 @@ var ful = (function (exports, ftl) {
|
|
|
1650
1796
|
if (values === undefined) {
|
|
1651
1797
|
throw new Error("null data");
|
|
1652
1798
|
}
|
|
1799
|
+
this.#options = new Map(values.map((v,i) => [String(i), v]));
|
|
1653
1800
|
if (values.length === 0) {
|
|
1654
1801
|
const el = document.createElement('div');
|
|
1655
1802
|
el.classList.add('text-center', 'py-2', 'bi', 'bi-database-slash');
|
|
1656
1803
|
this.#menu.replaceChildren(el);
|
|
1657
1804
|
return;
|
|
1658
1805
|
}
|
|
1659
|
-
this.#menu.replaceChildren(...values.map(([k, v], i) => {
|
|
1806
|
+
this.#menu.replaceChildren(...values.map(([k, v, m], i) => {
|
|
1660
1807
|
const el = document.createElement('li');
|
|
1661
1808
|
if (i === 0) {
|
|
1662
1809
|
el.setAttribute("selected", '');
|
|
1663
1810
|
}
|
|
1664
|
-
el.setAttribute("value",
|
|
1811
|
+
el.setAttribute("value", i);
|
|
1665
1812
|
el.innerText = v;
|
|
1666
1813
|
return el;
|
|
1667
1814
|
}));
|
|
1668
1815
|
}
|
|
1669
1816
|
#change(target) {
|
|
1670
|
-
const
|
|
1671
|
-
const
|
|
1817
|
+
const index = target.getAttribute('value');
|
|
1818
|
+
const data = this.#options.get(index);
|
|
1672
1819
|
this.hide();
|
|
1673
1820
|
this.dispatchEvent(new CustomEvent('change', {
|
|
1674
1821
|
bubbles: true,
|
|
1675
1822
|
cancelable: false,
|
|
1676
|
-
detail: {
|
|
1823
|
+
detail: { index, data }
|
|
1677
1824
|
}));
|
|
1678
1825
|
}
|
|
1679
1826
|
hide() {
|
|
@@ -1695,12 +1842,13 @@ var ful = (function (exports, ftl) {
|
|
|
1695
1842
|
}
|
|
1696
1843
|
}
|
|
1697
1844
|
async moveOrShow(forward, loader) {
|
|
1698
|
-
if (
|
|
1845
|
+
if (this.shown) {
|
|
1699
1846
|
const selected = this.#menu.querySelector('[selected]') ?? this.#menu.firstElementChild;
|
|
1700
1847
|
const candidate = selected[`${forward ? 'next' : 'previous'}ElementSibling`];
|
|
1701
1848
|
if (candidate) {
|
|
1702
1849
|
selected.removeAttribute('selected');
|
|
1703
1850
|
candidate.setAttribute("selected", "");
|
|
1851
|
+
candidate.scrollIntoView({block: "nearest", behavior: "smooth"});
|
|
1704
1852
|
}
|
|
1705
1853
|
return;
|
|
1706
1854
|
}
|
|
@@ -1719,14 +1867,16 @@ var ful = (function (exports, ftl) {
|
|
|
1719
1867
|
<div class="input-group flex-nowrap" tabindex="-1">
|
|
1720
1868
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1721
1869
|
{{{{ slots.before }}}}
|
|
1722
|
-
<div class="ful-select-input">
|
|
1723
|
-
<
|
|
1724
|
-
|
|
1870
|
+
<div class="ful-select-input-container">
|
|
1871
|
+
<div class="ful-select-input">
|
|
1872
|
+
<badges></badges>
|
|
1873
|
+
<input type="text" form="">
|
|
1874
|
+
</div>
|
|
1875
|
+
<ful-dropdown hidden popover="manual"></ful-dropdown>
|
|
1725
1876
|
</div>
|
|
1726
1877
|
{{{{ slots.after }}}}
|
|
1727
1878
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1728
1879
|
</div>
|
|
1729
|
-
<ful-dropdown hidden></ful-dropdown>
|
|
1730
1880
|
<ful-field-error></ful-field-error>
|
|
1731
1881
|
`;
|
|
1732
1882
|
static mappers = {
|
|
@@ -1754,6 +1904,7 @@ var ful = (function (exports, ftl) {
|
|
|
1754
1904
|
async render({ slots, observed, disabled }) {
|
|
1755
1905
|
const name = this.getAttribute("name");
|
|
1756
1906
|
this.#loader = Loaders.fromAttributes(this, 'loaders:select', { options: slots.options });
|
|
1907
|
+
this.#multiple = this.hasAttribute("multiple");
|
|
1757
1908
|
await this.#loader.prefetch?.();
|
|
1758
1909
|
const fragment = this.template().withOverlay({ slots, name }).render();
|
|
1759
1910
|
this.#input = fragment.querySelector('input');
|
|
@@ -1764,7 +1915,6 @@ var ful = (function (exports, ftl) {
|
|
|
1764
1915
|
this.readonly = observed.readonly;
|
|
1765
1916
|
|
|
1766
1917
|
this.#ddmenu = fragment.querySelector('ful-dropdown');
|
|
1767
|
-
this.#multiple = this.hasAttribute("multiple");
|
|
1768
1918
|
const label = fragment.querySelector('label');
|
|
1769
1919
|
label.addEventListener('click', () => this.focus());
|
|
1770
1920
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
@@ -1772,12 +1922,14 @@ var ful = (function (exports, ftl) {
|
|
|
1772
1922
|
this.#input.ariaLabelledByElements = [label];
|
|
1773
1923
|
|
|
1774
1924
|
const self = this;
|
|
1775
|
-
const [dload, abortdload] =
|
|
1925
|
+
const [dload, abortdload] = Timing.throttle(400, () => self.#ddmenu.show(() => self.#loader.load(self.#input.value)));
|
|
1776
1926
|
this.addEventListener('click', (/** @type any */e) => {
|
|
1777
|
-
e.stopPropagation();
|
|
1778
1927
|
if (e.target.matches('input')) {
|
|
1779
1928
|
return;
|
|
1780
1929
|
}
|
|
1930
|
+
if(this.disabled || this.readonly){
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1781
1933
|
if (this.#ddmenu.shown) {
|
|
1782
1934
|
this.#ddmenu.hide();
|
|
1783
1935
|
return;
|
|
@@ -1787,15 +1939,20 @@ var ful = (function (exports, ftl) {
|
|
|
1787
1939
|
});
|
|
1788
1940
|
this.#badges.addEventListener('click', (e) => {
|
|
1789
1941
|
e.stopPropagation();
|
|
1942
|
+
if(this.disabled || this.readonly){
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1790
1945
|
const idx = [...this.#badges.children].indexOf(e.target);
|
|
1791
1946
|
if (idx === -1) {
|
|
1792
1947
|
return;
|
|
1793
1948
|
}
|
|
1794
1949
|
this.#values.delete(Array.from(this.#values.keys()).pop());
|
|
1950
|
+
this.#changed();
|
|
1795
1951
|
this.#syncBadges();
|
|
1796
1952
|
});
|
|
1797
1953
|
|
|
1798
1954
|
this.#input.addEventListener('blur', e => {
|
|
1955
|
+
e.stopPropagation();
|
|
1799
1956
|
if (e.relatedTarget && this.contains(e.relatedTarget)) {
|
|
1800
1957
|
return;
|
|
1801
1958
|
}
|
|
@@ -1804,6 +1961,10 @@ var ful = (function (exports, ftl) {
|
|
|
1804
1961
|
this.#input.value = '';
|
|
1805
1962
|
});
|
|
1806
1963
|
this.#input.addEventListener('keydown', e => {
|
|
1964
|
+
e.stopPropagation();
|
|
1965
|
+
if(this.disabled || this.readonly){
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1807
1968
|
switch (e.code) {
|
|
1808
1969
|
case 'ArrowUp': {
|
|
1809
1970
|
this.#ddmenu.moveOrShow(false, () => self.#loader.load(self.#input.value));
|
|
@@ -1826,6 +1987,7 @@ var ful = (function (exports, ftl) {
|
|
|
1826
1987
|
//remove last if caret a position 0
|
|
1827
1988
|
if (this.#values.size && this.#input.selectionStart === 0 && this.#input.selectionEnd === 0) {
|
|
1828
1989
|
this.#values.delete(Array.from(this.#values.keys()).pop());
|
|
1990
|
+
this.#changed();
|
|
1829
1991
|
this.#syncBadges();
|
|
1830
1992
|
}
|
|
1831
1993
|
break;
|
|
@@ -1838,19 +2000,37 @@ var ful = (function (exports, ftl) {
|
|
|
1838
2000
|
}
|
|
1839
2001
|
});
|
|
1840
2002
|
this.#input.addEventListener('input', e => {
|
|
2003
|
+
e.stopPropagation();
|
|
2004
|
+
if(this.disabled || this.readonly){
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
1841
2007
|
dload();
|
|
1842
2008
|
});
|
|
1843
2009
|
this.#ddmenu.addEventListener('change', (e) => {
|
|
2010
|
+
e.stopPropagation();
|
|
1844
2011
|
if (!this.#multiple) {
|
|
1845
2012
|
this.#values.clear();
|
|
1846
2013
|
}
|
|
1847
|
-
this.#values.set(e.detail.
|
|
2014
|
+
this.#values.set(e.detail.data[0], e.detail.data.slice(1));
|
|
2015
|
+
this.#changed();
|
|
1848
2016
|
this.#syncBadges();
|
|
1849
2017
|
this.#input.focus();
|
|
1850
2018
|
this.#ddmenu.hide();
|
|
1851
2019
|
});
|
|
1852
2020
|
this.replaceChildren(fragment);
|
|
1853
2021
|
}
|
|
2022
|
+
withLoader(fn) {
|
|
2023
|
+
fn(this.#loader);
|
|
2024
|
+
}
|
|
2025
|
+
#changed() {
|
|
2026
|
+
const selection = [...this.#values.entries()].map(e => ({key: e[0], label: e[1][0], metadata: e[1].slice(1)}));
|
|
2027
|
+
const value = this.#multiple ? selection : (selection[0] ?? null);
|
|
2028
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
2029
|
+
bubbles: true,
|
|
2030
|
+
cancelable: false,
|
|
2031
|
+
detail: { value }
|
|
2032
|
+
}));
|
|
2033
|
+
}
|
|
1854
2034
|
#syncBadges() {
|
|
1855
2035
|
const badges = Array.from(this.#values.entries()).map(([k, v]) => {
|
|
1856
2036
|
const b = document.createElement('badge');
|
|
@@ -1862,14 +2042,14 @@ var ful = (function (exports, ftl) {
|
|
|
1862
2042
|
this.#badges.innerHTML = '';
|
|
1863
2043
|
this.#badges.append(...badges);
|
|
1864
2044
|
}
|
|
1865
|
-
set value(
|
|
1866
|
-
if(
|
|
2045
|
+
set value(vs) {
|
|
2046
|
+
if(vs === null){
|
|
1867
2047
|
this.#values = new Map();
|
|
1868
2048
|
this.#syncBadges();
|
|
1869
2049
|
return;
|
|
1870
2050
|
}
|
|
1871
2051
|
(async () => {
|
|
1872
|
-
const entries = await (this.#multiple ? this.#loader.exact(...
|
|
2052
|
+
const entries = await (this.#multiple ? this.#loader.exact(...vs) : this.#loader.exact(vs));
|
|
1873
2053
|
this.#values = new Map(entries);
|
|
1874
2054
|
this.#syncBadges();
|
|
1875
2055
|
})();
|
|
@@ -1880,6 +2060,25 @@ var ful = (function (exports, ftl) {
|
|
|
1880
2060
|
}
|
|
1881
2061
|
return [...this.#values.keys()][0] ?? null;
|
|
1882
2062
|
}
|
|
2063
|
+
get entry() {
|
|
2064
|
+
if (this.#multiple) {
|
|
2065
|
+
return [...this.#values.entries()];
|
|
2066
|
+
}
|
|
2067
|
+
return [...this.#values.entries()][0] ?? null;
|
|
2068
|
+
}
|
|
2069
|
+
//@ts-ignore
|
|
2070
|
+
get disabled(){
|
|
2071
|
+
return this.#input.hasAttribute('disabled');
|
|
2072
|
+
}
|
|
2073
|
+
set disabled(d){
|
|
2074
|
+
ftl.Attributes.toggle(this.#input, 'disabled', d);
|
|
2075
|
+
}
|
|
2076
|
+
get readonly(){
|
|
2077
|
+
return this.#input.readOnly;
|
|
2078
|
+
}
|
|
2079
|
+
set readonly(v) {
|
|
2080
|
+
this.#input.readOnly = v;
|
|
2081
|
+
}
|
|
1883
2082
|
focus(options) {
|
|
1884
2083
|
this.#input.focus(options);
|
|
1885
2084
|
}
|
|
@@ -1988,7 +2187,8 @@ var ful = (function (exports, ftl) {
|
|
|
1988
2187
|
}
|
|
1989
2188
|
set readonly(v) {
|
|
1990
2189
|
this.#fieldset.inert = v;
|
|
1991
|
-
}
|
|
2190
|
+
}
|
|
2191
|
+
//@ts-ignore
|
|
1992
2192
|
get disabled(){
|
|
1993
2193
|
return this.#fieldset.hasAttribute('disabled');
|
|
1994
2194
|
}
|
|
@@ -2076,7 +2276,8 @@ var ful = (function (exports, ftl) {
|
|
|
2076
2276
|
}
|
|
2077
2277
|
set readonly(v) {
|
|
2078
2278
|
this.#container.inert = v;
|
|
2079
|
-
}
|
|
2279
|
+
}
|
|
2280
|
+
//@ts-ignore
|
|
2080
2281
|
get disabled() {
|
|
2081
2282
|
return this.#input.hasAttribute('disabled');
|
|
2082
2283
|
}
|
|
@@ -2545,21 +2746,12 @@ var ful = (function (exports, ftl) {
|
|
|
2545
2746
|
}
|
|
2546
2747
|
const [operator, ...values] = v;
|
|
2547
2748
|
this.#operator.setAttribute('value', operator);
|
|
2548
|
-
this.#value1.value = values[0] ?
|
|
2549
|
-
this.#value2.value = values[1] ?
|
|
2749
|
+
this.#value1.value = values[0] ? Instant.isoToLocal(values[0]) : values[0];
|
|
2750
|
+
this.#value2.value = values[1] ? Instant.isoToLocal(values[1]) : values[1];
|
|
2550
2751
|
this.reflect(() => {
|
|
2551
2752
|
this.setAttribute('value', JSON.stringify(v));
|
|
2552
2753
|
});
|
|
2553
2754
|
}
|
|
2554
|
-
|
|
2555
|
-
static isoToLocal(iso) {
|
|
2556
|
-
//this is so sad
|
|
2557
|
-
const d = new Date(iso);
|
|
2558
|
-
const pad = (n, v) => String(v).padStart(n, '0');
|
|
2559
|
-
const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;
|
|
2560
|
-
const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;
|
|
2561
|
-
return `${date}T${time}`
|
|
2562
|
-
}
|
|
2563
2755
|
focus(options) {
|
|
2564
2756
|
this.#value1.focus(options);
|
|
2565
2757
|
}
|
|
@@ -2768,6 +2960,11 @@ var ful = (function (exports, ftl) {
|
|
|
2768
2960
|
.defineElement('ful-form', Form)
|
|
2769
2961
|
.defineElement('ful-checkbox', Checkbox)
|
|
2770
2962
|
.defineElement('ful-input', Input)
|
|
2963
|
+
.defineElement('ful-local-date', LocalDate)
|
|
2964
|
+
.defineElement('ful-instant', Instant)
|
|
2965
|
+
.defineElement('ful-input-local-date', InputLocalDate)
|
|
2966
|
+
.defineElement('ful-input-local-time', InputLocalTime)
|
|
2967
|
+
.defineElement('ful-input-instant', InputInstant)
|
|
2771
2968
|
.defineElement('ful-radio-group', RadioGroup)
|
|
2772
2969
|
.defineElement('ful-table', Table)
|
|
2773
2970
|
.defineElement('ful-pagination', Pagination)
|
|
@@ -2798,8 +2995,13 @@ var ful = (function (exports, ftl) {
|
|
|
2798
2995
|
exports.HttpClient = HttpClient;
|
|
2799
2996
|
exports.HttpClientError = HttpClientError;
|
|
2800
2997
|
exports.Input = Input;
|
|
2998
|
+
exports.InputInstant = InputInstant;
|
|
2999
|
+
exports.InputLocalDate = InputLocalDate;
|
|
3000
|
+
exports.InputLocalTime = InputLocalTime;
|
|
3001
|
+
exports.Instant = Instant;
|
|
2801
3002
|
exports.InstantFilter = InstantFilter;
|
|
2802
3003
|
exports.Loaders = Loaders;
|
|
3004
|
+
exports.LocalDate = LocalDate;
|
|
2803
3005
|
exports.LocalDateFilter = LocalDateFilter;
|
|
2804
3006
|
exports.LocalStorage = LocalStorage;
|
|
2805
3007
|
exports.MediaType = MediaType;
|
|
@@ -2814,8 +3016,9 @@ var ful = (function (exports, ftl) {
|
|
|
2814
3016
|
exports.Table = Table;
|
|
2815
3017
|
exports.TableSchemaParser = TableSchemaParser;
|
|
2816
3018
|
exports.TextFilter = TextFilter;
|
|
2817
|
-
exports.
|
|
2818
|
-
exports.
|
|
3019
|
+
exports.Timing = Timing;
|
|
3020
|
+
exports.VersionedLocalStorage = VersionedLocalStorage;
|
|
3021
|
+
exports.VersionedSessionStorage = VersionedSessionStorage;
|
|
2819
3022
|
|
|
2820
3023
|
return exports;
|
|
2821
3024
|
|