@liedekef/ftable 1.3.6 → 1.3.8
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 +123 -254
- package/ftable.js +123 -254
- package/ftable.min.js +2 -2
- package/ftable.umd.js +123 -254
- package/localization/ftable.nl.js +4 -1
- package/package.json +1 -1
- package/themes/basic/ftable_basic.css +15 -6
- package/themes/basic/ftable_basic.min.css +1 -1
- package/themes/ftable_theme_base.less +17 -6
- package/themes/lightcolor/blue/ftable.css +15 -6
- package/themes/lightcolor/blue/ftable.min.css +1 -1
- package/themes/lightcolor/gray/ftable.css +15 -6
- package/themes/lightcolor/gray/ftable.min.css +1 -1
- package/themes/lightcolor/green/ftable.css +15 -6
- package/themes/lightcolor/green/ftable.min.css +1 -1
- package/themes/lightcolor/orange/ftable.css +15 -6
- package/themes/lightcolor/orange/ftable.min.css +1 -1
- package/themes/lightcolor/red/ftable.css +15 -6
- package/themes/lightcolor/red/ftable.min.css +1 -1
- package/themes/metro/blue/ftable.css +15 -6
- package/themes/metro/blue/ftable.min.css +1 -1
- package/themes/metro/brown/ftable.css +15 -6
- package/themes/metro/brown/ftable.min.css +1 -1
- package/themes/metro/crimson/ftable.css +15 -6
- package/themes/metro/crimson/ftable.min.css +1 -1
- package/themes/metro/darkgray/ftable.css +15 -6
- package/themes/metro/darkgray/ftable.min.css +1 -1
- package/themes/metro/darkorange/ftable.css +15 -6
- package/themes/metro/darkorange/ftable.min.css +1 -1
- package/themes/metro/green/ftable.css +15 -6
- package/themes/metro/green/ftable.min.css +1 -1
- package/themes/metro/lightgray/ftable.css +15 -6
- package/themes/metro/lightgray/ftable.min.css +1 -1
- package/themes/metro/pink/ftable.css +15 -6
- package/themes/metro/pink/ftable.min.css +1 -1
- package/themes/metro/purple/ftable.css +15 -6
- package/themes/metro/purple/ftable.min.css +1 -1
- package/themes/metro/red/ftable.css +15 -6
- package/themes/metro/red/ftable.min.css +1 -1
package/ftable.esm.js
CHANGED
|
@@ -33,7 +33,8 @@ const FTABLE_DEFAULT_MESSAGES = {
|
|
|
33
33
|
printTable: '🖨️ Print',
|
|
34
34
|
cloneRecord: 'Clone Record',
|
|
35
35
|
resetTable: 'Reset table',
|
|
36
|
-
resetTableConfirm: 'This will reset
|
|
36
|
+
resetTableConfirm: 'This will reset column visibility, column widths and page size to their defaults. Do you want to continue?',
|
|
37
|
+
resetTableTooltip: 'Resets column visibility, column widths and page size to defaults. Sorting is not affected.',
|
|
37
38
|
resetSearch: 'Reset'
|
|
38
39
|
};
|
|
39
40
|
|
|
@@ -1331,7 +1332,23 @@ class FTableFormBuilder {
|
|
|
1331
1332
|
});
|
|
1332
1333
|
|
|
1333
1334
|
if (field.options) {
|
|
1334
|
-
|
|
1335
|
+
// If a placeholder is defined and the options don't already start with an empty
|
|
1336
|
+
// option, prepend one so that populateSelectOptions handles selected-state correctly.
|
|
1337
|
+
let options = field.options;
|
|
1338
|
+
if (field.placeholder !== undefined) {
|
|
1339
|
+
const firstValue = Array.isArray(options)
|
|
1340
|
+
? (options[0]?.Value ?? options[0]?.value ?? options[0])
|
|
1341
|
+
: Object.keys(options)[0];
|
|
1342
|
+
if (firstValue !== '' && firstValue !== undefined) {
|
|
1343
|
+
const emptyOption = Array.isArray(options)
|
|
1344
|
+
? { Value: '', DisplayText: field.placeholder }
|
|
1345
|
+
: { '': field.placeholder };
|
|
1346
|
+
options = Array.isArray(options)
|
|
1347
|
+
? [emptyOption, ...options]
|
|
1348
|
+
: Object.fromEntries([['', field.placeholder], ...Object.entries(options)]);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
this.populateSelectOptions(select, options, value);
|
|
1335
1352
|
}
|
|
1336
1353
|
|
|
1337
1354
|
return select;
|
|
@@ -2017,7 +2034,8 @@ class FTable extends FTableEventEmitter {
|
|
|
2017
2034
|
saveUserPreferences: true,
|
|
2018
2035
|
saveUserPreferencesMethod: 'localStorage',
|
|
2019
2036
|
defaultSorting: '',
|
|
2020
|
-
|
|
2037
|
+
tableResetButton: false,
|
|
2038
|
+
sortingResetButton: false,
|
|
2021
2039
|
|
|
2022
2040
|
// Paging
|
|
2023
2041
|
paging: false,
|
|
@@ -2227,6 +2245,23 @@ class FTable extends FTableEventEmitter {
|
|
|
2227
2245
|
this.createPageSizeSelector();
|
|
2228
2246
|
}
|
|
2229
2247
|
|
|
2248
|
+
// Table reset button — resets column visibility/widths and pageSize (not sorting)
|
|
2249
|
+
if (this.options.tableResetButton) {
|
|
2250
|
+
const resetTableBtn = FTableDOMHelper.create('button', {
|
|
2251
|
+
className: 'ftable-toolbar-item ftable-table-reset-btn',
|
|
2252
|
+
textContent: this.options.messages.resetTable || 'Reset table',
|
|
2253
|
+
title: this.options.messages.resetTableTooltip || 'Resets column visibility, column widths and page size to defaults.',
|
|
2254
|
+
type: 'button',
|
|
2255
|
+
parent: this.elements.rightArea
|
|
2256
|
+
});
|
|
2257
|
+
resetTableBtn.addEventListener('click', (e) => {
|
|
2258
|
+
e.preventDefault();
|
|
2259
|
+
const msg = this.options.messages.resetTableConfirm;
|
|
2260
|
+
this.modals.resetTable.setContent(`<p>${msg}</p>`);
|
|
2261
|
+
this.modals.resetTable.show();
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2230
2265
|
}
|
|
2231
2266
|
|
|
2232
2267
|
createPageSizeSelector() {
|
|
@@ -2825,7 +2860,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2825
2860
|
if (!hasEmptyFirst) {
|
|
2826
2861
|
FTableDOMHelper.create('option', {
|
|
2827
2862
|
value: '',
|
|
2828
|
-
innerHTML: ' ',
|
|
2863
|
+
innerHTML: field.searchPlaceholder || field.placeholder || ' ',
|
|
2829
2864
|
parent: select
|
|
2830
2865
|
});
|
|
2831
2866
|
}
|
|
@@ -3196,6 +3231,10 @@ class FTable extends FTableEventEmitter {
|
|
|
3196
3231
|
this.createInfoModal();
|
|
3197
3232
|
this.createLoadingModal();
|
|
3198
3233
|
|
|
3234
|
+
if (this.options.tableResetButton) {
|
|
3235
|
+
this.createResetTableModal();
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3199
3238
|
// Initialize them (create DOM) once
|
|
3200
3239
|
Object.values(this.modals).forEach(modal => modal.create());
|
|
3201
3240
|
}
|
|
@@ -3281,6 +3320,34 @@ class FTable extends FTableEventEmitter {
|
|
|
3281
3320
|
});
|
|
3282
3321
|
}
|
|
3283
3322
|
|
|
3323
|
+
createResetTableModal() {
|
|
3324
|
+
this.modals.resetTable = new FtableModal({
|
|
3325
|
+
parent: this.elements.mainContainer,
|
|
3326
|
+
title: this.options.messages.resetTable || 'Reset table',
|
|
3327
|
+
className: 'ftable-reset-table-modal',
|
|
3328
|
+
closeOnOverlayClick: this.options.closeOnOverlayClick,
|
|
3329
|
+
buttons: [
|
|
3330
|
+
{
|
|
3331
|
+
text: this.options.messages.cancel,
|
|
3332
|
+
className: 'ftable-dialog-cancelbutton',
|
|
3333
|
+
onClick: () => this.modals.resetTable.close()
|
|
3334
|
+
},
|
|
3335
|
+
{
|
|
3336
|
+
text: this.options.messages.yes,
|
|
3337
|
+
className: 'ftable-dialog-savebutton',
|
|
3338
|
+
onClick: () => {
|
|
3339
|
+
this.userPrefs.remove('column-settings');
|
|
3340
|
+
// Preserve current sorting, only reset column settings and pageSize
|
|
3341
|
+
this.userPrefs.set('table-state', JSON.stringify({
|
|
3342
|
+
sorting: this.state.sorting
|
|
3343
|
+
}));
|
|
3344
|
+
location.reload();
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
]
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3284
3351
|
createErrorModal() {
|
|
3285
3352
|
this.modals.error = new FtableModal({
|
|
3286
3353
|
parent: this.elements.mainContainer,
|
|
@@ -3564,6 +3631,21 @@ class FTable extends FTableEventEmitter {
|
|
|
3564
3631
|
});
|
|
3565
3632
|
}
|
|
3566
3633
|
|
|
3634
|
+
// Sorting reset button — visible only when sorting differs from default
|
|
3635
|
+
if (this.options.sorting && this.options.sortingResetButton) {
|
|
3636
|
+
this.elements.sortingResetBtn = this.addToolbarButton({
|
|
3637
|
+
text: this.options.messages.resetSorting || 'Reset sorting',
|
|
3638
|
+
className: 'ftable-toolbar-item-sorting-reset',
|
|
3639
|
+
onClick: () => {
|
|
3640
|
+
this.state.sorting = [];
|
|
3641
|
+
this.updateSortingHeaders();
|
|
3642
|
+
this.load();
|
|
3643
|
+
this.saveState();
|
|
3644
|
+
}
|
|
3645
|
+
});
|
|
3646
|
+
FTableDOMHelper.hide(this.elements.sortingResetBtn); // hidden by default
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3567
3649
|
if (this.options.actions.createAction) {
|
|
3568
3650
|
this.addToolbarButton({
|
|
3569
3651
|
text: this.options.messages.addNewRecord,
|
|
@@ -4603,19 +4685,45 @@ class FTable extends FTableEventEmitter {
|
|
|
4603
4685
|
}
|
|
4604
4686
|
|
|
4605
4687
|
updateSortingHeaders() {
|
|
4606
|
-
// Clear all sorting classes
|
|
4688
|
+
// Clear all sorting classes and remove any existing sort badges
|
|
4607
4689
|
const headers = this.elements.table.querySelectorAll('.ftable-column-header-sortable');
|
|
4608
4690
|
headers.forEach(header => {
|
|
4609
4691
|
FTableDOMHelper.removeClass(header, 'ftable-column-header-sorted-asc ftable-column-header-sorted-desc');
|
|
4692
|
+
const existing = header.querySelector('.ftable-sort-badge');
|
|
4693
|
+
if (existing) existing.remove();
|
|
4610
4694
|
});
|
|
4611
|
-
|
|
4612
|
-
// Apply current sorting classes
|
|
4613
|
-
this.state.sorting.forEach(sort => {
|
|
4695
|
+
|
|
4696
|
+
// Apply current sorting classes and sort number badges
|
|
4697
|
+
this.state.sorting.forEach((sort, index) => {
|
|
4614
4698
|
const header = this.elements.table.querySelector(`[data-field-name="${sort.fieldName}"]`);
|
|
4615
|
-
if (header)
|
|
4616
|
-
|
|
4699
|
+
if (!header) return;
|
|
4700
|
+
|
|
4701
|
+
FTableDOMHelper.addClass(header, `ftable-column-header-sorted-${sort.direction.toLowerCase()}`);
|
|
4702
|
+
|
|
4703
|
+
// Sort number badge — only show when multisorting with more than 1 active sort
|
|
4704
|
+
if (this.options.multiSorting && this.state.sorting.length > 1) {
|
|
4705
|
+
const container = header.querySelector('.ftable-column-header-container');
|
|
4706
|
+
if (container) {
|
|
4707
|
+
FTableDOMHelper.create('span', {
|
|
4708
|
+
className: 'ftable-sort-badge',
|
|
4709
|
+
textContent: String(index + 1),
|
|
4710
|
+
parent: container
|
|
4711
|
+
});
|
|
4712
|
+
}
|
|
4617
4713
|
}
|
|
4618
4714
|
});
|
|
4715
|
+
|
|
4716
|
+
// Update visibility of the sorting reset toolbar button
|
|
4717
|
+
this._updateSortingResetButton();
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
_updateSortingResetButton() {
|
|
4721
|
+
if (!this.elements.sortingResetBtn) return;
|
|
4722
|
+
if (this.state.sorting.length === 0) {
|
|
4723
|
+
FTableDOMHelper.hide(this.elements.sortingResetBtn);
|
|
4724
|
+
} else {
|
|
4725
|
+
FTableDOMHelper.show(this.elements.sortingResetBtn);
|
|
4726
|
+
}
|
|
4619
4727
|
}
|
|
4620
4728
|
|
|
4621
4729
|
// Paging Methods
|
|
@@ -5197,8 +5305,8 @@ class FTable extends FTableEventEmitter {
|
|
|
5197
5305
|
// this.emit('columnVisibilityChanged', { field: field });
|
|
5198
5306
|
}
|
|
5199
5307
|
|
|
5200
|
-
// Responsive helpers
|
|
5201
5308
|
/*
|
|
5309
|
+
// Responsive helpers
|
|
5202
5310
|
makeResponsive() {
|
|
5203
5311
|
// Add responsive classes and behavior
|
|
5204
5312
|
FTableDOMHelper.addClass(this.elements.mainContainer, 'ftable-responsive');
|
|
@@ -5243,200 +5351,6 @@ class FTable extends FTableEventEmitter {
|
|
|
5243
5351
|
});
|
|
5244
5352
|
}
|
|
5245
5353
|
|
|
5246
|
-
// Advanced search functionality
|
|
5247
|
-
enableSearch(options = {}) {
|
|
5248
|
-
const searchOptions = {
|
|
5249
|
-
placeholder: 'Search...',
|
|
5250
|
-
debounceMs: 300,
|
|
5251
|
-
searchFields: this.columnList,
|
|
5252
|
-
...options
|
|
5253
|
-
};
|
|
5254
|
-
|
|
5255
|
-
const searchContainer = FTableDOMHelper.create('div', {
|
|
5256
|
-
className: 'ftable-search-container',
|
|
5257
|
-
parent: this.elements.toolbarDiv
|
|
5258
|
-
});
|
|
5259
|
-
|
|
5260
|
-
const searchInput = FTableDOMHelper.create('input', {
|
|
5261
|
-
attributes: {
|
|
5262
|
-
type: 'text',
|
|
5263
|
-
placeholder: searchOptions.placeholder,
|
|
5264
|
-
class: 'ftable-search-input'
|
|
5265
|
-
},
|
|
5266
|
-
parent: searchContainer
|
|
5267
|
-
});
|
|
5268
|
-
|
|
5269
|
-
// Debounced search
|
|
5270
|
-
let searchTimeout;
|
|
5271
|
-
searchInput.addEventListener('input', (e) => {
|
|
5272
|
-
clearTimeout(searchTimeout);
|
|
5273
|
-
searchTimeout = setTimeout(() => {
|
|
5274
|
-
this.performSearch(e.target.value, searchOptions.searchFields);
|
|
5275
|
-
}, searchOptions.debounceMs);
|
|
5276
|
-
});
|
|
5277
|
-
|
|
5278
|
-
return searchInput;
|
|
5279
|
-
}
|
|
5280
|
-
|
|
5281
|
-
async performSearch(query, searchFields) {
|
|
5282
|
-
if (!query.trim()) {
|
|
5283
|
-
return this.load(); // Clear search
|
|
5284
|
-
}
|
|
5285
|
-
|
|
5286
|
-
const searchParams = {
|
|
5287
|
-
search: query,
|
|
5288
|
-
searchFields: searchFields.join(',')
|
|
5289
|
-
};
|
|
5290
|
-
|
|
5291
|
-
return this.load(searchParams);
|
|
5292
|
-
}
|
|
5293
|
-
|
|
5294
|
-
// Keyboard shortcuts
|
|
5295
|
-
enableKeyboardShortcuts() {
|
|
5296
|
-
document.addEventListener('keydown', (e) => {
|
|
5297
|
-
// Only handle shortcuts when table has focus or is active
|
|
5298
|
-
if (!this.elements.mainContainer.contains(document.activeElement)) return;
|
|
5299
|
-
|
|
5300
|
-
switch (e.key) {
|
|
5301
|
-
case 'n':
|
|
5302
|
-
if (e.ctrlKey && this.options.actions.createAction) {
|
|
5303
|
-
e.preventDefault();
|
|
5304
|
-
this.showAddRecordForm();
|
|
5305
|
-
}
|
|
5306
|
-
break;
|
|
5307
|
-
case 'r':
|
|
5308
|
-
if (e.ctrlKey) {
|
|
5309
|
-
e.preventDefault();
|
|
5310
|
-
this.reload();
|
|
5311
|
-
}
|
|
5312
|
-
break;
|
|
5313
|
-
case 'Delete':
|
|
5314
|
-
if (this.options.actions.deleteAction) {
|
|
5315
|
-
const selectedRows = this.getSelectedRows();
|
|
5316
|
-
if (selectedRows.length > 0) {
|
|
5317
|
-
e.preventDefault();
|
|
5318
|
-
this.bulkDelete();
|
|
5319
|
-
}
|
|
5320
|
-
}
|
|
5321
|
-
break;
|
|
5322
|
-
case 'a':
|
|
5323
|
-
if (e.ctrlKey && this.options.selecting && this.options.multiselect) {
|
|
5324
|
-
e.preventDefault();
|
|
5325
|
-
this.toggleSelectAll(true);
|
|
5326
|
-
}
|
|
5327
|
-
break;
|
|
5328
|
-
case 'Escape':
|
|
5329
|
-
// Close any open modals
|
|
5330
|
-
Object.values(this.modals).forEach(modal => {
|
|
5331
|
-
if (modal.isOpen) modal.close();
|
|
5332
|
-
});
|
|
5333
|
-
break;
|
|
5334
|
-
}
|
|
5335
|
-
});
|
|
5336
|
-
}
|
|
5337
|
-
|
|
5338
|
-
// Real-time updates via WebSocket
|
|
5339
|
-
enableRealTimeUpdates(websocketUrl) {
|
|
5340
|
-
if (!websocketUrl) return;
|
|
5341
|
-
|
|
5342
|
-
this.websocket = new WebSocket(websocketUrl);
|
|
5343
|
-
|
|
5344
|
-
this.websocket.onmessage = (event) => {
|
|
5345
|
-
try {
|
|
5346
|
-
const data = JSON.parse(event.data);
|
|
5347
|
-
this.handleRealTimeUpdate(data);
|
|
5348
|
-
} catch (error) {
|
|
5349
|
-
this.logger.error('Failed to parse WebSocket message', error);
|
|
5350
|
-
}
|
|
5351
|
-
};
|
|
5352
|
-
|
|
5353
|
-
this.websocket.onerror = (error) => {
|
|
5354
|
-
this.logger.error('WebSocket error', error);
|
|
5355
|
-
};
|
|
5356
|
-
|
|
5357
|
-
this.websocket.onclose = () => {
|
|
5358
|
-
this.logger.info('WebSocket connection closed');
|
|
5359
|
-
// Attempt to reconnect after delay
|
|
5360
|
-
setTimeout(() => {
|
|
5361
|
-
if (this.websocket.readyState === WebSocket.CLOSED) {
|
|
5362
|
-
this.enableRealTimeUpdates(websocketUrl);
|
|
5363
|
-
}
|
|
5364
|
-
}, 5000);
|
|
5365
|
-
};
|
|
5366
|
-
}
|
|
5367
|
-
|
|
5368
|
-
handleRealTimeUpdate(data) {
|
|
5369
|
-
switch (data.type) {
|
|
5370
|
-
case 'record_added':
|
|
5371
|
-
this.addRecordToTable(data.record);
|
|
5372
|
-
break;
|
|
5373
|
-
case 'record_updated':
|
|
5374
|
-
this.updateRecordInTable(data.record);
|
|
5375
|
-
break;
|
|
5376
|
-
case 'record_deleted':
|
|
5377
|
-
this.removeRecordFromTable(data.recordKey);
|
|
5378
|
-
break;
|
|
5379
|
-
case 'refresh':
|
|
5380
|
-
this.reload();
|
|
5381
|
-
break;
|
|
5382
|
-
}
|
|
5383
|
-
}
|
|
5384
|
-
|
|
5385
|
-
addRecordToTable(record) {
|
|
5386
|
-
const row = this.createTableRow(record);
|
|
5387
|
-
|
|
5388
|
-
// Add to beginning or end based on sorting
|
|
5389
|
-
if (this.state.sorting.length > 0) {
|
|
5390
|
-
// Would need to calculate correct position based on sort
|
|
5391
|
-
this.elements.tableBody.appendChild(row);
|
|
5392
|
-
} else {
|
|
5393
|
-
this.elements.tableBody.appendChild(row);
|
|
5394
|
-
}
|
|
5395
|
-
|
|
5396
|
-
this.state.records.push(record);
|
|
5397
|
-
this.removeNoDataRow();
|
|
5398
|
-
this.refreshRowStyles();
|
|
5399
|
-
|
|
5400
|
-
// Show animation
|
|
5401
|
-
if (this.options.animationsEnabled) {
|
|
5402
|
-
this.showRowAnimation(row, 'added');
|
|
5403
|
-
}
|
|
5404
|
-
}
|
|
5405
|
-
|
|
5406
|
-
updateRecordInTable(record) {
|
|
5407
|
-
const keyValue = this.getKeyValue(record);
|
|
5408
|
-
const existingRow = this.getRowByKey(keyValue);
|
|
5409
|
-
|
|
5410
|
-
if (existingRow) {
|
|
5411
|
-
this.updateRowData(existingRow, record);
|
|
5412
|
-
|
|
5413
|
-
if (this.options.animationsEnabled) {
|
|
5414
|
-
this.showRowAnimation(existingRow, 'updated');
|
|
5415
|
-
}
|
|
5416
|
-
}
|
|
5417
|
-
}
|
|
5418
|
-
|
|
5419
|
-
removeRecordFromTable(keyValue) {
|
|
5420
|
-
const row = this.getRowByKey(keyValue);
|
|
5421
|
-
if (row) {
|
|
5422
|
-
this.removeRowFromTable(row);
|
|
5423
|
-
|
|
5424
|
-
// Remove from state
|
|
5425
|
-
this.state.records = this.state.records.filter(r =>
|
|
5426
|
-
this.getKeyValue(r) !== keyValue
|
|
5427
|
-
);
|
|
5428
|
-
}
|
|
5429
|
-
}
|
|
5430
|
-
|
|
5431
|
-
showRowAnimation(row, type) {
|
|
5432
|
-
const animationClass = `ftable-row-${type}`;
|
|
5433
|
-
FTableDOMHelper.addClass(row, animationClass);
|
|
5434
|
-
|
|
5435
|
-
setTimeout(() => {
|
|
5436
|
-
FTableDOMHelper.removeClass(row, animationClass);
|
|
5437
|
-
}, 2000);
|
|
5438
|
-
}
|
|
5439
|
-
|
|
5440
5354
|
// Plugin system for extensions
|
|
5441
5355
|
use(plugin, options = {}) {
|
|
5442
5356
|
if (typeof plugin === 'function') {
|
|
@@ -5617,65 +5531,20 @@ class FTable extends FTableEventEmitter {
|
|
|
5617
5531
|
|
|
5618
5532
|
const messages = this.options.messages || {};
|
|
5619
5533
|
|
|
5620
|
-
// Get prefix/suffix if defined
|
|
5621
|
-
const prefix = messages.sortingInfoPrefix ? `<span class="ftable-sorting-prefix">${messages.sortingInfoPrefix}</span> ` : '';
|
|
5622
|
-
const suffix = messages.sortingInfoSuffix ? ` <span class="ftable-sorting-suffix">${messages.sortingInfoSuffix}</span>` : '';
|
|
5623
|
-
|
|
5624
5534
|
if (this.state.sorting.length === 0) {
|
|
5625
5535
|
container.innerHTML = messages.sortingInfoNone || '';
|
|
5626
5536
|
return;
|
|
5627
5537
|
}
|
|
5628
5538
|
|
|
5539
|
+
// Get prefix/suffix if defined
|
|
5540
|
+
const prefix = messages.sortingInfoPrefix ? `<span class="ftable-sorting-prefix">${messages.sortingInfoPrefix}</span> ` : '';
|
|
5541
|
+
const suffix = messages.sortingInfoSuffix ? ` <span class="ftable-sorting-suffix">${messages.sortingInfoSuffix}</span>` : '';
|
|
5542
|
+
|
|
5629
5543
|
// Build sorted fields list with translated directions
|
|
5630
5544
|
const sortingInfo = this.getSortingInfo();
|
|
5631
5545
|
|
|
5632
5546
|
// Combine with prefix and suffix
|
|
5633
5547
|
container.innerHTML = `${prefix}${sortingInfo}${suffix}`;
|
|
5634
|
-
|
|
5635
|
-
// Add reset sorting button
|
|
5636
|
-
if (this.state.sorting.length > 0) {
|
|
5637
|
-
const resetSortBtn = document.createElement('button');
|
|
5638
|
-
resetSortBtn.textContent = messages.resetSorting || 'Reset Sorting';
|
|
5639
|
-
resetSortBtn.style.marginLeft = '10px';
|
|
5640
|
-
resetSortBtn.classList.add('ftable-sorting-reset-btn');
|
|
5641
|
-
resetSortBtn.addEventListener('click', (e) => {
|
|
5642
|
-
e.preventDefault();
|
|
5643
|
-
this.state.sorting = [];
|
|
5644
|
-
this.updateSortingHeaders();
|
|
5645
|
-
this.load();
|
|
5646
|
-
this.saveState();
|
|
5647
|
-
});
|
|
5648
|
-
container.appendChild(resetSortBtn);
|
|
5649
|
-
}
|
|
5650
|
-
|
|
5651
|
-
// Add reset table button if enabled
|
|
5652
|
-
if (this.options.tableReset) {
|
|
5653
|
-
const resetTableBtn = document.createElement('button');
|
|
5654
|
-
resetTableBtn.textContent = messages.resetTable || 'Reset Table';
|
|
5655
|
-
resetTableBtn.style.marginLeft = '10px';
|
|
5656
|
-
resetTableBtn.classList.add('ftable-table-reset-btn');
|
|
5657
|
-
resetTableBtn.addEventListener('click', (e) => {
|
|
5658
|
-
e.preventDefault();
|
|
5659
|
-
const confirmMsg = messages.resetTableConfirm;
|
|
5660
|
-
if (confirm(confirmMsg)) {
|
|
5661
|
-
this.userPrefs.remove('column-settings');
|
|
5662
|
-
this.userPrefs.remove('table-state');
|
|
5663
|
-
|
|
5664
|
-
// Clear any in-memory state that might affect rendering
|
|
5665
|
-
this.state.sorting = [];
|
|
5666
|
-
this.state.pageSize = this.options.pageSize;
|
|
5667
|
-
|
|
5668
|
-
// Reset field visibility to default
|
|
5669
|
-
this.columnList.forEach(fieldName => {
|
|
5670
|
-
const field = this.options.fields[fieldName];
|
|
5671
|
-
// Reset to default: hidden only if explicitly set
|
|
5672
|
-
field.visibility = field.visibility === 'fixed' ? 'fixed' : 'visible';
|
|
5673
|
-
});
|
|
5674
|
-
location.reload();
|
|
5675
|
-
}
|
|
5676
|
-
});
|
|
5677
|
-
container.appendChild(resetTableBtn);
|
|
5678
|
-
}
|
|
5679
5548
|
}
|
|
5680
5549
|
|
|
5681
5550
|
/**
|