@optionfactory/ful 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ful.iife.js +149 -131
- 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 +147 -129
- package/dist/ful.mjs.map +1 -1
- package/package.json +1 -1
package/dist/ful.mjs
CHANGED
|
@@ -665,6 +665,38 @@ class Nodes {
|
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
+
class TemplateRegistry {
|
|
669
|
+
#idToFragment = {};
|
|
670
|
+
#idToTemplate = {};
|
|
671
|
+
#ec;
|
|
672
|
+
put(k, fragment) {
|
|
673
|
+
if (this.#ec) {
|
|
674
|
+
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
this.#idToFragment[k] = fragment;
|
|
678
|
+
}
|
|
679
|
+
get(k) {
|
|
680
|
+
if (!this.#ec) {
|
|
681
|
+
throw new Error("evaluationContext is not configured");
|
|
682
|
+
}
|
|
683
|
+
const tpl = this.#idToTemplate[k];
|
|
684
|
+
if (!tpl) {
|
|
685
|
+
throw new Error(`missing template: '${k}'`);
|
|
686
|
+
}
|
|
687
|
+
return tpl;
|
|
688
|
+
}
|
|
689
|
+
configure(ec) {
|
|
690
|
+
this.#ec = ec;
|
|
691
|
+
for (const [k, fragment] of Object.entries(this.#idToFragment)) {
|
|
692
|
+
delete this.#idToFragment[k];
|
|
693
|
+
this.#idToTemplate[k] = ftl.Template.fromFragment(fragment, ec);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const templates = new TemplateRegistry();
|
|
699
|
+
|
|
668
700
|
class UpgradeQueue {
|
|
669
701
|
#q = [];
|
|
670
702
|
constructor() {
|
|
@@ -683,83 +715,85 @@ class UpgradeQueue {
|
|
|
683
715
|
|
|
684
716
|
const upgradeQueue = new UpgradeQueue();
|
|
685
717
|
|
|
686
|
-
|
|
687
|
-
#parsed;
|
|
688
|
-
connectedCallback() {
|
|
689
|
-
if (this.#parsed) {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
if (this.ownerDocument.readyState === 'complete' || Nodes.isParsed(this)) {
|
|
693
|
-
upgradeQueue.enqueue(this);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
this.ownerDocument.addEventListener('DOMContentLoaded', () => {
|
|
697
|
-
observer.disconnect();
|
|
698
|
-
upgradeQueue.enqueue(this);
|
|
699
|
-
});
|
|
700
|
-
const observer = new MutationObserver(() => {
|
|
701
|
-
if (!Nodes.isParsed(this)) {
|
|
702
|
-
return;
|
|
703
|
-
}
|
|
704
|
-
observer.disconnect();
|
|
705
|
-
upgradeQueue.enqueue(this);
|
|
706
|
-
});
|
|
707
|
-
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
708
|
-
}
|
|
709
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
710
|
-
if (!this.#parsed || oldValue === newValue) {
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
this[name] = newValue;
|
|
714
|
-
}
|
|
715
|
-
upgrade() {
|
|
716
|
-
if (this.#parsed) {
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
this.#parsed = true;
|
|
720
|
-
return this.ready();
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
718
|
+
const ParsedElement = (flags, others) => {
|
|
724
719
|
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
const slotted = Slots.from(this);
|
|
729
|
-
const fragment = await Promise.resolve(this.render(slotted, template));
|
|
730
|
-
this.replaceChildren(fragment);
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
};
|
|
734
|
-
|
|
735
|
-
const Stateful = (SuperClass, flags, others) => {
|
|
720
|
+
const observed_flags = flags || [];
|
|
721
|
+
const observed_others = others || [];
|
|
722
|
+
const observed = [].concat(observed_flags).concat(observed_others);
|
|
736
723
|
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
const k = class extends SuperClass {
|
|
724
|
+
const k = class extends HTMLElement {
|
|
740
725
|
static get observedAttributes() {
|
|
741
|
-
return
|
|
726
|
+
return observed;
|
|
742
727
|
}
|
|
728
|
+
#parsed;
|
|
729
|
+
#internals;
|
|
743
730
|
constructor(...args) {
|
|
744
731
|
super(...args);
|
|
745
|
-
this
|
|
732
|
+
this.#internals = this.attachInternals();
|
|
733
|
+
}
|
|
734
|
+
get internals() {
|
|
735
|
+
return this.#internals;
|
|
736
|
+
}
|
|
737
|
+
connectedCallback() {
|
|
738
|
+
if (this.#parsed) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
if (this.ownerDocument.readyState === 'complete' || Nodes.isParsed(this)) {
|
|
742
|
+
upgradeQueue.enqueue(this);
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
this.ownerDocument.addEventListener('DOMContentLoaded', () => {
|
|
746
|
+
observer.disconnect();
|
|
747
|
+
upgradeQueue.enqueue(this);
|
|
748
|
+
});
|
|
749
|
+
const observer = new MutationObserver(() => {
|
|
750
|
+
if (!Nodes.isParsed(this)) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
observer.disconnect();
|
|
754
|
+
upgradeQueue.enqueue(this);
|
|
755
|
+
});
|
|
756
|
+
observer.observe(this.parentNode, { childList: true, subtree: true });
|
|
746
757
|
}
|
|
758
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
759
|
+
if (!this.#parsed || oldValue === newValue) {
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
this[name] = newValue;
|
|
763
|
+
}
|
|
764
|
+
async upgrade() {
|
|
765
|
+
if (this.#parsed) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
this.#parsed = true;
|
|
769
|
+
await this.render();
|
|
770
|
+
for (const flag of observed_flags) {
|
|
771
|
+
if(this.hasAttribute(flag)){
|
|
772
|
+
this[flag] = true;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
for (const other of observed_others) {
|
|
776
|
+
if(this.hasAttribute(other)){
|
|
777
|
+
this[other] = this.getAttribute(other);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
747
781
|
};
|
|
748
782
|
|
|
749
|
-
for (const flag of
|
|
783
|
+
for (const flag of observed_flags) {
|
|
750
784
|
Object.defineProperty(k.prototype, flag, {
|
|
751
785
|
enumerable: true,
|
|
752
786
|
configurable: true,
|
|
753
787
|
get() {
|
|
754
|
-
return this.
|
|
788
|
+
return this.internals.states.has(`--${flag}`);
|
|
755
789
|
},
|
|
756
790
|
set(value) {
|
|
757
791
|
//see https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet#using_double_dash_prefixed_idents
|
|
758
792
|
if (Attributes.asBoolean(value)) {
|
|
759
|
-
this.
|
|
793
|
+
this.internals.states.add(`--${flag}`);
|
|
760
794
|
return;
|
|
761
795
|
}
|
|
762
|
-
this.
|
|
796
|
+
this.internals.states.delete(`--${flag}`);
|
|
763
797
|
}
|
|
764
798
|
});
|
|
765
799
|
}
|
|
@@ -836,12 +870,12 @@ function mutate(el, raw) {
|
|
|
836
870
|
el.value = raw;
|
|
837
871
|
}
|
|
838
872
|
|
|
839
|
-
class Form extends
|
|
873
|
+
class Form extends ParsedElement() {
|
|
840
874
|
static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';
|
|
841
875
|
static SCROLL_OFFSET = 50;
|
|
842
|
-
render(
|
|
876
|
+
render() {
|
|
843
877
|
const form = document.createElement('form');
|
|
844
|
-
form.
|
|
878
|
+
form.replaceChildren(...this.childNodes);
|
|
845
879
|
form.addEventListener('submit', async (e) => {
|
|
846
880
|
e.preventDefault();
|
|
847
881
|
this.spinner(true);
|
|
@@ -859,7 +893,7 @@ class Form extends Templated(ParsedElement) {
|
|
|
859
893
|
this.spinner(false);
|
|
860
894
|
}
|
|
861
895
|
});
|
|
862
|
-
|
|
896
|
+
this.replaceChildren(form);
|
|
863
897
|
}
|
|
864
898
|
spinner(spin) {
|
|
865
899
|
this.querySelectorAll('ful-spinner').forEach(el => el.hidden = !spin);
|
|
@@ -916,11 +950,7 @@ class Form extends Templated(ParsedElement) {
|
|
|
916
950
|
}
|
|
917
951
|
}
|
|
918
952
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
});
|
|
922
|
-
|
|
923
|
-
const ful_input_template_ = globalThis.ful_input_template || ftl.Template.fromHtml(`
|
|
953
|
+
templates.put('ful-input', Fragments.fromHtml(`
|
|
924
954
|
<label data-tpl-for="id" class="form-label">{{{{ slotted.default }}}}</label>
|
|
925
955
|
<div class="input-group">
|
|
926
956
|
<span data-tpl-if="slotted.ibefore" class="input-group-text">{{{{ slotted.ibefore }}}}</span>
|
|
@@ -930,33 +960,31 @@ const ful_input_template_ = globalThis.ful_input_template || ftl.Template.fromHt
|
|
|
930
960
|
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
931
961
|
</div>
|
|
932
962
|
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
}
|
|
963
|
+
`));
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
const makeInputFragment = (el, slotted) => {
|
|
967
|
+
const input = el.input = slotted.input = slotted.input || (() => {
|
|
968
|
+
const el = document.createElement("input");
|
|
969
|
+
el.classList.add("form-control");
|
|
970
|
+
return el;
|
|
971
|
+
})();
|
|
972
|
+
input.setAttribute('ful-validation-target', '');
|
|
973
|
+
|
|
974
|
+
const id = input.getAttribute('id') || el.getAttribute('input-id') || Attributes.uid('ful-input');
|
|
975
|
+
Attributes.forward('input-', el, slotted.input);
|
|
976
|
+
Attributes.defaultValue(slotted.input, "id", id);
|
|
977
|
+
Attributes.defaultValue(slotted.input, "type", "text");
|
|
978
|
+
Attributes.defaultValue(slotted.input, "placeholder", " ");
|
|
979
|
+
const name = el.getAttribute('name');
|
|
980
|
+
return templates.get('ful-input').render(el, { id, name, slotted });
|
|
981
|
+
};
|
|
954
982
|
|
|
955
|
-
class Input extends
|
|
956
|
-
render(
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
983
|
+
class Input extends ParsedElement([], ['value']) {
|
|
984
|
+
render() {
|
|
985
|
+
const slotted = Slots.from(el);
|
|
986
|
+
const fragment = makeInputFragment(this, slotted);
|
|
987
|
+
this.replaceChildren(fragment);
|
|
960
988
|
}
|
|
961
989
|
get value() {
|
|
962
990
|
return this.input.value;
|
|
@@ -970,11 +998,8 @@ class Input extends Stateful(StatelessInput, [], ['value']) {
|
|
|
970
998
|
* <script src="tom-select.complete.js"></script>
|
|
971
999
|
* <link href="tom-select.bootstrap5.css" rel="stylesheet" />
|
|
972
1000
|
*/
|
|
973
|
-
const ful_select_ec = globalThis.ec || ftl.EvaluationContext.configure({
|
|
974
|
-
|
|
975
|
-
});
|
|
976
1001
|
|
|
977
|
-
|
|
1002
|
+
templates.put('ful-select', Fragments.fromHtml(`
|
|
978
1003
|
<label data-tpl-for="tsId" class="form-label">{{{{ slotted.default }}}}</label>
|
|
979
1004
|
{{{{ input }}}}
|
|
980
1005
|
<div class="input-group">
|
|
@@ -985,15 +1010,17 @@ const ful_select_template_ = globalThis.ful_select_template || ftl.Template.from
|
|
|
985
1010
|
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
986
1011
|
</div>
|
|
987
1012
|
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
988
|
-
|
|
1013
|
+
`));
|
|
989
1014
|
|
|
990
1015
|
|
|
991
|
-
class Select extends
|
|
1016
|
+
class Select extends ParsedElement([], ["value"]) {
|
|
992
1017
|
constructor(tsConfig) {
|
|
993
1018
|
super();
|
|
994
1019
|
this.tsConfig = tsConfig;
|
|
995
1020
|
}
|
|
996
|
-
render(
|
|
1021
|
+
render() {
|
|
1022
|
+
const slotted = Slots.from(this);
|
|
1023
|
+
|
|
997
1024
|
const type = this.getAttribute("type") || 'local';
|
|
998
1025
|
const remote = type != 'local';
|
|
999
1026
|
const loadOnce = this.getAttribute('load') != 'always';
|
|
@@ -1021,7 +1048,6 @@ class Select extends Stateful(Templated(ParsedElement, ful_select_template_), []
|
|
|
1021
1048
|
}
|
|
1022
1049
|
};
|
|
1023
1050
|
|
|
1024
|
-
|
|
1025
1051
|
this._remote = remote;
|
|
1026
1052
|
// we need to await this load in setValue when remote is configured and the option
|
|
1027
1053
|
// is not loaded yet.
|
|
@@ -1036,7 +1062,7 @@ class Select extends Stateful(Templated(ParsedElement, ful_select_template_), []
|
|
|
1036
1062
|
const type = query && query.hasOwnProperty('byId') ? 'id' : 'query';
|
|
1037
1063
|
const qvalue = type === 'id' ? query.byId : query;
|
|
1038
1064
|
const data = await (this.loader ? this.loader(qvalue, type) : []);
|
|
1039
|
-
if(type !== 'id'){
|
|
1065
|
+
if (type !== 'id') {
|
|
1040
1066
|
this.loaded = true;
|
|
1041
1067
|
}
|
|
1042
1068
|
callback(data);
|
|
@@ -1050,12 +1076,12 @@ class Select extends Stateful(Templated(ParsedElement, ful_select_template_), []
|
|
|
1050
1076
|
} : {}, tsDefaultConfig, this.tsConfig));
|
|
1051
1077
|
//we remove the input to move it
|
|
1052
1078
|
input.remove();
|
|
1053
|
-
|
|
1079
|
+
templates.get('ful-select').renderTo(this, { id, tsId, name, input, slotted });
|
|
1054
1080
|
}
|
|
1055
1081
|
set value(v) {
|
|
1056
1082
|
(async () => {
|
|
1057
|
-
if(this._remote){
|
|
1058
|
-
await this._unwrappedRemoteLoad({byId: v}, this.ts.loadCallback.bind(this.ts));
|
|
1083
|
+
if (this._remote) {
|
|
1084
|
+
await this._unwrappedRemoteLoad({ byId: v }, this.ts.loadCallback.bind(this.ts));
|
|
1059
1085
|
}
|
|
1060
1086
|
this.ts.setValue(v);
|
|
1061
1087
|
})();
|
|
@@ -1066,11 +1092,7 @@ class Select extends Stateful(Templated(ParsedElement, ful_select_template_), []
|
|
|
1066
1092
|
}
|
|
1067
1093
|
}
|
|
1068
1094
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
});
|
|
1072
|
-
|
|
1073
|
-
const ful_radiougroup_template_ = globalThis.ful_radiogroup_template || ftl.Template.fromHtml(`
|
|
1095
|
+
templates.put('ful-radio-group', Fragments.fromHtml(`
|
|
1074
1096
|
<fieldset>
|
|
1075
1097
|
<legend class="form-label">
|
|
1076
1098
|
{{{{ slotted.default }}}}
|
|
@@ -1089,11 +1111,12 @@ const ful_radiougroup_template_ = globalThis.ful_radiogroup_template || ftl.Temp
|
|
|
1089
1111
|
{{{{ slotted.footer }}}}
|
|
1090
1112
|
</footer>
|
|
1091
1113
|
</fieldset>
|
|
1092
|
-
|
|
1114
|
+
`));
|
|
1093
1115
|
|
|
1094
1116
|
|
|
1095
|
-
class RadioGroup extends
|
|
1096
|
-
render(
|
|
1117
|
+
class RadioGroup extends ParsedElement(['disabled'], ['value']) {
|
|
1118
|
+
render() {
|
|
1119
|
+
const slotted = Slots.from(this);
|
|
1097
1120
|
const name = this.getAttribute('name') || Attributes.uid('ful-radiogroup');
|
|
1098
1121
|
const radioEls = Array.from(slotted.default.querySelectorAll('ful-radio'));
|
|
1099
1122
|
const inputsAndLabels = radioEls.map(el => {
|
|
@@ -1108,38 +1131,32 @@ class RadioGroup extends Stateful(Templated(ParsedElement, ful_radiougroup_templ
|
|
|
1108
1131
|
return [input, label];
|
|
1109
1132
|
});
|
|
1110
1133
|
radioEls.forEach(el => el.remove());
|
|
1111
|
-
|
|
1112
|
-
const fragment = template.render({
|
|
1134
|
+
templates.get('ful-radio-group').renderTo(this, {
|
|
1113
1135
|
name: name,
|
|
1114
1136
|
slotted: slotted,
|
|
1115
1137
|
inputsAndLabels: inputsAndLabels
|
|
1116
1138
|
});
|
|
1117
|
-
return fragment;
|
|
1118
1139
|
}
|
|
1119
1140
|
get value() {
|
|
1120
1141
|
const checked = this.querySelector('input[type=radio]:checked');
|
|
1121
1142
|
return checked ? checked.value : null;
|
|
1122
1143
|
}
|
|
1123
|
-
set value(value){
|
|
1144
|
+
set value(value) {
|
|
1124
1145
|
this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`).checked = true;
|
|
1125
1146
|
}
|
|
1126
1147
|
}
|
|
1127
1148
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
const ful_spinner_template_ = globalThis.ful_spinner_template || ftl.Template.fromHtml(`
|
|
1149
|
+
templates.put('ful-spinner', Fragments.fromHtml(`
|
|
1133
1150
|
<div class="ful-spinner-wrapper">
|
|
1134
1151
|
<div class="ful-spinner-text">{{{{ slotted.default }}}}</div>
|
|
1135
1152
|
<div class="ful-spinner-icon"></div>
|
|
1136
1153
|
</div>
|
|
1137
|
-
|
|
1154
|
+
`));
|
|
1138
1155
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1156
|
+
class Spinner extends ParsedElement() {
|
|
1157
|
+
render() {
|
|
1158
|
+
const slotted = Slots.from(this);
|
|
1159
|
+
templates.get('ful-spinner').renderTo(this, { slotted });
|
|
1143
1160
|
}
|
|
1144
1161
|
}
|
|
1145
1162
|
|
|
@@ -1216,7 +1233,8 @@ class Wizard extends HTMLElement {
|
|
|
1216
1233
|
}
|
|
1217
1234
|
|
|
1218
1235
|
class CustomElements {
|
|
1219
|
-
static configure() {
|
|
1236
|
+
static configure(ec) {
|
|
1237
|
+
templates.configure(ec);
|
|
1220
1238
|
customElements.define('ful-spinner', Spinner);
|
|
1221
1239
|
customElements.define('ful-input', Input);
|
|
1222
1240
|
customElements.define('ful-radio-group', RadioGroup);
|
|
@@ -1225,5 +1243,5 @@ class CustomElements {
|
|
|
1225
1243
|
}
|
|
1226
1244
|
}
|
|
1227
1245
|
|
|
1228
|
-
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, CustomElements, Failure, Form, Fragments, Hex, HttpClient, Input, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Slots, Spinner,
|
|
1246
|
+
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, CustomElements, Failure, Form, Fragments, Hex, HttpClient, Input, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Slots, Spinner, SyncEvent, TemplateRegistry, VersionedStorage, Wizard, jsonPatch, jsonPost, jsonPut, jsonRequest, makeInputFragment, templates, timing };
|
|
1229
1247
|
//# sourceMappingURL=ful.mjs.map
|