@liedekef/ftable 1.2.0 → 1.3.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/ftable.esm.js +107 -32
- package/ftable.js +107 -32
- package/ftable.min.js +2 -2
- package/ftable.umd.js +107 -32
- package/package.json +1 -1
package/ftable.esm.js
CHANGED
|
@@ -1413,9 +1413,7 @@ class FTableFormBuilder {
|
|
|
1413
1413
|
: [];
|
|
1414
1414
|
|
|
1415
1415
|
// Support data-livesearch attribute on the virtual select as well as field.livesearch
|
|
1416
|
-
const livesearch = field.livesearch
|
|
1417
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
1418
|
-
?? false;
|
|
1416
|
+
const livesearch = field.livesearch ?? false;
|
|
1419
1417
|
|
|
1420
1418
|
return this._buildCustomMultiSelect({
|
|
1421
1419
|
containerId: fieldName,
|
|
@@ -2187,7 +2185,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2187
2185
|
initColumnWidths() {
|
|
2188
2186
|
const visibleFields = this.columnList.filter(fieldName => {
|
|
2189
2187
|
const field = this.options.fields[fieldName];
|
|
2190
|
-
return field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2188
|
+
return !field.action && field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2191
2189
|
});
|
|
2192
2190
|
|
|
2193
2191
|
const count = visibleFields.length;
|
|
@@ -2206,7 +2204,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2206
2204
|
th: this.elements.table.querySelector(`[data-field-name="${fieldName}"]`),
|
|
2207
2205
|
field: this.options.fields[fieldName]
|
|
2208
2206
|
}))
|
|
2209
|
-
.filter(item => item.th && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2207
|
+
.filter(item => item.th && !item.field.action && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2210
2208
|
|
|
2211
2209
|
if (visibleHeaders.length === 0) return;
|
|
2212
2210
|
|
|
@@ -2341,8 +2339,17 @@ class FTable extends FTableEventEmitter {
|
|
|
2341
2339
|
this.fieldList.forEach(fieldName => {
|
|
2342
2340
|
const field = this.options.fields[fieldName];
|
|
2343
2341
|
const isKeyField = field.key === true;
|
|
2344
|
-
|
|
2345
|
-
|
|
2342
|
+
const isActionField = !!field.action; // action: 'select' | 'update' | 'clone' | 'delete'
|
|
2343
|
+
|
|
2344
|
+
if (isActionField) {
|
|
2345
|
+
// Action columns are always listed but never part of forms or sorting
|
|
2346
|
+
field.list = true;
|
|
2347
|
+
field.create = false;
|
|
2348
|
+
field.edit = false;
|
|
2349
|
+
field.sorting = false;
|
|
2350
|
+
field.searchable = false;
|
|
2351
|
+
field.visibility = field.visibility ?? 'visible';
|
|
2352
|
+
} else if (isKeyField) {
|
|
2346
2353
|
if (field.create === undefined || !field.create) {
|
|
2347
2354
|
field.create = true;
|
|
2348
2355
|
field.type = 'hidden';
|
|
@@ -2367,6 +2374,13 @@ class FTable extends FTableEventEmitter {
|
|
|
2367
2374
|
return field.list !== false;
|
|
2368
2375
|
});
|
|
2369
2376
|
|
|
2377
|
+
// Track which actions are user-placed (via action columns in fields)
|
|
2378
|
+
this._userPlacedActions = new Set(
|
|
2379
|
+
this.fieldList
|
|
2380
|
+
.filter(name => this.options.fields[name].action)
|
|
2381
|
+
.map(name => this.options.fields[name].action)
|
|
2382
|
+
);
|
|
2383
|
+
|
|
2370
2384
|
// Find key field
|
|
2371
2385
|
this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
|
|
2372
2386
|
if (!this.keyField) {
|
|
@@ -2377,6 +2391,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2377
2391
|
async resolveAsyncFieldOptions() {
|
|
2378
2392
|
const promises = this.columnList.map(async (fieldName) => {
|
|
2379
2393
|
const field = this.options.fields[fieldName];
|
|
2394
|
+
if (field.action) return; // Skip action columns
|
|
2380
2395
|
const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName);
|
|
2381
2396
|
|
|
2382
2397
|
if (this.formBuilder.shouldResolveOptions(originalOptions)) {
|
|
@@ -2402,7 +2417,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2402
2417
|
for (const row of rows) {
|
|
2403
2418
|
for (const fieldName of this.columnList) {
|
|
2404
2419
|
const field = this.options.fields[fieldName];
|
|
2405
|
-
if (!field.options) continue;
|
|
2420
|
+
if (field.action || !field.options) continue;
|
|
2406
2421
|
|
|
2407
2422
|
const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
|
|
2408
2423
|
if (!cell) continue;
|
|
@@ -2473,8 +2488,8 @@ class FTable extends FTableEventEmitter {
|
|
|
2473
2488
|
parent: thead
|
|
2474
2489
|
});
|
|
2475
2490
|
|
|
2476
|
-
// Add selecting column if enabled
|
|
2477
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2491
|
+
// Add selecting column if enabled (only if not user-placed)
|
|
2492
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2478
2493
|
const selectHeader = FTableDOMHelper.create('th', {
|
|
2479
2494
|
className: `ftable-command-column-header ftable-column-header-select`,
|
|
2480
2495
|
parent: headerRow
|
|
@@ -2492,9 +2507,41 @@ class FTable extends FTableEventEmitter {
|
|
|
2492
2507
|
}
|
|
2493
2508
|
}
|
|
2494
2509
|
|
|
2495
|
-
// Add data columns
|
|
2510
|
+
// Add data columns (including any user-placed action columns)
|
|
2496
2511
|
this.columnList.forEach(fieldName => {
|
|
2497
2512
|
const field = this.options.fields[fieldName];
|
|
2513
|
+
|
|
2514
|
+
// If this column is a user-placed action column, render an action header
|
|
2515
|
+
if (field.action) {
|
|
2516
|
+
const actionClassMap = {
|
|
2517
|
+
select: 'ftable-column-header-select',
|
|
2518
|
+
update: 'ftable-column-header-edit',
|
|
2519
|
+
clone: 'ftable-column-header-clone',
|
|
2520
|
+
delete: 'ftable-column-header-delete',
|
|
2521
|
+
};
|
|
2522
|
+
const th = FTableDOMHelper.create('th', {
|
|
2523
|
+
className: `ftable-command-column-header ${actionClassMap[field.action] || ''}`,
|
|
2524
|
+
parent: headerRow
|
|
2525
|
+
});
|
|
2526
|
+
if (field.title) {
|
|
2527
|
+
th.textContent = field.title;
|
|
2528
|
+
}
|
|
2529
|
+
// For select action with multiselect, add the select-all checkbox
|
|
2530
|
+
if (field.action === 'select' && this.options.selecting && this.options.selectingCheckboxes && this.options.multiselect) {
|
|
2531
|
+
const selectAllCheckbox = FTableDOMHelper.create('input', {
|
|
2532
|
+
attributes: { type: 'checkbox' },
|
|
2533
|
+
parent: th
|
|
2534
|
+
});
|
|
2535
|
+
selectAllCheckbox.addEventListener('change', () => {
|
|
2536
|
+
this.toggleSelectAll(selectAllCheckbox.checked);
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
if (field.width) {
|
|
2540
|
+
th.style.width = field.width;
|
|
2541
|
+
}
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2498
2545
|
const th = FTableDOMHelper.create('th', {
|
|
2499
2546
|
className: `ftable-column-header ${field.listClass || ''} ${field.listClassHeader || ''}`,
|
|
2500
2547
|
attributes: { 'data-field-name': fieldName },
|
|
@@ -2543,22 +2590,22 @@ class FTable extends FTableEventEmitter {
|
|
|
2543
2590
|
}
|
|
2544
2591
|
});
|
|
2545
2592
|
|
|
2546
|
-
// Add action columns
|
|
2547
|
-
if (this.options.actions.updateAction) {
|
|
2593
|
+
// Add default action columns only if not user-placed
|
|
2594
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
2548
2595
|
FTableDOMHelper.create('th', {
|
|
2549
2596
|
className: 'ftable-command-column-header ftable-column-header-edit',
|
|
2550
2597
|
parent: headerRow
|
|
2551
2598
|
});
|
|
2552
2599
|
}
|
|
2553
2600
|
|
|
2554
|
-
if (this.options.actions.cloneAction) {
|
|
2601
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
2555
2602
|
FTableDOMHelper.create('th', {
|
|
2556
2603
|
className: 'ftable-command-column-header ftable-column-header-clone',
|
|
2557
2604
|
parent: headerRow
|
|
2558
2605
|
});
|
|
2559
2606
|
}
|
|
2560
2607
|
|
|
2561
|
-
if (this.options.actions.deleteAction) {
|
|
2608
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
2562
2609
|
FTableDOMHelper.create('th', {
|
|
2563
2610
|
className: 'ftable-command-column-header ftable-column-header-delete',
|
|
2564
2611
|
parent: headerRow
|
|
@@ -2579,17 +2626,27 @@ class FTable extends FTableEventEmitter {
|
|
|
2579
2626
|
parent: theadParent
|
|
2580
2627
|
});
|
|
2581
2628
|
|
|
2582
|
-
// Add empty cell for selecting column if enabled
|
|
2583
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2629
|
+
// Add empty cell for selecting column if enabled (only if not user-placed)
|
|
2630
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2584
2631
|
FTableDOMHelper.create('th', {
|
|
2585
2632
|
className: 'ftable-toolbarsearch-column-header',
|
|
2586
2633
|
parent: searchRow
|
|
2587
2634
|
});
|
|
2588
2635
|
}
|
|
2589
2636
|
|
|
2590
|
-
// Add search input cells for data columns
|
|
2637
|
+
// Add search input cells for data columns (including user-placed action columns)
|
|
2591
2638
|
for (const fieldName of this.columnList) {
|
|
2592
2639
|
const field = this.options.fields[fieldName];
|
|
2640
|
+
|
|
2641
|
+
// Action columns get an empty search cell
|
|
2642
|
+
if (field.action) {
|
|
2643
|
+
FTableDOMHelper.create('th', {
|
|
2644
|
+
className: 'ftable-toolbarsearch-column-header ftable-command-column-header',
|
|
2645
|
+
parent: searchRow
|
|
2646
|
+
});
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2593
2650
|
const isSearchable = field.searchable !== false;
|
|
2594
2651
|
|
|
2595
2652
|
const th = FTableDOMHelper.create('th', {
|
|
@@ -2761,9 +2818,9 @@ class FTable extends FTableEventEmitter {
|
|
|
2761
2818
|
parent: searchRow
|
|
2762
2819
|
});
|
|
2763
2820
|
|
|
2764
|
-
const actionCount = (this.options.actions.updateAction ? 1 : 0) +
|
|
2765
|
-
(this.options.actions.deleteAction ? 1 : 0) +
|
|
2766
|
-
(this.options.actions.cloneAction ? 1 : 0);
|
|
2821
|
+
const actionCount = (this.options.actions.updateAction && !this._userPlacedActions.has('update') ? 1 : 0) +
|
|
2822
|
+
(this.options.actions.deleteAction && !this._userPlacedActions.has('delete') ? 1 : 0) +
|
|
2823
|
+
(this.options.actions.cloneAction && !this._userPlacedActions.has('clone') ? 1 : 0);
|
|
2767
2824
|
|
|
2768
2825
|
if (actionCount > 0) {
|
|
2769
2826
|
resetTh.colSpan = actionCount;
|
|
@@ -2871,9 +2928,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2871
2928
|
}
|
|
2872
2929
|
|
|
2873
2930
|
createCustomMultiSelectForSearch(fieldSearchName, fieldName, field, optionsSource, attributes) {
|
|
2874
|
-
const livesearch = field.livesearch
|
|
2875
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
2876
|
-
?? false;
|
|
2931
|
+
const livesearch = field.livesearch ?? false;
|
|
2877
2932
|
|
|
2878
2933
|
return this.formBuilder._buildCustomMultiSelect({
|
|
2879
2934
|
hiddenSelectId: fieldSearchName,
|
|
@@ -3450,6 +3505,7 @@ class FTable extends FTableEventEmitter {
|
|
|
3450
3505
|
|
|
3451
3506
|
this.columnList.forEach(fieldName => {
|
|
3452
3507
|
const field = this.options.fields[fieldName];
|
|
3508
|
+
if (field.action) return; // Action columns don't appear in column picker
|
|
3453
3509
|
const isVisible = field.visibility !== 'hidden';
|
|
3454
3510
|
const isFixed = field.visibility === 'fixed';
|
|
3455
3511
|
const isSeparator = field.visibility === 'separator';
|
|
@@ -3862,26 +3918,45 @@ class FTable extends FTableEventEmitter {
|
|
|
3862
3918
|
// Store record data
|
|
3863
3919
|
row.recordData = record;
|
|
3864
3920
|
|
|
3865
|
-
// Add selecting checkbox if enabled
|
|
3866
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
3921
|
+
// Add selecting checkbox if enabled (only if not user-placed)
|
|
3922
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
3867
3923
|
this.addSelectingCell(row);
|
|
3868
3924
|
}
|
|
3869
3925
|
|
|
3870
|
-
// Add data cells
|
|
3926
|
+
// Add data cells (including user-placed action columns)
|
|
3871
3927
|
this.columnList.forEach(fieldName => {
|
|
3872
|
-
this.
|
|
3928
|
+
const field = this.options.fields[fieldName];
|
|
3929
|
+
if (field.action) {
|
|
3930
|
+
// Render inline action cell
|
|
3931
|
+
switch (field.action) {
|
|
3932
|
+
case 'select':
|
|
3933
|
+
this.addSelectingCell(row);
|
|
3934
|
+
break;
|
|
3935
|
+
case 'update':
|
|
3936
|
+
this.addEditCell(row);
|
|
3937
|
+
break;
|
|
3938
|
+
case 'clone':
|
|
3939
|
+
this.addCloneCell(row);
|
|
3940
|
+
break;
|
|
3941
|
+
case 'delete':
|
|
3942
|
+
this.addDeleteCell(row);
|
|
3943
|
+
break;
|
|
3944
|
+
}
|
|
3945
|
+
} else {
|
|
3946
|
+
this.addDataCell(row, record, fieldName);
|
|
3947
|
+
}
|
|
3873
3948
|
});
|
|
3874
3949
|
|
|
3875
|
-
// Add action cells
|
|
3876
|
-
if (this.options.actions.updateAction) {
|
|
3950
|
+
// Add default action cells only if not user-placed
|
|
3951
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
3877
3952
|
this.addEditCell(row);
|
|
3878
3953
|
}
|
|
3879
3954
|
|
|
3880
|
-
if (this.options.actions.cloneAction) {
|
|
3955
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
3881
3956
|
this.addCloneCell(row);
|
|
3882
3957
|
}
|
|
3883
3958
|
|
|
3884
|
-
if (this.options.actions.deleteAction) {
|
|
3959
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
3885
3960
|
this.addDeleteCell(row);
|
|
3886
3961
|
}
|
|
3887
3962
|
|
package/ftable.js
CHANGED
|
@@ -1414,9 +1414,7 @@ class FTableFormBuilder {
|
|
|
1414
1414
|
: [];
|
|
1415
1415
|
|
|
1416
1416
|
// Support data-livesearch attribute on the virtual select as well as field.livesearch
|
|
1417
|
-
const livesearch = field.livesearch
|
|
1418
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
1419
|
-
?? false;
|
|
1417
|
+
const livesearch = field.livesearch ?? false;
|
|
1420
1418
|
|
|
1421
1419
|
return this._buildCustomMultiSelect({
|
|
1422
1420
|
containerId: fieldName,
|
|
@@ -2188,7 +2186,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2188
2186
|
initColumnWidths() {
|
|
2189
2187
|
const visibleFields = this.columnList.filter(fieldName => {
|
|
2190
2188
|
const field = this.options.fields[fieldName];
|
|
2191
|
-
return field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2189
|
+
return !field.action && field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2192
2190
|
});
|
|
2193
2191
|
|
|
2194
2192
|
const count = visibleFields.length;
|
|
@@ -2207,7 +2205,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2207
2205
|
th: this.elements.table.querySelector(`[data-field-name="${fieldName}"]`),
|
|
2208
2206
|
field: this.options.fields[fieldName]
|
|
2209
2207
|
}))
|
|
2210
|
-
.filter(item => item.th && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2208
|
+
.filter(item => item.th && !item.field.action && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2211
2209
|
|
|
2212
2210
|
if (visibleHeaders.length === 0) return;
|
|
2213
2211
|
|
|
@@ -2342,8 +2340,17 @@ class FTable extends FTableEventEmitter {
|
|
|
2342
2340
|
this.fieldList.forEach(fieldName => {
|
|
2343
2341
|
const field = this.options.fields[fieldName];
|
|
2344
2342
|
const isKeyField = field.key === true;
|
|
2345
|
-
|
|
2346
|
-
|
|
2343
|
+
const isActionField = !!field.action; // action: 'select' | 'update' | 'clone' | 'delete'
|
|
2344
|
+
|
|
2345
|
+
if (isActionField) {
|
|
2346
|
+
// Action columns are always listed but never part of forms or sorting
|
|
2347
|
+
field.list = true;
|
|
2348
|
+
field.create = false;
|
|
2349
|
+
field.edit = false;
|
|
2350
|
+
field.sorting = false;
|
|
2351
|
+
field.searchable = false;
|
|
2352
|
+
field.visibility = field.visibility ?? 'visible';
|
|
2353
|
+
} else if (isKeyField) {
|
|
2347
2354
|
if (field.create === undefined || !field.create) {
|
|
2348
2355
|
field.create = true;
|
|
2349
2356
|
field.type = 'hidden';
|
|
@@ -2368,6 +2375,13 @@ class FTable extends FTableEventEmitter {
|
|
|
2368
2375
|
return field.list !== false;
|
|
2369
2376
|
});
|
|
2370
2377
|
|
|
2378
|
+
// Track which actions are user-placed (via action columns in fields)
|
|
2379
|
+
this._userPlacedActions = new Set(
|
|
2380
|
+
this.fieldList
|
|
2381
|
+
.filter(name => this.options.fields[name].action)
|
|
2382
|
+
.map(name => this.options.fields[name].action)
|
|
2383
|
+
);
|
|
2384
|
+
|
|
2371
2385
|
// Find key field
|
|
2372
2386
|
this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
|
|
2373
2387
|
if (!this.keyField) {
|
|
@@ -2378,6 +2392,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2378
2392
|
async resolveAsyncFieldOptions() {
|
|
2379
2393
|
const promises = this.columnList.map(async (fieldName) => {
|
|
2380
2394
|
const field = this.options.fields[fieldName];
|
|
2395
|
+
if (field.action) return; // Skip action columns
|
|
2381
2396
|
const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName);
|
|
2382
2397
|
|
|
2383
2398
|
if (this.formBuilder.shouldResolveOptions(originalOptions)) {
|
|
@@ -2403,7 +2418,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2403
2418
|
for (const row of rows) {
|
|
2404
2419
|
for (const fieldName of this.columnList) {
|
|
2405
2420
|
const field = this.options.fields[fieldName];
|
|
2406
|
-
if (!field.options) continue;
|
|
2421
|
+
if (field.action || !field.options) continue;
|
|
2407
2422
|
|
|
2408
2423
|
const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
|
|
2409
2424
|
if (!cell) continue;
|
|
@@ -2474,8 +2489,8 @@ class FTable extends FTableEventEmitter {
|
|
|
2474
2489
|
parent: thead
|
|
2475
2490
|
});
|
|
2476
2491
|
|
|
2477
|
-
// Add selecting column if enabled
|
|
2478
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2492
|
+
// Add selecting column if enabled (only if not user-placed)
|
|
2493
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2479
2494
|
const selectHeader = FTableDOMHelper.create('th', {
|
|
2480
2495
|
className: `ftable-command-column-header ftable-column-header-select`,
|
|
2481
2496
|
parent: headerRow
|
|
@@ -2493,9 +2508,41 @@ class FTable extends FTableEventEmitter {
|
|
|
2493
2508
|
}
|
|
2494
2509
|
}
|
|
2495
2510
|
|
|
2496
|
-
// Add data columns
|
|
2511
|
+
// Add data columns (including any user-placed action columns)
|
|
2497
2512
|
this.columnList.forEach(fieldName => {
|
|
2498
2513
|
const field = this.options.fields[fieldName];
|
|
2514
|
+
|
|
2515
|
+
// If this column is a user-placed action column, render an action header
|
|
2516
|
+
if (field.action) {
|
|
2517
|
+
const actionClassMap = {
|
|
2518
|
+
select: 'ftable-column-header-select',
|
|
2519
|
+
update: 'ftable-column-header-edit',
|
|
2520
|
+
clone: 'ftable-column-header-clone',
|
|
2521
|
+
delete: 'ftable-column-header-delete',
|
|
2522
|
+
};
|
|
2523
|
+
const th = FTableDOMHelper.create('th', {
|
|
2524
|
+
className: `ftable-command-column-header ${actionClassMap[field.action] || ''}`,
|
|
2525
|
+
parent: headerRow
|
|
2526
|
+
});
|
|
2527
|
+
if (field.title) {
|
|
2528
|
+
th.textContent = field.title;
|
|
2529
|
+
}
|
|
2530
|
+
// For select action with multiselect, add the select-all checkbox
|
|
2531
|
+
if (field.action === 'select' && this.options.selecting && this.options.selectingCheckboxes && this.options.multiselect) {
|
|
2532
|
+
const selectAllCheckbox = FTableDOMHelper.create('input', {
|
|
2533
|
+
attributes: { type: 'checkbox' },
|
|
2534
|
+
parent: th
|
|
2535
|
+
});
|
|
2536
|
+
selectAllCheckbox.addEventListener('change', () => {
|
|
2537
|
+
this.toggleSelectAll(selectAllCheckbox.checked);
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
if (field.width) {
|
|
2541
|
+
th.style.width = field.width;
|
|
2542
|
+
}
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2499
2546
|
const th = FTableDOMHelper.create('th', {
|
|
2500
2547
|
className: `ftable-column-header ${field.listClass || ''} ${field.listClassHeader || ''}`,
|
|
2501
2548
|
attributes: { 'data-field-name': fieldName },
|
|
@@ -2544,22 +2591,22 @@ class FTable extends FTableEventEmitter {
|
|
|
2544
2591
|
}
|
|
2545
2592
|
});
|
|
2546
2593
|
|
|
2547
|
-
// Add action columns
|
|
2548
|
-
if (this.options.actions.updateAction) {
|
|
2594
|
+
// Add default action columns only if not user-placed
|
|
2595
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
2549
2596
|
FTableDOMHelper.create('th', {
|
|
2550
2597
|
className: 'ftable-command-column-header ftable-column-header-edit',
|
|
2551
2598
|
parent: headerRow
|
|
2552
2599
|
});
|
|
2553
2600
|
}
|
|
2554
2601
|
|
|
2555
|
-
if (this.options.actions.cloneAction) {
|
|
2602
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
2556
2603
|
FTableDOMHelper.create('th', {
|
|
2557
2604
|
className: 'ftable-command-column-header ftable-column-header-clone',
|
|
2558
2605
|
parent: headerRow
|
|
2559
2606
|
});
|
|
2560
2607
|
}
|
|
2561
2608
|
|
|
2562
|
-
if (this.options.actions.deleteAction) {
|
|
2609
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
2563
2610
|
FTableDOMHelper.create('th', {
|
|
2564
2611
|
className: 'ftable-command-column-header ftable-column-header-delete',
|
|
2565
2612
|
parent: headerRow
|
|
@@ -2580,17 +2627,27 @@ class FTable extends FTableEventEmitter {
|
|
|
2580
2627
|
parent: theadParent
|
|
2581
2628
|
});
|
|
2582
2629
|
|
|
2583
|
-
// Add empty cell for selecting column if enabled
|
|
2584
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2630
|
+
// Add empty cell for selecting column if enabled (only if not user-placed)
|
|
2631
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2585
2632
|
FTableDOMHelper.create('th', {
|
|
2586
2633
|
className: 'ftable-toolbarsearch-column-header',
|
|
2587
2634
|
parent: searchRow
|
|
2588
2635
|
});
|
|
2589
2636
|
}
|
|
2590
2637
|
|
|
2591
|
-
// Add search input cells for data columns
|
|
2638
|
+
// Add search input cells for data columns (including user-placed action columns)
|
|
2592
2639
|
for (const fieldName of this.columnList) {
|
|
2593
2640
|
const field = this.options.fields[fieldName];
|
|
2641
|
+
|
|
2642
|
+
// Action columns get an empty search cell
|
|
2643
|
+
if (field.action) {
|
|
2644
|
+
FTableDOMHelper.create('th', {
|
|
2645
|
+
className: 'ftable-toolbarsearch-column-header ftable-command-column-header',
|
|
2646
|
+
parent: searchRow
|
|
2647
|
+
});
|
|
2648
|
+
continue;
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2594
2651
|
const isSearchable = field.searchable !== false;
|
|
2595
2652
|
|
|
2596
2653
|
const th = FTableDOMHelper.create('th', {
|
|
@@ -2762,9 +2819,9 @@ class FTable extends FTableEventEmitter {
|
|
|
2762
2819
|
parent: searchRow
|
|
2763
2820
|
});
|
|
2764
2821
|
|
|
2765
|
-
const actionCount = (this.options.actions.updateAction ? 1 : 0) +
|
|
2766
|
-
(this.options.actions.deleteAction ? 1 : 0) +
|
|
2767
|
-
(this.options.actions.cloneAction ? 1 : 0);
|
|
2822
|
+
const actionCount = (this.options.actions.updateAction && !this._userPlacedActions.has('update') ? 1 : 0) +
|
|
2823
|
+
(this.options.actions.deleteAction && !this._userPlacedActions.has('delete') ? 1 : 0) +
|
|
2824
|
+
(this.options.actions.cloneAction && !this._userPlacedActions.has('clone') ? 1 : 0);
|
|
2768
2825
|
|
|
2769
2826
|
if (actionCount > 0) {
|
|
2770
2827
|
resetTh.colSpan = actionCount;
|
|
@@ -2872,9 +2929,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2872
2929
|
}
|
|
2873
2930
|
|
|
2874
2931
|
createCustomMultiSelectForSearch(fieldSearchName, fieldName, field, optionsSource, attributes) {
|
|
2875
|
-
const livesearch = field.livesearch
|
|
2876
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
2877
|
-
?? false;
|
|
2932
|
+
const livesearch = field.livesearch ?? false;
|
|
2878
2933
|
|
|
2879
2934
|
return this.formBuilder._buildCustomMultiSelect({
|
|
2880
2935
|
hiddenSelectId: fieldSearchName,
|
|
@@ -3451,6 +3506,7 @@ class FTable extends FTableEventEmitter {
|
|
|
3451
3506
|
|
|
3452
3507
|
this.columnList.forEach(fieldName => {
|
|
3453
3508
|
const field = this.options.fields[fieldName];
|
|
3509
|
+
if (field.action) return; // Action columns don't appear in column picker
|
|
3454
3510
|
const isVisible = field.visibility !== 'hidden';
|
|
3455
3511
|
const isFixed = field.visibility === 'fixed';
|
|
3456
3512
|
const isSeparator = field.visibility === 'separator';
|
|
@@ -3863,26 +3919,45 @@ class FTable extends FTableEventEmitter {
|
|
|
3863
3919
|
// Store record data
|
|
3864
3920
|
row.recordData = record;
|
|
3865
3921
|
|
|
3866
|
-
// Add selecting checkbox if enabled
|
|
3867
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
3922
|
+
// Add selecting checkbox if enabled (only if not user-placed)
|
|
3923
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
3868
3924
|
this.addSelectingCell(row);
|
|
3869
3925
|
}
|
|
3870
3926
|
|
|
3871
|
-
// Add data cells
|
|
3927
|
+
// Add data cells (including user-placed action columns)
|
|
3872
3928
|
this.columnList.forEach(fieldName => {
|
|
3873
|
-
this.
|
|
3929
|
+
const field = this.options.fields[fieldName];
|
|
3930
|
+
if (field.action) {
|
|
3931
|
+
// Render inline action cell
|
|
3932
|
+
switch (field.action) {
|
|
3933
|
+
case 'select':
|
|
3934
|
+
this.addSelectingCell(row);
|
|
3935
|
+
break;
|
|
3936
|
+
case 'update':
|
|
3937
|
+
this.addEditCell(row);
|
|
3938
|
+
break;
|
|
3939
|
+
case 'clone':
|
|
3940
|
+
this.addCloneCell(row);
|
|
3941
|
+
break;
|
|
3942
|
+
case 'delete':
|
|
3943
|
+
this.addDeleteCell(row);
|
|
3944
|
+
break;
|
|
3945
|
+
}
|
|
3946
|
+
} else {
|
|
3947
|
+
this.addDataCell(row, record, fieldName);
|
|
3948
|
+
}
|
|
3874
3949
|
});
|
|
3875
3950
|
|
|
3876
|
-
// Add action cells
|
|
3877
|
-
if (this.options.actions.updateAction) {
|
|
3951
|
+
// Add default action cells only if not user-placed
|
|
3952
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
3878
3953
|
this.addEditCell(row);
|
|
3879
3954
|
}
|
|
3880
3955
|
|
|
3881
|
-
if (this.options.actions.cloneAction) {
|
|
3956
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
3882
3957
|
this.addCloneCell(row);
|
|
3883
3958
|
}
|
|
3884
3959
|
|
|
3885
|
-
if (this.options.actions.deleteAction) {
|
|
3960
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
3886
3961
|
this.addDeleteCell(row);
|
|
3887
3962
|
}
|
|
3888
3963
|
|
package/ftable.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(e=>{let s={serverCommunicationError:"An error occurred while communicating to the server.",loadingMessage:"Loading records...",noDataAvailable:"No data available!",addNewRecord:"Add new record",editRecord:"Edit record",areYouSure:"Are you sure?",deleteConfirmation:"This record will be deleted. Are you sure?",yes:"Yes",no:"No",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",close:"Close",cannotLoadOptionsFor:"Cannot load options for field {0}!",pagingInfo:"Showing {0}-{1} of {2}",canNotDeletedRecords:"Can not delete {0} of {1} records!",deleteProgress:"Deleting {0} of {1} records, processing...",pageSizeChangeLabel:"Row count",gotoPageLabel:"Go to page",sortingInfoPrefix:"Sorting applied: ",sortingInfoSuffix:"",ascending:"Ascending",descending:"Descending",sortingInfoNone:"No sorting applied",resetSorting:"Reset sorting",csvExport:"CSV",printTable:"🖨️ Print",cloneRecord:"Clone Record",resetTable:"Reset table",resetTableConfirm:"This will reset all columns, pagesize, sorting to their defaults. Do you want to continue?",resetSearch:"Reset"};class t{constructor(){this.cache=new Map,this.pendingRequests=new Map}generateKey(e,t){return e+"?"+Object.keys(t||{}).sort().map(e=>e+"="+t[e]).join("&")}get(e,t){e=this.generateKey(e,t);return this.cache.get(e)}set(e,t,s){e=this.generateKey(e,t);this.cache.set(e,s)}clear(e=null,t=null){if(e)if(t){t=this.generateKey(e,t);this.cache.delete(t)}else{var s,a=e.split("?")[0];for([s]of this.cache)s.startsWith(a)&&this.cache.delete(s)}else this.cache.clear()}async getOrCreate(e,t,s){let a=this.generateKey(e,t);e=this.cache.get(a);return e||(this.pendingRequests.has(a)?this.pendingRequests.get(a):(t=(async()=>{try{var e=await s();return this.cache.set(a,e),e}finally{this.pendingRequests.delete(a)}})(),this.pendingRequests.set(a,t),t))}size(){return this.cache.size}}class a{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=a.LOG_LEVELS.WARN){this.level=e}log(t,e){var s;!window.console||t<this.level||(s=Object.keys(a.LOG_LEVELS).find(e=>a.LOG_LEVELS[e]===t),console.log(`fTable ${s}: `+e))}debug(e){this.log(a.LOG_LEVELS.DEBUG,e)}info(e){this.log(a.LOG_LEVELS.INFO,e)}warn(e){this.log(a.LOG_LEVELS.WARN,e)}error(e){this.log(a.LOG_LEVELS.ERROR,e)}}class O{static PROPERTY_ATTRIBUTES=new Set(["value","checked","selected","disabled","readOnly","name","id","type","placeholder","min","max","step","required","multiple","accept","className","textContent","innerHTML","title"]);static create(e,t={}){let s=document.createElement(e);return void 0!==t.style&&(s.style.cssText=t.style),O.PROPERTY_ATTRIBUTES.forEach(e=>{e in t&&null!==t[e]&&(s[e]=t[e])}),void 0!==t.parent&&t.parent.appendChild(s),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{null!==t&&(O.PROPERTY_ATTRIBUTES.has(e)?s[e]=t:s.setAttribute(e,t))}),s}static find(e,t=document){return t.querySelector(e)}static findAll(e,t=document){return Array.from(t.querySelectorAll(e))}static addClass(e,t){e.classList.add(...t.split(" "))}static removeClass(e,t){e.classList.remove(...t.split(" "))}static toggleClass(e,t){e.classList.toggle(t)}static show(e){e.style.display=""}static hide(e){e.style.display="none"}static escapeHtml(e){if(!e)return e;let t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>t[e])}}class l{static async request(e,t={}){var s={method:"GET",headers:{}},a={...s,...t};t.headers&&(a.headers={...s.headers,...t.headers});try{var i=await fetch(e,a);if(401===i.status)throw new Error("Unauthorized");if(!i.ok)throw new Error("HTTP error! status: "+i.status);var o=i.headers.get("content-type");if(o&&o.includes("application/json"))return await i.json();var r=await i.text();try{return JSON.parse(r)}catch{return{Result:"OK",Message:r}}}catch(e){throw e}}static async get(e,t={}){let a=new URL(e,window.location.href);return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.endsWith("[]")?e:e+"[]";s.forEach(e=>{null!=e&&a.searchParams.append(t,e)})}else a.searchParams.append(e,s)}),this.request(a.toString(),{method:"GET",headers:{"Content-Type":"application/x-www-form-urlencoded"}})}static async post(e,t={}){e=new URL(e,window.location.href);let a=new FormData;return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.endsWith("[]")?e:e+"[]";s.forEach(e=>{null!=e&&a.append(t,e)})}else a.append(e,s)}),this.request(e.toString(),{method:"POST",body:a})}}class i{constructor(e,t="localStorage"){this.prefix=e,this.method=t}set(e,t){var s,e=""+this.prefix+e;"localStorage"===this.method?localStorage.setItem(e,t):((s=new Date).setDate(s.getDate()+30),document.cookie=e+`=${t}; expires=${s.toUTCString()}; path=/`)}get(e){e=""+this.prefix+e;if("localStorage"===this.method)return localStorage.getItem(e);var t,s=e+"=";for(t of decodeURIComponent(document.cookie).split(";")){for(;" "===t.charAt(0);)t=t.substring(1);if(0===t.indexOf(s))return t.substring(s.length,t.length)}return null}remove(e){e=""+this.prefix+e;"localStorage"===this.method?localStorage.removeItem(e):document.cookie=e+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"}generatePrefix(e,t){e=e?e+"#":"";return"ftable#"+(t=>{let s=0;if(0!==t.length)for(let e=0;e<t.length;e++){var a=t.charCodeAt(e);s=(s<<5)-s+a,s&=s}return s})(e+=t.join("$")+"#c"+t.length)}}class o{constructor(e={}){this.options={title:"Modal",content:"",buttons:[],className:"ftable-modal",parent:document.body,...e},this.overlay=null,this.modal=null,this.isOpen=!1}create(){this.overlay=O.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=O.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});O.create("h2",{className:"ftable-modal-header",textContent:this.options.title,parent:this.modal});O.create("span",{className:"ftable-modal-close",innerHTML:"×",parent:this.modal}).addEventListener("click",()=>this.close());var e=O.create("div",{className:"ftable-modal-body",parent:this.modal});if("string"==typeof this.options.content?e.innerHTML=this.options.content:e.appendChild(this.options.content),0<this.options.buttons.length){let s=O.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=O.create("button",{className:"ftable-dialog-button "+(e.className||""),innerHTML:`<span>${e.text}</span>`,parent:s});e.onClick&&(t._originalOnClick=e.onClick,t.addEventListener("click",this._createWrappedClickHandler(t)))})}return this.options.closeOnOverlayClick&&this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.hide(),this}show(){return this.modal||this.create(),this.overlay.style.display="flex",this.isOpen=!0,this.modal.querySelectorAll(".ftable-dialog-button").forEach(e=>{e.disabled=!1}),this}hide(){return this.overlay&&(this.overlay.style.display="none"),this.isOpen=!1,this}close(){return this.hide(),this.options.onClose&&this.options.onClose(),this}destroy(){return this.overlay&&this.overlay.remove(),this.isOpen=!1,this}setContent(e){this.options.content=e;var t=this.modal.querySelector(".ftable-modal-body");t&&(t.innerHTML="","string"==typeof e?t.innerHTML=e:t.appendChild(e))}_createWrappedClickHandler(a){return async e=>{a.disabled=!0;try{var t,s=a._originalOnClick;"function"==typeof s&&(t=s.call(a,e))instanceof Promise&&await t}catch(e){console.error("Modal button action failed:",e)}finally{a.disabled=!1}}}}class r{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t,this.originalFieldOptions=new Map,this.resolvedFieldOptions=new Map,Object.keys(this.options.fields||{}).forEach(e=>{this.resolvedFieldOptions.set(e,{})}),Object.entries(this.options.fields).forEach(([e,t])=>{this.originalFieldOptions.set(e,t.options)})}async getFieldOptions(t,s="table",e={}){var a=this.options.fields[t],i=this.originalFieldOptions.get(t);if(!i)return null;var o=this.shouldForceRefreshForContext(a,s,e),r=this.generateOptionsCacheKey(s,e);if(!o&&!e.forceRefresh){var n=this.resolvedFieldOptions.get(t)[r];if(n)return n}try{var l={...a,options:i},c=await this.resolveOptions(l,{...e},s,o);return this.resolvedFieldOptions.get(t)[r]=c}catch(e){return console.error(`Failed to resolve options for ${t} (${s}):`,e),i}}clearResolvedOptions(e=null,s=null){e?this.resolvedFieldOptions.has(e)&&(s?this.resolvedFieldOptions.get(e)[s]=null:this.resolvedFieldOptions.set(e,{table:null,create:null,edit:null})):s?this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.get(t)[s]=null}):this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.set(t,{table:null,create:null,edit:null})})}shouldForceRefreshForContext(e,t,s){return!!e.noCache&&("boolean"==typeof e.noCache?e.noCache:"function"==typeof e.noCache?e.noCache({context:t,...s}):"object"==typeof e.noCache&&!0===e.noCache[t])}generateOptionsCacheKey(e,t){let s=[e];return t.dependedValues&&Object.keys(t.dependedValues).sort().forEach(e=>{s.push(e+"="+t.dependedValues[e])}),s.join("|")}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,s,a){var i=O.create("div",{className:"hidden"!=t.type?"ftable-input-field-container":"",attributes:{id:"ftable-input-field-container-div-"+e}}),t=("hidden"!=t.type&&O.create("div",{className:"ftable-input-label",textContent:t.inputTitle||t.title,parent:i}),this.createInput(e,t,s[e],a));return i.appendChild(t),i}async createForm(e="create",t={}){this.currentFormRecord=t;var s,a,i,o,r=O.create("form",{className:`ftable-dialog-form ftable-${e}-form`});this.buildDependencyMap();for([s,a]of Object.entries(this.options.fields))this.shouldIncludeField(a,e)&&(i={...a},a.dependsOn?i.options=a.options:(o=await this.getFieldOptions(s,e,{record:t,source:e}),i.options=o),o=this.createFieldContainer(s,i,t,e),r.appendChild(o));return this.setupDependencyListeners(r),r}shouldResolveOptions(e){return e&&("function"==typeof e||"string"==typeof e)&&!Array.isArray(e)&&!("object"==typeof e&&!Array.isArray(e)&&0<Object.keys(e).length)}buildDependencyMap(){this.dependencies.clear(),Object.entries(this.options.fields).forEach(([t,s])=>{if(s.dependsOn){let e;"string"==typeof s.dependsOn&&(e=s.dependsOn.split(",").map(e=>e.trim()).filter(e=>e)).forEach(e=>{this.dependencies.has(e)||this.dependencies.set(e,[]),this.dependencies.get(e).push(t)})}})}setupDependencyListeners(s){Array.from(this.dependencies.keys()).forEach(e=>{var t=s.querySelector(`[name="${e}"]`);t&&t.addEventListener("change",()=>{this.handleDependencyChange(s,e)})}),this.handleDependencyChange(s)}async resolveOptions(e,t={},s="",a=!1){if(!e.options)return[];if(Array.isArray(e.options)||"object"==typeof e.options)return e.options;let i;t={...t,source:s,clearCache:()=>{a=!0,this.updateFieldCacheSetting(e,s,!0)}};if("function"==typeof e.options)i=await e.options(t);else{if("string"!=typeof e.options)return[];i=e.options}t=i&&"object"==typeof i&&i.url;let o=t?i.url:i;if(a=t&&void 0!==i.noCache?i.noCache:a,"string"!=typeof o)return[];if(!a)return this.optionsCache.getOrCreate(o,{},async()=>{try{var e=this.options.forcePost?await l.post(o):await l.get(o);return e.Options||e.options||e||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}});try{var r=this.options.forcePost?await l.post(o):await l.get(o);return r.Options||r.options||r||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}}updateFieldCacheSetting(e,t,s){e.noCache?"boolean"==typeof e.noCache?e.noCache={table:e.noCache,create:e.noCache,edit:e.noCache,[t]:s}:"object"==typeof e.noCache&&(e.noCache[t]=s):e.noCache={[t]:s}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}getFormValues(e){var t={},s=e.elements;for(let e=0;e<s.length;e++){var a=s[e],i=a.name;if(i&&!a.disabled)switch(a.type){case"checkbox":t[i]=a.checked?a.value||"1":"0";break;case"radio":a.checked&&(t[i]=a.value);break;case"select-multiple":t[i]=Array.from(a.selectedOptions).map(e=>e.value);break;default:t[i]=a.value}}return t}async handleDependencyChange(e,s=""){var a,i,o=this.getFormValues(e),r=e.classList.contains("ftable-create-form")?"create":"edit",n=this.currentFormRecord||{},l={record:n,source:r,form:e,dependedValues:o};for([a,i]of Object.entries(this.options.fields))if(i.dependsOn){if(""!==s)if(!i.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(s))continue;let t=e.querySelector(`[name="${a}"]`);if(t&&this.shouldIncludeField(i,r))try{"SELECT"===t.tagName?t.innerHTML='<option value="">Loading...</option>':"INPUT"===t.tagName&&t.list&&(c=document.getElementById(t.list.id))&&(c.innerHTML="");var c,d=t.value||n[a]||"",h={...l,dependsOnField:i.dependsOn,dependsOnValue:o[i.dependsOn]},p=await this.getFieldOptions(a,r,h);"SELECT"===t.tagName?this.populateSelectOptions(t,p,d):"INPUT"===t.tagName&&t.list&&(this.populateDatalistOptions(t.list,p),d)&&(t.value=d),setTimeout(()=>{t.dispatchEvent(new Event("change",{bubbles:!0}))},0)}catch(e){console.error(`Error loading options for ${a}:`,e),"SELECT"===t.tagName&&(t.innerHTML='<option value="">Error</option>')}}}parseInputAttributes(e){if("string"!=typeof e)return e||{};for(var t={},s=/(\w+)(?:=("[^"]*"|'[^']*'|\S+))?/g;null!==(i=s.exec(e));){var a=i[1],i=i[2]?i[2].replace(/^["']|["']$/g,""):"";t[a]=""===i?"true":i}return t}createInput(e,t,s,a){var i=O.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null===(s=void 0===s?null:s)&&t.defaultValue&&(s=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":o=this.createHiddenInput(e,t,s);break;case"textarea":o=this.createTextarea(e,t,s);break;case"select":o=this.createSelect(e,t,s);break;case"checkbox":o=this.createCheckbox(e,t,s);break;case"radio":o=this.createRadioGroup(e,t,s);break;case"datalist":o=this.createDatalistInput(e,t,s);break;case"file":o=this.createFileInput(e,t,s);break;case"date":case"datetime":case"datetime-local":o=this.createDateInput(e,t,s);break;default:o=this.createTypedInput(e,t,s)}return"function"==typeof t.input?(a={field:t,record:this.currentFormRecord,inputField:o,formType:a},"string"==typeof(a=t.input(a))?i.innerHTML=a:a instanceof Node?i.appendChild(a):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement))):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement)),t.explain&&O.create("div",{className:"ftable-field-explain",innerHTML:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(s,a,i){if("undefined"==typeof FDatepicker)return createTypedInput(s,a,i);{let e=a.dateFormat||this.options.defaultDateFormat;var o,r=document.createElement("div"),n=O.create("input",{id:"real-"+s,type:"hidden",value:i,name:s}),i={"data-date":i};a.inputAttributes&&(o=this.parseInputAttributes(a.inputAttributes),Object.assign(i,o));let t=O.create("input",{attributes:i,id:"Edit-"+s,type:"text",placeholder:a.placeholder||null,className:a.inputClass||"datepicker-input",readOnly:!0});switch(r.appendChild(n),r.appendChild(t),a.type){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"real-"+s,altFormat:"Y-m-d"})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"real-"+s,altFormat:"Y-m-d H:i:00"})},0)}return r}}createTypedInput(e,t,s){var a,i=t.type||"text",o={};let r=e,n=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(o,a),void 0!==a.multiple&&!1!==a.multiple)&&(r=e+"[]"),O.create("input",{attributes:o,type:i,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s,name:r}));return n.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),n.dispatchEvent(new Event("change",{bubbles:!0})),!1}),n}createDatalistInput(e,t,s){var a={list:e+"-datalist"},i=(t.inputAttributes&&(i=this.parseInputAttributes(t.inputAttributes),Object.assign(a,i)),O.create("input",{attributes:a,type:"search",name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})),a=O.create("datalist",{id:e+"-datalist"});return t.options&&this.populateDatalistOptions(a,t.options),i.datalistElement=a,i}populateDatalistOptions(s,e){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{O.create("option",{value:e.Value||e.value||e,textContent:e.DisplayText||e.text||e,parent:s})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:s})})}createHiddenInput(e,t,s){var a={};return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(a,t)),O.create("input",{attributes:a,type:"hidden",name:e,id:"Edit-"+e,value:s})}createTextarea(e,t,s){var a,i={};return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a)),O.create("textarea",{attributes:i,name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})}createSelect(e,t,s){var a={};let i=e,o=!1;if(t.inputAttributes&&(r=this.parseInputAttributes(t.inputAttributes),Object.assign(a,r),o=void 0!==r.multiple&&!1!==r.multiple)&&(i=e+"[]"),o)return this.createCustomMultiSelect(e,t,s,a,i);a.name=i;var r=O.create("select",{attributes:a,name:e,id:"Edit-"+e,className:t.inputClass||null});return t.options&&this.populateSelectOptions(r,t.options,s),r}createCustomMultiSelect(e,t,s,a,i){var o=Array.isArray(t.options)?t.options:t.options&&"object"==typeof t.options?Object.entries(t.options).map(([e,t])=>({Value:e,DisplayText:t})):[],a=t.livesearch??("true"===a["data-livesearch"]||!0===a["data-livesearch"])??!1;return this._buildCustomMultiSelect({containerId:e,hiddenSelectId:"Edit-"+e,hiddenSelectName:i,extraClasses:"",containerDataFieldName:e,hiddenSelectAttributes:{},optionsSource:o,initialValues:Array.isArray(s)?s:s?s.toString().split(",").filter(e=>e):[],placeholderText:t.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:a,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!0})}_buildCustomMultiSelect(e){let{hiddenSelectId:t,hiddenSelectName:s,extraClasses:a,containerDataFieldName:i,hiddenSelectAttributes:o,optionsSource:r,initialValues:n,placeholderText:l,livesearch:c,onChangeExtra:d,buildHiddenSelectOnUpdate:h}=e;let p=(e=r)?(Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({Value:e,DisplayText:t}))).map(e=>({optValue:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,optText:e.DisplayText||e.text||e,groupLabel:e.Group||e.group||null})).filter(e=>null!=e.optValue&&""!==e.optValue):[],u=new Map(p.map(e=>[e.optValue.toString(),e.optText]));e=["ftable-multiselect-container",...a.split(" ").filter(Boolean)].join(" ");let m=O.create("div",{className:e,attributes:{"data-field-name":i}}),f=O.create("select",{id:t,name:s,multiple:!0,style:"display: none;",attributes:o}),g=(m.appendChild(f),m.hiddenSelect=f,O.create("div",{className:"ftable-multiselect-display",parent:m,attributes:{tabindex:"0"}})),b=O.create("div",{className:"ftable-multiselect-selected",parent:g}),v=O.create("span",{className:"ftable-multiselect-placeholder",textContent:l,parent:b}),y=(O.create("button",{type:"button",className:"ftable-multiselect-toggle",innerHTML:"▼",parent:g,attributes:{tabindex:"-1"}}),null),C=null,w=new Set(n.map(e=>e.toString())),S=new Map,E=(h||p.forEach(({optValue:e,optText:t})=>{O.create("option",{value:e,textContent:t,parent:f})}),()=>{b.innerHTML="",h?(f.innerHTML="",w.forEach(e=>{var t=u.get(e)??e;O.create("option",{value:e,textContent:t,selected:!0,parent:f})})):Array.from(f.options).forEach(e=>{e.selected=w.has(e.value)}),0===w.size?(v.textContent=l,b.appendChild(v)):w.forEach(t=>{var e=O.create("span",{className:"ftable-multiselect-tag",parent:b});O.create("span",{className:"ftable-multiselect-tag-text",textContent:u.get(t)||t,parent:e}),O.create("span",{className:"ftable-multiselect-tag-remove",innerHTML:"×",parent:e}).addEventListener("click",e=>{e.stopPropagation(),w.delete(t);e=S.get(t);e&&(e.checked=!1),E(),d&&d(f)})}),d&&d(f)}),x=()=>{g.focus(),y&&(y.remove(),y=null),C&&(C.remove(),C=null),m._cleanupHandlers&&(m._cleanupHandlers(),m._cleanupHandlers=null)},N=()=>{var e,t,s;y&&(e=g.getBoundingClientRect(),s=window.pageYOffset||document.documentElement.scrollTop,t=window.pageXOffset||document.documentElement.scrollLeft,t=e.left+t,s=e.bottom+s+4,Object.assign(y.style,{position:"absolute",left:t+"px",top:s+"px",width:e.width+"px",minWidth:"fit-content",boxSizing:"border-box",zIndex:"10000"}),(s=y.getBoundingClientRect()).right>window.innerWidth)&&(t=Math.max(10,window.innerWidth-s.width-10),y.style.left=t+"px")},T=(e="")=>{if(y){Array.from(y.querySelectorAll(".ftable-multiselect-option, .ftable-multiselect-optgroup")).forEach(e=>e.remove());let t=e.toLowerCase();e=e?p.filter(e=>e.optText.toLowerCase().includes(t)):p;let i=new Set,o=null;e.forEach(({optValue:t,optText:e,groupLabel:s})=>{s&&s!==i[i.size-1]?i.has(s)||(i.add(s),o=O.create("div",{className:"ftable-multiselect-optgroup",textContent:s,parent:y})):s||(o=null);s=O.create("div",{className:"ftable-multiselect-option",parent:y});let a=O.create("input",{type:"checkbox",className:"ftable-multiselect-checkbox",checked:w.has(t.toString()),parent:s});S.set(t.toString(),a),O.create("label",{className:"ftable-multiselect-label",textContent:e,parent:s}),s.addEventListener("click",e=>{e.stopPropagation();e=t.toString();w.has(e)?(w.delete(e),a.checked=!1):(w.add(e),a.checked=!0),E()})})}},A=a=>{if(a&&a.stopPropagation(),y)x();else{if(document.querySelectorAll(".ftable-multiselect-dropdown").forEach(e=>e.remove()),document.querySelectorAll(".ftable-multiselect-overlay").forEach(e=>e.remove()),C=O.create("div",{className:"ftable-multiselect-overlay",parent:document.body}),y=O.create("div",{className:"ftable-multiselect-dropdown",parent:document.body,attributes:{tabindex:"-1",role:"listbox","aria-multiselectable":"true"}}),c){a=O.create("div",{className:"ftable-multiselect-livesearch-wrap",parent:y});let e=O.create("input",{type:"search",className:"ftable-multiselect-livesearch",placeholder:"Search...",parent:a,attributes:{autocomplete:"off"}});e.addEventListener("input",()=>{T(e.value)}),e.addEventListener("click",e=>e.stopPropagation()),setTimeout(()=>e.focus(),0)}T(),N(),c||y.focus(),y.addEventListener("keydown",e=>{var t,s;"Escape"===e.key?x():"ArrowDown"===e.key||"ArrowUp"===e.key?(e.preventDefault(),s=(t=Array.from(y.querySelectorAll(".ftable-multiselect-checkbox"))).indexOf(document.activeElement),t["ArrowDown"===e.key?s<t.length-1?s+1:0:0<s?s-1:t.length-1]?.focus()):" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),document.activeElement.classList.contains("ftable-multiselect-checkbox")&&document.activeElement.click())}),C.addEventListener("click",e=>{e.target===C&&x()});let e=()=>N(),t=e=>{y&&y.contains(e.target)||N()},s=new ResizeObserver(()=>N());window.addEventListener("scroll",t,!0),window.addEventListener("resize",e),s.observe(b),m._cleanupHandlers=()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",e),s.disconnect()}}},L=(g.addEventListener("click",A),g.querySelector(".ftable-multiselect-toggle").addEventListener("click",A),g.addEventListener("keydown",e=>{"ArrowDown"!==e.key&&"Enter"!==e.key||(e.preventDefault(),A())}),m.resetMultiSelect=()=>{w.clear(),S.forEach(e=>{e.checked=!1}),x(),E()},new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{(e===m||e.contains&&e.contains(m))&&(x(),L.disconnect())})})}));return setTimeout(()=>{m.parentNode&&L.observe(m.parentNode,{childList:!0,subtree:!0})},0),E(),m}createRadioGroup(o,r,n){let l=O.create("div",{className:"ftable-radio-group"});return r.options&&(Array.isArray(r.options)?r.options:"object"==typeof r.options?Object.entries(r.options).map(([e,t])=>({Value:e,DisplayText:t})):[]).forEach((e,t)=>{var s=O.create("div",{className:"ftable-radio-wrapper",parent:l}),t=o+"_"+t,a={},i=(r.inputAttributes&&(i=this.parseInputAttributes(r.inputAttributes),Object.assign(a,i)),void 0!==e.Value?e.Value:void 0!==e.value?e.value:e);O.create("input",{attributes:a,type:"radio",name:o,id:t,value:i,className:r.inputClass||null,checked:i==n,parent:s}),O.create("label",{attributes:{for:t},textContent:e.DisplayText||e.text||e,parent:s})}),l}createCheckbox(e,t,s){var a=O.create("div",{className:"ftable-yesno-check-wrapper"}),s=[1,"1",!0,"true"].includes(s);let i=this.options.messages.no,o=this.options.messages.yes;return t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]),O.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),type:"checkbox",name:e,id:"Edit-"+e,value:"1",parent:a}).checked=s,t.label?O.create("label",{className:"ftable-yesno-check-fixedlabel",attributes:{for:"Edit-"+e},textContent:t.label,parent:a}):O.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:a}),a}populateSelectOptions(o,e,r){if(o.innerHTML="",Array.isArray(e)){let s=new Map,a=[],i=(e.forEach(e=>{var t=e.Group||e.group||null;(t?(s.has(t)||s.set(t,[]),s.get(t)):a).push(e)}),(e,t)=>{var s=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let a=O.create("option",{value:s,textContent:e.DisplayText||e.text||e,selected:s==r,parent:t});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{a.setAttribute("data-"+e,t)})});a.forEach(e=>i(e,o)),s.forEach((e,t)=>{let s=O.create("optgroup",{attributes:{label:t},parent:o});e.forEach(e=>i(e,s))})}else"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,selected:e==r,parent:o})})}createFileInput(e,t,s){var a,i={};let o=e;return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a),void 0!==a.multiple&&!1!==a.multiple)&&(o=e+"[]"),O.create("input",{type:"file",id:"Edit-"+e,name:o,className:t.inputClass||null,attributes:i})}}class n extends class{constructor(){this.events={}}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),this}once(t,s){let a=(...e)=>{this.off(t,a),s.apply(this,e)};return a.fn=s,this.on(t,a),this}emit(e,t={}){return this.events[e]&&this.events[e].forEach(e=>e(t)),this}off(e,t){return this.events[e]&&(this.events[e]=this.events[e].filter(e=>e!==t)),this}}{constructor(e,t={}){if(super(),this.element="string"==typeof e?document.querySelector(e):e,this.element){if(this.element.ftableInstance)return this.element.ftableInstance;this.options=this.mergeOptions(t),this.verifyOptions(),this.logger=new a(this.options.logLevel),this.userPrefs=new i("",this.options.saveUserPreferencesMethod),this.formBuilder=new r(this.options,this),this.state={records:[],totalRecordCount:0,currentPage:1,isLoading:!1,selectedRecords:new Set,sorting:[],searchQueries:{}},this.elements={},this.modals={},this.searchTimeout=null,this.lastSortEvent=null,this._recalculatedOnce=!1,this.shiftKeyDown=!1,this.lastSelectedRow=null,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:a.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,closeOnOverlayClick:!0,animationsEnabled:!0,loadingAnimationDelay:1e3,defaultDateLocale:"",defaultDateFormat:"Y-m-d",saveUserPreferences:!0,saveUserPreferencesMethod:"localStorage",defaultSorting:"",tableReset:!1,paging:!1,pageList:"normal",pageSize:10,pageSizes:[10,25,50,100,250,500],gotoPageArea:"combobox",sorting:!1,multiSorting:!1,multiSortingCtrlKey:!0,selecting:!1,multiselect:!1,openChildAsAccordion:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...s}};return this.deepMerge(t,e)}deepMerge(e,t){var s,a={...e};for(s in t)t[s]&&"object"==typeof t[s]&&!Array.isArray(t[s])?a[s]=this.deepMerge(a[s]||{},t[s]):a[s]=t[s];return a}verifyOptions(){this.options.pageSize&&!this.options.pageSizes.includes(this.options.pageSize)&&(this.options.pageSize=this.options.pageSizes[0])}static setMessages(e){Object.assign(s,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAsyncFieldOptions().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.updateSortingHeaders(),this.renderSortingInfo(),this.initColumnWidths()}initColumnWidths(){var e=this.columnList.filter(e=>{e=this.options.fields[e];return"hidden"!==e.visibility&&"separator"!==e.visibility});let t=e.length;e.forEach(e=>{e=this.options.fields[e];e.width=e.width||100/t+"%"})}normalizeColumnWidths(){var e=this.elements.mainContainer,t=this.columnList.map(e=>({th:this.elements.table.querySelector(`[data-field-name="${e}"]`),field:this.options.fields[e]})).filter(e=>e.th&&"hidden"!==e.field.visibility&&"separator"!==e.field.visibility);if(0!==t.length){let s=e.offsetWidth,a=0;t.forEach(e=>{var t=e.th.offsetWidth/s*100;e.field.width=t+"%",e.th.style.width=e.field.width,a+=t})}}parseDefaultSorting(e){let o=[];return e&&"string"==typeof e&&e.split(",").forEach(s=>{s=s.trim();if(s){var a=s.toUpperCase().indexOf(" DESC"),i=s.toUpperCase().indexOf(" ASC");let e="ASC",t=s;e=0<a?(t=s.slice(0,a).trim(),"DESC"):(t=(0<i?s.slice(0,i):s).trim(),"ASC");a=this.options.fields[t];a&&!1!==a.sorting&&o.push({fieldName:t,direction:e})}}),o}createPagingUI(){this.elements.bottomPanel=O.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=O.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=O.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=O.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=O.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=O.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=O.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});O.create("span",{textContent:this.options.messages.pageSizeChangeLabel,parent:e});let s=O.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100,250,500]).forEach(e=>{var t=O.create("option",{attributes:{value:e},textContent:e.toString(),parent:s});e===this.state.pageSize&&(t.selected=!0)}),s.addEventListener("change",e=>{this.changePageSize(parseInt(e.target.value))})}processFieldDefinitions(){this.fieldList=Object.keys(this.options.fields),this.fieldList.forEach(e=>{e=this.options.fields[e];!0===e.key?(void 0!==e.create&&e.create||(e.create=!0,e.type="hidden"),void 0!==e.edit&&e.edit||(e.edit=!0,e.type="hidden")):(e.create=e.create??!0,e.edit=e.edit??!0,e.list=e.list??!0,e.sorting=e.sorting??!0),e.visibility=e.visibility??"visible"}),this.columnList=this.fieldList.filter(e=>!1!==this.options.fields[e].list),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.info("No key field defined")}async resolveAsyncFieldOptions(){var e=this.columnList.map(async t=>{this.options.fields[t];var e=this.formBuilder.originalFieldOptions.get(t);if(this.formBuilder.shouldResolveOptions(e))try{var s=this.formBuilder.generateOptionsCacheKey("table",{});this.formBuilder.resolvedFieldOptions.get(t)?.[s]||await this.formBuilder.getFieldOptions(t,"table")}catch(e){console.error(`Failed to resolve table options for ${t}:`,e)}});await Promise.all(e)}async refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");if(0!==e.length)for(var t of e)for(var s of this.columnList){var a,i,o=this.options.fields[s];o.options&&(a=t.querySelector(`td[data-field-name="${s}"]`))&&(i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],s=this.getDisplayText(t.recordData,s,i),a.innerHTML=o.listEscapeHTML?O.escapeHtml(s):s)}}createMainStructure(){this.elements.mainContainer=O.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=O.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),O.create("div",{className:"ftable-title-text",innerHTML:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=O.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=O.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=O.create("table",{className:"ftable",parent:this.elements.tableDiv}),this.options.tableId&&(this.elements.table.id=this.options.tableId),this.createTableHeader(),this.createTableBody(),this.addNoDataRow()}createTableHeader(){var e=O.create("thead",{parent:this.elements.table});let o=O.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes){var t=O.create("th",{className:"ftable-command-column-header ftable-column-header-select",parent:o});if(this.options.multiselect){let e=O.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var e=this.options.fields[t],s=O.create("th",{className:`ftable-column-header ${e.listClass||""} `+(e.listClassHeader||""),attributes:{"data-field-name":t},parent:o}),a=(e.width&&(s.style.width=e.width),O.create("div",{className:"ftable-column-header-container",parent:s})),i=(e.tooltip&&a.setAttribute("title",e.tooltip),O.create("span",{className:"ftable-column-header-text",innerHTML:e.title||t,parent:a}));this.options.sorting&&!1!==e.sorting&&(O.addClass(i,"ftable-sortable-text"),O.addClass(s,"ftable-column-header-sortable"),s.addEventListener("click",e=>{e.preventDefault();e=e.ctrlKey||e.metaKey;this.sortByColumn(t,e)})),!1!==this.options.columnResizable&&!1!==e.columnResizable&&this.makeColumnResizable(s,a),"hidden"!==e.visibility&&"separator"!==e.visibility||O.hide(s)}),this.options.actions.updateAction&&O.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:o}),this.options.actions.cloneAction&&O.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:o}),this.options.actions.deleteAction&&O.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:o}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,s=O.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});for(let i of this.columnList){var o=this.options.fields[i],r=!1!==o.searchable,n=O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});if(r){r=O.create("div",{className:"ftable-column-header-container",parent:n});let s,a="text";o.searchType?a=o.searchType:!o.type&&o.options?a="select":o.type&&(a=o.type);var l="ftable-toolbarsearch-"+i;switch(a){case"date":case"datetime":case"datetime-local":if("undefined"!=typeof FDatepicker){let e=o.searchDateFormat||o.dateFormat||this.options.defaultDateFormat;var c=document.createElement("div"),d=O.create("input",{className:"ftable-toolbarsearch-extra",type:"hidden",id:"ftable-toolbarsearch-extra-"+i,attributes:{"data-field-name":i}});let t=O.create("input",{className:"ftable-toolbarsearch",id:"ftable-toolbarsearch-"+i,type:"text",placeholder:o.searchPlaceholder||o.placeholder||"",readOnly:!0});switch(c.appendChild(d),c.appendChild(t),a){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d",autoClose:!0})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d H:i:00"})},0)}s=c}else s=O.create("input",{className:"ftable-toolbarsearch",type:a,id:l,attributes:{"data-field-name":i}});break;case"checkbox":o.values||(o.values={0:this.options.messages.no,1:this.options.messages.yes}),s=await this.createSelectForSearch(i,o,!0);break;case"select":s=o.options?await this.createSelectForSearch(i,o,!1):O.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}});break;case"datalist":s=await this.createDatalistForSearch(i,o);break;default:s=O.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}})}if(s){r.appendChild(s),s.datalistElement&&s.datalistElement instanceof Node&&r.appendChild(s.datalistElement);let e=s;"SELECT"===(e=s.classList&&s.classList.contains("ftable-multiselect-container")&&s.hiddenSelect?s.hiddenSelect:e).tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)})}}"hidden"!==o.visibility&&"separator"!==o.visibility||O.hide(n)}this.options.toolbarsearch&&this.options.toolbarreset&&(e=O.create("th",{className:"ftable-toolbarsearch-column-header ftable-toolbarsearch-reset",parent:s}),0<(t=(this.options.actions.updateAction?1:0)+(this.options.actions.deleteAction?1:0)+(this.options.actions.cloneAction?1:0))?e.colSpan=t:O.addClass(e,"ftable-command-column-header"),O.create("button",{className:"ftable-toolbarsearch-reset-button",textContent:this.options.messages.resetSearch,attributes:{id:"ftable-toolbarsearch-reset-button"},parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,s){var a,i="ftable-toolbarsearch-"+e,o={};let r=e,n=!1;t.searchAttributes?(a=this.formBuilder.parseInputAttributes(t.searchAttributes),Object.assign(o,a),n=void 0!==a.multiple&&!1!==a.multiple):t.inputAttributes&&(a=this.formBuilder.parseInputAttributes(t.inputAttributes),Object.assign(o,a),n=void 0!==a.multiple&&!1!==a.multiple),n&&(r=e+"[]"),o["data-field-name"]=r;let l;if(s&&t.values?l=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):t.options&&(l=await this.formBuilder.getFieldOptions(e)),n)return this.createCustomMultiSelectForSearch(i,e,t,l,o);let c=O.create("select",{attributes:o,id:i,className:"ftable-toolbarsearch"});return 0<l?.length&&(""===l[0].Value||""===l[0].value||""===l[0]||""===l[0].DisplayText&&null==l[0].Value)||O.create("option",{value:"",innerHTML:" ",parent:c}),l&&Array.isArray(l)?l.forEach(e=>{O.create("option",{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,textContent:e.DisplayText||e.text||e,parent:c})}):l&&"object"==typeof l&&Object.entries(l).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:c})}),c}createCustomMultiSelectForSearch(e,t,s,a,i){var o=s.livesearch??("true"===i["data-livesearch"]||!0===i["data-livesearch"])??!1;return this.formBuilder._buildCustomMultiSelect({hiddenSelectId:e,hiddenSelectName:i["data-field-name"]||e,extraClasses:"ftable-multiselect-search ftable-toolbarsearch",containerDataFieldName:i["data-field-name"]||e,hiddenSelectAttributes:i,optionsSource:a,initialValues:[],placeholderText:s.searchPlaceholder||s.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:o,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!1})}async createDatalistForSearch(e,t){var s="ftable-toolbarsearch-"+e,a=s+"-datalist",i=O.create("datalist",{attributes:{id:a}}),s=O.create("input",{className:"ftable-toolbarsearch",type:"search",id:s,placeholder:t.searchPlaceholder||t.placeholder||"Type or select...",attributes:{"data-field-name":e,list:a}});s.datalistElement=i;let o;return t.searchOptions?o=t.searchOptions:t.options&&(o=await this.formBuilder.getFieldOptions(e,"table")),o&&this.formBuilder.populateDatalistOptions(i,o),s}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name");let s;s=e.multiple&&e.options?Array.from(e.selectedOptions).map(e=>e.value).filter(e=>""!==e.trim()).map(e=>e.trim()):e.value.trim(),this.state.currentPage=1,Array.isArray(s)&&0<s.length||!Array.isArray(s)&&s?this.state.searchQueries[t]=s:delete this.state.searchQueries[t],clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.load()},this.options.searchDebounceMs)}resetSearch(){this.state.searchQueries={},this.elements.table.querySelectorAll(".ftable-toolbarsearch").forEach(e=>{"SELECT"===e.tagName?e.selectedIndex=0:e.value=""}),this.elements.table.querySelectorAll(".ftable-multiselect-container").forEach(e=>{"function"==typeof e.resetMultiSelect&&e.resetMultiSelect()}),this.load()}getNextResizableHeader(t){var s=Array.from(this.elements.table.querySelectorAll("thead th.ftable-column-header-resizable"));for(let e=s.indexOf(t)+1;e<s.length;e++)if(null!==s[e].offsetParent)return s[e];return null}makeColumnResizable(a,e){O.addClass(a,"ftable-column-header-resizable"),this.elements.resizeBar||(this.elements.resizeBar=O.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),O.hide(this.elements.resizeBar));e=O.create("div",{className:"ftable-column-resize-handler",parent:e});let i=!1,o=0,r=0,n,l=null,c=0,d=null,h=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),i=!0,n=this.elements.mainContainer.getBoundingClientRect(),o=e.clientX,r=a.offsetWidth,(l=this.getNextResizableHeader(a))&&(c=l.offsetWidth,e=l.dataset.fieldName,d=this.options.fields[e]);e=a.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-n.left+"px",this.elements.resizeBar.style.top=e.top-n.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",O.show(this.elements.resizeBar),document.addEventListener("mousemove",h),document.addEventListener("mouseup",p)}),e=>{i&&(this.elements.resizeBar.style.left=e.clientX-n.left+"px")}),p=e=>{var t,s;i&&(i=!1,e=e.clientX-o,s=n.width,t=Math.max(50,r+e)/s*100,l&&(e=Math.max(50,c-e)/s*100,d.width=e.toFixed(2)+"%",l.style.width=d.width),(s=this.options.fields[a.dataset.fieldName]).width=t.toFixed(2)+"%",a.style.width=s.width,this.normalizeColumnWidths(),this.options.saveUserPreferences&&this.saveColumnSettings(),O.hide(this.elements.resizeBar),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",p))}}saveColumnSettings(){if(this.options.saveUserPreferences){let a={};this.columnList.forEach(e=>{var t,s=this.elements.table.querySelector(`[data-field-name="${e}"]`);s&&(t=this.options.fields[e],a[e]={width:s.style.width||t.width||"auto",visibility:t.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(a))}}saveState(){var e;this.options.saveUserPreferences&&(e={sorting:this.state.sorting,pageSize:this.state.pageSize},this.userPrefs.set("table-state",JSON.stringify(e)))}loadColumnSettings(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("column-settings");if(e)try{var t=JSON.parse(e);Object.entries(t).forEach(([e,t])=>{e=this.options.fields[e];e&&(t.width&&(e.width=t.width),t.visibility)&&(e.visibility=t.visibility)})}catch(e){this.logger.warn("Failed to load column settings:",e)}}}loadState(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("table-state");if(e)try{var t=JSON.parse(e);Array.isArray(t.sorting)&&(this.state.sorting=t.sorting),t.pageSize&&this.options.pageSizes.includes(t.pageSize)&&(this.state.pageSize=t.pageSize)}catch(e){this.logger.warn("Failed to load table state:",e)}}}createTableBody(){this.elements.tableBody=O.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=O.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,O.create("td",{attributes:{colspan:t},textContent:this.options.messages.noDataAvailable,parent:e}))}removeNoDataRow(){var e=this.elements.tableBody.querySelector(".ftable-no-data-row");e&&e.remove()}createModals(){this.options.actions.createAction&&this.createAddRecordModal(),this.options.actions.updateAction&&this.createEditRecordModal(),this.options.actions.deleteAction&&this.createDeleteConfirmModal(),this.createErrorModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new o({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>this.modals.deleteConfirm.close()},{text:this.options.messages.deleteText,className:"ftable-dialog-deletebutton",onClick:()=>this.confirmDelete()}]})}createErrorModal(){this.modals.error=new o({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createInfoModal(){this.modals.info=new o({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new o({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",closeOnOverlayClick:!1,content:`<div class="ftable-loading-message">${this.options.messages.loadingMessage}</div>`})}bindEvents(){this.subscribeOptionEvents(),this.createCustomToolbarItems(),this.createToolbarButtons(),this.bindKeyboardEvents(),!1!==this.options.columnSelectable&&this.createColumnSelectionMenu()}subscribeOptionEvents(){["formCreated","formClosed","recordsLoaded","recordAdded","recordUpdated","recordDeleted","selectionChanged"].forEach(e=>{"function"==typeof this.options[e]&&this.on(e,this.options[e])})}createColumnSelectionMenu(){this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null,this.elements.table.querySelector("thead").addEventListener("contextmenu",e=>{e.preventDefault(),this.showColumnSelectionMenu(e)})}showColumnSelectionMenu(e){this.hideColumnSelectionMenu(),this.elements.columnSelectionOverlay=O.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=O.create("div",{className:"ftable-column-selection-container",parent:document.body}),this.populateColumnSelectionMenu(),this.positionColumnSelectionMenu(e),this.elements.columnSelectionOverlay.addEventListener("click",e=>{e.target===this.elements.columnSelectionOverlay&&this.hideColumnSelectionMenu()}),this.elements.columnSelectionOverlay.addEventListener("contextmenu",e=>{e.preventDefault(),this.hideColumnSelectionMenu()})}populateColumnSelectionMenu(){let l=O.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(t=>{var e=this.options.fields[t],s="hidden"!==e.visibility,a="fixed"===e.visibility,i="separator"===e.visibility,o=this.isFieldSorted(t),r=O.create("li",{className:"ftable-column-select-item",parent:l}),n=O.create("label",{className:"ftable-column-select-label",parent:r});if(!i){let e=O.create("input",{attributes:{type:"checkbox",id:"column-"+t},parent:n});e.checked=s,(a||o&&s)&&(e.disabled=!0,r.style.opacity="0.6"),e.disabled||e.addEventListener("change",()=>{this.setColumnVisibility(t,e.checked)})}a=O.create("span",{textContent:e.title||t,style:i?"font-weight: bold;":null,parent:n});o&&((s=O.create("span",{className:"ftable-sort-indicator",textContent:" (sorted)",parent:a})).style.fontSize="0.8em",s.style.color="#666")})}positionColumnSelectionMenu(e){var t=this,s=e.pageX,e=e.pageY,e=(t.elements.columnSelectionMenu.style.position="absolute",t.elements.columnSelectionMenu.style.left=s+"px",t.elements.columnSelectionMenu.style.top=e+"px",t.elements.columnSelectionMenu.style.minWidth="100px",t.elements.columnSelectionMenu.style.boxSizing="border-box",t.elements.columnSelectionMenu.offsetWidth),a=window.innerWidth;a<s+e&&(s=Math.max(10,a-e-10),t.elements.columnSelectionMenu.style.left=s+"px")}hideColumnSelectionMenu(){this.elements.columnSelectionOverlay&&(this.elements.columnSelectionOverlay.remove(),this.elements.columnSelectionMenu.remove(),this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null)}isFieldSorted(t){return this.state.sorting.some(e=>e.fieldName===t)}createToolbarButtons(){this.options.csvExport&&this.addToolbarButton({text:this.options.messages.csvExport,className:"ftable-toolbar-item-csv",onClick:()=>{var e=this.options.title?this.options.title.replace(/[^a-z0-9]/gi,"-").toLowerCase()+".csv":"table-export.csv";this.exportToCSV(e)}}),this.options.printTable&&this.addToolbarButton({text:this.options.messages.printTable,className:"ftable-toolbar-item-print",onClick:()=>{this.printTable()}}),this.options.actions.createAction&&this.addToolbarButton({text:this.options.messages.addNewRecord,className:"ftable-toolbar-item-add-record",addIconSpan:!0,onClick:()=>this.showAddRecordForm()})}addToolbarButton(t){var e,s=O.create("button",{className:"ftable-toolbar-item "+(t.className||""),id:t.id||null,title:t.title||null,textContent:t.text||null,type:"button",parent:this.elements.toolbarDiv});return t.addIconSpan&&(e=O.create("span",{className:"ftable-toolbar-item-icon "+(t.className||""),parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.icon&&(e=O.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.onClick&&s.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.onClick(e)}),t.disabled&&(s.disabled=!0),s}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach((e,t)=>{this.addToolbarButton({text:e.text||"",className:"ftable-toolbar-item-custom "+(e.buttonClass||""),id:e.buttonId||"ftable-toolbar-item-custom-id-"+t,title:e.tooltip||"",icon:e.icon||null,onClick:"function"==typeof e.click?e.click:null})})}bindKeyboardEvents(){this.options.selecting&&(document.addEventListener("keydown",e=>{"Shift"===e.key&&(this.shiftKeyDown=!0)}),document.addEventListener("keyup",e=>{"Shift"===e.key&&(this.shiftKeyDown=!1)}))}setupFTableUserPreferences(){var e;this.options.saveUserPreferences&&(e=this.userPrefs.generatePrefix(this.options.tableId||"",this.fieldList),this.userPrefs=new i(e,this.options.saveUserPreferencesMethod),this.loadState(),this.loadColumnSettings())}async load(e={}){if(!this.state.isLoading){this.state.isLoading=!0,this.showLoadingIndicator();try{var t={...e,...this.buildLoadParams()},s=await this.performLoad(t);this.processLoadedData(s),this.emit("recordsLoaded",{records:s.Records,serverResponse:s})}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Load failed: "+e.message)}finally{this.state.isLoading=!1,this.hideLoadingIndicator()}this.renderSortingInfo(),this.normalizeColumnWidths()}}buildLoadParams(){var e,t={};if(this.options.paging&&(this.state.pageSize||(this.state.pageSize=this.options.pageSize),t.jtStartIndex=(this.state.currentPage-1)*this.state.pageSize,t.jtPageSize=this.state.pageSize),this.options.sorting&&(0<this.state.sorting.length?t.jtSorting=this.state.sorting.map(e=>e.fieldName+" "+e.direction).join(", "):this.options.defaultSorting&&(t.jtSorting=this.parseDefaultSorting(this.options.defaultSorting).map(e=>e.fieldName+" "+e.direction).join(", "))),this.options.toolbarsearch&&0<Object.keys(this.state.searchQueries).length){let s=[],a=[];Object.entries(this.state.searchQueries).forEach(([t,e])=>{Array.isArray(e)?e.forEach(e=>{""!==e&&null!=e&&(s.push(e),a.push(t))}):""!==e&&(s.push(e),a.push(t))}),0<s.length&&(t.q=s,t.opt=a)}return"function"==typeof this.options.listQueryParams&&(e=this.options.listQueryParams(),Object.assign(t,e)),t}isCacheExpired(e,t){return!e||!e.timestamp||t<Date.now()-e.timestamp}async performLoad(e){var t=this.options.actions.listAction;if(this.options.listCache&&"string"==typeof t){var s=this.formBuilder.optionsCache.get(t,e);if(s&&!this.isCacheExpired(s,this.options.listCache))return s.data}let a;if("function"==typeof t)a=await t(e);else{if("string"!=typeof t)throw new Error("No valid listAction provided");a=this.options.forcePost?await l.post(t,e):await l.get(t,e)}if(a&&"OK"===a.Result)return this.options.listCache&&"string"==typeof t&&this.formBuilder.optionsCache.set(t,e,{data:a,timestamp:Date.now()}),a;throw new Error(a?.Message||"Invalid response from server")}processLoadedData(e){"OK"!==e.Result?this.showError(e.Message||"Unknown error occurred"):(this.state.records=e.Records||[],this.state.totalRecordCount=e.TotalRecordCount||this.state.records.length,this.renderTableData(),this.updatePagingInfo())}renderTableData(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>e.remove()),0===this.state.records.length?this.addNoDataRow():(this.removeNoDataRow(),this.state.records.forEach(e=>{e=this.createTableRow(e);this.elements.tableBody.appendChild(e)}),this.refreshRowStyles())}createTableRow(t){let s=O.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(t)}});return s.recordData=t,this.options.selecting&&this.options.selectingCheckboxes&&this.addSelectingCell(s),this.columnList.forEach(e=>{this.addDataCell(s,t,e)}),this.options.actions.updateAction&&this.addEditCell(s),this.options.actions.cloneAction&&this.addCloneCell(s),this.options.actions.deleteAction&&this.addDeleteCell(s),this.options.selecting&&this.makeRowSelectable(s),s}addSelectingCell(t){var e=O.create("td",{className:"ftable-command-column ftable-selecting-column",parent:t});O.create("input",{className:"norowselectonclick",attributes:{type:"checkbox"},parent:e}).addEventListener("change",e=>{this.toggleRowSelection(t)})}addDataCell(e,t,s){var a=this.options.fields[s],i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],t=this.getDisplayText(t,s,i),i=O.create("td",{className:`${a.listClass||""} `+(a.listClassEntry||""),innerHTML:a.listEscapeHTML?O.escapeHtml(t):t,attributes:{"data-field-name":s},parent:e});"fixed"===a.visibility||"hidden"!==a.visibility&&"separator"!==a.visibility||O.hide(i)}addEditCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},innerHTML:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},innerHTML:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},innerHTML:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t,s=null){var a=this.options.fields[t],i=e[t],s=s||a.options;let o=i;return"date"===a.type&&i&&(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDate(i,a.dateLocale||this.options.defaultDateLocale)),"datetime-local"!==a.type&&"datetime"!==a.type||!i||(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDateTime(i,a.dateLocale||this.options.defaultDateLocale)),"checkbox"===a.type&&(o=this.getCheckboxText(t,i)),s&&(t=this.findOptionByValue(s,i),o=t?t.DisplayText||t.text||t:i),(o=a.display&&"function"==typeof a.display?a.display({record:e,value:i,displayValue:o}):o)||""}_parseDate(e){return e.includes("Date")?new Date(parseInt(e.substr(6),10)):10==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10)):19==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10),parseInt(e.substr(11,2),10),parseInt(e.substr(14,2),10),parseInt(e.substr(17,2),10)):new Date(e)}formatDate(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleDateString(t,{year:"numeric",month:"2-digit",day:"2-digit"})}catch{return e}}formatDateTime(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleString(t)}catch{return e}}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?this.options.messages.yes:this.options.messages.no}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):"object"==typeof e&&null!==e&&e.hasOwnProperty(t)?e[t]:null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?O.addClass(e,"ftable-row-even"):O.removeClass(e,"ftable-row-even")})}getKeyValue(e){return this.keyField?e[this.keyField]:null}async showAddRecordForm(){var e=await this.formBuilder.createForm("create");this.modals.addRecord.setContent(e),this.modals.addRecord.show(),this.currentForm=e,this.emit("formCreated",{form:e,formType:"create",record:null})}async saveNewRecord(){if(this.currentForm)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performCreate(e);"OK"===t.Result?(this.clearListCache(),this.modals.addRecord.close(),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),t.Message&&this.showInfo(t.Message),await this.load(),this.emit("recordAdded",{record:t.Record})):this.showError(t.Message||"Create failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Create failed: "+e.message)}}else this.currentForm.reportValidity()}async editRecord(e){var t=e.recordData,s=await this.formBuilder.createForm("edit",t);this.modals.editRecord.setContent(s),this.modals.editRecord.show(),this.currentForm=s,this.currentEditingRow=e,this.emit("formCreated",{form:s,formType:"edit",record:t})}async saveEditedRecord(){if(this.currentForm&&this.currentEditingRow)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performUpdate(e);"OK"===t.Result?(this.clearListCache(),this.modals.editRecord.close(),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,this.emit("formClosed",{form:this.currentForm,formType:"edit",record:this.currentEditingRow.recordData}),this.updateRowData(this.currentEditingRow,t.Record||e),t.Message&&this.showInfo(t.Message),this.emit("recordUpdated",{record:t.Record||e,row:this.currentEditingRow})):this.showError(t.Message||"Update failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Update failed: "+e.message)}}else this.currentForm.reportValidity()}async cloneRecord(e){var e={...e.recordData},t=(this.keyField&&(e[this.keyField]=""),await this.formBuilder.createForm("create",e));this.modals.addRecord.options.content=t,this.modals.addRecord.setContent(t),this.modals.addRecord.show(),this.currentForm=t,this.emit("formCreated",{form:t,formType:"create",record:e})}async deleteRows(e){if(e.length){var t=this.options.messages.areYouSure;if(confirm(t)){var s,a=[];for(s of e)try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});t=a.filter(e=>!e.success).length;0<t&&this.showError(t+` of ${a.length} records could not be deleted`),this.refreshRowStyles(),this.updatePagingInfo()}}}deleteRecord(e){var t=e.recordData;let s=this.options.messages.deleteConfirmation;if("function"==typeof this.options.deleteConfirmation){t={row:e,record:t,deleteConfirmMessage:s,cancel:!1,cancelMessage:this.options.messages.cancel};if(this.options.deleteConfirmation(t),t.cancel)return void(t.cancelMessage&&this.showError(t.cancelMessage));s=t.deleteConfirmMessage}this.modals.deleteConfirm.setContent(`<p>${s}</p>`),this.modals.deleteConfirm.show(),this.currentDeletingRow=e}async confirmDelete(){if(this.currentDeletingRow){var e=this.getKeyValue(this.currentDeletingRow.recordData);try{var t=await this.performDelete(e);"OK"===t.Result?(this.clearListCache(),this.modals.deleteConfirm.close(),this.removeRowFromTable(this.currentDeletingRow),t.Message&&this.showInfo(t.Message),this.emit("recordDeleted",{record:this.currentDeletingRow.recordData})):this.showError(t.Message||"Delete failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Delete failed: "+e.message)}}}async performCreate(e){var t=this.options.actions.createAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid createAction provided")}async performUpdate(e){var t=this.options.actions.updateAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid updateAction provided")}async performDelete(e){var t=this.options.actions.deleteAction;let s;if(s=null===e||"object"!=typeof e||Array.isArray(e)?{[this.keyField]:e}:e,"function"==typeof t)return t(s);if("string"==typeof t)return l.post(t,s);throw new Error("No valid deleteAction provided")}getFormData(e){var t,s,a,i={};for([t,s]of new FormData(e).entries())t.endsWith("[]")?(i[a=t.slice(0,-2)]||(i[a]=[]),i[a].push(s)):i.hasOwnProperty(t)?Array.isArray(i[t])?i[t].push(s):i[t]=[i[t],s]:i[t]=s;return i}updateRowData(i,e){i.recordData={...i.recordData,...e},Object.keys(e).forEach(e=>{var t,s,a=this.options.fields[e];a&&(t=i.querySelector(`td[data-field-name="${e}"]`))&&(s=this.formBuilder.generateOptionsCacheKey("table",{}),s=this.formBuilder.resolvedFieldOptions.get(e)?.[s],e=this.getDisplayText(i.recordData,e,s),t.innerHTML=a.listEscapeHTML?O.escapeHtml(e):e,t.className=(`${a.listClass||""} `+(a.listClassEntry||"")).trim())})}removeRowFromTable(e){e.remove(),0===this.elements.tableBody.querySelectorAll(".ftable-data-row").length&&this.addNoDataRow(),this.refreshRowStyles()}makeRowSelectable(t){!1!==this.options.selectOnRowClick&&t.addEventListener("click",e=>{["INPUT","BUTTON","SELECT","TEXTAREA","A"].includes(e.target.tagName)||e.target.classList.contains("norowselectonclick")||this.toggleRowSelection(t)})}toggleRowSelection(e){var t=e.classList.contains("ftable-row-selected");if(this.shiftKeyDown&&this.lastSelectedRow&&this.options.multiselect){this.clearAllSelections();var s=Array.from(this.elements.tableBody.querySelectorAll(".ftable-data-row")),a=s.indexOf(this.lastSelectedRow),i=s.indexOf(e),[i,o]=a<i?[a,i]:[i,a];for(let e=i;e<=o;e++)this.selectRow(s[e])}else this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e);t&&!this.shiftKeyDown||(this.lastSelectedRow=e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){O.addClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!0),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.add(t)}deselectRow(e){O.removeClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!1),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.delete(t)}recalcColumnWidths(){this.columnList.forEach(e=>{var t=this.options.fields[e],e=this.elements.table.querySelector(`[data-field-name="${e}"]`);e&&t.width&&(e.style.width=t.width)}),this.elements.table.offsetHeight}recalcColumnWidthsOnce(){this._recalculatedOnce||(this.recalcColumnWidths(),this._recalculatedOnce=!0)}clearAllSelections(){this.elements.tableBody.querySelectorAll(".ftable-row-selected").forEach(e=>this.deselectRow(e))}toggleSelectAll(t){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{t?this.selectRow(e):this.deselectRow(e)}),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}getSelectedRows(){return Array.from(this.elements.tableBody.querySelectorAll(".ftable-row-selected"))}sortByColumn(s,a=!1){var i=this.options.fields[s];if(i&&!1!==i.sorting){i=this.state.sorting.findIndex(e=>e.fieldName===s);let e=!0,t="ASC";0<=i?"ASC"===this.state.sorting[i].direction?(t="DESC",this.state.sorting[i].direction=t):(this.state.sorting.splice(i,1),e=!1):this.state.sorting.push({fieldName:s,direction:t}),(!this.options.multiSorting||this.options.multiSortingCtrlKey&&!a)&&(this.state.sorting=e?[{fieldName:s,direction:t}]:[]),this.updateSortingHeaders(),this.load(),this.saveState()}}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{O.removeClass(e,"ftable-column-header-sorted-asc ftable-column-header-sorted-desc")}),this.state.sorting.forEach(e=>{var t=this.elements.table.querySelector(`[data-field-name="${e.fieldName}"]`);t&&O.addClass(t,"ftable-column-header-sorted-"+e.direction.toLowerCase())})}updatePagingInfo(){var e,t,s;this.options.paging&&this.elements.pageInfoSpan&&(this.state.totalRecordCount<=0?(this.elements.pageInfoSpan.textContent="",this.elements.pagingListArea.innerHTML=""):(e=(this.state.currentPage-1)*this.state.pageSize+1,t=Math.min(this.state.currentPage*this.state.pageSize,this.state.totalRecordCount),s=this.options.messages.pagingInfo||"Showing {0}-{1} of {2}",this.elements.pageInfoSpan.textContent=s.replace(/\{0\}/g,e).replace(/\{1\}/g,t).replace(/\{2\}/g,this.state.totalRecordCount),this.createPageListNavigation(),this.createPageGotoNavigation()))}createPageListNavigation(){if(this.elements.pagingListArea){this.elements.pagingListArea.innerHTML="";var e=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(!(e<=1)){if(this.createPageButton("«",1,1===this.state.currentPage,"ftable-page-number-first"),this.createPageButton("‹",this.state.currentPage-1,1===this.state.currentPage,"ftable-page-number-previous"),"normal"==this.options.pageList){var s=this.calculatePageNumbers(e);let t=0;s.forEach(e=>{1<e-t&&O.create("span",{className:"ftable-page-number-space",textContent:"...",parent:this.elements.pagingListArea}),this.createPageButton(e.toString(),e,!1,e===this.state.currentPage?"ftable-page-number ftable-page-number-active":"ftable-page-number"),t=e})}this.createPageButton("›",this.state.currentPage+1,this.state.currentPage>=e,"ftable-page-number-next"),this.createPageButton("»",e,this.state.currentPage>=e,"ftable-page-number-last")}}}createPageGotoNavigation(){if(this.options.paging&&"none"!==this.options.gotoPageArea){let s=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(s<=1)this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML="";else{this.elements.pagingGotoArea.style.display="inline-block",this.elements.pagingGotoArea.innerHTML="";O.create("span",{textContent:this.options.messages.gotoPageLabel+": ",parent:this.elements.pagingGotoArea});var e="ftable-goto-page-"+(this.options.tableId||"default");if("combobox"===this.options.gotoPageArea){this.elements.gotoPageSelect=O.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=s;e++)O.create("option",{attributes:{value:e},textContent:e,parent:this.elements.gotoPageSelect});this.elements.gotoPageSelect.value=this.state.currentPage,this.elements.gotoPageSelect.addEventListener("change",e=>{e=parseInt(e.target.value);1<=e&&e<=s&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=O.create("input",{attributes:{type:"number",id:e,min:"1",max:s,value:this.state.currentPage,className:"ftable-page-goto-input",style:"width: 65px; margin-left: 4px;"},parent:this.elements.pagingGotoArea}),this.elements.gotoPageInput.addEventListener("change",e=>{var t=parseInt(e.target.value);1<=t&&t<=s?this.changePage(t):e.target.value=this.state.currentPage}))}}else this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML=""}createPageButton(e,t,s,a){a=O.create("span",{className:a+(s?" ftable-page-number-disabled":""),innerHTML:e,parent:this.elements.pagingListArea});s||(a.style.cursor="pointer",a.addEventListener("click",e=>{e.preventDefault(),this.changePage(t)}))}calculatePageNumbers(t){if(t<=7)return Array.from({length:t},(e,t)=>t+1);var s=this.state.currentPage,a=new Set([1,2,t-1,t]);for(let e=Math.max(1,s-1);e<=Math.min(t,s+1);e++)a.add(e);return Array.from(a).sort((e,t)=>e-t)}changePage(e){var t=Math.ceil(this.state.totalRecordCount/this.state.pageSize);(e=Math.max(1,Math.min(e,t)))!==this.state.currentPage&&(this.state.currentPage=e,this.load())}changePageSize(e){this.state.pageSize=e,this.state.currentPage=1,this.load(),this.saveState()}showLoadingIndicator(){0===this.options.loadingAnimationDelay?this.modals.loading&&this.modals.loading.show():this.loadingTimeout=setTimeout(()=>{this.modals.loading&&this.modals.loading.show(),this.loadingShownAt=Date.now()},this.options.loadingAnimationDelay||500)}hideLoadingIndicator(){this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null);var e=this.loadingShownAt?Date.now()-this.loadingShownAt:0;this.modals.loading&&(e<200?setTimeout(()=>{this.modals.loading.hide()},200-e):this.modals.loading.hide()),this.loadingShownAt=null}showError(e){this.modals.error?(this.modals.error.setContent(`<p>${e}</p>`),this.modals.error.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(`<p>${e}</p>`),this.modals.info.show()):alert(e)}reload(e=!1){return this.clearListCache(),e?this.preservedSelections=new Set(this.state.selectedRecords):this.state.selectedRecords.clear(),this.load().then(()=>(e&&this.preservedSelections&&(this.restoreSelections(),this.preservedSelections=null),this))}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}restoreSelections(){if(this.preservedSelections)return this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{var t=this.getKeyValue(e.recordData);t&&this.preservedSelections.has(t)&&this.selectRow(e)}),this}getRowByKey(e){return this.elements.tableBody.querySelector(`[data-record-key="${e}"]`)}destroy(){this.element&&this.element.ftableInstance&&(this.element.ftableInstance=null),Object.values(this.modals).forEach(e=>e.destroy()),this.elements.mainContainer&&this.elements.mainContainer.remove(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.loadingTimeout&&clearTimeout(this.loadingTimeout),window.removeEventListener("resize",this.handleResize),this.options=null,this.state=null,this.elements=null,this.formBuilder=null,this.modals=null}setOption(e,t){return this.options[e]=t,this}getState(){return{...this.state}}addFilter(t,e,s="equals"){return this.state.filters||(this.state.filters=[]),this.state.filters=this.state.filters.filter(e=>e.fieldName!==t),null!=e&&""!==e&&this.state.filters.push({fieldName:t,value:e,operator:s}),this}clearFilters(){return this.state.filters=[],this}exportToCSV(e="table-data.csv"){var t,s,a,i=this.elements.table.cloneNode(!0),o=[],r=e=>`"${String(e||"").replace(/"/g,'""')}"`,n=[];for(t of i.querySelectorAll("thead th"))t.classList.contains("ftable-command-column-header")||t.classList.contains("ftable-toolbarsearch-column-header")||"none"===t.style.display||(s=t.textContent.trim(),n.push(r(s)));o.push(n.join(","));for(a of i.querySelectorAll("tbody tr"))if("none"!==a.style.display){var l,c,d,h=[];let e=!1;for(l of a.querySelectorAll("td"))l.classList.contains("ftable-command-column")||"none"===l.style.display||(l.querySelector("img, button, input, select")&&(l.innerHTML=l.textContent),c=l.innerHTML.replace(/<br\s*\/?>/gi,"\n"),(d=document.createElement("div")).innerHTML=c,h.push(r(d.textContent||"")),e=!0);e&&o.push(h.join(","))}var i=o.join("\n"),i=new Blob(["\ufeff"+i],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a");p.href=URL.createObjectURL(i),p.download=e,p.click(),p.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
|
|
1
|
+
(e=>{let s={serverCommunicationError:"An error occurred while communicating to the server.",loadingMessage:"Loading records...",noDataAvailable:"No data available!",addNewRecord:"Add new record",editRecord:"Edit record",areYouSure:"Are you sure?",deleteConfirmation:"This record will be deleted. Are you sure?",yes:"Yes",no:"No",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",close:"Close",cannotLoadOptionsFor:"Cannot load options for field {0}!",pagingInfo:"Showing {0}-{1} of {2}",canNotDeletedRecords:"Can not delete {0} of {1} records!",deleteProgress:"Deleting {0} of {1} records, processing...",pageSizeChangeLabel:"Row count",gotoPageLabel:"Go to page",sortingInfoPrefix:"Sorting applied: ",sortingInfoSuffix:"",ascending:"Ascending",descending:"Descending",sortingInfoNone:"No sorting applied",resetSorting:"Reset sorting",csvExport:"CSV",printTable:"🖨️ Print",cloneRecord:"Clone Record",resetTable:"Reset table",resetTableConfirm:"This will reset all columns, pagesize, sorting to their defaults. Do you want to continue?",resetSearch:"Reset"};class t{constructor(){this.cache=new Map,this.pendingRequests=new Map}generateKey(e,t){return e+"?"+Object.keys(t||{}).sort().map(e=>e+"="+t[e]).join("&")}get(e,t){e=this.generateKey(e,t);return this.cache.get(e)}set(e,t,s){e=this.generateKey(e,t);this.cache.set(e,s)}clear(e=null,t=null){if(e)if(t){t=this.generateKey(e,t);this.cache.delete(t)}else{var s,a=e.split("?")[0];for([s]of this.cache)s.startsWith(a)&&this.cache.delete(s)}else this.cache.clear()}async getOrCreate(e,t,s){let a=this.generateKey(e,t);e=this.cache.get(a);return e||(this.pendingRequests.has(a)?this.pendingRequests.get(a):(t=(async()=>{try{var e=await s();return this.cache.set(a,e),e}finally{this.pendingRequests.delete(a)}})(),this.pendingRequests.set(a,t),t))}size(){return this.cache.size}}class a{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=a.LOG_LEVELS.WARN){this.level=e}log(t,e){var s;!window.console||t<this.level||(s=Object.keys(a.LOG_LEVELS).find(e=>a.LOG_LEVELS[e]===t),console.log(`fTable ${s}: `+e))}debug(e){this.log(a.LOG_LEVELS.DEBUG,e)}info(e){this.log(a.LOG_LEVELS.INFO,e)}warn(e){this.log(a.LOG_LEVELS.WARN,e)}error(e){this.log(a.LOG_LEVELS.ERROR,e)}}class O{static PROPERTY_ATTRIBUTES=new Set(["value","checked","selected","disabled","readOnly","name","id","type","placeholder","min","max","step","required","multiple","accept","className","textContent","innerHTML","title"]);static create(e,t={}){let s=document.createElement(e);return void 0!==t.style&&(s.style.cssText=t.style),O.PROPERTY_ATTRIBUTES.forEach(e=>{e in t&&null!==t[e]&&(s[e]=t[e])}),void 0!==t.parent&&t.parent.appendChild(s),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{null!==t&&(O.PROPERTY_ATTRIBUTES.has(e)?s[e]=t:s.setAttribute(e,t))}),s}static find(e,t=document){return t.querySelector(e)}static findAll(e,t=document){return Array.from(t.querySelectorAll(e))}static addClass(e,t){e.classList.add(...t.split(" "))}static removeClass(e,t){e.classList.remove(...t.split(" "))}static toggleClass(e,t){e.classList.toggle(t)}static show(e){e.style.display=""}static hide(e){e.style.display="none"}static escapeHtml(e){if(!e)return e;let t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>t[e])}}class n{static async request(e,t={}){var s={method:"GET",headers:{}},a={...s,...t};t.headers&&(a.headers={...s.headers,...t.headers});try{var i=await fetch(e,a);if(401===i.status)throw new Error("Unauthorized");if(!i.ok)throw new Error("HTTP error! status: "+i.status);var o=i.headers.get("content-type");if(o&&o.includes("application/json"))return await i.json();var r=await i.text();try{return JSON.parse(r)}catch{return{Result:"OK",Message:r}}}catch(e){throw e}}static async get(e,t={}){let a=new URL(e,window.location.href);return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.endsWith("[]")?e:e+"[]";s.forEach(e=>{null!=e&&a.searchParams.append(t,e)})}else a.searchParams.append(e,s)}),this.request(a.toString(),{method:"GET",headers:{"Content-Type":"application/x-www-form-urlencoded"}})}static async post(e,t={}){e=new URL(e,window.location.href);let a=new FormData;return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.endsWith("[]")?e:e+"[]";s.forEach(e=>{null!=e&&a.append(t,e)})}else a.append(e,s)}),this.request(e.toString(),{method:"POST",body:a})}}class i{constructor(e,t="localStorage"){this.prefix=e,this.method=t}set(e,t){var s,e=""+this.prefix+e;"localStorage"===this.method?localStorage.setItem(e,t):((s=new Date).setDate(s.getDate()+30),document.cookie=e+`=${t}; expires=${s.toUTCString()}; path=/`)}get(e){e=""+this.prefix+e;if("localStorage"===this.method)return localStorage.getItem(e);var t,s=e+"=";for(t of decodeURIComponent(document.cookie).split(";")){for(;" "===t.charAt(0);)t=t.substring(1);if(0===t.indexOf(s))return t.substring(s.length,t.length)}return null}remove(e){e=""+this.prefix+e;"localStorage"===this.method?localStorage.removeItem(e):document.cookie=e+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"}generatePrefix(e,t){e=e?e+"#":"";return"ftable#"+(t=>{let s=0;if(0!==t.length)for(let e=0;e<t.length;e++){var a=t.charCodeAt(e);s=(s<<5)-s+a,s&=s}return s})(e+=t.join("$")+"#c"+t.length)}}class o{constructor(e={}){this.options={title:"Modal",content:"",buttons:[],className:"ftable-modal",parent:document.body,...e},this.overlay=null,this.modal=null,this.isOpen=!1}create(){this.overlay=O.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=O.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});O.create("h2",{className:"ftable-modal-header",textContent:this.options.title,parent:this.modal});O.create("span",{className:"ftable-modal-close",innerHTML:"×",parent:this.modal}).addEventListener("click",()=>this.close());var e=O.create("div",{className:"ftable-modal-body",parent:this.modal});if("string"==typeof this.options.content?e.innerHTML=this.options.content:e.appendChild(this.options.content),0<this.options.buttons.length){let s=O.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=O.create("button",{className:"ftable-dialog-button "+(e.className||""),innerHTML:`<span>${e.text}</span>`,parent:s});e.onClick&&(t._originalOnClick=e.onClick,t.addEventListener("click",this._createWrappedClickHandler(t)))})}return this.options.closeOnOverlayClick&&this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.hide(),this}show(){return this.modal||this.create(),this.overlay.style.display="flex",this.isOpen=!0,this.modal.querySelectorAll(".ftable-dialog-button").forEach(e=>{e.disabled=!1}),this}hide(){return this.overlay&&(this.overlay.style.display="none"),this.isOpen=!1,this}close(){return this.hide(),this.options.onClose&&this.options.onClose(),this}destroy(){return this.overlay&&this.overlay.remove(),this.isOpen=!1,this}setContent(e){this.options.content=e;var t=this.modal.querySelector(".ftable-modal-body");t&&(t.innerHTML="","string"==typeof e?t.innerHTML=e:t.appendChild(e))}_createWrappedClickHandler(a){return async e=>{a.disabled=!0;try{var t,s=a._originalOnClick;"function"==typeof s&&(t=s.call(a,e))instanceof Promise&&await t}catch(e){console.error("Modal button action failed:",e)}finally{a.disabled=!1}}}}class r{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t,this.originalFieldOptions=new Map,this.resolvedFieldOptions=new Map,Object.keys(this.options.fields||{}).forEach(e=>{this.resolvedFieldOptions.set(e,{})}),Object.entries(this.options.fields).forEach(([e,t])=>{this.originalFieldOptions.set(e,t.options)})}async getFieldOptions(t,s="table",e={}){var a=this.options.fields[t],i=this.originalFieldOptions.get(t);if(!i)return null;var o=this.shouldForceRefreshForContext(a,s,e),r=this.generateOptionsCacheKey(s,e);if(!o&&!e.forceRefresh){var l=this.resolvedFieldOptions.get(t)[r];if(l)return l}try{var n={...a,options:i},c=await this.resolveOptions(n,{...e},s,o);return this.resolvedFieldOptions.get(t)[r]=c}catch(e){return console.error(`Failed to resolve options for ${t} (${s}):`,e),i}}clearResolvedOptions(e=null,s=null){e?this.resolvedFieldOptions.has(e)&&(s?this.resolvedFieldOptions.get(e)[s]=null:this.resolvedFieldOptions.set(e,{table:null,create:null,edit:null})):s?this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.get(t)[s]=null}):this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.set(t,{table:null,create:null,edit:null})})}shouldForceRefreshForContext(e,t,s){return!!e.noCache&&("boolean"==typeof e.noCache?e.noCache:"function"==typeof e.noCache?e.noCache({context:t,...s}):"object"==typeof e.noCache&&!0===e.noCache[t])}generateOptionsCacheKey(e,t){let s=[e];return t.dependedValues&&Object.keys(t.dependedValues).sort().forEach(e=>{s.push(e+"="+t.dependedValues[e])}),s.join("|")}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,s,a){var i=O.create("div",{className:"hidden"!=t.type?"ftable-input-field-container":"",attributes:{id:"ftable-input-field-container-div-"+e}}),t=("hidden"!=t.type&&O.create("div",{className:"ftable-input-label",textContent:t.inputTitle||t.title,parent:i}),this.createInput(e,t,s[e],a));return i.appendChild(t),i}async createForm(e="create",t={}){this.currentFormRecord=t;var s,a,i,o,r=O.create("form",{className:`ftable-dialog-form ftable-${e}-form`});this.buildDependencyMap();for([s,a]of Object.entries(this.options.fields))this.shouldIncludeField(a,e)&&(i={...a},a.dependsOn?i.options=a.options:(o=await this.getFieldOptions(s,e,{record:t,source:e}),i.options=o),o=this.createFieldContainer(s,i,t,e),r.appendChild(o));return this.setupDependencyListeners(r),r}shouldResolveOptions(e){return e&&("function"==typeof e||"string"==typeof e)&&!Array.isArray(e)&&!("object"==typeof e&&!Array.isArray(e)&&0<Object.keys(e).length)}buildDependencyMap(){this.dependencies.clear(),Object.entries(this.options.fields).forEach(([t,s])=>{if(s.dependsOn){let e;"string"==typeof s.dependsOn&&(e=s.dependsOn.split(",").map(e=>e.trim()).filter(e=>e)).forEach(e=>{this.dependencies.has(e)||this.dependencies.set(e,[]),this.dependencies.get(e).push(t)})}})}setupDependencyListeners(s){Array.from(this.dependencies.keys()).forEach(e=>{var t=s.querySelector(`[name="${e}"]`);t&&t.addEventListener("change",()=>{this.handleDependencyChange(s,e)})}),this.handleDependencyChange(s)}async resolveOptions(e,t={},s="",a=!1){if(!e.options)return[];if(Array.isArray(e.options)||"object"==typeof e.options)return e.options;let i;t={...t,source:s,clearCache:()=>{a=!0,this.updateFieldCacheSetting(e,s,!0)}};if("function"==typeof e.options)i=await e.options(t);else{if("string"!=typeof e.options)return[];i=e.options}t=i&&"object"==typeof i&&i.url;let o=t?i.url:i;if(a=t&&void 0!==i.noCache?i.noCache:a,"string"!=typeof o)return[];if(!a)return this.optionsCache.getOrCreate(o,{},async()=>{try{var e=this.options.forcePost?await n.post(o):await n.get(o);return e.Options||e.options||e||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}});try{var r=this.options.forcePost?await n.post(o):await n.get(o);return r.Options||r.options||r||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}}updateFieldCacheSetting(e,t,s){e.noCache?"boolean"==typeof e.noCache?e.noCache={table:e.noCache,create:e.noCache,edit:e.noCache,[t]:s}:"object"==typeof e.noCache&&(e.noCache[t]=s):e.noCache={[t]:s}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}getFormValues(e){var t={},s=e.elements;for(let e=0;e<s.length;e++){var a=s[e],i=a.name;if(i&&!a.disabled)switch(a.type){case"checkbox":t[i]=a.checked?a.value||"1":"0";break;case"radio":a.checked&&(t[i]=a.value);break;case"select-multiple":t[i]=Array.from(a.selectedOptions).map(e=>e.value);break;default:t[i]=a.value}}return t}async handleDependencyChange(e,s=""){var a,i,o=this.getFormValues(e),r=e.classList.contains("ftable-create-form")?"create":"edit",l=this.currentFormRecord||{},n={record:l,source:r,form:e,dependedValues:o};for([a,i]of Object.entries(this.options.fields))if(i.dependsOn){if(""!==s)if(!i.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(s))continue;let t=e.querySelector(`[name="${a}"]`);if(t&&this.shouldIncludeField(i,r))try{"SELECT"===t.tagName?t.innerHTML='<option value="">Loading...</option>':"INPUT"===t.tagName&&t.list&&(c=document.getElementById(t.list.id))&&(c.innerHTML="");var c,d=t.value||l[a]||"",h={...n,dependsOnField:i.dependsOn,dependsOnValue:o[i.dependsOn]},p=await this.getFieldOptions(a,r,h);"SELECT"===t.tagName?this.populateSelectOptions(t,p,d):"INPUT"===t.tagName&&t.list&&(this.populateDatalistOptions(t.list,p),d)&&(t.value=d),setTimeout(()=>{t.dispatchEvent(new Event("change",{bubbles:!0}))},0)}catch(e){console.error(`Error loading options for ${a}:`,e),"SELECT"===t.tagName&&(t.innerHTML='<option value="">Error</option>')}}}parseInputAttributes(e){if("string"!=typeof e)return e||{};for(var t={},s=/(\w+)(?:=("[^"]*"|'[^']*'|\S+))?/g;null!==(i=s.exec(e));){var a=i[1],i=i[2]?i[2].replace(/^["']|["']$/g,""):"";t[a]=""===i?"true":i}return t}createInput(e,t,s,a){var i=O.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null===(s=void 0===s?null:s)&&t.defaultValue&&(s=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":o=this.createHiddenInput(e,t,s);break;case"textarea":o=this.createTextarea(e,t,s);break;case"select":o=this.createSelect(e,t,s);break;case"checkbox":o=this.createCheckbox(e,t,s);break;case"radio":o=this.createRadioGroup(e,t,s);break;case"datalist":o=this.createDatalistInput(e,t,s);break;case"file":o=this.createFileInput(e,t,s);break;case"date":case"datetime":case"datetime-local":o=this.createDateInput(e,t,s);break;default:o=this.createTypedInput(e,t,s)}return"function"==typeof t.input?(a={field:t,record:this.currentFormRecord,inputField:o,formType:a},"string"==typeof(a=t.input(a))?i.innerHTML=a:a instanceof Node?i.appendChild(a):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement))):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement)),t.explain&&O.create("div",{className:"ftable-field-explain",innerHTML:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(s,a,i){if("undefined"==typeof FDatepicker)return createTypedInput(s,a,i);{let e=a.dateFormat||this.options.defaultDateFormat;var o,r=document.createElement("div"),l=O.create("input",{id:"real-"+s,type:"hidden",value:i,name:s}),i={"data-date":i};a.inputAttributes&&(o=this.parseInputAttributes(a.inputAttributes),Object.assign(i,o));let t=O.create("input",{attributes:i,id:"Edit-"+s,type:"text",placeholder:a.placeholder||null,className:a.inputClass||"datepicker-input",readOnly:!0});switch(r.appendChild(l),r.appendChild(t),a.type){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"real-"+s,altFormat:"Y-m-d"})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"real-"+s,altFormat:"Y-m-d H:i:00"})},0)}return r}}createTypedInput(e,t,s){var a,i=t.type||"text",o={};let r=e,l=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(o,a),void 0!==a.multiple&&!1!==a.multiple)&&(r=e+"[]"),O.create("input",{attributes:o,type:i,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s,name:r}));return l.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),l.dispatchEvent(new Event("change",{bubbles:!0})),!1}),l}createDatalistInput(e,t,s){var a={list:e+"-datalist"},i=(t.inputAttributes&&(i=this.parseInputAttributes(t.inputAttributes),Object.assign(a,i)),O.create("input",{attributes:a,type:"search",name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})),a=O.create("datalist",{id:e+"-datalist"});return t.options&&this.populateDatalistOptions(a,t.options),i.datalistElement=a,i}populateDatalistOptions(s,e){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{O.create("option",{value:e.Value||e.value||e,textContent:e.DisplayText||e.text||e,parent:s})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:s})})}createHiddenInput(e,t,s){var a={};return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(a,t)),O.create("input",{attributes:a,type:"hidden",name:e,id:"Edit-"+e,value:s})}createTextarea(e,t,s){var a,i={};return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a)),O.create("textarea",{attributes:i,name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})}createSelect(e,t,s){var a={};let i=e,o=!1;if(t.inputAttributes&&(r=this.parseInputAttributes(t.inputAttributes),Object.assign(a,r),o=void 0!==r.multiple&&!1!==r.multiple)&&(i=e+"[]"),o)return this.createCustomMultiSelect(e,t,s,a,i);a.name=i;var r=O.create("select",{attributes:a,name:e,id:"Edit-"+e,className:t.inputClass||null});return t.options&&this.populateSelectOptions(r,t.options,s),r}createCustomMultiSelect(e,t,s,a,i){var o=Array.isArray(t.options)?t.options:t.options&&"object"==typeof t.options?Object.entries(t.options).map(([e,t])=>({Value:e,DisplayText:t})):[],r=t.livesearch??!1;return this._buildCustomMultiSelect({containerId:e,hiddenSelectId:"Edit-"+e,hiddenSelectName:i,extraClasses:"",containerDataFieldName:e,hiddenSelectAttributes:{},optionsSource:o,initialValues:Array.isArray(s)?s:s?s.toString().split(",").filter(e=>e):[],placeholderText:t.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:r,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!0})}_buildCustomMultiSelect(e){let{hiddenSelectId:t,hiddenSelectName:s,extraClasses:a,containerDataFieldName:i,hiddenSelectAttributes:o,optionsSource:r,initialValues:l,placeholderText:n,livesearch:c,onChangeExtra:d,buildHiddenSelectOnUpdate:h}=e;let p=(e=r)?(Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({Value:e,DisplayText:t}))).map(e=>({optValue:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,optText:e.DisplayText||e.text||e,groupLabel:e.Group||e.group||null})).filter(e=>null!=e.optValue&&""!==e.optValue):[],u=new Map(p.map(e=>[e.optValue.toString(),e.optText]));e=["ftable-multiselect-container",...a.split(" ").filter(Boolean)].join(" ");let m=O.create("div",{className:e,attributes:{"data-field-name":i}}),f=O.create("select",{id:t,name:s,multiple:!0,style:"display: none;",attributes:o}),g=(m.appendChild(f),m.hiddenSelect=f,O.create("div",{className:"ftable-multiselect-display",parent:m,attributes:{tabindex:"0"}})),b=O.create("div",{className:"ftable-multiselect-selected",parent:g}),v=O.create("span",{className:"ftable-multiselect-placeholder",textContent:n,parent:b}),y=(O.create("button",{type:"button",className:"ftable-multiselect-toggle",innerHTML:"▼",parent:g,attributes:{tabindex:"-1"}}),null),C=null,w=new Set(l.map(e=>e.toString())),S=new Map,E=(h||p.forEach(({optValue:e,optText:t})=>{O.create("option",{value:e,textContent:t,parent:f})}),()=>{b.innerHTML="",h?(f.innerHTML="",w.forEach(e=>{var t=u.get(e)??e;O.create("option",{value:e,textContent:t,selected:!0,parent:f})})):Array.from(f.options).forEach(e=>{e.selected=w.has(e.value)}),0===w.size?(v.textContent=n,b.appendChild(v)):w.forEach(t=>{var e=O.create("span",{className:"ftable-multiselect-tag",parent:b});O.create("span",{className:"ftable-multiselect-tag-text",textContent:u.get(t)||t,parent:e}),O.create("span",{className:"ftable-multiselect-tag-remove",innerHTML:"×",parent:e}).addEventListener("click",e=>{e.stopPropagation(),w.delete(t);e=S.get(t);e&&(e.checked=!1),E(),d&&d(f)})}),d&&d(f)}),x=()=>{g.focus(),y&&(y.remove(),y=null),C&&(C.remove(),C=null),m._cleanupHandlers&&(m._cleanupHandlers(),m._cleanupHandlers=null)},A=()=>{var e,t,s;y&&(e=g.getBoundingClientRect(),s=window.pageYOffset||document.documentElement.scrollTop,t=window.pageXOffset||document.documentElement.scrollLeft,t=e.left+t,s=e.bottom+s+4,Object.assign(y.style,{position:"absolute",left:t+"px",top:s+"px",width:e.width+"px",minWidth:"fit-content",boxSizing:"border-box",zIndex:"10000"}),(s=y.getBoundingClientRect()).right>window.innerWidth)&&(t=Math.max(10,window.innerWidth-s.width-10),y.style.left=t+"px")},N=(e="")=>{if(y){Array.from(y.querySelectorAll(".ftable-multiselect-option, .ftable-multiselect-optgroup")).forEach(e=>e.remove());let t=e.toLowerCase();e=e?p.filter(e=>e.optText.toLowerCase().includes(t)):p;let i=new Set,o=null;e.forEach(({optValue:t,optText:e,groupLabel:s})=>{s&&s!==i[i.size-1]?i.has(s)||(i.add(s),o=O.create("div",{className:"ftable-multiselect-optgroup",textContent:s,parent:y})):s||(o=null);s=O.create("div",{className:"ftable-multiselect-option",parent:y});let a=O.create("input",{type:"checkbox",className:"ftable-multiselect-checkbox",checked:w.has(t.toString()),parent:s});S.set(t.toString(),a),O.create("label",{className:"ftable-multiselect-label",textContent:e,parent:s}),s.addEventListener("click",e=>{e.stopPropagation();e=t.toString();w.has(e)?(w.delete(e),a.checked=!1):(w.add(e),a.checked=!0),E()})})}},L=a=>{if(a&&a.stopPropagation(),y)x();else{if(document.querySelectorAll(".ftable-multiselect-dropdown").forEach(e=>e.remove()),document.querySelectorAll(".ftable-multiselect-overlay").forEach(e=>e.remove()),C=O.create("div",{className:"ftable-multiselect-overlay",parent:document.body}),y=O.create("div",{className:"ftable-multiselect-dropdown",parent:document.body,attributes:{tabindex:"-1",role:"listbox","aria-multiselectable":"true"}}),c){a=O.create("div",{className:"ftable-multiselect-livesearch-wrap",parent:y});let e=O.create("input",{type:"search",className:"ftable-multiselect-livesearch",placeholder:"Search...",parent:a,attributes:{autocomplete:"off"}});e.addEventListener("input",()=>{N(e.value)}),e.addEventListener("click",e=>e.stopPropagation()),setTimeout(()=>e.focus(),0)}N(),A(),c||y.focus(),y.addEventListener("keydown",e=>{var t,s;"Escape"===e.key?x():"ArrowDown"===e.key||"ArrowUp"===e.key?(e.preventDefault(),s=(t=Array.from(y.querySelectorAll(".ftable-multiselect-checkbox"))).indexOf(document.activeElement),t["ArrowDown"===e.key?s<t.length-1?s+1:0:0<s?s-1:t.length-1]?.focus()):" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),document.activeElement.classList.contains("ftable-multiselect-checkbox")&&document.activeElement.click())}),C.addEventListener("click",e=>{e.target===C&&x()});let e=()=>A(),t=e=>{y&&y.contains(e.target)||A()},s=new ResizeObserver(()=>A());window.addEventListener("scroll",t,!0),window.addEventListener("resize",e),s.observe(b),m._cleanupHandlers=()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",e),s.disconnect()}}},T=(g.addEventListener("click",L),g.querySelector(".ftable-multiselect-toggle").addEventListener("click",L),g.addEventListener("keydown",e=>{"ArrowDown"!==e.key&&"Enter"!==e.key||(e.preventDefault(),L())}),m.resetMultiSelect=()=>{w.clear(),S.forEach(e=>{e.checked=!1}),x(),E()},new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{(e===m||e.contains&&e.contains(m))&&(x(),T.disconnect())})})}));return setTimeout(()=>{m.parentNode&&T.observe(m.parentNode,{childList:!0,subtree:!0})},0),E(),m}createRadioGroup(o,r,l){let n=O.create("div",{className:"ftable-radio-group"});return r.options&&(Array.isArray(r.options)?r.options:"object"==typeof r.options?Object.entries(r.options).map(([e,t])=>({Value:e,DisplayText:t})):[]).forEach((e,t)=>{var s=O.create("div",{className:"ftable-radio-wrapper",parent:n}),t=o+"_"+t,a={},i=(r.inputAttributes&&(i=this.parseInputAttributes(r.inputAttributes),Object.assign(a,i)),void 0!==e.Value?e.Value:void 0!==e.value?e.value:e);O.create("input",{attributes:a,type:"radio",name:o,id:t,value:i,className:r.inputClass||null,checked:i==l,parent:s}),O.create("label",{attributes:{for:t},textContent:e.DisplayText||e.text||e,parent:s})}),n}createCheckbox(e,t,s){var a=O.create("div",{className:"ftable-yesno-check-wrapper"}),s=[1,"1",!0,"true"].includes(s);let i=this.options.messages.no,o=this.options.messages.yes;return t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]),O.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),type:"checkbox",name:e,id:"Edit-"+e,value:"1",parent:a}).checked=s,t.label?O.create("label",{className:"ftable-yesno-check-fixedlabel",attributes:{for:"Edit-"+e},textContent:t.label,parent:a}):O.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:a}),a}populateSelectOptions(o,e,r){if(o.innerHTML="",Array.isArray(e)){let s=new Map,a=[],i=(e.forEach(e=>{var t=e.Group||e.group||null;(t?(s.has(t)||s.set(t,[]),s.get(t)):a).push(e)}),(e,t)=>{var s=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let a=O.create("option",{value:s,textContent:e.DisplayText||e.text||e,selected:s==r,parent:t});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{a.setAttribute("data-"+e,t)})});a.forEach(e=>i(e,o)),s.forEach((e,t)=>{let s=O.create("optgroup",{attributes:{label:t},parent:o});e.forEach(e=>i(e,s))})}else"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,selected:e==r,parent:o})})}createFileInput(e,t,s){var a,i={};let o=e;return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a),void 0!==a.multiple&&!1!==a.multiple)&&(o=e+"[]"),O.create("input",{type:"file",id:"Edit-"+e,name:o,className:t.inputClass||null,attributes:i})}}class l extends class{constructor(){this.events={}}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),this}once(t,s){let a=(...e)=>{this.off(t,a),s.apply(this,e)};return a.fn=s,this.on(t,a),this}emit(e,t={}){return this.events[e]&&this.events[e].forEach(e=>e(t)),this}off(e,t){return this.events[e]&&(this.events[e]=this.events[e].filter(e=>e!==t)),this}}{constructor(e,t={}){if(super(),this.element="string"==typeof e?document.querySelector(e):e,this.element){if(this.element.ftableInstance)return this.element.ftableInstance;this.options=this.mergeOptions(t),this.verifyOptions(),this.logger=new a(this.options.logLevel),this.userPrefs=new i("",this.options.saveUserPreferencesMethod),this.formBuilder=new r(this.options,this),this.state={records:[],totalRecordCount:0,currentPage:1,isLoading:!1,selectedRecords:new Set,sorting:[],searchQueries:{}},this.elements={},this.modals={},this.searchTimeout=null,this.lastSortEvent=null,this._recalculatedOnce=!1,this.shiftKeyDown=!1,this.lastSelectedRow=null,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:a.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,closeOnOverlayClick:!0,animationsEnabled:!0,loadingAnimationDelay:1e3,defaultDateLocale:"",defaultDateFormat:"Y-m-d",saveUserPreferences:!0,saveUserPreferencesMethod:"localStorage",defaultSorting:"",tableReset:!1,paging:!1,pageList:"normal",pageSize:10,pageSizes:[10,25,50,100,250,500],gotoPageArea:"combobox",sorting:!1,multiSorting:!1,multiSortingCtrlKey:!0,selecting:!1,multiselect:!1,openChildAsAccordion:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...s}};return this.deepMerge(t,e)}deepMerge(e,t){var s,a={...e};for(s in t)t[s]&&"object"==typeof t[s]&&!Array.isArray(t[s])?a[s]=this.deepMerge(a[s]||{},t[s]):a[s]=t[s];return a}verifyOptions(){this.options.pageSize&&!this.options.pageSizes.includes(this.options.pageSize)&&(this.options.pageSize=this.options.pageSizes[0])}static setMessages(e){Object.assign(s,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAsyncFieldOptions().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.updateSortingHeaders(),this.renderSortingInfo(),this.initColumnWidths()}initColumnWidths(){var e=this.columnList.filter(e=>{e=this.options.fields[e];return!e.action&&"hidden"!==e.visibility&&"separator"!==e.visibility});let t=e.length;e.forEach(e=>{e=this.options.fields[e];e.width=e.width||100/t+"%"})}normalizeColumnWidths(){var e=this.elements.mainContainer,t=this.columnList.map(e=>({th:this.elements.table.querySelector(`[data-field-name="${e}"]`),field:this.options.fields[e]})).filter(e=>e.th&&!e.field.action&&"hidden"!==e.field.visibility&&"separator"!==e.field.visibility);if(0!==t.length){let s=e.offsetWidth,a=0;t.forEach(e=>{var t=e.th.offsetWidth/s*100;e.field.width=t+"%",e.th.style.width=e.field.width,a+=t})}}parseDefaultSorting(e){let o=[];return e&&"string"==typeof e&&e.split(",").forEach(s=>{s=s.trim();if(s){var a=s.toUpperCase().indexOf(" DESC"),i=s.toUpperCase().indexOf(" ASC");let e="ASC",t=s;e=0<a?(t=s.slice(0,a).trim(),"DESC"):(t=(0<i?s.slice(0,i):s).trim(),"ASC");a=this.options.fields[t];a&&!1!==a.sorting&&o.push({fieldName:t,direction:e})}}),o}createPagingUI(){this.elements.bottomPanel=O.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=O.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=O.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=O.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=O.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=O.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=O.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});O.create("span",{textContent:this.options.messages.pageSizeChangeLabel,parent:e});let s=O.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100,250,500]).forEach(e=>{var t=O.create("option",{attributes:{value:e},textContent:e.toString(),parent:s});e===this.state.pageSize&&(t.selected=!0)}),s.addEventListener("change",e=>{this.changePageSize(parseInt(e.target.value))})}processFieldDefinitions(){this.fieldList=Object.keys(this.options.fields),this.fieldList.forEach(e=>{var e=this.options.fields[e],t=!0===e.key;!!e.action?(e.list=!0,e.create=!1,e.edit=!1,e.sorting=!1,e.searchable=!1):t?(void 0!==e.create&&e.create||(e.create=!0,e.type="hidden"),void 0!==e.edit&&e.edit||(e.edit=!0,e.type="hidden")):(e.create=e.create??!0,e.edit=e.edit??!0,e.list=e.list??!0,e.sorting=e.sorting??!0),e.visibility=e.visibility??"visible"}),this.columnList=this.fieldList.filter(e=>!1!==this.options.fields[e].list),this._userPlacedActions=new Set(this.fieldList.filter(e=>this.options.fields[e].action).map(e=>this.options.fields[e].action)),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.info("No key field defined")}async resolveAsyncFieldOptions(){var e=this.columnList.map(async t=>{var e=this.options.fields[t];if(!e.action){e=this.formBuilder.originalFieldOptions.get(t);if(this.formBuilder.shouldResolveOptions(e))try{var s=this.formBuilder.generateOptionsCacheKey("table",{});this.formBuilder.resolvedFieldOptions.get(t)?.[s]||await this.formBuilder.getFieldOptions(t,"table")}catch(e){console.error(`Failed to resolve table options for ${t}:`,e)}}});await Promise.all(e)}async refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");if(0!==e.length)for(var t of e)for(var s of this.columnList){var a,i,o=this.options.fields[s];!o.action&&o.options&&(a=t.querySelector(`td[data-field-name="${s}"]`))&&(i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],s=this.getDisplayText(t.recordData,s,i),a.innerHTML=o.listEscapeHTML?O.escapeHtml(s):s)}}createMainStructure(){this.elements.mainContainer=O.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=O.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),O.create("div",{className:"ftable-title-text",innerHTML:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=O.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=O.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=O.create("table",{className:"ftable",parent:this.elements.tableDiv}),this.options.tableId&&(this.elements.table.id=this.options.tableId),this.createTableHeader(),this.createTableBody(),this.addNoDataRow()}createTableHeader(){var e=O.create("thead",{parent:this.elements.table});let o=O.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")){var t=O.create("th",{className:"ftable-command-column-header ftable-column-header-select",parent:o});if(this.options.multiselect){let e=O.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var s=this.options.fields[t];if(s.action){var a={select:"ftable-column-header-select",update:"ftable-column-header-edit",clone:"ftable-column-header-clone",delete:"ftable-column-header-delete"};let t=O.create("th",{className:"ftable-command-column-header "+(a[s.action]||""),parent:o});if(s.title&&(t.textContent=s.title),"select"===s.action&&this.options.selecting&&this.options.selectingCheckboxes&&this.options.multiselect){let e=O.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}void(s.width&&(t.style.width=s.width))}else{let e=O.create("th",{className:`ftable-column-header ${s.listClass||""} `+(s.listClassHeader||""),attributes:{"data-field-name":t},parent:o});s.width&&(e.style.width=s.width);var a=O.create("div",{className:"ftable-column-header-container",parent:e}),i=(s.tooltip&&a.setAttribute("title",s.tooltip),O.create("span",{className:"ftable-column-header-text",innerHTML:s.title||t,parent:a}));this.options.sorting&&!1!==s.sorting&&(O.addClass(i,"ftable-sortable-text"),O.addClass(e,"ftable-column-header-sortable"),e.addEventListener("click",e=>{e.preventDefault();e=e.ctrlKey||e.metaKey;this.sortByColumn(t,e)})),!1!==this.options.columnResizable&&!1!==s.columnResizable&&this.makeColumnResizable(e,a),"hidden"!==s.visibility&&"separator"!==s.visibility||O.hide(e)}}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:o}),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:o}),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:o}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,s=O.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});for(let i of this.columnList){var o=this.options.fields[i];if(o.action)O.create("th",{className:"ftable-toolbarsearch-column-header ftable-command-column-header",parent:s});else{var r=!1!==o.searchable,l=O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});if(r){r=O.create("div",{className:"ftable-column-header-container",parent:l});let s,a="text";o.searchType?a=o.searchType:!o.type&&o.options?a="select":o.type&&(a=o.type);var n="ftable-toolbarsearch-"+i;switch(a){case"date":case"datetime":case"datetime-local":if("undefined"!=typeof FDatepicker){let e=o.searchDateFormat||o.dateFormat||this.options.defaultDateFormat;var c=document.createElement("div"),d=O.create("input",{className:"ftable-toolbarsearch-extra",type:"hidden",id:"ftable-toolbarsearch-extra-"+i,attributes:{"data-field-name":i}});let t=O.create("input",{className:"ftable-toolbarsearch",id:"ftable-toolbarsearch-"+i,type:"text",placeholder:o.searchPlaceholder||o.placeholder||"",readOnly:!0});switch(c.appendChild(d),c.appendChild(t),a){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d",autoClose:!0})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d H:i:00"})},0)}s=c}else s=O.create("input",{className:"ftable-toolbarsearch",type:a,id:n,attributes:{"data-field-name":i}});break;case"checkbox":o.values||(o.values={0:this.options.messages.no,1:this.options.messages.yes}),s=await this.createSelectForSearch(i,o,!0);break;case"select":s=o.options?await this.createSelectForSearch(i,o,!1):O.create("input",{className:"ftable-toolbarsearch",type:"text",id:n,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}});break;case"datalist":s=await this.createDatalistForSearch(i,o);break;default:s=O.create("input",{className:"ftable-toolbarsearch",type:"text",id:n,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}})}if(s){r.appendChild(s),s.datalistElement&&s.datalistElement instanceof Node&&r.appendChild(s.datalistElement);let e=s;"SELECT"===(e=s.classList&&s.classList.contains("ftable-multiselect-container")&&s.hiddenSelect?s.hiddenSelect:e).tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)})}}"hidden"!==o.visibility&&"separator"!==o.visibility||O.hide(l)}}this.options.toolbarsearch&&this.options.toolbarreset&&(e=O.create("th",{className:"ftable-toolbarsearch-column-header ftable-toolbarsearch-reset",parent:s}),0<(t=(this.options.actions.updateAction&&!this._userPlacedActions.has("update")?1:0)+(this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")?1:0)+(this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")?1:0))?e.colSpan=t:O.addClass(e,"ftable-command-column-header"),O.create("button",{className:"ftable-toolbarsearch-reset-button",textContent:this.options.messages.resetSearch,attributes:{id:"ftable-toolbarsearch-reset-button"},parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,s){var a,i="ftable-toolbarsearch-"+e,o={};let r=e,l=!1;t.searchAttributes?(a=this.formBuilder.parseInputAttributes(t.searchAttributes),Object.assign(o,a),l=void 0!==a.multiple&&!1!==a.multiple):t.inputAttributes&&(a=this.formBuilder.parseInputAttributes(t.inputAttributes),Object.assign(o,a),l=void 0!==a.multiple&&!1!==a.multiple),l&&(r=e+"[]"),o["data-field-name"]=r;let n;if(s&&t.values?n=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):t.options&&(n=await this.formBuilder.getFieldOptions(e)),l)return this.createCustomMultiSelectForSearch(i,e,t,n,o);let c=O.create("select",{attributes:o,id:i,className:"ftable-toolbarsearch"});return 0<n?.length&&(""===n[0].Value||""===n[0].value||""===n[0]||""===n[0].DisplayText&&null==n[0].Value)||O.create("option",{value:"",innerHTML:" ",parent:c}),n&&Array.isArray(n)?n.forEach(e=>{O.create("option",{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,textContent:e.DisplayText||e.text||e,parent:c})}):n&&"object"==typeof n&&Object.entries(n).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:c})}),c}createCustomMultiSelectForSearch(e,t,s,a,i){var o=s.livesearch??!1;return this.formBuilder._buildCustomMultiSelect({hiddenSelectId:e,hiddenSelectName:i["data-field-name"]||e,extraClasses:"ftable-multiselect-search ftable-toolbarsearch",containerDataFieldName:i["data-field-name"]||e,hiddenSelectAttributes:i,optionsSource:a,initialValues:[],placeholderText:s.searchPlaceholder||s.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:o,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!1})}async createDatalistForSearch(e,t){var s="ftable-toolbarsearch-"+e,a=s+"-datalist",i=O.create("datalist",{attributes:{id:a}}),s=O.create("input",{className:"ftable-toolbarsearch",type:"search",id:s,placeholder:t.searchPlaceholder||t.placeholder||"Type or select...",attributes:{"data-field-name":e,list:a}});s.datalistElement=i;let o;return t.searchOptions?o=t.searchOptions:t.options&&(o=await this.formBuilder.getFieldOptions(e,"table")),o&&this.formBuilder.populateDatalistOptions(i,o),s}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name");let s;s=e.multiple&&e.options?Array.from(e.selectedOptions).map(e=>e.value).filter(e=>""!==e.trim()).map(e=>e.trim()):e.value.trim(),this.state.currentPage=1,Array.isArray(s)&&0<s.length||!Array.isArray(s)&&s?this.state.searchQueries[t]=s:delete this.state.searchQueries[t],clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.load()},this.options.searchDebounceMs)}resetSearch(){this.state.searchQueries={},this.elements.table.querySelectorAll(".ftable-toolbarsearch").forEach(e=>{"SELECT"===e.tagName?e.selectedIndex=0:e.value=""}),this.elements.table.querySelectorAll(".ftable-multiselect-container").forEach(e=>{"function"==typeof e.resetMultiSelect&&e.resetMultiSelect()}),this.load()}getNextResizableHeader(t){var s=Array.from(this.elements.table.querySelectorAll("thead th.ftable-column-header-resizable"));for(let e=s.indexOf(t)+1;e<s.length;e++)if(null!==s[e].offsetParent)return s[e];return null}makeColumnResizable(a,e){O.addClass(a,"ftable-column-header-resizable"),this.elements.resizeBar||(this.elements.resizeBar=O.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),O.hide(this.elements.resizeBar));e=O.create("div",{className:"ftable-column-resize-handler",parent:e});let i=!1,o=0,r=0,l,n=null,c=0,d=null,h=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),i=!0,l=this.elements.mainContainer.getBoundingClientRect(),o=e.clientX,r=a.offsetWidth,(n=this.getNextResizableHeader(a))&&(c=n.offsetWidth,e=n.dataset.fieldName,d=this.options.fields[e]);e=a.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-l.left+"px",this.elements.resizeBar.style.top=e.top-l.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",O.show(this.elements.resizeBar),document.addEventListener("mousemove",h),document.addEventListener("mouseup",p)}),e=>{i&&(this.elements.resizeBar.style.left=e.clientX-l.left+"px")}),p=e=>{var t,s;i&&(i=!1,e=e.clientX-o,s=l.width,t=Math.max(50,r+e)/s*100,n&&(e=Math.max(50,c-e)/s*100,d.width=e.toFixed(2)+"%",n.style.width=d.width),(s=this.options.fields[a.dataset.fieldName]).width=t.toFixed(2)+"%",a.style.width=s.width,this.normalizeColumnWidths(),this.options.saveUserPreferences&&this.saveColumnSettings(),O.hide(this.elements.resizeBar),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",p))}}saveColumnSettings(){if(this.options.saveUserPreferences){let a={};this.columnList.forEach(e=>{var t,s=this.elements.table.querySelector(`[data-field-name="${e}"]`);s&&(t=this.options.fields[e],a[e]={width:s.style.width||t.width||"auto",visibility:t.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(a))}}saveState(){var e;this.options.saveUserPreferences&&(e={sorting:this.state.sorting,pageSize:this.state.pageSize},this.userPrefs.set("table-state",JSON.stringify(e)))}loadColumnSettings(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("column-settings");if(e)try{var t=JSON.parse(e);Object.entries(t).forEach(([e,t])=>{e=this.options.fields[e];e&&(t.width&&(e.width=t.width),t.visibility)&&(e.visibility=t.visibility)})}catch(e){this.logger.warn("Failed to load column settings:",e)}}}loadState(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("table-state");if(e)try{var t=JSON.parse(e);Array.isArray(t.sorting)&&(this.state.sorting=t.sorting),t.pageSize&&this.options.pageSizes.includes(t.pageSize)&&(this.state.pageSize=t.pageSize)}catch(e){this.logger.warn("Failed to load table state:",e)}}}createTableBody(){this.elements.tableBody=O.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=O.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,O.create("td",{attributes:{colspan:t},textContent:this.options.messages.noDataAvailable,parent:e}))}removeNoDataRow(){var e=this.elements.tableBody.querySelector(".ftable-no-data-row");e&&e.remove()}createModals(){this.options.actions.createAction&&this.createAddRecordModal(),this.options.actions.updateAction&&this.createEditRecordModal(),this.options.actions.deleteAction&&this.createDeleteConfirmModal(),this.createErrorModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new o({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>this.modals.deleteConfirm.close()},{text:this.options.messages.deleteText,className:"ftable-dialog-deletebutton",onClick:()=>this.confirmDelete()}]})}createErrorModal(){this.modals.error=new o({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createInfoModal(){this.modals.info=new o({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new o({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",closeOnOverlayClick:!1,content:`<div class="ftable-loading-message">${this.options.messages.loadingMessage}</div>`})}bindEvents(){this.subscribeOptionEvents(),this.createCustomToolbarItems(),this.createToolbarButtons(),this.bindKeyboardEvents(),!1!==this.options.columnSelectable&&this.createColumnSelectionMenu()}subscribeOptionEvents(){["formCreated","formClosed","recordsLoaded","recordAdded","recordUpdated","recordDeleted","selectionChanged"].forEach(e=>{"function"==typeof this.options[e]&&this.on(e,this.options[e])})}createColumnSelectionMenu(){this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null,this.elements.table.querySelector("thead").addEventListener("contextmenu",e=>{e.preventDefault(),this.showColumnSelectionMenu(e)})}showColumnSelectionMenu(e){this.hideColumnSelectionMenu(),this.elements.columnSelectionOverlay=O.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=O.create("div",{className:"ftable-column-selection-container",parent:document.body}),this.populateColumnSelectionMenu(),this.positionColumnSelectionMenu(e),this.elements.columnSelectionOverlay.addEventListener("click",e=>{e.target===this.elements.columnSelectionOverlay&&this.hideColumnSelectionMenu()}),this.elements.columnSelectionOverlay.addEventListener("contextmenu",e=>{e.preventDefault(),this.hideColumnSelectionMenu()})}populateColumnSelectionMenu(){let n=O.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(t=>{var e=this.options.fields[t];if(!e.action){var s="hidden"!==e.visibility,a="fixed"===e.visibility,i="separator"===e.visibility,o=this.isFieldSorted(t),r=O.create("li",{className:"ftable-column-select-item",parent:n}),l=O.create("label",{className:"ftable-column-select-label",parent:r});if(!i){let e=O.create("input",{attributes:{type:"checkbox",id:"column-"+t},parent:l});e.checked=s,(a||o&&s)&&(e.disabled=!0,r.style.opacity="0.6"),e.disabled||e.addEventListener("change",()=>{this.setColumnVisibility(t,e.checked)})}a=O.create("span",{textContent:e.title||t,style:i?"font-weight: bold;":null,parent:l});o&&((s=O.create("span",{className:"ftable-sort-indicator",textContent:" (sorted)",parent:a})).style.fontSize="0.8em",s.style.color="#666")}})}positionColumnSelectionMenu(e){var t=this,s=e.pageX,e=e.pageY,e=(t.elements.columnSelectionMenu.style.position="absolute",t.elements.columnSelectionMenu.style.left=s+"px",t.elements.columnSelectionMenu.style.top=e+"px",t.elements.columnSelectionMenu.style.minWidth="100px",t.elements.columnSelectionMenu.style.boxSizing="border-box",t.elements.columnSelectionMenu.offsetWidth),a=window.innerWidth;a<s+e&&(s=Math.max(10,a-e-10),t.elements.columnSelectionMenu.style.left=s+"px")}hideColumnSelectionMenu(){this.elements.columnSelectionOverlay&&(this.elements.columnSelectionOverlay.remove(),this.elements.columnSelectionMenu.remove(),this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null)}isFieldSorted(t){return this.state.sorting.some(e=>e.fieldName===t)}createToolbarButtons(){this.options.csvExport&&this.addToolbarButton({text:this.options.messages.csvExport,className:"ftable-toolbar-item-csv",onClick:()=>{var e=this.options.title?this.options.title.replace(/[^a-z0-9]/gi,"-").toLowerCase()+".csv":"table-export.csv";this.exportToCSV(e)}}),this.options.printTable&&this.addToolbarButton({text:this.options.messages.printTable,className:"ftable-toolbar-item-print",onClick:()=>{this.printTable()}}),this.options.actions.createAction&&this.addToolbarButton({text:this.options.messages.addNewRecord,className:"ftable-toolbar-item-add-record",addIconSpan:!0,onClick:()=>this.showAddRecordForm()})}addToolbarButton(t){var e,s=O.create("button",{className:"ftable-toolbar-item "+(t.className||""),id:t.id||null,title:t.title||null,textContent:t.text||null,type:"button",parent:this.elements.toolbarDiv});return t.addIconSpan&&(e=O.create("span",{className:"ftable-toolbar-item-icon "+(t.className||""),parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.icon&&(e=O.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.onClick&&s.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.onClick(e)}),t.disabled&&(s.disabled=!0),s}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach((e,t)=>{this.addToolbarButton({text:e.text||"",className:"ftable-toolbar-item-custom "+(e.buttonClass||""),id:e.buttonId||"ftable-toolbar-item-custom-id-"+t,title:e.tooltip||"",icon:e.icon||null,onClick:"function"==typeof e.click?e.click:null})})}bindKeyboardEvents(){this.options.selecting&&(document.addEventListener("keydown",e=>{"Shift"===e.key&&(this.shiftKeyDown=!0)}),document.addEventListener("keyup",e=>{"Shift"===e.key&&(this.shiftKeyDown=!1)}))}setupFTableUserPreferences(){var e;this.options.saveUserPreferences&&(e=this.userPrefs.generatePrefix(this.options.tableId||"",this.fieldList),this.userPrefs=new i(e,this.options.saveUserPreferencesMethod),this.loadState(),this.loadColumnSettings())}async load(e={}){if(!this.state.isLoading){this.state.isLoading=!0,this.showLoadingIndicator();try{var t={...e,...this.buildLoadParams()},s=await this.performLoad(t);this.processLoadedData(s),this.emit("recordsLoaded",{records:s.Records,serverResponse:s})}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Load failed: "+e.message)}finally{this.state.isLoading=!1,this.hideLoadingIndicator()}this.renderSortingInfo(),this.normalizeColumnWidths()}}buildLoadParams(){var e,t={};if(this.options.paging&&(this.state.pageSize||(this.state.pageSize=this.options.pageSize),t.jtStartIndex=(this.state.currentPage-1)*this.state.pageSize,t.jtPageSize=this.state.pageSize),this.options.sorting&&(0<this.state.sorting.length?t.jtSorting=this.state.sorting.map(e=>e.fieldName+" "+e.direction).join(", "):this.options.defaultSorting&&(t.jtSorting=this.parseDefaultSorting(this.options.defaultSorting).map(e=>e.fieldName+" "+e.direction).join(", "))),this.options.toolbarsearch&&0<Object.keys(this.state.searchQueries).length){let s=[],a=[];Object.entries(this.state.searchQueries).forEach(([t,e])=>{Array.isArray(e)?e.forEach(e=>{""!==e&&null!=e&&(s.push(e),a.push(t))}):""!==e&&(s.push(e),a.push(t))}),0<s.length&&(t.q=s,t.opt=a)}return"function"==typeof this.options.listQueryParams&&(e=this.options.listQueryParams(),Object.assign(t,e)),t}isCacheExpired(e,t){return!e||!e.timestamp||t<Date.now()-e.timestamp}async performLoad(e){var t=this.options.actions.listAction;if(this.options.listCache&&"string"==typeof t){var s=this.formBuilder.optionsCache.get(t,e);if(s&&!this.isCacheExpired(s,this.options.listCache))return s.data}let a;if("function"==typeof t)a=await t(e);else{if("string"!=typeof t)throw new Error("No valid listAction provided");a=this.options.forcePost?await n.post(t,e):await n.get(t,e)}if(a&&"OK"===a.Result)return this.options.listCache&&"string"==typeof t&&this.formBuilder.optionsCache.set(t,e,{data:a,timestamp:Date.now()}),a;throw new Error(a?.Message||"Invalid response from server")}processLoadedData(e){"OK"!==e.Result?this.showError(e.Message||"Unknown error occurred"):(this.state.records=e.Records||[],this.state.totalRecordCount=e.TotalRecordCount||this.state.records.length,this.renderTableData(),this.updatePagingInfo())}renderTableData(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>e.remove()),0===this.state.records.length?this.addNoDataRow():(this.removeNoDataRow(),this.state.records.forEach(e=>{e=this.createTableRow(e);this.elements.tableBody.appendChild(e)}),this.refreshRowStyles())}createTableRow(s){let a=O.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(s)}});return a.recordData=s,this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&this.addSelectingCell(a),this.columnList.forEach(e=>{var t=this.options.fields[e];if(t.action)switch(t.action){case"select":this.addSelectingCell(a);break;case"update":this.addEditCell(a);break;case"clone":this.addCloneCell(a);break;case"delete":this.addDeleteCell(a)}else this.addDataCell(a,s,e)}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&this.addEditCell(a),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&this.addCloneCell(a),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&this.addDeleteCell(a),this.options.selecting&&this.makeRowSelectable(a),a}addSelectingCell(t){var e=O.create("td",{className:"ftable-command-column ftable-selecting-column",parent:t});O.create("input",{className:"norowselectonclick",attributes:{type:"checkbox"},parent:e}).addEventListener("change",e=>{this.toggleRowSelection(t)})}addDataCell(e,t,s){var a=this.options.fields[s],i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],t=this.getDisplayText(t,s,i),i=O.create("td",{className:`${a.listClass||""} `+(a.listClassEntry||""),innerHTML:a.listEscapeHTML?O.escapeHtml(t):t,attributes:{"data-field-name":s},parent:e});"fixed"===a.visibility||"hidden"!==a.visibility&&"separator"!==a.visibility||O.hide(i)}addEditCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},innerHTML:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},innerHTML:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},innerHTML:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t,s=null){var a=this.options.fields[t],i=e[t],s=s||a.options;let o=i;return"date"===a.type&&i&&(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDate(i,a.dateLocale||this.options.defaultDateLocale)),"datetime-local"!==a.type&&"datetime"!==a.type||!i||(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDateTime(i,a.dateLocale||this.options.defaultDateLocale)),"checkbox"===a.type&&(o=this.getCheckboxText(t,i)),s&&(t=this.findOptionByValue(s,i),o=t?t.DisplayText||t.text||t:i),(o=a.display&&"function"==typeof a.display?a.display({record:e,value:i,displayValue:o}):o)||""}_parseDate(e){return e.includes("Date")?new Date(parseInt(e.substr(6),10)):10==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10)):19==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10),parseInt(e.substr(11,2),10),parseInt(e.substr(14,2),10),parseInt(e.substr(17,2),10)):new Date(e)}formatDate(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleDateString(t,{year:"numeric",month:"2-digit",day:"2-digit"})}catch{return e}}formatDateTime(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleString(t)}catch{return e}}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?this.options.messages.yes:this.options.messages.no}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):"object"==typeof e&&null!==e&&e.hasOwnProperty(t)?e[t]:null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?O.addClass(e,"ftable-row-even"):O.removeClass(e,"ftable-row-even")})}getKeyValue(e){return this.keyField?e[this.keyField]:null}async showAddRecordForm(){var e=await this.formBuilder.createForm("create");this.modals.addRecord.setContent(e),this.modals.addRecord.show(),this.currentForm=e,this.emit("formCreated",{form:e,formType:"create",record:null})}async saveNewRecord(){if(this.currentForm)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performCreate(e);"OK"===t.Result?(this.clearListCache(),this.modals.addRecord.close(),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),t.Message&&this.showInfo(t.Message),await this.load(),this.emit("recordAdded",{record:t.Record})):this.showError(t.Message||"Create failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Create failed: "+e.message)}}else this.currentForm.reportValidity()}async editRecord(e){var t=e.recordData,s=await this.formBuilder.createForm("edit",t);this.modals.editRecord.setContent(s),this.modals.editRecord.show(),this.currentForm=s,this.currentEditingRow=e,this.emit("formCreated",{form:s,formType:"edit",record:t})}async saveEditedRecord(){if(this.currentForm&&this.currentEditingRow)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performUpdate(e);"OK"===t.Result?(this.clearListCache(),this.modals.editRecord.close(),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,this.emit("formClosed",{form:this.currentForm,formType:"edit",record:this.currentEditingRow.recordData}),this.updateRowData(this.currentEditingRow,t.Record||e),t.Message&&this.showInfo(t.Message),this.emit("recordUpdated",{record:t.Record||e,row:this.currentEditingRow})):this.showError(t.Message||"Update failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Update failed: "+e.message)}}else this.currentForm.reportValidity()}async cloneRecord(e){var e={...e.recordData},t=(this.keyField&&(e[this.keyField]=""),await this.formBuilder.createForm("create",e));this.modals.addRecord.options.content=t,this.modals.addRecord.setContent(t),this.modals.addRecord.show(),this.currentForm=t,this.emit("formCreated",{form:t,formType:"create",record:e})}async deleteRows(e){if(e.length){var t=this.options.messages.areYouSure;if(confirm(t)){var s,a=[];for(s of e)try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});t=a.filter(e=>!e.success).length;0<t&&this.showError(t+` of ${a.length} records could not be deleted`),this.refreshRowStyles(),this.updatePagingInfo()}}}deleteRecord(e){var t=e.recordData;let s=this.options.messages.deleteConfirmation;if("function"==typeof this.options.deleteConfirmation){t={row:e,record:t,deleteConfirmMessage:s,cancel:!1,cancelMessage:this.options.messages.cancel};if(this.options.deleteConfirmation(t),t.cancel)return void(t.cancelMessage&&this.showError(t.cancelMessage));s=t.deleteConfirmMessage}this.modals.deleteConfirm.setContent(`<p>${s}</p>`),this.modals.deleteConfirm.show(),this.currentDeletingRow=e}async confirmDelete(){if(this.currentDeletingRow){var e=this.getKeyValue(this.currentDeletingRow.recordData);try{var t=await this.performDelete(e);"OK"===t.Result?(this.clearListCache(),this.modals.deleteConfirm.close(),this.removeRowFromTable(this.currentDeletingRow),t.Message&&this.showInfo(t.Message),this.emit("recordDeleted",{record:this.currentDeletingRow.recordData})):this.showError(t.Message||"Delete failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Delete failed: "+e.message)}}}async performCreate(e){var t=this.options.actions.createAction;if("function"==typeof t)return t(e);if("string"==typeof t)return n.post(t,e);throw new Error("No valid createAction provided")}async performUpdate(e){var t=this.options.actions.updateAction;if("function"==typeof t)return t(e);if("string"==typeof t)return n.post(t,e);throw new Error("No valid updateAction provided")}async performDelete(e){var t=this.options.actions.deleteAction;let s;if(s=null===e||"object"!=typeof e||Array.isArray(e)?{[this.keyField]:e}:e,"function"==typeof t)return t(s);if("string"==typeof t)return n.post(t,s);throw new Error("No valid deleteAction provided")}getFormData(e){var t,s,a,i={};for([t,s]of new FormData(e).entries())t.endsWith("[]")?(i[a=t.slice(0,-2)]||(i[a]=[]),i[a].push(s)):i.hasOwnProperty(t)?Array.isArray(i[t])?i[t].push(s):i[t]=[i[t],s]:i[t]=s;return i}updateRowData(i,e){i.recordData={...i.recordData,...e},Object.keys(e).forEach(e=>{var t,s,a=this.options.fields[e];a&&(t=i.querySelector(`td[data-field-name="${e}"]`))&&(s=this.formBuilder.generateOptionsCacheKey("table",{}),s=this.formBuilder.resolvedFieldOptions.get(e)?.[s],e=this.getDisplayText(i.recordData,e,s),t.innerHTML=a.listEscapeHTML?O.escapeHtml(e):e,t.className=(`${a.listClass||""} `+(a.listClassEntry||"")).trim())})}removeRowFromTable(e){e.remove(),0===this.elements.tableBody.querySelectorAll(".ftable-data-row").length&&this.addNoDataRow(),this.refreshRowStyles()}makeRowSelectable(t){!1!==this.options.selectOnRowClick&&t.addEventListener("click",e=>{["INPUT","BUTTON","SELECT","TEXTAREA","A"].includes(e.target.tagName)||e.target.classList.contains("norowselectonclick")||this.toggleRowSelection(t)})}toggleRowSelection(e){var t=e.classList.contains("ftable-row-selected");if(this.shiftKeyDown&&this.lastSelectedRow&&this.options.multiselect){this.clearAllSelections();var s=Array.from(this.elements.tableBody.querySelectorAll(".ftable-data-row")),a=s.indexOf(this.lastSelectedRow),i=s.indexOf(e),[i,o]=a<i?[a,i]:[i,a];for(let e=i;e<=o;e++)this.selectRow(s[e])}else this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e);t&&!this.shiftKeyDown||(this.lastSelectedRow=e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){O.addClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!0),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.add(t)}deselectRow(e){O.removeClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!1),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.delete(t)}recalcColumnWidths(){this.columnList.forEach(e=>{var t=this.options.fields[e],e=this.elements.table.querySelector(`[data-field-name="${e}"]`);e&&t.width&&(e.style.width=t.width)}),this.elements.table.offsetHeight}recalcColumnWidthsOnce(){this._recalculatedOnce||(this.recalcColumnWidths(),this._recalculatedOnce=!0)}clearAllSelections(){this.elements.tableBody.querySelectorAll(".ftable-row-selected").forEach(e=>this.deselectRow(e))}toggleSelectAll(t){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{t?this.selectRow(e):this.deselectRow(e)}),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}getSelectedRows(){return Array.from(this.elements.tableBody.querySelectorAll(".ftable-row-selected"))}sortByColumn(s,a=!1){var i=this.options.fields[s];if(i&&!1!==i.sorting){i=this.state.sorting.findIndex(e=>e.fieldName===s);let e=!0,t="ASC";0<=i?"ASC"===this.state.sorting[i].direction?(t="DESC",this.state.sorting[i].direction=t):(this.state.sorting.splice(i,1),e=!1):this.state.sorting.push({fieldName:s,direction:t}),(!this.options.multiSorting||this.options.multiSortingCtrlKey&&!a)&&(this.state.sorting=e?[{fieldName:s,direction:t}]:[]),this.updateSortingHeaders(),this.load(),this.saveState()}}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{O.removeClass(e,"ftable-column-header-sorted-asc ftable-column-header-sorted-desc")}),this.state.sorting.forEach(e=>{var t=this.elements.table.querySelector(`[data-field-name="${e.fieldName}"]`);t&&O.addClass(t,"ftable-column-header-sorted-"+e.direction.toLowerCase())})}updatePagingInfo(){var e,t,s;this.options.paging&&this.elements.pageInfoSpan&&(this.state.totalRecordCount<=0?(this.elements.pageInfoSpan.textContent="",this.elements.pagingListArea.innerHTML=""):(e=(this.state.currentPage-1)*this.state.pageSize+1,t=Math.min(this.state.currentPage*this.state.pageSize,this.state.totalRecordCount),s=this.options.messages.pagingInfo||"Showing {0}-{1} of {2}",this.elements.pageInfoSpan.textContent=s.replace(/\{0\}/g,e).replace(/\{1\}/g,t).replace(/\{2\}/g,this.state.totalRecordCount),this.createPageListNavigation(),this.createPageGotoNavigation()))}createPageListNavigation(){if(this.elements.pagingListArea){this.elements.pagingListArea.innerHTML="";var e=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(!(e<=1)){if(this.createPageButton("«",1,1===this.state.currentPage,"ftable-page-number-first"),this.createPageButton("‹",this.state.currentPage-1,1===this.state.currentPage,"ftable-page-number-previous"),"normal"==this.options.pageList){var s=this.calculatePageNumbers(e);let t=0;s.forEach(e=>{1<e-t&&O.create("span",{className:"ftable-page-number-space",textContent:"...",parent:this.elements.pagingListArea}),this.createPageButton(e.toString(),e,!1,e===this.state.currentPage?"ftable-page-number ftable-page-number-active":"ftable-page-number"),t=e})}this.createPageButton("›",this.state.currentPage+1,this.state.currentPage>=e,"ftable-page-number-next"),this.createPageButton("»",e,this.state.currentPage>=e,"ftable-page-number-last")}}}createPageGotoNavigation(){if(this.options.paging&&"none"!==this.options.gotoPageArea){let s=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(s<=1)this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML="";else{this.elements.pagingGotoArea.style.display="inline-block",this.elements.pagingGotoArea.innerHTML="";O.create("span",{textContent:this.options.messages.gotoPageLabel+": ",parent:this.elements.pagingGotoArea});var e="ftable-goto-page-"+(this.options.tableId||"default");if("combobox"===this.options.gotoPageArea){this.elements.gotoPageSelect=O.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=s;e++)O.create("option",{attributes:{value:e},textContent:e,parent:this.elements.gotoPageSelect});this.elements.gotoPageSelect.value=this.state.currentPage,this.elements.gotoPageSelect.addEventListener("change",e=>{e=parseInt(e.target.value);1<=e&&e<=s&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=O.create("input",{attributes:{type:"number",id:e,min:"1",max:s,value:this.state.currentPage,className:"ftable-page-goto-input",style:"width: 65px; margin-left: 4px;"},parent:this.elements.pagingGotoArea}),this.elements.gotoPageInput.addEventListener("change",e=>{var t=parseInt(e.target.value);1<=t&&t<=s?this.changePage(t):e.target.value=this.state.currentPage}))}}else this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML=""}createPageButton(e,t,s,a){a=O.create("span",{className:a+(s?" ftable-page-number-disabled":""),innerHTML:e,parent:this.elements.pagingListArea});s||(a.style.cursor="pointer",a.addEventListener("click",e=>{e.preventDefault(),this.changePage(t)}))}calculatePageNumbers(t){if(t<=7)return Array.from({length:t},(e,t)=>t+1);var s=this.state.currentPage,a=new Set([1,2,t-1,t]);for(let e=Math.max(1,s-1);e<=Math.min(t,s+1);e++)a.add(e);return Array.from(a).sort((e,t)=>e-t)}changePage(e){var t=Math.ceil(this.state.totalRecordCount/this.state.pageSize);(e=Math.max(1,Math.min(e,t)))!==this.state.currentPage&&(this.state.currentPage=e,this.load())}changePageSize(e){this.state.pageSize=e,this.state.currentPage=1,this.load(),this.saveState()}showLoadingIndicator(){0===this.options.loadingAnimationDelay?this.modals.loading&&this.modals.loading.show():this.loadingTimeout=setTimeout(()=>{this.modals.loading&&this.modals.loading.show(),this.loadingShownAt=Date.now()},this.options.loadingAnimationDelay||500)}hideLoadingIndicator(){this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null);var e=this.loadingShownAt?Date.now()-this.loadingShownAt:0;this.modals.loading&&(e<200?setTimeout(()=>{this.modals.loading.hide()},200-e):this.modals.loading.hide()),this.loadingShownAt=null}showError(e){this.modals.error?(this.modals.error.setContent(`<p>${e}</p>`),this.modals.error.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(`<p>${e}</p>`),this.modals.info.show()):alert(e)}reload(e=!1){return this.clearListCache(),e?this.preservedSelections=new Set(this.state.selectedRecords):this.state.selectedRecords.clear(),this.load().then(()=>(e&&this.preservedSelections&&(this.restoreSelections(),this.preservedSelections=null),this))}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}restoreSelections(){if(this.preservedSelections)return this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{var t=this.getKeyValue(e.recordData);t&&this.preservedSelections.has(t)&&this.selectRow(e)}),this}getRowByKey(e){return this.elements.tableBody.querySelector(`[data-record-key="${e}"]`)}destroy(){this.element&&this.element.ftableInstance&&(this.element.ftableInstance=null),Object.values(this.modals).forEach(e=>e.destroy()),this.elements.mainContainer&&this.elements.mainContainer.remove(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.loadingTimeout&&clearTimeout(this.loadingTimeout),window.removeEventListener("resize",this.handleResize),this.options=null,this.state=null,this.elements=null,this.formBuilder=null,this.modals=null}setOption(e,t){return this.options[e]=t,this}getState(){return{...this.state}}addFilter(t,e,s="equals"){return this.state.filters||(this.state.filters=[]),this.state.filters=this.state.filters.filter(e=>e.fieldName!==t),null!=e&&""!==e&&this.state.filters.push({fieldName:t,value:e,operator:s}),this}clearFilters(){return this.state.filters=[],this}exportToCSV(e="table-data.csv"){var t,s,a,i=this.elements.table.cloneNode(!0),o=[],r=e=>`"${String(e||"").replace(/"/g,'""')}"`,l=[];for(t of i.querySelectorAll("thead th"))t.classList.contains("ftable-command-column-header")||t.classList.contains("ftable-toolbarsearch-column-header")||"none"===t.style.display||(s=t.textContent.trim(),l.push(r(s)));o.push(l.join(","));for(a of i.querySelectorAll("tbody tr"))if("none"!==a.style.display){var n,c,d,h=[];let e=!1;for(n of a.querySelectorAll("td"))n.classList.contains("ftable-command-column")||"none"===n.style.display||(n.querySelector("img, button, input, select")&&(n.innerHTML=n.textContent),c=n.innerHTML.replace(/<br\s*\/?>/gi,"\n"),(d=document.createElement("div")).innerHTML=c,h.push(r(d.textContent||"")),e=!0);e&&o.push(h.join(","))}var i=o.join("\n"),i=new Blob(["\ufeff"+i],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a");p.href=URL.createObjectURL(i),p.download=e,p.click(),p.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
|
|
2
2
|
<!DOCTYPE html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
</script>
|
|
33
33
|
</body>
|
|
34
34
|
</html>
|
|
35
|
-
`;e.document.write(t),e.document.close()}async bulkDelete(e="Delete selected records?"){var t=this.getSelectedRows();if(0===t.length)this.showError("No records selected");else if(confirm(e)){var s,a=[];for(s of t.map(e=>this.getKeyValue(e.recordData)))try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});e=a.filter(e=>!e.success).length;0<e&&this.showError(e+` of ${a.length} records could not be deleted`)}}showColumn(e){this.setColumnVisibility(e,!0)}hideColumn(e){this.setColumnVisibility(e,!1)}setColumnVisibility(t,s){var a=this.options.fields[t];if(a)if(!s&&this.isFieldSorted(t))this.showError(`Cannot hide column "${a.title||t}" because it is currently sorted`);else if("fixed"!==a.visibility){a.visibility=s?"visible":"hidden";a=this.columnList.indexOf(t);if(0<=a){let e=a+1;this.options.selecting&&this.options.selectingCheckboxes&&(e+=1);t=`th:nth-child(${e}), td:nth-child(${e})`;this.elements.table.querySelectorAll(t).forEach(e=>{s?O.show(e):O.hide(e)})}this.options.saveUserPreferences&&(this.saveColumnSettings(),this.saveState())}}editRecordByKey(e){var t=this.getRowByKey(e);t?this.editRecord(t):this.showError(`Record with key '${e}' not found`)}async editRecordViaAjax(e,t,s={}){try{var a=this.keyField;if(!a)throw new Error("No key field defined in fTable options");var i={[a]:e,...s},o=this.options.forcePost?await
|
|
35
|
+
`;e.document.write(t),e.document.close()}async bulkDelete(e="Delete selected records?"){var t=this.getSelectedRows();if(0===t.length)this.showError("No records selected");else if(confirm(e)){var s,a=[];for(s of t.map(e=>this.getKeyValue(e.recordData)))try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});e=a.filter(e=>!e.success).length;0<e&&this.showError(e+` of ${a.length} records could not be deleted`)}}showColumn(e){this.setColumnVisibility(e,!0)}hideColumn(e){this.setColumnVisibility(e,!1)}setColumnVisibility(t,s){var a=this.options.fields[t];if(a)if(!s&&this.isFieldSorted(t))this.showError(`Cannot hide column "${a.title||t}" because it is currently sorted`);else if("fixed"!==a.visibility){a.visibility=s?"visible":"hidden";a=this.columnList.indexOf(t);if(0<=a){let e=a+1;this.options.selecting&&this.options.selectingCheckboxes&&(e+=1);t=`th:nth-child(${e}), td:nth-child(${e})`;this.elements.table.querySelectorAll(t).forEach(e=>{s?O.show(e):O.hide(e)})}this.options.saveUserPreferences&&(this.saveColumnSettings(),this.saveState())}}editRecordByKey(e){var t=this.getRowByKey(e);t?this.editRecord(t):this.showError(`Record with key '${e}' not found`)}async editRecordViaAjax(e,t,s={}){try{var a=this.keyField;if(!a)throw new Error("No key field defined in fTable options");var i={[a]:e,...s},o=this.options.forcePost?await n.post(t,i):await n.get(t,i);if(!o||!o.Record)throw new Error("Invalid response or missing Record");var r=o.Record,l=this.getRowByKey(e)||O.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":e}});l.recordData={...r},await this.editRecord(l)}catch(e){this.showError("Failed to load record for editing."),this.logger.error("editRecordViaAjax failed: "+e.message)}}openChildTable(e,t,s){this.options.openChildAsAccordion&&this.closeAllChildTables(),this.closeChildTable(e);var a=O.create("tr",{className:"ftable-child-row"}),i=O.create("td",{attributes:{colspan:this.getVisibleColumnCount()},parent:a}),i=O.create("div",{className:"ftable-child-table-container",parent:i}),a=(e.parentNode.insertBefore(a,e.nextSibling),(e.childRow=a).parentRow=e,new l(i,{...t,paging:void 0===t.paging||t.paging,pageSize:t.pageSize||10,sorting:void 0===t.sorting||t.sorting,selecting:!1,toolbarsearch:!0,messages:{...this.options.messages,...t.messages}}));a.close;return a.close=()=>{this.closeChildTable(e)},a.init(),s&&s(a),e.childTable=a}closeChildTable(e){e.childRow&&(e.childTable&&"function"==typeof e.childTable.destroy&&e.childTable.destroy(),e.childRow.remove(),e.childRow=null,e.childTable=null)}closeAllChildTables(){Object.values(this.elements.tableRows).forEach(e=>{e.childTable&&this.closeChildTable(e)})}getSortingInfo(){let t=this.options.messages||{};return this.state.sorting.map(e=>(this.options.fields[e.fieldName]?.title||e.fieldName)+` (${"ASC"===e.direction?t.ascending||"ascending":t.descending||"descending"})`).join(", ")}renderSortingInfo(){if(this.options.sortingInfoSelector&&this.options.sorting){var e=document.querySelector(this.options.sortingInfoSelector);if(e){e.innerHTML="";let t=this.options.messages||{};var s,a=t.sortingInfoPrefix?`<span class="ftable-sorting-prefix">${t.sortingInfoPrefix}</span> `:"",i=t.sortingInfoSuffix?` <span class="ftable-sorting-suffix">${t.sortingInfoSuffix}</span>`:"";0===this.state.sorting.length?e.innerHTML=t.sortingInfoNone||"":(s=this.getSortingInfo(),e.innerHTML=a+s+i,0<this.state.sorting.length&&((a=document.createElement("button")).textContent=t.resetSorting||"Reset Sorting",a.style.marginLeft="10px",a.classList.add("ftable-sorting-reset-btn"),a.addEventListener("click",e=>{e.preventDefault(),this.state.sorting=[],this.updateSortingHeaders(),this.load(),this.saveState()}),e.appendChild(a)),this.options.tableReset&&((s=document.createElement("button")).textContent=t.resetTable||"Reset Table",s.style.marginLeft="10px",s.classList.add("ftable-table-reset-btn"),s.addEventListener("click",e=>{e.preventDefault();e=t.resetTableConfirm;confirm(e)&&(this.userPrefs.remove("column-settings"),this.userPrefs.remove("table-state"),this.state.sorting=[],this.state.pageSize=this.options.pageSize,this.columnList.forEach(e=>{e=this.options.fields[e];e.visibility="fixed"===e.visibility?"fixed":"visible"}),location.reload())}),e.appendChild(s)))}}}static _waitForFieldReady(s,e,a,i=5e3){if(e){let t=e.querySelector(`[name="${s}"]`);if(t&&"SELECT"===t.tagName)if(1<t.options.length)a();else{let e=new MutationObserver(()=>{1<t.options.length&&(e.disconnect(),a())});e.observe(t,{childList:!0}),0<i&&setTimeout(()=>{e.disconnect(),1<t.options.length?a():console.warn(`FTable: Timeout waiting for field '${s}' to load options`)},i)}else console.warn(`FTable: Field '${s}' not found or not a <select>`)}else console.warn(`FTable: No form provided for waitForFieldReady('${s}')`)}static async waitForFieldReady(t,s,a=5e3){return new Promise(e=>{l._waitForFieldReady(t,s,e,a)})}}e.FTable=l,e.FtableModal=o,e.FTableHttpClient=n,"undefined"!=typeof module&&module.exports&&(module.exports=l,module.exports.FtableModal=o,module.exports.FTableHttpClient=n)})("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this);
|
package/ftable.umd.js
CHANGED
|
@@ -1414,9 +1414,7 @@ class FTableFormBuilder {
|
|
|
1414
1414
|
: [];
|
|
1415
1415
|
|
|
1416
1416
|
// Support data-livesearch attribute on the virtual select as well as field.livesearch
|
|
1417
|
-
const livesearch = field.livesearch
|
|
1418
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
1419
|
-
?? false;
|
|
1417
|
+
const livesearch = field.livesearch ?? false;
|
|
1420
1418
|
|
|
1421
1419
|
return this._buildCustomMultiSelect({
|
|
1422
1420
|
containerId: fieldName,
|
|
@@ -2188,7 +2186,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2188
2186
|
initColumnWidths() {
|
|
2189
2187
|
const visibleFields = this.columnList.filter(fieldName => {
|
|
2190
2188
|
const field = this.options.fields[fieldName];
|
|
2191
|
-
return field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2189
|
+
return !field.action && field.visibility !== 'hidden' && field.visibility !== 'separator';
|
|
2192
2190
|
});
|
|
2193
2191
|
|
|
2194
2192
|
const count = visibleFields.length;
|
|
@@ -2207,7 +2205,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2207
2205
|
th: this.elements.table.querySelector(`[data-field-name="${fieldName}"]`),
|
|
2208
2206
|
field: this.options.fields[fieldName]
|
|
2209
2207
|
}))
|
|
2210
|
-
.filter(item => item.th && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2208
|
+
.filter(item => item.th && !item.field.action && item.field.visibility !== 'hidden' && item.field.visibility !== 'separator');
|
|
2211
2209
|
|
|
2212
2210
|
if (visibleHeaders.length === 0) return;
|
|
2213
2211
|
|
|
@@ -2342,8 +2340,17 @@ class FTable extends FTableEventEmitter {
|
|
|
2342
2340
|
this.fieldList.forEach(fieldName => {
|
|
2343
2341
|
const field = this.options.fields[fieldName];
|
|
2344
2342
|
const isKeyField = field.key === true;
|
|
2345
|
-
|
|
2346
|
-
|
|
2343
|
+
const isActionField = !!field.action; // action: 'select' | 'update' | 'clone' | 'delete'
|
|
2344
|
+
|
|
2345
|
+
if (isActionField) {
|
|
2346
|
+
// Action columns are always listed but never part of forms or sorting
|
|
2347
|
+
field.list = true;
|
|
2348
|
+
field.create = false;
|
|
2349
|
+
field.edit = false;
|
|
2350
|
+
field.sorting = false;
|
|
2351
|
+
field.searchable = false;
|
|
2352
|
+
field.visibility = field.visibility ?? 'visible';
|
|
2353
|
+
} else if (isKeyField) {
|
|
2347
2354
|
if (field.create === undefined || !field.create) {
|
|
2348
2355
|
field.create = true;
|
|
2349
2356
|
field.type = 'hidden';
|
|
@@ -2368,6 +2375,13 @@ class FTable extends FTableEventEmitter {
|
|
|
2368
2375
|
return field.list !== false;
|
|
2369
2376
|
});
|
|
2370
2377
|
|
|
2378
|
+
// Track which actions are user-placed (via action columns in fields)
|
|
2379
|
+
this._userPlacedActions = new Set(
|
|
2380
|
+
this.fieldList
|
|
2381
|
+
.filter(name => this.options.fields[name].action)
|
|
2382
|
+
.map(name => this.options.fields[name].action)
|
|
2383
|
+
);
|
|
2384
|
+
|
|
2371
2385
|
// Find key field
|
|
2372
2386
|
this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
|
|
2373
2387
|
if (!this.keyField) {
|
|
@@ -2378,6 +2392,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2378
2392
|
async resolveAsyncFieldOptions() {
|
|
2379
2393
|
const promises = this.columnList.map(async (fieldName) => {
|
|
2380
2394
|
const field = this.options.fields[fieldName];
|
|
2395
|
+
if (field.action) return; // Skip action columns
|
|
2381
2396
|
const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName);
|
|
2382
2397
|
|
|
2383
2398
|
if (this.formBuilder.shouldResolveOptions(originalOptions)) {
|
|
@@ -2403,7 +2418,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2403
2418
|
for (const row of rows) {
|
|
2404
2419
|
for (const fieldName of this.columnList) {
|
|
2405
2420
|
const field = this.options.fields[fieldName];
|
|
2406
|
-
if (!field.options) continue;
|
|
2421
|
+
if (field.action || !field.options) continue;
|
|
2407
2422
|
|
|
2408
2423
|
const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
|
|
2409
2424
|
if (!cell) continue;
|
|
@@ -2474,8 +2489,8 @@ class FTable extends FTableEventEmitter {
|
|
|
2474
2489
|
parent: thead
|
|
2475
2490
|
});
|
|
2476
2491
|
|
|
2477
|
-
// Add selecting column if enabled
|
|
2478
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2492
|
+
// Add selecting column if enabled (only if not user-placed)
|
|
2493
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2479
2494
|
const selectHeader = FTableDOMHelper.create('th', {
|
|
2480
2495
|
className: `ftable-command-column-header ftable-column-header-select`,
|
|
2481
2496
|
parent: headerRow
|
|
@@ -2493,9 +2508,41 @@ class FTable extends FTableEventEmitter {
|
|
|
2493
2508
|
}
|
|
2494
2509
|
}
|
|
2495
2510
|
|
|
2496
|
-
// Add data columns
|
|
2511
|
+
// Add data columns (including any user-placed action columns)
|
|
2497
2512
|
this.columnList.forEach(fieldName => {
|
|
2498
2513
|
const field = this.options.fields[fieldName];
|
|
2514
|
+
|
|
2515
|
+
// If this column is a user-placed action column, render an action header
|
|
2516
|
+
if (field.action) {
|
|
2517
|
+
const actionClassMap = {
|
|
2518
|
+
select: 'ftable-column-header-select',
|
|
2519
|
+
update: 'ftable-column-header-edit',
|
|
2520
|
+
clone: 'ftable-column-header-clone',
|
|
2521
|
+
delete: 'ftable-column-header-delete',
|
|
2522
|
+
};
|
|
2523
|
+
const th = FTableDOMHelper.create('th', {
|
|
2524
|
+
className: `ftable-command-column-header ${actionClassMap[field.action] || ''}`,
|
|
2525
|
+
parent: headerRow
|
|
2526
|
+
});
|
|
2527
|
+
if (field.title) {
|
|
2528
|
+
th.textContent = field.title;
|
|
2529
|
+
}
|
|
2530
|
+
// For select action with multiselect, add the select-all checkbox
|
|
2531
|
+
if (field.action === 'select' && this.options.selecting && this.options.selectingCheckboxes && this.options.multiselect) {
|
|
2532
|
+
const selectAllCheckbox = FTableDOMHelper.create('input', {
|
|
2533
|
+
attributes: { type: 'checkbox' },
|
|
2534
|
+
parent: th
|
|
2535
|
+
});
|
|
2536
|
+
selectAllCheckbox.addEventListener('change', () => {
|
|
2537
|
+
this.toggleSelectAll(selectAllCheckbox.checked);
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
if (field.width) {
|
|
2541
|
+
th.style.width = field.width;
|
|
2542
|
+
}
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2499
2546
|
const th = FTableDOMHelper.create('th', {
|
|
2500
2547
|
className: `ftable-column-header ${field.listClass || ''} ${field.listClassHeader || ''}`,
|
|
2501
2548
|
attributes: { 'data-field-name': fieldName },
|
|
@@ -2544,22 +2591,22 @@ class FTable extends FTableEventEmitter {
|
|
|
2544
2591
|
}
|
|
2545
2592
|
});
|
|
2546
2593
|
|
|
2547
|
-
// Add action columns
|
|
2548
|
-
if (this.options.actions.updateAction) {
|
|
2594
|
+
// Add default action columns only if not user-placed
|
|
2595
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
2549
2596
|
FTableDOMHelper.create('th', {
|
|
2550
2597
|
className: 'ftable-command-column-header ftable-column-header-edit',
|
|
2551
2598
|
parent: headerRow
|
|
2552
2599
|
});
|
|
2553
2600
|
}
|
|
2554
2601
|
|
|
2555
|
-
if (this.options.actions.cloneAction) {
|
|
2602
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
2556
2603
|
FTableDOMHelper.create('th', {
|
|
2557
2604
|
className: 'ftable-command-column-header ftable-column-header-clone',
|
|
2558
2605
|
parent: headerRow
|
|
2559
2606
|
});
|
|
2560
2607
|
}
|
|
2561
2608
|
|
|
2562
|
-
if (this.options.actions.deleteAction) {
|
|
2609
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
2563
2610
|
FTableDOMHelper.create('th', {
|
|
2564
2611
|
className: 'ftable-command-column-header ftable-column-header-delete',
|
|
2565
2612
|
parent: headerRow
|
|
@@ -2580,17 +2627,27 @@ class FTable extends FTableEventEmitter {
|
|
|
2580
2627
|
parent: theadParent
|
|
2581
2628
|
});
|
|
2582
2629
|
|
|
2583
|
-
// Add empty cell for selecting column if enabled
|
|
2584
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
2630
|
+
// Add empty cell for selecting column if enabled (only if not user-placed)
|
|
2631
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
2585
2632
|
FTableDOMHelper.create('th', {
|
|
2586
2633
|
className: 'ftable-toolbarsearch-column-header',
|
|
2587
2634
|
parent: searchRow
|
|
2588
2635
|
});
|
|
2589
2636
|
}
|
|
2590
2637
|
|
|
2591
|
-
// Add search input cells for data columns
|
|
2638
|
+
// Add search input cells for data columns (including user-placed action columns)
|
|
2592
2639
|
for (const fieldName of this.columnList) {
|
|
2593
2640
|
const field = this.options.fields[fieldName];
|
|
2641
|
+
|
|
2642
|
+
// Action columns get an empty search cell
|
|
2643
|
+
if (field.action) {
|
|
2644
|
+
FTableDOMHelper.create('th', {
|
|
2645
|
+
className: 'ftable-toolbarsearch-column-header ftable-command-column-header',
|
|
2646
|
+
parent: searchRow
|
|
2647
|
+
});
|
|
2648
|
+
continue;
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2594
2651
|
const isSearchable = field.searchable !== false;
|
|
2595
2652
|
|
|
2596
2653
|
const th = FTableDOMHelper.create('th', {
|
|
@@ -2762,9 +2819,9 @@ class FTable extends FTableEventEmitter {
|
|
|
2762
2819
|
parent: searchRow
|
|
2763
2820
|
});
|
|
2764
2821
|
|
|
2765
|
-
const actionCount = (this.options.actions.updateAction ? 1 : 0) +
|
|
2766
|
-
(this.options.actions.deleteAction ? 1 : 0) +
|
|
2767
|
-
(this.options.actions.cloneAction ? 1 : 0);
|
|
2822
|
+
const actionCount = (this.options.actions.updateAction && !this._userPlacedActions.has('update') ? 1 : 0) +
|
|
2823
|
+
(this.options.actions.deleteAction && !this._userPlacedActions.has('delete') ? 1 : 0) +
|
|
2824
|
+
(this.options.actions.cloneAction && !this._userPlacedActions.has('clone') ? 1 : 0);
|
|
2768
2825
|
|
|
2769
2826
|
if (actionCount > 0) {
|
|
2770
2827
|
resetTh.colSpan = actionCount;
|
|
@@ -2872,9 +2929,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2872
2929
|
}
|
|
2873
2930
|
|
|
2874
2931
|
createCustomMultiSelectForSearch(fieldSearchName, fieldName, field, optionsSource, attributes) {
|
|
2875
|
-
const livesearch = field.livesearch
|
|
2876
|
-
?? (attributes['data-livesearch'] === 'true' || attributes['data-livesearch'] === true)
|
|
2877
|
-
?? false;
|
|
2932
|
+
const livesearch = field.livesearch ?? false;
|
|
2878
2933
|
|
|
2879
2934
|
return this.formBuilder._buildCustomMultiSelect({
|
|
2880
2935
|
hiddenSelectId: fieldSearchName,
|
|
@@ -3451,6 +3506,7 @@ class FTable extends FTableEventEmitter {
|
|
|
3451
3506
|
|
|
3452
3507
|
this.columnList.forEach(fieldName => {
|
|
3453
3508
|
const field = this.options.fields[fieldName];
|
|
3509
|
+
if (field.action) return; // Action columns don't appear in column picker
|
|
3454
3510
|
const isVisible = field.visibility !== 'hidden';
|
|
3455
3511
|
const isFixed = field.visibility === 'fixed';
|
|
3456
3512
|
const isSeparator = field.visibility === 'separator';
|
|
@@ -3863,26 +3919,45 @@ class FTable extends FTableEventEmitter {
|
|
|
3863
3919
|
// Store record data
|
|
3864
3920
|
row.recordData = record;
|
|
3865
3921
|
|
|
3866
|
-
// Add selecting checkbox if enabled
|
|
3867
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
3922
|
+
// Add selecting checkbox if enabled (only if not user-placed)
|
|
3923
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
3868
3924
|
this.addSelectingCell(row);
|
|
3869
3925
|
}
|
|
3870
3926
|
|
|
3871
|
-
// Add data cells
|
|
3927
|
+
// Add data cells (including user-placed action columns)
|
|
3872
3928
|
this.columnList.forEach(fieldName => {
|
|
3873
|
-
this.
|
|
3929
|
+
const field = this.options.fields[fieldName];
|
|
3930
|
+
if (field.action) {
|
|
3931
|
+
// Render inline action cell
|
|
3932
|
+
switch (field.action) {
|
|
3933
|
+
case 'select':
|
|
3934
|
+
this.addSelectingCell(row);
|
|
3935
|
+
break;
|
|
3936
|
+
case 'update':
|
|
3937
|
+
this.addEditCell(row);
|
|
3938
|
+
break;
|
|
3939
|
+
case 'clone':
|
|
3940
|
+
this.addCloneCell(row);
|
|
3941
|
+
break;
|
|
3942
|
+
case 'delete':
|
|
3943
|
+
this.addDeleteCell(row);
|
|
3944
|
+
break;
|
|
3945
|
+
}
|
|
3946
|
+
} else {
|
|
3947
|
+
this.addDataCell(row, record, fieldName);
|
|
3948
|
+
}
|
|
3874
3949
|
});
|
|
3875
3950
|
|
|
3876
|
-
// Add action cells
|
|
3877
|
-
if (this.options.actions.updateAction) {
|
|
3951
|
+
// Add default action cells only if not user-placed
|
|
3952
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
3878
3953
|
this.addEditCell(row);
|
|
3879
3954
|
}
|
|
3880
3955
|
|
|
3881
|
-
if (this.options.actions.cloneAction) {
|
|
3956
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
3882
3957
|
this.addCloneCell(row);
|
|
3883
3958
|
}
|
|
3884
3959
|
|
|
3885
|
-
if (this.options.actions.deleteAction) {
|
|
3960
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
3886
3961
|
this.addDeleteCell(row);
|
|
3887
3962
|
}
|
|
3888
3963
|
|