@liedekef/ftable 1.1.12 → 1.1.13

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.
Files changed (38) hide show
  1. package/ftable.esm.js +119 -32
  2. package/ftable.js +119 -32
  3. package/ftable.min.js +3 -3
  4. package/ftable.umd.js +119 -32
  5. package/package.json +1 -1
  6. package/themes/basic/ftable_basic.css +1 -0
  7. package/themes/basic/ftable_basic.min.css +1 -1
  8. package/themes/ftable_theme_base.less +1 -0
  9. package/themes/lightcolor/blue/ftable.css +1 -0
  10. package/themes/lightcolor/blue/ftable.min.css +1 -1
  11. package/themes/lightcolor/gray/ftable.css +1 -0
  12. package/themes/lightcolor/gray/ftable.min.css +1 -1
  13. package/themes/lightcolor/green/ftable.css +1 -0
  14. package/themes/lightcolor/green/ftable.min.css +1 -1
  15. package/themes/lightcolor/orange/ftable.css +1 -0
  16. package/themes/lightcolor/orange/ftable.min.css +1 -1
  17. package/themes/lightcolor/red/ftable.css +1 -0
  18. package/themes/lightcolor/red/ftable.min.css +1 -1
  19. package/themes/metro/blue/ftable.css +1 -0
  20. package/themes/metro/blue/ftable.min.css +1 -1
  21. package/themes/metro/brown/ftable.css +1 -0
  22. package/themes/metro/brown/ftable.min.css +1 -1
  23. package/themes/metro/crimson/ftable.css +1 -0
  24. package/themes/metro/crimson/ftable.min.css +1 -1
  25. package/themes/metro/darkgray/ftable.css +1 -0
  26. package/themes/metro/darkgray/ftable.min.css +1 -1
  27. package/themes/metro/darkorange/ftable.css +1 -0
  28. package/themes/metro/darkorange/ftable.min.css +1 -1
  29. package/themes/metro/green/ftable.css +1 -0
  30. package/themes/metro/green/ftable.min.css +1 -1
  31. package/themes/metro/lightgray/ftable.css +1 -0
  32. package/themes/metro/lightgray/ftable.min.css +1 -1
  33. package/themes/metro/pink/ftable.css +1 -0
  34. package/themes/metro/pink/ftable.min.css +1 -1
  35. package/themes/metro/purple/ftable.css +1 -0
  36. package/themes/metro/purple/ftable.min.css +1 -1
  37. package/themes/metro/red/ftable.css +1 -0
  38. package/themes/metro/red/ftable.min.css +1 -1
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) {
@@ -1897,7 +1941,10 @@ class FTable extends FTableEventEmitter {
1897
1941
 
1898
1942
  // Add empty cell for selecting column if enabled
1899
1943
  if (this.options.selecting && this.options.selectingCheckboxes) {
1900
- FTableDOMHelper.create('th', { parent: searchRow });
1944
+ FTableDOMHelper.create('th', {
1945
+ className: 'ftable-toolbarsearch-column-header',
1946
+ parent: searchRow
1947
+ });
1901
1948
  }
1902
1949
 
1903
1950
  // Add search input cells for data columns
@@ -2040,7 +2087,7 @@ class FTable extends FTableEventEmitter {
2040
2087
  if (this.options.toolbarsearch && this.options.toolbarreset) {
2041
2088
  // Add reset button cell
2042
2089
  const resetTh = FTableDOMHelper.create('th', {
2043
- className: 'ftable-toolbarsearch-reset',
2090
+ className: 'ftable-toolbarsearch-column-header ftable-toolbarsearch-reset',
2044
2091
  parent: searchRow
2045
2092
  });
2046
2093
 
@@ -2157,8 +2204,18 @@ class FTable extends FTableEventEmitter {
2157
2204
  this.load();
2158
2205
  }
2159
2206
 
2207
+ getNextVisibleHeader(th) {
2208
+ const headers = Array.from(this.elements.table.querySelectorAll('thead th:not(.ftable-command-column-header, .ftable-toolbarsearch-column-header)'));
2209
+ const index = headers.indexOf(th);
2210
+ for (let i = index + 1; i < headers.length; i++) {
2211
+ if (headers[i].offsetParent !== null) { // visible
2212
+ return headers[i];
2213
+ }
2214
+ }
2215
+ return null;
2216
+ }
2217
+
2160
2218
  makeColumnResizable(th, container) {
2161
- // Create resize bar if it doesn't exist
2162
2219
  if (!this.elements.resizeBar) {
2163
2220
  this.elements.resizeBar = FTableDOMHelper.create('div', {
2164
2221
  className: 'ftable-column-resize-bar',
@@ -2175,59 +2232,88 @@ class FTable extends FTableEventEmitter {
2175
2232
  let isResizing = false;
2176
2233
  let startX = 0;
2177
2234
  let startWidth = 0;
2235
+ let containerRect;
2236
+ let nextTh = null;
2237
+ let nextStartWidth = 0;
2238
+ let nextField = null;
2178
2239
 
2179
2240
  resizeHandler.addEventListener('mousedown', (e) => {
2180
2241
  e.preventDefault();
2181
2242
  e.stopPropagation();
2182
-
2243
+
2183
2244
  isResizing = true;
2245
+
2246
+ // Capture layout
2247
+ containerRect = this.elements.mainContainer.getBoundingClientRect();
2184
2248
  startX = e.clientX;
2185
2249
  startWidth = th.offsetWidth;
2186
-
2187
- // Show resize bar
2188
- const rect = th.getBoundingClientRect();
2189
- const containerRect = this.elements.mainContainer.getBoundingClientRect();
2190
-
2191
- this.elements.resizeBar.style.left = (rect.right - containerRect.left) + 'px';
2192
- this.elements.resizeBar.style.top = (rect.top - containerRect.top) + 'px';
2250
+
2251
+ // Find next visible column
2252
+ nextTh = this.getNextVisibleHeader(th);
2253
+ if (nextTh) {
2254
+ nextStartWidth = nextTh.offsetWidth;
2255
+ const fieldName = nextTh.dataset.fieldName;
2256
+ nextField = this.options.fields[fieldName];
2257
+ } else {
2258
+ return;
2259
+ }
2260
+
2261
+ // Position resize bar
2262
+ const thRect = th.getBoundingClientRect();
2263
+ this.elements.resizeBar.style.left = (thRect.right - containerRect.left) + 'px';
2264
+ this.elements.resizeBar.style.top = (thRect.top - containerRect.top) + 'px';
2193
2265
  this.elements.resizeBar.style.height = this.elements.table.offsetHeight + 'px';
2266
+
2194
2267
  FTableDOMHelper.show(this.elements.resizeBar);
2195
-
2268
+
2196
2269
  document.addEventListener('mousemove', handleMouseMove);
2197
2270
  document.addEventListener('mouseup', handleMouseUp);
2198
2271
  });
2199
2272
 
2200
2273
  const handleMouseMove = (e) => {
2201
2274
  if (!isResizing) return;
2202
-
2203
- const diff = e.clientX - startX;
2204
- const newWidth = Math.max(50, startWidth + diff); // Minimum 50px width
2205
-
2206
- // Update resize bar position
2207
- const containerRect = this.elements.mainContainer.getBoundingClientRect();
2275
+
2276
+ // Move resize bar with mouse
2208
2277
  this.elements.resizeBar.style.left = (e.clientX - containerRect.left) + 'px';
2209
2278
  };
2210
2279
 
2211
2280
  const handleMouseUp = (e) => {
2212
2281
  if (!isResizing) return;
2213
-
2214
2282
  isResizing = false;
2215
- const diff = e.clientX - startX;
2216
- const newWidth = Math.max(50, startWidth + diff);
2217
-
2218
- // Apply new width
2219
- th.style.width = newWidth + 'px';
2220
-
2221
- // Hide resize bar
2222
- FTableDOMHelper.hide(this.elements.resizeBar);
2223
-
2224
- document.removeEventListener('mousemove', handleMouseMove);
2225
- document.removeEventListener('mouseup', handleMouseUp);
2226
-
2227
- // Save column width preference if enabled
2283
+
2284
+ const diff = e.clientX - startX; // px
2285
+ const totalWidth = containerRect.width;
2286
+
2287
+ // Current column new width in px
2288
+ const newCurrentPx = Math.max(50, startWidth + diff);
2289
+ const newCurrentPct = (newCurrentPx / totalWidth) * 100;
2290
+
2291
+ // Next column adjustment
2292
+ if (nextTh) {
2293
+ const newNextPx = Math.max(50, nextStartWidth - diff); // opposite delta
2294
+ const newNextPct = (newNextPx / totalWidth) * 100;
2295
+
2296
+ // Apply to next
2297
+ nextField.width = `${newNextPct.toFixed(2)}%`;
2298
+ nextTh.style.width = nextField.width;
2299
+ }
2300
+
2301
+ // Apply to current
2302
+ const field = this.options.fields[th.dataset.fieldName];
2303
+ field.width = `${newCurrentPct.toFixed(2)}%`;
2304
+ th.style.width = field.width;
2305
+
2306
+ // Final normalization (optional, but safe)
2307
+ this.normalizeColumnWidths();
2308
+
2309
+ // Save
2228
2310
  if (this.options.saveUserPreferences) {
2229
2311
  this.saveColumnSettings();
2230
2312
  }
2313
+
2314
+ FTableDOMHelper.hide(this.elements.resizeBar);
2315
+ document.removeEventListener('mousemove', handleMouseMove);
2316
+ document.removeEventListener('mouseup', handleMouseUp);
2231
2317
  };
2232
2318
  }
2233
2319
 
@@ -2814,6 +2900,7 @@ class FTable extends FTableEventEmitter {
2814
2900
  // Update sorting display
2815
2901
  this.renderSortingInfo();
2816
2902
 
2903
+ this.normalizeColumnWidths();
2817
2904
  }
2818
2905
 
2819
2906
  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) {
@@ -1902,7 +1946,10 @@ class FTable extends FTableEventEmitter {
1902
1946
 
1903
1947
  // Add empty cell for selecting column if enabled
1904
1948
  if (this.options.selecting && this.options.selectingCheckboxes) {
1905
- FTableDOMHelper.create('th', { parent: searchRow });
1949
+ FTableDOMHelper.create('th', {
1950
+ className: 'ftable-toolbarsearch-column-header',
1951
+ parent: searchRow
1952
+ });
1906
1953
  }
1907
1954
 
1908
1955
  // Add search input cells for data columns
@@ -2045,7 +2092,7 @@ class FTable extends FTableEventEmitter {
2045
2092
  if (this.options.toolbarsearch && this.options.toolbarreset) {
2046
2093
  // Add reset button cell
2047
2094
  const resetTh = FTableDOMHelper.create('th', {
2048
- className: 'ftable-toolbarsearch-reset',
2095
+ className: 'ftable-toolbarsearch-column-header ftable-toolbarsearch-reset',
2049
2096
  parent: searchRow
2050
2097
  });
2051
2098
 
@@ -2162,8 +2209,18 @@ class FTable extends FTableEventEmitter {
2162
2209
  this.load();
2163
2210
  }
2164
2211
 
2212
+ getNextVisibleHeader(th) {
2213
+ const headers = Array.from(this.elements.table.querySelectorAll('thead th:not(.ftable-command-column-header, .ftable-toolbarsearch-column-header)'));
2214
+ const index = headers.indexOf(th);
2215
+ for (let i = index + 1; i < headers.length; i++) {
2216
+ if (headers[i].offsetParent !== null) { // visible
2217
+ return headers[i];
2218
+ }
2219
+ }
2220
+ return null;
2221
+ }
2222
+
2165
2223
  makeColumnResizable(th, container) {
2166
- // Create resize bar if it doesn't exist
2167
2224
  if (!this.elements.resizeBar) {
2168
2225
  this.elements.resizeBar = FTableDOMHelper.create('div', {
2169
2226
  className: 'ftable-column-resize-bar',
@@ -2180,59 +2237,88 @@ class FTable extends FTableEventEmitter {
2180
2237
  let isResizing = false;
2181
2238
  let startX = 0;
2182
2239
  let startWidth = 0;
2240
+ let containerRect;
2241
+ let nextTh = null;
2242
+ let nextStartWidth = 0;
2243
+ let nextField = null;
2183
2244
 
2184
2245
  resizeHandler.addEventListener('mousedown', (e) => {
2185
2246
  e.preventDefault();
2186
2247
  e.stopPropagation();
2187
-
2248
+
2188
2249
  isResizing = true;
2250
+
2251
+ // Capture layout
2252
+ containerRect = this.elements.mainContainer.getBoundingClientRect();
2189
2253
  startX = e.clientX;
2190
2254
  startWidth = th.offsetWidth;
2191
-
2192
- // Show resize bar
2193
- const rect = th.getBoundingClientRect();
2194
- const containerRect = this.elements.mainContainer.getBoundingClientRect();
2195
-
2196
- this.elements.resizeBar.style.left = (rect.right - containerRect.left) + 'px';
2197
- this.elements.resizeBar.style.top = (rect.top - containerRect.top) + 'px';
2255
+
2256
+ // Find next visible column
2257
+ nextTh = this.getNextVisibleHeader(th);
2258
+ if (nextTh) {
2259
+ nextStartWidth = nextTh.offsetWidth;
2260
+ const fieldName = nextTh.dataset.fieldName;
2261
+ nextField = this.options.fields[fieldName];
2262
+ } else {
2263
+ return;
2264
+ }
2265
+
2266
+ // Position resize bar
2267
+ const thRect = th.getBoundingClientRect();
2268
+ this.elements.resizeBar.style.left = (thRect.right - containerRect.left) + 'px';
2269
+ this.elements.resizeBar.style.top = (thRect.top - containerRect.top) + 'px';
2198
2270
  this.elements.resizeBar.style.height = this.elements.table.offsetHeight + 'px';
2271
+
2199
2272
  FTableDOMHelper.show(this.elements.resizeBar);
2200
-
2273
+
2201
2274
  document.addEventListener('mousemove', handleMouseMove);
2202
2275
  document.addEventListener('mouseup', handleMouseUp);
2203
2276
  });
2204
2277
 
2205
2278
  const handleMouseMove = (e) => {
2206
2279
  if (!isResizing) return;
2207
-
2208
- const diff = e.clientX - startX;
2209
- const newWidth = Math.max(50, startWidth + diff); // Minimum 50px width
2210
-
2211
- // Update resize bar position
2212
- const containerRect = this.elements.mainContainer.getBoundingClientRect();
2280
+
2281
+ // Move resize bar with mouse
2213
2282
  this.elements.resizeBar.style.left = (e.clientX - containerRect.left) + 'px';
2214
2283
  };
2215
2284
 
2216
2285
  const handleMouseUp = (e) => {
2217
2286
  if (!isResizing) return;
2218
-
2219
2287
  isResizing = false;
2220
- const diff = e.clientX - startX;
2221
- const newWidth = Math.max(50, startWidth + diff);
2222
-
2223
- // Apply new width
2224
- th.style.width = newWidth + 'px';
2225
-
2226
- // Hide resize bar
2227
- FTableDOMHelper.hide(this.elements.resizeBar);
2228
-
2229
- document.removeEventListener('mousemove', handleMouseMove);
2230
- document.removeEventListener('mouseup', handleMouseUp);
2231
-
2232
- // Save column width preference if enabled
2288
+
2289
+ const diff = e.clientX - startX; // px
2290
+ const totalWidth = containerRect.width;
2291
+
2292
+ // Current column new width in px
2293
+ const newCurrentPx = Math.max(50, startWidth + diff);
2294
+ const newCurrentPct = (newCurrentPx / totalWidth) * 100;
2295
+
2296
+ // Next column adjustment
2297
+ if (nextTh) {
2298
+ const newNextPx = Math.max(50, nextStartWidth - diff); // opposite delta
2299
+ const newNextPct = (newNextPx / totalWidth) * 100;
2300
+
2301
+ // Apply to next
2302
+ nextField.width = `${newNextPct.toFixed(2)}%`;
2303
+ nextTh.style.width = nextField.width;
2304
+ }
2305
+
2306
+ // Apply to current
2307
+ const field = this.options.fields[th.dataset.fieldName];
2308
+ field.width = `${newCurrentPct.toFixed(2)}%`;
2309
+ th.style.width = field.width;
2310
+
2311
+ // Final normalization (optional, but safe)
2312
+ this.normalizeColumnWidths();
2313
+
2314
+ // Save
2233
2315
  if (this.options.saveUserPreferences) {
2234
2316
  this.saveColumnSettings();
2235
2317
  }
2318
+
2319
+ FTableDOMHelper.hide(this.elements.resizeBar);
2320
+ document.removeEventListener('mousemove', handleMouseMove);
2321
+ document.removeEventListener('mouseup', handleMouseUp);
2236
2322
  };
2237
2323
  }
2238
2324
 
@@ -2819,6 +2905,7 @@ class FTable extends FTableEventEmitter {
2819
2905
  // Update sorting display
2820
2906
  this.renderSortingInfo();
2821
2907
 
2908
+ this.normalizeColumnWidths();
2822
2909
  }
2823
2910
 
2824
2911
  buildLoadParams() {