@liedekef/ftable 1.1.9 → 1.1.12

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 CHANGED
@@ -157,7 +157,11 @@ class FTableDOMHelper {
157
157
  if (options.className) {
158
158
  element.className = options.className;
159
159
  }
160
-
160
+
161
+ if (options.style) {
162
+ element.style.cssText = options.style;
163
+ }
164
+
161
165
  if (options.attributes) {
162
166
  Object.entries(options.attributes).forEach(([key, value]) => {
163
167
  element.setAttribute(key, value);
@@ -1655,25 +1659,13 @@ class FTable extends FTableEventEmitter {
1655
1659
  field.edit = true;
1656
1660
  field.type = 'hidden';
1657
1661
  }
1658
- if (!field.hasOwnProperty('visibility')) {
1659
- field.visibility = 'hidden';
1660
- }
1662
+ field.visibility = field.visibility ?? 'visible';
1661
1663
  } else {
1662
- if (field.create === undefined) {
1663
- field.create = true;
1664
- }
1665
- if (field.edit === undefined) {
1666
- field.edit = true;
1667
- }
1668
- if (field.list === undefined) {
1669
- field.list = true;
1670
- }
1671
- if (field.sorting === undefined) {
1672
- field.sorting = true;
1673
- }
1674
- if (!field.hasOwnProperty('visibility')) {
1675
- field.visibility = 'visible';
1676
- }
1664
+ field.create = field.create ?? true;
1665
+ field.edit = field.edit ?? true;
1666
+ field.list = field.list ?? true;
1667
+ field.sorting = field.sorting ?? true;
1668
+ field.visibility = field.visibility ?? 'visible';
1677
1669
  }
1678
1670
  });
1679
1671
 
@@ -1686,7 +1678,7 @@ class FTable extends FTableEventEmitter {
1686
1678
  // Find key field
1687
1679
  this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
1688
1680
  if (!this.keyField) {
1689
- this.logger.warn('No key field defined');
1681
+ this.logger.info('No key field defined');
1690
1682
  }
1691
1683
  }
1692
1684
 
@@ -1862,7 +1854,7 @@ class FTable extends FTableEventEmitter {
1862
1854
  }
1863
1855
 
1864
1856
  // Hide column if needed
1865
- if (field.visibility === 'hidden') {
1857
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
1866
1858
  FTableDOMHelper.hide(th);
1867
1859
  }
1868
1860
  });
@@ -2040,7 +2032,7 @@ class FTable extends FTableEventEmitter {
2040
2032
  }
2041
2033
 
2042
2034
  // Hide search cell if column is hidden
2043
- if (field.visibility === 'hidden') {
2035
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
2044
2036
  FTableDOMHelper.hide(th);
2045
2037
  }
2046
2038
  }
@@ -2466,8 +2458,8 @@ class FTable extends FTableEventEmitter {
2466
2458
  this.subscribeOptionEvents();
2467
2459
 
2468
2460
  // Add toolbar buttons
2469
- this.createToolbarButtons();
2470
2461
  this.createCustomToolbarItems();
2462
+ this.createToolbarButtons();
2471
2463
 
2472
2464
  // Keyboard shortcuts
2473
2465
  this.bindKeyboardEvents();
@@ -2564,6 +2556,7 @@ class FTable extends FTableEventEmitter {
2564
2556
  const field = this.options.fields[fieldName];
2565
2557
  const isVisible = field.visibility !== 'hidden';
2566
2558
  const isFixed = field.visibility === 'fixed';
2559
+ const isSeparator = field.visibility === 'separator';
2567
2560
  const isSorted = this.isFieldSorted(fieldName);
2568
2561
 
2569
2562
  const listItem = FTableDOMHelper.create('li', {
@@ -2576,24 +2569,32 @@ class FTable extends FTableEventEmitter {
2576
2569
  parent: listItem
2577
2570
  });
2578
2571
 
2579
- const checkbox = FTableDOMHelper.create('input', {
2580
- attributes: {
2581
- type: 'checkbox',
2582
- id: `column-${fieldName}`
2583
- },
2584
- parent: label
2585
- });
2586
-
2587
- checkbox.checked = isVisible;
2572
+ if (!isSeparator) {
2573
+ const checkbox = FTableDOMHelper.create('input', {
2574
+ attributes: {
2575
+ type: 'checkbox',
2576
+ id: `column-${fieldName}`
2577
+ },
2578
+ parent: label
2579
+ });
2580
+ checkbox.checked = isVisible;
2588
2581
 
2589
- // Disable checkbox if column is fixed or currently sorted
2590
- if (isFixed || (isSorted && isVisible)) {
2591
- checkbox.disabled = true;
2592
- listItem.style.opacity = '0.6';
2582
+ // Disable checkbox if column is fixed or currently sorted
2583
+ if (isFixed || (isSorted && isVisible)) {
2584
+ checkbox.disabled = true;
2585
+ listItem.style.opacity = '0.6';
2586
+ }
2587
+ // Handle checkbox change
2588
+ if (!checkbox.disabled) {
2589
+ checkbox.addEventListener('change', () => {
2590
+ this.setColumnVisibility(fieldName, checkbox.checked);
2591
+ });
2592
+ }
2593
2593
  }
2594
2594
 
2595
2595
  const labelText = FTableDOMHelper.create('span', {
2596
2596
  text: field.title || fieldName,
2597
+ style: isSeparator ? 'font-weight: bold;' : null,
2597
2598
  parent: label
2598
2599
  });
2599
2600
 
@@ -2608,12 +2609,6 @@ class FTable extends FTableEventEmitter {
2608
2609
  sortIndicator.style.color = '#666';
2609
2610
  }
2610
2611
 
2611
- // Handle checkbox change
2612
- if (!checkbox.disabled) {
2613
- checkbox.addEventListener('change', () => {
2614
- this.setColumnVisibility(fieldName, checkbox.checked);
2615
- });
2616
- }
2617
2612
  });
2618
2613
  }
2619
2614
 
@@ -2721,7 +2716,7 @@ class FTable extends FTableEventEmitter {
2721
2716
  if (!this.options.toolbar || !this.options.toolbar.items) return;
2722
2717
 
2723
2718
  this.options.toolbar.items.forEach(item => {
2724
- const button = FTableDOMHelper.create('button', {
2719
+ const button = FTableDOMHelper.create('span', {
2725
2720
  className: `ftable-toolbar-item ftable-toolbar-item-custom ${item.buttonClass || ''}`,
2726
2721
  parent: this.elements.toolbarDiv
2727
2722
  });
@@ -2749,6 +2744,7 @@ class FTable extends FTableEventEmitter {
2749
2744
  if (item.text) {
2750
2745
  FTableDOMHelper.create('span', {
2751
2746
  text: item.text,
2747
+ className: `ftable-toolbar-item-text ftable-toolbar-item-custom-text ${item.buttonTextClass || ''}`,
2752
2748
  parent: button
2753
2749
  });
2754
2750
  }
@@ -2999,11 +2995,12 @@ class FTable extends FTableEventEmitter {
2999
2995
  });
3000
2996
 
3001
2997
  const checkbox = FTableDOMHelper.create('input', {
2998
+ className: 'norowselectonclick', // this prevents clicks on the select to also become clicks on the row
3002
2999
  attributes: { type: 'checkbox' },
3003
3000
  parent: cell
3004
3001
  });
3005
3002
 
3006
- checkbox.addEventListener('change', () => {
3003
+ checkbox.addEventListener('change', (e) => {
3007
3004
  this.toggleRowSelection(row);
3008
3005
  });
3009
3006
  }
@@ -3505,7 +3502,9 @@ class FTable extends FTableEventEmitter {
3505
3502
  makeRowSelectable(row) {
3506
3503
  if (this.options.selectOnRowClick !== false) {
3507
3504
  row.addEventListener('click', (e) => {
3508
- if (!e.target.classList.contains('norowselectonclick')) {
3505
+ // input elements can't select the row, nor norowselectonclick class
3506
+ if (!['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA', 'A'].includes(e.target.tagName) &&
3507
+ !e.target.classList.contains('norowselectonclick')) {
3509
3508
  this.toggleRowSelection(row);
3510
3509
  }
3511
3510
  });
@@ -3897,11 +3896,8 @@ class FTable extends FTableEventEmitter {
3897
3896
  }
3898
3897
 
3899
3898
  // Public API Methods
3900
- reload(hard = false) {
3901
- if (hard) {
3902
- // Clear list cache
3903
- this.clearListCache();
3904
- }
3899
+ reload() {
3900
+ this.clearListCache();
3905
3901
  return this.load();
3906
3902
  }
3907
3903
 
package/ftable.js CHANGED
@@ -162,7 +162,11 @@ class FTableDOMHelper {
162
162
  if (options.className) {
163
163
  element.className = options.className;
164
164
  }
165
-
165
+
166
+ if (options.style) {
167
+ element.style.cssText = options.style;
168
+ }
169
+
166
170
  if (options.attributes) {
167
171
  Object.entries(options.attributes).forEach(([key, value]) => {
168
172
  element.setAttribute(key, value);
@@ -1660,25 +1664,13 @@ class FTable extends FTableEventEmitter {
1660
1664
  field.edit = true;
1661
1665
  field.type = 'hidden';
1662
1666
  }
1663
- if (!field.hasOwnProperty('visibility')) {
1664
- field.visibility = 'hidden';
1665
- }
1667
+ field.visibility = field.visibility ?? 'visible';
1666
1668
  } else {
1667
- if (field.create === undefined) {
1668
- field.create = true;
1669
- }
1670
- if (field.edit === undefined) {
1671
- field.edit = true;
1672
- }
1673
- if (field.list === undefined) {
1674
- field.list = true;
1675
- }
1676
- if (field.sorting === undefined) {
1677
- field.sorting = true;
1678
- }
1679
- if (!field.hasOwnProperty('visibility')) {
1680
- field.visibility = 'visible';
1681
- }
1669
+ field.create = field.create ?? true;
1670
+ field.edit = field.edit ?? true;
1671
+ field.list = field.list ?? true;
1672
+ field.sorting = field.sorting ?? true;
1673
+ field.visibility = field.visibility ?? 'visible';
1682
1674
  }
1683
1675
  });
1684
1676
 
@@ -1691,7 +1683,7 @@ class FTable extends FTableEventEmitter {
1691
1683
  // Find key field
1692
1684
  this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
1693
1685
  if (!this.keyField) {
1694
- this.logger.warn('No key field defined');
1686
+ this.logger.info('No key field defined');
1695
1687
  }
1696
1688
  }
1697
1689
 
@@ -1867,7 +1859,7 @@ class FTable extends FTableEventEmitter {
1867
1859
  }
1868
1860
 
1869
1861
  // Hide column if needed
1870
- if (field.visibility === 'hidden') {
1862
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
1871
1863
  FTableDOMHelper.hide(th);
1872
1864
  }
1873
1865
  });
@@ -2045,7 +2037,7 @@ class FTable extends FTableEventEmitter {
2045
2037
  }
2046
2038
 
2047
2039
  // Hide search cell if column is hidden
2048
- if (field.visibility === 'hidden') {
2040
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
2049
2041
  FTableDOMHelper.hide(th);
2050
2042
  }
2051
2043
  }
@@ -2471,8 +2463,8 @@ class FTable extends FTableEventEmitter {
2471
2463
  this.subscribeOptionEvents();
2472
2464
 
2473
2465
  // Add toolbar buttons
2474
- this.createToolbarButtons();
2475
2466
  this.createCustomToolbarItems();
2467
+ this.createToolbarButtons();
2476
2468
 
2477
2469
  // Keyboard shortcuts
2478
2470
  this.bindKeyboardEvents();
@@ -2569,6 +2561,7 @@ class FTable extends FTableEventEmitter {
2569
2561
  const field = this.options.fields[fieldName];
2570
2562
  const isVisible = field.visibility !== 'hidden';
2571
2563
  const isFixed = field.visibility === 'fixed';
2564
+ const isSeparator = field.visibility === 'separator';
2572
2565
  const isSorted = this.isFieldSorted(fieldName);
2573
2566
 
2574
2567
  const listItem = FTableDOMHelper.create('li', {
@@ -2581,24 +2574,32 @@ class FTable extends FTableEventEmitter {
2581
2574
  parent: listItem
2582
2575
  });
2583
2576
 
2584
- const checkbox = FTableDOMHelper.create('input', {
2585
- attributes: {
2586
- type: 'checkbox',
2587
- id: `column-${fieldName}`
2588
- },
2589
- parent: label
2590
- });
2591
-
2592
- checkbox.checked = isVisible;
2577
+ if (!isSeparator) {
2578
+ const checkbox = FTableDOMHelper.create('input', {
2579
+ attributes: {
2580
+ type: 'checkbox',
2581
+ id: `column-${fieldName}`
2582
+ },
2583
+ parent: label
2584
+ });
2585
+ checkbox.checked = isVisible;
2593
2586
 
2594
- // Disable checkbox if column is fixed or currently sorted
2595
- if (isFixed || (isSorted && isVisible)) {
2596
- checkbox.disabled = true;
2597
- listItem.style.opacity = '0.6';
2587
+ // Disable checkbox if column is fixed or currently sorted
2588
+ if (isFixed || (isSorted && isVisible)) {
2589
+ checkbox.disabled = true;
2590
+ listItem.style.opacity = '0.6';
2591
+ }
2592
+ // Handle checkbox change
2593
+ if (!checkbox.disabled) {
2594
+ checkbox.addEventListener('change', () => {
2595
+ this.setColumnVisibility(fieldName, checkbox.checked);
2596
+ });
2597
+ }
2598
2598
  }
2599
2599
 
2600
2600
  const labelText = FTableDOMHelper.create('span', {
2601
2601
  text: field.title || fieldName,
2602
+ style: isSeparator ? 'font-weight: bold;' : null,
2602
2603
  parent: label
2603
2604
  });
2604
2605
 
@@ -2613,12 +2614,6 @@ class FTable extends FTableEventEmitter {
2613
2614
  sortIndicator.style.color = '#666';
2614
2615
  }
2615
2616
 
2616
- // Handle checkbox change
2617
- if (!checkbox.disabled) {
2618
- checkbox.addEventListener('change', () => {
2619
- this.setColumnVisibility(fieldName, checkbox.checked);
2620
- });
2621
- }
2622
2617
  });
2623
2618
  }
2624
2619
 
@@ -2726,7 +2721,7 @@ class FTable extends FTableEventEmitter {
2726
2721
  if (!this.options.toolbar || !this.options.toolbar.items) return;
2727
2722
 
2728
2723
  this.options.toolbar.items.forEach(item => {
2729
- const button = FTableDOMHelper.create('button', {
2724
+ const button = FTableDOMHelper.create('span', {
2730
2725
  className: `ftable-toolbar-item ftable-toolbar-item-custom ${item.buttonClass || ''}`,
2731
2726
  parent: this.elements.toolbarDiv
2732
2727
  });
@@ -2754,6 +2749,7 @@ class FTable extends FTableEventEmitter {
2754
2749
  if (item.text) {
2755
2750
  FTableDOMHelper.create('span', {
2756
2751
  text: item.text,
2752
+ className: `ftable-toolbar-item-text ftable-toolbar-item-custom-text ${item.buttonTextClass || ''}`,
2757
2753
  parent: button
2758
2754
  });
2759
2755
  }
@@ -3004,11 +3000,12 @@ class FTable extends FTableEventEmitter {
3004
3000
  });
3005
3001
 
3006
3002
  const checkbox = FTableDOMHelper.create('input', {
3003
+ className: 'norowselectonclick', // this prevents clicks on the select to also become clicks on the row
3007
3004
  attributes: { type: 'checkbox' },
3008
3005
  parent: cell
3009
3006
  });
3010
3007
 
3011
- checkbox.addEventListener('change', () => {
3008
+ checkbox.addEventListener('change', (e) => {
3012
3009
  this.toggleRowSelection(row);
3013
3010
  });
3014
3011
  }
@@ -3510,7 +3507,9 @@ class FTable extends FTableEventEmitter {
3510
3507
  makeRowSelectable(row) {
3511
3508
  if (this.options.selectOnRowClick !== false) {
3512
3509
  row.addEventListener('click', (e) => {
3513
- if (!e.target.classList.contains('norowselectonclick')) {
3510
+ // input elements can't select the row, nor norowselectonclick class
3511
+ if (!['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA', 'A'].includes(e.target.tagName) &&
3512
+ !e.target.classList.contains('norowselectonclick')) {
3514
3513
  this.toggleRowSelection(row);
3515
3514
  }
3516
3515
  });
@@ -3902,11 +3901,8 @@ class FTable extends FTableEventEmitter {
3902
3901
  }
3903
3902
 
3904
3903
  // Public API Methods
3905
- reload(hard = false) {
3906
- if (hard) {
3907
- // Clear list cache
3908
- this.clearListCache();
3909
- }
3904
+ reload() {
3905
+ this.clearListCache();
3910
3906
  return this.load();
3911
3907
  }
3912
3908
 
package/ftable.min.js CHANGED
@@ -1,4 +1,4 @@
1
- ((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).FTable=t()})(this,function(){let s={serverCommunicationError:"An error occurred while communicating to the server.",loadingMessage:"Loading records...",noDataAvailable:"No data available!",addNewRecord:"Add new record",editRecord:"Edit record",areYouSure:"Are you sure?",deleteConfirmation:"This record will be deleted. Are you sure?",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",close:"Close",cannotLoadOptionsFor:"Cannot load options for field {0}!",pagingInfo:"Showing {0}-{1} of {2}",canNotDeletedRecords:"Can not delete {0} of {1} records!",deleteProgress:"Deleting {0} of {1} records, processing...",pageSizeChangeLabel:"Row count",gotoPageLabel:"Go to page",sortingInfoPrefix:"Sorting applied: ",sortingInfoSuffix:"",ascending:"Ascending",descending:"Descending",sortingInfoNone:"No sorting applied",resetSorting:"Reset sorting",csvExport:"CSV",printTable:"🖨️ Print",cloneRecord:"Clone Record",resetTable:"Reset table",resetTableConfirm:"This will reset all columns, pagesize, sorting to their defaults. Do you want to continue?",resetSearch:"Reset"};class t{constructor(){this.cache=new Map}generateKey(e,t){return e+"?"+Object.keys(t||{}).sort().map(e=>e+"="+t[e]).join("&")}get(e,t){e=this.generateKey(e,t);return this.cache.get(e)}set(e,t,s){e=this.generateKey(e,t);this.cache.set(e,s)}clear(e=null,t=null){if(e)if(t){t=this.generateKey(e,t);this.cache.delete(t)}else{var s,a=e.split("?")[0];for([s]of this.cache)s.startsWith(a)&&this.cache.delete(s)}else this.cache.clear()}size(){return this.cache.size}}class a{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=a.LOG_LEVELS.WARN){this.level=e}log(t,e){var s;!window.console||t<this.level||(s=Object.keys(a.LOG_LEVELS).find(e=>a.LOG_LEVELS[e]===t),console.log(`fTable ${s}: `+e))}debug(e){this.log(a.LOG_LEVELS.DEBUG,e)}info(e){this.log(a.LOG_LEVELS.INFO,e)}warn(e){this.log(a.LOG_LEVELS.WARN,e)}error(e){this.log(a.LOG_LEVELS.ERROR,e)}}class h{static create(e,t={}){let s=document.createElement(e);return t.className&&(s.className=t.className),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{s.setAttribute(e,t)}),t.text&&(s.textContent=t.text),t.html&&(s.innerHTML=t.html),t.parent&&t.parent.appendChild(s),s}static find(e,t=document){return t.querySelector(e)}static findAll(e,t=document){return Array.from(t.querySelectorAll(e))}static addClass(e,t){e.classList.add(...t.split(" "))}static removeClass(e,t){e.classList.remove(...t.split(" "))}static toggleClass(e,t){e.classList.toggle(t)}static show(e){e.style.display=""}static hide(e){e.style.display="none"}static escapeHtml(e){if(!e)return e;let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return e.replace(/[&<>"']/g,e=>t[e])}}class l{static async request(e,t={}){var s={method:"GET",headers:{}},a={...s,...t};t.headers&&(a.headers={...s.headers,...t.headers});try{var i=await fetch(e,a);if(401===i.status)throw new Error("Unauthorized");if(!i.ok)throw new Error("HTTP error! status: "+i.status);var o=i.headers.get("content-type");if(o&&o.includes("application/json"))return await i.json();var r=await i.text();try{return JSON.parse(r)}catch{return{Result:"OK",Message:r}}}catch(e){throw e}}static async get(e,t={}){let a=new URL(e,window.location.href);return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.replace(/\[\]$/,"")+"[]";s.forEach(e=>{null!=e&&a.searchParams.append(t,e)})}else a.searchParams.append(e,s)}),this.request(a.toString(),{method:"GET",headers:{"Content-Type":"application/x-www-form-urlencoded"}})}static async post(e,t={}){e=new URL(e,window.location.href);let a=new FormData;return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.replace(/\[\]$/,"")+"[]";s.forEach(e=>{null!=e&&a.append(t,e)})}else a.append(e,s)}),this.request(e.toString(),{method:"POST",body:a})}}class i{constructor(e,t="localStorage"){this.prefix=e,this.method=t}set(e,t){var s,e=""+this.prefix+e;"localStorage"===this.method?localStorage.setItem(e,t):((s=new Date).setDate(s.getDate()+30),document.cookie=e+`=${t}; expires=${s.toUTCString()}; path=/`)}get(e){e=""+this.prefix+e;if("localStorage"===this.method)return localStorage.getItem(e);var t,s=e+"=";for(t of decodeURIComponent(document.cookie).split(";")){for(;" "===t.charAt(0);)t=t.substring(1);if(0===t.indexOf(s))return t.substring(s.length,t.length)}return null}remove(e){e=""+this.prefix+e;"localStorage"===this.method?localStorage.removeItem(e):document.cookie=e+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"}generatePrefix(e,t){e=e?e+"#":"";return"ftable#"+(t=>{let s=0;if(0!==t.length)for(let e=0;e<t.length;e++){var a=t.charCodeAt(e);s=(s<<5)-s+a,s&=s}return s})(e+=t.join("$")+"#c"+t.length)}}class e{constructor(e={}){this.options={title:"Modal",content:"",buttons:[],className:"ftable-modal",parent:document.body,...e},this.overlay=null,this.modal=null,this.isOpen=!1}create(){this.overlay=h.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=h.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});h.create("h2",{className:"ftable-modal-header",text:this.options.title,parent:this.modal});h.create("span",{className:"ftable-modal-close",html:"&times;",parent:this.modal}).addEventListener("click",()=>this.close());var e=h.create("div",{className:"ftable-modal-body",parent:this.modal});if("string"==typeof this.options.content?e.innerHTML=this.options.content:e.appendChild(this.options.content),0<this.options.buttons.length){let s=h.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=h.create("button",{className:"ftable-dialog-button "+(e.className||""),html:`<span>${e.text}</span>`,parent:s});e.onClick&&t.addEventListener("click",e.onClick)})}return this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.hide(),this}show(){return this.modal||this.create(),this.overlay.style.display="flex",this.isOpen=!0,this}hide(){return this.overlay&&(this.overlay.style.display="none"),this.isOpen=!1,this}close(){return this.hide(),this.options.onClose&&this.options.onClose(),this}destroy(){return this.overlay&&this.overlay.remove(),this.isOpen=!1,this}setContent(e){this.options.content=e;var t=this.modal.querySelector(".ftable-modal-body");t&&(t.innerHTML="","string"==typeof e?t.innerHTML=e:t.appendChild(e))}}class o{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t,this.originalFieldOptions=new Map}storeOriginalFieldOptions(){0<this.originalFieldOptions.size||Object.entries(this.options.fields).forEach(([e,t])=>{!t.options||"function"!=typeof t.options&&"string"!=typeof t.options||this.originalFieldOptions.set(e,t.options)})}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,s,a){var i=h.create("div",{className:"ftable-input-field-container",attributes:{id:"ftable-input-field-container-div-"+e}}),t=(h.create("div",{className:"ftable-input-label",text:t.inputTitle||t.title,parent:i}),this.createInput(e,t,s[e],a));return i.appendChild(t),i}async resolveNonDependantFieldOptions(r){this.storeOriginalFieldOptions();var e=Object.entries(this.options.fields).map(async([t,e])=>{if(!e.dependsOn){var s=this.originalFieldOptions.get(t)||e.options;if(s&&("function"==typeof s||"string"==typeof s))try{var a={dependedValues:r},i={...e,options:s},o=await this.resolveOptions(i,a);e.options=o}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}});await Promise.all(e)}async createForm(s="create",a={}){this.currentFormRecord=a,await this.resolveNonDependantFieldOptions(a);let i=h.create("form",{className:`ftable-dialog-form ftable-${s}-form`});return this.buildDependencyMap(),Object.entries(this.options.fields).forEach(([e,t])=>{this.shouldIncludeField(t,s)&&(e=this.createFieldContainer(e,t,a,s),i.appendChild(e))}),this.setupDependencyListeners(i),i}buildDependencyMap(){this.dependencies.clear(),Object.entries(this.options.fields).forEach(([t,s])=>{if(s.dependsOn){let e;"string"==typeof s.dependsOn&&(e=s.dependsOn.split(",").map(e=>e.trim()).filter(e=>e)).forEach(e=>{this.dependencies.has(e)||this.dependencies.set(e,[]),this.dependencies.get(e).push(t)})}})}setupDependencyListeners(s){Array.from(this.dependencies.keys()).forEach(e=>{var t=s.querySelector(`[name="${e}"]`);t&&t.addEventListener("change",()=>{this.handleDependencyChange(s,e)})}),this.handleDependencyChange(s)}async resolveOptions(t,e={}){if(!t.options)return[];if(Array.isArray(t.options)||"object"==typeof t.options)return t.options;let s,a=!1;e={...e,clearCache:()=>{a=!0}};if("function"==typeof t.options)s=await t.options(e);else{if("string"!=typeof t.options)return[];s=t.options}e=s&&"object"==typeof s&&s.url,t=e?s.url:s;if(a=e&&void 0!==s.noCache?s.noCache:a,"string"!=typeof t)return[];if(!a){e=this.optionsCache.get(t,{});if(e)return e}try{var i=this.options.forcePost?await l.post(t):await l.get(t),o=i.Options||i.options||i||[];return a||this.optionsCache.set(t,{},o),o}catch(e){return console.error(`Failed to load options from ${t}:`,e),[]}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}async handleDependencyChange(e,t=""){var s,a,i={};for([s,a]of Object.entries(this.options.fields)){var o=e.querySelector(`[name="${s}"]`);o&&("checkbox"===o.type?i[s]=o.checked?"1":"0":i[s]=o.value)}var r,n,l=e.classList.contains("ftable-create-form")?"create":"edit",c={record:this.currentFormRecord||{},source:l,form:e,dependedValues:i};for([r,n]of Object.entries(this.options.fields))if(n.dependsOn){if(""!==t)if(!n.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(t))continue;var d=e.querySelector(`[name="${r}"]`);if(d&&this.shouldIncludeField(n,l))try{"SELECT"===d.tagName?d.innerHTML='<option value="">Loading...</option>':"INPUT"===d.tagName&&d.list&&(h=document.getElementById(d.list.id))&&(h.innerHTML="");var h,p={...c,dependsOnField:n.dependsOn,dependsOnValue:i[n.dependsOn]},m=this.originalFieldOptions.get(r)||n.options,u={...n,options:m},f=await this.resolveOptions(u,p);"SELECT"===d.tagName?this.populateSelectOptions(d,f,""):"INPUT"===d.tagName&&d.list&&this.populateDatalistOptions(d.list,f)}catch(e){console.error(`Error loading options for ${r}:`,e),"SELECT"===d.tagName&&(d.innerHTML='<option value="">Error</option>')}}}parseInputAttributes(e){if("string"!=typeof e)return e||{};for(var t={},s=/(\w+)(?:=("[^"]*"|'[^']*'|\S+))?/g;null!==(i=s.exec(e));){var a=i[1],i=i[2]?i[2].replace(/^["']|["']$/g,""):"";t[a]=""===i?"true":i}return t}createInput(e,t,s,a){var i=h.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null==s&&(s=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":o=this.createHiddenInput(e,t,s);break;case"textarea":o=this.createTextarea(e,t,s);break;case"select":o=this.createSelect(e,t,s);break;case"checkbox":o=this.createCheckbox(e,t,s);break;case"radio":o=this.createRadioGroup(e,t,s);break;case"datalist":o=this.createDatalistInput(e,t,s);break;case"file":o=this.createFileInput(e,t,s);break;case"date":case"datetime-local":o=this.createDateInput(e,t,s);break;default:o=this.createTypedInput(e,t,s)}return"function"==typeof t.input?(a={field:t,record:this.currentFormRecord,inputField:o,formType:a},"string"==typeof(a=t.input(a))?i.innerHTML=a:a instanceof Node?i.appendChild(a):i.appendChild(o)):i.appendChild(o),t.explain&&h.create("div",{className:"ftable-field-explain",html:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(e,s,a){if("undefined"==typeof FDatepicker)return createTypedInput(e,s,a);{var i=s.dateFormat||this.options.defaultDateFormat,o=document.createElement("div"),r=h.create("input",{attributes:{id:"real-"+e,type:"hidden",value:a||"",name:e}});let t=h.create("input",{className:s.inputClass||"datepicker-input",attributes:{id:"Edit-"+e,type:"text","data-date":a,placeholder:s.placeholder||"",readOnly:!0}});s.inputAttributes&&Object.keys(s.inputAttributes).forEach(e=>{t.setAttribute(e,s.inputAttributes[e])}),o.appendChild(r),o.appendChild(t);new FDatepicker(t,{format:i,altField:"real-"+e,altFormat:"Y-m-d"});return o}}createTypedInput(e,t,s){var a,s={type:t.type||"text",id:"Edit-"+e,placeholder:t.placeholder||"",value:s||""};let i=e,o=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(s,a),void 0!==a.multiple&&!1!==a.multiple)&&(i=e+"[]"),s.name=i,h.create("input",{className:t.inputClass||"",attributes:s}));return o.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),o.dispatchEvent(new Event("change",{bubbles:!0})),!1}),o}createDatalistInput(e,t,s){s=h.create("input",{attributes:{type:"text",name:e,id:"Edit-"+e,placeholder:t.placeholder||"",value:s||"",class:t.inputClass||"",list:e+"-datalist"}}),e=h.create("datalist",{attributes:{id:e+"-datalist"}});return t.options&&this.populateDatalistOptions(e,t.options),document.body.appendChild(e),s.datalistElement=e,s}populateDatalistOptions(s,e){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{h.create("option",{attributes:{value:e.Value||e.value||e},text:e.DisplayText||e.text||e,parent:s})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{h.create("option",{attributes:{value:e},text:t,parent:s})})}createHiddenInput(e,t,s){e={type:"hidden",name:e,id:"Edit-"+e,value:s||""};return t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(e,s)),h.create("input",{attributes:e})}createTextarea(e,t,s){e={name:e,id:"Edit-"+e,class:t.inputClass||"",placeholder:t.placeholder||""},t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(e,t)),t=h.create("textarea",{attributes:e});return t.value=s||"",t}createSelect(e,t,s){var e={name:e,id:"Edit-"+e,class:t.inputClass||""},a=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(e,a)),h.create("select",{attributes:e}));return t.options&&this.populateSelectOptions(a,t.options,s),a}createRadioGroup(o,r,n){let l=h.create("div",{className:"ftable-radio-group"});return r.options&&(Array.isArray(r.options)?r.options:"object"==typeof r.options?Object.entries(r.options).map(([e,t])=>({Value:e,DisplayText:t})):[]).forEach((e,t)=>{var s=h.create("div",{className:"ftable-radio-wrapper",parent:l}),a=o+"_"+t,i={type:"radio",name:o,id:a,value:e.Value||e.value||e,class:r.inputClass||""},t=(r.required&&0===t&&(i.required="required"),r.disabled&&(i.disabled="disabled"),r.inputAttributes&&(t=this.parseInputAttributes(r.inputAttributes),Object.assign(attributes,t)),h.create("input",{attributes:i,parent:s}));i.value===n&&(t.checked=!0),h.create("label",{attributes:{for:a},text:e.DisplayText||e.text||e,parent:s})}),l}createCheckbox(e,t,s){var a=h.create("div",{className:"ftable-yesno-check-wrapper"}),s=[1,"1",!0,"true"].includes(s);let i="No",o="Yes";t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]);h.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),attributes:{type:"checkbox",name:e,id:"Edit-"+e,value:"1"},properties:{checked:s},parent:a}),h.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:a});return t.formText&&(h.create("span",{text:t.formText,parent:a}).style.marginLeft="8px"),a}populateSelectOptions(a,e,i){a.innerHTML="",Array.isArray(e)?e.forEach(e=>{var t=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let s=h.create("option",{attributes:{value:t},text:e.DisplayText||e.text||e,parent:a});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{s.setAttribute("data-"+e,t)}),s.value==i&&(s.selected=!0)}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{t=h.create("option",{attributes:{value:e},text:t,parent:a});e==i&&(t.selected=!0)})}createFileInput(e,t,s){var a={type:"file",id:"Edit-"+e,class:t.inputClass||""};let i=e;return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(a,t),void 0!==t.multiple&&!1!==t.multiple)&&(i=e+"[]"),a.name=i,h.create("input",{attributes:a})}}class r extends class{constructor(){this.events={}}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),this}once(t,s){let a=(...e)=>{this.off(t,a),s.apply(this,e)};return a.fn=s,this.on(t,a),this}emit(e,t={}){return this.events[e]&&this.events[e].forEach(e=>e(t)),this}off(e,t){return this.events[e]&&(this.events[e]=this.events[e].filter(e=>e!==t)),this}}{constructor(e,t={}){if(super(),this.element="string"==typeof e?document.querySelector(e):e,this.element){if(this.element.ftableInstance)return this.element.ftableInstance;this.options=this.mergeOptions(t),this.verifyOptions(),this.logger=new a(this.options.logLevel),this.userPrefs=new i("",this.options.saveUserPreferencesMethod),this.formBuilder=new o(this.options,this),this.state={records:[],totalRecordCount:0,currentPage:1,isLoading:!1,selectedRecords:new Set,sorting:[],searchQueries:{}},this.elements={},this.modals={},this.searchTimeout=null,this.lastSortEvent=null,this._recalculatedOnce=!1,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:a.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,animationsEnabled:!0,loadingAnimationDelay:1e3,defaultDateLocale:"",defaultDateFormat:"Y-m-d",saveUserPreferences:!0,saveUserPreferencesMethod:"localStorage",defaultSorting:"",tableReset:!1,paging:!1,pageList:"normal",pageSize:10,pageSizes:[10,25,50,100],gotoPageArea:"combobox",sorting:!1,multiSorting:!1,multiSortingCtrlKey:!0,selecting:!1,multiselect:!1,openChildAsAccordion:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...s}};return this.deepMerge(t,e)}deepMerge(e,t){var s,a={...e};for(s in t)t[s]&&"object"==typeof t[s]&&!Array.isArray(t[s])?a[s]=this.deepMerge(a[s]||{},t[s]):a[s]=t[s];return a}verifyOptions(){this.options.pageSize&&!this.options.pageSizes.includes(this.options.pageSize)&&(this.options.pageSize=this.options.pageSizes[0])}static setMessages(e){Object.assign(s,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAsyncFieldOptions().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.renderSortingInfo()}parseDefaultSorting(e){let o=[];return e&&"string"==typeof e&&e.split(",").forEach(s=>{s=s.trim();if(s){var a=s.toUpperCase().indexOf(" DESC"),i=s.toUpperCase().indexOf(" ASC");let e="ASC",t=s;e=0<a?(t=s.slice(0,a).trim(),"DESC"):(t=(0<i?s.slice(0,i):s).trim(),"ASC");a=this.options.fields[t];a&&!1!==a.sorting&&o.push({fieldName:t,direction:e})}}),o}addEssentialCSS(){var e;document.querySelector("#ftable-essential-css")||((e=document.createElement("style")).id="ftable-essential-css",e.textContent=`
1
+ ((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).FTable=t()})(this,function(){let s={serverCommunicationError:"An error occurred while communicating to the server.",loadingMessage:"Loading records...",noDataAvailable:"No data available!",addNewRecord:"Add new record",editRecord:"Edit record",areYouSure:"Are you sure?",deleteConfirmation:"This record will be deleted. Are you sure?",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",close:"Close",cannotLoadOptionsFor:"Cannot load options for field {0}!",pagingInfo:"Showing {0}-{1} of {2}",canNotDeletedRecords:"Can not delete {0} of {1} records!",deleteProgress:"Deleting {0} of {1} records, processing...",pageSizeChangeLabel:"Row count",gotoPageLabel:"Go to page",sortingInfoPrefix:"Sorting applied: ",sortingInfoSuffix:"",ascending:"Ascending",descending:"Descending",sortingInfoNone:"No sorting applied",resetSorting:"Reset sorting",csvExport:"CSV",printTable:"🖨️ Print",cloneRecord:"Clone Record",resetTable:"Reset table",resetTableConfirm:"This will reset all columns, pagesize, sorting to their defaults. Do you want to continue?",resetSearch:"Reset"};class t{constructor(){this.cache=new Map}generateKey(e,t){return e+"?"+Object.keys(t||{}).sort().map(e=>e+"="+t[e]).join("&")}get(e,t){e=this.generateKey(e,t);return this.cache.get(e)}set(e,t,s){e=this.generateKey(e,t);this.cache.set(e,s)}clear(e=null,t=null){if(e)if(t){t=this.generateKey(e,t);this.cache.delete(t)}else{var s,a=e.split("?")[0];for([s]of this.cache)s.startsWith(a)&&this.cache.delete(s)}else this.cache.clear()}size(){return this.cache.size}}class a{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=a.LOG_LEVELS.WARN){this.level=e}log(t,e){var s;!window.console||t<this.level||(s=Object.keys(a.LOG_LEVELS).find(e=>a.LOG_LEVELS[e]===t),console.log(`fTable ${s}: `+e))}debug(e){this.log(a.LOG_LEVELS.DEBUG,e)}info(e){this.log(a.LOG_LEVELS.INFO,e)}warn(e){this.log(a.LOG_LEVELS.WARN,e)}error(e){this.log(a.LOG_LEVELS.ERROR,e)}}class h{static create(e,t={}){let s=document.createElement(e);return t.className&&(s.className=t.className),t.style&&(s.style.cssText=t.style),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{s.setAttribute(e,t)}),t.text&&(s.textContent=t.text),t.html&&(s.innerHTML=t.html),t.parent&&t.parent.appendChild(s),s}static find(e,t=document){return t.querySelector(e)}static findAll(e,t=document){return Array.from(t.querySelectorAll(e))}static addClass(e,t){e.classList.add(...t.split(" "))}static removeClass(e,t){e.classList.remove(...t.split(" "))}static toggleClass(e,t){e.classList.toggle(t)}static show(e){e.style.display=""}static hide(e){e.style.display="none"}static escapeHtml(e){if(!e)return e;let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return e.replace(/[&<>"']/g,e=>t[e])}}class l{static async request(e,t={}){var s={method:"GET",headers:{}},a={...s,...t};t.headers&&(a.headers={...s.headers,...t.headers});try{var i=await fetch(e,a);if(401===i.status)throw new Error("Unauthorized");if(!i.ok)throw new Error("HTTP error! status: "+i.status);var o=i.headers.get("content-type");if(o&&o.includes("application/json"))return await i.json();var r=await i.text();try{return JSON.parse(r)}catch{return{Result:"OK",Message:r}}}catch(e){throw e}}static async get(e,t={}){let a=new URL(e,window.location.href);return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.replace(/\[\]$/,"")+"[]";s.forEach(e=>{null!=e&&a.searchParams.append(t,e)})}else a.searchParams.append(e,s)}),this.request(a.toString(),{method:"GET",headers:{"Content-Type":"application/x-www-form-urlencoded"}})}static async post(e,t={}){e=new URL(e,window.location.href);let a=new FormData;return Object.entries(t).forEach(([e,s])=>{if(null!=s)if(Array.isArray(s)){let t=e.replace(/\[\]$/,"")+"[]";s.forEach(e=>{null!=e&&a.append(t,e)})}else a.append(e,s)}),this.request(e.toString(),{method:"POST",body:a})}}class i{constructor(e,t="localStorage"){this.prefix=e,this.method=t}set(e,t){var s,e=""+this.prefix+e;"localStorage"===this.method?localStorage.setItem(e,t):((s=new Date).setDate(s.getDate()+30),document.cookie=e+`=${t}; expires=${s.toUTCString()}; path=/`)}get(e){e=""+this.prefix+e;if("localStorage"===this.method)return localStorage.getItem(e);var t,s=e+"=";for(t of decodeURIComponent(document.cookie).split(";")){for(;" "===t.charAt(0);)t=t.substring(1);if(0===t.indexOf(s))return t.substring(s.length,t.length)}return null}remove(e){e=""+this.prefix+e;"localStorage"===this.method?localStorage.removeItem(e):document.cookie=e+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"}generatePrefix(e,t){e=e?e+"#":"";return"ftable#"+(t=>{let s=0;if(0!==t.length)for(let e=0;e<t.length;e++){var a=t.charCodeAt(e);s=(s<<5)-s+a,s&=s}return s})(e+=t.join("$")+"#c"+t.length)}}class e{constructor(e={}){this.options={title:"Modal",content:"",buttons:[],className:"ftable-modal",parent:document.body,...e},this.overlay=null,this.modal=null,this.isOpen=!1}create(){this.overlay=h.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=h.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});h.create("h2",{className:"ftable-modal-header",text:this.options.title,parent:this.modal});h.create("span",{className:"ftable-modal-close",html:"&times;",parent:this.modal}).addEventListener("click",()=>this.close());var e=h.create("div",{className:"ftable-modal-body",parent:this.modal});if("string"==typeof this.options.content?e.innerHTML=this.options.content:e.appendChild(this.options.content),0<this.options.buttons.length){let s=h.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=h.create("button",{className:"ftable-dialog-button "+(e.className||""),html:`<span>${e.text}</span>`,parent:s});e.onClick&&t.addEventListener("click",e.onClick)})}return this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.hide(),this}show(){return this.modal||this.create(),this.overlay.style.display="flex",this.isOpen=!0,this}hide(){return this.overlay&&(this.overlay.style.display="none"),this.isOpen=!1,this}close(){return this.hide(),this.options.onClose&&this.options.onClose(),this}destroy(){return this.overlay&&this.overlay.remove(),this.isOpen=!1,this}setContent(e){this.options.content=e;var t=this.modal.querySelector(".ftable-modal-body");t&&(t.innerHTML="","string"==typeof e?t.innerHTML=e:t.appendChild(e))}}class o{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t,this.originalFieldOptions=new Map}storeOriginalFieldOptions(){0<this.originalFieldOptions.size||Object.entries(this.options.fields).forEach(([e,t])=>{!t.options||"function"!=typeof t.options&&"string"!=typeof t.options||this.originalFieldOptions.set(e,t.options)})}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,s,a){var i=h.create("div",{className:"ftable-input-field-container",attributes:{id:"ftable-input-field-container-div-"+e}}),t=(h.create("div",{className:"ftable-input-label",text:t.inputTitle||t.title,parent:i}),this.createInput(e,t,s[e],a));return i.appendChild(t),i}async resolveNonDependantFieldOptions(r){this.storeOriginalFieldOptions();var e=Object.entries(this.options.fields).map(async([t,e])=>{if(!e.dependsOn){var s=this.originalFieldOptions.get(t)||e.options;if(s&&("function"==typeof s||"string"==typeof s))try{var a={dependedValues:r},i={...e,options:s},o=await this.resolveOptions(i,a);e.options=o}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}});await Promise.all(e)}async createForm(s="create",a={}){this.currentFormRecord=a,await this.resolveNonDependantFieldOptions(a);let i=h.create("form",{className:`ftable-dialog-form ftable-${s}-form`});return this.buildDependencyMap(),Object.entries(this.options.fields).forEach(([e,t])=>{this.shouldIncludeField(t,s)&&(e=this.createFieldContainer(e,t,a,s),i.appendChild(e))}),this.setupDependencyListeners(i),i}buildDependencyMap(){this.dependencies.clear(),Object.entries(this.options.fields).forEach(([t,s])=>{if(s.dependsOn){let e;"string"==typeof s.dependsOn&&(e=s.dependsOn.split(",").map(e=>e.trim()).filter(e=>e)).forEach(e=>{this.dependencies.has(e)||this.dependencies.set(e,[]),this.dependencies.get(e).push(t)})}})}setupDependencyListeners(s){Array.from(this.dependencies.keys()).forEach(e=>{var t=s.querySelector(`[name="${e}"]`);t&&t.addEventListener("change",()=>{this.handleDependencyChange(s,e)})}),this.handleDependencyChange(s)}async resolveOptions(t,e={}){if(!t.options)return[];if(Array.isArray(t.options)||"object"==typeof t.options)return t.options;let s,a=!1;e={...e,clearCache:()=>{a=!0}};if("function"==typeof t.options)s=await t.options(e);else{if("string"!=typeof t.options)return[];s=t.options}e=s&&"object"==typeof s&&s.url,t=e?s.url:s;if(a=e&&void 0!==s.noCache?s.noCache:a,"string"!=typeof t)return[];if(!a){e=this.optionsCache.get(t,{});if(e)return e}try{var i=this.options.forcePost?await l.post(t):await l.get(t),o=i.Options||i.options||i||[];return a||this.optionsCache.set(t,{},o),o}catch(e){return console.error(`Failed to load options from ${t}:`,e),[]}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}async handleDependencyChange(e,t=""){var s,a,i={};for([s,a]of Object.entries(this.options.fields)){var o=e.querySelector(`[name="${s}"]`);o&&("checkbox"===o.type?i[s]=o.checked?"1":"0":i[s]=o.value)}var r,n,l=e.classList.contains("ftable-create-form")?"create":"edit",c={record:this.currentFormRecord||{},source:l,form:e,dependedValues:i};for([r,n]of Object.entries(this.options.fields))if(n.dependsOn){if(""!==t)if(!n.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(t))continue;var d=e.querySelector(`[name="${r}"]`);if(d&&this.shouldIncludeField(n,l))try{"SELECT"===d.tagName?d.innerHTML='<option value="">Loading...</option>':"INPUT"===d.tagName&&d.list&&(h=document.getElementById(d.list.id))&&(h.innerHTML="");var h,p={...c,dependsOnField:n.dependsOn,dependsOnValue:i[n.dependsOn]},m=this.originalFieldOptions.get(r)||n.options,u={...n,options:m},f=await this.resolveOptions(u,p);"SELECT"===d.tagName?this.populateSelectOptions(d,f,""):"INPUT"===d.tagName&&d.list&&this.populateDatalistOptions(d.list,f)}catch(e){console.error(`Error loading options for ${r}:`,e),"SELECT"===d.tagName&&(d.innerHTML='<option value="">Error</option>')}}}parseInputAttributes(e){if("string"!=typeof e)return e||{};for(var t={},s=/(\w+)(?:=("[^"]*"|'[^']*'|\S+))?/g;null!==(i=s.exec(e));){var a=i[1],i=i[2]?i[2].replace(/^["']|["']$/g,""):"";t[a]=""===i?"true":i}return t}createInput(e,t,s,a){var i=h.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null==s&&(s=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":o=this.createHiddenInput(e,t,s);break;case"textarea":o=this.createTextarea(e,t,s);break;case"select":o=this.createSelect(e,t,s);break;case"checkbox":o=this.createCheckbox(e,t,s);break;case"radio":o=this.createRadioGroup(e,t,s);break;case"datalist":o=this.createDatalistInput(e,t,s);break;case"file":o=this.createFileInput(e,t,s);break;case"date":case"datetime-local":o=this.createDateInput(e,t,s);break;default:o=this.createTypedInput(e,t,s)}return"function"==typeof t.input?(a={field:t,record:this.currentFormRecord,inputField:o,formType:a},"string"==typeof(a=t.input(a))?i.innerHTML=a:a instanceof Node?i.appendChild(a):i.appendChild(o)):i.appendChild(o),t.explain&&h.create("div",{className:"ftable-field-explain",html:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(e,s,a){if("undefined"==typeof FDatepicker)return createTypedInput(e,s,a);{var i=s.dateFormat||this.options.defaultDateFormat,o=document.createElement("div"),r=h.create("input",{attributes:{id:"real-"+e,type:"hidden",value:a||"",name:e}});let t=h.create("input",{className:s.inputClass||"datepicker-input",attributes:{id:"Edit-"+e,type:"text","data-date":a,placeholder:s.placeholder||"",readOnly:!0}});s.inputAttributes&&Object.keys(s.inputAttributes).forEach(e=>{t.setAttribute(e,s.inputAttributes[e])}),o.appendChild(r),o.appendChild(t);new FDatepicker(t,{format:i,altField:"real-"+e,altFormat:"Y-m-d"});return o}}createTypedInput(e,t,s){var a,s={type:t.type||"text",id:"Edit-"+e,placeholder:t.placeholder||"",value:s||""};let i=e,o=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(s,a),void 0!==a.multiple&&!1!==a.multiple)&&(i=e+"[]"),s.name=i,h.create("input",{className:t.inputClass||"",attributes:s}));return o.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),o.dispatchEvent(new Event("change",{bubbles:!0})),!1}),o}createDatalistInput(e,t,s){s=h.create("input",{attributes:{type:"text",name:e,id:"Edit-"+e,placeholder:t.placeholder||"",value:s||"",class:t.inputClass||"",list:e+"-datalist"}}),e=h.create("datalist",{attributes:{id:e+"-datalist"}});return t.options&&this.populateDatalistOptions(e,t.options),document.body.appendChild(e),s.datalistElement=e,s}populateDatalistOptions(s,e){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{h.create("option",{attributes:{value:e.Value||e.value||e},text:e.DisplayText||e.text||e,parent:s})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{h.create("option",{attributes:{value:e},text:t,parent:s})})}createHiddenInput(e,t,s){e={type:"hidden",name:e,id:"Edit-"+e,value:s||""};return t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(e,s)),h.create("input",{attributes:e})}createTextarea(e,t,s){e={name:e,id:"Edit-"+e,class:t.inputClass||"",placeholder:t.placeholder||""},t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(e,t)),t=h.create("textarea",{attributes:e});return t.value=s||"",t}createSelect(e,t,s){var e={name:e,id:"Edit-"+e,class:t.inputClass||""},a=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(e,a)),h.create("select",{attributes:e}));return t.options&&this.populateSelectOptions(a,t.options,s),a}createRadioGroup(o,r,n){let l=h.create("div",{className:"ftable-radio-group"});return r.options&&(Array.isArray(r.options)?r.options:"object"==typeof r.options?Object.entries(r.options).map(([e,t])=>({Value:e,DisplayText:t})):[]).forEach((e,t)=>{var s=h.create("div",{className:"ftable-radio-wrapper",parent:l}),a=o+"_"+t,i={type:"radio",name:o,id:a,value:e.Value||e.value||e,class:r.inputClass||""},t=(r.required&&0===t&&(i.required="required"),r.disabled&&(i.disabled="disabled"),r.inputAttributes&&(t=this.parseInputAttributes(r.inputAttributes),Object.assign(attributes,t)),h.create("input",{attributes:i,parent:s}));i.value===n&&(t.checked=!0),h.create("label",{attributes:{for:a},text:e.DisplayText||e.text||e,parent:s})}),l}createCheckbox(e,t,s){var a=h.create("div",{className:"ftable-yesno-check-wrapper"}),s=[1,"1",!0,"true"].includes(s);let i="No",o="Yes";t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]);h.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),attributes:{type:"checkbox",name:e,id:"Edit-"+e,value:"1"},properties:{checked:s},parent:a}),h.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:a});return t.formText&&(h.create("span",{text:t.formText,parent:a}).style.marginLeft="8px"),a}populateSelectOptions(a,e,i){a.innerHTML="",Array.isArray(e)?e.forEach(e=>{var t=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let s=h.create("option",{attributes:{value:t},text:e.DisplayText||e.text||e,parent:a});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{s.setAttribute("data-"+e,t)}),s.value==i&&(s.selected=!0)}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{t=h.create("option",{attributes:{value:e},text:t,parent:a});e==i&&(t.selected=!0)})}createFileInput(e,t,s){var a={type:"file",id:"Edit-"+e,class:t.inputClass||""};let i=e;return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(a,t),void 0!==t.multiple&&!1!==t.multiple)&&(i=e+"[]"),a.name=i,h.create("input",{attributes:a})}}class r extends class{constructor(){this.events={}}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),this}once(t,s){let a=(...e)=>{this.off(t,a),s.apply(this,e)};return a.fn=s,this.on(t,a),this}emit(e,t={}){return this.events[e]&&this.events[e].forEach(e=>e(t)),this}off(e,t){return this.events[e]&&(this.events[e]=this.events[e].filter(e=>e!==t)),this}}{constructor(e,t={}){if(super(),this.element="string"==typeof e?document.querySelector(e):e,this.element){if(this.element.ftableInstance)return this.element.ftableInstance;this.options=this.mergeOptions(t),this.verifyOptions(),this.logger=new a(this.options.logLevel),this.userPrefs=new i("",this.options.saveUserPreferencesMethod),this.formBuilder=new o(this.options,this),this.state={records:[],totalRecordCount:0,currentPage:1,isLoading:!1,selectedRecords:new Set,sorting:[],searchQueries:{}},this.elements={},this.modals={},this.searchTimeout=null,this.lastSortEvent=null,this._recalculatedOnce=!1,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:a.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,animationsEnabled:!0,loadingAnimationDelay:1e3,defaultDateLocale:"",defaultDateFormat:"Y-m-d",saveUserPreferences:!0,saveUserPreferencesMethod:"localStorage",defaultSorting:"",tableReset:!1,paging:!1,pageList:"normal",pageSize:10,pageSizes:[10,25,50,100],gotoPageArea:"combobox",sorting:!1,multiSorting:!1,multiSortingCtrlKey:!0,selecting:!1,multiselect:!1,openChildAsAccordion:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...s}};return this.deepMerge(t,e)}deepMerge(e,t){var s,a={...e};for(s in t)t[s]&&"object"==typeof t[s]&&!Array.isArray(t[s])?a[s]=this.deepMerge(a[s]||{},t[s]):a[s]=t[s];return a}verifyOptions(){this.options.pageSize&&!this.options.pageSizes.includes(this.options.pageSize)&&(this.options.pageSize=this.options.pageSizes[0])}static setMessages(e){Object.assign(s,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAsyncFieldOptions().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.renderSortingInfo()}parseDefaultSorting(e){let o=[];return e&&"string"==typeof e&&e.split(",").forEach(s=>{s=s.trim();if(s){var a=s.toUpperCase().indexOf(" DESC"),i=s.toUpperCase().indexOf(" ASC");let e="ASC",t=s;e=0<a?(t=s.slice(0,a).trim(),"DESC"):(t=(0<i?s.slice(0,i):s).trim(),"ASC");a=this.options.fields[t];a&&!1!==a.sorting&&o.push({fieldName:t,direction:e})}}),o}addEssentialCSS(){var e;document.querySelector("#ftable-essential-css")||((e=document.createElement("style")).id="ftable-essential-css",e.textContent=`
2
2
  .ftable-row-animation {
3
3
  transition: background-color 0.3s ease;
4
4
  }
@@ -20,7 +20,7 @@
20
20
  .ftable-toolbarsearch {
21
21
  width: 90%;
22
22
  }
23
- `,document.head.appendChild(e))}createPagingUI(){this.elements.bottomPanel=h.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=h.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=h.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=h.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=h.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=h.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=h.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});h.create("span",{text:this.options.messages.pageSizeChangeLabel,parent:e});let s=h.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100]).forEach(e=>{var t=h.create("option",{attributes:{value:e},text:e.toString(),parent:s});e===this.state.pageSize&&(t.selected=!0)}),s.addEventListener("change",e=>{this.changePageSize(parseInt(e.target.value))})}processFieldDefinitions(){this.fieldList=Object.keys(this.options.fields),this.fieldList.forEach(e=>{e=this.options.fields[e];!0===e.key?(void 0!==e.create&&e.create||(e.create=!0,e.type="hidden"),void 0!==e.edit&&e.edit||(e.edit=!0,e.type="hidden"),e.hasOwnProperty("visibility")||(e.visibility="hidden")):(void 0===e.create&&(e.create=!0),void 0===e.edit&&(e.edit=!0),void 0===e.list&&(e.list=!0),void 0===e.sorting&&(e.sorting=!0),e.hasOwnProperty("visibility")||(e.visibility="visible"))}),this.columnList=this.fieldList.filter(e=>!1!==this.options.fields[e].list),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.warn("No key field defined")}async resolveAsyncFieldOptions(){this.formBuilder.storeOriginalFieldOptions();for(var t of this.columnList){var e=this.options.fields[t],s=this.formBuilder.originalFieldOptions.get(t)||e.options;if(s&&("function"==typeof s||"string"==typeof s)&&!Array.isArray(s)&&("object"!=typeof s||Array.isArray(s)||!(0<Object.keys(s).length)))try{var a={...e,options:s},i=await this.formBuilder.resolveOptions(a);e.options=i}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}}refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");0!==e.length&&e.forEach(a=>{this.columnList.forEach(e=>{var t,s=this.options.fields[e];s.options&&"function"!=typeof s.options&&"string"!=typeof s.options&&(t=a.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(a.recordData,e),t.innerHTML=s.listEscapeHTML?h.escapeHtml(e):e)})})}createMainStructure(){this.elements.mainContainer=h.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=h.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),h.create("div",{className:"ftable-title-text",text:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=h.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=h.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=h.create("table",{className:"ftable",parent:this.elements.tableDiv}),this.options.tableId&&(this.elements.table.id=this.options.tableId),this.createTableHeader(),this.createTableBody(),this.addNoDataRow()}createTableHeader(){var e=h.create("thead",{parent:this.elements.table});let i=h.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes){var t=h.create("th",{className:"ftable-column-header ftable-column-header-select",parent:i});if(this.options.multiselect){let e=h.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var e=this.options.fields[t],s=h.create("th",{className:`ftable-column-header ${e.listClass||""} `+(e.listClassHeader||""),attributes:{"data-field-name":t},parent:i}),a=(e.width&&(s.style.width=e.width),h.create("div",{className:"ftable-column-header-container",parent:s}));e.tooltip&&a.setAttribute("title",e.tooltip),h.create("span",{className:"ftable-column-header-text",text:e.title||t,parent:a}),this.options.sorting&&!1!==e.sorting&&(h.addClass(s,"ftable-column-header-sortable"),s.addEventListener("click",e=>{e.preventDefault(),this.lastSortEvent=e,this.sortByColumn(t)})),!1!==this.options.columnResizable&&!1!==e.columnResizable&&this.makeColumnResizable(s,a),"hidden"===e.visibility&&h.hide(s)}),this.options.actions.updateAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:i}),this.options.actions.cloneAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:i}),this.options.actions.deleteAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:i}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,s,a=h.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&h.create("th",{parent:a});for(t of this.columnList){var i=this.options.fields[t],o=!1!==i.searchable,r=h.create("th",{className:"ftable-toolbarsearch-column-header",parent:a});if(o){o=h.create("div",{className:"ftable-column-header-container",parent:r});let e;!i.type&&i.options&&(i.type="select");var n,l,c,d="ftable-toolbarsearch-"+t;switch(i.type){case"date":case"datetime-local":"undefined"!=typeof FDatepicker?(n=i.dateFormat||this.options.defaultDateFormat,e=document.createElement("div"),l=h.create("input",{className:"ftable-toolbarsearch-extra",attributes:{type:"hidden","data-field-name":t,id:"ftable-toolbarsearch-extra-"+t}}),c=h.create("input",{className:"ftable-toolbarsearch",attributes:{id:"ftable-toolbarsearch-"+t,type:"text",placeholder:i.placeholder||"",readOnly:!0}}),e.appendChild(l),e.appendChild(c),new FDatepicker(c,{format:n,altField:"ftable-toolbarsearch-extra-"+t,altFormat:"Y-m-d"})):e=h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"date","data-field-name":t,id:d}});break;case"checkbox":e=i.values?await this.createSelectForSearch(t,i,!0):h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}});break;case"select":e=i.options?await this.createSelectForSearch(t,i,!1):h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}});break;default:e=h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}})}e&&(o.appendChild(e),"SELECT"===e.tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)}))}"hidden"===i.visibility&&h.hide(r)}this.options.toolbarsearch&&this.options.toolbarreset&&(e=h.create("th",{className:"ftable-toolbarsearch-reset",parent:a}),0<(s=(this.options.actions.updateAction?1:0)+(this.options.actions.deleteAction?1:0))?e.colSpan=s:h.addClass(e,"ftable-command-column-header"),h.create("button",{className:"ftable-toolbarsearch-reset-button",text:this.options.messages.resetSearch,parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,s){var a="ftable-toolbarsearch-"+e;let i=h.create("select",{attributes:{"data-field-name":e,id:a,class:"ftable-toolbarsearch"}}),o;return s&&t.values?o=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):t.options&&(o=await this.formBuilder.resolveOptions(t)),0<o?.length&&(""===o[0].Value||""===o[0].value||""===o[0]||""===o[0].DisplayText&&null==o[0].Value)||h.create("option",{attributes:{value:""},text:"",parent:i}),o&&Array.isArray(o)?o.forEach(e=>{h.create("option",{attributes:{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e},text:e.DisplayText||e.text||e,parent:i})}):o&&"object"==typeof o&&Object.entries(o).forEach(([e,t])=>{h.create("option",{attributes:{value:e},text:t,parent:i})}),i}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name"),e=e.value.trim();e?this.state.searchQueries[t]=e:delete this.state.searchQueries[t],clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.load()},this.options.searchDebounceMs)}resetSearch(){this.state.searchQueries={},this.elements.table.querySelectorAll(".ftable-toolbarsearch").forEach(e=>{"SELECT"===e.tagName?e.selectedIndex=0:e.value=""}),this.load()}makeColumnResizable(s,e){this.elements.resizeBar||(this.elements.resizeBar=h.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),h.hide(this.elements.resizeBar));e=h.create("div",{className:"ftable-column-resize-handler",parent:e});let a=!1,i=0,o=0,r=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),a=!0,i=e.clientX,o=s.offsetWidth;var e=s.getBoundingClientRect(),t=this.elements.mainContainer.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-t.left+"px",this.elements.resizeBar.style.top=e.top-t.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",h.show(this.elements.resizeBar),document.addEventListener("mousemove",r),document.addEventListener("mouseup",n)}),e=>{var t;a&&(t=e.clientX-i,Math.max(50,o+t),t=this.elements.mainContainer.getBoundingClientRect(),this.elements.resizeBar.style.left=e.clientX-t.left+"px")}),n=e=>{a&&(a=!1,e=e.clientX-i,e=Math.max(50,o+e),s.style.width=e+"px",h.hide(this.elements.resizeBar),document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",n),this.options.saveUserPreferences)&&this.saveColumnSettings()}}saveColumnSettings(){if(this.options.saveUserPreferences){let a={};this.columnList.forEach(e=>{var t,s=this.elements.table.querySelector(`[data-field-name="${e}"]`);s&&(t=this.options.fields[e],a[e]={width:s.style.width||t.width||"auto",visibility:t.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(a))}}saveState(){var e;this.options.saveUserPreferences&&(e={sorting:this.state.sorting,pageSize:this.state.pageSize},this.userPrefs.set("table-state",JSON.stringify(e)))}loadColumnSettings(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("column-settings");if(e)try{var t=JSON.parse(e);Object.entries(t).forEach(([e,t])=>{e=this.options.fields[e];e&&(t.width&&(e.width=t.width),t.visibility)&&(e.visibility=t.visibility)})}catch(e){this.logger.warn("Failed to load column settings:",e)}}}loadState(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("table-state");if(e)try{var t=JSON.parse(e);Array.isArray(t.sorting)&&(this.state.sorting=t.sorting),t.pageSize&&this.options.pageSizes.includes(t.pageSize)&&(this.state.pageSize=t.pageSize)}catch(e){this.logger.warn("Failed to load table state:",e)}}}createTableBody(){this.elements.tableBody=h.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=h.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,h.create("td",{attributes:{colspan:t},text:this.options.messages.noDataAvailable,parent:e}))}removeNoDataRow(){var e=this.elements.tableBody.querySelector(".ftable-no-data-row");e&&e.remove()}createModals(){this.options.actions.createAction&&this.createAddRecordModal(),this.options.actions.updateAction&&this.createEditRecordModal(),this.options.actions.deleteAction&&this.createDeleteConfirmModal(),this.createErrorModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new e({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null})}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new e({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.modals.editRecord.close()}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new e({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>this.modals.deleteConfirm.close()},{text:this.options.messages.deleteText,className:"ftable-dialog-deletebutton",onClick:()=>this.confirmDelete()}]})}createErrorModal(){this.modals.error=new e({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createInfoModal(){this.modals.info=new e({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new e({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",content:`<div class="ftable-loading-message">${this.options.messages.loadingMessage}</div>`})}bindEvents(){this.subscribeOptionEvents(),this.createToolbarButtons(),this.createCustomToolbarItems(),this.bindKeyboardEvents(),!1!==this.options.columnSelectable&&this.createColumnSelectionMenu()}subscribeOptionEvents(){["formCreated","formClosed","recordsLoaded","recordAdded","recordUpdated","recordDeleted","selectionChanged"].forEach(e=>{"function"==typeof this.options[e]&&this.on(e,this.options[e])})}createColumnSelectionMenu(){this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null,this.elements.table.querySelector("thead").addEventListener("contextmenu",e=>{e.preventDefault(),this.showColumnSelectionMenu(e)})}showColumnSelectionMenu(e){this.hideColumnSelectionMenu(),this.elements.columnSelectionOverlay=h.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=h.create("div",{className:"ftable-column-selection-container",parent:document.body}),this.populateColumnSelectionMenu(),this.positionColumnSelectionMenu(e),this.elements.columnSelectionOverlay.addEventListener("click",e=>{e.target===this.elements.columnSelectionOverlay&&this.hideColumnSelectionMenu()}),this.elements.columnSelectionOverlay.addEventListener("contextmenu",e=>{e.preventDefault(),this.hideColumnSelectionMenu()})}populateColumnSelectionMenu(){let l=h.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(e=>{var t=this.options.fields[e],s="hidden"!==t.visibility,a="fixed"===t.visibility,i=this.isFieldSorted(e),o=h.create("li",{className:"ftable-column-select-item",parent:l}),r=h.create("label",{className:"ftable-column-select-label",parent:o});let n=h.create("input",{attributes:{type:"checkbox",id:"column-"+e},parent:r});n.checked=s,(a||i&&s)&&(n.disabled=!0,o.style.opacity="0.6");a=h.create("span",{text:t.title||e,parent:r});i&&((s=h.create("span",{className:"ftable-sort-indicator",text:" (sorted)",parent:a})).style.fontSize="0.8em",s.style.color="#666"),n.disabled||n.addEventListener("change",()=>{this.setColumnVisibility(e,n.checked)})})}positionColumnSelectionMenu(e){var t=this,s=e.pageX,e=e.pageY,e=(t.elements.columnSelectionMenu.style.position="absolute",t.elements.columnSelectionMenu.style.left=s+"px",t.elements.columnSelectionMenu.style.top=e+"px",t.elements.columnSelectionMenu.style.minWidth="100px",t.elements.columnSelectionMenu.style.boxSizing="border-box",t.elements.columnSelectionMenu.offsetWidth),a=window.innerWidth;a<s+e&&(s=Math.max(10,a-e-10),t.elements.columnSelectionMenu.style.left=s+"px")}hideColumnSelectionMenu(){this.elements.columnSelectionOverlay&&(this.elements.columnSelectionOverlay.remove(),this.elements.columnSelectionMenu.remove(),this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null)}isFieldSorted(t){return this.state.sorting.some(e=>e.fieldName===t)}createToolbarButtons(){this.options.csvExport&&this.addToolbarButton({text:this.options.messages.csvExport,className:"ftable-toolbar-item-csv",onClick:()=>{var e=this.options.title?this.options.title.replace(/[^a-z0-9]/gi,"-").toLowerCase()+".csv":"table-export.csv";this.exportToCSV(e)}}),this.options.printTable&&this.addToolbarButton({text:this.options.messages.printTable,className:"ftable-toolbar-item-print",onClick:()=>{this.printTable()}}),this.options.actions.createAction&&this.addToolbarButton({text:this.options.messages.addNewRecord,className:"ftable-toolbar-item-add-record",addIconSpan:!0,onClick:()=>this.showAddRecordForm()})}addToolbarButton(e){var t=h.create("span",{className:"ftable-toolbar-item "+(e.className||""),parent:this.elements.toolbarDiv});if(e.addIconSpan)h.create("span",{className:"ftable-toolbar-item-icon "+(e.className||""),parent:t});let s=h.create("span",{className:"ftable-toolbar-item-text "+(e.className||""),text:e.text,parent:t});return e.onClick&&t.addEventListener("click",e.onClick),t}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach(t=>{var e=h.create("button",{className:"ftable-toolbar-item ftable-toolbar-item-custom "+(t.buttonClass||""),parent:this.elements.toolbarDiv});t.tooltip&&e.setAttribute("title",t.tooltip),t.icon&&h.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:e}),t.text&&h.create("span",{text:t.text,parent:e}),"function"==typeof t.click&&e.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.click()})})}bindKeyboardEvents(){this.options.selecting&&(this.shiftKeyDown=!1,document.addEventListener("keydown",e=>{"Shift"===e.key&&(this.shiftKeyDown=!0)}),document.addEventListener("keyup",e=>{"Shift"===e.key&&(this.shiftKeyDown=!1)}))}setupFTableUserPreferences(){var e;this.options.saveUserPreferences&&(e=this.userPrefs.generatePrefix(this.options.tableId||"",this.fieldList),this.userPrefs=new i(e,this.options.saveUserPreferencesMethod),this.loadState(),this.loadColumnSettings())}async load(e={}){if(!this.state.isLoading){this.state.isLoading=!0,this.showLoadingIndicator();try{var t={...e,...this.buildLoadParams()},s=await this.performLoad(t);this.processLoadedData(s),this.emit("recordsLoaded",{records:s.Records,serverResponse:s})}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Load failed: "+e.message)}finally{this.state.isLoading=!1,this.hideLoadingIndicator()}this.renderSortingInfo()}}buildLoadParams(){var e,t={};if(this.options.paging&&(this.state.pageSize||(this.state.pageSize=this.options.pageSize),t.jtStartIndex=(this.state.currentPage-1)*this.state.pageSize,t.jtPageSize=this.state.pageSize),this.options.sorting&&(0<this.state.sorting.length?t.jtSorting=this.state.sorting.map(e=>e.fieldName+" "+e.direction).join(", "):this.options.defaultSorting&&(t.jtSorting=this.parseDefaultSorting(this.options.defaultSorting).map(e=>e.fieldName+" "+e.direction).join(", "))),this.options.toolbarsearch&&0<Object.keys(this.state.searchQueries).length){let s=[],a=[];Object.entries(this.state.searchQueries).forEach(([e,t])=>{""!==t&&(s.push(t),a.push(e))}),0<s.length&&(t.q=s,t.opt=a)}return"function"==typeof this.options.listQueryParams&&(e=this.options.listQueryParams(),Object.assign(t,e)),t}isCacheExpired(e,t){return!e||!e.timestamp||t<Date.now()-e.timestamp}async performLoad(e){var t=this.options.actions.listAction;if(this.options.listCache&&"string"==typeof t){var s=this.formBuilder.optionsCache.get(t,e);if(s&&!this.isCacheExpired(s,this.options.listCache))return s.data}let a;if("function"==typeof t)a=await t(e);else{if("string"!=typeof t)throw new Error("No valid listAction provided");a=this.options.forcePost?await l.post(t,e):await l.get(t,e)}if(a&&"OK"===a.Result)return this.options.listCache&&"string"==typeof t&&this.formBuilder.optionsCache.set(t,e,{data:a,timestamp:Date.now()}),a;throw new Error(a?.Message||"Invalid response from server")}processLoadedData(e){"OK"!==e.Result?this.showError(e.Message||"Unknown error occurred"):(this.state.records=e.Records||[],this.state.totalRecordCount=e.TotalRecordCount||this.state.records.length,this.renderTableData(),this.updatePagingInfo())}renderTableData(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>e.remove()),0===this.state.records.length?this.addNoDataRow():(this.removeNoDataRow(),this.state.records.forEach(e=>{e=this.createTableRow(e);this.elements.tableBody.appendChild(e)}),this.refreshRowStyles(),this.refreshDisplayValues())}createTableRow(t){let s=h.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(t)}}),e=(s.recordData=t,this.options.selecting&&this.options.selectingCheckboxes&&this.addSelectingCell(s),this.columnList.forEach(e=>{this.addDataCell(s,t,e)}),0);return this.options.actions.updateAction&&(this.addEditCell(s),e++),this.options.actions.cloneAction&&(this.addCloneCell(s),e++),this.options.actions.deleteAction&&(this.addDeleteCell(s),e++),this.options.selecting&&this.makeRowSelectable(s),s}addSelectingCell(e){var t=h.create("td",{className:"ftable-command-column ftable-selecting-column",parent:e});h.create("input",{attributes:{type:"checkbox"},parent:t}).addEventListener("change",()=>{this.toggleRowSelection(e)})}addDataCell(e,t,s){var a=this.options.fields[s],t=this.getDisplayText(t,s),t=h.create("td",{className:`${a.listClass||""} `+(a.listClassEntry||""),html:a.listEscapeHTML?h.escapeHtml(t):t,attributes:{"data-field-name":s},parent:e});"fixed"!==a.visibility&&"hidden"===a.visibility&&h.hide(t)}addEditCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},html:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},html:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},html:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t){var s=this.options.fields[t],a=e[t];return s.display&&"function"==typeof s.display?s.display({record:e}):"date"===s.type&&a?"undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(a),s.dateFormat||this.options.defaultDateFormat):this.formatDate(a,s.dateLocale||this.options.defaultDateLocale):"datetime-local"===s.type&&a?"undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(a),s.dateFormat||this.options.defaultDateFormat):this.formatDateTime(a,s.dateLocale||this.options.defaultDateLocale):"checkbox"===s.type?this.getCheckboxText(t,a):s.options?(e=this.findOptionByValue(s.options,a))?e.DisplayText||e.text||e:a:a||""}_parseDate(e){return e.includes("Date")?new Date(parseInt(e.substr(6),10)):10==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10)):19==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10),parseInt(e.substr(11,2),10),parseInt(e.substr(14,2),10),parseInt(e.substr(17,2),10)):new Date(e)}formatDate(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleDateString(t,{year:"numeric",month:"2-digit",day:"2-digit"})}catch{return e}}formatDateTime(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleString(t)}catch{return e}}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?"Yes":"No"}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?h.addClass(e,"ftable-row-even"):h.removeClass(e,"ftable-row-even")})}getKeyValue(e){return this.keyField?e[this.keyField]:null}async showAddRecordForm(){var e=await this.formBuilder.createForm("create");this.modals.addRecord.setContent(e),this.modals.addRecord.show(),this.currentForm=e,this.emit("formCreated",{form:e,formType:"create",record:null})}async saveNewRecord(){if(this.currentForm)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performCreate(e);"OK"===t.Result?(this.clearListCache(),this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),t.Message&&this.showInfo(t.Message),await this.load(),this.emit("recordAdded",{record:t.Record})):this.showError(t.Message||"Create failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Create failed: "+e.message)}}else this.currentForm.reportValidity()}async editRecord(e){var t=e.recordData,s=await this.formBuilder.createForm("edit",t);this.modals.editRecord.setContent(s),this.modals.editRecord.show(),this.currentForm=s,this.currentEditingRow=e,this.emit("formCreated",{form:s,formType:"edit",record:t})}async saveEditedRecord(){if(this.currentForm&&this.currentEditingRow)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performUpdate(e);"OK"===t.Result?(this.clearListCache(),this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:this.currentEditingRow.recordData}),this.updateRowData(this.currentEditingRow,t.Record||e),t.Message&&this.showInfo(t.Message),this.emit("recordUpdated",{record:t.Record||e,row:this.currentEditingRow})):this.showError(t.Message||"Update failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Update failed: "+e.message)}}else this.currentForm.reportValidity()}async cloneRecord(e){var e={...e.recordData},t=(this.keyField&&(e[this.keyField]=""),await this.formBuilder.createForm("create",e));this.modals.addRecord.options.content=t,this.modals.addRecord.setContent(t),this.modals.addRecord.show(),this.currentForm=t,this.emit("formCreated",{form:t,formType:"create",record:e})}async deleteRows(e){if(e.length){var t=this.options.messages.areYouSure;if(confirm(t)){var s,a=[];for(s of e)try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});t=a.filter(e=>!e.success).length;0<t&&this.showError(t+` of ${a.length} records could not be deleted`),this.refreshRowStyles(),this.updatePagingInfo()}}}deleteRecord(e){var t=e.recordData;let s=this.options.messages.deleteConfirmation;if("function"==typeof this.options.deleteConfirmation){t={row:e,record:t,deleteConfirmMessage:s,cancel:!1,cancelMessage:this.options.messages.cancel};if(this.options.deleteConfirmation(t),t.cancel)return void(t.cancelMessage&&this.showError(t.cancelMessage));s=t.deleteConfirmMessage}this.modals.deleteConfirm.setContent(`<p>${s}</p>`),this.modals.deleteConfirm.show(),this.currentDeletingRow=e}async confirmDelete(){if(this.currentDeletingRow){var e=this.getKeyValue(this.currentDeletingRow.recordData);try{var t=await this.performDelete(e);"OK"===t.Result?(this.clearListCache(),this.modals.deleteConfirm.close(),this.removeRowFromTable(this.currentDeletingRow),t.Message&&this.showInfo(t.Message),this.emit("recordDeleted",{record:this.currentDeletingRow.recordData})):this.showError(t.Message||"Delete failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Delete failed: "+e.message)}}}async performCreate(e){var t=this.options.actions.createAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid createAction provided")}async performUpdate(e){var t=this.options.actions.updateAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid updateAction provided")}async performDelete(e){var t=this.options.actions.deleteAction,e={[this.keyField]:e};if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid deleteAction provided")}getFormData(e){var t,s,a,i={};for([t,s]of new FormData(e).entries())t.endsWith("[]")?(i[a=t.slice(0,-2)]||(i[a]=[]),i[a].push(s)):i.hasOwnProperty(t)?Array.isArray(i[t])?i[t].push(s):i[t]=[i[t],s]:i[t]=s;return i}updateRowData(a,e){a.recordData={...a.recordData,...e},Object.keys(e).forEach(e=>{var t,s=this.options.fields[e];s&&(t=a.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(a.recordData,e),t.innerHTML=s.listEscapeHTML?h.escapeHtml(e):e,t.className=(`${s.listClass||""} `+(s.listClassEntry||"")).trim())})}removeRowFromTable(e){e.remove(),0===this.elements.tableBody.querySelectorAll(".ftable-data-row").length&&this.addNoDataRow(),this.refreshRowStyles()}makeRowSelectable(t){!1!==this.options.selectOnRowClick&&t.addEventListener("click",e=>{e.target.classList.contains("norowselectonclick")||this.toggleRowSelection(t)})}toggleRowSelection(e){var t=e.classList.contains("ftable-row-selected");this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){h.addClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!0),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.add(t)}deselectRow(e){h.removeClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!1),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.delete(t)}recalcColumnWidths(){this.columnList.forEach(e=>{var t=this.options.fields[e],e=this.elements.table.querySelector(`[data-field-name="${e}"]`);e&&t.width&&(e.style.width=t.width)}),this.elements.table.offsetHeight}recalcColumnWidthsOnce(){this._recalculatedOnce||(this.recalcColumnWidths(),this._recalculatedOnce=!0)}clearAllSelections(){this.elements.tableBody.querySelectorAll(".ftable-row-selected").forEach(e=>this.deselectRow(e))}toggleSelectAll(t){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{t?this.selectRow(e):this.deselectRow(e)}),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}getSelectedRows(){return Array.from(this.elements.tableBody.querySelectorAll(".ftable-row-selected"))}sortByColumn(s){var a=this.options.fields[s];if(a&&!1!==a.sorting){a=this.state.sorting.findIndex(e=>e.fieldName===s);let e=!0,t="ASC";0<=a?"ASC"===this.state.sorting[a].direction?(t="DESC",this.state.sorting[a].direction=t):(this.state.sorting.splice(a,1),e=!1):this.state.sorting.push({fieldName:s,direction:t});a=this.lastSortEvent?.ctrlKey||this.lastSortEvent?.metaKey;(!this.options.multiSorting||this.options.multiSortingCtrlKey&&!a)&&(this.state.sorting=e?[{fieldName:s,direction:t}]:[]),this.updateSortingHeaders(),this.load(),this.saveState()}}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{h.removeClass(e,"ftable-column-header-sorted-asc ftable-column-header-sorted-desc")}),this.state.sorting.forEach(e=>{var t=this.elements.table.querySelector(`[data-field-name="${e.fieldName}"]`);t&&h.addClass(t,"ftable-column-header-sorted-"+e.direction.toLowerCase())})}updatePagingInfo(){var e,t,s;this.options.paging&&this.elements.pageInfoSpan&&(this.state.totalRecordCount<=0?(this.elements.pageInfoSpan.textContent="",this.elements.pagingListArea.innerHTML=""):(e=(this.state.currentPage-1)*this.state.pageSize+1,t=Math.min(this.state.currentPage*this.state.pageSize,this.state.totalRecordCount),s=this.options.messages.pagingInfo||"Showing {0}-{1} of {2}",this.elements.pageInfoSpan.textContent=s.replace(/\{0\}/g,e).replace(/\{1\}/g,t).replace(/\{2\}/g,this.state.totalRecordCount),this.createPageListNavigation(),this.createPageGotoNavigation()))}createPageListNavigation(){if(this.elements.pagingListArea){this.elements.pagingListArea.innerHTML="";var e=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(!(e<=1)){if(this.createPageButton("&laquo;",1,1===this.state.currentPage,"ftable-page-number-first"),this.createPageButton("&lsaquo;",this.state.currentPage-1,1===this.state.currentPage,"ftable-page-number-previous"),"normal"==this.options.pageList){var s=this.calculatePageNumbers(e);let t=0;s.forEach(e=>{1<e-t&&h.create("span",{className:"ftable-page-number-space",text:"...",parent:this.elements.pagingListArea}),this.createPageButton(e.toString(),e,!1,e===this.state.currentPage?"ftable-page-number ftable-page-number-active":"ftable-page-number"),t=e})}this.createPageButton("&rsaquo;",this.state.currentPage+1,this.state.currentPage>=e,"ftable-page-number-next"),this.createPageButton("&raquo;",e,this.state.currentPage>=e,"ftable-page-number-last")}}}createPageGotoNavigation(){if(this.options.paging&&"none"!==this.options.gotoPageArea){let s=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(s<=1)this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML="";else{this.elements.pagingGotoArea.style.display="inline-block",this.elements.pagingGotoArea.innerHTML="";h.create("span",{text:this.options.messages.gotoPageLabel+": ",parent:this.elements.pagingGotoArea});var e="ftable-goto-page-"+(this.options.tableId||"default");if("combobox"===this.options.gotoPageArea){this.elements.gotoPageSelect=h.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=s;e++)h.create("option",{attributes:{value:e},text:e,parent:this.elements.gotoPageSelect});this.elements.gotoPageSelect.value=this.state.currentPage,this.elements.gotoPageSelect.addEventListener("change",e=>{e=parseInt(e.target.value);1<=e&&e<=s&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=h.create("input",{attributes:{type:"number",id:e,min:"1",max:s,value:this.state.currentPage,className:"ftable-page-goto-input",style:"width: 65px; margin-left: 4px;"},parent:this.elements.pagingGotoArea}),this.elements.gotoPageInput.addEventListener("change",e=>{var t=parseInt(e.target.value);1<=t&&t<=s?this.changePage(t):e.target.value=this.state.currentPage}))}}else this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML=""}createPageButton(e,t,s,a){a=h.create("span",{className:a+(s?" ftable-page-number-disabled":""),html:e,parent:this.elements.pagingListArea});s||(a.style.cursor="pointer",a.addEventListener("click",e=>{e.preventDefault(),this.changePage(t)}))}calculatePageNumbers(t){if(t<=7)return Array.from({length:t},(e,t)=>t+1);var s=this.state.currentPage,a=new Set([1,2,t-1,t]);for(let e=Math.max(1,s-1);e<=Math.min(t,s+1);e++)a.add(e);return Array.from(a).sort((e,t)=>e-t)}changePage(e){var t=Math.ceil(this.state.totalRecordCount/this.state.pageSize);(e=Math.max(1,Math.min(e,t)))!==this.state.currentPage&&(this.state.currentPage=e,this.load())}changePageSize(e){this.state.pageSize=e,this.state.currentPage=1,this.load(),this.saveState()}showLoadingIndicator(){0===this.options.loadingAnimationDelay?this.modals.loading&&this.modals.loading.show():this.loadingTimeout=setTimeout(()=>{this.modals.loading&&this.modals.loading.show(),this.loadingShownAt=Date.now()},this.options.loadingAnimationDelay||500)}hideLoadingIndicator(){this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null);var e=this.loadingShownAt?Date.now()-this.loadingShownAt:0;this.modals.loading&&(e<200?setTimeout(()=>{this.modals.loading.hide()},200-e):this.modals.loading.hide()),this.loadingShownAt=null}showError(e){this.modals.error?(this.modals.error.setContent(`<p>${e}</p>`),this.modals.error.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(`<p>${e}</p>`),this.modals.info.show()):alert(e)}reload(e=!1){return e&&this.clearListCache(),this.load()}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}getRowByKey(e){return this.elements.tableBody.querySelector(`[data-record-key="${e}"]`)}destroy(){this.element&&this.element.ftableInstance&&(this.element.ftableInstance=null),Object.values(this.modals).forEach(e=>e.destroy()),this.elements.mainContainer&&this.elements.mainContainer.remove(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.loadingTimeout&&clearTimeout(this.loadingTimeout),window.removeEventListener("resize",this.handleResize),this.options=null,this.state=null,this.elements=null,this.formBuilder=null,this.modals=null}setOption(e,t){return this.options[e]=t,this}getState(){return{...this.state}}addFilter(t,e,s="equals"){return this.state.filters||(this.state.filters=[]),this.state.filters=this.state.filters.filter(e=>e.fieldName!==t),null!=e&&""!==e&&this.state.filters.push({fieldName:t,value:e,operator:s}),this}clearFilters(){return this.state.filters=[],this}exportToCSV(e="table-data.csv"){var t=this.columnList.map(e=>this.options.fields[e].title||e),s=this.state.records.map(t=>this.columnList.map(e=>{e=this.getDisplayText(t,e);return`"${String(e).replace(/"/g,'""')}"`})),t=[t.map(e=>`"${e}"`).join(","),...s.map(e=>e.join(","))].join("\n"),s=new Blob(["\ufeff"+t],{type:"text/csv;charset=utf-8;"}),t=document.createElement("a");t.href=URL.createObjectURL(s),t.download=e,t.click(),t.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
23
+ `,document.head.appendChild(e))}createPagingUI(){this.elements.bottomPanel=h.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=h.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=h.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=h.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=h.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=h.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=h.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});h.create("span",{text:this.options.messages.pageSizeChangeLabel,parent:e});let s=h.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100]).forEach(e=>{var t=h.create("option",{attributes:{value:e},text:e.toString(),parent:s});e===this.state.pageSize&&(t.selected=!0)}),s.addEventListener("change",e=>{this.changePageSize(parseInt(e.target.value))})}processFieldDefinitions(){this.fieldList=Object.keys(this.options.fields),this.fieldList.forEach(e=>{e=this.options.fields[e];!0===e.key?(void 0!==e.create&&e.create||(e.create=!0,e.type="hidden"),void 0!==e.edit&&e.edit||(e.edit=!0,e.type="hidden")):(e.create=e.create??!0,e.edit=e.edit??!0,e.list=e.list??!0,e.sorting=e.sorting??!0),e.visibility=e.visibility??"visible"}),this.columnList=this.fieldList.filter(e=>!1!==this.options.fields[e].list),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.info("No key field defined")}async resolveAsyncFieldOptions(){this.formBuilder.storeOriginalFieldOptions();for(var t of this.columnList){var e=this.options.fields[t],s=this.formBuilder.originalFieldOptions.get(t)||e.options;if(s&&("function"==typeof s||"string"==typeof s)&&!Array.isArray(s)&&("object"!=typeof s||Array.isArray(s)||!(0<Object.keys(s).length)))try{var a={...e,options:s},i=await this.formBuilder.resolveOptions(a);e.options=i}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}}refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");0!==e.length&&e.forEach(a=>{this.columnList.forEach(e=>{var t,s=this.options.fields[e];s.options&&"function"!=typeof s.options&&"string"!=typeof s.options&&(t=a.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(a.recordData,e),t.innerHTML=s.listEscapeHTML?h.escapeHtml(e):e)})})}createMainStructure(){this.elements.mainContainer=h.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=h.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),h.create("div",{className:"ftable-title-text",text:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=h.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=h.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=h.create("table",{className:"ftable",parent:this.elements.tableDiv}),this.options.tableId&&(this.elements.table.id=this.options.tableId),this.createTableHeader(),this.createTableBody(),this.addNoDataRow()}createTableHeader(){var e=h.create("thead",{parent:this.elements.table});let i=h.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes){var t=h.create("th",{className:"ftable-column-header ftable-column-header-select",parent:i});if(this.options.multiselect){let e=h.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var e=this.options.fields[t],s=h.create("th",{className:`ftable-column-header ${e.listClass||""} `+(e.listClassHeader||""),attributes:{"data-field-name":t},parent:i}),a=(e.width&&(s.style.width=e.width),h.create("div",{className:"ftable-column-header-container",parent:s}));e.tooltip&&a.setAttribute("title",e.tooltip),h.create("span",{className:"ftable-column-header-text",text:e.title||t,parent:a}),this.options.sorting&&!1!==e.sorting&&(h.addClass(s,"ftable-column-header-sortable"),s.addEventListener("click",e=>{e.preventDefault(),this.lastSortEvent=e,this.sortByColumn(t)})),!1!==this.options.columnResizable&&!1!==e.columnResizable&&this.makeColumnResizable(s,a),"hidden"!==e.visibility&&"separator"!==e.visibility||h.hide(s)}),this.options.actions.updateAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:i}),this.options.actions.cloneAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:i}),this.options.actions.deleteAction&&h.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:i}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,s,a=h.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&h.create("th",{parent:a});for(t of this.columnList){var i=this.options.fields[t],o=!1!==i.searchable,r=h.create("th",{className:"ftable-toolbarsearch-column-header",parent:a});if(o){o=h.create("div",{className:"ftable-column-header-container",parent:r});let e;!i.type&&i.options&&(i.type="select");var n,l,c,d="ftable-toolbarsearch-"+t;switch(i.type){case"date":case"datetime-local":"undefined"!=typeof FDatepicker?(n=i.dateFormat||this.options.defaultDateFormat,e=document.createElement("div"),l=h.create("input",{className:"ftable-toolbarsearch-extra",attributes:{type:"hidden","data-field-name":t,id:"ftable-toolbarsearch-extra-"+t}}),c=h.create("input",{className:"ftable-toolbarsearch",attributes:{id:"ftable-toolbarsearch-"+t,type:"text",placeholder:i.placeholder||"",readOnly:!0}}),e.appendChild(l),e.appendChild(c),new FDatepicker(c,{format:n,altField:"ftable-toolbarsearch-extra-"+t,altFormat:"Y-m-d"})):e=h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"date","data-field-name":t,id:d}});break;case"checkbox":e=i.values?await this.createSelectForSearch(t,i,!0):h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}});break;case"select":e=i.options?await this.createSelectForSearch(t,i,!1):h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}});break;default:e=h.create("input",{className:"ftable-toolbarsearch",attributes:{type:"text","data-field-name":t,id:d,placeholder:"Search..."}})}e&&(o.appendChild(e),"SELECT"===e.tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)}))}"hidden"!==i.visibility&&"separator"!==i.visibility||h.hide(r)}this.options.toolbarsearch&&this.options.toolbarreset&&(e=h.create("th",{className:"ftable-toolbarsearch-reset",parent:a}),0<(s=(this.options.actions.updateAction?1:0)+(this.options.actions.deleteAction?1:0))?e.colSpan=s:h.addClass(e,"ftable-command-column-header"),h.create("button",{className:"ftable-toolbarsearch-reset-button",text:this.options.messages.resetSearch,parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,s){var a="ftable-toolbarsearch-"+e;let i=h.create("select",{attributes:{"data-field-name":e,id:a,class:"ftable-toolbarsearch"}}),o;return s&&t.values?o=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):t.options&&(o=await this.formBuilder.resolveOptions(t)),0<o?.length&&(""===o[0].Value||""===o[0].value||""===o[0]||""===o[0].DisplayText&&null==o[0].Value)||h.create("option",{attributes:{value:""},text:"",parent:i}),o&&Array.isArray(o)?o.forEach(e=>{h.create("option",{attributes:{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e},text:e.DisplayText||e.text||e,parent:i})}):o&&"object"==typeof o&&Object.entries(o).forEach(([e,t])=>{h.create("option",{attributes:{value:e},text:t,parent:i})}),i}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name"),e=e.value.trim();e?this.state.searchQueries[t]=e:delete this.state.searchQueries[t],clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.load()},this.options.searchDebounceMs)}resetSearch(){this.state.searchQueries={},this.elements.table.querySelectorAll(".ftable-toolbarsearch").forEach(e=>{"SELECT"===e.tagName?e.selectedIndex=0:e.value=""}),this.load()}makeColumnResizable(s,e){this.elements.resizeBar||(this.elements.resizeBar=h.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),h.hide(this.elements.resizeBar));e=h.create("div",{className:"ftable-column-resize-handler",parent:e});let a=!1,i=0,o=0,r=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),a=!0,i=e.clientX,o=s.offsetWidth;var e=s.getBoundingClientRect(),t=this.elements.mainContainer.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-t.left+"px",this.elements.resizeBar.style.top=e.top-t.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",h.show(this.elements.resizeBar),document.addEventListener("mousemove",r),document.addEventListener("mouseup",n)}),e=>{var t;a&&(t=e.clientX-i,Math.max(50,o+t),t=this.elements.mainContainer.getBoundingClientRect(),this.elements.resizeBar.style.left=e.clientX-t.left+"px")}),n=e=>{a&&(a=!1,e=e.clientX-i,e=Math.max(50,o+e),s.style.width=e+"px",h.hide(this.elements.resizeBar),document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",n),this.options.saveUserPreferences)&&this.saveColumnSettings()}}saveColumnSettings(){if(this.options.saveUserPreferences){let a={};this.columnList.forEach(e=>{var t,s=this.elements.table.querySelector(`[data-field-name="${e}"]`);s&&(t=this.options.fields[e],a[e]={width:s.style.width||t.width||"auto",visibility:t.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(a))}}saveState(){var e;this.options.saveUserPreferences&&(e={sorting:this.state.sorting,pageSize:this.state.pageSize},this.userPrefs.set("table-state",JSON.stringify(e)))}loadColumnSettings(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("column-settings");if(e)try{var t=JSON.parse(e);Object.entries(t).forEach(([e,t])=>{e=this.options.fields[e];e&&(t.width&&(e.width=t.width),t.visibility)&&(e.visibility=t.visibility)})}catch(e){this.logger.warn("Failed to load column settings:",e)}}}loadState(){if(this.options.saveUserPreferences){var e=this.userPrefs.get("table-state");if(e)try{var t=JSON.parse(e);Array.isArray(t.sorting)&&(this.state.sorting=t.sorting),t.pageSize&&this.options.pageSizes.includes(t.pageSize)&&(this.state.pageSize=t.pageSize)}catch(e){this.logger.warn("Failed to load table state:",e)}}}createTableBody(){this.elements.tableBody=h.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=h.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,h.create("td",{attributes:{colspan:t},text:this.options.messages.noDataAvailable,parent:e}))}removeNoDataRow(){var e=this.elements.tableBody.querySelector(".ftable-no-data-row");e&&e.remove()}createModals(){this.options.actions.createAction&&this.createAddRecordModal(),this.options.actions.updateAction&&this.createEditRecordModal(),this.options.actions.deleteAction&&this.createDeleteConfirmModal(),this.createErrorModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new e({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null})}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new e({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.modals.editRecord.close()}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new e({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>this.modals.deleteConfirm.close()},{text:this.options.messages.deleteText,className:"ftable-dialog-deletebutton",onClick:()=>this.confirmDelete()}]})}createErrorModal(){this.modals.error=new e({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createInfoModal(){this.modals.info=new e({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new e({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",content:`<div class="ftable-loading-message">${this.options.messages.loadingMessage}</div>`})}bindEvents(){this.subscribeOptionEvents(),this.createCustomToolbarItems(),this.createToolbarButtons(),this.bindKeyboardEvents(),!1!==this.options.columnSelectable&&this.createColumnSelectionMenu()}subscribeOptionEvents(){["formCreated","formClosed","recordsLoaded","recordAdded","recordUpdated","recordDeleted","selectionChanged"].forEach(e=>{"function"==typeof this.options[e]&&this.on(e,this.options[e])})}createColumnSelectionMenu(){this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null,this.elements.table.querySelector("thead").addEventListener("contextmenu",e=>{e.preventDefault(),this.showColumnSelectionMenu(e)})}showColumnSelectionMenu(e){this.hideColumnSelectionMenu(),this.elements.columnSelectionOverlay=h.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=h.create("div",{className:"ftable-column-selection-container",parent:document.body}),this.populateColumnSelectionMenu(),this.positionColumnSelectionMenu(e),this.elements.columnSelectionOverlay.addEventListener("click",e=>{e.target===this.elements.columnSelectionOverlay&&this.hideColumnSelectionMenu()}),this.elements.columnSelectionOverlay.addEventListener("contextmenu",e=>{e.preventDefault(),this.hideColumnSelectionMenu()})}populateColumnSelectionMenu(){let l=h.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(t=>{var e=this.options.fields[t],s="hidden"!==e.visibility,a="fixed"===e.visibility,i="separator"===e.visibility,o=this.isFieldSorted(t),r=h.create("li",{className:"ftable-column-select-item",parent:l}),n=h.create("label",{className:"ftable-column-select-label",parent:r});if(!i){let e=h.create("input",{attributes:{type:"checkbox",id:"column-"+t},parent:n});e.checked=s,(a||o&&s)&&(e.disabled=!0,r.style.opacity="0.6"),e.disabled||e.addEventListener("change",()=>{this.setColumnVisibility(t,e.checked)})}a=h.create("span",{text:e.title||t,style:i?"font-weight: bold;":null,parent:n});o&&((s=h.create("span",{className:"ftable-sort-indicator",text:" (sorted)",parent:a})).style.fontSize="0.8em",s.style.color="#666")})}positionColumnSelectionMenu(e){var t=this,s=e.pageX,e=e.pageY,e=(t.elements.columnSelectionMenu.style.position="absolute",t.elements.columnSelectionMenu.style.left=s+"px",t.elements.columnSelectionMenu.style.top=e+"px",t.elements.columnSelectionMenu.style.minWidth="100px",t.elements.columnSelectionMenu.style.boxSizing="border-box",t.elements.columnSelectionMenu.offsetWidth),a=window.innerWidth;a<s+e&&(s=Math.max(10,a-e-10),t.elements.columnSelectionMenu.style.left=s+"px")}hideColumnSelectionMenu(){this.elements.columnSelectionOverlay&&(this.elements.columnSelectionOverlay.remove(),this.elements.columnSelectionMenu.remove(),this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null)}isFieldSorted(t){return this.state.sorting.some(e=>e.fieldName===t)}createToolbarButtons(){this.options.csvExport&&this.addToolbarButton({text:this.options.messages.csvExport,className:"ftable-toolbar-item-csv",onClick:()=>{var e=this.options.title?this.options.title.replace(/[^a-z0-9]/gi,"-").toLowerCase()+".csv":"table-export.csv";this.exportToCSV(e)}}),this.options.printTable&&this.addToolbarButton({text:this.options.messages.printTable,className:"ftable-toolbar-item-print",onClick:()=>{this.printTable()}}),this.options.actions.createAction&&this.addToolbarButton({text:this.options.messages.addNewRecord,className:"ftable-toolbar-item-add-record",addIconSpan:!0,onClick:()=>this.showAddRecordForm()})}addToolbarButton(e){var t=h.create("span",{className:"ftable-toolbar-item "+(e.className||""),parent:this.elements.toolbarDiv});if(e.addIconSpan)h.create("span",{className:"ftable-toolbar-item-icon "+(e.className||""),parent:t});let s=h.create("span",{className:"ftable-toolbar-item-text "+(e.className||""),text:e.text,parent:t});return e.onClick&&t.addEventListener("click",e.onClick),t}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach(t=>{var e=h.create("span",{className:"ftable-toolbar-item ftable-toolbar-item-custom "+(t.buttonClass||""),parent:this.elements.toolbarDiv});t.tooltip&&e.setAttribute("title",t.tooltip),t.icon&&h.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:e}),t.text&&h.create("span",{text:t.text,className:"ftable-toolbar-item-text ftable-toolbar-item-custom-text "+(t.buttonTextClass||""),parent:e}),"function"==typeof t.click&&e.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.click()})})}bindKeyboardEvents(){this.options.selecting&&(this.shiftKeyDown=!1,document.addEventListener("keydown",e=>{"Shift"===e.key&&(this.shiftKeyDown=!0)}),document.addEventListener("keyup",e=>{"Shift"===e.key&&(this.shiftKeyDown=!1)}))}setupFTableUserPreferences(){var e;this.options.saveUserPreferences&&(e=this.userPrefs.generatePrefix(this.options.tableId||"",this.fieldList),this.userPrefs=new i(e,this.options.saveUserPreferencesMethod),this.loadState(),this.loadColumnSettings())}async load(e={}){if(!this.state.isLoading){this.state.isLoading=!0,this.showLoadingIndicator();try{var t={...e,...this.buildLoadParams()},s=await this.performLoad(t);this.processLoadedData(s),this.emit("recordsLoaded",{records:s.Records,serverResponse:s})}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Load failed: "+e.message)}finally{this.state.isLoading=!1,this.hideLoadingIndicator()}this.renderSortingInfo()}}buildLoadParams(){var e,t={};if(this.options.paging&&(this.state.pageSize||(this.state.pageSize=this.options.pageSize),t.jtStartIndex=(this.state.currentPage-1)*this.state.pageSize,t.jtPageSize=this.state.pageSize),this.options.sorting&&(0<this.state.sorting.length?t.jtSorting=this.state.sorting.map(e=>e.fieldName+" "+e.direction).join(", "):this.options.defaultSorting&&(t.jtSorting=this.parseDefaultSorting(this.options.defaultSorting).map(e=>e.fieldName+" "+e.direction).join(", "))),this.options.toolbarsearch&&0<Object.keys(this.state.searchQueries).length){let s=[],a=[];Object.entries(this.state.searchQueries).forEach(([e,t])=>{""!==t&&(s.push(t),a.push(e))}),0<s.length&&(t.q=s,t.opt=a)}return"function"==typeof this.options.listQueryParams&&(e=this.options.listQueryParams(),Object.assign(t,e)),t}isCacheExpired(e,t){return!e||!e.timestamp||t<Date.now()-e.timestamp}async performLoad(e){var t=this.options.actions.listAction;if(this.options.listCache&&"string"==typeof t){var s=this.formBuilder.optionsCache.get(t,e);if(s&&!this.isCacheExpired(s,this.options.listCache))return s.data}let a;if("function"==typeof t)a=await t(e);else{if("string"!=typeof t)throw new Error("No valid listAction provided");a=this.options.forcePost?await l.post(t,e):await l.get(t,e)}if(a&&"OK"===a.Result)return this.options.listCache&&"string"==typeof t&&this.formBuilder.optionsCache.set(t,e,{data:a,timestamp:Date.now()}),a;throw new Error(a?.Message||"Invalid response from server")}processLoadedData(e){"OK"!==e.Result?this.showError(e.Message||"Unknown error occurred"):(this.state.records=e.Records||[],this.state.totalRecordCount=e.TotalRecordCount||this.state.records.length,this.renderTableData(),this.updatePagingInfo())}renderTableData(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>e.remove()),0===this.state.records.length?this.addNoDataRow():(this.removeNoDataRow(),this.state.records.forEach(e=>{e=this.createTableRow(e);this.elements.tableBody.appendChild(e)}),this.refreshRowStyles(),this.refreshDisplayValues())}createTableRow(t){let s=h.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(t)}}),e=(s.recordData=t,this.options.selecting&&this.options.selectingCheckboxes&&this.addSelectingCell(s),this.columnList.forEach(e=>{this.addDataCell(s,t,e)}),0);return this.options.actions.updateAction&&(this.addEditCell(s),e++),this.options.actions.cloneAction&&(this.addCloneCell(s),e++),this.options.actions.deleteAction&&(this.addDeleteCell(s),e++),this.options.selecting&&this.makeRowSelectable(s),s}addSelectingCell(t){var e=h.create("td",{className:"ftable-command-column ftable-selecting-column",parent:t});h.create("input",{className:"norowselectonclick",attributes:{type:"checkbox"},parent:e}).addEventListener("change",e=>{this.toggleRowSelection(t)})}addDataCell(e,t,s){var a=this.options.fields[s],t=this.getDisplayText(t,s),t=h.create("td",{className:`${a.listClass||""} `+(a.listClassEntry||""),html:a.listEscapeHTML?h.escapeHtml(t):t,attributes:{"data-field-name":s},parent:e});"fixed"!==a.visibility&&"hidden"===a.visibility&&h.hide(t)}addEditCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},html:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},html:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=h.create("td",{className:"ftable-command-column",parent:t});h.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},html:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t){var s=this.options.fields[t],a=e[t];return s.display&&"function"==typeof s.display?s.display({record:e}):"date"===s.type&&a?"undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(a),s.dateFormat||this.options.defaultDateFormat):this.formatDate(a,s.dateLocale||this.options.defaultDateLocale):"datetime-local"===s.type&&a?"undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(a),s.dateFormat||this.options.defaultDateFormat):this.formatDateTime(a,s.dateLocale||this.options.defaultDateLocale):"checkbox"===s.type?this.getCheckboxText(t,a):s.options?(e=this.findOptionByValue(s.options,a))?e.DisplayText||e.text||e:a:a||""}_parseDate(e){return e.includes("Date")?new Date(parseInt(e.substr(6),10)):10==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10)):19==e.length?new Date(parseInt(e.substr(0,4),10),parseInt(e.substr(5,2),10)-1,parseInt(e.substr(8,2),10),parseInt(e.substr(11,2),10),parseInt(e.substr(14,2),10),parseInt(e.substr(17,2),10)):new Date(e)}formatDate(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleDateString(t,{year:"numeric",month:"2-digit",day:"2-digit"})}catch{return e}}formatDateTime(e,t){if(!e)return"";var s=this._parseDate(e);try{return isNaN(s.getTime())?e:s.toLocaleString(t)}catch{return e}}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?"Yes":"No"}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?h.addClass(e,"ftable-row-even"):h.removeClass(e,"ftable-row-even")})}getKeyValue(e){return this.keyField?e[this.keyField]:null}async showAddRecordForm(){var e=await this.formBuilder.createForm("create");this.modals.addRecord.setContent(e),this.modals.addRecord.show(),this.currentForm=e,this.emit("formCreated",{form:e,formType:"create",record:null})}async saveNewRecord(){if(this.currentForm)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performCreate(e);"OK"===t.Result?(this.clearListCache(),this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null}),t.Message&&this.showInfo(t.Message),await this.load(),this.emit("recordAdded",{record:t.Record})):this.showError(t.Message||"Create failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Create failed: "+e.message)}}else this.currentForm.reportValidity()}async editRecord(e){var t=e.recordData,s=await this.formBuilder.createForm("edit",t);this.modals.editRecord.setContent(s),this.modals.editRecord.show(),this.currentForm=s,this.currentEditingRow=e,this.emit("formCreated",{form:s,formType:"edit",record:t})}async saveEditedRecord(){if(this.currentForm&&this.currentEditingRow)if(this.currentForm.checkValidity()){var e=this.getFormData(this.currentForm);try{var t=await this.performUpdate(e);"OK"===t.Result?(this.clearListCache(),this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:this.currentEditingRow.recordData}),this.updateRowData(this.currentEditingRow,t.Record||e),t.Message&&this.showInfo(t.Message),this.emit("recordUpdated",{record:t.Record||e,row:this.currentEditingRow})):this.showError(t.Message||"Update failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Update failed: "+e.message)}}else this.currentForm.reportValidity()}async cloneRecord(e){var e={...e.recordData},t=(this.keyField&&(e[this.keyField]=""),await this.formBuilder.createForm("create",e));this.modals.addRecord.options.content=t,this.modals.addRecord.setContent(t),this.modals.addRecord.show(),this.currentForm=t,this.emit("formCreated",{form:t,formType:"create",record:e})}async deleteRows(e){if(e.length){var t=this.options.messages.areYouSure;if(confirm(t)){var s,a=[];for(s of e)try{var i=await this.performDelete(s);a.push({key:s,success:"OK"===i.Result,result:i})}catch(e){a.push({key:s,success:!1,error:e.message})}a.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});t=a.filter(e=>!e.success).length;0<t&&this.showError(t+` of ${a.length} records could not be deleted`),this.refreshRowStyles(),this.updatePagingInfo()}}}deleteRecord(e){var t=e.recordData;let s=this.options.messages.deleteConfirmation;if("function"==typeof this.options.deleteConfirmation){t={row:e,record:t,deleteConfirmMessage:s,cancel:!1,cancelMessage:this.options.messages.cancel};if(this.options.deleteConfirmation(t),t.cancel)return void(t.cancelMessage&&this.showError(t.cancelMessage));s=t.deleteConfirmMessage}this.modals.deleteConfirm.setContent(`<p>${s}</p>`),this.modals.deleteConfirm.show(),this.currentDeletingRow=e}async confirmDelete(){if(this.currentDeletingRow){var e=this.getKeyValue(this.currentDeletingRow.recordData);try{var t=await this.performDelete(e);"OK"===t.Result?(this.clearListCache(),this.modals.deleteConfirm.close(),this.removeRowFromTable(this.currentDeletingRow),t.Message&&this.showInfo(t.Message),this.emit("recordDeleted",{record:this.currentDeletingRow.recordData})):this.showError(t.Message||"Delete failed")}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Delete failed: "+e.message)}}}async performCreate(e){var t=this.options.actions.createAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid createAction provided")}async performUpdate(e){var t=this.options.actions.updateAction;if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid updateAction provided")}async performDelete(e){var t=this.options.actions.deleteAction,e={[this.keyField]:e};if("function"==typeof t)return t(e);if("string"==typeof t)return l.post(t,e);throw new Error("No valid deleteAction provided")}getFormData(e){var t,s,a,i={};for([t,s]of new FormData(e).entries())t.endsWith("[]")?(i[a=t.slice(0,-2)]||(i[a]=[]),i[a].push(s)):i.hasOwnProperty(t)?Array.isArray(i[t])?i[t].push(s):i[t]=[i[t],s]:i[t]=s;return i}updateRowData(a,e){a.recordData={...a.recordData,...e},Object.keys(e).forEach(e=>{var t,s=this.options.fields[e];s&&(t=a.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(a.recordData,e),t.innerHTML=s.listEscapeHTML?h.escapeHtml(e):e,t.className=(`${s.listClass||""} `+(s.listClassEntry||"")).trim())})}removeRowFromTable(e){e.remove(),0===this.elements.tableBody.querySelectorAll(".ftable-data-row").length&&this.addNoDataRow(),this.refreshRowStyles()}makeRowSelectable(t){!1!==this.options.selectOnRowClick&&t.addEventListener("click",e=>{["INPUT","BUTTON","SELECT","TEXTAREA","A"].includes(e.target.tagName)||e.target.classList.contains("norowselectonclick")||this.toggleRowSelection(t)})}toggleRowSelection(e){var t=e.classList.contains("ftable-row-selected");this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){h.addClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!0),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.add(t)}deselectRow(e){h.removeClass(e,"ftable-row-selected");var t=e.querySelector('input[type="checkbox"]'),t=(t&&(t.checked=!1),this.getKeyValue(e.recordData));t&&this.state.selectedRecords.delete(t)}recalcColumnWidths(){this.columnList.forEach(e=>{var t=this.options.fields[e],e=this.elements.table.querySelector(`[data-field-name="${e}"]`);e&&t.width&&(e.style.width=t.width)}),this.elements.table.offsetHeight}recalcColumnWidthsOnce(){this._recalculatedOnce||(this.recalcColumnWidths(),this._recalculatedOnce=!0)}clearAllSelections(){this.elements.tableBody.querySelectorAll(".ftable-row-selected").forEach(e=>this.deselectRow(e))}toggleSelectAll(t){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{t?this.selectRow(e):this.deselectRow(e)}),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}getSelectedRows(){return Array.from(this.elements.tableBody.querySelectorAll(".ftable-row-selected"))}sortByColumn(s){var a=this.options.fields[s];if(a&&!1!==a.sorting){a=this.state.sorting.findIndex(e=>e.fieldName===s);let e=!0,t="ASC";0<=a?"ASC"===this.state.sorting[a].direction?(t="DESC",this.state.sorting[a].direction=t):(this.state.sorting.splice(a,1),e=!1):this.state.sorting.push({fieldName:s,direction:t});a=this.lastSortEvent?.ctrlKey||this.lastSortEvent?.metaKey;(!this.options.multiSorting||this.options.multiSortingCtrlKey&&!a)&&(this.state.sorting=e?[{fieldName:s,direction:t}]:[]),this.updateSortingHeaders(),this.load(),this.saveState()}}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{h.removeClass(e,"ftable-column-header-sorted-asc ftable-column-header-sorted-desc")}),this.state.sorting.forEach(e=>{var t=this.elements.table.querySelector(`[data-field-name="${e.fieldName}"]`);t&&h.addClass(t,"ftable-column-header-sorted-"+e.direction.toLowerCase())})}updatePagingInfo(){var e,t,s;this.options.paging&&this.elements.pageInfoSpan&&(this.state.totalRecordCount<=0?(this.elements.pageInfoSpan.textContent="",this.elements.pagingListArea.innerHTML=""):(e=(this.state.currentPage-1)*this.state.pageSize+1,t=Math.min(this.state.currentPage*this.state.pageSize,this.state.totalRecordCount),s=this.options.messages.pagingInfo||"Showing {0}-{1} of {2}",this.elements.pageInfoSpan.textContent=s.replace(/\{0\}/g,e).replace(/\{1\}/g,t).replace(/\{2\}/g,this.state.totalRecordCount),this.createPageListNavigation(),this.createPageGotoNavigation()))}createPageListNavigation(){if(this.elements.pagingListArea){this.elements.pagingListArea.innerHTML="";var e=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(!(e<=1)){if(this.createPageButton("&laquo;",1,1===this.state.currentPage,"ftable-page-number-first"),this.createPageButton("&lsaquo;",this.state.currentPage-1,1===this.state.currentPage,"ftable-page-number-previous"),"normal"==this.options.pageList){var s=this.calculatePageNumbers(e);let t=0;s.forEach(e=>{1<e-t&&h.create("span",{className:"ftable-page-number-space",text:"...",parent:this.elements.pagingListArea}),this.createPageButton(e.toString(),e,!1,e===this.state.currentPage?"ftable-page-number ftable-page-number-active":"ftable-page-number"),t=e})}this.createPageButton("&rsaquo;",this.state.currentPage+1,this.state.currentPage>=e,"ftable-page-number-next"),this.createPageButton("&raquo;",e,this.state.currentPage>=e,"ftable-page-number-last")}}}createPageGotoNavigation(){if(this.options.paging&&"none"!==this.options.gotoPageArea){let s=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(s<=1)this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML="";else{this.elements.pagingGotoArea.style.display="inline-block",this.elements.pagingGotoArea.innerHTML="";h.create("span",{text:this.options.messages.gotoPageLabel+": ",parent:this.elements.pagingGotoArea});var e="ftable-goto-page-"+(this.options.tableId||"default");if("combobox"===this.options.gotoPageArea){this.elements.gotoPageSelect=h.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=s;e++)h.create("option",{attributes:{value:e},text:e,parent:this.elements.gotoPageSelect});this.elements.gotoPageSelect.value=this.state.currentPage,this.elements.gotoPageSelect.addEventListener("change",e=>{e=parseInt(e.target.value);1<=e&&e<=s&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=h.create("input",{attributes:{type:"number",id:e,min:"1",max:s,value:this.state.currentPage,className:"ftable-page-goto-input",style:"width: 65px; margin-left: 4px;"},parent:this.elements.pagingGotoArea}),this.elements.gotoPageInput.addEventListener("change",e=>{var t=parseInt(e.target.value);1<=t&&t<=s?this.changePage(t):e.target.value=this.state.currentPage}))}}else this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML=""}createPageButton(e,t,s,a){a=h.create("span",{className:a+(s?" ftable-page-number-disabled":""),html:e,parent:this.elements.pagingListArea});s||(a.style.cursor="pointer",a.addEventListener("click",e=>{e.preventDefault(),this.changePage(t)}))}calculatePageNumbers(t){if(t<=7)return Array.from({length:t},(e,t)=>t+1);var s=this.state.currentPage,a=new Set([1,2,t-1,t]);for(let e=Math.max(1,s-1);e<=Math.min(t,s+1);e++)a.add(e);return Array.from(a).sort((e,t)=>e-t)}changePage(e){var t=Math.ceil(this.state.totalRecordCount/this.state.pageSize);(e=Math.max(1,Math.min(e,t)))!==this.state.currentPage&&(this.state.currentPage=e,this.load())}changePageSize(e){this.state.pageSize=e,this.state.currentPage=1,this.load(),this.saveState()}showLoadingIndicator(){0===this.options.loadingAnimationDelay?this.modals.loading&&this.modals.loading.show():this.loadingTimeout=setTimeout(()=>{this.modals.loading&&this.modals.loading.show(),this.loadingShownAt=Date.now()},this.options.loadingAnimationDelay||500)}hideLoadingIndicator(){this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null);var e=this.loadingShownAt?Date.now()-this.loadingShownAt:0;this.modals.loading&&(e<200?setTimeout(()=>{this.modals.loading.hide()},200-e):this.modals.loading.hide()),this.loadingShownAt=null}showError(e){this.modals.error?(this.modals.error.setContent(`<p>${e}</p>`),this.modals.error.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(`<p>${e}</p>`),this.modals.info.show()):alert(e)}reload(){return this.clearListCache(),this.load()}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}getRowByKey(e){return this.elements.tableBody.querySelector(`[data-record-key="${e}"]`)}destroy(){this.element&&this.element.ftableInstance&&(this.element.ftableInstance=null),Object.values(this.modals).forEach(e=>e.destroy()),this.elements.mainContainer&&this.elements.mainContainer.remove(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.loadingTimeout&&clearTimeout(this.loadingTimeout),window.removeEventListener("resize",this.handleResize),this.options=null,this.state=null,this.elements=null,this.formBuilder=null,this.modals=null}setOption(e,t){return this.options[e]=t,this}getState(){return{...this.state}}addFilter(t,e,s="equals"){return this.state.filters||(this.state.filters=[]),this.state.filters=this.state.filters.filter(e=>e.fieldName!==t),null!=e&&""!==e&&this.state.filters.push({fieldName:t,value:e,operator:s}),this}clearFilters(){return this.state.filters=[],this}exportToCSV(e="table-data.csv"){var t=this.columnList.map(e=>this.options.fields[e].title||e),s=this.state.records.map(t=>this.columnList.map(e=>{e=this.getDisplayText(t,e);return`"${String(e).replace(/"/g,'""')}"`})),t=[t.map(e=>`"${e}"`).join(","),...s.map(e=>e.join(","))].join("\n"),s=new Blob(["\ufeff"+t],{type:"text/csv;charset=utf-8;"}),t=document.createElement("a");t.href=URL.createObjectURL(s),t.download=e,t.click(),t.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
24
24
  <!DOCTYPE html>
25
25
  <html>
26
26
  <head>
package/ftable.umd.js CHANGED
@@ -162,7 +162,11 @@ class FTableDOMHelper {
162
162
  if (options.className) {
163
163
  element.className = options.className;
164
164
  }
165
-
165
+
166
+ if (options.style) {
167
+ element.style.cssText = options.style;
168
+ }
169
+
166
170
  if (options.attributes) {
167
171
  Object.entries(options.attributes).forEach(([key, value]) => {
168
172
  element.setAttribute(key, value);
@@ -1660,25 +1664,13 @@ class FTable extends FTableEventEmitter {
1660
1664
  field.edit = true;
1661
1665
  field.type = 'hidden';
1662
1666
  }
1663
- if (!field.hasOwnProperty('visibility')) {
1664
- field.visibility = 'hidden';
1665
- }
1667
+ field.visibility = field.visibility ?? 'visible';
1666
1668
  } else {
1667
- if (field.create === undefined) {
1668
- field.create = true;
1669
- }
1670
- if (field.edit === undefined) {
1671
- field.edit = true;
1672
- }
1673
- if (field.list === undefined) {
1674
- field.list = true;
1675
- }
1676
- if (field.sorting === undefined) {
1677
- field.sorting = true;
1678
- }
1679
- if (!field.hasOwnProperty('visibility')) {
1680
- field.visibility = 'visible';
1681
- }
1669
+ field.create = field.create ?? true;
1670
+ field.edit = field.edit ?? true;
1671
+ field.list = field.list ?? true;
1672
+ field.sorting = field.sorting ?? true;
1673
+ field.visibility = field.visibility ?? 'visible';
1682
1674
  }
1683
1675
  });
1684
1676
 
@@ -1691,7 +1683,7 @@ class FTable extends FTableEventEmitter {
1691
1683
  // Find key field
1692
1684
  this.keyField = this.fieldList.find(name => this.options.fields[name].key === true);
1693
1685
  if (!this.keyField) {
1694
- this.logger.warn('No key field defined');
1686
+ this.logger.info('No key field defined');
1695
1687
  }
1696
1688
  }
1697
1689
 
@@ -1867,7 +1859,7 @@ class FTable extends FTableEventEmitter {
1867
1859
  }
1868
1860
 
1869
1861
  // Hide column if needed
1870
- if (field.visibility === 'hidden') {
1862
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
1871
1863
  FTableDOMHelper.hide(th);
1872
1864
  }
1873
1865
  });
@@ -2045,7 +2037,7 @@ class FTable extends FTableEventEmitter {
2045
2037
  }
2046
2038
 
2047
2039
  // Hide search cell if column is hidden
2048
- if (field.visibility === 'hidden') {
2040
+ if (field.visibility === 'hidden' || field.visibility === 'separator') {
2049
2041
  FTableDOMHelper.hide(th);
2050
2042
  }
2051
2043
  }
@@ -2471,8 +2463,8 @@ class FTable extends FTableEventEmitter {
2471
2463
  this.subscribeOptionEvents();
2472
2464
 
2473
2465
  // Add toolbar buttons
2474
- this.createToolbarButtons();
2475
2466
  this.createCustomToolbarItems();
2467
+ this.createToolbarButtons();
2476
2468
 
2477
2469
  // Keyboard shortcuts
2478
2470
  this.bindKeyboardEvents();
@@ -2569,6 +2561,7 @@ class FTable extends FTableEventEmitter {
2569
2561
  const field = this.options.fields[fieldName];
2570
2562
  const isVisible = field.visibility !== 'hidden';
2571
2563
  const isFixed = field.visibility === 'fixed';
2564
+ const isSeparator = field.visibility === 'separator';
2572
2565
  const isSorted = this.isFieldSorted(fieldName);
2573
2566
 
2574
2567
  const listItem = FTableDOMHelper.create('li', {
@@ -2581,24 +2574,32 @@ class FTable extends FTableEventEmitter {
2581
2574
  parent: listItem
2582
2575
  });
2583
2576
 
2584
- const checkbox = FTableDOMHelper.create('input', {
2585
- attributes: {
2586
- type: 'checkbox',
2587
- id: `column-${fieldName}`
2588
- },
2589
- parent: label
2590
- });
2591
-
2592
- checkbox.checked = isVisible;
2577
+ if (!isSeparator) {
2578
+ const checkbox = FTableDOMHelper.create('input', {
2579
+ attributes: {
2580
+ type: 'checkbox',
2581
+ id: `column-${fieldName}`
2582
+ },
2583
+ parent: label
2584
+ });
2585
+ checkbox.checked = isVisible;
2593
2586
 
2594
- // Disable checkbox if column is fixed or currently sorted
2595
- if (isFixed || (isSorted && isVisible)) {
2596
- checkbox.disabled = true;
2597
- listItem.style.opacity = '0.6';
2587
+ // Disable checkbox if column is fixed or currently sorted
2588
+ if (isFixed || (isSorted && isVisible)) {
2589
+ checkbox.disabled = true;
2590
+ listItem.style.opacity = '0.6';
2591
+ }
2592
+ // Handle checkbox change
2593
+ if (!checkbox.disabled) {
2594
+ checkbox.addEventListener('change', () => {
2595
+ this.setColumnVisibility(fieldName, checkbox.checked);
2596
+ });
2597
+ }
2598
2598
  }
2599
2599
 
2600
2600
  const labelText = FTableDOMHelper.create('span', {
2601
2601
  text: field.title || fieldName,
2602
+ style: isSeparator ? 'font-weight: bold;' : null,
2602
2603
  parent: label
2603
2604
  });
2604
2605
 
@@ -2613,12 +2614,6 @@ class FTable extends FTableEventEmitter {
2613
2614
  sortIndicator.style.color = '#666';
2614
2615
  }
2615
2616
 
2616
- // Handle checkbox change
2617
- if (!checkbox.disabled) {
2618
- checkbox.addEventListener('change', () => {
2619
- this.setColumnVisibility(fieldName, checkbox.checked);
2620
- });
2621
- }
2622
2617
  });
2623
2618
  }
2624
2619
 
@@ -2726,7 +2721,7 @@ class FTable extends FTableEventEmitter {
2726
2721
  if (!this.options.toolbar || !this.options.toolbar.items) return;
2727
2722
 
2728
2723
  this.options.toolbar.items.forEach(item => {
2729
- const button = FTableDOMHelper.create('button', {
2724
+ const button = FTableDOMHelper.create('span', {
2730
2725
  className: `ftable-toolbar-item ftable-toolbar-item-custom ${item.buttonClass || ''}`,
2731
2726
  parent: this.elements.toolbarDiv
2732
2727
  });
@@ -2754,6 +2749,7 @@ class FTable extends FTableEventEmitter {
2754
2749
  if (item.text) {
2755
2750
  FTableDOMHelper.create('span', {
2756
2751
  text: item.text,
2752
+ className: `ftable-toolbar-item-text ftable-toolbar-item-custom-text ${item.buttonTextClass || ''}`,
2757
2753
  parent: button
2758
2754
  });
2759
2755
  }
@@ -3004,11 +3000,12 @@ class FTable extends FTableEventEmitter {
3004
3000
  });
3005
3001
 
3006
3002
  const checkbox = FTableDOMHelper.create('input', {
3003
+ className: 'norowselectonclick', // this prevents clicks on the select to also become clicks on the row
3007
3004
  attributes: { type: 'checkbox' },
3008
3005
  parent: cell
3009
3006
  });
3010
3007
 
3011
- checkbox.addEventListener('change', () => {
3008
+ checkbox.addEventListener('change', (e) => {
3012
3009
  this.toggleRowSelection(row);
3013
3010
  });
3014
3011
  }
@@ -3510,7 +3507,9 @@ class FTable extends FTableEventEmitter {
3510
3507
  makeRowSelectable(row) {
3511
3508
  if (this.options.selectOnRowClick !== false) {
3512
3509
  row.addEventListener('click', (e) => {
3513
- if (!e.target.classList.contains('norowselectonclick')) {
3510
+ // input elements can't select the row, nor norowselectonclick class
3511
+ if (!['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA', 'A'].includes(e.target.tagName) &&
3512
+ !e.target.classList.contains('norowselectonclick')) {
3514
3513
  this.toggleRowSelection(row);
3515
3514
  }
3516
3515
  });
@@ -3902,11 +3901,8 @@ class FTable extends FTableEventEmitter {
3902
3901
  }
3903
3902
 
3904
3903
  // Public API Methods
3905
- reload(hard = false) {
3906
- if (hard) {
3907
- // Clear list cache
3908
- this.clearListCache();
3909
- }
3904
+ reload() {
3905
+ this.clearListCache();
3910
3906
  return this.load();
3911
3907
  }
3912
3908
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liedekef/ftable",
3
- "version": "1.1.9",
3
+ "version": "1.1.12",
4
4
  "description": "Modern, lightweight, jQuery-free CRUD table for dynamic AJAX-powered tables.",
5
5
  "main": "ftable.js",
6
6
  "module": "ftable.esm.js",
@@ -6,7 +6,7 @@
6
6
 
7
7
  @import "../ftable_theme_base.less";
8
8
 
9
- .ftable_theme_base;
9
+ .ftable_theme_base();
10
10
 
11
11
  div.ftable-main-container
12
12
  {
@@ -268,12 +268,12 @@
268
268
 
269
269
  &.ftable-command-column
270
270
  {
271
- .centered;
271
+ .centered();
272
272
  }
273
273
 
274
274
  &.ftable-selecting-column
275
275
  {
276
- .centered;
276
+ .centered();
277
277
 
278
278
  input
279
279
  {
@@ -567,7 +567,7 @@
567
567
 
568
568
  ul.ftable-column-select-list
569
569
  {
570
- .clear-list-styles;
570
+ .clear-list-styles();
571
571
 
572
572
  li
573
573
  {
@@ -12,11 +12,11 @@
12
12
  font-weight: 400;
13
13
  }
14
14
 
15
- .ftable_theme_base;
15
+ .ftable_theme_base();
16
16
 
17
17
  div.ftable-main-container
18
18
  {
19
- .default-font;
19
+ .default-font();
20
20
  color: #222;
21
21
 
22
22
  div.ftable-title
@@ -74,7 +74,7 @@
74
74
 
75
75
  .ftable_metro_base( @theme-folder, @main-theme-color )
76
76
  {
77
- .ftable_theme_base; //Inherit from ftable_theme_base
77
+ .ftable_theme_base(); //Inherit from ftable_theme_base
78
78
 
79
79
  // Variables //////////////////////////////////////////////////////////////
80
80