@optionfactory/ful 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ful.css +1 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.iife.js +58 -173
- 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 +59 -170
- package/dist/ful.mjs.map +1 -1
- package/package.json +1 -1
package/dist/ful.mjs
CHANGED
|
@@ -70,38 +70,6 @@ class Hex {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const Observable = (SuperClass) => class extends SuperClass {
|
|
74
|
-
constructor(...args) {
|
|
75
|
-
super(...args);
|
|
76
|
-
this.listeners = {};
|
|
77
|
-
}
|
|
78
|
-
fireSync(event, data, initialAcc) {
|
|
79
|
-
const listeners = this.listeners[event] || [];
|
|
80
|
-
let acc = initialAcc;
|
|
81
|
-
for (const l of listeners) {
|
|
82
|
-
acc = l(data, this, acc);
|
|
83
|
-
}
|
|
84
|
-
return acc;
|
|
85
|
-
}
|
|
86
|
-
async fire(event, data, initialAcc) {
|
|
87
|
-
const listeners = this.listeners[event] || [];
|
|
88
|
-
let acc = initialAcc;
|
|
89
|
-
for (const l of listeners) {
|
|
90
|
-
acc = await l(data, this, acc);
|
|
91
|
-
}
|
|
92
|
-
return acc;
|
|
93
|
-
}
|
|
94
|
-
on(event, listener) {
|
|
95
|
-
this.listeners[event] = this.listeners[event] || [];
|
|
96
|
-
this.listeners[event].push(listener);
|
|
97
|
-
}
|
|
98
|
-
un(event, listener) {
|
|
99
|
-
const listeners = this.listeners[event] || [];
|
|
100
|
-
const idx = listeners.indexOf(listener);
|
|
101
|
-
return idx === -1 ? [] : listeners.splice(idx, 1);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
|
|
105
73
|
class ContextInterceptor {
|
|
106
74
|
constructor() {
|
|
107
75
|
const context = document.querySelector("meta[name='context']").getAttribute("content");
|
|
@@ -727,35 +695,14 @@ const Stateful = (SuperClass, flags, others) => {
|
|
|
727
695
|
};
|
|
728
696
|
};
|
|
729
697
|
|
|
730
|
-
class FieldError extends Templated(HTMLElement) {
|
|
731
|
-
render(slotted, template) {
|
|
732
|
-
this.classList.add('invalid-feedback');
|
|
733
|
-
}
|
|
734
|
-
static configure() {
|
|
735
|
-
customElements.define('ful-field-error', FieldError);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
class Errors extends Templated(HTMLElement) {
|
|
740
|
-
render(slotted, template) {
|
|
741
|
-
this.classList.add('alert', 'alert-danger', 'd-none');
|
|
742
|
-
}
|
|
743
|
-
static configure() {
|
|
744
|
-
customElements.define('ful-errors', Errors);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
|
|
749
698
|
/* global Infinity, CSS */
|
|
750
699
|
|
|
751
|
-
class Form extends Templated(
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
this.ignoredChildrenSelector = ignoredChildrenSelector || '.d-none, [hidden]';
|
|
758
|
-
}
|
|
700
|
+
class Form extends Templated(HTMLElement) {
|
|
701
|
+
static MUTATORS = {};
|
|
702
|
+
static EXTRACTORS = {};
|
|
703
|
+
static VALUE_HOLDERS_SELECTOR = '[name]';
|
|
704
|
+
static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';
|
|
705
|
+
|
|
759
706
|
render(slotted, template) {
|
|
760
707
|
const form = document.createElement('form');
|
|
761
708
|
form.append(slotted.default);
|
|
@@ -763,7 +710,9 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
763
710
|
e.preventDefault();
|
|
764
711
|
this.spinner(true);
|
|
765
712
|
try {
|
|
766
|
-
|
|
713
|
+
if(this.submitter) {
|
|
714
|
+
await this.submitter(this.getValues(), this);
|
|
715
|
+
}
|
|
767
716
|
} catch (e) {
|
|
768
717
|
if (e instanceof Failure) {
|
|
769
718
|
this.setErrors(e.problems);
|
|
@@ -790,20 +739,20 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
790
739
|
continue;
|
|
791
740
|
}
|
|
792
741
|
Array.from(this.querySelectorAll(`[name='${CSS.escape(k)}']`)).forEach((el) => {
|
|
793
|
-
Form.mutate(
|
|
742
|
+
Form.mutate(Form.MUTATORS, el, values[k], k, values);
|
|
794
743
|
});
|
|
795
744
|
}
|
|
796
745
|
}
|
|
797
746
|
getValues() {
|
|
798
|
-
return Array.from(this.querySelectorAll(
|
|
747
|
+
return Array.from(this.querySelectorAll(Form.VALUE_HOLDERS_SELECTOR))
|
|
799
748
|
.filter((el) => {
|
|
800
749
|
if (el.dataset['fulBindInclude'] === 'never') {
|
|
801
750
|
return false;
|
|
802
751
|
}
|
|
803
|
-
return el.dataset['fulBindInclude'] === 'always' || el.closest(
|
|
752
|
+
return el.dataset['fulBindInclude'] === 'always' || el.closest(Form.IGNORED_CHILDREN_SELECTOR) === null;
|
|
804
753
|
})
|
|
805
754
|
.reduce((result, el) => {
|
|
806
|
-
return Form.providePath(result, el.getAttribute('name'), Form.extract(
|
|
755
|
+
return Form.providePath(result, el.getAttribute('name'), Form.extract(Form.EXTRACTORS, el));
|
|
807
756
|
}, {});
|
|
808
757
|
}
|
|
809
758
|
setErrors(errors, scroll) {
|
|
@@ -812,13 +761,10 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
812
761
|
.filter((e) => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT')
|
|
813
762
|
.forEach((e) => {
|
|
814
763
|
const name = e.context.replace("[", ".").replace("].", ".");
|
|
764
|
+
//TODO: match [name=] ful-validation-target and [name=]:not(:has(ful-validation-target))
|
|
765
|
+
//
|
|
815
766
|
this.querySelectorAll(`[name='${CSS.escape(name)}']`)
|
|
816
|
-
.forEach(input =>
|
|
817
|
-
input.classList.add('is-invalid');
|
|
818
|
-
if (input.parentElement.classList.contains("form-floating")) {
|
|
819
|
-
input.parentElement.classList.add('is-invalid');
|
|
820
|
-
}
|
|
821
|
-
});
|
|
767
|
+
.forEach(input => input.classList.add('is-invalid'));
|
|
822
768
|
this.querySelectorAll(`ful-field-error[field='${CSS.escape(name)}']`)
|
|
823
769
|
.forEach(el => el.innerText = e.reason);
|
|
824
770
|
});
|
|
@@ -827,14 +773,14 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
827
773
|
const globalErrors = errors.filter((e) => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');
|
|
828
774
|
el.innerHTML = globalErrors.map(e => e.reason).join("\n");
|
|
829
775
|
if (globalErrors.length !== 0) {
|
|
830
|
-
el.
|
|
776
|
+
el.removeAttribute('hidden');
|
|
831
777
|
}
|
|
832
778
|
});
|
|
833
779
|
|
|
834
780
|
if (!scroll) {
|
|
835
781
|
return;
|
|
836
782
|
}
|
|
837
|
-
const ys = Array.from(this.querySelectorAll('ful-field-error
|
|
783
|
+
const ys = Array.from(this.querySelectorAll('ful-field-error'))
|
|
838
784
|
.map(el => el.getBoundingClientRect().y + window.scrollY);
|
|
839
785
|
const miny = Math.min(...ys);
|
|
840
786
|
if (miny !== Infinity) {
|
|
@@ -842,12 +788,12 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
842
788
|
}
|
|
843
789
|
}
|
|
844
790
|
clearErrors() {
|
|
845
|
-
this.querySelectorAll('
|
|
791
|
+
this.querySelectorAll('.is-invalid')
|
|
846
792
|
.forEach(el => el.classList.remove('is-invalid'));
|
|
847
793
|
this.querySelectorAll("ful-errors")
|
|
848
794
|
.forEach(el => {
|
|
849
795
|
el.innerHTML = '';
|
|
850
|
-
el.
|
|
796
|
+
el.setAttribute('hidden', '');
|
|
851
797
|
});
|
|
852
798
|
}
|
|
853
799
|
static extract(extractors, el) {
|
|
@@ -867,9 +813,6 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
867
813
|
if (el.dataset['fulBindType'] === 'boolean') {
|
|
868
814
|
return !el.value ? null : el.value === 'true';
|
|
869
815
|
}
|
|
870
|
-
if (el.getValue) {
|
|
871
|
-
return el.getValue();
|
|
872
|
-
}
|
|
873
816
|
return el.value || null;
|
|
874
817
|
}
|
|
875
818
|
static mutate(mutators, el, raw, key, values) {
|
|
@@ -886,10 +829,6 @@ class Form extends Templated(Observable(HTMLElement)) {
|
|
|
886
829
|
el.checked = raw;
|
|
887
830
|
return;
|
|
888
831
|
}
|
|
889
|
-
if (el.setValue) {
|
|
890
|
-
el.setValue(raw);
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
832
|
el.value = raw;
|
|
894
833
|
}
|
|
895
834
|
|
|
@@ -933,35 +872,19 @@ const ful_input_ec = globalThis.ec || ftl.EvaluationContext.configure({
|
|
|
933
872
|
});
|
|
934
873
|
|
|
935
874
|
const ful_input_template_ = globalThis.ful_input_template || ftl.Template.fromHtml(`
|
|
936
|
-
<
|
|
875
|
+
<label data-tpl-for="id" class="form-label">{{{{ slotted.default }}}}</label>
|
|
876
|
+
<div class="input-group">
|
|
937
877
|
<span data-tpl-if="slotted.ibefore" class="input-group-text">{{{{ slotted.ibefore }}}}</span>
|
|
938
878
|
<div data-tpl-if="slotted.before" data-tpl-remove="tag">{{{{ slotted.before }}}}</div>
|
|
939
|
-
|
|
940
|
-
{{{{ slotted.input }}}}
|
|
941
|
-
<label data-tpl-for="name" class="form-label">{{{{ slotted.default }}}}</label>
|
|
942
|
-
</div>
|
|
879
|
+
{{{{ slotted.input }}}}
|
|
943
880
|
<div data-tpl-if="slotted.after" data-tpl-remove="tag">{{{{ slotted.after }}}}</div>
|
|
944
881
|
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
945
|
-
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
946
|
-
</div>
|
|
947
|
-
<div data-tpl-if="!floating" data-tpl-remove="tag">
|
|
948
|
-
<label data-tpl-for="id" class="form-label">{{{{ slotted.default }}}}</label>
|
|
949
|
-
<div class="input-group has-validation">
|
|
950
|
-
<span data-tpl-if="slotted.ibefore" class="input-group-text">{{{{ slotted.ibefore }}}}</span>
|
|
951
|
-
<div data-tpl-if="slotted.before" data-tpl-remove="tag">{{{{ slotted.before }}}}</div>
|
|
952
|
-
{{{{ slotted.input }}}}
|
|
953
|
-
<div data-tpl-if="slotted.after" data-tpl-remove="tag">{{{{ slotted.after }}}}</div>
|
|
954
|
-
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
955
|
-
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
956
|
-
</div>
|
|
957
882
|
</div>
|
|
883
|
+
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
958
884
|
`, ful_input_ec);
|
|
959
885
|
|
|
960
|
-
|
|
961
|
-
|
|
962
886
|
class Input extends Templated(HTMLElement, ful_input_template_) {
|
|
963
887
|
render(slotted, template) {
|
|
964
|
-
const floating = this.hasAttribute('floating');
|
|
965
888
|
const input = slotted.input = slotted.input || (() => {
|
|
966
889
|
const el = document.createElement("input");
|
|
967
890
|
el.classList.add("form-control");
|
|
@@ -973,7 +896,7 @@ class Input extends Templated(HTMLElement, ful_input_template_) {
|
|
|
973
896
|
Attributes.defaultValue(slotted.input, "type", "text");
|
|
974
897
|
Attributes.defaultValue(slotted.input, "placeholder", " ");
|
|
975
898
|
const name = input.getAttribute('name');
|
|
976
|
-
return template.render({ id, name,
|
|
899
|
+
return template.render({ id, name, slotted });
|
|
977
900
|
}
|
|
978
901
|
static configure() {
|
|
979
902
|
customElements.define('ful-input', Input);
|
|
@@ -989,30 +912,16 @@ const ful_select_ec = globalThis.ec || ftl.EvaluationContext.configure({
|
|
|
989
912
|
});
|
|
990
913
|
|
|
991
914
|
const ful_select_template_ = globalThis.ful_select_template || ftl.Template.fromHtml(`
|
|
992
|
-
<
|
|
915
|
+
<label data-tpl-for="tsId" class="form-label">{{{{ slotted.default }}}}</label>
|
|
916
|
+
{{{{ input }}}}
|
|
917
|
+
<div class="input-group">
|
|
993
918
|
<span data-tpl-if="slotted.ibefore" class="input-group-text">{{{{ slotted.ibefore }}}}</span>
|
|
994
919
|
<div data-tpl-if="slotted.before" data-tpl-remove="tag">{{{{ slotted.before }}}}</div>
|
|
995
|
-
|
|
996
|
-
{{{{ slotted.input }}}}
|
|
997
|
-
{{{{ input }}}}
|
|
998
|
-
<label data-tpl-for="name" class="form-label">{{{{ slotted.default }}}}</label>
|
|
999
|
-
</div>
|
|
920
|
+
{{{{ slotted.input }}}}
|
|
1000
921
|
<div data-tpl-if="slotted.after" data-tpl-remove="tag">{{{{ slotted.after }}}}</div>
|
|
1001
922
|
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
1002
|
-
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
1003
|
-
</div>
|
|
1004
|
-
<div data-tpl-if="!floating" data-tpl-remove="tag">
|
|
1005
|
-
<label data-tpl-for="tsId" class="form-label">{{{{ slotted.default }}}}</label>
|
|
1006
|
-
{{{{ input }}}}
|
|
1007
|
-
<div class="input-group has-validation">
|
|
1008
|
-
<span data-tpl-if="slotted.ibefore" class="input-group-text">{{{{ slotted.ibefore }}}}</span>
|
|
1009
|
-
<div data-tpl-if="slotted.before" data-tpl-remove="tag">{{{{ slotted.before }}}}</div>
|
|
1010
|
-
{{{{ slotted.input }}}}
|
|
1011
|
-
<div data-tpl-if="slotted.after" data-tpl-remove="tag">{{{{ slotted.after }}}}</div>
|
|
1012
|
-
<span data-tpl-if="slotted.iafter" class="input-group-text">{{{{ slotted.iafter }}}}</span>
|
|
1013
|
-
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
1014
|
-
</div>
|
|
1015
923
|
</div>
|
|
924
|
+
<ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
|
|
1016
925
|
`, ful_select_ec);
|
|
1017
926
|
|
|
1018
927
|
|
|
@@ -1022,8 +931,6 @@ class Select extends Templated(HTMLElement, ful_select_template_) {
|
|
|
1022
931
|
this.tsConfig = tsConfig;
|
|
1023
932
|
}
|
|
1024
933
|
render(slotted, template) {
|
|
1025
|
-
const floating = this.hasAttribute('floating');
|
|
1026
|
-
|
|
1027
934
|
const type = this.getAttribute("type") || 'local';
|
|
1028
935
|
const remote = type != 'local';
|
|
1029
936
|
const loadOnce = this.getAttribute('load') != 'always';
|
|
@@ -1052,34 +959,42 @@ class Select extends Templated(HTMLElement, ful_select_template_) {
|
|
|
1052
959
|
}
|
|
1053
960
|
};
|
|
1054
961
|
|
|
962
|
+
|
|
963
|
+
this._remote = remote;
|
|
964
|
+
// we need to await this load in setValue when remote is configured and the option
|
|
965
|
+
// is not loaded yet.
|
|
966
|
+
// tomselect settings.load does not retun a promise as it wraps the configured load function
|
|
967
|
+
// with a debouncer
|
|
968
|
+
this._unwrappedRemoteLoad = async (query, callback) => {
|
|
969
|
+
|
|
970
|
+
if (!remote || remote && loadOnce && this.loaded) {
|
|
971
|
+
callback();
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const type = query && query.hasOwnProperty('byId') ? 'id' : 'query';
|
|
975
|
+
const qvalue = type === 'id' ? query.byId : query;
|
|
976
|
+
const data = await (this.loader ? this.loader(qvalue, type) : []);
|
|
977
|
+
if(type !== 'id'){
|
|
978
|
+
this.loaded = true;
|
|
979
|
+
}
|
|
980
|
+
callback(data);
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
|
|
1055
984
|
this.ts = new TomSelect(input, Object.assign(remote ? {
|
|
1056
985
|
preload: 'focus',
|
|
1057
|
-
load:
|
|
1058
|
-
|
|
1059
|
-
callback();
|
|
1060
|
-
return;
|
|
1061
|
-
}
|
|
1062
|
-
const data = await this.load(query);
|
|
1063
|
-
this.loaded = true;
|
|
1064
|
-
callback(data);
|
|
1065
|
-
},
|
|
1066
|
-
shouldLoad: (query) => this.shouldLoad(query)
|
|
986
|
+
load: this._unwrappedRemoteLoad,
|
|
987
|
+
shouldLoad: (query) => this.shouldLoad ? this.shouldLoad(query) : true
|
|
1067
988
|
} : {}, tsDefaultConfig, this.tsConfig));
|
|
1068
|
-
|
|
989
|
+
console.log("ts created");
|
|
1069
990
|
//we remove the input to move it
|
|
1070
991
|
input.remove();
|
|
1071
992
|
|
|
1072
|
-
return template.render({ id, tsId, name,
|
|
1073
|
-
}
|
|
1074
|
-
shouldLoad(q){
|
|
1075
|
-
return true;
|
|
1076
|
-
}
|
|
1077
|
-
load(q){
|
|
1078
|
-
return []
|
|
993
|
+
return template.render({ id, tsId, name, input, slotted });
|
|
1079
994
|
}
|
|
1080
995
|
async setValue(v) {
|
|
1081
|
-
if
|
|
1082
|
-
await this.ts.
|
|
996
|
+
if(this._remote){
|
|
997
|
+
await this._unwrappedRemoteLoad({byId: v}, this.ts.loadCallback.bind(this.ts));
|
|
1083
998
|
}
|
|
1084
999
|
this.ts.setValue(v);
|
|
1085
1000
|
}
|
|
@@ -1250,31 +1165,5 @@ class Wizard extends HTMLElement {
|
|
|
1250
1165
|
}
|
|
1251
1166
|
}
|
|
1252
1167
|
|
|
1253
|
-
|
|
1254
|
-
constructor() {
|
|
1255
|
-
this.configurers = [];
|
|
1256
|
-
this.initializers = [];
|
|
1257
|
-
this.handlers = [];
|
|
1258
|
-
this.running = false;
|
|
1259
|
-
document.addEventListener("DOMContentLoaded", async () => {
|
|
1260
|
-
await Promise.all(this.configurers);
|
|
1261
|
-
await Promise.all(this.initializers.map(h => Promise.resolve(h())));
|
|
1262
|
-
await Promise.all(this.handlers.map(h => Promise.resolve(h())));
|
|
1263
|
-
});
|
|
1264
|
-
}
|
|
1265
|
-
configure(cb) {
|
|
1266
|
-
this.configurers.push(Promise.resolve(cb()));
|
|
1267
|
-
return this;
|
|
1268
|
-
}
|
|
1269
|
-
initialize(cb) {
|
|
1270
|
-
this.initializers.push(cb);
|
|
1271
|
-
return this;
|
|
1272
|
-
}
|
|
1273
|
-
ready(cb) {
|
|
1274
|
-
this.handlers.push(cb);
|
|
1275
|
-
return this;
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
export { App, Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Errors, Failure, FieldError, Form, Fragments, Hex, HttpClient, Input, LocalStorage, Observable, RadioGroup, Select, SessionStorage, Slots, Spinner, Stateful, Templated, VersionedStorage, Wizard, jsonPatch, jsonPost, jsonPut, jsonRequest, timing };
|
|
1168
|
+
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Failure, Form, Fragments, Hex, HttpClient, Input, LocalStorage, RadioGroup, Select, SessionStorage, Slots, Spinner, Stateful, Templated, VersionedStorage, Wizard, jsonPatch, jsonPost, jsonPut, jsonRequest, timing };
|
|
1280
1169
|
//# sourceMappingURL=ful.mjs.map
|