@neeloong/form 0.22.0 → 0.23.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 +60 -13
- package/index.full.js +389 -454
- package/index.full.min.js +5 -5
- package/index.full.min.mjs +7 -7
- package/index.min.mjs +2 -2
- package/index.mjs +389 -454
- package/package.json +1 -1
package/index.full.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @neeloong/form v0.
|
|
2
|
+
* @neeloong/form v0.23.0
|
|
3
3
|
* (c) 2024-2026 Fierflame
|
|
4
4
|
* @license Apache-2.0
|
|
5
5
|
*/
|
|
@@ -2892,13 +2892,36 @@
|
|
|
2892
2892
|
|
|
2893
2893
|
/**
|
|
2894
2894
|
* 相应式执行
|
|
2895
|
+
* @overload
|
|
2895
2896
|
* @param {() => void} fn 执行函数
|
|
2897
|
+
* @param {null} [signal]
|
|
2896
2898
|
* @returns {() => void} 取消函数
|
|
2897
2899
|
*/
|
|
2898
|
-
|
|
2900
|
+
/**
|
|
2901
|
+
* 相应式执行
|
|
2902
|
+
* @overload
|
|
2903
|
+
* @param {() => void} fn 执行函数
|
|
2904
|
+
* @param {AbortSignal} signal
|
|
2905
|
+
* @returns {void} 取消函数
|
|
2906
|
+
*/
|
|
2907
|
+
/**
|
|
2908
|
+
* 相应式执行
|
|
2909
|
+
* @overload
|
|
2910
|
+
* @param {() => void} fn 执行函数
|
|
2911
|
+
* @param {AbortSignal?} [signal]
|
|
2912
|
+
* @returns {(() => void) | void} 取消函数
|
|
2913
|
+
*/
|
|
2914
|
+
/**
|
|
2915
|
+
* 相应式执行
|
|
2916
|
+
* @param {() => void} fn 执行函数
|
|
2917
|
+
* @param {AbortSignal?} [signal]
|
|
2918
|
+
* @returns {(() => void) | void} 取消函数
|
|
2919
|
+
*/
|
|
2920
|
+
function effect(fn, signal) {
|
|
2921
|
+
if (signal?.aborted) { return; }
|
|
2899
2922
|
let needsEnqueue = true;
|
|
2900
2923
|
const w = new exports.Signal.subtle.Watcher(() => {
|
|
2901
|
-
if (!needsEnqueue) { return }
|
|
2924
|
+
if (!needsEnqueue) { return; }
|
|
2902
2925
|
needsEnqueue = false;
|
|
2903
2926
|
queueMicrotask(() => {
|
|
2904
2927
|
needsEnqueue = true;
|
|
@@ -2912,19 +2935,54 @@
|
|
|
2912
2935
|
|
|
2913
2936
|
w.watch(computed);
|
|
2914
2937
|
computed.get();
|
|
2938
|
+
if (!signal) { return () => { w.unwatch(computed); }; }
|
|
2939
|
+
signal.addEventListener('abort', () => {
|
|
2940
|
+
w.unwatch(computed);
|
|
2941
|
+
}, { once: true });
|
|
2915
2942
|
|
|
2916
|
-
return () => { w.unwatch(computed); };
|
|
2917
2943
|
}
|
|
2918
2944
|
|
|
2919
2945
|
/**
|
|
2920
2946
|
* 创建可赋值计算值
|
|
2921
2947
|
* @template T
|
|
2948
|
+
* @overload
|
|
2922
2949
|
* @param {() => T} getter 取值方法
|
|
2923
2950
|
* @param {(value: T) => void} callback 取值方法
|
|
2924
2951
|
* @param {boolean} immediate 是否立即执行一次
|
|
2952
|
+
* @param {null} [signal]
|
|
2925
2953
|
* @returns {() => void}
|
|
2926
2954
|
*/
|
|
2927
|
-
|
|
2955
|
+
|
|
2956
|
+
/**
|
|
2957
|
+
* 创建可赋值计算值
|
|
2958
|
+
* @template T
|
|
2959
|
+
* @overload
|
|
2960
|
+
* @param {() => T} getter 取值方法
|
|
2961
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2962
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2963
|
+
* @param {AbortSignal?} [signal]
|
|
2964
|
+
* @returns {(() => void) | void}
|
|
2965
|
+
*/
|
|
2966
|
+
/**
|
|
2967
|
+
* 创建可赋值计算值
|
|
2968
|
+
* @template T
|
|
2969
|
+
* @overload
|
|
2970
|
+
* @param {() => T} getter 取值方法
|
|
2971
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2972
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2973
|
+
* @param {AbortSignal} signal
|
|
2974
|
+
* @returns {void}
|
|
2975
|
+
*/
|
|
2976
|
+
/**
|
|
2977
|
+
* 创建可赋值计算值
|
|
2978
|
+
* @template T
|
|
2979
|
+
* @param {() => T} getter 取值方法
|
|
2980
|
+
* @param {(value: T) => void} callback 取值方法
|
|
2981
|
+
* @param {boolean} immediate 是否立即执行一次
|
|
2982
|
+
* @param {AbortSignal?} [signal]
|
|
2983
|
+
* @returns {(() => void) | void}
|
|
2984
|
+
*/
|
|
2985
|
+
function watch(getter, callback, immediate, signal) {
|
|
2928
2986
|
let run = false;
|
|
2929
2987
|
/** @type {any} */
|
|
2930
2988
|
let value;
|
|
@@ -2939,7 +2997,7 @@
|
|
|
2939
2997
|
if (Object.is(val, value)) { return; }
|
|
2940
2998
|
value = val;
|
|
2941
2999
|
callback(val);
|
|
2942
|
-
});
|
|
3000
|
+
}, signal);
|
|
2943
3001
|
}
|
|
2944
3002
|
|
|
2945
3003
|
const bindable = {
|
|
@@ -5251,67 +5309,65 @@
|
|
|
5251
5309
|
/** @import { Store } from '../Store/index.mjs' */
|
|
5252
5310
|
/** @import { StoreLayout } from '../types.mjs' */
|
|
5253
5311
|
|
|
5254
|
-
|
|
5255
5312
|
/**
|
|
5256
5313
|
*
|
|
5314
|
+
* @template T
|
|
5257
5315
|
* @param {string} field
|
|
5316
|
+
* @returns {(v: StoreLayout.Item<T>) => v is StoreLayout.Field<T>}
|
|
5258
5317
|
*/
|
|
5259
5318
|
function createFieldFilter(field) {
|
|
5260
|
-
|
|
5261
5319
|
/**
|
|
5262
5320
|
*
|
|
5263
|
-
* @param {StoreLayout.Item} v
|
|
5264
|
-
* @returns {v is StoreLayout.Field}
|
|
5321
|
+
* @param {StoreLayout.Item<T>} v
|
|
5322
|
+
* @returns {v is StoreLayout.Field<T>}
|
|
5265
5323
|
*/
|
|
5266
|
-
|
|
5267
|
-
return function (v) {
|
|
5324
|
+
return v => {
|
|
5268
5325
|
if (v.type && v.type !== 'field') { return false; }
|
|
5269
5326
|
return v.field === field;
|
|
5270
5327
|
|
|
5271
5328
|
};
|
|
5272
5329
|
}
|
|
5273
5330
|
/**
|
|
5274
|
-
*
|
|
5275
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5331
|
+
* @template T
|
|
5332
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5276
5333
|
* @param {Store} store
|
|
5277
5334
|
* @param {Node} node
|
|
5278
5335
|
* @param {StoreLayout.Options?} options
|
|
5279
|
-
* @param {StoreLayout
|
|
5336
|
+
* @param {StoreLayout<T>?} [layout]
|
|
5280
5337
|
* @param {Node} [anchor]
|
|
5281
5338
|
* @param {(child?: Store<any, any> | undefined) => void} [dragenter]
|
|
5339
|
+
* @returns {void}
|
|
5282
5340
|
*/
|
|
5283
5341
|
function renderHtml(store, fieldRenderer, node, options, layout, anchor, dragenter) {
|
|
5284
|
-
|
|
5285
|
-
const destroyList = [];
|
|
5342
|
+
if (options?.signal?.aborted) { return; }
|
|
5286
5343
|
if (node instanceof Element) {
|
|
5287
5344
|
const tagName = node.tagName.toLowerCase();
|
|
5288
|
-
if (!node.parentNode) { return
|
|
5345
|
+
if (!node.parentNode) { return; }
|
|
5289
5346
|
if (tagName === 'nl-form-field') {
|
|
5290
5347
|
const field = node.getAttribute('name') || '';
|
|
5291
5348
|
const mode = node.getAttribute('mode') || '';
|
|
5292
5349
|
const fieldStore = field ? store.child(field) : store;
|
|
5293
5350
|
const fieldLayout = field ? layout?.fields?.find(createFieldFilter(field)) || null : null;
|
|
5294
|
-
if (!fieldStore) { return
|
|
5351
|
+
if (!fieldStore) { return; }
|
|
5295
5352
|
switch (mode) {
|
|
5296
5353
|
case 'grid': {
|
|
5297
|
-
const
|
|
5298
|
-
node.replaceWith(el);
|
|
5299
|
-
return
|
|
5354
|
+
const el = Form(store, fieldRenderer, fieldLayout, options);
|
|
5355
|
+
if (el) { node.replaceWith(el); }
|
|
5356
|
+
return;
|
|
5300
5357
|
}
|
|
5301
5358
|
}
|
|
5302
|
-
const res = fieldRenderer(fieldStore, options);
|
|
5359
|
+
const res = fieldRenderer(fieldStore, layout?.renderer, options);
|
|
5303
5360
|
if (res) {
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
return destroy;
|
|
5361
|
+
node.replaceWith(res);
|
|
5362
|
+
return;
|
|
5307
5363
|
}
|
|
5308
5364
|
const value = node.getAttribute('placeholder') || '';
|
|
5309
5365
|
node.replaceWith(document.createTextNode(value));
|
|
5310
|
-
return
|
|
5366
|
+
return;
|
|
5311
5367
|
}
|
|
5312
5368
|
if (tagName === 'nl-form-button') {
|
|
5313
5369
|
const button = document.createElement('button');
|
|
5314
|
-
button.
|
|
5370
|
+
button.classList.add('NeeloongForm-item-button');
|
|
5315
5371
|
const click = node.getAttribute('click') || '';
|
|
5316
5372
|
const call = options?.call;
|
|
5317
5373
|
if (click && typeof call === 'function') {
|
|
@@ -5321,7 +5377,7 @@
|
|
|
5321
5377
|
button.appendChild(n);
|
|
5322
5378
|
}
|
|
5323
5379
|
node.replaceWith(button);
|
|
5324
|
-
return
|
|
5380
|
+
return;
|
|
5325
5381
|
}
|
|
5326
5382
|
const name = node.getAttribute('nl-form-field');
|
|
5327
5383
|
if (name) {
|
|
@@ -5330,32 +5386,35 @@
|
|
|
5330
5386
|
|
|
5331
5387
|
const fieldStore = field ? store.child(field) : store;
|
|
5332
5388
|
if (!fieldStore) {
|
|
5333
|
-
return
|
|
5389
|
+
return;
|
|
5334
5390
|
}
|
|
5335
5391
|
node.removeAttribute('nl-form-field');
|
|
5336
5392
|
const fieldLayout = field ? layout?.fields?.find(createFieldFilter(field)) : layout;
|
|
5337
|
-
if (!array) {
|
|
5393
|
+
if (!array) {
|
|
5394
|
+
renderHtml(fieldStore, fieldRenderer, node, options, fieldLayout, anchor);
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5338
5397
|
if (!(fieldStore instanceof ArrayStore)) {
|
|
5339
5398
|
node.remove();
|
|
5340
|
-
return
|
|
5399
|
+
return;
|
|
5341
5400
|
}
|
|
5342
5401
|
const parentElement = node.parentElement;
|
|
5343
5402
|
if (!parentElement) {
|
|
5344
5403
|
node.remove();
|
|
5345
|
-
return
|
|
5404
|
+
return;
|
|
5346
5405
|
}
|
|
5347
5406
|
const comment = parentElement.insertBefore(document.createComment(''), node) || null;
|
|
5348
5407
|
node.remove();
|
|
5349
5408
|
|
|
5350
|
-
/** @type {Map<Store, [Node,
|
|
5409
|
+
/** @type {Map<Store, [Node, AbortController]>} */
|
|
5351
5410
|
let seMap = new Map();
|
|
5352
|
-
/** @param {Map<Store, [
|
|
5411
|
+
/** @param {Map<Store, [Node, AbortController]>} map */
|
|
5353
5412
|
function destroyMap(map) {
|
|
5354
|
-
for (const [el,
|
|
5355
|
-
destroy();
|
|
5413
|
+
for (const [el, ac] of map.values()) {
|
|
5356
5414
|
if (el instanceof Element) {
|
|
5357
5415
|
el.remove();
|
|
5358
5416
|
}
|
|
5417
|
+
ac.abort();
|
|
5359
5418
|
}
|
|
5360
5419
|
}
|
|
5361
5420
|
let dragRow = -1;
|
|
@@ -5372,22 +5431,26 @@
|
|
|
5372
5431
|
}
|
|
5373
5432
|
};
|
|
5374
5433
|
|
|
5375
|
-
|
|
5434
|
+
watch(() => fieldStore.children, children => {
|
|
5376
5435
|
let nextNode = comment.nextSibling;
|
|
5377
5436
|
const oldSeMap = seMap;
|
|
5378
5437
|
seMap = new Map();
|
|
5379
5438
|
for (const child of children) {
|
|
5380
5439
|
const old = oldSeMap.get(child);
|
|
5381
5440
|
if (!old) {
|
|
5441
|
+
const ac = new AbortController();
|
|
5382
5442
|
const el = parentElement.insertBefore(node.cloneNode(true), nextNode);
|
|
5383
|
-
|
|
5443
|
+
renderHtml(child, fieldRenderer, el, {
|
|
5444
|
+
...options,
|
|
5445
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
5446
|
+
}, fieldLayout, el);
|
|
5384
5447
|
el.addEventListener('dragenter', () => { newDragenter(child); });
|
|
5385
5448
|
el.addEventListener('dragstart', (event) => {
|
|
5386
5449
|
if (event.target !== event.currentTarget) { return; }
|
|
5387
5450
|
dragRow = Number(child.index);
|
|
5388
5451
|
});
|
|
5389
5452
|
el.addEventListener('dragend', () => { dragRow = -1; });
|
|
5390
|
-
seMap.set(child, [el,
|
|
5453
|
+
seMap.set(child, [el, ac]);
|
|
5391
5454
|
continue;
|
|
5392
5455
|
}
|
|
5393
5456
|
oldSeMap.delete(child);
|
|
@@ -5399,13 +5462,13 @@
|
|
|
5399
5462
|
parentElement.insertBefore(old[0], nextNode);
|
|
5400
5463
|
}
|
|
5401
5464
|
destroyMap(oldSeMap);
|
|
5402
|
-
}, true);
|
|
5465
|
+
}, true, options?.signal);
|
|
5403
5466
|
|
|
5404
|
-
|
|
5467
|
+
options?.signal?.addEventListener('abort', () => {
|
|
5405
5468
|
comment.remove();
|
|
5406
5469
|
destroyMap(seMap);
|
|
5407
|
-
|
|
5408
|
-
|
|
5470
|
+
}, { once: true });
|
|
5471
|
+
return;
|
|
5409
5472
|
|
|
5410
5473
|
}
|
|
5411
5474
|
if (node.getAttribute('nl-form-remove') !== null) {
|
|
@@ -5448,11 +5511,11 @@
|
|
|
5448
5511
|
const field = node.getAttribute(attr);
|
|
5449
5512
|
const fieldStore = field ? store.child(field) : store;
|
|
5450
5513
|
if (!fieldStore) { continue; }
|
|
5451
|
-
|
|
5514
|
+
effect(() => {
|
|
5452
5515
|
try {
|
|
5453
5516
|
node.setAttribute(name, fieldStore.value);
|
|
5454
5517
|
} catch { }
|
|
5455
|
-
})
|
|
5518
|
+
}, options?.signal);
|
|
5456
5519
|
} else if (prefix === 'nl-form-event' && typeof call === 'function') {
|
|
5457
5520
|
const event = node.getAttribute(attr);
|
|
5458
5521
|
if (!event) { continue; }
|
|
@@ -5464,15 +5527,9 @@
|
|
|
5464
5527
|
}
|
|
5465
5528
|
if (node instanceof Element || node instanceof DocumentFragment) {
|
|
5466
5529
|
for (const n of [...node.children]) {
|
|
5467
|
-
|
|
5530
|
+
renderHtml(store, fieldRenderer, n, options, layout, anchor);
|
|
5468
5531
|
}
|
|
5469
5532
|
}
|
|
5470
|
-
return () => {
|
|
5471
|
-
for (const destroy of destroyList) {
|
|
5472
|
-
destroy();
|
|
5473
|
-
}
|
|
5474
|
-
};
|
|
5475
|
-
|
|
5476
5533
|
}
|
|
5477
5534
|
|
|
5478
5535
|
/**
|
|
@@ -5494,14 +5551,16 @@
|
|
|
5494
5551
|
|
|
5495
5552
|
/**
|
|
5496
5553
|
*
|
|
5554
|
+
* @template T
|
|
5497
5555
|
* @param {Store<any, any>} store
|
|
5498
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5499
|
-
* @param {StoreLayout.Field
|
|
5556
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5557
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
5500
5558
|
* @param {StoreLayout.Options?} options
|
|
5501
|
-
* @returns {
|
|
5559
|
+
* @returns {ParentNode?}
|
|
5502
5560
|
*/
|
|
5503
5561
|
function FormFieldInline(store, fieldRenderer, layout, options) {
|
|
5504
|
-
|
|
5562
|
+
if (options?.signal?.aborted) { return null; }
|
|
5563
|
+
return fieldRenderer(store, layout?.renderer, options);
|
|
5505
5564
|
}
|
|
5506
5565
|
|
|
5507
5566
|
/** @import { Store } from '../Store/index.mjs' */
|
|
@@ -5509,9 +5568,10 @@
|
|
|
5509
5568
|
|
|
5510
5569
|
/**
|
|
5511
5570
|
*
|
|
5571
|
+
* @template T
|
|
5512
5572
|
* @param {Store<any, any>} store
|
|
5513
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5514
|
-
* @param {StoreLayout.Field
|
|
5573
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5574
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
5515
5575
|
* @param {object} option
|
|
5516
5576
|
* @param {StoreLayout.Column[]} option.columns
|
|
5517
5577
|
* @param {() => void} option.remove
|
|
@@ -5520,8 +5580,7 @@
|
|
|
5520
5580
|
* @param {() => void} option.dragend
|
|
5521
5581
|
* @param {{get(): boolean}} option.deletable
|
|
5522
5582
|
* @param {StoreLayout.Options?} options
|
|
5523
|
-
|
|
5524
|
-
* @returns {[HTMLTableSectionElement, () => void]}
|
|
5583
|
+
* @returns {HTMLTableSectionElement}
|
|
5525
5584
|
*/
|
|
5526
5585
|
function Line(store, fieldRenderer, layout, {
|
|
5527
5586
|
columns,
|
|
@@ -5538,38 +5597,34 @@
|
|
|
5538
5597
|
root.addEventListener('dragend', dragend);
|
|
5539
5598
|
const head = root.appendChild(document.createElement('tr'));
|
|
5540
5599
|
|
|
5541
|
-
/** @type {(() => void)[]} */
|
|
5542
|
-
const destroyList = [];
|
|
5543
5600
|
|
|
5544
5601
|
|
|
5545
5602
|
let trigger = () => { };
|
|
5546
5603
|
/** @type {HTMLButtonElement[]} */
|
|
5547
5604
|
const triggerList = [];
|
|
5548
5605
|
if (columns.find(v => v.actions?.includes('trigger'))) {
|
|
5549
|
-
const
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
ext.classList.add('NeeloongForm-table-line-open');
|
|
5606
|
+
const form = Form(store, fieldRenderer, layout, options);
|
|
5607
|
+
if (form) {
|
|
5608
|
+
const body = root.appendChild(document.createElement('tr'));
|
|
5609
|
+
const main = body.appendChild(document.createElement('td'));
|
|
5610
|
+
main.colSpan = columns.length;
|
|
5611
|
+
body.hidden = true;
|
|
5612
|
+
trigger = () => {
|
|
5613
|
+
if (body.hidden) {
|
|
5614
|
+
body.hidden = false;
|
|
5615
|
+
for (const ext of triggerList) {
|
|
5616
|
+
ext.classList.remove('NeeloongForm-table-line-open');
|
|
5617
|
+
ext.classList.add('NeeloongForm-table-line-close');
|
|
5618
|
+
}
|
|
5619
|
+
} else {
|
|
5620
|
+
body.hidden = true;
|
|
5621
|
+
for (const ext of triggerList) {
|
|
5622
|
+
ext.classList.remove('NeeloongForm-table-line-close');
|
|
5623
|
+
ext.classList.add('NeeloongForm-table-line-open');
|
|
5624
|
+
}
|
|
5569
5625
|
}
|
|
5570
|
-
}
|
|
5571
|
-
}
|
|
5572
|
-
|
|
5626
|
+
};
|
|
5627
|
+
}
|
|
5573
5628
|
}
|
|
5574
5629
|
|
|
5575
5630
|
/**
|
|
@@ -5597,9 +5652,8 @@
|
|
|
5597
5652
|
const td = head.appendChild(document.createElement('td'));
|
|
5598
5653
|
const child = field && store.child(field);
|
|
5599
5654
|
if (child) {
|
|
5600
|
-
const
|
|
5601
|
-
|
|
5602
|
-
td.appendChild(el);
|
|
5655
|
+
const el = FormFieldInline(child, fieldRenderer, null, options);
|
|
5656
|
+
if (el) { td.appendChild(el); }
|
|
5603
5657
|
}
|
|
5604
5658
|
continue;
|
|
5605
5659
|
}
|
|
@@ -5619,9 +5673,9 @@
|
|
|
5619
5673
|
const move = handle.appendChild(document.createElement('button'));
|
|
5620
5674
|
move.classList.add('NeeloongForm-table-move');
|
|
5621
5675
|
move.addEventListener('pointerdown', pointerdown);
|
|
5622
|
-
|
|
5676
|
+
watch(() => store.readonly || store.disabled, disabled => {
|
|
5623
5677
|
move.disabled = disabled;
|
|
5624
|
-
}, true)
|
|
5678
|
+
}, true, options.signal);
|
|
5625
5679
|
continue;
|
|
5626
5680
|
}
|
|
5627
5681
|
case 'remove': {
|
|
@@ -5629,9 +5683,9 @@
|
|
|
5629
5683
|
const del = handle.appendChild(document.createElement('button'));
|
|
5630
5684
|
del.classList.add('NeeloongForm-table-remove');
|
|
5631
5685
|
del.addEventListener('click', remove);
|
|
5632
|
-
|
|
5686
|
+
watch(() => !deletable.get() || store.readonly || store.disabled, disabled => {
|
|
5633
5687
|
del.disabled = disabled;
|
|
5634
|
-
}, true)
|
|
5688
|
+
}, true, options.signal);
|
|
5635
5689
|
continue;
|
|
5636
5690
|
}
|
|
5637
5691
|
case 'serial': {
|
|
@@ -5643,11 +5697,7 @@
|
|
|
5643
5697
|
}
|
|
5644
5698
|
}
|
|
5645
5699
|
|
|
5646
|
-
return
|
|
5647
|
-
for (const destroy of destroyList) {
|
|
5648
|
-
destroy();
|
|
5649
|
-
}
|
|
5650
|
-
}];
|
|
5700
|
+
return root;
|
|
5651
5701
|
}
|
|
5652
5702
|
|
|
5653
5703
|
/** @import { Store, ArrayStore } from '../Store/index.mjs' */
|
|
@@ -5655,16 +5705,16 @@
|
|
|
5655
5705
|
|
|
5656
5706
|
/**
|
|
5657
5707
|
*
|
|
5708
|
+
* @param {AbortSignal | null | undefined} signal
|
|
5658
5709
|
* @param {HTMLElement} parent
|
|
5659
5710
|
* @param {StoreLayout.Column[]} columns
|
|
5660
5711
|
* @param {() => any} add
|
|
5661
5712
|
* @param {{get(): boolean}} addable
|
|
5662
5713
|
* @param {boolean?} [editable]
|
|
5714
|
+
* @returns {void}
|
|
5663
5715
|
*/
|
|
5664
|
-
function renderHead(parent, columns, add, addable, editable) {
|
|
5716
|
+
function renderHead(signal, parent, columns, add, addable, editable) {
|
|
5665
5717
|
const tr = parent.appendChild(document.createElement('tr'));
|
|
5666
|
-
/** @type {(() => void)[]} */
|
|
5667
|
-
const destroyList = [];
|
|
5668
5718
|
for (const { action, actions, width, label } of columns) {
|
|
5669
5719
|
const th = tr.appendChild(document.createElement('th'));
|
|
5670
5720
|
if (width) { th.setAttribute('width', `${width}`); }
|
|
@@ -5676,23 +5726,20 @@
|
|
|
5676
5726
|
const button = th.appendChild(document.createElement('button'));
|
|
5677
5727
|
button.addEventListener('click', add);
|
|
5678
5728
|
button.classList.add('NeeloongForm-table-add');
|
|
5679
|
-
|
|
5729
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, signal);
|
|
5680
5730
|
}
|
|
5681
|
-
return () => {
|
|
5682
|
-
for (const destroy of destroyList) {
|
|
5683
|
-
destroy();
|
|
5684
|
-
}
|
|
5685
|
-
};
|
|
5686
5731
|
}
|
|
5687
5732
|
/**
|
|
5688
5733
|
*
|
|
5734
|
+
* @template T
|
|
5689
5735
|
* @param {ArrayStore} store
|
|
5690
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
5691
|
-
* @param {StoreLayout.Field
|
|
5736
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
5737
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
5692
5738
|
* @param {StoreLayout.Options?} options
|
|
5693
|
-
* @returns {
|
|
5739
|
+
* @returns {HTMLTableElement?}
|
|
5694
5740
|
*/
|
|
5695
5741
|
function Table(store, fieldRenderer, layout, options) {
|
|
5742
|
+
if (options?.signal?.aborted) { return null; }
|
|
5696
5743
|
const headerColumns = layout?.columns;
|
|
5697
5744
|
const fieldList = Object.entries(store.type || {})
|
|
5698
5745
|
.filter(([k, v]) => typeof v?.type !== 'object')
|
|
@@ -5743,7 +5790,7 @@
|
|
|
5743
5790
|
}
|
|
5744
5791
|
|
|
5745
5792
|
const table = document.createElement('table');
|
|
5746
|
-
table.
|
|
5793
|
+
table.classList.add('NeeloongForm-table');
|
|
5747
5794
|
const thead = table.appendChild(document.createElement('thead'));
|
|
5748
5795
|
|
|
5749
5796
|
const addable = new exports.Signal.Computed(() => store.addable);
|
|
@@ -5784,15 +5831,13 @@
|
|
|
5784
5831
|
dragRow = -1;
|
|
5785
5832
|
|
|
5786
5833
|
}
|
|
5787
|
-
|
|
5788
|
-
const destroyList = [];
|
|
5789
|
-
destroyList.push(renderHead(thead, columns, add, addable, Boolean(options?.editable)));
|
|
5834
|
+
renderHead(options?.signal, thead, columns, add, addable, Boolean(options?.editable));
|
|
5790
5835
|
switch (layout?.tableFoot) {
|
|
5791
5836
|
default:
|
|
5792
5837
|
case 'header': {
|
|
5793
5838
|
const tfoot = table.appendChild(document.createElement('tfoot'));
|
|
5794
5839
|
tfoot.addEventListener('dragenter', () => { dragenter(); });
|
|
5795
|
-
|
|
5840
|
+
renderHead(options?.signal, tfoot, columns, add, addable, Boolean(options?.editable));
|
|
5796
5841
|
break;
|
|
5797
5842
|
}
|
|
5798
5843
|
case 'add': {
|
|
@@ -5804,39 +5849,34 @@
|
|
|
5804
5849
|
const button = th.appendChild(document.createElement('button'));
|
|
5805
5850
|
button.addEventListener('click', add);
|
|
5806
5851
|
button.classList.add('NeeloongForm-table-foot-add');
|
|
5807
|
-
|
|
5852
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options?.signal);
|
|
5808
5853
|
break;
|
|
5809
5854
|
}
|
|
5810
5855
|
case 'none':
|
|
5811
5856
|
}
|
|
5812
|
-
|
|
5813
|
-
/** @type {Map<Store, [HTMLTableSectionElement, () => void]>} */
|
|
5857
|
+
/** @type {Map<Store, [HTMLTableSectionElement, AbortController]>} */
|
|
5814
5858
|
let seMap = new Map();
|
|
5815
|
-
|
|
5816
|
-
function destroyMap(map) {
|
|
5817
|
-
for (const [el, destroy] of map.values()) {
|
|
5818
|
-
destroy();
|
|
5819
|
-
el.remove();
|
|
5820
|
-
}
|
|
5821
|
-
|
|
5822
|
-
}
|
|
5823
|
-
const childrenResult = watch(() => store.children, function render(children) {
|
|
5859
|
+
watch(() => store.children, children => {
|
|
5824
5860
|
let nextNode = thead.nextSibling;
|
|
5825
5861
|
const oldSeMap = seMap;
|
|
5826
5862
|
seMap = new Map();
|
|
5827
5863
|
for (let child of children) {
|
|
5828
5864
|
const old = oldSeMap.get(child);
|
|
5829
5865
|
if (!old) {
|
|
5830
|
-
const
|
|
5866
|
+
const ac = new AbortController();
|
|
5867
|
+
const el = Line(child, fieldRenderer, layout, {
|
|
5831
5868
|
columns,
|
|
5832
5869
|
remove: remove.bind(null, child),
|
|
5833
5870
|
dragenter: dragenter.bind(null, child),
|
|
5834
5871
|
dragstart: dragstart.bind(null, child),
|
|
5835
5872
|
dragend,
|
|
5836
5873
|
deletable,
|
|
5837
|
-
},
|
|
5874
|
+
}, {
|
|
5875
|
+
...options,
|
|
5876
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
5877
|
+
});
|
|
5838
5878
|
table.insertBefore(el, nextNode);
|
|
5839
|
-
seMap.set(child, [el,
|
|
5879
|
+
seMap.set(child, [el, ac]);
|
|
5840
5880
|
continue;
|
|
5841
5881
|
}
|
|
5842
5882
|
oldSeMap.delete(child);
|
|
@@ -5847,18 +5887,13 @@
|
|
|
5847
5887
|
}
|
|
5848
5888
|
table.insertBefore(old[0], nextNode);
|
|
5849
5889
|
}
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
return [table, () => {
|
|
5854
|
-
start.remove();
|
|
5855
|
-
thead.remove();
|
|
5856
|
-
destroyMap(seMap);
|
|
5857
|
-
childrenResult();
|
|
5858
|
-
for (const destroy of destroyList) {
|
|
5859
|
-
destroy();
|
|
5890
|
+
for (const [el, ac] of oldSeMap.values()) {
|
|
5891
|
+
el.remove();
|
|
5892
|
+
ac.abort();
|
|
5860
5893
|
}
|
|
5861
|
-
}
|
|
5894
|
+
}, true, options?.signal);
|
|
5895
|
+
|
|
5896
|
+
return table;
|
|
5862
5897
|
}
|
|
5863
5898
|
|
|
5864
5899
|
/** @import { StoreLayout } from '../types.mjs' */
|
|
@@ -5867,6 +5902,7 @@
|
|
|
5867
5902
|
*
|
|
5868
5903
|
* @param {HTMLElement} root
|
|
5869
5904
|
* @param {StoreLayout.Grid?} [layout]
|
|
5905
|
+
* @returns {void}
|
|
5870
5906
|
*/
|
|
5871
5907
|
function bindGrid(root, layout) {
|
|
5872
5908
|
const { colStart, colSpan, colEnd, rowStart, rowSpan, rowEnd } = layout || {};
|
|
@@ -5885,211 +5921,109 @@
|
|
|
5885
5921
|
} else if (rowSpan) {
|
|
5886
5922
|
root.style.gridRow = `span ${rowSpan}`;
|
|
5887
5923
|
}
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
5924
|
}
|
|
5893
5925
|
|
|
5894
|
-
/** @import {
|
|
5895
|
-
|
|
5896
|
-
/**
|
|
5897
|
-
*
|
|
5898
|
-
* @param {HTMLElement} root
|
|
5899
|
-
* @param {CellValues} [values]
|
|
5900
|
-
* @returns {() => void}
|
|
5901
|
-
*/
|
|
5902
|
-
function bindErrored(root, values) {
|
|
5903
|
-
return effect(() => {
|
|
5904
|
-
if (values?.error) {
|
|
5905
|
-
root.classList.add('NeeloongForm-item-errored');
|
|
5906
|
-
} else {
|
|
5907
|
-
root.classList.remove('NeeloongForm-item-errored');
|
|
5908
|
-
}
|
|
5909
|
-
});
|
|
5910
|
-
}
|
|
5926
|
+
/** @import { StoreLayout } from '../types.mjs' */
|
|
5911
5927
|
|
|
5912
5928
|
/**
|
|
5913
|
-
*
|
|
5914
|
-
* @
|
|
5915
|
-
* @
|
|
5916
|
-
* @
|
|
5929
|
+
* @typedef {object} CellValues
|
|
5930
|
+
* @property {string?} [label]
|
|
5931
|
+
* @property {string?} [description]
|
|
5932
|
+
* @property {string?} [error]
|
|
5933
|
+
* @property {boolean?} [required]
|
|
5917
5934
|
*/
|
|
5918
|
-
function bindRequired(root, values) {
|
|
5919
|
-
return effect(() => {
|
|
5920
|
-
if (values?.required) {
|
|
5921
|
-
root.classList.add('NeeloongForm-item-required');
|
|
5922
|
-
} else {
|
|
5923
|
-
root.classList.remove('NeeloongForm-item-required');
|
|
5924
|
-
}
|
|
5925
|
-
});
|
|
5926
|
-
}
|
|
5927
|
-
|
|
5928
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5929
|
-
|
|
5930
5935
|
/**
|
|
5931
5936
|
*
|
|
5937
|
+
* @param {AbortSignal | null | undefined} signal
|
|
5932
5938
|
* @param {CellValues} [values]
|
|
5933
|
-
* @returns {[HTMLDivElement,
|
|
5939
|
+
* @returns {[HTMLDivElement, HTMLDivElement]}
|
|
5934
5940
|
*/
|
|
5935
|
-
function createStdCell(values) {
|
|
5936
|
-
/** @type {(() => void)[]} */
|
|
5937
|
-
const destroyList = [];
|
|
5941
|
+
function createStdCell(signal, values) {
|
|
5938
5942
|
const root = document.createElement('div');
|
|
5939
|
-
root.className = 'NeeloongForm-item';
|
|
5940
|
-
destroyList.push(bindRequired(root, values));
|
|
5941
|
-
|
|
5942
5943
|
const label = root.appendChild(document.createElement('div'));
|
|
5943
|
-
label.
|
|
5944
|
-
|
|
5944
|
+
label.classList.add('NeeloongForm-item-label');
|
|
5945
|
+
effect(() => label.innerText = values?.label || '', signal);
|
|
5945
5946
|
|
|
5946
5947
|
const content = root.appendChild(document.createElement('div'));
|
|
5947
|
-
content.
|
|
5948
|
+
content.classList.add('NeeloongForm-item-content');
|
|
5948
5949
|
|
|
5949
5950
|
const description = root.appendChild(document.createElement('div'));
|
|
5950
|
-
description.
|
|
5951
|
-
|
|
5951
|
+
description.classList.add('NeeloongForm-item-description');
|
|
5952
|
+
effect(() => description.innerText = values?.description || '', signal);
|
|
5952
5953
|
const error = root.appendChild(document.createElement('div'));
|
|
5953
|
-
error.
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
return [root, () => {
|
|
5958
|
-
for (const destroy of destroyList) {
|
|
5959
|
-
destroy();
|
|
5960
|
-
}
|
|
5961
|
-
}, content, destroyList];
|
|
5954
|
+
error.classList.add('NeeloongForm-item-error');
|
|
5955
|
+
effect(() => error.innerText = values?.error || '', signal);
|
|
5956
|
+
return [root, content];
|
|
5962
5957
|
|
|
5963
5958
|
|
|
5964
5959
|
}
|
|
5965
5960
|
|
|
5966
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5967
|
-
|
|
5968
|
-
/**
|
|
5969
|
-
*
|
|
5970
|
-
* @param {CellValues} [values]
|
|
5971
|
-
* @returns {[HTMLElement, () => void, HTMLElement, (() => void)[]]}
|
|
5972
|
-
*/
|
|
5973
|
-
function createCollapseCell(values) {
|
|
5974
|
-
/** @type {(() => void)[]} */
|
|
5975
|
-
const destroyList = [];
|
|
5976
|
-
const root = document.createElement('details');
|
|
5977
|
-
root.className = 'NeeloongForm-item';
|
|
5978
|
-
destroyList.push(bindRequired(root, values));
|
|
5979
|
-
|
|
5980
|
-
root.open = true;
|
|
5981
|
-
const summary = root.appendChild(document.createElement('summary'));
|
|
5982
|
-
destroyList.push(effect(() => summary.innerText = values?.label || ''));
|
|
5983
|
-
destroyList.push(bindErrored(root, values));
|
|
5984
|
-
|
|
5985
|
-
return [root, () => {
|
|
5986
|
-
for (const destroy of destroyList) {
|
|
5987
|
-
destroy();
|
|
5988
|
-
}
|
|
5989
|
-
}, root, destroyList];
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
}
|
|
5993
|
-
|
|
5994
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
5995
|
-
|
|
5996
|
-
/**
|
|
5997
|
-
*
|
|
5998
|
-
* @param {CellValues} [values]
|
|
5999
|
-
* @returns {[HTMLDivElement, () => void, HTMLDivElement, (() => void)[]]}
|
|
6000
|
-
*/
|
|
6001
|
-
function createNullCell(values) {
|
|
6002
|
-
/** @type {(() => void)[]} */
|
|
6003
|
-
const destroyList = [];
|
|
6004
|
-
const root = document.createElement('div');
|
|
6005
|
-
root.className = 'NeeloongForm-item';
|
|
6006
|
-
destroyList.push(bindRequired(root, values));
|
|
6007
|
-
destroyList.push(bindErrored(root, values));
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
return [root, () => {
|
|
6011
|
-
for (const destroy of destroyList) {
|
|
6012
|
-
destroy();
|
|
6013
|
-
}
|
|
6014
|
-
}, root, destroyList];
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
}
|
|
6018
|
-
|
|
6019
|
-
/** @import { CellValues } from './createCell.mjs' */
|
|
6020
|
-
|
|
6021
|
-
/**
|
|
6022
|
-
*
|
|
6023
|
-
* @param {CellValues} [values]
|
|
6024
|
-
* @returns {[HTMLElement, () => void, HTMLElement, (() => void)[]]}
|
|
6025
|
-
*/
|
|
6026
|
-
function createFieldsetCell(values) {
|
|
6027
|
-
/** @type {(() => void)[]} */
|
|
6028
|
-
const destroyList = [];
|
|
6029
|
-
const root = document.createElement('fieldset');
|
|
6030
|
-
root.className = 'NeeloongForm-item';
|
|
6031
|
-
destroyList.push(bindRequired(root, values));
|
|
6032
|
-
|
|
6033
|
-
const legend = root.appendChild(document.createElement('legend'));
|
|
6034
|
-
destroyList.push(effect(() => legend.innerText = values?.label || ''));
|
|
6035
|
-
destroyList.push(bindErrored(root, values));
|
|
6036
|
-
|
|
6037
|
-
return [root, () => {
|
|
6038
|
-
for (const destroy of destroyList) {
|
|
6039
|
-
destroy();
|
|
6040
|
-
}
|
|
6041
|
-
}, root, destroyList];
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
}
|
|
6045
|
-
|
|
6046
|
-
/** @import { StoreLayout } from '../types.mjs' */
|
|
6047
|
-
|
|
6048
|
-
/**
|
|
6049
|
-
* @typedef {object} CellValues
|
|
6050
|
-
* @property {string?} [label]
|
|
6051
|
-
* @property {string?} [description]
|
|
6052
|
-
* @property {string?} [error]
|
|
6053
|
-
* @property {boolean?} [required]
|
|
6054
|
-
*/
|
|
6055
5961
|
/**
|
|
6056
5962
|
*
|
|
5963
|
+
* @param {AbortSignal | null | undefined} signal
|
|
6057
5964
|
* @param {StoreLayout.Grid?} [layout]
|
|
6058
5965
|
* @param {CellValues} [values]
|
|
6059
5966
|
* @param {StoreLayout.Grid['cell']?} [defCell]
|
|
6060
5967
|
* @param {boolean?} [blockOnly]
|
|
6061
|
-
* @returns {[HTMLElement,
|
|
5968
|
+
* @returns {[HTMLElement, HTMLElement]}
|
|
6062
5969
|
*/
|
|
6063
|
-
function createCell(layout, values, defCell, blockOnly) {
|
|
5970
|
+
function createCell(signal, layout, values, defCell, blockOnly) {
|
|
6064
5971
|
/**
|
|
6065
5972
|
*
|
|
6066
5973
|
* @param {string?} [cellType]
|
|
6067
|
-
* @returns {[HTMLElement,
|
|
5974
|
+
* @returns {[HTMLElement, HTMLElement]?}
|
|
6068
5975
|
*/
|
|
6069
5976
|
function create(cellType) {
|
|
6070
5977
|
if (!cellType) { return null; }
|
|
6071
5978
|
if (!blockOnly) {
|
|
6072
5979
|
switch (cellType) {
|
|
6073
5980
|
case 'inline': {
|
|
6074
|
-
const
|
|
6075
|
-
bindGrid(
|
|
6076
|
-
return
|
|
5981
|
+
const [root, content] = createStdCell(signal, values);
|
|
5982
|
+
bindGrid(root, layout);
|
|
5983
|
+
return [root, content];
|
|
6077
5984
|
}
|
|
6078
5985
|
case 'base': {
|
|
6079
|
-
const
|
|
6080
|
-
bindGrid(
|
|
6081
|
-
return
|
|
5986
|
+
const root = document.createElement('div');
|
|
5987
|
+
bindGrid(root, layout);
|
|
5988
|
+
return [root, root];
|
|
6082
5989
|
}
|
|
6083
5990
|
}
|
|
6084
5991
|
}
|
|
6085
5992
|
switch (cellType) {
|
|
6086
|
-
case 'block': return createStdCell(values);
|
|
6087
|
-
case 'fieldset':
|
|
6088
|
-
|
|
5993
|
+
case 'block': return createStdCell(signal, values);
|
|
5994
|
+
case 'fieldset': {
|
|
5995
|
+
const root = document.createElement('fieldset');
|
|
5996
|
+
const legend = root.appendChild(document.createElement('legend'));
|
|
5997
|
+
effect(() => legend.innerText = values?.label || '', signal);
|
|
5998
|
+
return [root, root];
|
|
5999
|
+
}
|
|
6000
|
+
case 'collapse': {
|
|
6001
|
+
const root = document.createElement('details');
|
|
6002
|
+
root.open = true;
|
|
6003
|
+
const summary = root.appendChild(document.createElement('summary'));
|
|
6004
|
+
effect(() => summary.innerText = values?.label || '', signal);
|
|
6005
|
+
return [root, root];
|
|
6006
|
+
}
|
|
6089
6007
|
}
|
|
6090
6008
|
return null;
|
|
6091
6009
|
}
|
|
6092
|
-
|
|
6010
|
+
const [root, content] = create(layout?.cell) || create(defCell) || createStdCell(signal, values);
|
|
6011
|
+
root.classList.add('NeeloongForm-item');
|
|
6012
|
+
effect(() => {
|
|
6013
|
+
if (values?.error) {
|
|
6014
|
+
root.classList.add('NeeloongForm-item-errored');
|
|
6015
|
+
} else {
|
|
6016
|
+
root.classList.remove('NeeloongForm-item-errored');
|
|
6017
|
+
}
|
|
6018
|
+
}, signal);
|
|
6019
|
+
effect(() => {
|
|
6020
|
+
if (values?.required) {
|
|
6021
|
+
root.classList.add('NeeloongForm-item-required');
|
|
6022
|
+
} else {
|
|
6023
|
+
root.classList.remove('NeeloongForm-item-required');
|
|
6024
|
+
}
|
|
6025
|
+
}, signal);
|
|
6026
|
+
return [root, content];
|
|
6093
6027
|
}
|
|
6094
6028
|
|
|
6095
6029
|
/** @import { Store } from '../Store/index.mjs' */
|
|
@@ -6098,11 +6032,12 @@
|
|
|
6098
6032
|
|
|
6099
6033
|
/**
|
|
6100
6034
|
*
|
|
6035
|
+
* @template T
|
|
6101
6036
|
* @param {Store<any, any>} store
|
|
6102
6037
|
* @param {Signal.State<Store<any, any>?>} currentStore
|
|
6103
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6104
|
-
* @param {StoreLayout.Field
|
|
6105
|
-
* @param {State}
|
|
6038
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6039
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
6040
|
+
* @param {Signal.State<State>} state
|
|
6106
6041
|
* @param {object} option
|
|
6107
6042
|
* @param {StoreLayout.Column[]} option.columns
|
|
6108
6043
|
* @param {() => void} option.remove
|
|
@@ -6114,15 +6049,13 @@
|
|
|
6114
6049
|
* @param {() => void} option.addNode
|
|
6115
6050
|
* @param {(store: Store<any, any>) => () => void} option.createDetails
|
|
6116
6051
|
* @param {StoreLayout.Options?} options
|
|
6117
|
-
|
|
6118
|
-
* @returns {[HTMLElement, () => void, (s: State) => void]}
|
|
6052
|
+
* @returns {HTMLElement}
|
|
6119
6053
|
*/
|
|
6120
6054
|
function TreeLine(
|
|
6121
|
-
store, currentStore, fieldRenderer, layout,
|
|
6055
|
+
store, currentStore, fieldRenderer, layout, state, {
|
|
6122
6056
|
columns,
|
|
6123
6057
|
remove, dragenter, dragstart, dragend, deletable, addNode, drop, createDetails,
|
|
6124
6058
|
}, options) {
|
|
6125
|
-
const state = new exports.Signal.State(initState);
|
|
6126
6059
|
const root = document.createElement('div');
|
|
6127
6060
|
root.addEventListener('dragstart', (event) => {
|
|
6128
6061
|
if (event.target !== event.currentTarget) { return; }
|
|
@@ -6130,23 +6063,21 @@
|
|
|
6130
6063
|
});
|
|
6131
6064
|
root.addEventListener('dragend', dragend);
|
|
6132
6065
|
|
|
6133
|
-
/** @type {(() => void)[]} */
|
|
6134
|
-
const destroyList = [];
|
|
6135
6066
|
root.classList.add('NeeloongForm-tree-item');
|
|
6136
6067
|
|
|
6137
|
-
|
|
6068
|
+
effect(() => {
|
|
6138
6069
|
if (currentStore.get() === store) {
|
|
6139
6070
|
root.classList.add('NeeloongForm-tree-current');
|
|
6140
6071
|
} else {
|
|
6141
6072
|
root.classList.remove('NeeloongForm-tree-current');
|
|
6142
6073
|
}
|
|
6143
|
-
})
|
|
6144
|
-
|
|
6074
|
+
}, options?.signal);
|
|
6075
|
+
effect(() => {
|
|
6145
6076
|
const level = state.get().level;
|
|
6146
6077
|
root.style.setProperty(`--NeeloongForm-tree-level`, `${level}`);
|
|
6147
|
-
})
|
|
6078
|
+
}, options?.signal);
|
|
6148
6079
|
|
|
6149
|
-
|
|
6080
|
+
effect(() => { root.hidden = state.get().hidden; }, options?.signal);
|
|
6150
6081
|
|
|
6151
6082
|
|
|
6152
6083
|
/** @type {HTMLButtonElement[]} */
|
|
@@ -6199,9 +6130,9 @@
|
|
|
6199
6130
|
dropChildren.addEventListener('dragover', (e) => e.preventDefault());
|
|
6200
6131
|
dropFront.addEventListener('drop', () => drop());
|
|
6201
6132
|
dropChildren.addEventListener('drop', () => drop(true));
|
|
6202
|
-
|
|
6133
|
+
effect(() => {
|
|
6203
6134
|
dropFront.hidden = dropChildren.hidden = !state.get().droppable;
|
|
6204
|
-
})
|
|
6135
|
+
}, options?.signal);
|
|
6205
6136
|
|
|
6206
6137
|
let dragleave = () => { };
|
|
6207
6138
|
dropFront.addEventListener('dragenter', () => dragleave = dragenter(dropFront));
|
|
@@ -6218,9 +6149,8 @@
|
|
|
6218
6149
|
if (field) {
|
|
6219
6150
|
const child = store.child(field);
|
|
6220
6151
|
if (!child) { continue; }
|
|
6221
|
-
const
|
|
6222
|
-
|
|
6223
|
-
td.appendChild(el);
|
|
6152
|
+
const el = FormFieldInline(child, fieldRenderer, null, { ...options, editable: false });
|
|
6153
|
+
if (el) { td.appendChild(el); }
|
|
6224
6154
|
continue;
|
|
6225
6155
|
}
|
|
6226
6156
|
if (typeof placeholder === 'number') {
|
|
@@ -6258,9 +6188,9 @@
|
|
|
6258
6188
|
const move = line.appendChild(document.createElement('button'));
|
|
6259
6189
|
move.classList.add('NeeloongForm-tree-move');
|
|
6260
6190
|
move.addEventListener('pointerdown', pointerdown);
|
|
6261
|
-
|
|
6191
|
+
watch(() => store.readonly || store.disabled, disabled => {
|
|
6262
6192
|
move.disabled = disabled;
|
|
6263
|
-
}, true)
|
|
6193
|
+
}, true, options.signal);
|
|
6264
6194
|
continue;
|
|
6265
6195
|
}
|
|
6266
6196
|
case 'add': {
|
|
@@ -6268,9 +6198,9 @@
|
|
|
6268
6198
|
const move = line.appendChild(document.createElement('button'));
|
|
6269
6199
|
move.classList.add('NeeloongForm-tree-add');
|
|
6270
6200
|
move.addEventListener('click', addNode);
|
|
6271
|
-
|
|
6201
|
+
watch(() => store.readonly || store.disabled, disabled => {
|
|
6272
6202
|
move.disabled = disabled;
|
|
6273
|
-
}, true)
|
|
6203
|
+
}, true, options.signal);
|
|
6274
6204
|
continue;
|
|
6275
6205
|
}
|
|
6276
6206
|
case 'remove': {
|
|
@@ -6278,9 +6208,9 @@
|
|
|
6278
6208
|
const del = line.appendChild(document.createElement('button'));
|
|
6279
6209
|
del.classList.add('NeeloongForm-tree-remove');
|
|
6280
6210
|
del.addEventListener('click', remove);
|
|
6281
|
-
|
|
6211
|
+
watch(() => !deletable.get() || store.readonly || store.disabled, disabled => {
|
|
6282
6212
|
del.disabled = disabled;
|
|
6283
|
-
}, true)
|
|
6213
|
+
}, true, options.signal);
|
|
6284
6214
|
continue;
|
|
6285
6215
|
}
|
|
6286
6216
|
case 'serial': {
|
|
@@ -6291,7 +6221,7 @@
|
|
|
6291
6221
|
}
|
|
6292
6222
|
}
|
|
6293
6223
|
}
|
|
6294
|
-
|
|
6224
|
+
effect(() => {
|
|
6295
6225
|
const s = state.get();
|
|
6296
6226
|
if (!s.hasChildren) {
|
|
6297
6227
|
for (const btn of collapseList) {
|
|
@@ -6312,13 +6242,9 @@
|
|
|
6312
6242
|
btn.disabled = false;
|
|
6313
6243
|
}
|
|
6314
6244
|
}
|
|
6315
|
-
})
|
|
6245
|
+
}, options?.signal);
|
|
6316
6246
|
|
|
6317
|
-
return
|
|
6318
|
-
for (const destroy of destroyList) {
|
|
6319
|
-
destroy();
|
|
6320
|
-
}
|
|
6321
|
-
}, s => state.set(s)];
|
|
6247
|
+
return root;
|
|
6322
6248
|
}
|
|
6323
6249
|
|
|
6324
6250
|
/** @import { Store, ArrayStore } from '../Store/index.mjs' */
|
|
@@ -6428,13 +6354,15 @@
|
|
|
6428
6354
|
}
|
|
6429
6355
|
/**
|
|
6430
6356
|
*
|
|
6357
|
+
* @template T
|
|
6431
6358
|
* @param {ArrayStore} store
|
|
6432
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6433
|
-
* @param {StoreLayout.Field
|
|
6359
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6360
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
6434
6361
|
* @param {StoreLayout.Options?} options
|
|
6435
|
-
* @returns {
|
|
6362
|
+
* @returns {HTMLElement?}
|
|
6436
6363
|
*/
|
|
6437
6364
|
function Tree(store, fieldRenderer, layout, options) {
|
|
6365
|
+
if (options?.signal?.aborted) { return null; }
|
|
6438
6366
|
const headerColumns = layout?.columns;
|
|
6439
6367
|
const fieldList = Object.entries(store.type || {})
|
|
6440
6368
|
.filter(([k, v]) => typeof v?.type !== 'object')
|
|
@@ -6488,13 +6416,13 @@
|
|
|
6488
6416
|
|
|
6489
6417
|
|
|
6490
6418
|
const root = document.createElement('div');
|
|
6491
|
-
root.
|
|
6419
|
+
root.classList.add('NeeloongForm-tree');
|
|
6492
6420
|
const main = root.appendChild(document.createElement('div'));
|
|
6493
|
-
main.
|
|
6421
|
+
main.classList.add('NeeloongForm-tree-main');
|
|
6494
6422
|
const splitter = root.appendChild(document.createElement('div'));
|
|
6495
|
-
splitter.
|
|
6423
|
+
splitter.classList.add('NeeloongForm-tree-splitter');
|
|
6496
6424
|
const details = root.appendChild(document.createElement('div'));
|
|
6497
|
-
details.
|
|
6425
|
+
details.classList.add('NeeloongForm-tree-details');
|
|
6498
6426
|
splitter.hidden = true;
|
|
6499
6427
|
details.hidden = true;
|
|
6500
6428
|
/** @type {number?} */
|
|
@@ -6558,9 +6486,8 @@
|
|
|
6558
6486
|
});
|
|
6559
6487
|
|
|
6560
6488
|
|
|
6561
|
-
/** @type {
|
|
6562
|
-
|
|
6563
|
-
let destroyDetails = () => { };
|
|
6489
|
+
/** @type {AbortController?} */
|
|
6490
|
+
let detailAbortController = null;
|
|
6564
6491
|
const detailsStore = new exports.Signal.State(/** @type{Store<any, any>?}*/(null));
|
|
6565
6492
|
/**
|
|
6566
6493
|
*
|
|
@@ -6568,25 +6495,36 @@
|
|
|
6568
6495
|
* @returns
|
|
6569
6496
|
*/
|
|
6570
6497
|
function createDetails(store) {
|
|
6571
|
-
if (
|
|
6572
|
-
|
|
6498
|
+
if (options?.signal?.aborted) { return () => { }; }
|
|
6499
|
+
if (detailsStore.get() === store && detailAbortController) {
|
|
6500
|
+
const ac = detailAbortController;
|
|
6501
|
+
return () => { ac.abort(); };
|
|
6502
|
+
}
|
|
6503
|
+
detailAbortController?.abort();
|
|
6573
6504
|
detailsStore.set(store);
|
|
6574
|
-
const
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6505
|
+
const ac = new AbortController();
|
|
6506
|
+
detailAbortController = ac;
|
|
6507
|
+
const signal = options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal;
|
|
6508
|
+
const form = Form(store, fieldRenderer, layout, {
|
|
6509
|
+
...options,
|
|
6510
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, signal]) : signal,
|
|
6511
|
+
});
|
|
6512
|
+
signal.addEventListener('abort', () => {
|
|
6582
6513
|
detailsStore.set(null);
|
|
6583
|
-
form.remove();
|
|
6584
|
-
destroy();
|
|
6585
6514
|
stopMove();
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6515
|
+
}, { once: true });
|
|
6516
|
+
if (form) {
|
|
6517
|
+
details.appendChild(form);
|
|
6518
|
+
details.hidden = false;
|
|
6519
|
+
splitter.hidden = false;
|
|
6520
|
+
signal.addEventListener('abort', () => {
|
|
6521
|
+
form.remove();
|
|
6522
|
+
splitter.hidden = true;
|
|
6523
|
+
details.hidden = true;
|
|
6524
|
+
}, { once: true });
|
|
6525
|
+
|
|
6526
|
+
}
|
|
6527
|
+
return () => { ac.abort(); };
|
|
6590
6528
|
|
|
6591
6529
|
}
|
|
6592
6530
|
|
|
@@ -6722,7 +6660,7 @@
|
|
|
6722
6660
|
const button = main.appendChild(document.createElement('button'));
|
|
6723
6661
|
button.addEventListener('click', () => addNode(-1));
|
|
6724
6662
|
button.classList.add('NeeloongForm-tree-head-add');
|
|
6725
|
-
|
|
6663
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options.signal);
|
|
6726
6664
|
}
|
|
6727
6665
|
const start = main.appendChild(document.createComment(''));
|
|
6728
6666
|
if (options?.editable) {
|
|
@@ -6742,21 +6680,13 @@
|
|
|
6742
6680
|
dropFront.addEventListener('drop', () => drop());
|
|
6743
6681
|
|
|
6744
6682
|
|
|
6745
|
-
|
|
6683
|
+
watch(() => !addable.get(), disabled => { button.disabled = disabled; }, true, options.signal);
|
|
6746
6684
|
}
|
|
6747
|
-
/** @type {Map<Store, [HTMLElement,
|
|
6685
|
+
/** @type {Map<Store, [tbody: HTMLElement, AbortController, (s: State) => void]>} */
|
|
6748
6686
|
let seMap = new Map();
|
|
6749
|
-
/** @param {Map<Store, [tbody: HTMLElement, destroy: () => void, (s: State) => void]>} map */
|
|
6750
|
-
function destroyMap(map) {
|
|
6751
|
-
for (const [el, destroy] of map.values()) {
|
|
6752
|
-
destroy();
|
|
6753
|
-
el.remove();
|
|
6754
|
-
}
|
|
6755
|
-
|
|
6756
|
-
}
|
|
6757
6687
|
/** @type {State[]} */
|
|
6758
6688
|
const states = [];
|
|
6759
|
-
|
|
6689
|
+
watch(() => store.children, children => {
|
|
6760
6690
|
let nextNode = start.nextSibling;
|
|
6761
6691
|
const oldSeMap = seMap;
|
|
6762
6692
|
seMap = new Map();
|
|
@@ -6771,7 +6701,9 @@
|
|
|
6771
6701
|
const state = states[i];
|
|
6772
6702
|
const old = oldSeMap.get(child);
|
|
6773
6703
|
if (!old) {
|
|
6774
|
-
const
|
|
6704
|
+
const elState = new exports.Signal.State(state);
|
|
6705
|
+
const ac = new AbortController();
|
|
6706
|
+
const el = TreeLine(child, detailsStore, fieldRenderer, layout, elState, {
|
|
6775
6707
|
columns,
|
|
6776
6708
|
remove: remove.bind(null, child),
|
|
6777
6709
|
dragenter,
|
|
@@ -6781,9 +6713,12 @@
|
|
|
6781
6713
|
addNode: () => addNode(Number(child.index)),
|
|
6782
6714
|
createDetails,
|
|
6783
6715
|
drop: drop.bind(null, child),
|
|
6784
|
-
},
|
|
6716
|
+
}, {
|
|
6717
|
+
...options,
|
|
6718
|
+
signal: options?.signal ? AbortSignal.any([options?.signal, ac.signal]) : ac.signal,
|
|
6719
|
+
});
|
|
6785
6720
|
main.insertBefore(el, nextNode);
|
|
6786
|
-
seMap.set(child, [el,
|
|
6721
|
+
seMap.set(child, [el, ac, s => elState.set(s)]);
|
|
6787
6722
|
continue;
|
|
6788
6723
|
}
|
|
6789
6724
|
oldSeMap.delete(child);
|
|
@@ -6796,77 +6731,78 @@
|
|
|
6796
6731
|
main.insertBefore(old[0], nextNode);
|
|
6797
6732
|
}
|
|
6798
6733
|
states.splice(childrenLength);
|
|
6799
|
-
|
|
6800
|
-
|
|
6734
|
+
for (const [el, ac] of oldSeMap.values()) {
|
|
6735
|
+
el.remove();
|
|
6736
|
+
ac.abort();
|
|
6737
|
+
}
|
|
6738
|
+
}, true, options?.signal);
|
|
6801
6739
|
|
|
6802
|
-
return
|
|
6803
|
-
start.remove();
|
|
6804
|
-
destroyMap(seMap);
|
|
6805
|
-
childrenResult();
|
|
6806
|
-
destroyDetails?.();
|
|
6807
|
-
for (const destroy of destroyList) {
|
|
6808
|
-
destroy();
|
|
6809
|
-
}
|
|
6810
|
-
}];
|
|
6740
|
+
return root;
|
|
6811
6741
|
}
|
|
6812
6742
|
|
|
6813
6743
|
/**
|
|
6814
6744
|
*
|
|
6745
|
+
* @template T
|
|
6815
6746
|
* @param {string | ParentNode} html
|
|
6816
6747
|
* @param {Store<any, any>} store
|
|
6817
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6748
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6818
6749
|
* @param {StoreLayout.Options?} options
|
|
6819
|
-
* @param {StoreLayout.Field
|
|
6820
|
-
* @returns
|
|
6750
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
6751
|
+
* @returns {ParentNode}
|
|
6821
6752
|
*/
|
|
6822
6753
|
function Html(html, store, fieldRenderer, options, layout) {
|
|
6823
6754
|
const htmlContent = getHtmlContent(html);
|
|
6824
|
-
|
|
6825
|
-
return
|
|
6755
|
+
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6756
|
+
return htmlContent;
|
|
6826
6757
|
}
|
|
6827
|
-
|
|
6828
6758
|
/**
|
|
6829
6759
|
*
|
|
6830
|
-
* @
|
|
6760
|
+
* @template T
|
|
6761
|
+
* @param {StoreLayout.Field<T>['arrayStyle']?} arrayStyle
|
|
6762
|
+
* @param {ArrayStore} store
|
|
6763
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6764
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
6765
|
+
* @param {StoreLayout.Options?} options
|
|
6766
|
+
* @returns {HTMLElement?}
|
|
6831
6767
|
*/
|
|
6832
|
-
function
|
|
6833
|
-
switch(arrayStyle) {
|
|
6834
|
-
case 'tree': return Tree;
|
|
6835
|
-
default: return Table;
|
|
6768
|
+
function renderArrayCell(arrayStyle, store, fieldRenderer, layout, options) {
|
|
6769
|
+
switch (arrayStyle) {
|
|
6770
|
+
case 'tree': return Tree(store, fieldRenderer, layout, options);
|
|
6771
|
+
default: return Table(store, fieldRenderer, layout, options);
|
|
6836
6772
|
}
|
|
6837
6773
|
|
|
6838
6774
|
}
|
|
6839
6775
|
|
|
6840
6776
|
/**
|
|
6841
6777
|
*
|
|
6778
|
+
* @template T
|
|
6842
6779
|
* @param {Store<any, any>} store
|
|
6843
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6844
|
-
* @param {StoreLayout.Field
|
|
6780
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6781
|
+
* @param {StoreLayout.Field<T>?} layout
|
|
6845
6782
|
* @param {StoreLayout.Options?} options
|
|
6846
|
-
* @returns {
|
|
6783
|
+
* @returns {ParentNode}
|
|
6847
6784
|
*/
|
|
6848
6785
|
function FormField(store, fieldRenderer, layout, options) {
|
|
6849
6786
|
const { type } = store;
|
|
6850
|
-
const isObject = type && typeof type === 'object';
|
|
6787
|
+
const isObject = Boolean(type && typeof type === 'object');
|
|
6851
6788
|
const html = layout?.html;
|
|
6852
6789
|
/** @type {StoreLayout.Grid['cell']} */
|
|
6853
6790
|
const cellType = isObject
|
|
6854
6791
|
? store instanceof ArrayStore ? 'collapse' : 'fieldset'
|
|
6855
6792
|
: html ? 'base' : 'inline';
|
|
6856
|
-
const [root,
|
|
6857
|
-
|
|
6793
|
+
const [root, content] = createCell(options?.signal, layout, store, cellType, isObject);
|
|
6794
|
+
effect(() => root.hidden = store.hidden, options?.signal);
|
|
6858
6795
|
|
|
6796
|
+
/** @type {false | ParentNode | null} */
|
|
6859
6797
|
const r =
|
|
6860
6798
|
html && Html(html, store, fieldRenderer, options, layout)
|
|
6861
|
-
|| fieldRenderer(store, options)
|
|
6862
|
-
|| store instanceof ArrayStore &&
|
|
6799
|
+
|| fieldRenderer(store, layout?.renderer, options)
|
|
6800
|
+
|| store instanceof ArrayStore && renderArrayCell(layout?.arrayStyle, store, fieldRenderer, layout, options)
|
|
6863
6801
|
|| isObject && Form(store, fieldRenderer, layout, options);
|
|
6864
6802
|
if (r) {
|
|
6865
|
-
|
|
6866
|
-
content.appendChild(el);
|
|
6867
|
-
destroyList.push(destroy);
|
|
6803
|
+
content.appendChild(r);
|
|
6868
6804
|
}
|
|
6869
|
-
return
|
|
6805
|
+
return root;
|
|
6870
6806
|
}
|
|
6871
6807
|
|
|
6872
6808
|
/** @import { Store } from '../Store/index.mjs' */
|
|
@@ -6877,22 +6813,22 @@
|
|
|
6877
6813
|
* @param {Store<any, any>} store
|
|
6878
6814
|
* @param {StoreLayout.Button} layout
|
|
6879
6815
|
* @param {StoreLayout.Options?} options
|
|
6880
|
-
* @returns {
|
|
6816
|
+
* @returns {ParentNode}
|
|
6881
6817
|
*/
|
|
6882
6818
|
function FormButton(store, layout, options) {
|
|
6883
|
-
const [root,
|
|
6819
|
+
const [root, content] = createCell(options?.signal, layout, store);
|
|
6884
6820
|
const button = document.createElement('button');
|
|
6885
|
-
|
|
6821
|
+
effect(() => {
|
|
6886
6822
|
const t = layout.text;
|
|
6887
6823
|
const text = typeof t === 'function' ? t(store, options) : t;
|
|
6888
6824
|
button.innerText = text ?? '';
|
|
6889
|
-
});
|
|
6890
|
-
|
|
6825
|
+
}, options?.signal);
|
|
6826
|
+
effect(() => {
|
|
6891
6827
|
const d = layout.disabled;
|
|
6892
6828
|
const disabled = typeof d === 'function' ? d(store, options) : d;
|
|
6893
6829
|
button.disabled = Boolean(disabled);
|
|
6894
|
-
});
|
|
6895
|
-
button.
|
|
6830
|
+
}, options?.signal);
|
|
6831
|
+
button.classList.add('NeeloongForm-item-button');
|
|
6896
6832
|
content.appendChild(button);
|
|
6897
6833
|
const click = layout.click;
|
|
6898
6834
|
if (typeof click === 'function') {
|
|
@@ -6903,7 +6839,7 @@
|
|
|
6903
6839
|
button.addEventListener('click', e => call(click, e, store, options));
|
|
6904
6840
|
}
|
|
6905
6841
|
}
|
|
6906
|
-
return
|
|
6842
|
+
return root;
|
|
6907
6843
|
}
|
|
6908
6844
|
|
|
6909
6845
|
/** @import { Store } from '../Store/index.mjs' */
|
|
@@ -6911,20 +6847,21 @@
|
|
|
6911
6847
|
|
|
6912
6848
|
/**
|
|
6913
6849
|
*
|
|
6850
|
+
* @template T
|
|
6914
6851
|
* @param {Store<any, any>} store
|
|
6915
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6852
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6916
6853
|
* @param {StoreLayout.Html} layout
|
|
6917
6854
|
* @param {StoreLayout.Options?} options
|
|
6918
|
-
* @returns {
|
|
6855
|
+
* @returns {ParentNode?}
|
|
6919
6856
|
*/
|
|
6920
6857
|
function FormHtml(store, fieldRenderer, layout, options) {
|
|
6921
|
-
const [root, destroy, content, destroyList] = createCell(layout, store);
|
|
6922
6858
|
const html = layout.html;
|
|
6923
|
-
if (!html) { return
|
|
6859
|
+
if (!html) { return null; }
|
|
6860
|
+
const [root, content] = createCell(options?.signal, layout, store);
|
|
6924
6861
|
const htmlContent = getHtmlContent(html);
|
|
6925
|
-
|
|
6862
|
+
renderHtml(store, fieldRenderer, htmlContent, options, layout);
|
|
6926
6863
|
content.appendChild(htmlContent);
|
|
6927
|
-
return
|
|
6864
|
+
return root;
|
|
6928
6865
|
}
|
|
6929
6866
|
|
|
6930
6867
|
/** @import { Store } from '../Store/index.mjs' */
|
|
@@ -6932,11 +6869,12 @@
|
|
|
6932
6869
|
|
|
6933
6870
|
/**
|
|
6934
6871
|
*
|
|
6872
|
+
* @template T
|
|
6935
6873
|
* @param {Store<any, any>} store
|
|
6936
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6937
|
-
* @param {StoreLayout.Item} item
|
|
6874
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6875
|
+
* @param {StoreLayout.Item<T>} item
|
|
6938
6876
|
* @param {StoreLayout.Options?} options
|
|
6939
|
-
* @returns {
|
|
6877
|
+
* @returns {ParentNode?}
|
|
6940
6878
|
*/
|
|
6941
6879
|
function FormItem(store, fieldRenderer, item, options) {
|
|
6942
6880
|
if (item.type === 'button') {
|
|
@@ -6954,40 +6892,32 @@
|
|
|
6954
6892
|
|
|
6955
6893
|
/**
|
|
6956
6894
|
*
|
|
6895
|
+
* @template T
|
|
6957
6896
|
* @param {Store<any, any>} store
|
|
6958
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6959
|
-
* @param {StoreLayout
|
|
6897
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
6898
|
+
* @param {StoreLayout<T>?} layout
|
|
6960
6899
|
* @param {StoreLayout.Options?} options
|
|
6961
6900
|
* @param {HTMLElement} [parent]
|
|
6962
|
-
* @returns {
|
|
6901
|
+
* @returns {HTMLElement?}
|
|
6963
6902
|
*/
|
|
6964
6903
|
function Form(store, fieldRenderer, layout, options, parent) {
|
|
6904
|
+
if (options?.signal?.aborted) { return null; }
|
|
6965
6905
|
const root = parent instanceof HTMLElement ? parent : document.createElement('div');
|
|
6966
|
-
root.
|
|
6967
|
-
/** @type {(() => void)[]} */
|
|
6968
|
-
const destroyList = [];
|
|
6906
|
+
root.classList.add('NeeloongForm');
|
|
6969
6907
|
const fieldLayouts = layout?.fields;
|
|
6970
6908
|
if (fieldLayouts) {
|
|
6971
6909
|
for (const fieldTemplate of fieldLayouts) {
|
|
6972
|
-
const
|
|
6973
|
-
if (
|
|
6974
|
-
const [el, destroy] = result;
|
|
6975
|
-
root.appendChild(el);
|
|
6976
|
-
destroyList.push(destroy);
|
|
6910
|
+
const el = FormItem(store, fieldRenderer, fieldTemplate, options);
|
|
6911
|
+
if (el) { root.appendChild(el); }
|
|
6977
6912
|
}
|
|
6978
6913
|
} else {
|
|
6979
6914
|
const fields = [...store].map(([, v]) => v);
|
|
6980
6915
|
for (const field of fields) {
|
|
6981
|
-
const
|
|
6982
|
-
root.appendChild(el);
|
|
6983
|
-
destroyList.push(destroy);
|
|
6916
|
+
const el = FormField(field, fieldRenderer, null, options);
|
|
6917
|
+
if (el) { root.appendChild(el); }
|
|
6984
6918
|
}
|
|
6985
6919
|
}
|
|
6986
|
-
return
|
|
6987
|
-
for (const destroy of destroyList) {
|
|
6988
|
-
destroy();
|
|
6989
|
-
}
|
|
6990
|
-
}];
|
|
6920
|
+
return root;
|
|
6991
6921
|
|
|
6992
6922
|
}
|
|
6993
6923
|
|
|
@@ -6996,22 +6926,27 @@
|
|
|
6996
6926
|
|
|
6997
6927
|
/**
|
|
6998
6928
|
*
|
|
6929
|
+
* @template T
|
|
6999
6930
|
* @param {Store} store
|
|
7000
|
-
* @param {StoreLayout.Renderer} fieldRenderer
|
|
6931
|
+
* @param {StoreLayout.Renderer<T>} fieldRenderer
|
|
7001
6932
|
* @param {HTMLElement} root
|
|
7002
|
-
* @param {StoreLayout
|
|
6933
|
+
* @param {StoreLayout<T>?} [layout]
|
|
7003
6934
|
* @param {StoreLayout.Options & {clone?: boolean} | null} [options]
|
|
6935
|
+
* @returns {void}
|
|
7004
6936
|
*/
|
|
7005
6937
|
function renderStore(store, fieldRenderer, root, layout, options) {
|
|
6938
|
+
if (options?.signal?.aborted) { return; }
|
|
7006
6939
|
const html = layout?.html;
|
|
7007
|
-
if (html) {
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
6940
|
+
if (!html) {
|
|
6941
|
+
Form(store, fieldRenderer, layout || null, options || null, root);
|
|
6942
|
+
return;
|
|
6943
|
+
}
|
|
6944
|
+
const content = getHtmlContent(html);
|
|
6945
|
+
renderHtml(store, fieldRenderer, content, options || null, layout);
|
|
6946
|
+
root.appendChild(content);
|
|
6947
|
+
options?.signal?.addEventListener('abort', () => {
|
|
6948
|
+
root.removeChild(content);
|
|
6949
|
+
}, { once: true });
|
|
7015
6950
|
}
|
|
7016
6951
|
|
|
7017
6952
|
exports.ArrayStore = ArrayStore;
|