@liedekef/ftable 1.1.6 → 1.1.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 +66 -193
- package/ftable.js +67 -194
- package/ftable.min.js +3 -3
- package/ftable.umd.js +67 -194
- package/package.json +1 -1
- package/themes/basic/ftable_basic.css +35 -25
- package/themes/basic/ftable_basic.min.css +1 -1
- package/themes/ftable_theme_base.less +49 -35
- package/themes/lightcolor/blue/ftable.css +43 -33
- package/themes/lightcolor/blue/ftable.min.css +1 -1
- package/themes/lightcolor/ftable_lightcolor_base.less +6 -5
- package/themes/lightcolor/gray/ftable.css +43 -33
- package/themes/lightcolor/gray/ftable.min.css +1 -1
- package/themes/lightcolor/green/ftable.css +43 -33
- package/themes/lightcolor/green/ftable.min.css +1 -1
- package/themes/lightcolor/orange/ftable.css +43 -33
- package/themes/lightcolor/orange/ftable.min.css +1 -1
- package/themes/lightcolor/red/ftable.css +43 -33
- package/themes/lightcolor/red/ftable.min.css +1 -1
- package/themes/metro/blue/ftable.css +35 -25
- package/themes/metro/blue/ftable.min.css +1 -1
- package/themes/metro/brown/ftable.css +35 -25
- package/themes/metro/brown/ftable.min.css +1 -1
- package/themes/metro/crimson/ftable.css +35 -25
- package/themes/metro/crimson/ftable.min.css +1 -1
- package/themes/metro/darkgray/ftable.css +35 -25
- package/themes/metro/darkgray/ftable.min.css +1 -1
- package/themes/metro/darkorange/ftable.css +35 -25
- package/themes/metro/darkorange/ftable.min.css +1 -1
- package/themes/metro/green/ftable.css +35 -25
- package/themes/metro/green/ftable.min.css +1 -1
- package/themes/metro/lightgray/ftable.css +35 -25
- package/themes/metro/lightgray/ftable.min.css +1 -1
- package/themes/metro/pink/ftable.css +35 -25
- package/themes/metro/pink/ftable.min.css +1 -1
- package/themes/metro/purple/ftable.css +35 -25
- package/themes/metro/purple/ftable.min.css +1 -1
- package/themes/metro/red/ftable.css +35 -25
- package/themes/metro/red/ftable.min.css +1 -1
package/ftable.js
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
5
5
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.FTable = factory());
|
|
6
6
|
}(this, (function () {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const FTABLE_DEFAULT_MESSAGES = {
|
|
7
|
+
const FTABLE_DEFAULT_MESSAGES = {
|
|
10
8
|
serverCommunicationError: 'An error occurred while communicating to the server.',
|
|
11
9
|
loadingMessage: 'Loading records...',
|
|
12
10
|
noDataAvailable: 'No data available!',
|
|
@@ -753,7 +751,9 @@ class FTableFormBuilder {
|
|
|
753
751
|
}
|
|
754
752
|
|
|
755
753
|
try {
|
|
756
|
-
const response =
|
|
754
|
+
const response = this.options.forcePost
|
|
755
|
+
? await FTableHttpClient.post(url)
|
|
756
|
+
: await FTableHttpClient.get(url);
|
|
757
757
|
const options = response.Options || response.options || response || [];
|
|
758
758
|
|
|
759
759
|
// Only cache if noCache is false
|
|
@@ -1223,64 +1223,55 @@ class FTableFormBuilder {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
|
|
1225
1225
|
createCheckbox(fieldName, field, value) {
|
|
1226
|
-
function getCheckboxText(field, value) {
|
|
1227
|
-
if (value == undefined ) {
|
|
1228
|
-
value = 0;
|
|
1229
|
-
}
|
|
1230
|
-
if (field.values && field.values[value] !== undefined) {
|
|
1231
|
-
return field.values[value];
|
|
1232
|
-
}
|
|
1233
|
-
return value ? 'Yes' : 'No';
|
|
1234
|
-
}
|
|
1235
1226
|
const wrapper = FTableDOMHelper.create('div', {
|
|
1236
|
-
className: 'ftable-
|
|
1227
|
+
className: 'ftable-yesno-check-wrapper'
|
|
1237
1228
|
});
|
|
1238
1229
|
|
|
1239
1230
|
const isChecked = [1, '1', true, 'true'].includes(value);
|
|
1240
1231
|
|
|
1241
|
-
|
|
1232
|
+
// Determine "Yes" and "No" labels
|
|
1233
|
+
let dataNo = 'No';
|
|
1234
|
+
let dataYes = 'Yes';
|
|
1242
1235
|
|
|
1236
|
+
if (field.values && typeof field.values === 'object') {
|
|
1237
|
+
if (field.values['0'] !== undefined) dataNo = field.values['0'];
|
|
1238
|
+
if (field.values['1'] !== undefined) dataYes = field.values['1'];
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Create the checkbox
|
|
1243
1242
|
const checkbox = FTableDOMHelper.create('input', {
|
|
1243
|
+
className: ['ftable-yesno-check-input', field.inputClass || ''].filter(Boolean).join(' '),
|
|
1244
1244
|
attributes: {
|
|
1245
1245
|
type: 'checkbox',
|
|
1246
1246
|
name: fieldName,
|
|
1247
1247
|
id: `Edit-${fieldName}`,
|
|
1248
|
-
class: field.inputClass || '',
|
|
1249
1248
|
value: '1'
|
|
1250
1249
|
},
|
|
1250
|
+
properties: {
|
|
1251
|
+
checked: isChecked
|
|
1252
|
+
},
|
|
1251
1253
|
parent: wrapper
|
|
1252
1254
|
});
|
|
1253
|
-
checkbox.checked = isChecked;
|
|
1254
1255
|
|
|
1256
|
+
// Create the label with data attributes
|
|
1255
1257
|
const label = FTableDOMHelper.create('label', {
|
|
1256
|
-
|
|
1258
|
+
className: 'ftable-yesno-check-text',
|
|
1259
|
+
attributes: {
|
|
1260
|
+
for: `Edit-${fieldName}`,
|
|
1261
|
+
'data-yes': dataYes,
|
|
1262
|
+
'data-no': dataNo
|
|
1263
|
+
},
|
|
1257
1264
|
parent: wrapper
|
|
1258
1265
|
});
|
|
1259
1266
|
|
|
1260
|
-
// Add
|
|
1267
|
+
// Optional: Add a static form label (e.g., "Is Active?")
|
|
1261
1268
|
if (field.formText) {
|
|
1262
|
-
FTableDOMHelper.create('span', {
|
|
1269
|
+
const formSpan = FTableDOMHelper.create('span', {
|
|
1263
1270
|
text: field.formText,
|
|
1264
|
-
parent:
|
|
1271
|
+
parent: wrapper
|
|
1265
1272
|
});
|
|
1273
|
+
formSpan.style.marginLeft = '8px';
|
|
1266
1274
|
}
|
|
1267
|
-
|
|
1268
|
-
// Only add dynamic value span if field.values is defined
|
|
1269
|
-
if (field.values) {
|
|
1270
|
-
const valueSpan = FTableDOMHelper.create('span', {
|
|
1271
|
-
className: 'ftable-checkbox-dynamic-value',
|
|
1272
|
-
text: ` ${displayValue}`,
|
|
1273
|
-
parent: label
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
|
-
// Update on change
|
|
1277
|
-
checkbox.addEventListener('change', () => {
|
|
1278
|
-
const newValue = checkbox.checked ? '1' : '0';
|
|
1279
|
-
const newText = getCheckboxText(field, newValue);
|
|
1280
|
-
valueSpan.textContent = ` ${newText}`;
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
1275
|
return wrapper;
|
|
1285
1276
|
}
|
|
1286
1277
|
|
|
@@ -1359,10 +1350,14 @@ class FTable extends FTableEventEmitter {
|
|
|
1359
1350
|
this.element = typeof element === 'string' ?
|
|
1360
1351
|
document.querySelector(element) : element;
|
|
1361
1352
|
|
|
1353
|
+
if (!this.element) {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1362
1357
|
// Prevent double initialization
|
|
1363
|
-
if (element.ftableInstance) {
|
|
1358
|
+
if (this.element.ftableInstance) {
|
|
1364
1359
|
//console.warn('FTable is already initialized on this element. Using that.');
|
|
1365
|
-
return element.ftableInstance;
|
|
1360
|
+
return this.element.ftableInstance;
|
|
1366
1361
|
}
|
|
1367
1362
|
|
|
1368
1363
|
this.options = this.mergeOptions(options);
|
|
@@ -1399,6 +1394,7 @@ class FTable extends FTableEventEmitter {
|
|
|
1399
1394
|
logLevel: FTableLogger.LOG_LEVELS.WARN,
|
|
1400
1395
|
actions: {},
|
|
1401
1396
|
fields: {},
|
|
1397
|
+
forcePost: true,
|
|
1402
1398
|
animationsEnabled: true,
|
|
1403
1399
|
loadingAnimationDelay: 1000,
|
|
1404
1400
|
defaultDateLocale: '',
|
|
@@ -2525,13 +2521,15 @@ class FTable extends FTableEventEmitter {
|
|
|
2525
2521
|
// Create overlay to capture clicks outside menu
|
|
2526
2522
|
this.elements.columnSelectionOverlay = FTableDOMHelper.create('div', {
|
|
2527
2523
|
className: 'ftable-contextmenu-overlay',
|
|
2528
|
-
parent: this.elements.mainContainer
|
|
2524
|
+
//parent: this.elements.mainContainer
|
|
2525
|
+
parent: document.body
|
|
2529
2526
|
});
|
|
2530
2527
|
|
|
2531
2528
|
// Create the menu
|
|
2532
2529
|
this.elements.columnSelectionMenu = FTableDOMHelper.create('div', {
|
|
2533
2530
|
className: 'ftable-column-selection-container',
|
|
2534
|
-
parent: this.elements.columnSelectionOverlay
|
|
2531
|
+
//parent: this.elements.columnSelectionOverlay
|
|
2532
|
+
parent: document.body
|
|
2535
2533
|
});
|
|
2536
2534
|
|
|
2537
2535
|
// Populate menu with column options
|
|
@@ -2617,29 +2615,36 @@ class FTable extends FTableEventEmitter {
|
|
|
2617
2615
|
}
|
|
2618
2616
|
|
|
2619
2617
|
positionColumnSelectionMenu(e) {
|
|
2620
|
-
const
|
|
2621
|
-
const menuWidth = 200; // Approximate menu width
|
|
2622
|
-
const menuHeight = this.columnList.length * 30 + 20; // Approximate height
|
|
2618
|
+
const self = this;
|
|
2623
2619
|
|
|
2624
|
-
|
|
2625
|
-
let
|
|
2620
|
+
// menu is bounded to the body for absolute positioning above other content, so safest is to use pageX/Y
|
|
2621
|
+
let left = e.pageX;
|
|
2622
|
+
let top = e.pageY;
|
|
2626
2623
|
|
|
2627
|
-
//
|
|
2628
|
-
|
|
2629
|
-
left = Math.max(0, containerRect.width - menuWidth);
|
|
2630
|
-
}
|
|
2624
|
+
// Define minimum width
|
|
2625
|
+
const minWidth = 100;
|
|
2631
2626
|
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
}
|
|
2627
|
+
// Position the menu
|
|
2628
|
+
self.elements.columnSelectionMenu.style.position = 'absolute';
|
|
2629
|
+
self.elements.columnSelectionMenu.style.left = `${left}px`;
|
|
2630
|
+
self.elements.columnSelectionMenu.style.top = `${top}px`;
|
|
2631
|
+
self.elements.columnSelectionMenu.style.minWidth = `${minWidth}px`;
|
|
2632
|
+
self.elements.columnSelectionMenu.style.boxSizing = 'border-box';
|
|
2633
|
+
|
|
2634
|
+
// Optional: Adjust if menu would overflow right edge
|
|
2635
|
+
const menuWidth = self.elements.columnSelectionMenu.offsetWidth;
|
|
2636
|
+
const windowWidth = window.innerWidth;
|
|
2635
2637
|
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
+
if (left + menuWidth > windowWidth) {
|
|
2639
|
+
left = Math.max(10, windowWidth - menuWidth - 10); // 10px margin
|
|
2640
|
+
self.elements.columnSelectionMenu.style.left = `${left}px`;
|
|
2641
|
+
}
|
|
2638
2642
|
}
|
|
2639
2643
|
|
|
2640
2644
|
hideColumnSelectionMenu() {
|
|
2641
2645
|
if (this.elements.columnSelectionOverlay) {
|
|
2642
2646
|
this.elements.columnSelectionOverlay.remove();
|
|
2647
|
+
this.elements.columnSelectionMenu.remove();
|
|
2643
2648
|
this.elements.columnSelectionOverlay = null;
|
|
2644
2649
|
this.elements.columnSelectionMenu = null;
|
|
2645
2650
|
}
|
|
@@ -2882,7 +2887,9 @@ class FTable extends FTableEventEmitter {
|
|
|
2882
2887
|
if (typeof listAction === 'function') {
|
|
2883
2888
|
data = await listAction(params);
|
|
2884
2889
|
} else if (typeof listAction === 'string') {
|
|
2885
|
-
data =
|
|
2890
|
+
data = this.options.forcePost
|
|
2891
|
+
? await FTableHttpClient.post(listAction, params)
|
|
2892
|
+
: await FTableHttpClient.get(listAction, params);
|
|
2886
2893
|
} else {
|
|
2887
2894
|
throw new Error('No valid listAction provided');
|
|
2888
2895
|
}
|
|
@@ -4416,7 +4423,9 @@ class FTable extends FTableEventEmitter {
|
|
|
4416
4423
|
...params
|
|
4417
4424
|
};
|
|
4418
4425
|
|
|
4419
|
-
const response =
|
|
4426
|
+
const response = this.options.forcePost
|
|
4427
|
+
? await FTableHttpClient.post(url, fullParams)
|
|
4428
|
+
: await FTableHttpClient.get(url, fullParams);
|
|
4420
4429
|
|
|
4421
4430
|
if (!response || !response.Record) {
|
|
4422
4431
|
throw new Error('Invalid response or missing Record');
|
|
@@ -4718,141 +4727,5 @@ class FTable extends FTableEventEmitter {
|
|
|
4718
4727
|
}
|
|
4719
4728
|
}
|
|
4720
4729
|
|
|
4721
|
-
// Export for use
|
|
4722
|
-
//window.FTable = FTable;
|
|
4723
|
-
|
|
4724
|
-
// Usage example:
|
|
4725
|
-
/*
|
|
4726
|
-
const table = new FTable('#myTable', {
|
|
4727
|
-
title: 'My Data Table',
|
|
4728
|
-
paging: true,
|
|
4729
|
-
pageSize: 25,
|
|
4730
|
-
sorting: true,
|
|
4731
|
-
selecting: true,
|
|
4732
|
-
actions: {
|
|
4733
|
-
listAction: '/api/users',
|
|
4734
|
-
createAction: '/api/users',
|
|
4735
|
-
updateAction: '/api/users',
|
|
4736
|
-
deleteAction: '/api/users'
|
|
4737
|
-
},
|
|
4738
|
-
fields: {
|
|
4739
|
-
id: { key: true, list: false },
|
|
4740
|
-
name: {
|
|
4741
|
-
title: 'Name',
|
|
4742
|
-
type: 'text',
|
|
4743
|
-
inputAttributes: "maxlength=100 required"
|
|
4744
|
-
},
|
|
4745
|
-
email: {
|
|
4746
|
-
title: 'Email',
|
|
4747
|
-
type: 'email',
|
|
4748
|
-
width: '40%',
|
|
4749
|
-
inputAttributes: {
|
|
4750
|
-
pattern: '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$'
|
|
4751
|
-
}
|
|
4752
|
-
},
|
|
4753
|
-
created: { title: 'Created', type: 'date', width: '30%' }
|
|
4754
|
-
},
|
|
4755
|
-
toolbarsearch: true,
|
|
4756
|
-
childTable: {
|
|
4757
|
-
title: 'Child Records',
|
|
4758
|
-
actions: {
|
|
4759
|
-
listAction: '/api/users/{id}/orders', // {id} will be replaced with parent record id
|
|
4760
|
-
createAction: '/api/users/{id}/orders',
|
|
4761
|
-
updateAction: '/api/orders',
|
|
4762
|
-
deleteAction: '/api/orders'
|
|
4763
|
-
},
|
|
4764
|
-
fields: {
|
|
4765
|
-
orderId: { key: true, list: false },
|
|
4766
|
-
orderDate: { title: 'Date', type: 'date' },
|
|
4767
|
-
amount: { title: 'Amount', type: 'number' }
|
|
4768
|
-
}
|
|
4769
|
-
},
|
|
4770
|
-
childTableColumnsVisible: true,
|
|
4771
|
-
|
|
4772
|
-
});
|
|
4773
|
-
|
|
4774
|
-
// Or dynamic child table
|
|
4775
|
-
childTable: async function(parentRecord) {
|
|
4776
|
-
return {
|
|
4777
|
-
title: `Orders for ${parentRecord.name}`,
|
|
4778
|
-
actions: {
|
|
4779
|
-
listAction: `/api/users/${parentRecord.id}/orders`
|
|
4780
|
-
},
|
|
4781
|
-
fields: {
|
|
4782
|
-
// Dynamic fields based on parent
|
|
4783
|
-
}
|
|
4784
|
-
};
|
|
4785
|
-
}
|
|
4786
|
-
|
|
4787
|
-
// function for select options
|
|
4788
|
-
fields: {
|
|
4789
|
-
assignee: {
|
|
4790
|
-
title: 'Assigned To',
|
|
4791
|
-
type: 'select',
|
|
4792
|
-
options: async function(params) {
|
|
4793
|
-
// params contains dependsOnValue, dependsOnField, etc.
|
|
4794
|
-
const department = params.dependsOnValue;
|
|
4795
|
-
const response = await fetch(`/api/users?department=${department}`);
|
|
4796
|
-
return response.json();
|
|
4797
|
-
},
|
|
4798
|
-
dependsOn: 'department'
|
|
4799
|
-
}
|
|
4800
|
-
}
|
|
4801
|
-
|
|
4802
|
-
// child table:
|
|
4803
|
-
phoneNumbers: {
|
|
4804
|
-
title: 'Phones',
|
|
4805
|
-
display: (data) => {
|
|
4806
|
-
const img = document.createElement('img');
|
|
4807
|
-
img.className = 'child-opener-image';
|
|
4808
|
-
img.src = '/Content/images/Misc/phone.png';
|
|
4809
|
-
img.title = 'Edit phone numbers';
|
|
4810
|
-
img.style.cursor = 'pointer';
|
|
4811
|
-
|
|
4812
|
-
parentRow = img.closest('tr');
|
|
4813
|
-
img.addEventListener('click', () => {
|
|
4814
|
-
e.stopPropagation();
|
|
4815
|
-
if (parentRow.childRow) {
|
|
4816
|
-
myTable.closeChildTable(parentRow);
|
|
4817
|
-
} else {
|
|
4818
|
-
myTable.openChildTable( parentRow, {
|
|
4819
|
-
title: `${data.record.Name} - Phone numbers`,
|
|
4820
|
-
actions: {
|
|
4821
|
-
listAction: `/PagingPerson/PhoneList?PersonId=${data.record.PersonId}`,
|
|
4822
|
-
deleteAction: '/PagingPerson/DeletePhone',
|
|
4823
|
-
updateAction: '/PagingPerson/UpdatePhone',
|
|
4824
|
-
createAction: `/PagingPerson/CreatePhone?PersonId=${data.record.PersonId}`
|
|
4825
|
-
},
|
|
4826
|
-
fields: {
|
|
4827
|
-
PhoneId: { key: true },
|
|
4828
|
-
Number: { title: 'Number', type: 'text' },
|
|
4829
|
-
Type: { title: 'Type', options: { 0: 'Home', 1: 'Work', 2: 'Mobile' } }
|
|
4830
|
-
}
|
|
4831
|
-
}, (childTable) => {
|
|
4832
|
-
console.log('Child table created');
|
|
4833
|
-
};
|
|
4834
|
-
}
|
|
4835
|
-
});
|
|
4836
|
-
img.addEventListener('click', (e) => {
|
|
4837
|
-
e.stopPropagation();
|
|
4838
|
-
if (parentRow.childRow) {
|
|
4839
|
-
myTable.closeChildTable(parentRow);
|
|
4840
|
-
} else {
|
|
4841
|
-
myTable.openChildTable(parentRow, childOptions);
|
|
4842
|
-
}
|
|
4843
|
-
});
|
|
4844
|
-
|
|
4845
|
-
return img;
|
|
4846
|
-
}
|
|
4847
|
-
}
|
|
4848
|
-
|
|
4849
|
-
// Clear specific options cache
|
|
4850
|
-
table.clearOptionsCache('/api/countries');
|
|
4851
|
-
|
|
4852
|
-
table.load();
|
|
4853
|
-
*/
|
|
4854
|
-
|
|
4855
|
-
window.FTable = FTable;
|
|
4856
|
-
|
|
4857
4730
|
return FTable;
|
|
4858
4731
|
})));
|