@liedekef/ftable 1.1.12 → 1.1.14
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 +124 -33
- package/ftable.js +124 -33
- package/ftable.min.js +3 -3
- package/ftable.umd.js +124 -33
- package/package.json +1 -1
- package/themes/basic/ftable_basic.css +75 -37
- package/themes/basic/ftable_basic.less +0 -61
- package/themes/basic/ftable_basic.min.css +1 -1
- package/themes/ftable_theme_base.less +87 -10
- package/themes/lightcolor/blue/ftable.css +76 -66
- package/themes/lightcolor/blue/ftable.min.css +1 -1
- package/themes/lightcolor/ftable_lightcolor_base.less +0 -71
- package/themes/lightcolor/gray/ftable.css +76 -66
- package/themes/lightcolor/gray/ftable.min.css +1 -1
- package/themes/lightcolor/green/ftable.css +76 -66
- package/themes/lightcolor/green/ftable.min.css +1 -1
- package/themes/lightcolor/orange/ftable.css +76 -66
- package/themes/lightcolor/orange/ftable.min.css +1 -1
- package/themes/lightcolor/red/ftable.css +76 -66
- package/themes/lightcolor/red/ftable.min.css +1 -1
- package/themes/metro/blue/ftable.css +76 -74
- package/themes/metro/blue/ftable.min.css +1 -1
- package/themes/metro/brown/ftable.css +76 -74
- package/themes/metro/brown/ftable.min.css +1 -1
- package/themes/metro/crimson/ftable.css +76 -74
- package/themes/metro/crimson/ftable.min.css +1 -1
- package/themes/metro/darkgray/ftable.css +76 -74
- package/themes/metro/darkgray/ftable.min.css +1 -1
- package/themes/metro/darkorange/ftable.css +76 -74
- package/themes/metro/darkorange/ftable.min.css +1 -1
- package/themes/metro/ftable_metro_base.less +0 -96
- package/themes/metro/green/ftable.css +76 -74
- package/themes/metro/green/ftable.min.css +1 -1
- package/themes/metro/lightgray/ftable.css +76 -74
- package/themes/metro/lightgray/ftable.min.css +1 -1
- package/themes/metro/pink/ftable.css +76 -74
- package/themes/metro/pink/ftable.min.css +1 -1
- package/themes/metro/purple/ftable.css +76 -74
- package/themes/metro/purple/ftable.min.css +1 -1
- package/themes/metro/red/ftable.css +76 -74
- package/themes/metro/red/ftable.min.css +1 -1
- package/themes/basic/clone.png +0 -0
- package/themes/basic/close.png +0 -0
- package/themes/basic/column-asc.png +0 -0
- package/themes/basic/column-desc.png +0 -0
- package/themes/basic/column-sortable.png +0 -0
- package/themes/basic/delete.png +0 -0
- package/themes/basic/edit.png +0 -0
- package/themes/lightcolor/add.png +0 -0
- package/themes/lightcolor/blue/loading.gif +0 -0
- package/themes/lightcolor/clone.png +0 -0
- package/themes/lightcolor/close.png +0 -0
- package/themes/lightcolor/column-asc.png +0 -0
- package/themes/lightcolor/column-desc.png +0 -0
- package/themes/lightcolor/column-sortable.png +0 -0
- package/themes/lightcolor/delete.png +0 -0
- package/themes/lightcolor/edit.png +0 -0
- package/themes/lightcolor/gray/loading.gif +0 -0
- package/themes/lightcolor/green/loading.gif +0 -0
- package/themes/lightcolor/orange/loading.gif +0 -0
- package/themes/lightcolor/red/loading.gif +0 -0
- package/themes/metro/add.png +0 -0
- package/themes/metro/blue/loading.gif +0 -0
- package/themes/metro/brown/loading.gif +0 -0
- package/themes/metro/clone.png +0 -0
- package/themes/metro/close.png +0 -0
- package/themes/metro/column-asc.png +0 -0
- package/themes/metro/column-desc.png +0 -0
- package/themes/metro/column-sortable.png +0 -0
- package/themes/metro/crimson/loading.gif +0 -0
- package/themes/metro/darkgray/loading.gif +0 -0
- package/themes/metro/darkorange/loading.gif +0 -0
- package/themes/metro/delete.png +0 -0
- package/themes/metro/edit.png +0 -0
- package/themes/metro/green/loading.gif +0 -0
- package/themes/metro/lightgray/loading.gif +0 -0
- package/themes/metro/pink/loading.gif +0 -0
- package/themes/metro/purple/loading.gif +0 -0
- package/themes/metro/red/loading.gif +0 -0
package/ftable.esm.js
CHANGED
|
@@ -1497,6 +1497,50 @@ class FTable extends FTableEventEmitter {
|
|
|
1497
1497
|
|
|
1498
1498
|
// Add essential CSS if not already present
|
|
1499
1499
|
//this.addEssentialCSS();
|
|
1500
|
+
|
|
1501
|
+
// now make sure all tables have a % width
|
|
1502
|
+
this.initColumnWidths();
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
initColumnWidths() {
|
|
1506
|
+
const visibleFields = this.columnList.filter(fieldName => {
|
|
1507
|
+
const field = this.options.fields[fieldName];
|
|
1508
|
+
return field.visibility !== 'hidden';
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
const count = visibleFields.length;
|
|
1512
|
+
visibleFields.forEach(fieldName => {
|
|
1513
|
+
const field = this.options.fields[fieldName];
|
|
1514
|
+
// Use configured width or equal distribution
|
|
1515
|
+
//field.width = field.width || `${(100 / count).toFixed(2)}%`;
|
|
1516
|
+
field.width = field.width || `${(100 / count)}%`;
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
normalizeColumnWidths() {
|
|
1521
|
+
const container = this.elements.mainContainer;
|
|
1522
|
+
const visibleHeaders = this.columnList
|
|
1523
|
+
.map(fieldName => ({
|
|
1524
|
+
th: this.elements.table.querySelector(`[data-field-name="${fieldName}"]`),
|
|
1525
|
+
field: this.options.fields[fieldName]
|
|
1526
|
+
}))
|
|
1527
|
+
.filter(item => item.th && item.field.visibility !== 'hidden');
|
|
1528
|
+
|
|
1529
|
+
if (visibleHeaders.length === 0) return;
|
|
1530
|
+
|
|
1531
|
+
const totalContainerWidth = container.offsetWidth;
|
|
1532
|
+
let totalPercent = 0;
|
|
1533
|
+
|
|
1534
|
+
visibleHeaders.forEach(item => {
|
|
1535
|
+
const widthPct = (item.th.offsetWidth / totalContainerWidth) * 100;
|
|
1536
|
+
//item.field.width = `${widthPct.toFixed(2)}%`;
|
|
1537
|
+
item.field.width = `${widthPct}%`;
|
|
1538
|
+
item.th.style.width = item.field.width;
|
|
1539
|
+
totalPercent += widthPct;
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
// Optional: adjust for rounding drift
|
|
1543
|
+
// (not critical, but can help)
|
|
1500
1544
|
}
|
|
1501
1545
|
|
|
1502
1546
|
parseDefaultSorting(sortStr) {
|
|
@@ -1831,7 +1875,7 @@ class FTable extends FTableEventEmitter {
|
|
|
1831
1875
|
container.setAttribute('title', field.tooltip);
|
|
1832
1876
|
}
|
|
1833
1877
|
|
|
1834
|
-
FTableDOMHelper.create('span', {
|
|
1878
|
+
const textHeader = FTableDOMHelper.create('span', {
|
|
1835
1879
|
className: 'ftable-column-header-text',
|
|
1836
1880
|
text: field.title || fieldName,
|
|
1837
1881
|
parent: container
|
|
@@ -1839,6 +1883,10 @@ class FTable extends FTableEventEmitter {
|
|
|
1839
1883
|
|
|
1840
1884
|
// Make sortable if enabled
|
|
1841
1885
|
if (this.options.sorting && field.sorting !== false) {
|
|
1886
|
+
// Add some empty spaces after the text so the background icon has room next to it
|
|
1887
|
+
// one could play with css and ::after, but then the width calculation of columns borks, resize bar is off etc ...
|
|
1888
|
+
//textHeader.innerHTML += ' ';
|
|
1889
|
+
FTableDOMHelper.addClass(textHeader, 'ftable-sortable-text'); // Add class for spacing
|
|
1842
1890
|
FTableDOMHelper.addClass(th, 'ftable-column-header-sortable');
|
|
1843
1891
|
th.addEventListener('click', (e) => {
|
|
1844
1892
|
e.preventDefault();
|
|
@@ -1897,7 +1945,10 @@ class FTable extends FTableEventEmitter {
|
|
|
1897
1945
|
|
|
1898
1946
|
// Add empty cell for selecting column if enabled
|
|
1899
1947
|
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
1900
|
-
FTableDOMHelper.create('th', {
|
|
1948
|
+
FTableDOMHelper.create('th', {
|
|
1949
|
+
className: 'ftable-toolbarsearch-column-header',
|
|
1950
|
+
parent: searchRow
|
|
1951
|
+
});
|
|
1901
1952
|
}
|
|
1902
1953
|
|
|
1903
1954
|
// Add search input cells for data columns
|
|
@@ -2040,7 +2091,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2040
2091
|
if (this.options.toolbarsearch && this.options.toolbarreset) {
|
|
2041
2092
|
// Add reset button cell
|
|
2042
2093
|
const resetTh = FTableDOMHelper.create('th', {
|
|
2043
|
-
className: 'ftable-toolbarsearch-reset',
|
|
2094
|
+
className: 'ftable-toolbarsearch-column-header ftable-toolbarsearch-reset',
|
|
2044
2095
|
parent: searchRow
|
|
2045
2096
|
});
|
|
2046
2097
|
|
|
@@ -2157,8 +2208,18 @@ class FTable extends FTableEventEmitter {
|
|
|
2157
2208
|
this.load();
|
|
2158
2209
|
}
|
|
2159
2210
|
|
|
2211
|
+
getNextVisibleHeader(th) {
|
|
2212
|
+
const headers = Array.from(this.elements.table.querySelectorAll('thead th:not(.ftable-command-column-header, .ftable-toolbarsearch-column-header)'));
|
|
2213
|
+
const index = headers.indexOf(th);
|
|
2214
|
+
for (let i = index + 1; i < headers.length; i++) {
|
|
2215
|
+
if (headers[i].offsetParent !== null) { // visible
|
|
2216
|
+
return headers[i];
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
return null;
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2160
2222
|
makeColumnResizable(th, container) {
|
|
2161
|
-
// Create resize bar if it doesn't exist
|
|
2162
2223
|
if (!this.elements.resizeBar) {
|
|
2163
2224
|
this.elements.resizeBar = FTableDOMHelper.create('div', {
|
|
2164
2225
|
className: 'ftable-column-resize-bar',
|
|
@@ -2175,59 +2236,88 @@ class FTable extends FTableEventEmitter {
|
|
|
2175
2236
|
let isResizing = false;
|
|
2176
2237
|
let startX = 0;
|
|
2177
2238
|
let startWidth = 0;
|
|
2239
|
+
let containerRect;
|
|
2240
|
+
let nextTh = null;
|
|
2241
|
+
let nextStartWidth = 0;
|
|
2242
|
+
let nextField = null;
|
|
2178
2243
|
|
|
2179
2244
|
resizeHandler.addEventListener('mousedown', (e) => {
|
|
2180
2245
|
e.preventDefault();
|
|
2181
2246
|
e.stopPropagation();
|
|
2182
|
-
|
|
2247
|
+
|
|
2183
2248
|
isResizing = true;
|
|
2249
|
+
|
|
2250
|
+
// Capture layout
|
|
2251
|
+
containerRect = this.elements.mainContainer.getBoundingClientRect();
|
|
2184
2252
|
startX = e.clientX;
|
|
2185
2253
|
startWidth = th.offsetWidth;
|
|
2186
|
-
|
|
2187
|
-
//
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2254
|
+
|
|
2255
|
+
// Find next visible column
|
|
2256
|
+
nextTh = this.getNextVisibleHeader(th);
|
|
2257
|
+
if (nextTh) {
|
|
2258
|
+
nextStartWidth = nextTh.offsetWidth;
|
|
2259
|
+
const fieldName = nextTh.dataset.fieldName;
|
|
2260
|
+
nextField = this.options.fields[fieldName];
|
|
2261
|
+
} else {
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
// Position resize bar
|
|
2266
|
+
const thRect = th.getBoundingClientRect();
|
|
2267
|
+
this.elements.resizeBar.style.left = (thRect.right - containerRect.left) + 'px';
|
|
2268
|
+
this.elements.resizeBar.style.top = (thRect.top - containerRect.top) + 'px';
|
|
2193
2269
|
this.elements.resizeBar.style.height = this.elements.table.offsetHeight + 'px';
|
|
2270
|
+
|
|
2194
2271
|
FTableDOMHelper.show(this.elements.resizeBar);
|
|
2195
|
-
|
|
2272
|
+
|
|
2196
2273
|
document.addEventListener('mousemove', handleMouseMove);
|
|
2197
2274
|
document.addEventListener('mouseup', handleMouseUp);
|
|
2198
2275
|
});
|
|
2199
2276
|
|
|
2200
2277
|
const handleMouseMove = (e) => {
|
|
2201
2278
|
if (!isResizing) return;
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
const newWidth = Math.max(50, startWidth + diff); // Minimum 50px width
|
|
2205
|
-
|
|
2206
|
-
// Update resize bar position
|
|
2207
|
-
const containerRect = this.elements.mainContainer.getBoundingClientRect();
|
|
2279
|
+
|
|
2280
|
+
// Move resize bar with mouse
|
|
2208
2281
|
this.elements.resizeBar.style.left = (e.clientX - containerRect.left) + 'px';
|
|
2209
2282
|
};
|
|
2210
2283
|
|
|
2211
2284
|
const handleMouseUp = (e) => {
|
|
2212
2285
|
if (!isResizing) return;
|
|
2213
|
-
|
|
2214
2286
|
isResizing = false;
|
|
2215
|
-
|
|
2216
|
-
const
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2287
|
+
|
|
2288
|
+
const diff = e.clientX - startX; // px
|
|
2289
|
+
const totalWidth = containerRect.width;
|
|
2290
|
+
|
|
2291
|
+
// Current column new width in px
|
|
2292
|
+
const newCurrentPx = Math.max(50, startWidth + diff);
|
|
2293
|
+
const newCurrentPct = (newCurrentPx / totalWidth) * 100;
|
|
2294
|
+
|
|
2295
|
+
// Next column adjustment
|
|
2296
|
+
if (nextTh) {
|
|
2297
|
+
const newNextPx = Math.max(50, nextStartWidth - diff); // opposite delta
|
|
2298
|
+
const newNextPct = (newNextPx / totalWidth) * 100;
|
|
2299
|
+
|
|
2300
|
+
// Apply to next
|
|
2301
|
+
nextField.width = `${newNextPct.toFixed(2)}%`;
|
|
2302
|
+
nextTh.style.width = nextField.width;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
// Apply to current
|
|
2306
|
+
const field = this.options.fields[th.dataset.fieldName];
|
|
2307
|
+
field.width = `${newCurrentPct.toFixed(2)}%`;
|
|
2308
|
+
th.style.width = field.width;
|
|
2309
|
+
|
|
2310
|
+
// Final normalization (optional, but safe)
|
|
2311
|
+
this.normalizeColumnWidths();
|
|
2312
|
+
|
|
2313
|
+
// Save
|
|
2228
2314
|
if (this.options.saveUserPreferences) {
|
|
2229
2315
|
this.saveColumnSettings();
|
|
2230
2316
|
}
|
|
2317
|
+
|
|
2318
|
+
FTableDOMHelper.hide(this.elements.resizeBar);
|
|
2319
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
2320
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
2231
2321
|
};
|
|
2232
2322
|
}
|
|
2233
2323
|
|
|
@@ -2814,6 +2904,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2814
2904
|
// Update sorting display
|
|
2815
2905
|
this.renderSortingInfo();
|
|
2816
2906
|
|
|
2907
|
+
this.normalizeColumnWidths();
|
|
2817
2908
|
}
|
|
2818
2909
|
|
|
2819
2910
|
buildLoadParams() {
|
package/ftable.js
CHANGED
|
@@ -1502,6 +1502,50 @@ class FTable extends FTableEventEmitter {
|
|
|
1502
1502
|
|
|
1503
1503
|
// Add essential CSS if not already present
|
|
1504
1504
|
//this.addEssentialCSS();
|
|
1505
|
+
|
|
1506
|
+
// now make sure all tables have a % width
|
|
1507
|
+
this.initColumnWidths();
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
initColumnWidths() {
|
|
1511
|
+
const visibleFields = this.columnList.filter(fieldName => {
|
|
1512
|
+
const field = this.options.fields[fieldName];
|
|
1513
|
+
return field.visibility !== 'hidden';
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
const count = visibleFields.length;
|
|
1517
|
+
visibleFields.forEach(fieldName => {
|
|
1518
|
+
const field = this.options.fields[fieldName];
|
|
1519
|
+
// Use configured width or equal distribution
|
|
1520
|
+
//field.width = field.width || `${(100 / count).toFixed(2)}%`;
|
|
1521
|
+
field.width = field.width || `${(100 / count)}%`;
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
normalizeColumnWidths() {
|
|
1526
|
+
const container = this.elements.mainContainer;
|
|
1527
|
+
const visibleHeaders = this.columnList
|
|
1528
|
+
.map(fieldName => ({
|
|
1529
|
+
th: this.elements.table.querySelector(`[data-field-name="${fieldName}"]`),
|
|
1530
|
+
field: this.options.fields[fieldName]
|
|
1531
|
+
}))
|
|
1532
|
+
.filter(item => item.th && item.field.visibility !== 'hidden');
|
|
1533
|
+
|
|
1534
|
+
if (visibleHeaders.length === 0) return;
|
|
1535
|
+
|
|
1536
|
+
const totalContainerWidth = container.offsetWidth;
|
|
1537
|
+
let totalPercent = 0;
|
|
1538
|
+
|
|
1539
|
+
visibleHeaders.forEach(item => {
|
|
1540
|
+
const widthPct = (item.th.offsetWidth / totalContainerWidth) * 100;
|
|
1541
|
+
//item.field.width = `${widthPct.toFixed(2)}%`;
|
|
1542
|
+
item.field.width = `${widthPct}%`;
|
|
1543
|
+
item.th.style.width = item.field.width;
|
|
1544
|
+
totalPercent += widthPct;
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1547
|
+
// Optional: adjust for rounding drift
|
|
1548
|
+
// (not critical, but can help)
|
|
1505
1549
|
}
|
|
1506
1550
|
|
|
1507
1551
|
parseDefaultSorting(sortStr) {
|
|
@@ -1836,7 +1880,7 @@ class FTable extends FTableEventEmitter {
|
|
|
1836
1880
|
container.setAttribute('title', field.tooltip);
|
|
1837
1881
|
}
|
|
1838
1882
|
|
|
1839
|
-
FTableDOMHelper.create('span', {
|
|
1883
|
+
const textHeader = FTableDOMHelper.create('span', {
|
|
1840
1884
|
className: 'ftable-column-header-text',
|
|
1841
1885
|
text: field.title || fieldName,
|
|
1842
1886
|
parent: container
|
|
@@ -1844,6 +1888,10 @@ class FTable extends FTableEventEmitter {
|
|
|
1844
1888
|
|
|
1845
1889
|
// Make sortable if enabled
|
|
1846
1890
|
if (this.options.sorting && field.sorting !== false) {
|
|
1891
|
+
// Add some empty spaces after the text so the background icon has room next to it
|
|
1892
|
+
// one could play with css and ::after, but then the width calculation of columns borks, resize bar is off etc ...
|
|
1893
|
+
//textHeader.innerHTML += ' ';
|
|
1894
|
+
FTableDOMHelper.addClass(textHeader, 'ftable-sortable-text'); // Add class for spacing
|
|
1847
1895
|
FTableDOMHelper.addClass(th, 'ftable-column-header-sortable');
|
|
1848
1896
|
th.addEventListener('click', (e) => {
|
|
1849
1897
|
e.preventDefault();
|
|
@@ -1902,7 +1950,10 @@ class FTable extends FTableEventEmitter {
|
|
|
1902
1950
|
|
|
1903
1951
|
// Add empty cell for selecting column if enabled
|
|
1904
1952
|
if (this.options.selecting && this.options.selectingCheckboxes) {
|
|
1905
|
-
FTableDOMHelper.create('th', {
|
|
1953
|
+
FTableDOMHelper.create('th', {
|
|
1954
|
+
className: 'ftable-toolbarsearch-column-header',
|
|
1955
|
+
parent: searchRow
|
|
1956
|
+
});
|
|
1906
1957
|
}
|
|
1907
1958
|
|
|
1908
1959
|
// Add search input cells for data columns
|
|
@@ -2045,7 +2096,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2045
2096
|
if (this.options.toolbarsearch && this.options.toolbarreset) {
|
|
2046
2097
|
// Add reset button cell
|
|
2047
2098
|
const resetTh = FTableDOMHelper.create('th', {
|
|
2048
|
-
className: 'ftable-toolbarsearch-reset',
|
|
2099
|
+
className: 'ftable-toolbarsearch-column-header ftable-toolbarsearch-reset',
|
|
2049
2100
|
parent: searchRow
|
|
2050
2101
|
});
|
|
2051
2102
|
|
|
@@ -2162,8 +2213,18 @@ class FTable extends FTableEventEmitter {
|
|
|
2162
2213
|
this.load();
|
|
2163
2214
|
}
|
|
2164
2215
|
|
|
2216
|
+
getNextVisibleHeader(th) {
|
|
2217
|
+
const headers = Array.from(this.elements.table.querySelectorAll('thead th:not(.ftable-command-column-header, .ftable-toolbarsearch-column-header)'));
|
|
2218
|
+
const index = headers.indexOf(th);
|
|
2219
|
+
for (let i = index + 1; i < headers.length; i++) {
|
|
2220
|
+
if (headers[i].offsetParent !== null) { // visible
|
|
2221
|
+
return headers[i];
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
return null;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2165
2227
|
makeColumnResizable(th, container) {
|
|
2166
|
-
// Create resize bar if it doesn't exist
|
|
2167
2228
|
if (!this.elements.resizeBar) {
|
|
2168
2229
|
this.elements.resizeBar = FTableDOMHelper.create('div', {
|
|
2169
2230
|
className: 'ftable-column-resize-bar',
|
|
@@ -2180,59 +2241,88 @@ class FTable extends FTableEventEmitter {
|
|
|
2180
2241
|
let isResizing = false;
|
|
2181
2242
|
let startX = 0;
|
|
2182
2243
|
let startWidth = 0;
|
|
2244
|
+
let containerRect;
|
|
2245
|
+
let nextTh = null;
|
|
2246
|
+
let nextStartWidth = 0;
|
|
2247
|
+
let nextField = null;
|
|
2183
2248
|
|
|
2184
2249
|
resizeHandler.addEventListener('mousedown', (e) => {
|
|
2185
2250
|
e.preventDefault();
|
|
2186
2251
|
e.stopPropagation();
|
|
2187
|
-
|
|
2252
|
+
|
|
2188
2253
|
isResizing = true;
|
|
2254
|
+
|
|
2255
|
+
// Capture layout
|
|
2256
|
+
containerRect = this.elements.mainContainer.getBoundingClientRect();
|
|
2189
2257
|
startX = e.clientX;
|
|
2190
2258
|
startWidth = th.offsetWidth;
|
|
2191
|
-
|
|
2192
|
-
//
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2259
|
+
|
|
2260
|
+
// Find next visible column
|
|
2261
|
+
nextTh = this.getNextVisibleHeader(th);
|
|
2262
|
+
if (nextTh) {
|
|
2263
|
+
nextStartWidth = nextTh.offsetWidth;
|
|
2264
|
+
const fieldName = nextTh.dataset.fieldName;
|
|
2265
|
+
nextField = this.options.fields[fieldName];
|
|
2266
|
+
} else {
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
// Position resize bar
|
|
2271
|
+
const thRect = th.getBoundingClientRect();
|
|
2272
|
+
this.elements.resizeBar.style.left = (thRect.right - containerRect.left) + 'px';
|
|
2273
|
+
this.elements.resizeBar.style.top = (thRect.top - containerRect.top) + 'px';
|
|
2198
2274
|
this.elements.resizeBar.style.height = this.elements.table.offsetHeight + 'px';
|
|
2275
|
+
|
|
2199
2276
|
FTableDOMHelper.show(this.elements.resizeBar);
|
|
2200
|
-
|
|
2277
|
+
|
|
2201
2278
|
document.addEventListener('mousemove', handleMouseMove);
|
|
2202
2279
|
document.addEventListener('mouseup', handleMouseUp);
|
|
2203
2280
|
});
|
|
2204
2281
|
|
|
2205
2282
|
const handleMouseMove = (e) => {
|
|
2206
2283
|
if (!isResizing) return;
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
const newWidth = Math.max(50, startWidth + diff); // Minimum 50px width
|
|
2210
|
-
|
|
2211
|
-
// Update resize bar position
|
|
2212
|
-
const containerRect = this.elements.mainContainer.getBoundingClientRect();
|
|
2284
|
+
|
|
2285
|
+
// Move resize bar with mouse
|
|
2213
2286
|
this.elements.resizeBar.style.left = (e.clientX - containerRect.left) + 'px';
|
|
2214
2287
|
};
|
|
2215
2288
|
|
|
2216
2289
|
const handleMouseUp = (e) => {
|
|
2217
2290
|
if (!isResizing) return;
|
|
2218
|
-
|
|
2219
2291
|
isResizing = false;
|
|
2220
|
-
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2292
|
+
|
|
2293
|
+
const diff = e.clientX - startX; // px
|
|
2294
|
+
const totalWidth = containerRect.width;
|
|
2295
|
+
|
|
2296
|
+
// Current column new width in px
|
|
2297
|
+
const newCurrentPx = Math.max(50, startWidth + diff);
|
|
2298
|
+
const newCurrentPct = (newCurrentPx / totalWidth) * 100;
|
|
2299
|
+
|
|
2300
|
+
// Next column adjustment
|
|
2301
|
+
if (nextTh) {
|
|
2302
|
+
const newNextPx = Math.max(50, nextStartWidth - diff); // opposite delta
|
|
2303
|
+
const newNextPct = (newNextPx / totalWidth) * 100;
|
|
2304
|
+
|
|
2305
|
+
// Apply to next
|
|
2306
|
+
nextField.width = `${newNextPct.toFixed(2)}%`;
|
|
2307
|
+
nextTh.style.width = nextField.width;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// Apply to current
|
|
2311
|
+
const field = this.options.fields[th.dataset.fieldName];
|
|
2312
|
+
field.width = `${newCurrentPct.toFixed(2)}%`;
|
|
2313
|
+
th.style.width = field.width;
|
|
2314
|
+
|
|
2315
|
+
// Final normalization (optional, but safe)
|
|
2316
|
+
this.normalizeColumnWidths();
|
|
2317
|
+
|
|
2318
|
+
// Save
|
|
2233
2319
|
if (this.options.saveUserPreferences) {
|
|
2234
2320
|
this.saveColumnSettings();
|
|
2235
2321
|
}
|
|
2322
|
+
|
|
2323
|
+
FTableDOMHelper.hide(this.elements.resizeBar);
|
|
2324
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
2325
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
2236
2326
|
};
|
|
2237
2327
|
}
|
|
2238
2328
|
|
|
@@ -2819,6 +2909,7 @@ class FTable extends FTableEventEmitter {
|
|
|
2819
2909
|
// Update sorting display
|
|
2820
2910
|
this.renderSortingInfo();
|
|
2821
2911
|
|
|
2912
|
+
this.normalizeColumnWidths();
|
|
2822
2913
|
}
|
|
2823
2914
|
|
|
2824
2915
|
buildLoadParams() {
|