@neeloong/form 0.25.0 → 0.27.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/index.d.mts +131 -44
- package/index.full.js +168 -57
- package/index.full.min.js +4 -4
- package/index.full.min.mjs +6 -6
- package/index.min.mjs +2 -2
- package/index.mjs +168 -57
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.27.0
|
|
3
3
|
* (c) 2024-2026 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -145,7 +145,8 @@ let ArrayStoreClass = null;
|
|
|
145
145
|
let TypeStores = Object.create(null);
|
|
146
146
|
/**
|
|
147
147
|
* @template [M=any]
|
|
148
|
-
* @
|
|
148
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
149
|
+
* @param {Schema.Field<M, S>} schema
|
|
149
150
|
* @param {object} [options]
|
|
150
151
|
* @param {Store?} [options.parent]
|
|
151
152
|
* @param {string | number | null} [options.index]
|
|
@@ -299,6 +300,7 @@ function makeDefault(store, def) {
|
|
|
299
300
|
* 管理单个表单字段的状态和行为
|
|
300
301
|
* @template [T=any]
|
|
301
302
|
* @template [M=any]
|
|
303
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
302
304
|
*/
|
|
303
305
|
class Store {
|
|
304
306
|
/** @type {Map<string, Set<(value: any, store: any) => void | boolean | null>>} */
|
|
@@ -341,7 +343,8 @@ class Store {
|
|
|
341
343
|
/**
|
|
342
344
|
* 从数据结构模式创建存储
|
|
343
345
|
* @template [M=any]
|
|
344
|
-
* @
|
|
346
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
347
|
+
* @param {Schema<M, S>} schema 数据结构模式
|
|
345
348
|
* @param {object} [options] 选项
|
|
346
349
|
* @param {boolean} [options.new] 是否为新建环境
|
|
347
350
|
*/
|
|
@@ -365,9 +368,10 @@ class Store {
|
|
|
365
368
|
#ref = null;
|
|
366
369
|
get ref() { return this.#ref || createRef(this); }
|
|
367
370
|
/**
|
|
368
|
-
* @param {Schema.Field<M>} schema 字段的 Schema 定义
|
|
371
|
+
* @param {Schema.Field<M, S>} schema 字段的 Schema 定义
|
|
369
372
|
* @param {object} [options] 可选配置
|
|
370
373
|
* @param {Store?} [options.parent]
|
|
374
|
+
* @param {Partial<S>?} [options.states]
|
|
371
375
|
* @param {((store: Store, value?: any) => any) | object | number | string | boolean | null | undefined} [options.default]
|
|
372
376
|
* @param {number | string | null} [options.index]
|
|
373
377
|
* @param {number | Signal.State<number> | Signal.Computed<number>} [options.size]
|
|
@@ -402,7 +406,7 @@ class Store {
|
|
|
402
406
|
*/
|
|
403
407
|
constructor(schema, {
|
|
404
408
|
null: isNull, ref, default: defaultValue,
|
|
405
|
-
setValue, convert, onUpdate,
|
|
409
|
+
setValue, convert, onUpdate, states,
|
|
406
410
|
validator, validators,
|
|
407
411
|
index, size, new: isNew, parent: parentNode,
|
|
408
412
|
hidden, clearable, required, disabled, readonly, removable,
|
|
@@ -480,6 +484,22 @@ class Store {
|
|
|
480
484
|
|
|
481
485
|
const validatorResult = createValidator(this, schema.validator, validator);
|
|
482
486
|
|
|
487
|
+
|
|
488
|
+
const schemaStates = schema.states;
|
|
489
|
+
this.#states = schemaStates ? Object.defineProperties(Object.create(null),
|
|
490
|
+
Object.fromEntries(
|
|
491
|
+
Object.entries(schemaStates).map(([k, { get, set, toState }]) => {
|
|
492
|
+
const state = new Signal.State(toState?.(states?.[k]));
|
|
493
|
+
const computed = new Signal.Computed(() => get(this, state));
|
|
494
|
+
return [k, {
|
|
495
|
+
configurable: true,
|
|
496
|
+
enumerable: true,
|
|
497
|
+
get() { return computed.get(); },
|
|
498
|
+
set(v) { return set?.(this, state, v); },
|
|
499
|
+
}];
|
|
500
|
+
})
|
|
501
|
+
)) : null;
|
|
502
|
+
|
|
483
503
|
const [changed, changedResult, cancelChange] = createAsyncValidator(this, schema.validators?.change, validators?.change);
|
|
484
504
|
const [blurred, blurredResult, cancelBlur] = createAsyncValidator(this, schema.validators?.blur, validators?.blur);
|
|
485
505
|
this.listen('change', () => { changed(); });
|
|
@@ -514,8 +534,11 @@ class Store {
|
|
|
514
534
|
this.listen(k, f);
|
|
515
535
|
}
|
|
516
536
|
}
|
|
537
|
+
/** @type {S?} */
|
|
538
|
+
#states;
|
|
539
|
+
get states() { return this.#states; }
|
|
517
540
|
/** @type {StoreLayout.Field<any>} */
|
|
518
|
-
#layout
|
|
541
|
+
#layout;
|
|
519
542
|
get layout() { return this.#layout; }
|
|
520
543
|
#createDefault;
|
|
521
544
|
/** @param {any} [value] @returns {any} */
|
|
@@ -691,9 +714,10 @@ class Store {
|
|
|
691
714
|
#selfMin;
|
|
692
715
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
693
716
|
#min;
|
|
717
|
+
/** @deprecated */
|
|
694
718
|
get selfMin() { return this.#selfMin.get(); }
|
|
695
719
|
set selfMin(v) { this.#selfMin.set(number(v)); }
|
|
696
|
-
/** 数值字段的最小值限制 */
|
|
720
|
+
/** @deprecated 数值字段的最小值限制 */
|
|
697
721
|
get min() { return this.#min.get(); }
|
|
698
722
|
set min(v) { this.#selfMin.set(number(v)); }
|
|
699
723
|
|
|
@@ -702,9 +726,10 @@ class Store {
|
|
|
702
726
|
#selfMax;
|
|
703
727
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
704
728
|
#max;
|
|
729
|
+
/** @deprecated */
|
|
705
730
|
get selfMax() { return this.#selfMax.get(); }
|
|
706
731
|
set selfMax(v) { this.#selfMax.set(number(v)); }
|
|
707
|
-
/** 数值字段的最大值限制 */
|
|
732
|
+
/** @deprecated 数值字段的最大值限制 */
|
|
708
733
|
get max() { return this.#max.get(); }
|
|
709
734
|
set max(v) { this.#selfMax.set(number(v)); }
|
|
710
735
|
|
|
@@ -713,9 +738,10 @@ class Store {
|
|
|
713
738
|
#selfStep;
|
|
714
739
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
715
740
|
#step;
|
|
741
|
+
/** @deprecated */
|
|
716
742
|
get selfStep() { return this.#selfStep.get(); }
|
|
717
743
|
set selfStep(v) { this.#selfStep.set(number(v)); }
|
|
718
|
-
/** 数值字段的步长 */
|
|
744
|
+
/** @deprecated 数值字段的步长 */
|
|
719
745
|
get step() { return this.#step.get(); }
|
|
720
746
|
set step(v) { this.#selfStep.set(number(v)); }
|
|
721
747
|
|
|
@@ -723,9 +749,10 @@ class Store {
|
|
|
723
749
|
#selfMinLength;
|
|
724
750
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
725
751
|
#minLength;
|
|
752
|
+
/** @deprecated */
|
|
726
753
|
get selfMinLength() { return this.#selfMinLength.get(); }
|
|
727
754
|
set selfMinLength(v) { this.#selfMinLength.set(number(v)); }
|
|
728
|
-
/** 最小长度 */
|
|
755
|
+
/** @deprecated 最小长度 */
|
|
729
756
|
get minLength() { return this.#minLength.get(); }
|
|
730
757
|
set minLength(v) { this.#selfMinLength.set(number(v)); }
|
|
731
758
|
|
|
@@ -733,9 +760,10 @@ class Store {
|
|
|
733
760
|
#selfMaxLength;
|
|
734
761
|
/** @readonly @type {Signal.Computed<number?>} */
|
|
735
762
|
#maxLength;
|
|
763
|
+
/** @deprecated */
|
|
736
764
|
get selfMaxLength() { return this.#selfMaxLength.get(); }
|
|
737
765
|
set selfMaxLength(v) { this.#selfMaxLength.set(number(v)); }
|
|
738
|
-
/** 最大长度 */
|
|
766
|
+
/** @deprecated 最大长度 */
|
|
739
767
|
get maxLength() { return this.#maxLength.get(); }
|
|
740
768
|
set maxLength(v) { this.#selfMaxLength.set(number(v)); }
|
|
741
769
|
|
|
@@ -743,9 +771,10 @@ class Store {
|
|
|
743
771
|
#selfPattern;
|
|
744
772
|
/** @readonly @type {Signal.Computed<RegExp?>} */
|
|
745
773
|
#pattern;
|
|
774
|
+
/** @deprecated */
|
|
746
775
|
get selfPattern() { return this.#selfPattern.get(); }
|
|
747
776
|
set selfPattern(v) { this.#selfPattern.set(regex(v)); }
|
|
748
|
-
/** 模式 */
|
|
777
|
+
/** @deprecated 模式 */
|
|
749
778
|
get pattern() { return this.#pattern.get(); }
|
|
750
779
|
set pattern(v) { this.#selfPattern.set(regex(v)); }
|
|
751
780
|
|
|
@@ -754,9 +783,10 @@ class Store {
|
|
|
754
783
|
#selfValues;
|
|
755
784
|
/** @readonly @type {Signal.Computed<(Schema.Value.Group | Schema.Value)[] | null>} */
|
|
756
785
|
#values;
|
|
786
|
+
/** @deprecated */
|
|
757
787
|
get selfValues() { return this.#selfValues.get(); }
|
|
758
788
|
set selfValues(v) { this.#selfValues.set(values(v)); }
|
|
759
|
-
/** 可选值列表 */
|
|
789
|
+
/** @deprecated 可选值列表 */
|
|
760
790
|
get values() { return this.#values.get(); }
|
|
761
791
|
set values(v) { this.#selfValues.set(values(v)); }
|
|
762
792
|
|
|
@@ -791,6 +821,40 @@ class Store {
|
|
|
791
821
|
#initValue = new Signal.State(/** @type {T?} */(null));
|
|
792
822
|
#value = new Signal.State(this.#initValue.get());
|
|
793
823
|
|
|
824
|
+
/**
|
|
825
|
+
* @template [M=any]
|
|
826
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
827
|
+
* @param {Schema<M, S>} schema 数据结构模式
|
|
828
|
+
*/
|
|
829
|
+
bindObject(schema) {
|
|
830
|
+
const bindStores = this.#bindStores;
|
|
831
|
+
/** @type {Store[]} */
|
|
832
|
+
const list = [];
|
|
833
|
+
for (const [index, field] of Object.entries(schema)) {
|
|
834
|
+
const bindStore = create(field, {
|
|
835
|
+
index, parent: this,
|
|
836
|
+
/** @param {*} value @param {*} currentIndex @param {Store} store */
|
|
837
|
+
onUpdate: (value, currentIndex, store) => {
|
|
838
|
+
if (index !== currentIndex) { return; }
|
|
839
|
+
if (bindStores.has(store)) { return; }
|
|
840
|
+
const val = this.#value ?? null;
|
|
841
|
+
if (typeof val !== 'object' || Array.isArray(val)) { return }
|
|
842
|
+
// @ts-ignore
|
|
843
|
+
this.value = { ...val, [currentIndex]: value };
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
list.push(bindStore);
|
|
847
|
+
bindStores.set(bindStore, index);
|
|
848
|
+
}
|
|
849
|
+
this.#requestUpdate();
|
|
850
|
+
return () => {
|
|
851
|
+
for (const bindStore of list) {
|
|
852
|
+
bindStores.delete(bindStore);
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
/** @type {Map<Store, string>} */
|
|
857
|
+
#bindStores = new Map();
|
|
794
858
|
|
|
795
859
|
/** 内容是否已改变 */
|
|
796
860
|
get changed() { return !Object.is(this.#value.get(), this.#initValue.get()); }
|
|
@@ -837,6 +901,9 @@ class Store {
|
|
|
837
901
|
for (const [, field] of this) {
|
|
838
902
|
field.#reset(null, false);
|
|
839
903
|
}
|
|
904
|
+
for (const [field] of this.#bindStores) {
|
|
905
|
+
field.#reset(null, false);
|
|
906
|
+
}
|
|
840
907
|
this.#value.set(value);
|
|
841
908
|
this.#initValue.set(value);
|
|
842
909
|
this.#onUpdate?.(value, this.#index.get(), this);
|
|
@@ -847,6 +914,9 @@ class Store {
|
|
|
847
914
|
for (const [key, field] of this) {
|
|
848
915
|
newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
|
|
849
916
|
}
|
|
917
|
+
for (const [field, key] of this.#bindStores) {
|
|
918
|
+
newValues[key] = field.#reset(Object.hasOwn(newValues, key) ? newValues[key] : undefined, false);
|
|
919
|
+
}
|
|
850
920
|
this.#value.set(newValues);
|
|
851
921
|
this.#initValue.set(newValues);
|
|
852
922
|
this.#onUpdate?.(newValues, this.#index.get(), this);
|
|
@@ -888,6 +958,15 @@ class Store {
|
|
|
888
958
|
newValues[key] = newData;
|
|
889
959
|
updated = true;
|
|
890
960
|
}
|
|
961
|
+
for (const [field, key] of this.#bindStores) {
|
|
962
|
+
// @ts-ignore
|
|
963
|
+
const data = Object.hasOwn(val, key) ? val[key] : undefined;
|
|
964
|
+
const newData = field.#toUpdate(data);
|
|
965
|
+
if (Object.is(data, newData)) { continue; }
|
|
966
|
+
// @ts-ignore
|
|
967
|
+
newValues[key] = newData;
|
|
968
|
+
updated = true;
|
|
969
|
+
}
|
|
891
970
|
if (updated) {
|
|
892
971
|
val = newValues;
|
|
893
972
|
initValue = val;
|
|
@@ -935,6 +1014,9 @@ class Store {
|
|
|
935
1014
|
for (const [key, field] of this) {
|
|
936
1015
|
list.push(field.validate([...selfPath, key]));
|
|
937
1016
|
}
|
|
1017
|
+
for (const [field, key] of this.#bindStores) {
|
|
1018
|
+
list.push(field.validate([...selfPath, key]));
|
|
1019
|
+
}
|
|
938
1020
|
return Promise.all(list).then(v => v.flat());
|
|
939
1021
|
}
|
|
940
1022
|
}
|
|
@@ -944,7 +1026,8 @@ class Store {
|
|
|
944
1026
|
/**
|
|
945
1027
|
* @template {Record<string, any>} [T=Record<string, any>]
|
|
946
1028
|
* @template [M=any]
|
|
947
|
-
* @
|
|
1029
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1030
|
+
* @extends {Store<T, M, S>}
|
|
948
1031
|
*/
|
|
949
1032
|
class ObjectStore extends Store {
|
|
950
1033
|
get kind() { return 'object'; }
|
|
@@ -958,7 +1041,7 @@ class ObjectStore extends Store {
|
|
|
958
1041
|
*/
|
|
959
1042
|
child(key) { return this.#children[key] || null; }
|
|
960
1043
|
/**
|
|
961
|
-
* @param {Schema.Object<M> & Schema.Attr<M>} schema
|
|
1044
|
+
* @param {Schema.Object<M, S> & Schema.Attr<M, S>} schema
|
|
962
1045
|
* @param {object} [options]
|
|
963
1046
|
* @param {Store?} [options.parent]
|
|
964
1047
|
* @param {number | string | null} [options.index]
|
|
@@ -1010,7 +1093,8 @@ setObjectStore(ObjectStore);
|
|
|
1010
1093
|
/**
|
|
1011
1094
|
* @template [T=any]
|
|
1012
1095
|
* @template [M=any]
|
|
1013
|
-
* @
|
|
1096
|
+
* @template {Object.<string, Schema.State>} [S=Object.<string, Schema.State>]
|
|
1097
|
+
* @extends {Store<(T | null)[], M, S>}
|
|
1014
1098
|
*/
|
|
1015
1099
|
class ArrayStore extends Store {
|
|
1016
1100
|
/** @type {(index: number, isNew?: boolean) => Store} */
|
|
@@ -1033,7 +1117,7 @@ class ArrayStore extends Store {
|
|
|
1033
1117
|
}
|
|
1034
1118
|
get kind() { return 'array'; }
|
|
1035
1119
|
/**
|
|
1036
|
-
* @param {Schema.Field<M>} schema
|
|
1120
|
+
* @param {Schema.Field<M, S>} schema
|
|
1037
1121
|
* @param {object} [options]
|
|
1038
1122
|
* @param {Store?} [options.parent]
|
|
1039
1123
|
* @param {string | number | null} [options.index]
|
|
@@ -1102,6 +1186,8 @@ class ArrayStore extends Store {
|
|
|
1102
1186
|
return child;
|
|
1103
1187
|
};
|
|
1104
1188
|
}
|
|
1189
|
+
/** @returns {never} */
|
|
1190
|
+
bindObject() { throw new Error(`ArrayStore 不支持 bindObject()方法`); }
|
|
1105
1191
|
|
|
1106
1192
|
|
|
1107
1193
|
/** @readonly @type {Signal.State<boolean?>} */
|
|
@@ -4219,7 +4305,7 @@ function renderObject(parent, next, store, env, renderItem, sort) {
|
|
|
4219
4305
|
const children = [];
|
|
4220
4306
|
const childStores = [...store];
|
|
4221
4307
|
const count = childStores.length;
|
|
4222
|
-
/** @type {[string, Store<any, any>, number][]} */
|
|
4308
|
+
/** @type {[string, Store<any, any, any>, number][]} */
|
|
4223
4309
|
const stores = sort
|
|
4224
4310
|
? childStores
|
|
4225
4311
|
.map(([k,v]) => [k,v,env.setStore(v, store).exec(sort)])
|
|
@@ -4766,7 +4852,7 @@ function createFieldFilter(field) {
|
|
|
4766
4852
|
* @param {StoreLayout.Options?} options
|
|
4767
4853
|
* @param {StoreLayout<T>} layout
|
|
4768
4854
|
* @param {Node} [anchor]
|
|
4769
|
-
* @param {(child?: Store<any, any> | undefined) => void} [dragenter]
|
|
4855
|
+
* @param {(child?: Store<any, any, any> | undefined) => void} [dragenter]
|
|
4770
4856
|
* @returns {void}
|
|
4771
4857
|
*/
|
|
4772
4858
|
function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragenter) {
|
|
@@ -4777,29 +4863,53 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4777
4863
|
if (tagName === 'nl-form-field') {
|
|
4778
4864
|
const field = node.getAttribute('name') || '';
|
|
4779
4865
|
const mode = node.getAttribute('mode') || '';
|
|
4866
|
+
const renderer = node.getAttribute('renderer') || '';
|
|
4867
|
+
const editable = options?.editable && !node.hasAttribute('non-editable');
|
|
4780
4868
|
const fieldStore = field ? store.child(field) : store;
|
|
4781
4869
|
if (!fieldStore) { return; }
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
: { ...layout, html: '' };
|
|
4870
|
+
/** @type {HTMLElement?} */
|
|
4871
|
+
let el = null;
|
|
4785
4872
|
switch (mode) {
|
|
4786
4873
|
case 'grid': {
|
|
4787
|
-
const
|
|
4788
|
-
|
|
4789
|
-
|
|
4874
|
+
const fieldLayout = field
|
|
4875
|
+
? layout?.fields?.find(createFieldFilter(field)) || fieldStore.layout
|
|
4876
|
+
: { ...layout, html: '' };
|
|
4877
|
+
el = Form(fieldStore, fieldRenderer, fieldLayout, {...options, editable});
|
|
4878
|
+
break;
|
|
4879
|
+
}
|
|
4880
|
+
default: {
|
|
4881
|
+
el = fieldRenderer(fieldStore, renderer || layout.renderer, {...options, editable});
|
|
4882
|
+
break;
|
|
4790
4883
|
}
|
|
4791
4884
|
}
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
node.replaceWith(
|
|
4885
|
+
if (!el) {
|
|
4886
|
+
const value = node.getAttribute('placeholder') || '';
|
|
4887
|
+
node.replaceWith(document.createTextNode(value));
|
|
4795
4888
|
return;
|
|
4796
4889
|
}
|
|
4797
|
-
const
|
|
4798
|
-
|
|
4890
|
+
const className = node.getAttribute('class') || '';
|
|
4891
|
+
if (className) {
|
|
4892
|
+
el.setAttribute('class', [
|
|
4893
|
+
el.getAttribute('class') || '',
|
|
4894
|
+
className,
|
|
4895
|
+
].filter(Boolean).join(' '));
|
|
4896
|
+
}
|
|
4897
|
+
const style = node.getAttribute('style') || '';
|
|
4898
|
+
if (style) {
|
|
4899
|
+
el.setAttribute('style', [
|
|
4900
|
+
el.getAttribute('style') || '',
|
|
4901
|
+
style,
|
|
4902
|
+
].filter(Boolean).join(' '));
|
|
4903
|
+
}
|
|
4904
|
+
node.replaceWith(el);
|
|
4799
4905
|
return;
|
|
4800
4906
|
}
|
|
4801
4907
|
if (tagName === 'nl-form-button') {
|
|
4802
4908
|
const button = document.createElement('button');
|
|
4909
|
+
const className = node.getAttribute('class') || '';
|
|
4910
|
+
const style = node.getAttribute('style') || '';
|
|
4911
|
+
if (className) { button.setAttribute('class', className); }
|
|
4912
|
+
if (style) { button.setAttribute('style', style); }
|
|
4803
4913
|
button.classList.add('NeeloongForm-item-button');
|
|
4804
4914
|
const click = node.getAttribute('click') || '';
|
|
4805
4915
|
const call = options?.call;
|
|
@@ -4970,9 +5080,10 @@ function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragent
|
|
|
4970
5080
|
/**
|
|
4971
5081
|
*
|
|
4972
5082
|
* @param {string | ParentNode | null} [html]
|
|
5083
|
+
* @param {function(string): string} [sanitize]
|
|
4973
5084
|
* @returns {ParentNode}
|
|
4974
5085
|
*/
|
|
4975
|
-
function getHtmlContent(html) {
|
|
5086
|
+
function getHtmlContent(html, sanitize) {
|
|
4976
5087
|
if (!html) {
|
|
4977
5088
|
return document.createElement('template').content;
|
|
4978
5089
|
}
|
|
@@ -4980,14 +5091,14 @@ function getHtmlContent(html) {
|
|
|
4980
5091
|
return /** @type {ParentNode} */(html.cloneNode(true));
|
|
4981
5092
|
}
|
|
4982
5093
|
const template = document.createElement('template');
|
|
4983
|
-
template.innerHTML = html;
|
|
5094
|
+
template.innerHTML = sanitize ? sanitize(html) : html;
|
|
4984
5095
|
return template.content;
|
|
4985
5096
|
}
|
|
4986
5097
|
|
|
4987
5098
|
/**
|
|
4988
5099
|
*
|
|
4989
5100
|
* @template T
|
|
4990
|
-
* @param {Store<any, any>} store
|
|
5101
|
+
* @param {Store<any, any, any>} store
|
|
4991
5102
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
4992
5103
|
* @param {StoreLayout<T>} layout
|
|
4993
5104
|
* @param {StoreLayout.Options?} options
|
|
@@ -4997,7 +5108,7 @@ function FormFieldInline(store, fieldRenderer, layout, options) {
|
|
|
4997
5108
|
if (options?.signal?.aborted) { return null; }
|
|
4998
5109
|
const html = layout.html;
|
|
4999
5110
|
if (html) {
|
|
5000
|
-
const content = getHtmlContent(html);
|
|
5111
|
+
const content = getHtmlContent(html, options?.sanitizeHtml);
|
|
5001
5112
|
renderHtml(store, fieldRenderer, content, options, layout);
|
|
5002
5113
|
return content;
|
|
5003
5114
|
}
|
|
@@ -5010,7 +5121,7 @@ function FormFieldInline(store, fieldRenderer, layout, options) {
|
|
|
5010
5121
|
/**
|
|
5011
5122
|
*
|
|
5012
5123
|
* @template T
|
|
5013
|
-
* @param {Store<any, any>} store
|
|
5124
|
+
* @param {Store<any, any, any>} store
|
|
5014
5125
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5015
5126
|
* @param {StoreLayout.Field<T>} layout
|
|
5016
5127
|
* @param {object} option
|
|
@@ -5089,12 +5200,12 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5089
5200
|
}
|
|
5090
5201
|
|
|
5091
5202
|
for (const column of columns) {
|
|
5092
|
-
const { actions, field, pattern } = column;
|
|
5203
|
+
const { actions, field, pattern, editable } = column;
|
|
5093
5204
|
if (!actions?.length) {
|
|
5094
5205
|
const td = head.appendChild(document.createElement('td'));
|
|
5095
5206
|
const child = field && store.child(field);
|
|
5096
5207
|
if (child) {
|
|
5097
|
-
const el = FormFieldInline(child, fieldRenderer, column, options);
|
|
5208
|
+
const el = FormFieldInline(child, fieldRenderer, column, {...options, editable: options?.editable && (editable !== false)});
|
|
5098
5209
|
if (el) { td.appendChild(el); }
|
|
5099
5210
|
}
|
|
5100
5211
|
continue;
|
|
@@ -5151,7 +5262,7 @@ function Line(store, fieldRenderer, layout, {
|
|
|
5151
5262
|
* @param {ArrayStore} store
|
|
5152
5263
|
* @param {StoreLayout.Field<T>} layout
|
|
5153
5264
|
* @param {StoreLayout.Action[]} actionOptions
|
|
5154
|
-
* @param {(fields: { field: string; width: any; label: any; }[]) => StoreLayout.Column<T>[]} createDefault
|
|
5265
|
+
* @param {(fields: { field: string; width: any; label: any; editable?: boolean? }[]) => StoreLayout.Column<T>[]} createDefault
|
|
5155
5266
|
* @returns {StoreLayout.Column<T>[]}
|
|
5156
5267
|
*/
|
|
5157
5268
|
function getColumns(store, layout, actionOptions, createDefault) {
|
|
@@ -5174,23 +5285,23 @@ function getColumns(store, layout, actionOptions, createDefault) {
|
|
|
5174
5285
|
if (!actions) { return null; }
|
|
5175
5286
|
return { actions };
|
|
5176
5287
|
}
|
|
5177
|
-
const { action, actions, field, placeholder, pattern, width, label } = v;
|
|
5288
|
+
const { action, actions, field, placeholder, pattern, width, label, editable } = v;
|
|
5178
5289
|
if (field) {
|
|
5179
5290
|
const define = map.get(field);
|
|
5180
5291
|
if (define) {
|
|
5181
|
-
return { field, placeholder, width, label: label || define.label };
|
|
5292
|
+
return { field, placeholder, width, label: label || define.label, editable };
|
|
5182
5293
|
}
|
|
5183
5294
|
}
|
|
5184
5295
|
const options = new Set(actionOptions);
|
|
5185
5296
|
const allActions = [action, actions].flat().filter(v => v && options.delete(v));
|
|
5186
5297
|
if (allActions.length) {
|
|
5187
|
-
return { actions: /** @type {StoreLayout.Action[]} */(allActions), width, label };
|
|
5298
|
+
return { actions: /** @type {StoreLayout.Action[]} */(allActions), width, label, editable };
|
|
5188
5299
|
}
|
|
5189
5300
|
if (pattern) {
|
|
5190
|
-
return { pattern, placeholder, width, label };
|
|
5301
|
+
return { pattern, placeholder, width, label, editable };
|
|
5191
5302
|
}
|
|
5192
5303
|
if (placeholder || width) {
|
|
5193
|
-
return { placeholder, width, label };
|
|
5304
|
+
return { placeholder, width, label, editable };
|
|
5194
5305
|
}
|
|
5195
5306
|
return null;
|
|
5196
5307
|
});
|
|
@@ -5495,8 +5606,8 @@ function createCell(signal, layout, values, defCell, blockOnly) {
|
|
|
5495
5606
|
/**
|
|
5496
5607
|
*
|
|
5497
5608
|
* @template T
|
|
5498
|
-
* @param {Store<any, any>} store
|
|
5499
|
-
* @param {Signal.State<Store<any, any>?>} currentStore
|
|
5609
|
+
* @param {Store<any, any, any>} store
|
|
5610
|
+
* @param {Signal.State<Store<any, any, any>?>} currentStore
|
|
5500
5611
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5501
5612
|
* @param {StoreLayout.Field<T>} layout
|
|
5502
5613
|
* @param {Signal.State<State>} state
|
|
@@ -5510,7 +5621,7 @@ function createCell(signal, layout, values, defCell, blockOnly) {
|
|
|
5510
5621
|
* @param {() => void} option.dragend
|
|
5511
5622
|
* @param {{get(): boolean}} option.deletable
|
|
5512
5623
|
* @param {() => void} option.addNode
|
|
5513
|
-
* @param {(store: Store<any, any>) => () => void} option.createDetails
|
|
5624
|
+
* @param {(store: Store<any, any, any>) => () => void} option.createDetails
|
|
5514
5625
|
* @param {StoreLayout.Options?} options
|
|
5515
5626
|
* @returns {HTMLElement}
|
|
5516
5627
|
*/
|
|
@@ -5912,10 +6023,10 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
5912
6023
|
|
|
5913
6024
|
/** @type {AbortController?} */
|
|
5914
6025
|
let detailAbortController = null;
|
|
5915
|
-
const detailsStore = new Signal.State(/** @type{Store<any, any>?}*/(null));
|
|
6026
|
+
const detailsStore = new Signal.State(/** @type{Store<any, any, any>?}*/(null));
|
|
5916
6027
|
/**
|
|
5917
6028
|
*
|
|
5918
|
-
* @param {Store<any, any>} store
|
|
6029
|
+
* @param {Store<any, any, any>} store
|
|
5919
6030
|
* @returns
|
|
5920
6031
|
*/
|
|
5921
6032
|
function createDetails(store) {
|
|
@@ -6167,14 +6278,14 @@ function Tree(store, fieldRenderer, layout, options) {
|
|
|
6167
6278
|
*
|
|
6168
6279
|
* @template T
|
|
6169
6280
|
* @param {string | ParentNode} html
|
|
6170
|
-
* @param {Store<any, any>} store
|
|
6281
|
+
* @param {Store<any, any, any>} store
|
|
6171
6282
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6172
6283
|
* @param {StoreLayout.Options?} options
|
|
6173
6284
|
* @param {StoreLayout.Field<T>} layout
|
|
6174
6285
|
* @returns {ParentNode}
|
|
6175
6286
|
*/
|
|
6176
6287
|
function Html(html, store, fieldRenderer, options, layout) {
|
|
6177
|
-
const htmlContent = getHtmlContent(html);
|
|
6288
|
+
const htmlContent = getHtmlContent(html, options?.sanitizeHtml);
|
|
6178
6289
|
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6179
6290
|
return htmlContent;
|
|
6180
6291
|
}
|
|
@@ -6199,7 +6310,7 @@ function renderArrayCell(arrayStyle, store, fieldRenderer, layout, options) {
|
|
|
6199
6310
|
/**
|
|
6200
6311
|
*
|
|
6201
6312
|
* @template T
|
|
6202
|
-
* @param {Store<any, any>} store
|
|
6313
|
+
* @param {Store<any, any, any>} store
|
|
6203
6314
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6204
6315
|
* @param {StoreLayout.Field<T>} layout
|
|
6205
6316
|
* @param {StoreLayout.Options?} options
|
|
@@ -6233,7 +6344,7 @@ function FormField(store, fieldRenderer, layout, options) {
|
|
|
6233
6344
|
|
|
6234
6345
|
/**
|
|
6235
6346
|
*
|
|
6236
|
-
* @param {Store<any, any>} store
|
|
6347
|
+
* @param {Store<any, any, any>} store
|
|
6237
6348
|
* @param {StoreLayout.Button} layout
|
|
6238
6349
|
* @param {StoreLayout.Options?} options
|
|
6239
6350
|
* @returns {ParentNode}
|
|
@@ -6271,7 +6382,7 @@ function FormButton(store, layout, options) {
|
|
|
6271
6382
|
/**
|
|
6272
6383
|
*
|
|
6273
6384
|
* @template T
|
|
6274
|
-
* @param {Store<any, any>} store
|
|
6385
|
+
* @param {Store<any, any, any>} store
|
|
6275
6386
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6276
6387
|
* @param {StoreLayout.Html} layout
|
|
6277
6388
|
* @param {StoreLayout.Options?} options
|
|
@@ -6281,7 +6392,7 @@ function FormHtml(store, fieldRenderer, layout, options) {
|
|
|
6281
6392
|
const html = layout.html;
|
|
6282
6393
|
if (!html) { return null; }
|
|
6283
6394
|
const [root, content] = createCell(options?.signal, layout, store);
|
|
6284
|
-
const htmlContent = getHtmlContent(html);
|
|
6395
|
+
const htmlContent = getHtmlContent(html, options?.sanitizeHtml);
|
|
6285
6396
|
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6286
6397
|
content.appendChild(htmlContent);
|
|
6287
6398
|
return root;
|
|
@@ -6293,7 +6404,7 @@ function FormHtml(store, fieldRenderer, layout, options) {
|
|
|
6293
6404
|
/**
|
|
6294
6405
|
*
|
|
6295
6406
|
* @template T
|
|
6296
|
-
* @param {Store<any, any>} store
|
|
6407
|
+
* @param {Store<any, any, any>} store
|
|
6297
6408
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6298
6409
|
* @param {StoreLayout.Item<T>} item
|
|
6299
6410
|
* @param {StoreLayout.Options?} options
|
|
@@ -6318,7 +6429,7 @@ function FormItem(store, fieldRenderer, item, options) {
|
|
|
6318
6429
|
/**
|
|
6319
6430
|
*
|
|
6320
6431
|
* @template T
|
|
6321
|
-
* @param {Store<any, any>} store
|
|
6432
|
+
* @param {Store<any, any, any>} store
|
|
6322
6433
|
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6323
6434
|
* @param {StoreLayout<T>} layout
|
|
6324
6435
|
* @param {StoreLayout.Options?} options
|
|
@@ -6367,7 +6478,7 @@ function renderStore(store, fieldRenderer, root, layout, options) {
|
|
|
6367
6478
|
Form(store, fieldRenderer, storeLayout, options || null, root);
|
|
6368
6479
|
return;
|
|
6369
6480
|
}
|
|
6370
|
-
const content = getHtmlContent(html);
|
|
6481
|
+
const content = getHtmlContent(html, options?.sanitizeHtml);
|
|
6371
6482
|
renderHtml(store, fieldRenderer, content, options || null, storeLayout);
|
|
6372
6483
|
root.appendChild(content);
|
|
6373
6484
|
options?.signal?.addEventListener('abort', () => {
|