@liedekef/ftable 1.2.0 → 1.3.1
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 +110 -34
- package/ftable.js +110 -34
- package/ftable.min.js +2 -2
- package/ftable.umd.js +110 -34
- package/package.json +1 -1
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,
|
|
@@ -3115,9 +3170,10 @@ class FTable extends FTableEventEmitter {
|
|
|
3115
3170
|
|
|
3116
3171
|
const settings = {};
|
|
3117
3172
|
this.columnList.forEach(fieldName => {
|
|
3173
|
+
const field = this.options.fields[fieldName];
|
|
3174
|
+
if (field.action) return; // Action columns have no persistent state
|
|
3118
3175
|
const th = this.elements.table.querySelector(`[data-field-name="${fieldName}"]`);
|
|
3119
3176
|
if (th) {
|
|
3120
|
-
const field = this.options.fields[fieldName];
|
|
3121
3177
|
settings[fieldName] = {
|
|
3122
3178
|
width: th.style.width || field.width || 'auto',
|
|
3123
3179
|
visibility: field.visibility || 'visible'
|
|
@@ -3149,7 +3205,7 @@ class FTable extends FTableEventEmitter {
|
|
|
3149
3205
|
const settings = JSON.parse(settingsJson);
|
|
3150
3206
|
Object.entries(settings).forEach(([fieldName, config]) => {
|
|
3151
3207
|
const field = this.options.fields[fieldName];
|
|
3152
|
-
if (field) {
|
|
3208
|
+
if (field && !field.action) {
|
|
3153
3209
|
if (config.width) field.width = config.width;
|
|
3154
3210
|
if (config.visibility) field.visibility = config.visibility;
|
|
3155
3211
|
}
|
|
@@ -3451,6 +3507,7 @@ class FTable extends FTableEventEmitter {
|
|
|
3451
3507
|
|
|
3452
3508
|
this.columnList.forEach(fieldName => {
|
|
3453
3509
|
const field = this.options.fields[fieldName];
|
|
3510
|
+
if (field.action) return; // Action columns don't appear in column picker
|
|
3454
3511
|
const isVisible = field.visibility !== 'hidden';
|
|
3455
3512
|
const isFixed = field.visibility === 'fixed';
|
|
3456
3513
|
const isSeparator = field.visibility === 'separator';
|
|
@@ -3863,26 +3920,45 @@ class FTable extends FTableEventEmitter {
|
|
|
3863
3920
|
// Store record data
|
|
3864
3921
|
row.recordData = record;
|
|
3865
3922
|
|
|
3866
|
-
// Add selecting checkbox if enabled
|
|
3867
|
-
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
3923
|
+
// Add selecting checkbox if enabled (only if not user-placed)
|
|
3924
|
+
if (this.options.selecting && this.options.selectingCheckboxes && !this._userPlacedActions.has('select')) {
|
|
3868
3925
|
this.addSelectingCell(row);
|
|
3869
3926
|
}
|
|
3870
3927
|
|
|
3871
|
-
// Add data cells
|
|
3928
|
+
// Add data cells (including user-placed action columns)
|
|
3872
3929
|
this.columnList.forEach(fieldName => {
|
|
3873
|
-
this.
|
|
3930
|
+
const field = this.options.fields[fieldName];
|
|
3931
|
+
if (field.action) {
|
|
3932
|
+
// Render inline action cell
|
|
3933
|
+
switch (field.action) {
|
|
3934
|
+
case 'select':
|
|
3935
|
+
this.addSelectingCell(row);
|
|
3936
|
+
break;
|
|
3937
|
+
case 'update':
|
|
3938
|
+
this.addEditCell(row);
|
|
3939
|
+
break;
|
|
3940
|
+
case 'clone':
|
|
3941
|
+
this.addCloneCell(row);
|
|
3942
|
+
break;
|
|
3943
|
+
case 'delete':
|
|
3944
|
+
this.addDeleteCell(row);
|
|
3945
|
+
break;
|
|
3946
|
+
}
|
|
3947
|
+
} else {
|
|
3948
|
+
this.addDataCell(row, record, fieldName);
|
|
3949
|
+
}
|
|
3874
3950
|
});
|
|
3875
3951
|
|
|
3876
|
-
// Add action cells
|
|
3877
|
-
if (this.options.actions.updateAction) {
|
|
3952
|
+
// Add default action cells only if not user-placed
|
|
3953
|
+
if (this.options.actions.updateAction && !this._userPlacedActions.has('update')) {
|
|
3878
3954
|
this.addEditCell(row);
|
|
3879
3955
|
}
|
|
3880
3956
|
|
|
3881
|
-
if (this.options.actions.cloneAction) {
|
|
3957
|
+
if (this.options.actions.cloneAction && !this._userPlacedActions.has('clone')) {
|
|
3882
3958
|
this.addCloneCell(row);
|
|
3883
3959
|
}
|
|
3884
3960
|
|
|
3885
|
-
if (this.options.actions.deleteAction) {
|
|
3961
|
+
if (this.options.actions.deleteAction && !this._userPlacedActions.has('delete')) {
|
|
3886
3962
|
this.addDeleteCell(row);
|
|
3887
3963
|
}
|
|
3888
3964
|
|