@liedekef/ftable 1.3.5 → 1.3.6

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
@@ -622,124 +622,46 @@ class FTableFormBuilder {
622
622
  this.options = options;
623
623
  this.dependencies = new Map(); // Track field dependencies
624
624
  this.optionsCache = new FTableOptionsCache();
625
- this.originalFieldOptions = new Map(); // Store original field.options
626
- this.resolvedFieldOptions = new Map(); // Store resolved options per context
627
-
628
- // Initialize with empty cache objects
629
- Object.keys(this.options.fields || {}).forEach(fieldName => {
630
- this.resolvedFieldOptions.set(fieldName, {});
631
- });
632
- Object.entries(this.options.fields).forEach(([fieldName, field]) => {
633
- this.originalFieldOptions.set(fieldName, {
634
- options: field.options,
635
- searchOptions: field.searchOptions
636
- });
637
- });
638
625
  }
639
626
 
640
- // Get options for specific context
627
+ // Get options for a field, respecting context ('search' prefers searchOptions over options).
628
+ // URL-level caching and concurrent-request deduplication is handled by FTableOptionsCache
629
+ // inside resolveOptions
641
630
  async getFieldOptions(fieldName, context = 'table', params = {}) {
642
631
  const field = this.options.fields[fieldName];
643
- const stored = this.originalFieldOptions.get(fieldName);
644
632
 
645
- // Determine which options source to use for this context
646
- let originalOptions;
647
- if (context === 'search') {
648
- // Prefer searchOptions; fall back to regular options
649
- originalOptions = stored?.searchOptions ?? stored?.options;
650
- } else {
651
- originalOptions = stored?.options;
652
- }
633
+ // For search context, prefer searchOptions and fall back to options
634
+ const optionsSource = (context === 'search')
635
+ ? (field.searchOptions ?? field.options)
636
+ : field.options;
653
637
 
654
- // If no options or already resolved for this context with same params, return cached
655
- if (!originalOptions) {
656
- return null;
657
- }
638
+ if (!optionsSource) return null;
658
639
 
659
- // Determine if we should skip caching for this specific context
660
- const shouldSkipCache = this.shouldForceRefreshForContext(field, context, params);
661
- const cacheKey = this.generateOptionsCacheKey(context, params);
662
- // Skip cache if configured or forceRefresh requested
663
- if (!shouldSkipCache && !params.forceRefresh) {
664
- const cached = this.resolvedFieldOptions.get(fieldName)[cacheKey];
665
- if (cached) return cached;
666
- }
640
+ const noCache = this.shouldSkipCache(field, context, params);
667
641
 
668
642
  try {
669
- // Create temp field with original options for resolution
670
- const tempField = { ...field, options: originalOptions };
671
- const resolved = await this.resolveOptions(tempField, {
672
- ...params
673
- }, context, shouldSkipCache);
674
-
675
- // we store the resolved option always
676
- this.resolvedFieldOptions.get(fieldName)[cacheKey] = resolved;
677
- return resolved;
643
+ return await this.resolveOptions(
644
+ { ...field, options: optionsSource },
645
+ params,
646
+ context,
647
+ noCache
648
+ );
678
649
  } catch (err) {
679
650
  console.error(`Failed to resolve options for ${fieldName} (${context}):`, err);
680
- return originalOptions;
681
- }
682
- }
683
-
684
- /**
685
- * Clear resolved options for specific field or all fields
686
- * @param {string|null} fieldName - Field name to clear, or null for all fields
687
- * @param {string|null} context - Context to clear ('table', 'create', 'edit'), or null for all contexts
688
- */
689
- clearResolvedOptions(fieldName = null, context = null) {
690
- if (fieldName) {
691
- // Clear specific field
692
- if (this.resolvedFieldOptions.has(fieldName)) {
693
- if (context) {
694
- // Clear specific context for specific field
695
- this.resolvedFieldOptions.get(fieldName)[context] = null;
696
- } else {
697
- // Clear all contexts for specific field
698
- this.resolvedFieldOptions.set(fieldName, { table: null, create: null, edit: null });
699
- }
700
- }
701
- } else {
702
- // Clear all fields
703
- if (context) {
704
- // Clear specific context for all fields
705
- this.resolvedFieldOptions.forEach((value, key) => {
706
- this.resolvedFieldOptions.get(key)[context] = null;
707
- });
708
- } else {
709
- // Clear everything
710
- this.resolvedFieldOptions.forEach((value, key) => {
711
- this.resolvedFieldOptions.set(key, { table: null, create: null, edit: null });
712
- });
713
- }
651
+ return optionsSource;
714
652
  }
715
653
  }
716
654
 
717
- // Helper method to determine caching behavior
718
- shouldForceRefreshForContext(field, context, params) {
719
- // Rename to reflect what it actually does now
655
+ // Determine whether to bypass the URL cache for this field/context
656
+ shouldSkipCache(field, context, params) {
657
+ if (params.forceRefresh) return true;
720
658
  if (!field.noCache) return false;
721
-
722
659
  if (typeof field.noCache === 'boolean') return field.noCache;
723
660
  if (typeof field.noCache === 'function') return field.noCache({ context, ...params });
724
661
  if (typeof field.noCache === 'object') return field.noCache[context] === true;
725
-
726
662
  return false;
727
663
  }
728
664
 
729
- generateOptionsCacheKey(context, params) {
730
- // Create a unique key based on context and dependency values
731
- const keyParts = [context];
732
-
733
- if (params.dependedValues) {
734
- // Include relevant dependency values in the cache key
735
- Object.keys(params.dependedValues).sort().forEach(key => {
736
- keyParts.push(`${key}=${params.dependedValues[key]}`);
737
- });
738
- }
739
-
740
- return keyParts.join('|');
741
- }
742
-
743
665
  shouldIncludeField(field, formType) {
744
666
  if (formType === 'create') {
745
667
  return field.create !== false && !(field.key === true && field.create !== true);
@@ -812,12 +734,6 @@ class FTableFormBuilder {
812
734
  return form;
813
735
  }
814
736
 
815
- shouldResolveOptions(options) {
816
- return options &&
817
- (typeof options === 'function' || typeof options === 'string') &&
818
- !Array.isArray(options) &&
819
- !(typeof options === 'object' && !Array.isArray(options) && Object.keys(options).length > 0);
820
- }
821
737
 
822
738
  buildDependencyMap() {
823
739
  this.dependencies.clear();
@@ -2176,13 +2092,13 @@ class FTable extends FTableEventEmitter {
2176
2092
  }
2177
2093
 
2178
2094
  // Start resolving in background
2179
- this.resolveAsyncFieldOptions().then(() => {
2095
+ this.resolveAllFieldOptionsForTable().then(() => {
2180
2096
  // re-render dynamic options rows — no server call
2181
2097
  // this is needed so that once options are resolved, the table shows correct display values
2182
2098
  // why: load() can actually finish faster than option resolving (and calling refreshDisplayValues
2183
2099
  // there is then pointless, since the resolving hasn't finished yet),
2184
2100
  // so we need to do it when the options are actually resolved (here)
2185
- // We could call await this.resolveAsyncFieldOptions() during load, but that would slow down the loading ...
2101
+ // We could call await this.resolveAllFieldOptionsForTable() during load, but that would slow down the loading ...
2186
2102
  setTimeout(() => {
2187
2103
  this.refreshDisplayValues();
2188
2104
  }, 0);
@@ -2403,22 +2319,17 @@ class FTable extends FTableEventEmitter {
2403
2319
  }
2404
2320
  }
2405
2321
 
2406
- async resolveAsyncFieldOptions() {
2322
+ async resolveAllFieldOptionsForTable() {
2323
+ this.tableOptionsCache = new Map();
2324
+
2407
2325
  const promises = this.columnList.map(async (fieldName) => {
2408
2326
  const field = this.options.fields[fieldName];
2409
2327
  if (field.action) return; // Skip action columns
2410
- const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName)?.options;
2411
-
2412
- if (this.formBuilder.shouldResolveOptions(originalOptions)) {
2413
- try {
2414
- // Check if already resolved to avoid duplicate work
2415
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2416
- if (!this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey]) {
2417
- await this.formBuilder.getFieldOptions(fieldName, 'table');
2418
- }
2419
- } catch (err) {
2420
- console.error(`Failed to resolve table options for ${fieldName}:`, err);
2421
- }
2328
+ try {
2329
+ const resolved = await this.formBuilder.getFieldOptions(fieldName, 'table');
2330
+ if (resolved) this.tableOptionsCache.set(fieldName, resolved);
2331
+ } catch (err) {
2332
+ console.error(`Failed to resolve table options for ${fieldName}:`, err);
2422
2333
  }
2423
2334
  });
2424
2335
 
@@ -2437,9 +2348,7 @@ class FTable extends FTableEventEmitter {
2437
2348
  const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
2438
2349
  if (!cell) continue;
2439
2350
 
2440
- // Get table-specific options
2441
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2442
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
2351
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
2443
2352
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
2444
2353
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
2445
2354
  }
@@ -4025,8 +3934,7 @@ class FTable extends FTableEventEmitter {
4025
3934
 
4026
3935
  addDataCell(row, record, fieldName) {
4027
3936
  const field = this.options.fields[fieldName];
4028
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4029
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
3937
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4030
3938
  const value = this.getDisplayText(record, fieldName, resolvedOptions);
4031
3939
 
4032
3940
  const cell = FTableDOMHelper.create('td', {
@@ -4529,8 +4437,7 @@ class FTable extends FTableEventEmitter {
4529
4437
  if (!cell) return;
4530
4438
 
4531
4439
  // Get display text
4532
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4533
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
4440
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4534
4441
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
4535
4442
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
4536
4443
  cell.className = `${field.listClass || ''} ${field.listClassEntry || ''}`.trim();
package/ftable.js CHANGED
@@ -623,124 +623,46 @@ class FTableFormBuilder {
623
623
  this.options = options;
624
624
  this.dependencies = new Map(); // Track field dependencies
625
625
  this.optionsCache = new FTableOptionsCache();
626
- this.originalFieldOptions = new Map(); // Store original field.options
627
- this.resolvedFieldOptions = new Map(); // Store resolved options per context
628
-
629
- // Initialize with empty cache objects
630
- Object.keys(this.options.fields || {}).forEach(fieldName => {
631
- this.resolvedFieldOptions.set(fieldName, {});
632
- });
633
- Object.entries(this.options.fields).forEach(([fieldName, field]) => {
634
- this.originalFieldOptions.set(fieldName, {
635
- options: field.options,
636
- searchOptions: field.searchOptions
637
- });
638
- });
639
626
  }
640
627
 
641
- // Get options for specific context
628
+ // Get options for a field, respecting context ('search' prefers searchOptions over options).
629
+ // URL-level caching and concurrent-request deduplication is handled by FTableOptionsCache
630
+ // inside resolveOptions
642
631
  async getFieldOptions(fieldName, context = 'table', params = {}) {
643
632
  const field = this.options.fields[fieldName];
644
- const stored = this.originalFieldOptions.get(fieldName);
645
633
 
646
- // Determine which options source to use for this context
647
- let originalOptions;
648
- if (context === 'search') {
649
- // Prefer searchOptions; fall back to regular options
650
- originalOptions = stored?.searchOptions ?? stored?.options;
651
- } else {
652
- originalOptions = stored?.options;
653
- }
634
+ // For search context, prefer searchOptions and fall back to options
635
+ const optionsSource = (context === 'search')
636
+ ? (field.searchOptions ?? field.options)
637
+ : field.options;
654
638
 
655
- // If no options or already resolved for this context with same params, return cached
656
- if (!originalOptions) {
657
- return null;
658
- }
639
+ if (!optionsSource) return null;
659
640
 
660
- // Determine if we should skip caching for this specific context
661
- const shouldSkipCache = this.shouldForceRefreshForContext(field, context, params);
662
- const cacheKey = this.generateOptionsCacheKey(context, params);
663
- // Skip cache if configured or forceRefresh requested
664
- if (!shouldSkipCache && !params.forceRefresh) {
665
- const cached = this.resolvedFieldOptions.get(fieldName)[cacheKey];
666
- if (cached) return cached;
667
- }
641
+ const noCache = this.shouldSkipCache(field, context, params);
668
642
 
669
643
  try {
670
- // Create temp field with original options for resolution
671
- const tempField = { ...field, options: originalOptions };
672
- const resolved = await this.resolveOptions(tempField, {
673
- ...params
674
- }, context, shouldSkipCache);
675
-
676
- // we store the resolved option always
677
- this.resolvedFieldOptions.get(fieldName)[cacheKey] = resolved;
678
- return resolved;
644
+ return await this.resolveOptions(
645
+ { ...field, options: optionsSource },
646
+ params,
647
+ context,
648
+ noCache
649
+ );
679
650
  } catch (err) {
680
651
  console.error(`Failed to resolve options for ${fieldName} (${context}):`, err);
681
- return originalOptions;
682
- }
683
- }
684
-
685
- /**
686
- * Clear resolved options for specific field or all fields
687
- * @param {string|null} fieldName - Field name to clear, or null for all fields
688
- * @param {string|null} context - Context to clear ('table', 'create', 'edit'), or null for all contexts
689
- */
690
- clearResolvedOptions(fieldName = null, context = null) {
691
- if (fieldName) {
692
- // Clear specific field
693
- if (this.resolvedFieldOptions.has(fieldName)) {
694
- if (context) {
695
- // Clear specific context for specific field
696
- this.resolvedFieldOptions.get(fieldName)[context] = null;
697
- } else {
698
- // Clear all contexts for specific field
699
- this.resolvedFieldOptions.set(fieldName, { table: null, create: null, edit: null });
700
- }
701
- }
702
- } else {
703
- // Clear all fields
704
- if (context) {
705
- // Clear specific context for all fields
706
- this.resolvedFieldOptions.forEach((value, key) => {
707
- this.resolvedFieldOptions.get(key)[context] = null;
708
- });
709
- } else {
710
- // Clear everything
711
- this.resolvedFieldOptions.forEach((value, key) => {
712
- this.resolvedFieldOptions.set(key, { table: null, create: null, edit: null });
713
- });
714
- }
652
+ return optionsSource;
715
653
  }
716
654
  }
717
655
 
718
- // Helper method to determine caching behavior
719
- shouldForceRefreshForContext(field, context, params) {
720
- // Rename to reflect what it actually does now
656
+ // Determine whether to bypass the URL cache for this field/context
657
+ shouldSkipCache(field, context, params) {
658
+ if (params.forceRefresh) return true;
721
659
  if (!field.noCache) return false;
722
-
723
660
  if (typeof field.noCache === 'boolean') return field.noCache;
724
661
  if (typeof field.noCache === 'function') return field.noCache({ context, ...params });
725
662
  if (typeof field.noCache === 'object') return field.noCache[context] === true;
726
-
727
663
  return false;
728
664
  }
729
665
 
730
- generateOptionsCacheKey(context, params) {
731
- // Create a unique key based on context and dependency values
732
- const keyParts = [context];
733
-
734
- if (params.dependedValues) {
735
- // Include relevant dependency values in the cache key
736
- Object.keys(params.dependedValues).sort().forEach(key => {
737
- keyParts.push(`${key}=${params.dependedValues[key]}`);
738
- });
739
- }
740
-
741
- return keyParts.join('|');
742
- }
743
-
744
666
  shouldIncludeField(field, formType) {
745
667
  if (formType === 'create') {
746
668
  return field.create !== false && !(field.key === true && field.create !== true);
@@ -813,12 +735,6 @@ class FTableFormBuilder {
813
735
  return form;
814
736
  }
815
737
 
816
- shouldResolveOptions(options) {
817
- return options &&
818
- (typeof options === 'function' || typeof options === 'string') &&
819
- !Array.isArray(options) &&
820
- !(typeof options === 'object' && !Array.isArray(options) && Object.keys(options).length > 0);
821
- }
822
738
 
823
739
  buildDependencyMap() {
824
740
  this.dependencies.clear();
@@ -2177,13 +2093,13 @@ class FTable extends FTableEventEmitter {
2177
2093
  }
2178
2094
 
2179
2095
  // Start resolving in background
2180
- this.resolveAsyncFieldOptions().then(() => {
2096
+ this.resolveAllFieldOptionsForTable().then(() => {
2181
2097
  // re-render dynamic options rows — no server call
2182
2098
  // this is needed so that once options are resolved, the table shows correct display values
2183
2099
  // why: load() can actually finish faster than option resolving (and calling refreshDisplayValues
2184
2100
  // there is then pointless, since the resolving hasn't finished yet),
2185
2101
  // so we need to do it when the options are actually resolved (here)
2186
- // We could call await this.resolveAsyncFieldOptions() during load, but that would slow down the loading ...
2102
+ // We could call await this.resolveAllFieldOptionsForTable() during load, but that would slow down the loading ...
2187
2103
  setTimeout(() => {
2188
2104
  this.refreshDisplayValues();
2189
2105
  }, 0);
@@ -2404,22 +2320,17 @@ class FTable extends FTableEventEmitter {
2404
2320
  }
2405
2321
  }
2406
2322
 
2407
- async resolveAsyncFieldOptions() {
2323
+ async resolveAllFieldOptionsForTable() {
2324
+ this.tableOptionsCache = new Map();
2325
+
2408
2326
  const promises = this.columnList.map(async (fieldName) => {
2409
2327
  const field = this.options.fields[fieldName];
2410
2328
  if (field.action) return; // Skip action columns
2411
- const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName)?.options;
2412
-
2413
- if (this.formBuilder.shouldResolveOptions(originalOptions)) {
2414
- try {
2415
- // Check if already resolved to avoid duplicate work
2416
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2417
- if (!this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey]) {
2418
- await this.formBuilder.getFieldOptions(fieldName, 'table');
2419
- }
2420
- } catch (err) {
2421
- console.error(`Failed to resolve table options for ${fieldName}:`, err);
2422
- }
2329
+ try {
2330
+ const resolved = await this.formBuilder.getFieldOptions(fieldName, 'table');
2331
+ if (resolved) this.tableOptionsCache.set(fieldName, resolved);
2332
+ } catch (err) {
2333
+ console.error(`Failed to resolve table options for ${fieldName}:`, err);
2423
2334
  }
2424
2335
  });
2425
2336
 
@@ -2438,9 +2349,7 @@ class FTable extends FTableEventEmitter {
2438
2349
  const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
2439
2350
  if (!cell) continue;
2440
2351
 
2441
- // Get table-specific options
2442
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2443
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
2352
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
2444
2353
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
2445
2354
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
2446
2355
  }
@@ -4026,8 +3935,7 @@ class FTable extends FTableEventEmitter {
4026
3935
 
4027
3936
  addDataCell(row, record, fieldName) {
4028
3937
  const field = this.options.fields[fieldName];
4029
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4030
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
3938
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4031
3939
  const value = this.getDisplayText(record, fieldName, resolvedOptions);
4032
3940
 
4033
3941
  const cell = FTableDOMHelper.create('td', {
@@ -4530,8 +4438,7 @@ class FTable extends FTableEventEmitter {
4530
4438
  if (!cell) return;
4531
4439
 
4532
4440
  // Get display text
4533
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4534
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
4441
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4535
4442
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
4536
4443
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
4537
4444
  cell.className = `${field.listClass || ''} ${field.listClassEntry || ''}`.trim();
package/ftable.min.js CHANGED
@@ -1,4 +1,4 @@
1
- (e=>{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?",yes:"Yes",no:"No",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",warning:"Warning",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,this.pendingRequests=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()}async getOrCreate(e,t,s){let a=this.generateKey(e,t);e=this.cache.get(a);return e||(this.pendingRequests.has(a)?this.pendingRequests.get(a):(t=(async()=>{try{var e=await s();return this.cache.set(a,e),e}finally{this.pendingRequests.delete(a)}})(),this.pendingRequests.set(a,t),t))}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 O{static PROPERTY_ATTRIBUTES=new Set(["value","checked","selected","disabled","readOnly","name","id","type","placeholder","min","max","step","required","multiple","accept","className","textContent","innerHTML","title"]);static create(e,t={}){let s=document.createElement(e);return void 0!==t.style&&(s.style.cssText=t.style),O.PROPERTY_ATTRIBUTES.forEach(e=>{e in t&&null!==t[e]&&(s[e]=t[e])}),void 0!==t.parent&&t.parent.appendChild(s),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{null!==t&&(O.PROPERTY_ATTRIBUTES.has(e)?s[e]=t:s.setAttribute(e,t))}),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.endsWith("[]")?e:e+"[]";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.endsWith("[]")?e:e+"[]";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 o{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=O.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=O.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});O.create("h2",{className:"ftable-modal-header",textContent:this.options.title,parent:this.modal});O.create("span",{className:"ftable-modal-close",innerHTML:"&times;",parent:this.modal}).addEventListener("click",()=>this.close());var e=O.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=O.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=O.create("button",{className:"ftable-dialog-button "+(e.className||""),innerHTML:`<span>${e.text}</span>`,parent:s});e.onClick&&(t._originalOnClick=e.onClick,t.addEventListener("click",this._createWrappedClickHandler(t)))})}return this.options.closeOnOverlayClick&&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.modal.querySelectorAll(".ftable-dialog-button").forEach(e=>{e.disabled=!1}),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=/<(div|ul|ol|table|p|h[1-6]|blockquote)/i.test(e)?e:`<p>${e}</p>`:t.appendChild(e))}_createWrappedClickHandler(a){return async e=>{a.disabled=!0;try{var t,s=a._originalOnClick;"function"==typeof s&&(t=s.call(a,e))instanceof Promise&&await t}catch(e){console.error("Modal button action failed:",e)}finally{a.disabled=!1}}}}class r{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t,this.originalFieldOptions=new Map,this.resolvedFieldOptions=new Map,Object.keys(this.options.fields||{}).forEach(e=>{this.resolvedFieldOptions.set(e,{})}),Object.entries(this.options.fields).forEach(([e,t])=>{this.originalFieldOptions.set(e,{options:t.options,searchOptions:t.searchOptions})})}async getFieldOptions(t,s="table",e={}){var a=this.options.fields[t],i=this.originalFieldOptions.get(t);let o;if(!(o="search"===s?i?.searchOptions??i?.options:i?.options))return null;var i=this.shouldForceRefreshForContext(a,s,e),r=this.generateOptionsCacheKey(s,e);if(!i&&!e.forceRefresh){var n=this.resolvedFieldOptions.get(t)[r];if(n)return n}try{var l={...a,options:o},c=await this.resolveOptions(l,{...e},s,i);return this.resolvedFieldOptions.get(t)[r]=c}catch(e){return console.error(`Failed to resolve options for ${t} (${s}):`,e),o}}clearResolvedOptions(e=null,s=null){e?this.resolvedFieldOptions.has(e)&&(s?this.resolvedFieldOptions.get(e)[s]=null:this.resolvedFieldOptions.set(e,{table:null,create:null,edit:null})):s?this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.get(t)[s]=null}):this.resolvedFieldOptions.forEach((e,t)=>{this.resolvedFieldOptions.set(t,{table:null,create:null,edit:null})})}shouldForceRefreshForContext(e,t,s){return!!e.noCache&&("boolean"==typeof e.noCache?e.noCache:"function"==typeof e.noCache?e.noCache({context:t,...s}):"object"==typeof e.noCache&&!0===e.noCache[t])}generateOptionsCacheKey(e,t){let s=[e];return t.dependedValues&&Object.keys(t.dependedValues).sort().forEach(e=>{s.push(e+"="+t.dependedValues[e])}),s.join("|")}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=O.create("div",{className:"hidden"!=t.type?"ftable-input-field-container":"",attributes:{id:"ftable-input-field-container-div-"+e}}),t=("hidden"!=t.type&&O.create("div",{className:"ftable-input-label",textContent:t.inputTitle||t.title,parent:i}),this.createInput(e,t,s[e],a));return i.appendChild(t),i}async createForm(e="create",t={}){this.currentFormRecord=t;var s,a,i,o,r=O.create("form",{className:`ftable-dialog-form ftable-${e}-form`});this.buildDependencyMap();for([s,a]of Object.entries(this.options.fields))this.shouldIncludeField(a,e)&&(i={...a},a.dependsOn?i.options=a.options:(o=await this.getFieldOptions(s,e,{record:t,source:e}),i.options=o),o=this.createFieldContainer(s,i,t,e),r.appendChild(o));return this.setupDependencyListeners(r),r}shouldResolveOptions(e){return e&&("function"==typeof e||"string"==typeof e)&&!Array.isArray(e)&&!("object"==typeof e&&!Array.isArray(e)&&0<Object.keys(e).length)}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(e,t={},s="",a=!1){if(!e.options)return[];if(Array.isArray(e.options)||"object"==typeof e.options)return e.options;let i;t={...t,source:s,clearCache:()=>{a=!0,this.updateFieldCacheSetting(e,s,!0)}};if("function"==typeof e.options)i=await e.options(t);else{if("string"!=typeof e.options)return[];i=e.options}t=i&&"object"==typeof i&&i.url;let o=t?i.url:i;if(a=t&&void 0!==i.noCache?i.noCache:a,"string"!=typeof o)return[];if(!a)return this.optionsCache.getOrCreate(o,{},async()=>{try{var e=this.options.forcePost?await l.post(o):await l.get(o);return e.Options||e.options||e||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}});try{var r=this.options.forcePost?await l.post(o):await l.get(o);return r.Options||r.options||r||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}}updateFieldCacheSetting(e,t,s){e.noCache?"boolean"==typeof e.noCache?e.noCache={table:e.noCache,create:e.noCache,edit:e.noCache,[t]:s}:"object"==typeof e.noCache&&(e.noCache[t]=s):e.noCache={[t]:s}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}getFormValues(e){var t={},s=e.elements;for(let e=0;e<s.length;e++){var a=s[e],i=a.name;if(i&&!a.disabled)switch(a.type){case"checkbox":t[i]=a.checked?a.value||"1":"0";break;case"radio":a.checked&&(t[i]=a.value);break;case"select-multiple":t[i]=Array.from(a.selectedOptions).map(e=>e.value);break;default:t[i]=a.value}}return t}async handleDependencyChange(e,s=""){var a,i,o=this.getFormValues(e),r=e.classList.contains("ftable-create-form")?"create":"edit",n=this.currentFormRecord||{},l={record:n,source:r,form:e,dependedValues:o};for([a,i]of Object.entries(this.options.fields))if(i.dependsOn){if(""!==s)if(!i.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(s))continue;let t=e.querySelector(`[name="${a}"]`);if(t&&this.shouldIncludeField(i,r))try{"SELECT"===t.tagName?t.innerHTML='<option value="">Loading...</option>':"INPUT"===t.tagName&&t.list&&(c=document.getElementById(t.list.id))&&(c.innerHTML="");var c,d=t.value||n[a]||"",h={...l,dependsOnField:i.dependsOn,dependsOnValue:o[i.dependsOn]},p=await this.getFieldOptions(a,r,h);"SELECT"===t.tagName?this.populateSelectOptions(t,p,d):"INPUT"===t.tagName&&t.list&&(this.populateDatalistOptions(t.list,p),d)&&(t.value=d),setTimeout(()=>{t.dispatchEvent(new Event("change",{bubbles:!0}))},0)}catch(e){console.error(`Error loading options for ${a}:`,e),"SELECT"===t.tagName&&(t.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=O.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null===(s=void 0===s?null:s)&&t.defaultValue&&(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":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),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement))):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement)),t.explain&&O.create("div",{className:"ftable-field-explain",innerHTML:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(s,a,i){if("undefined"==typeof FDatepicker)return createTypedInput(s,a,i);{let e=a.dateFormat||this.options.defaultDateFormat;var o,r=document.createElement("div"),n=O.create("input",{id:"real-"+s,type:"hidden",value:i,name:s}),i={"data-date":i};a.inputAttributes&&(o=this.parseInputAttributes(a.inputAttributes),Object.assign(i,o));let t=O.create("input",{attributes:i,id:"Edit-"+s,type:"text",placeholder:a.placeholder||null,className:a.inputClass||"datepicker-input",readOnly:!0});switch(r.appendChild(n),r.appendChild(t),a.type){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"real-"+s,altFormat:"Y-m-d"})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"real-"+s,altFormat:"Y-m-d H:i:00"})},0)}return r}}createTypedInput(e,t,s){var a,i=t.type||"text",o={};let r=e,n=(t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(o,a),void 0!==a.multiple&&!1!==a.multiple)&&(r=e+"[]"),O.create("input",{attributes:o,type:i,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s,name:r}));return n.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),n.dispatchEvent(new Event("change",{bubbles:!0})),!1}),n}createDatalistInput(e,t,s){var a={list:e+"-datalist"},i=(t.inputAttributes&&(i=this.parseInputAttributes(t.inputAttributes),Object.assign(a,i)),O.create("input",{attributes:a,type:"search",name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})),a=O.create("datalist",{id:e+"-datalist"});return t.options&&this.populateDatalistOptions(a,t.options),i.datalistElement=a,i}populateDatalistOptions(s,e){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{O.create("option",{value:e.Value||e.value||e,textContent:e.DisplayText||e.text||e,parent:s})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:s})})}createHiddenInput(e,t,s){var a={};return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(a,t)),O.create("input",{attributes:a,type:"hidden",name:e,id:"Edit-"+e,value:s})}createTextarea(e,t,s){var a,i={};return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a)),O.create("textarea",{attributes:i,name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:s})}createSelect(e,t,s){var a={};let i=e,o=!1;if(t.inputAttributes&&(r=this.parseInputAttributes(t.inputAttributes),Object.assign(a,r),o=void 0!==r.multiple&&!1!==r.multiple)&&(i=e+"[]"),o)return this.createCustomMultiSelect(e,t,s,a,i);a.name=i;var r=O.create("select",{attributes:a,name:e,id:"Edit-"+e,className:t.inputClass||null});return t.options&&this.populateSelectOptions(r,t.options,s),r}createCustomMultiSelect(e,t,s,a,i){var o=Array.isArray(t.options)?t.options:t.options&&"object"==typeof t.options?Object.entries(t.options).map(([e,t])=>({Value:e,DisplayText:t})):[],r=t.livesearch??!1;return this._buildCustomMultiSelect({containerId:e,hiddenSelectId:"Edit-"+e,hiddenSelectName:i,extraClasses:"",containerDataFieldName:e,hiddenSelectAttributes:{},optionsSource:o,initialValues:Array.isArray(s)?s:s?s.toString().split(",").filter(e=>e):[],placeholderText:t.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:r,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!0})}_buildCustomMultiSelect(e){let{hiddenSelectId:t,hiddenSelectName:s,extraClasses:a,containerDataFieldName:i,hiddenSelectAttributes:o,optionsSource:r,initialValues:n,placeholderText:l,livesearch:c,onChangeExtra:d,buildHiddenSelectOnUpdate:h}=e;let p=(e=r)?(Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({Value:e,DisplayText:t}))).map(e=>({optValue:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,optText:e.DisplayText||e.text||e,groupLabel:e.Group||e.group||null})).filter(e=>null!=e.optValue&&""!==e.optValue):[],u=new Map(p.map(e=>[e.optValue.toString(),e.optText]));e=["ftable-multiselect-container",...a.split(" ").filter(Boolean)].join(" ");let m=O.create("div",{className:e,attributes:{"data-field-name":i}}),f=O.create("select",{id:t,name:s,multiple:!0,style:"display: none;",attributes:o}),g=(m.appendChild(f),m.hiddenSelect=f,O.create("div",{className:"ftable-multiselect-display",parent:m,attributes:{tabindex:"0"}})),b=O.create("div",{className:"ftable-multiselect-selected",parent:g}),v=O.create("span",{className:"ftable-multiselect-placeholder",textContent:l,parent:b}),y=(O.create("button",{type:"button",className:"ftable-multiselect-toggle",innerHTML:"▼",parent:g,attributes:{tabindex:"-1"}}),null),w=null,C=new Set(n.map(e=>e.toString())),S=new Map,E=(h||p.forEach(({optValue:e,optText:t})=>{O.create("option",{value:e,textContent:t,parent:f})}),()=>{b.innerHTML="",h?(f.innerHTML="",C.forEach(e=>{var t=u.get(e)??e;O.create("option",{value:e,textContent:t,selected:!0,parent:f})})):Array.from(f.options).forEach(e=>{e.selected=C.has(e.value)}),0===C.size?(v.textContent=l,b.appendChild(v)):C.forEach(t=>{var e=O.create("span",{className:"ftable-multiselect-tag",parent:b});O.create("span",{className:"ftable-multiselect-tag-text",textContent:u.get(t)||t,parent:e}),O.create("span",{className:"ftable-multiselect-tag-remove",innerHTML:"×",parent:e}).addEventListener("click",e=>{e.stopPropagation(),C.delete(t);e=S.get(t);e&&(e.checked=!1),E(),d&&d(f)})}),d&&d(f)}),x=()=>{g.focus(),y&&(y.remove(),y=null),w&&(w.remove(),w=null),m._cleanupHandlers&&(m._cleanupHandlers(),m._cleanupHandlers=null)},A=()=>{var e,t,s;y&&(e=g.getBoundingClientRect(),s=window.pageYOffset||document.documentElement.scrollTop,t=window.pageXOffset||document.documentElement.scrollLeft,t=e.left+t,s=e.bottom+s+4,Object.assign(y.style,{position:"absolute",left:t+"px",top:s+"px",width:e.width+"px",minWidth:"fit-content",boxSizing:"border-box",zIndex:"10000"}),(s=y.getBoundingClientRect()).right>window.innerWidth)&&(t=Math.max(10,window.innerWidth-s.width-10),y.style.left=t+"px")},N=(e="")=>{if(y){Array.from(y.querySelectorAll(".ftable-multiselect-option, .ftable-multiselect-optgroup")).forEach(e=>e.remove());let t=e.toLowerCase();e=e?p.filter(e=>e.optText.toLowerCase().includes(t)):p;let i=new Set,o=null;e.forEach(({optValue:t,optText:e,groupLabel:s})=>{s&&s!==i[i.size-1]?i.has(s)||(i.add(s),o=O.create("div",{className:"ftable-multiselect-optgroup",textContent:s,parent:y})):s||(o=null);s=O.create("div",{className:"ftable-multiselect-option",parent:y});let a=O.create("input",{type:"checkbox",className:"ftable-multiselect-checkbox",checked:C.has(t.toString()),parent:s});S.set(t.toString(),a),O.create("label",{className:"ftable-multiselect-label",textContent:e,parent:s}),s.addEventListener("click",e=>{e.stopPropagation();e=t.toString();C.has(e)?(C.delete(e),a.checked=!1):(C.add(e),a.checked=!0),E()})})}},L=a=>{if(a&&a.stopPropagation(),y)x();else{if(document.querySelectorAll(".ftable-multiselect-dropdown").forEach(e=>e.remove()),document.querySelectorAll(".ftable-multiselect-overlay").forEach(e=>e.remove()),w=O.create("div",{className:"ftable-multiselect-overlay",parent:document.body}),y=O.create("div",{className:"ftable-multiselect-dropdown",parent:document.body,attributes:{tabindex:"-1",role:"listbox","aria-multiselectable":"true"}}),c){a=O.create("div",{className:"ftable-multiselect-livesearch-wrap",parent:y});let e=O.create("input",{type:"search",className:"ftable-multiselect-livesearch",placeholder:"Search...",parent:a,attributes:{autocomplete:"off"}});e.addEventListener("input",()=>{N(e.value)}),e.addEventListener("click",e=>e.stopPropagation()),setTimeout(()=>e.focus(),0)}N(),A(),c||y.focus(),y.addEventListener("keydown",e=>{var t,s;"Escape"===e.key?x():"ArrowDown"===e.key||"ArrowUp"===e.key?(e.preventDefault(),s=(t=Array.from(y.querySelectorAll(".ftable-multiselect-checkbox"))).indexOf(document.activeElement),t["ArrowDown"===e.key?s<t.length-1?s+1:0:0<s?s-1:t.length-1]?.focus()):" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),document.activeElement.classList.contains("ftable-multiselect-checkbox")&&document.activeElement.click())}),w.addEventListener("click",e=>{e.target===w&&x()});let e=()=>A(),t=e=>{y&&y.contains(e.target)||A()},s=new ResizeObserver(()=>A());window.addEventListener("scroll",t,!0),window.addEventListener("resize",e),s.observe(b),m._cleanupHandlers=()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",e),s.disconnect()}}},T=(g.addEventListener("click",L),g.querySelector(".ftable-multiselect-toggle").addEventListener("click",L),g.addEventListener("keydown",e=>{"ArrowDown"!==e.key&&"Enter"!==e.key||(e.preventDefault(),L())}),m.resetMultiSelect=()=>{C.clear(),S.forEach(e=>{e.checked=!1}),x(),E()},new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{(e===m||e.contains&&e.contains(m))&&(x(),T.disconnect())})})}));return setTimeout(()=>{m.parentNode&&T.observe(m.parentNode,{childList:!0,subtree:!0})},0),E(),m}createRadioGroup(o,r,n){let l=O.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=O.create("div",{className:"ftable-radio-wrapper",parent:l}),t=o+"_"+t,a={},i=(r.inputAttributes&&(i=this.parseInputAttributes(r.inputAttributes),Object.assign(a,i)),void 0!==e.Value?e.Value:void 0!==e.value?e.value:e);O.create("input",{attributes:a,type:"radio",name:o,id:t,value:i,className:r.inputClass||null,checked:i==n,parent:s}),O.create("label",{attributes:{for:t},textContent:e.DisplayText||e.text||e,parent:s})}),l}createCheckbox(e,t,s){var a=O.create("div",{className:"ftable-yesno-check-wrapper"}),s=[1,"1",!0,"true"].includes(s);let i=this.options.messages.no,o=this.options.messages.yes;return t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]),O.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),type:"checkbox",name:e,id:"Edit-"+e,value:"1",parent:a}).checked=s,t.label?O.create("label",{className:"ftable-yesno-check-fixedlabel",attributes:{for:"Edit-"+e},textContent:t.label,parent:a}):O.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:a}),a}populateSelectOptions(o,e,r){if(o.innerHTML="",Array.isArray(e)){let s=new Map,a=[],i=(e.forEach(e=>{var t=e.Group||e.group||null;(t?(s.has(t)||s.set(t,[]),s.get(t)):a).push(e)}),(e,t)=>{var s=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let a=O.create("option",{value:s,textContent:e.DisplayText||e.text||e,selected:s==r,parent:t});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{a.setAttribute("data-"+e,t)})});a.forEach(e=>i(e,o)),s.forEach((e,t)=>{let s=O.create("optgroup",{attributes:{label:t},parent:o});e.forEach(e=>i(e,s))})}else"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,selected:e==r,parent:o})})}createFileInput(e,t,s){var a,i={};let o=e;return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(i,a),void 0!==a.multiple&&!1!==a.multiple)&&(o=e+"[]"),O.create("input",{type:"file",id:"Edit-"+e,name:o,className:t.inputClass||null,attributes:i})}}class n 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 r(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.shiftKeyDown=!1,this.lastSelectedRow=null,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:a.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,closeOnOverlayClick:!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,250,500],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.updateSortingHeaders(),this.renderSortingInfo(),this.initColumnWidths()}initColumnWidths(){var e=this.columnList.filter(e=>{e=this.options.fields[e];return!e.action&&"hidden"!==e.visibility&&"separator"!==e.visibility});let t=e.length;e.forEach(e=>{e=this.options.fields[e];e.width=e.width||100/t+"%"})}normalizeColumnWidths(){var e=this.elements.mainContainer,t=this.columnList.map(e=>({th:this.elements.table.querySelector(`[data-field-name="${e}"]`),field:this.options.fields[e]})).filter(e=>e.th&&!e.field.action&&"hidden"!==e.field.visibility&&"separator"!==e.field.visibility);if(0!==t.length){let s=e.offsetWidth,a=0;t.forEach(e=>{var t=e.th.offsetWidth/s*100;e.field.width=t+"%",e.th.style.width=e.field.width,a+=t})}}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}createPagingUI(){this.elements.bottomPanel=O.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=O.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=O.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=O.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=O.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=O.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=O.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});O.create("span",{textContent:this.options.messages.pageSizeChangeLabel,parent:e});let s=O.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100,250,500]).forEach(e=>{var t=O.create("option",{attributes:{value:e},textContent: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=>{var e=this.options.fields[e],t=!0===e.key;!!e.action?(e.list=!0,e.create=!1,e.edit=!1,e.sorting=!1,e.searchable=!1):t?(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._userPlacedActions=new Set(this.fieldList.filter(e=>this.options.fields[e].action).map(e=>this.options.fields[e].action)),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.info("No key field defined")}async resolveAsyncFieldOptions(){var e=this.columnList.map(async t=>{var e=this.options.fields[t];if(!e.action){e=this.formBuilder.originalFieldOptions.get(t)?.options;if(this.formBuilder.shouldResolveOptions(e))try{var s=this.formBuilder.generateOptionsCacheKey("table",{});this.formBuilder.resolvedFieldOptions.get(t)?.[s]||await this.formBuilder.getFieldOptions(t,"table")}catch(e){console.error(`Failed to resolve table options for ${t}:`,e)}}});await Promise.all(e)}async refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");if(0!==e.length)for(var t of e)for(var s of this.columnList){var a,i,o=this.options.fields[s];!o.action&&o.options&&(a=t.querySelector(`td[data-field-name="${s}"]`))&&(i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],s=this.getDisplayText(t.recordData,s,i),a.innerHTML=o.listEscapeHTML?O.escapeHtml(s):s)}}createMainStructure(){this.elements.mainContainer=O.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=O.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),O.create("div",{className:"ftable-title-text",innerHTML:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=O.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=O.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=O.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=O.create("thead",{parent:this.elements.table});let o=O.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")){var t=O.create("th",{className:"ftable-command-column-header ftable-column-header-select",parent:o});if(this.options.multiselect){let e=O.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var s=this.options.fields[t];if(s.action){var a={select:"ftable-column-header-select",update:"ftable-column-header-edit",clone:"ftable-column-header-clone",delete:"ftable-column-header-delete"};let t=O.create("th",{className:"ftable-command-column-header "+(a[s.action]||""),parent:o});if(s.title&&(t.textContent=s.title),"select"===s.action&&this.options.selecting&&this.options.selectingCheckboxes&&this.options.multiselect){let e=O.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}void(s.width&&(t.style.width=s.width))}else{let e=O.create("th",{className:`ftable-column-header ${s.listClass||""} `+(s.listClassHeader||""),attributes:{"data-field-name":t},parent:o});s.width&&(e.style.width=s.width);var a=O.create("div",{className:"ftable-column-header-container",parent:e}),i=(s.tooltip&&a.setAttribute("title",s.tooltip),O.create("span",{className:"ftable-column-header-text",innerHTML:s.title||t,parent:a}));this.options.sorting&&!1!==s.sorting&&(O.addClass(i,"ftable-sortable-text"),O.addClass(e,"ftable-column-header-sortable"),e.addEventListener("click",e=>{e.preventDefault();e=e.ctrlKey||e.metaKey;this.sortByColumn(t,e)})),!1!==this.options.columnResizable&&!1!==s.columnResizable&&this.makeColumnResizable(e,a),"hidden"!==s.visibility&&"separator"!==s.visibility||O.hide(e)}}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:o}),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:o}),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&O.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:o}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,s=O.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});for(let i of this.columnList){var o=this.options.fields[i];if(o.action)O.create("th",{className:"ftable-toolbarsearch-column-header ftable-command-column-header",parent:s});else{var r=!1!==o.searchable,n=O.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});if(r){r=O.create("div",{className:"ftable-column-header-container",parent:n});let s,a="text";o.searchType?a=o.searchType:!o.type&&o.options?a="select":o.type&&(a=o.type);var l="ftable-toolbarsearch-"+i;switch(a){case"date":case"datetime":case"datetime-local":if("undefined"!=typeof FDatepicker){let e=o.searchDateFormat||o.dateFormat||this.options.defaultDateFormat;var c=document.createElement("div"),d=O.create("input",{className:"ftable-toolbarsearch-extra",type:"hidden",id:"ftable-toolbarsearch-extra-"+i,attributes:{"data-field-name":i}});let t=O.create("input",{className:"ftable-toolbarsearch",id:"ftable-toolbarsearch-"+i,type:"text",placeholder:o.searchPlaceholder||o.placeholder||"",readOnly:!0});switch(c.appendChild(d),c.appendChild(t),a){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d",autoClose:!0})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d H:i:00"})},0)}s=c}else s=O.create("input",{className:"ftable-toolbarsearch",type:a,id:l,attributes:{"data-field-name":i}});break;case"checkbox":o.values||(o.values={0:this.options.messages.no,1:this.options.messages.yes}),s=await this.createSelectForSearch(i,o,!0);break;case"select":s=o.options?await this.createSelectForSearch(i,o,!1):O.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}});break;case"datalist":s=await this.createDatalistForSearch(i,o);break;default:s=O.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}})}if(s){r.appendChild(s),s.datalistElement&&s.datalistElement instanceof Node&&r.appendChild(s.datalistElement);let e=s;"SELECT"===(e=s.classList&&s.classList.contains("ftable-multiselect-container")&&s.hiddenSelect?s.hiddenSelect:e).tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)})}}"hidden"!==o.visibility&&"separator"!==o.visibility||O.hide(n)}}this.options.toolbarsearch&&this.options.toolbarreset&&(e=O.create("th",{className:"ftable-toolbarsearch-column-header ftable-toolbarsearch-reset",parent:s}),0<(t=(this.options.actions.updateAction&&!this._userPlacedActions.has("update")?1:0)+(this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")?1:0)+(this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")?1:0))?e.colSpan=t:O.addClass(e,"ftable-command-column-header"),O.create("button",{className:"ftable-toolbarsearch-reset-button",textContent:this.options.messages.resetSearch,attributes:{id:"ftable-toolbarsearch-reset-button"},parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,s){var a,i="ftable-toolbarsearch-"+e,o={};let r=e,n=!1;t.searchAttributes?(a=this.formBuilder.parseInputAttributes(t.searchAttributes),Object.assign(o,a),n=void 0!==a.multiple&&!1!==a.multiple):t.inputAttributes&&(a=this.formBuilder.parseInputAttributes(t.inputAttributes),Object.assign(o,a),n=void 0!==a.multiple&&!1!==a.multiple),n&&(r=e+"[]"),o["data-field-name"]=r;let l;if(s&&t.values?l=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):(t.options||t.searchOptions)&&(l=await this.formBuilder.getFieldOptions(e,"search")),n)return this.createCustomMultiSelectForSearch(i,e,t,l,o);let c=O.create("select",{attributes:o,id:i,className:"ftable-toolbarsearch"});return 0<l?.length&&(""===l[0].Value||""===l[0].value||""===l[0]||""===l[0].DisplayText&&null==l[0].Value)||O.create("option",{value:"",innerHTML:"&nbsp;",parent:c}),l&&Array.isArray(l)?l.forEach(e=>{O.create("option",{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,textContent:e.DisplayText||e.text||e,parent:c})}):l&&"object"==typeof l&&Object.entries(l).forEach(([e,t])=>{O.create("option",{value:e,textContent:t,parent:c})}),c}createCustomMultiSelectForSearch(e,t,s,a,i){var o=s.livesearch??!1;return this.formBuilder._buildCustomMultiSelect({hiddenSelectId:e,hiddenSelectName:i["data-field-name"]||e,extraClasses:"ftable-multiselect-search ftable-toolbarsearch",containerDataFieldName:i["data-field-name"]||e,hiddenSelectAttributes:i,optionsSource:a,initialValues:[],placeholderText:s.searchPlaceholder||s.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:o,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!1})}async createDatalistForSearch(e,t){var s="ftable-toolbarsearch-"+e,a=s+"-datalist",i=O.create("datalist",{attributes:{id:a}}),s=O.create("input",{className:"ftable-toolbarsearch",type:"search",id:s,placeholder:t.searchPlaceholder||t.placeholder||"Type or select...",attributes:{"data-field-name":e,list:a}}),t=(s.datalistElement=i,await this.formBuilder.getFieldOptions(e,"search"));return t&&this.formBuilder.populateDatalistOptions(i,t),s}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name");let s;s=e.multiple&&e.options?Array.from(e.selectedOptions).map(e=>e.value).filter(e=>""!==e.trim()).map(e=>e.trim()):e.value.trim(),this.state.currentPage=1,Array.isArray(s)&&0<s.length||!Array.isArray(s)&&s?this.state.searchQueries[t]=s: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.elements.table.querySelectorAll(".ftable-multiselect-container").forEach(e=>{"function"==typeof e.resetMultiSelect&&e.resetMultiSelect()}),this.load()}getNextResizableHeader(t){var s=Array.from(this.elements.table.querySelectorAll("thead th.ftable-column-header-resizable"));for(let e=s.indexOf(t)+1;e<s.length;e++)if(null!==s[e].offsetParent)return s[e];return null}makeColumnResizable(a,e){O.addClass(a,"ftable-column-header-resizable"),this.elements.resizeBar||(this.elements.resizeBar=O.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),O.hide(this.elements.resizeBar));e=O.create("div",{className:"ftable-column-resize-handler",parent:e});let i=!1,o=0,r=0,n,l=null,c=0,d=null,h=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),i=!0,n=this.elements.mainContainer.getBoundingClientRect(),o=e.clientX,r=a.offsetWidth,(l=this.getNextResizableHeader(a))&&(c=l.offsetWidth,e=l.dataset.fieldName,d=this.options.fields[e]);e=a.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-n.left+"px",this.elements.resizeBar.style.top=e.top-n.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",O.show(this.elements.resizeBar),document.addEventListener("mousemove",h),document.addEventListener("mouseup",p)}),e=>{i&&(this.elements.resizeBar.style.left=e.clientX-n.left+"px")}),p=e=>{var t,s;i&&(i=!1,e=e.clientX-o,s=n.width,t=Math.max(50,r+e)/s*100,l&&(e=Math.max(50,c-e)/s*100,d.width=e.toFixed(2)+"%",l.style.width=d.width),(s=this.options.fields[a.dataset.fieldName]).width=t.toFixed(2)+"%",a.style.width=s.width,this.normalizeColumnWidths(),this.options.saveUserPreferences&&this.saveColumnSettings(),O.hide(this.elements.resizeBar),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",p))}}saveColumnSettings(){if(this.options.saveUserPreferences){let a={};this.columnList.forEach(e=>{var t,s=this.options.fields[e];s.action||(t=this.elements.table.querySelector(`[data-field-name="${e}"]`))&&(a[e]={width:t.style.width||s.width||"auto",visibility:s.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&&!e.action&&(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=O.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=O.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,O.create("td",{attributes:{colspan:t},textContent: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.createWarningModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,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}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new o({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,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 o({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createWarningModal(){this.modals.warning=new o({parent:this.elements.mainContainer,title:this.options.messages.warning,className:"ftable-warning-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.warning.close()}]})}createInfoModal(){this.modals.info=new o({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new o({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",closeOnOverlayClick:!1,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=O.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=O.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=O.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(t=>{var e=this.options.fields[t];if(!e.action){var s="hidden"!==e.visibility,a="fixed"===e.visibility,i="separator"===e.visibility,o=this.isFieldSorted(t),r=O.create("li",{className:"ftable-column-select-item",parent:l}),n=O.create("label",{className:"ftable-column-select-label",parent:r});if(!i){let e=O.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=O.create("span",{textContent:e.title||t,style:i?"font-weight: bold;":null,parent:n});o&&((s=O.create("span",{className:"ftable-sort-indicator",textContent:" (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(t){var e,s=O.create("button",{className:"ftable-toolbar-item "+(t.className||""),id:t.id||null,title:t.title||null,textContent:t.text||null,type:"button",parent:this.elements.toolbarDiv});return t.addIconSpan&&(e=O.create("span",{className:"ftable-toolbar-item-icon "+(t.className||""),parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.icon&&(e=O.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:s}),t.text)&&(s.textContent="",s.append(e,t.text||"")),t.onClick&&s.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.onClick(e)}),t.disabled&&(s.disabled=!0),s}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach((e,t)=>{this.addToolbarButton({text:e.text||"",className:"ftable-toolbar-item-custom "+(e.buttonClass||""),id:e.buttonId||"ftable-toolbar-item-custom-id-"+t,title:e.tooltip||"",icon:e.icon||null,onClick:"function"==typeof e.click?e.click:null})})}bindKeyboardEvents(){this.options.selecting&&(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={},t={}){if(!this.state.isLoading){t.fromPage1&&(this.state.currentPage=1),this.state.isLoading=!0,this.showLoadingIndicator();try{var s={...e,...this.buildLoadParams()},a=await this.performLoad(s);this.processLoadedData(a),this.emit("recordsLoaded",{records:a.Records,serverResponse:a})}catch(e){this.showError(this.options.messages.serverCommunicationError),this.logger.error("Load failed: "+e.message)}finally{this.state.isLoading=!1,this.hideLoadingIndicator()}this.renderSortingInfo(),this.normalizeColumnWidths()}}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(([t,e])=>{Array.isArray(e)?e.forEach(e=>{""!==e&&null!=e&&(s.push(e),a.push(t))}):""!==e&&(s.push(e),a.push(t))}),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.options.paging&&0===this.state.records.length&&0<this.state.totalRecordCount?(this.state.currentPage=1,this.load()):(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())}createTableRow(s){let a=O.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(s)}});return a.recordData=s,this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&this.addSelectingCell(a),this.columnList.forEach(e=>{var t=this.options.fields[e];if(t.action)switch(t.action){case"select":this.addSelectingCell(a);break;case"update":this.addEditCell(a);break;case"clone":this.addCloneCell(a);break;case"delete":this.addDeleteCell(a)}else this.addDataCell(a,s,e)}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&this.addEditCell(a),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&this.addCloneCell(a),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&this.addDeleteCell(a),this.options.selecting&&this.makeRowSelectable(a),a}addSelectingCell(t){var e=O.create("td",{className:"ftable-command-column ftable-selecting-column",parent:t});O.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],i=this.formBuilder.generateOptionsCacheKey("table",{}),i=this.formBuilder.resolvedFieldOptions.get(s)?.[i],t=this.getDisplayText(t,s,i),i=O.create("td",{className:`${a.listClass||""} `+(a.listClassEntry||""),innerHTML:a.listEscapeHTML?O.escapeHtml(t):t,attributes:{"data-field-name":s},parent:e});"fixed"===a.visibility||"hidden"!==a.visibility&&"separator"!==a.visibility||O.hide(i)}addEditCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},innerHTML:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},innerHTML:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=O.create("td",{className:"ftable-command-column",parent:t});O.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},innerHTML:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t,s=null){var a=this.options.fields[t],i=e[t],s=s||a.options;let o=i;return"date"===a.type&&i&&(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDate(i,a.dateLocale||this.options.defaultDateLocale)),"datetime-local"!==a.type&&"datetime"!==a.type||!i||(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),a.dateFormat||this.options.defaultDateFormat):this.formatDateTime(i,a.dateLocale||this.options.defaultDateLocale)),"checkbox"===a.type&&(o=this.getCheckboxText(t,i)),s&&(t=this.findOptionByValue(s,i),o=t?t.DisplayText||t.text||t:i),(o=a.display&&"function"==typeof a.display?a.display({record:e,value:i,displayValue:o}):o)||""}_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?this.options.messages.yes:this.options.messages.no}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):"object"==typeof e&&null!==e&&e.hasOwnProperty(t)?e[t]:null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?O.addClass(e,"ftable-row-even"):O.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.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,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.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,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;let s;if(s=null===e||"object"!=typeof e||Array.isArray(e)?{[this.keyField]:e}:e,"function"==typeof t)return t(s);if("string"==typeof t)return l.post(t,s);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(i,e){i.recordData={...i.recordData,...e},Object.keys(e).forEach(e=>{var t,s,a=this.options.fields[e];a&&(t=i.querySelector(`td[data-field-name="${e}"]`))&&(s=this.formBuilder.generateOptionsCacheKey("table",{}),s=this.formBuilder.resolvedFieldOptions.get(e)?.[s],e=this.getDisplayText(i.recordData,e,s),t.innerHTML=a.listEscapeHTML?O.escapeHtml(e):e,t.className=(`${a.listClass||""} `+(a.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");if(this.shiftKeyDown&&this.lastSelectedRow&&this.options.multiselect){this.clearAllSelections();var s=Array.from(this.elements.tableBody.querySelectorAll(".ftable-data-row")),a=s.indexOf(this.lastSelectedRow),i=s.indexOf(e),[i,o]=a<i?[a,i]:[i,a];for(let e=i;e<=o;e++)this.selectRow(s[e])}else this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e);t&&!this.shiftKeyDown||(this.lastSelectedRow=e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){O.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){O.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,a=!1){var i=this.options.fields[s];if(i&&!1!==i.sorting){i=this.state.sorting.findIndex(e=>e.fieldName===s);let e=!0,t="ASC";0<=i?"ASC"===this.state.sorting[i].direction?(t="DESC",this.state.sorting[i].direction=t):(this.state.sorting.splice(i,1),e=!1):this.state.sorting.push({fieldName:s,direction:t}),(!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=>{O.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&&O.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&&O.create("span",{className:"ftable-page-number-space",textContent:"...",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="";O.create("span",{textContent: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=O.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=s;e++)O.create("option",{attributes:{value:e},textContent: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=O.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=O.create("span",{className:a+(s?" ftable-page-number-disabled":""),innerHTML: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(e),this.modals.error.show()):alert(e)}showWarning(e){this.modals.warning?(this.modals.warning.setContent(e),this.modals.warning.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(e),this.modals.info.show()):alert(e)}reload(e=!1){return this.clearListCache(),e?this.preservedSelections=new Set(this.state.selectedRecords):this.state.selectedRecords.clear(),this.load().then(()=>(e&&this.preservedSelections&&(this.restoreSelections(),this.preservedSelections=null),this))}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}restoreSelections(){if(this.preservedSelections)return this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{var t=this.getKeyValue(e.recordData);t&&this.preservedSelections.has(t)&&this.selectRow(e)}),this}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,s,a,i=this.elements.table.cloneNode(!0),o=[],r=e=>`"${String(e||"").replace(/"/g,'""')}"`,n=[];for(t of i.querySelectorAll("thead th"))t.classList.contains("ftable-command-column-header")||t.classList.contains("ftable-toolbarsearch-column-header")||"none"===t.style.display||(s=t.textContent.trim(),n.push(r(s)));o.push(n.join(","));for(a of i.querySelectorAll("tbody tr"))if("none"!==a.style.display){var l,c,d,h=[];let e=!1;for(l of a.querySelectorAll("td"))l.classList.contains("ftable-command-column")||"none"===l.style.display||(l.querySelector("img, button, input, select")&&(l.innerHTML=l.textContent),c=l.innerHTML.replace(/<br\s*\/?>/gi,"\n"),(d=document.createElement("div")).innerHTML=c,h.push(r(d.textContent||"")),e=!0);e&&o.push(h.join(","))}var i=o.join("\n"),i=new Blob(["\ufeff"+i],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a");p.href=URL.createObjectURL(i),p.download=e,p.click(),p.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
1
+ (e=>{let a={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?",yes:"Yes",no:"No",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"An error has occured",warning:"Warning",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,this.pendingRequests=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,a){e=this.generateKey(e,t);this.cache.set(e,a)}clear(e=null,t=null){if(e)if(t){t=this.generateKey(e,t);this.cache.delete(t)}else{var a,s=e.split("?")[0];for([a]of this.cache)a.startsWith(s)&&this.cache.delete(a)}else this.cache.clear()}async getOrCreate(e,t,a){let s=this.generateKey(e,t);e=this.cache.get(s);return e||(this.pendingRequests.has(s)?this.pendingRequests.get(s):(t=(async()=>{try{var e=await a();return this.cache.set(s,e),e}finally{this.pendingRequests.delete(s)}})(),this.pendingRequests.set(s,t),t))}size(){return this.cache.size}}class s{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=s.LOG_LEVELS.WARN){this.level=e}log(t,e){var a;!window.console||t<this.level||(a=Object.keys(s.LOG_LEVELS).find(e=>s.LOG_LEVELS[e]===t),console.log(`fTable ${a}: `+e))}debug(e){this.log(s.LOG_LEVELS.DEBUG,e)}info(e){this.log(s.LOG_LEVELS.INFO,e)}warn(e){this.log(s.LOG_LEVELS.WARN,e)}error(e){this.log(s.LOG_LEVELS.ERROR,e)}}class k{static PROPERTY_ATTRIBUTES=new Set(["value","checked","selected","disabled","readOnly","name","id","type","placeholder","min","max","step","required","multiple","accept","className","textContent","innerHTML","title"]);static create(e,t={}){let a=document.createElement(e);return void 0!==t.style&&(a.style.cssText=t.style),k.PROPERTY_ATTRIBUTES.forEach(e=>{e in t&&null!==t[e]&&(a[e]=t[e])}),void 0!==t.parent&&t.parent.appendChild(a),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{null!==t&&(k.PROPERTY_ATTRIBUTES.has(e)?a[e]=t:a.setAttribute(e,t))}),a}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 a={method:"GET",headers:{}},s={...a,...t};t.headers&&(s.headers={...a.headers,...t.headers});try{var i=await fetch(e,s);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 s=new URL(e,window.location.href);return Object.entries(t).forEach(([e,a])=>{if(null!=a)if(Array.isArray(a)){let t=e.endsWith("[]")?e:e+"[]";a.forEach(e=>{null!=e&&s.searchParams.append(t,e)})}else s.searchParams.append(e,a)}),this.request(s.toString(),{method:"GET",headers:{"Content-Type":"application/x-www-form-urlencoded"}})}static async post(e,t={}){e=new URL(e,window.location.href);let s=new FormData;return Object.entries(t).forEach(([e,a])=>{if(null!=a)if(Array.isArray(a)){let t=e.endsWith("[]")?e:e+"[]";a.forEach(e=>{null!=e&&s.append(t,e)})}else s.append(e,a)}),this.request(e.toString(),{method:"POST",body:s})}}class i{constructor(e,t="localStorage"){this.prefix=e,this.method=t}set(e,t){var a,e=""+this.prefix+e;"localStorage"===this.method?localStorage.setItem(e,t):((a=new Date).setDate(a.getDate()+30),document.cookie=e+`=${t}; expires=${a.toUTCString()}; path=/`)}get(e){e=""+this.prefix+e;if("localStorage"===this.method)return localStorage.getItem(e);var t,a=e+"=";for(t of decodeURIComponent(document.cookie).split(";")){for(;" "===t.charAt(0);)t=t.substring(1);if(0===t.indexOf(a))return t.substring(a.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 a=0;if(0!==t.length)for(let e=0;e<t.length;e++){var s=t.charCodeAt(e);a=(a<<5)-a+s,a&=a}return a})(e+=t.join("$")+"#c"+t.length)}}class o{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=k.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=k.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});k.create("h2",{className:"ftable-modal-header",textContent:this.options.title,parent:this.modal});k.create("span",{className:"ftable-modal-close",innerHTML:"&times;",parent:this.modal}).addEventListener("click",()=>this.close());var e=k.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 a=k.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=k.create("button",{className:"ftable-dialog-button "+(e.className||""),innerHTML:`<span>${e.text}</span>`,parent:a});e.onClick&&(t._originalOnClick=e.onClick,t.addEventListener("click",this._createWrappedClickHandler(t)))})}return this.options.closeOnOverlayClick&&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.modal.querySelectorAll(".ftable-dialog-button").forEach(e=>{e.disabled=!1}),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=/<(div|ul|ol|table|p|h[1-6]|blockquote)/i.test(e)?e:`<p>${e}</p>`:t.appendChild(e))}_createWrappedClickHandler(s){return async e=>{s.disabled=!0;try{var t,a=s._originalOnClick;"function"==typeof a&&(t=a.call(s,e))instanceof Promise&&await t}catch(e){console.error("Modal button action failed:",e)}finally{s.disabled=!1}}}}class r{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new t}async getFieldOptions(t,a="table",e={}){var s=this.options.fields[t],i="search"===a?s.searchOptions??s.options:s.options;if(!i)return null;var o=this.shouldSkipCache(s,a,e);try{return await this.resolveOptions({...s,options:i},e,a,o)}catch(e){return console.error(`Failed to resolve options for ${t} (${a}):`,e),i}}shouldSkipCache(e,t,a){return!!a.forceRefresh||!!e.noCache&&("boolean"==typeof e.noCache?e.noCache:"function"==typeof e.noCache?e.noCache({context:t,...a}):"object"==typeof e.noCache&&!0===e.noCache[t])}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,a,s){var i=k.create("div",{className:"hidden"!=t.type?"ftable-input-field-container":"",attributes:{id:"ftable-input-field-container-div-"+e}}),t=("hidden"!=t.type&&k.create("div",{className:"ftable-input-label",textContent:t.inputTitle||t.title,parent:i}),this.createInput(e,t,a[e],s));return i.appendChild(t),i}async createForm(e="create",t={}){this.currentFormRecord=t;var a,s,i,o,r=k.create("form",{className:`ftable-dialog-form ftable-${e}-form`});this.buildDependencyMap();for([a,s]of Object.entries(this.options.fields))this.shouldIncludeField(s,e)&&(i={...s},s.dependsOn?i.options=s.options:(o=await this.getFieldOptions(a,e,{record:t,source:e}),i.options=o),o=this.createFieldContainer(a,i,t,e),r.appendChild(o));return this.setupDependencyListeners(r),r}buildDependencyMap(){this.dependencies.clear(),Object.entries(this.options.fields).forEach(([t,a])=>{if(a.dependsOn){let e;"string"==typeof a.dependsOn&&(e=a.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(a){Array.from(this.dependencies.keys()).forEach(e=>{var t=a.querySelector(`[name="${e}"]`);t&&t.addEventListener("change",()=>{this.handleDependencyChange(a,e)})}),this.handleDependencyChange(a)}async resolveOptions(e,t={},a="",s=!1){if(!e.options)return[];if(Array.isArray(e.options)||"object"==typeof e.options)return e.options;let i;t={...t,source:a,clearCache:()=>{s=!0,this.updateFieldCacheSetting(e,a,!0)}};if("function"==typeof e.options)i=await e.options(t);else{if("string"!=typeof e.options)return[];i=e.options}t=i&&"object"==typeof i&&i.url;let o=t?i.url:i;if(s=t&&void 0!==i.noCache?i.noCache:s,"string"!=typeof o)return[];if(!s)return this.optionsCache.getOrCreate(o,{},async()=>{try{var e=this.options.forcePost?await l.post(o):await l.get(o);return e.Options||e.options||e||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}});try{var r=this.options.forcePost?await l.post(o):await l.get(o);return r.Options||r.options||r||[]}catch(e){return console.error(`Failed to load options from ${o}:`,e),[]}}updateFieldCacheSetting(e,t,a){e.noCache?"boolean"==typeof e.noCache?e.noCache={table:e.noCache,create:e.noCache,edit:e.noCache,[t]:a}:"object"==typeof e.noCache&&(e.noCache[t]=a):e.noCache={[t]:a}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}getFormValues(e){var t={},a=e.elements;for(let e=0;e<a.length;e++){var s=a[e],i=s.name;if(i&&!s.disabled)switch(s.type){case"checkbox":t[i]=s.checked?s.value||"1":"0";break;case"radio":s.checked&&(t[i]=s.value);break;case"select-multiple":t[i]=Array.from(s.selectedOptions).map(e=>e.value);break;default:t[i]=s.value}}return t}async handleDependencyChange(e,a=""){var s,i,o=this.getFormValues(e),r=e.classList.contains("ftable-create-form")?"create":"edit",n=this.currentFormRecord||{},l={record:n,source:r,form:e,dependedValues:o};for([s,i]of Object.entries(this.options.fields))if(i.dependsOn){if(""!==a)if(!i.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(a))continue;let t=e.querySelector(`[name="${s}"]`);if(t&&this.shouldIncludeField(i,r))try{"SELECT"===t.tagName?t.innerHTML='<option value="">Loading...</option>':"INPUT"===t.tagName&&t.list&&(c=document.getElementById(t.list.id))&&(c.innerHTML="");var c,d=t.value||n[s]||"",h={...l,dependsOnField:i.dependsOn,dependsOnValue:o[i.dependsOn]},p=await this.getFieldOptions(s,r,h);"SELECT"===t.tagName?this.populateSelectOptions(t,p,d):"INPUT"===t.tagName&&t.list&&(this.populateDatalistOptions(t.list,p),d)&&(t.value=d),setTimeout(()=>{t.dispatchEvent(new Event("change",{bubbles:!0}))},0)}catch(e){console.error(`Error loading options for ${s}:`,e),"SELECT"===t.tagName&&(t.innerHTML='<option value="">Error</option>')}}}parseInputAttributes(e){if("string"!=typeof e)return e||{};for(var t={},a=/(\w+)(?:=("[^"]*"|'[^']*'|\S+))?/g;null!==(i=a.exec(e));){var s=i[1],i=i[2]?i[2].replace(/^["']|["']$/g,""):"";t[s]=""===i?"true":i}return t}createInput(e,t,a,s){var i=k.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let o;switch(null===(a=void 0===a?null:a)&&t.defaultValue&&(a=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":o=this.createHiddenInput(e,t,a);break;case"textarea":o=this.createTextarea(e,t,a);break;case"select":o=this.createSelect(e,t,a);break;case"checkbox":o=this.createCheckbox(e,t,a);break;case"radio":o=this.createRadioGroup(e,t,a);break;case"datalist":o=this.createDatalistInput(e,t,a);break;case"file":o=this.createFileInput(e,t,a);break;case"date":case"datetime":case"datetime-local":o=this.createDateInput(e,t,a);break;default:o=this.createTypedInput(e,t,a)}return"function"==typeof t.input?(s={field:t,record:this.currentFormRecord,inputField:o,formType:s},"string"==typeof(s=t.input(s))?i.innerHTML=s:s instanceof Node?i.appendChild(s):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement))):(i.appendChild(o),o.datalistElement&&o.datalistElement instanceof Node&&i.appendChild(o.datalistElement)),t.explain&&k.create("div",{className:"ftable-field-explain",innerHTML:`<small>${t.explain}</small>`,parent:i}),i}createDateInput(a,s,i){if("undefined"==typeof FDatepicker)return createTypedInput(a,s,i);{let e=s.dateFormat||this.options.defaultDateFormat;var o,r=document.createElement("div"),n=k.create("input",{id:"real-"+a,type:"hidden",value:i,name:a}),i={"data-date":i};s.inputAttributes&&(o=this.parseInputAttributes(s.inputAttributes),Object.assign(i,o));let t=k.create("input",{attributes:i,id:"Edit-"+a,type:"text",placeholder:s.placeholder||null,className:s.inputClass||"datepicker-input",readOnly:!0});switch(r.appendChild(n),r.appendChild(t),s.type){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"real-"+a,altFormat:"Y-m-d"})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"real-"+a,altFormat:"Y-m-d H:i:00"})},0)}return r}}createTypedInput(e,t,a){var s,i=t.type||"text",o={};let r=e,n=(t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(o,s),void 0!==s.multiple&&!1!==s.multiple)&&(r=e+"[]"),k.create("input",{attributes:o,type:i,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:a,name:r}));return n.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),n.dispatchEvent(new Event("change",{bubbles:!0})),!1}),n}createDatalistInput(e,t,a){var s={list:e+"-datalist"},i=(t.inputAttributes&&(i=this.parseInputAttributes(t.inputAttributes),Object.assign(s,i)),k.create("input",{attributes:s,type:"search",name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:a})),s=k.create("datalist",{id:e+"-datalist"});return t.options&&this.populateDatalistOptions(s,t.options),i.datalistElement=s,i}populateDatalistOptions(a,e){a.innerHTML="",Array.isArray(e)?e.forEach(e=>{k.create("option",{value:e.Value||e.value||e,textContent:e.DisplayText||e.text||e,parent:a})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{k.create("option",{value:e,textContent:t,parent:a})})}createHiddenInput(e,t,a){var s={};return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(s,t)),k.create("input",{attributes:s,type:"hidden",name:e,id:"Edit-"+e,value:a})}createTextarea(e,t,a){var s,i={};return t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(i,s)),k.create("textarea",{attributes:i,name:e,id:"Edit-"+e,className:t.inputClass||null,placeholder:t.placeholder||null,value:a})}createSelect(e,t,a){var s={};let i=e,o=!1;if(t.inputAttributes&&(r=this.parseInputAttributes(t.inputAttributes),Object.assign(s,r),o=void 0!==r.multiple&&!1!==r.multiple)&&(i=e+"[]"),o)return this.createCustomMultiSelect(e,t,a,s,i);s.name=i;var r=k.create("select",{attributes:s,name:e,id:"Edit-"+e,className:t.inputClass||null});return t.options&&this.populateSelectOptions(r,t.options,a),r}createCustomMultiSelect(e,t,a,s,i){var o=Array.isArray(t.options)?t.options:t.options&&"object"==typeof t.options?Object.entries(t.options).map(([e,t])=>({Value:e,DisplayText:t})):[],r=t.livesearch??!1;return this._buildCustomMultiSelect({containerId:e,hiddenSelectId:"Edit-"+e,hiddenSelectName:i,extraClasses:"",containerDataFieldName:e,hiddenSelectAttributes:{},optionsSource:o,initialValues:Array.isArray(a)?a:a?a.toString().split(",").filter(e=>e):[],placeholderText:t.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:r,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!0})}_buildCustomMultiSelect(e){let{hiddenSelectId:t,hiddenSelectName:a,extraClasses:s,containerDataFieldName:i,hiddenSelectAttributes:o,optionsSource:r,initialValues:n,placeholderText:l,livesearch:c,onChangeExtra:d,buildHiddenSelectOnUpdate:h}=e;let p=(e=r)?(Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({Value:e,DisplayText:t}))).map(e=>({optValue:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,optText:e.DisplayText||e.text||e,groupLabel:e.Group||e.group||null})).filter(e=>null!=e.optValue&&""!==e.optValue):[],u=new Map(p.map(e=>[e.optValue.toString(),e.optText]));e=["ftable-multiselect-container",...s.split(" ").filter(Boolean)].join(" ");let m=k.create("div",{className:e,attributes:{"data-field-name":i}}),f=k.create("select",{id:t,name:a,multiple:!0,style:"display: none;",attributes:o}),g=(m.appendChild(f),m.hiddenSelect=f,k.create("div",{className:"ftable-multiselect-display",parent:m,attributes:{tabindex:"0"}})),b=k.create("div",{className:"ftable-multiselect-selected",parent:g}),v=k.create("span",{className:"ftable-multiselect-placeholder",textContent:l,parent:b}),y=(k.create("button",{type:"button",className:"ftable-multiselect-toggle",innerHTML:"▼",parent:g,attributes:{tabindex:"-1"}}),null),w=null,C=new Set(n.map(e=>e.toString())),S=new Map,E=(h||p.forEach(({optValue:e,optText:t})=>{k.create("option",{value:e,textContent:t,parent:f})}),()=>{b.innerHTML="",h?(f.innerHTML="",C.forEach(e=>{var t=u.get(e)??e;k.create("option",{value:e,textContent:t,selected:!0,parent:f})})):Array.from(f.options).forEach(e=>{e.selected=C.has(e.value)}),0===C.size?(v.textContent=l,b.appendChild(v)):C.forEach(t=>{var e=k.create("span",{className:"ftable-multiselect-tag",parent:b});k.create("span",{className:"ftable-multiselect-tag-text",textContent:u.get(t)||t,parent:e}),k.create("span",{className:"ftable-multiselect-tag-remove",innerHTML:"×",parent:e}).addEventListener("click",e=>{e.stopPropagation(),C.delete(t);e=S.get(t);e&&(e.checked=!1),E(),d&&d(f)})}),d&&d(f)}),x=()=>{g.focus(),y&&(y.remove(),y=null),w&&(w.remove(),w=null),m._cleanupHandlers&&(m._cleanupHandlers(),m._cleanupHandlers=null)},A=()=>{var e,t,a;y&&(e=g.getBoundingClientRect(),a=window.pageYOffset||document.documentElement.scrollTop,t=window.pageXOffset||document.documentElement.scrollLeft,t=e.left+t,a=e.bottom+a+4,Object.assign(y.style,{position:"absolute",left:t+"px",top:a+"px",width:e.width+"px",minWidth:"fit-content",boxSizing:"border-box",zIndex:"10000"}),(a=y.getBoundingClientRect()).right>window.innerWidth)&&(t=Math.max(10,window.innerWidth-a.width-10),y.style.left=t+"px")},N=(e="")=>{if(y){Array.from(y.querySelectorAll(".ftable-multiselect-option, .ftable-multiselect-optgroup")).forEach(e=>e.remove());let t=e.toLowerCase();e=e?p.filter(e=>e.optText.toLowerCase().includes(t)):p;let i=new Set,o=null;e.forEach(({optValue:t,optText:e,groupLabel:a})=>{a&&a!==i[i.size-1]?i.has(a)||(i.add(a),o=k.create("div",{className:"ftable-multiselect-optgroup",textContent:a,parent:y})):a||(o=null);a=k.create("div",{className:"ftable-multiselect-option",parent:y});let s=k.create("input",{type:"checkbox",className:"ftable-multiselect-checkbox",checked:C.has(t.toString()),parent:a});S.set(t.toString(),s),k.create("label",{className:"ftable-multiselect-label",textContent:e,parent:a}),a.addEventListener("click",e=>{e.stopPropagation();e=t.toString();C.has(e)?(C.delete(e),s.checked=!1):(C.add(e),s.checked=!0),E()})})}},T=s=>{if(s&&s.stopPropagation(),y)x();else{if(document.querySelectorAll(".ftable-multiselect-dropdown").forEach(e=>e.remove()),document.querySelectorAll(".ftable-multiselect-overlay").forEach(e=>e.remove()),w=k.create("div",{className:"ftable-multiselect-overlay",parent:document.body}),y=k.create("div",{className:"ftable-multiselect-dropdown",parent:document.body,attributes:{tabindex:"-1",role:"listbox","aria-multiselectable":"true"}}),c){s=k.create("div",{className:"ftable-multiselect-livesearch-wrap",parent:y});let e=k.create("input",{type:"search",className:"ftable-multiselect-livesearch",placeholder:"Search...",parent:s,attributes:{autocomplete:"off"}});e.addEventListener("input",()=>{N(e.value)}),e.addEventListener("click",e=>e.stopPropagation()),setTimeout(()=>e.focus(),0)}N(),A(),c||y.focus(),y.addEventListener("keydown",e=>{var t,a;"Escape"===e.key?x():"ArrowDown"===e.key||"ArrowUp"===e.key?(e.preventDefault(),a=(t=Array.from(y.querySelectorAll(".ftable-multiselect-checkbox"))).indexOf(document.activeElement),t["ArrowDown"===e.key?a<t.length-1?a+1:0:0<a?a-1:t.length-1]?.focus()):" "!==e.key&&"Enter"!==e.key||(e.preventDefault(),document.activeElement.classList.contains("ftable-multiselect-checkbox")&&document.activeElement.click())}),w.addEventListener("click",e=>{e.target===w&&x()});let e=()=>A(),t=e=>{y&&y.contains(e.target)||A()},a=new ResizeObserver(()=>A());window.addEventListener("scroll",t,!0),window.addEventListener("resize",e),a.observe(b),m._cleanupHandlers=()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",e),a.disconnect()}}},L=(g.addEventListener("click",T),g.querySelector(".ftable-multiselect-toggle").addEventListener("click",T),g.addEventListener("keydown",e=>{"ArrowDown"!==e.key&&"Enter"!==e.key||(e.preventDefault(),T())}),m.resetMultiSelect=()=>{C.clear(),S.forEach(e=>{e.checked=!1}),x(),E()},new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(e=>{(e===m||e.contains&&e.contains(m))&&(x(),L.disconnect())})})}));return setTimeout(()=>{m.parentNode&&L.observe(m.parentNode,{childList:!0,subtree:!0})},0),E(),m}createRadioGroup(o,r,n){let l=k.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 a=k.create("div",{className:"ftable-radio-wrapper",parent:l}),t=o+"_"+t,s={},i=(r.inputAttributes&&(i=this.parseInputAttributes(r.inputAttributes),Object.assign(s,i)),void 0!==e.Value?e.Value:void 0!==e.value?e.value:e);k.create("input",{attributes:s,type:"radio",name:o,id:t,value:i,className:r.inputClass||null,checked:i==n,parent:a}),k.create("label",{attributes:{for:t},textContent:e.DisplayText||e.text||e,parent:a})}),l}createCheckbox(e,t,a){var s=k.create("div",{className:"ftable-yesno-check-wrapper"}),a=[1,"1",!0,"true"].includes(a);let i=this.options.messages.no,o=this.options.messages.yes;return t.values&&"object"==typeof t.values&&(void 0!==t.values[0]&&(i=t.values[0]),void 0!==t.values[1])&&(o=t.values[1]),k.create("input",{className:["ftable-yesno-check-input",t.inputClass||""].filter(Boolean).join(" "),type:"checkbox",name:e,id:"Edit-"+e,value:"1",parent:s}).checked=a,t.label?k.create("label",{className:"ftable-yesno-check-fixedlabel",attributes:{for:"Edit-"+e},textContent:t.label,parent:s}):k.create("label",{className:"ftable-yesno-check-text",attributes:{for:"Edit-"+e,"data-yes":o,"data-no":i},parent:s}),s}populateSelectOptions(o,e,r){if(o.innerHTML="",Array.isArray(e)){let a=new Map,s=[],i=(e.forEach(e=>{var t=e.Group||e.group||null;(t?(a.has(t)||a.set(t,[]),a.get(t)):s).push(e)}),(e,t)=>{var a=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let s=k.create("option",{value:a,textContent:e.DisplayText||e.text||e,selected:a==r,parent:t});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{s.setAttribute("data-"+e,t)})});s.forEach(e=>i(e,o)),a.forEach((e,t)=>{let a=k.create("optgroup",{attributes:{label:t},parent:o});e.forEach(e=>i(e,a))})}else"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{k.create("option",{value:e,textContent:t,selected:e==r,parent:o})})}createFileInput(e,t,a){var s,i={};let o=e;return t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(i,s),void 0!==s.multiple&&!1!==s.multiple)&&(o=e+"[]"),k.create("input",{type:"file",id:"Edit-"+e,name:o,className:t.inputClass||null,attributes:i})}}class n extends class{constructor(){this.events={}}on(e,t){return this.events[e]||(this.events[e]=[]),this.events[e].push(t),this}once(t,a){let s=(...e)=>{this.off(t,s),a.apply(this,e)};return s.fn=a,this.on(t,s),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 s(this.options.logLevel),this.userPrefs=new i("",this.options.saveUserPreferencesMethod),this.formBuilder=new r(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.shiftKeyDown=!1,this.lastSelectedRow=null,(this.element.ftableInstance=this).init()}}mergeOptions(e){var t={tableId:void 0,logLevel:s.LOG_LEVELS.WARN,actions:{},fields:{},forcePost:!0,closeOnOverlayClick:!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,250,500],gotoPageArea:"combobox",sorting:!1,multiSorting:!1,multiSortingCtrlKey:!0,selecting:!1,multiselect:!1,openChildAsAccordion:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...a}};return this.deepMerge(t,e)}deepMerge(e,t){var a,s={...e};for(a in t)t[a]&&"object"==typeof t[a]&&!Array.isArray(t[a])?s[a]=this.deepMerge(s[a]||{},t[a]):s[a]=t[a];return s}verifyOptions(){this.options.pageSize&&!this.options.pageSizes.includes(this.options.pageSize)&&(this.options.pageSize=this.options.pageSizes[0])}static setMessages(e){Object.assign(a,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAllFieldOptionsForTable().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.updateSortingHeaders(),this.renderSortingInfo(),this.initColumnWidths()}initColumnWidths(){var e=this.columnList.filter(e=>{e=this.options.fields[e];return!e.action&&"hidden"!==e.visibility&&"separator"!==e.visibility});let t=e.length;e.forEach(e=>{e=this.options.fields[e];e.width=e.width||100/t+"%"})}normalizeColumnWidths(){var e=this.elements.mainContainer,t=this.columnList.map(e=>({th:this.elements.table.querySelector(`[data-field-name="${e}"]`),field:this.options.fields[e]})).filter(e=>e.th&&!e.field.action&&"hidden"!==e.field.visibility&&"separator"!==e.field.visibility);if(0!==t.length){let a=e.offsetWidth,s=0;t.forEach(e=>{var t=e.th.offsetWidth/a*100;e.field.width=t+"%",e.th.style.width=e.field.width,s+=t})}}parseDefaultSorting(e){let o=[];return e&&"string"==typeof e&&e.split(",").forEach(a=>{a=a.trim();if(a){var s=a.toUpperCase().indexOf(" DESC"),i=a.toUpperCase().indexOf(" ASC");let e="ASC",t=a;e=0<s?(t=a.slice(0,s).trim(),"DESC"):(t=(0<i?a.slice(0,i):a).trim(),"ASC");s=this.options.fields[t];s&&!1!==s.sorting&&o.push({fieldName:t,direction:e})}}),o}createPagingUI(){this.elements.bottomPanel=k.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=k.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=k.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=k.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=k.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=k.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=k.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});k.create("span",{textContent:this.options.messages.pageSizeChangeLabel,parent:e});let a=k.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100,250,500]).forEach(e=>{var t=k.create("option",{attributes:{value:e},textContent:e.toString(),parent:a});e===this.state.pageSize&&(t.selected=!0)}),a.addEventListener("change",e=>{this.changePageSize(parseInt(e.target.value))})}processFieldDefinitions(){this.fieldList=Object.keys(this.options.fields),this.fieldList.forEach(e=>{var e=this.options.fields[e],t=!0===e.key;!!e.action?(e.list=!0,e.create=!1,e.edit=!1,e.sorting=!1,e.searchable=!1):t?(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._userPlacedActions=new Set(this.fieldList.filter(e=>this.options.fields[e].action).map(e=>this.options.fields[e].action)),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.info("No key field defined")}async resolveAllFieldOptionsForTable(){this.tableOptionsCache=new Map;var e=this.columnList.map(async t=>{var e=this.options.fields[t];if(!e.action)try{var a=await this.formBuilder.getFieldOptions(t,"table");a&&this.tableOptionsCache.set(t,a)}catch(e){console.error(`Failed to resolve table options for ${t}:`,e)}});await Promise.all(e)}async refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");if(0!==e.length)for(var t of e)for(var a of this.columnList){var s,i,o=this.options.fields[a];!o.action&&o.options&&(s=t.querySelector(`td[data-field-name="${a}"]`))&&(i=this.tableOptionsCache?.get(a),a=this.getDisplayText(t.recordData,a,i),s.innerHTML=o.listEscapeHTML?k.escapeHtml(a):a)}}createMainStructure(){this.elements.mainContainer=k.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=k.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),k.create("div",{className:"ftable-title-text",innerHTML:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=k.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=k.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=k.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=k.create("thead",{parent:this.elements.table});let o=k.create("tr",{parent:e});if(this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")){var t=k.create("th",{className:"ftable-command-column-header ftable-column-header-select",parent:o});if(this.options.multiselect){let e=k.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(t=>{var a=this.options.fields[t];if(a.action){var s={select:"ftable-column-header-select",update:"ftable-column-header-edit",clone:"ftable-column-header-clone",delete:"ftable-column-header-delete"};let t=k.create("th",{className:"ftable-command-column-header "+(s[a.action]||""),parent:o});if(a.title&&(t.textContent=a.title),"select"===a.action&&this.options.selecting&&this.options.selectingCheckboxes&&this.options.multiselect){let e=k.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}void(a.width&&(t.style.width=a.width))}else{let e=k.create("th",{className:`ftable-column-header ${a.listClass||""} `+(a.listClassHeader||""),attributes:{"data-field-name":t},parent:o});a.width&&(e.style.width=a.width);var s=k.create("div",{className:"ftable-column-header-container",parent:e}),i=(a.tooltip&&s.setAttribute("title",a.tooltip),k.create("span",{className:"ftable-column-header-text",innerHTML:a.title||t,parent:s}));this.options.sorting&&!1!==a.sorting&&(k.addClass(i,"ftable-sortable-text"),k.addClass(e,"ftable-column-header-sortable"),e.addEventListener("click",e=>{e.preventDefault();e=e.ctrlKey||e.metaKey;this.sortByColumn(t,e)})),!1!==this.options.columnResizable&&!1!==a.columnResizable&&this.makeColumnResizable(e,s),"hidden"!==a.visibility&&"separator"!==a.visibility||k.hide(e)}}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&k.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:o}),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&k.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:o}),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&k.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:o}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,a=k.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&k.create("th",{className:"ftable-toolbarsearch-column-header",parent:a});for(let i of this.columnList){var o=this.options.fields[i];if(o.action)k.create("th",{className:"ftable-toolbarsearch-column-header ftable-command-column-header",parent:a});else{var r=!1!==o.searchable,n=k.create("th",{className:"ftable-toolbarsearch-column-header",parent:a});if(r){r=k.create("div",{className:"ftable-column-header-container",parent:n});let a,s="text";o.searchType?s=o.searchType:!o.type&&o.options?s="select":o.type&&(s=o.type);var l="ftable-toolbarsearch-"+i;switch(s){case"date":case"datetime":case"datetime-local":if("undefined"!=typeof FDatepicker){let e=o.searchDateFormat||o.dateFormat||this.options.defaultDateFormat;var c=document.createElement("div"),d=k.create("input",{className:"ftable-toolbarsearch-extra",type:"hidden",id:"ftable-toolbarsearch-extra-"+i,attributes:{"data-field-name":i}});let t=k.create("input",{className:"ftable-toolbarsearch",id:"ftable-toolbarsearch-"+i,type:"text",placeholder:o.searchPlaceholder||o.placeholder||"",readOnly:!0});switch(c.appendChild(d),c.appendChild(t),s){case"date":setTimeout(()=>{new FDatepicker(t,{format:e,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d",autoClose:!0})},0);break;case"datetime":case"datetime-local":setTimeout(()=>{new FDatepicker(t,{format:e,timepicker:!0,altField:"ftable-toolbarsearch-extra-"+i,altFormat:"Y-m-d H:i:00"})},0)}a=c}else a=k.create("input",{className:"ftable-toolbarsearch",type:s,id:l,attributes:{"data-field-name":i}});break;case"checkbox":o.values||(o.values={0:this.options.messages.no,1:this.options.messages.yes}),a=await this.createSelectForSearch(i,o,!0);break;case"select":a=o.options?await this.createSelectForSearch(i,o,!1):k.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}});break;case"datalist":a=await this.createDatalistForSearch(i,o);break;default:a=k.create("input",{className:"ftable-toolbarsearch",type:"text",id:l,placeholder:o.searchPlaceholder||o.placeholder||"Search...",attributes:{"data-field-name":i}})}if(a){r.appendChild(a),a.datalistElement&&a.datalistElement instanceof Node&&r.appendChild(a.datalistElement);let e=a;"SELECT"===(e=a.classList&&a.classList.contains("ftable-multiselect-container")&&a.hiddenSelect?a.hiddenSelect:e).tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)})}}"hidden"!==o.visibility&&"separator"!==o.visibility||k.hide(n)}}this.options.toolbarsearch&&this.options.toolbarreset&&(e=k.create("th",{className:"ftable-toolbarsearch-column-header ftable-toolbarsearch-reset",parent:a}),0<(t=(this.options.actions.updateAction&&!this._userPlacedActions.has("update")?1:0)+(this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")?1:0)+(this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")?1:0))?e.colSpan=t:k.addClass(e,"ftable-command-column-header"),k.create("button",{className:"ftable-toolbarsearch-reset-button",textContent:this.options.messages.resetSearch,attributes:{id:"ftable-toolbarsearch-reset-button"},parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,a){var s,i="ftable-toolbarsearch-"+e,o={};let r=e,n=!1;t.searchAttributes?(s=this.formBuilder.parseInputAttributes(t.searchAttributes),Object.assign(o,s),n=void 0!==s.multiple&&!1!==s.multiple):t.inputAttributes&&(s=this.formBuilder.parseInputAttributes(t.inputAttributes),Object.assign(o,s),n=void 0!==s.multiple&&!1!==s.multiple),n&&(r=e+"[]"),o["data-field-name"]=r;let l;if(a&&t.values?l=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):(t.options||t.searchOptions)&&(l=await this.formBuilder.getFieldOptions(e,"search")),n)return this.createCustomMultiSelectForSearch(i,e,t,l,o);let c=k.create("select",{attributes:o,id:i,className:"ftable-toolbarsearch"});return 0<l?.length&&(""===l[0].Value||""===l[0].value||""===l[0]||""===l[0].DisplayText&&null==l[0].Value)||k.create("option",{value:"",innerHTML:"&nbsp;",parent:c}),l&&Array.isArray(l)?l.forEach(e=>{k.create("option",{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e,textContent:e.DisplayText||e.text||e,parent:c})}):l&&"object"==typeof l&&Object.entries(l).forEach(([e,t])=>{k.create("option",{value:e,textContent:t,parent:c})}),c}createCustomMultiSelectForSearch(e,t,a,s,i){var o=a.livesearch??!1;return this.formBuilder._buildCustomMultiSelect({hiddenSelectId:e,hiddenSelectName:i["data-field-name"]||e,extraClasses:"ftable-multiselect-search ftable-toolbarsearch",containerDataFieldName:i["data-field-name"]||e,hiddenSelectAttributes:i,optionsSource:s,initialValues:[],placeholderText:a.searchPlaceholder||a.placeholder||this.options.messages?.multiSelectPlaceholder||"Click to select options...",livesearch:o,onChangeExtra:e=>{e.dispatchEvent(new Event("change",{bubbles:!0}))},buildHiddenSelectOnUpdate:!1})}async createDatalistForSearch(e,t){var a="ftable-toolbarsearch-"+e,s=a+"-datalist",i=k.create("datalist",{attributes:{id:s}}),a=k.create("input",{className:"ftable-toolbarsearch",type:"search",id:a,placeholder:t.searchPlaceholder||t.placeholder||"Type or select...",attributes:{"data-field-name":e,list:s}}),t=(a.datalistElement=i,await this.formBuilder.getFieldOptions(e,"search"));return t&&this.formBuilder.populateDatalistOptions(i,t),a}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name");let a;a=e.multiple&&e.options?Array.from(e.selectedOptions).map(e=>e.value).filter(e=>""!==e.trim()).map(e=>e.trim()):e.value.trim(),this.state.currentPage=1,Array.isArray(a)&&0<a.length||!Array.isArray(a)&&a?this.state.searchQueries[t]=a: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.elements.table.querySelectorAll(".ftable-multiselect-container").forEach(e=>{"function"==typeof e.resetMultiSelect&&e.resetMultiSelect()}),this.load()}getNextResizableHeader(t){var a=Array.from(this.elements.table.querySelectorAll("thead th.ftable-column-header-resizable"));for(let e=a.indexOf(t)+1;e<a.length;e++)if(null!==a[e].offsetParent)return a[e];return null}makeColumnResizable(s,e){k.addClass(s,"ftable-column-header-resizable"),this.elements.resizeBar||(this.elements.resizeBar=k.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),k.hide(this.elements.resizeBar));e=k.create("div",{className:"ftable-column-resize-handler",parent:e});let i=!1,o=0,r=0,n,l=null,c=0,d=null,h=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),i=!0,n=this.elements.mainContainer.getBoundingClientRect(),o=e.clientX,r=s.offsetWidth,(l=this.getNextResizableHeader(s))&&(c=l.offsetWidth,e=l.dataset.fieldName,d=this.options.fields[e]);e=s.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-n.left+"px",this.elements.resizeBar.style.top=e.top-n.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",k.show(this.elements.resizeBar),document.addEventListener("mousemove",h),document.addEventListener("mouseup",p)}),e=>{i&&(this.elements.resizeBar.style.left=e.clientX-n.left+"px")}),p=e=>{var t,a;i&&(i=!1,e=e.clientX-o,a=n.width,t=Math.max(50,r+e)/a*100,l&&(e=Math.max(50,c-e)/a*100,d.width=e.toFixed(2)+"%",l.style.width=d.width),(a=this.options.fields[s.dataset.fieldName]).width=t.toFixed(2)+"%",s.style.width=a.width,this.normalizeColumnWidths(),this.options.saveUserPreferences&&this.saveColumnSettings(),k.hide(this.elements.resizeBar),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",p))}}saveColumnSettings(){if(this.options.saveUserPreferences){let s={};this.columnList.forEach(e=>{var t,a=this.options.fields[e];a.action||(t=this.elements.table.querySelector(`[data-field-name="${e}"]`))&&(s[e]={width:t.style.width||a.width||"auto",visibility:a.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(s))}}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&&!e.action&&(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=k.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=k.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,k.create("td",{attributes:{colspan:t},textContent: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.createWarningModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,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}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new o({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.editRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new o({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,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 o({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createWarningModal(){this.modals.warning=new o({parent:this.elements.mainContainer,title:this.options.messages.warning,className:"ftable-warning-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.warning.close()}]})}createInfoModal(){this.modals.info=new o({parent:this.elements.mainContainer,title:"",className:"ftable-info-modal",closeOnOverlayClick:this.options.closeOnOverlayClick,buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new o({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",closeOnOverlayClick:!1,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=k.create("div",{className:"ftable-contextmenu-overlay",parent:document.body}),this.elements.columnSelectionMenu=k.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=k.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(t=>{var e=this.options.fields[t];if(!e.action){var a="hidden"!==e.visibility,s="fixed"===e.visibility,i="separator"===e.visibility,o=this.isFieldSorted(t),r=k.create("li",{className:"ftable-column-select-item",parent:l}),n=k.create("label",{className:"ftable-column-select-label",parent:r});if(!i){let e=k.create("input",{attributes:{type:"checkbox",id:"column-"+t},parent:n});e.checked=a,(s||o&&a)&&(e.disabled=!0,r.style.opacity="0.6"),e.disabled||e.addEventListener("change",()=>{this.setColumnVisibility(t,e.checked)})}s=k.create("span",{textContent:e.title||t,style:i?"font-weight: bold;":null,parent:n});o&&((a=k.create("span",{className:"ftable-sort-indicator",textContent:" (sorted)",parent:s})).style.fontSize="0.8em",a.style.color="#666")}})}positionColumnSelectionMenu(e){var t=this,a=e.pageX,e=e.pageY,e=(t.elements.columnSelectionMenu.style.position="absolute",t.elements.columnSelectionMenu.style.left=a+"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),s=window.innerWidth;s<a+e&&(a=Math.max(10,s-e-10),t.elements.columnSelectionMenu.style.left=a+"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(t){var e,a=k.create("button",{className:"ftable-toolbar-item "+(t.className||""),id:t.id||null,title:t.title||null,textContent:t.text||null,type:"button",parent:this.elements.toolbarDiv});return t.addIconSpan&&(e=k.create("span",{className:"ftable-toolbar-item-icon "+(t.className||""),parent:a}),t.text)&&(a.textContent="",a.append(e,t.text||"")),t.icon&&(e=k.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:a}),t.text)&&(a.textContent="",a.append(e,t.text||"")),t.onClick&&a.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.onClick(e)}),t.disabled&&(a.disabled=!0),a}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach((e,t)=>{this.addToolbarButton({text:e.text||"",className:"ftable-toolbar-item-custom "+(e.buttonClass||""),id:e.buttonId||"ftable-toolbar-item-custom-id-"+t,title:e.tooltip||"",icon:e.icon||null,onClick:"function"==typeof e.click?e.click:null})})}bindKeyboardEvents(){this.options.selecting&&(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={},t={}){if(!this.state.isLoading){t.fromPage1&&(this.state.currentPage=1),this.state.isLoading=!0,this.showLoadingIndicator();try{var a={...e,...this.buildLoadParams()},s=await this.performLoad(a);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(),this.normalizeColumnWidths()}}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 a=[],s=[];Object.entries(this.state.searchQueries).forEach(([t,e])=>{Array.isArray(e)?e.forEach(e=>{""!==e&&null!=e&&(a.push(e),s.push(t))}):""!==e&&(a.push(e),s.push(t))}),0<a.length&&(t.q=a,t.opt=s)}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 a=this.formBuilder.optionsCache.get(t,e);if(a&&!this.isCacheExpired(a,this.options.listCache))return a.data}let s;if("function"==typeof t)s=await t(e);else{if("string"!=typeof t)throw new Error("No valid listAction provided");s=this.options.forcePost?await l.post(t,e):await l.get(t,e)}if(s&&"OK"===s.Result)return this.options.listCache&&"string"==typeof t&&this.formBuilder.optionsCache.set(t,e,{data:s,timestamp:Date.now()}),s;throw new Error(s?.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.options.paging&&0===this.state.records.length&&0<this.state.totalRecordCount?(this.state.currentPage=1,this.load()):(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())}createTableRow(a){let s=k.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(a)}});return s.recordData=a,this.options.selecting&&this.options.selectingCheckboxes&&!this._userPlacedActions.has("select")&&this.addSelectingCell(s),this.columnList.forEach(e=>{var t=this.options.fields[e];if(t.action)switch(t.action){case"select":this.addSelectingCell(s);break;case"update":this.addEditCell(s);break;case"clone":this.addCloneCell(s);break;case"delete":this.addDeleteCell(s)}else this.addDataCell(s,a,e)}),this.options.actions.updateAction&&!this._userPlacedActions.has("update")&&this.addEditCell(s),this.options.actions.cloneAction&&!this._userPlacedActions.has("clone")&&this.addCloneCell(s),this.options.actions.deleteAction&&!this._userPlacedActions.has("delete")&&this.addDeleteCell(s),this.options.selecting&&this.makeRowSelectable(s),s}addSelectingCell(t){var e=k.create("td",{className:"ftable-command-column ftable-selecting-column",parent:t});k.create("input",{className:"norowselectonclick",attributes:{type:"checkbox"},parent:e}).addEventListener("change",e=>{this.toggleRowSelection(t)})}addDataCell(e,t,a){var s=this.options.fields[a],i=this.tableOptionsCache?.get(a),t=this.getDisplayText(t,a,i),i=k.create("td",{className:`${s.listClass||""} `+(s.listClassEntry||""),innerHTML:s.listEscapeHTML?k.escapeHtml(t):t,attributes:{"data-field-name":a},parent:e});"fixed"===s.visibility||"hidden"!==s.visibility&&"separator"!==s.visibility||k.hide(i)}addEditCell(t){var e=k.create("td",{className:"ftable-command-column",parent:t});k.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},innerHTML:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=k.create("td",{className:"ftable-command-column",parent:t});k.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},innerHTML:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=k.create("td",{className:"ftable-command-column",parent:t});k.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},innerHTML:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t,a=null){var s=this.options.fields[t],i=e[t],a=a||s.options;let o=i;return"date"===s.type&&i&&(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),s.dateFormat||this.options.defaultDateFormat):this.formatDate(i,s.dateLocale||this.options.defaultDateLocale)),"datetime-local"!==s.type&&"datetime"!==s.type||!i||(o="undefined"!=typeof FDatepicker?FDatepicker.formatDate(this._parseDate(i),s.dateFormat||this.options.defaultDateFormat):this.formatDateTime(i,s.dateLocale||this.options.defaultDateLocale)),"checkbox"===s.type&&(o=this.getCheckboxText(t,i)),a&&(t=this.findOptionByValue(a,i),o=t?t.DisplayText||t.text||t:i),(o=s.display&&"function"==typeof s.display?s.display({record:e,value:i,displayValue:o}):o)||""}_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 a=this._parseDate(e);try{return isNaN(a.getTime())?e:a.toLocaleDateString(t,{year:"numeric",month:"2-digit",day:"2-digit"})}catch{return e}}formatDateTime(e,t){if(!e)return"";var a=this._parseDate(e);try{return isNaN(a.getTime())?e:a.toLocaleString(t)}catch{return e}}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?this.options.messages.yes:this.options.messages.no}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):"object"==typeof e&&null!==e&&e.hasOwnProperty(t)?e[t]:null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?k.addClass(e,"ftable-row-even"):k.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.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,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,a=await this.formBuilder.createForm("edit",t);this.modals.editRecord.setContent(a),this.modals.editRecord.show(),this.currentForm=a,this.currentEditingRow=e,this.emit("formCreated",{form:a,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.currentForm&&this.currentForm.parentNode&&this.currentForm.remove(),this.currentForm=null,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 a,s=[];for(a of e)try{var i=await this.performDelete(a);s.push({key:a,success:"OK"===i.Result,result:i})}catch(e){s.push({key:a,success:!1,error:e.message})}s.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});t=s.filter(e=>!e.success).length;0<t&&this.showError(t+` of ${s.length} records could not be deleted`),this.refreshRowStyles(),this.updatePagingInfo()}}}deleteRecord(e){var t=e.recordData;let a=this.options.messages.deleteConfirmation;if("function"==typeof this.options.deleteConfirmation){t={row:e,record:t,deleteConfirmMessage:a,cancel:!1,cancelMessage:this.options.messages.cancel};if(this.options.deleteConfirmation(t),t.cancel)return void(t.cancelMessage&&this.showError(t.cancelMessage));a=t.deleteConfirmMessage}this.modals.deleteConfirm.setContent(`<p>${a}</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;let a;if(a=null===e||"object"!=typeof e||Array.isArray(e)?{[this.keyField]:e}:e,"function"==typeof t)return t(a);if("string"==typeof t)return l.post(t,a);throw new Error("No valid deleteAction provided")}getFormData(e){var t,a,s,i={};for([t,a]of new FormData(e).entries())t.endsWith("[]")?(i[s=t.slice(0,-2)]||(i[s]=[]),i[s].push(a)):i.hasOwnProperty(t)?Array.isArray(i[t])?i[t].push(a):i[t]=[i[t],a]:i[t]=a;return i}updateRowData(i,e){i.recordData={...i.recordData,...e},Object.keys(e).forEach(e=>{var t,a,s=this.options.fields[e];s&&(t=i.querySelector(`td[data-field-name="${e}"]`))&&(a=this.tableOptionsCache?.get(e),e=this.getDisplayText(i.recordData,e,a),t.innerHTML=s.listEscapeHTML?k.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");if(this.shiftKeyDown&&this.lastSelectedRow&&this.options.multiselect){this.clearAllSelections();var a=Array.from(this.elements.tableBody.querySelectorAll(".ftable-data-row")),s=a.indexOf(this.lastSelectedRow),i=a.indexOf(e),[i,o]=s<i?[s,i]:[i,s];for(let e=i;e<=o;e++)this.selectRow(a[e])}else this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e);t&&!this.shiftKeyDown||(this.lastSelectedRow=e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){k.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){k.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(a,s=!1){var i=this.options.fields[a];if(i&&!1!==i.sorting){i=this.state.sorting.findIndex(e=>e.fieldName===a);let e=!0,t="ASC";0<=i?"ASC"===this.state.sorting[i].direction?(t="DESC",this.state.sorting[i].direction=t):(this.state.sorting.splice(i,1),e=!1):this.state.sorting.push({fieldName:a,direction:t}),(!this.options.multiSorting||this.options.multiSortingCtrlKey&&!s)&&(this.state.sorting=e?[{fieldName:a,direction:t}]:[]),this.updateSortingHeaders(),this.load(),this.saveState()}}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{k.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&&k.addClass(t,"ftable-column-header-sorted-"+e.direction.toLowerCase())})}updatePagingInfo(){var e,t,a;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),a=this.options.messages.pagingInfo||"Showing {0}-{1} of {2}",this.elements.pageInfoSpan.textContent=a.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 a=this.calculatePageNumbers(e);let t=0;a.forEach(e=>{1<e-t&&k.create("span",{className:"ftable-page-number-space",textContent:"...",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 a=Math.ceil(this.state.totalRecordCount/this.state.pageSize);if(a<=1)this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML="";else{this.elements.pagingGotoArea.style.display="inline-block",this.elements.pagingGotoArea.innerHTML="";k.create("span",{textContent: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=k.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=a;e++)k.create("option",{attributes:{value:e},textContent: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<=a&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=k.create("input",{attributes:{type:"number",id:e,min:"1",max:a,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<=a?this.changePage(t):e.target.value=this.state.currentPage}))}}else this.elements.pagingGotoArea.style.display="none",this.elements.pagingGotoArea.innerHTML=""}createPageButton(e,t,a,s){s=k.create("span",{className:s+(a?" ftable-page-number-disabled":""),innerHTML:e,parent:this.elements.pagingListArea});a||(s.style.cursor="pointer",s.addEventListener("click",e=>{e.preventDefault(),this.changePage(t)}))}calculatePageNumbers(t){if(t<=7)return Array.from({length:t},(e,t)=>t+1);var a=this.state.currentPage,s=new Set([1,2,t-1,t]);for(let e=Math.max(1,a-1);e<=Math.min(t,a+1);e++)s.add(e);return Array.from(s).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(e),this.modals.error.show()):alert(e)}showWarning(e){this.modals.warning?(this.modals.warning.setContent(e),this.modals.warning.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(e),this.modals.info.show()):alert(e)}reload(e=!1){return this.clearListCache(),e?this.preservedSelections=new Set(this.state.selectedRecords):this.state.selectedRecords.clear(),this.load().then(()=>(e&&this.preservedSelections&&(this.restoreSelections(),this.preservedSelections=null),this))}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}restoreSelections(){if(this.preservedSelections)return this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>{var t=this.getKeyValue(e.recordData);t&&this.preservedSelections.has(t)&&this.selectRow(e)}),this}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,a="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:a}),this}clearFilters(){return this.state.filters=[],this}exportToCSV(e="table-data.csv"){var t,a,s,i=this.elements.table.cloneNode(!0),o=[],r=e=>`"${String(e||"").replace(/"/g,'""')}"`,n=[];for(t of i.querySelectorAll("thead th"))t.classList.contains("ftable-command-column-header")||t.classList.contains("ftable-toolbarsearch-column-header")||"none"===t.style.display||(a=t.textContent.trim(),n.push(r(a)));o.push(n.join(","));for(s of i.querySelectorAll("tbody tr"))if("none"!==s.style.display){var l,c,d,h=[];let e=!1;for(l of s.querySelectorAll("td"))l.classList.contains("ftable-command-column")||"none"===l.style.display||(l.querySelector("img, button, input, select")&&(l.innerHTML=l.textContent),c=l.innerHTML.replace(/<br\s*\/?>/gi,"\n"),(d=document.createElement("div")).innerHTML=c,h.push(r(d.textContent||"")),e=!0);e&&o.push(h.join(","))}var i=o.join("\n"),i=new Blob(["\ufeff"+i],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a");p.href=URL.createObjectURL(i),p.download=e,p.click(),p.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
2
2
  <!DOCTYPE html>
3
3
  <html>
4
4
  <head>
@@ -32,4 +32,4 @@
32
32
  </script>
33
33
  </body>
34
34
  </html>
35
- `;e.document.write(t),e.document.close()}async bulkDelete(e="Delete selected records?"){var t=this.getSelectedRows();if(0===t.length)this.showError("No records selected");else if(confirm(e)){var s,a=[];for(s of t.map(e=>this.getKeyValue(e.recordData)))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)});e=a.filter(e=>!e.success).length;0<e&&this.showError(e+` of ${a.length} records could not be deleted`)}}showColumn(e){this.setColumnVisibility(e,!0)}hideColumn(e){this.setColumnVisibility(e,!1)}setColumnVisibility(t,s){var a=this.options.fields[t];if(a)if(!s&&this.isFieldSorted(t))this.showError(`Cannot hide column "${a.title||t}" because it is currently sorted`);else if("fixed"!==a.visibility){a.visibility=s?"visible":"hidden";a=this.columnList.indexOf(t);if(0<=a){let e=a+1;this.options.selecting&&this.options.selectingCheckboxes&&(e+=1);t=`th:nth-child(${e}), td:nth-child(${e})`;this.elements.table.querySelectorAll(t).forEach(e=>{s?O.show(e):O.hide(e)})}this.options.saveUserPreferences&&(this.saveColumnSettings(),this.saveState())}}editRecordByKey(e){var t=this.getRowByKey(e);t?this.editRecord(t):this.showError(`Record with key '${e}' not found`)}async editRecordViaAjax(e,t,s={}){try{var a=this.keyField;if(!a)throw new Error("No key field defined in fTable options");var i={[a]:e,...s},o=this.options.forcePost?await l.post(t,i):await l.get(t,i);if(!o||!o.Record)throw new Error("Invalid response or missing Record");var r=o.Record,n=this.getRowByKey(e)||O.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":e}});n.recordData={...r},await this.editRecord(n)}catch(e){this.showError("Failed to load record for editing."),this.logger.error("editRecordViaAjax failed: "+e.message)}}openChildTable(e,t,s){this.options.openChildAsAccordion&&this.closeAllChildTables(),this.closeChildTable(e);var a=O.create("tr",{className:"ftable-child-row"}),i=O.create("td",{attributes:{colspan:this.getVisibleColumnCount()},parent:a}),i=O.create("div",{className:"ftable-child-table-container",parent:i}),a=(e.parentNode.insertBefore(a,e.nextSibling),(e.childRow=a).parentRow=e,new n(i,{...t,paging:void 0===t.paging||t.paging,pageSize:t.pageSize||10,sorting:void 0===t.sorting||t.sorting,selecting:!1,toolbarsearch:!0,messages:{...this.options.messages,...t.messages}}));a.close;return a.close=()=>{this.closeChildTable(e)},a.init(),s&&s(a),e.childTable=a}closeChildTable(e){e.childRow&&(e.childTable&&"function"==typeof e.childTable.destroy&&e.childTable.destroy(),e.childRow.remove(),e.childRow=null,e.childTable=null)}closeAllChildTables(){Object.values(this.elements.tableRows).forEach(e=>{e.childTable&&this.closeChildTable(e)})}getSortingInfo(){let t=this.options.messages||{};return this.state.sorting.map(e=>(this.options.fields[e.fieldName]?.title||e.fieldName)+` (${"ASC"===e.direction?t.ascending||"ascending":t.descending||"descending"})`).join(", ")}renderSortingInfo(){if(this.options.sortingInfoSelector&&this.options.sorting){var e=document.querySelector(this.options.sortingInfoSelector);if(e){e.innerHTML="";let t=this.options.messages||{};var s,a=t.sortingInfoPrefix?`<span class="ftable-sorting-prefix">${t.sortingInfoPrefix}</span> `:"",i=t.sortingInfoSuffix?` <span class="ftable-sorting-suffix">${t.sortingInfoSuffix}</span>`:"";0===this.state.sorting.length?e.innerHTML=t.sortingInfoNone||"":(s=this.getSortingInfo(),e.innerHTML=a+s+i,0<this.state.sorting.length&&((a=document.createElement("button")).textContent=t.resetSorting||"Reset Sorting",a.style.marginLeft="10px",a.classList.add("ftable-sorting-reset-btn"),a.addEventListener("click",e=>{e.preventDefault(),this.state.sorting=[],this.updateSortingHeaders(),this.load(),this.saveState()}),e.appendChild(a)),this.options.tableReset&&((s=document.createElement("button")).textContent=t.resetTable||"Reset Table",s.style.marginLeft="10px",s.classList.add("ftable-table-reset-btn"),s.addEventListener("click",e=>{e.preventDefault();e=t.resetTableConfirm;confirm(e)&&(this.userPrefs.remove("column-settings"),this.userPrefs.remove("table-state"),this.state.sorting=[],this.state.pageSize=this.options.pageSize,this.columnList.forEach(e=>{e=this.options.fields[e];e.visibility="fixed"===e.visibility?"fixed":"visible"}),location.reload())}),e.appendChild(s)))}}}static _waitForFieldReady(s,e,a,i=5e3){if(e){let t=e.querySelector(`[name="${s}"]`);if(t&&"SELECT"===t.tagName)if(1<t.options.length)a();else{let e=new MutationObserver(()=>{1<t.options.length&&(e.disconnect(),a())});e.observe(t,{childList:!0}),0<i&&setTimeout(()=>{e.disconnect(),1<t.options.length?a():console.warn(`FTable: Timeout waiting for field '${s}' to load options`)},i)}else console.warn(`FTable: Field '${s}' not found or not a <select>`)}else console.warn(`FTable: No form provided for waitForFieldReady('${s}')`)}static async waitForFieldReady(t,s,a=5e3){return new Promise(e=>{n._waitForFieldReady(t,s,e,a)})}}e.FTable=n,e.FtableModal=o,e.FTableHttpClient=l,"undefined"!=typeof module&&module.exports&&(module.exports=n,module.exports.FtableModal=o,module.exports.FTableHttpClient=l)})("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this);
35
+ `;e.document.write(t),e.document.close()}async bulkDelete(e="Delete selected records?"){var t=this.getSelectedRows();if(0===t.length)this.showError("No records selected");else if(confirm(e)){var a,s=[];for(a of t.map(e=>this.getKeyValue(e.recordData)))try{var i=await this.performDelete(a);s.push({key:a,success:"OK"===i.Result,result:i})}catch(e){s.push({key:a,success:!1,error:e.message})}s.filter(e=>e.success).forEach(({key:e})=>{e=this.getRowByKey(e);e&&this.removeRowFromTable(e)});e=s.filter(e=>!e.success).length;0<e&&this.showError(e+` of ${s.length} records could not be deleted`)}}showColumn(e){this.setColumnVisibility(e,!0)}hideColumn(e){this.setColumnVisibility(e,!1)}setColumnVisibility(t,a){var s=this.options.fields[t];if(s)if(!a&&this.isFieldSorted(t))this.showError(`Cannot hide column "${s.title||t}" because it is currently sorted`);else if("fixed"!==s.visibility){s.visibility=a?"visible":"hidden";s=this.columnList.indexOf(t);if(0<=s){let e=s+1;this.options.selecting&&this.options.selectingCheckboxes&&(e+=1);t=`th:nth-child(${e}), td:nth-child(${e})`;this.elements.table.querySelectorAll(t).forEach(e=>{a?k.show(e):k.hide(e)})}this.options.saveUserPreferences&&(this.saveColumnSettings(),this.saveState())}}editRecordByKey(e){var t=this.getRowByKey(e);t?this.editRecord(t):this.showError(`Record with key '${e}' not found`)}async editRecordViaAjax(e,t,a={}){try{var s=this.keyField;if(!s)throw new Error("No key field defined in fTable options");var i={[s]:e,...a},o=this.options.forcePost?await l.post(t,i):await l.get(t,i);if(!o||!o.Record)throw new Error("Invalid response or missing Record");var r=o.Record,n=this.getRowByKey(e)||k.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":e}});n.recordData={...r},await this.editRecord(n)}catch(e){this.showError("Failed to load record for editing."),this.logger.error("editRecordViaAjax failed: "+e.message)}}openChildTable(e,t,a){this.options.openChildAsAccordion&&this.closeAllChildTables(),this.closeChildTable(e);var s=k.create("tr",{className:"ftable-child-row"}),i=k.create("td",{attributes:{colspan:this.getVisibleColumnCount()},parent:s}),i=k.create("div",{className:"ftable-child-table-container",parent:i}),s=(e.parentNode.insertBefore(s,e.nextSibling),(e.childRow=s).parentRow=e,new n(i,{...t,paging:void 0===t.paging||t.paging,pageSize:t.pageSize||10,sorting:void 0===t.sorting||t.sorting,selecting:!1,toolbarsearch:!0,messages:{...this.options.messages,...t.messages}}));s.close;return s.close=()=>{this.closeChildTable(e)},s.init(),a&&a(s),e.childTable=s}closeChildTable(e){e.childRow&&(e.childTable&&"function"==typeof e.childTable.destroy&&e.childTable.destroy(),e.childRow.remove(),e.childRow=null,e.childTable=null)}closeAllChildTables(){Object.values(this.elements.tableRows).forEach(e=>{e.childTable&&this.closeChildTable(e)})}getSortingInfo(){let t=this.options.messages||{};return this.state.sorting.map(e=>(this.options.fields[e.fieldName]?.title||e.fieldName)+` (${"ASC"===e.direction?t.ascending||"ascending":t.descending||"descending"})`).join(", ")}renderSortingInfo(){if(this.options.sortingInfoSelector&&this.options.sorting){var e=document.querySelector(this.options.sortingInfoSelector);if(e){e.innerHTML="";let t=this.options.messages||{};var a,s=t.sortingInfoPrefix?`<span class="ftable-sorting-prefix">${t.sortingInfoPrefix}</span> `:"",i=t.sortingInfoSuffix?` <span class="ftable-sorting-suffix">${t.sortingInfoSuffix}</span>`:"";0===this.state.sorting.length?e.innerHTML=t.sortingInfoNone||"":(a=this.getSortingInfo(),e.innerHTML=s+a+i,0<this.state.sorting.length&&((s=document.createElement("button")).textContent=t.resetSorting||"Reset Sorting",s.style.marginLeft="10px",s.classList.add("ftable-sorting-reset-btn"),s.addEventListener("click",e=>{e.preventDefault(),this.state.sorting=[],this.updateSortingHeaders(),this.load(),this.saveState()}),e.appendChild(s)),this.options.tableReset&&((a=document.createElement("button")).textContent=t.resetTable||"Reset Table",a.style.marginLeft="10px",a.classList.add("ftable-table-reset-btn"),a.addEventListener("click",e=>{e.preventDefault();e=t.resetTableConfirm;confirm(e)&&(this.userPrefs.remove("column-settings"),this.userPrefs.remove("table-state"),this.state.sorting=[],this.state.pageSize=this.options.pageSize,this.columnList.forEach(e=>{e=this.options.fields[e];e.visibility="fixed"===e.visibility?"fixed":"visible"}),location.reload())}),e.appendChild(a)))}}}static _waitForFieldReady(a,e,s,i=5e3){if(e){let t=e.querySelector(`[name="${a}"]`);if(t&&"SELECT"===t.tagName)if(1<t.options.length)s();else{let e=new MutationObserver(()=>{1<t.options.length&&(e.disconnect(),s())});e.observe(t,{childList:!0}),0<i&&setTimeout(()=>{e.disconnect(),1<t.options.length?s():console.warn(`FTable: Timeout waiting for field '${a}' to load options`)},i)}else console.warn(`FTable: Field '${a}' not found or not a <select>`)}else console.warn(`FTable: No form provided for waitForFieldReady('${a}')`)}static async waitForFieldReady(t,a,s=5e3){return new Promise(e=>{n._waitForFieldReady(t,a,e,s)})}}e.FTable=n,e.FtableModal=o,e.FTableHttpClient=l,"undefined"!=typeof module&&module.exports&&(module.exports=n,module.exports.FtableModal=o,module.exports.FTableHttpClient=l)})("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this);
package/ftable.umd.js CHANGED
@@ -623,124 +623,46 @@ class FTableFormBuilder {
623
623
  this.options = options;
624
624
  this.dependencies = new Map(); // Track field dependencies
625
625
  this.optionsCache = new FTableOptionsCache();
626
- this.originalFieldOptions = new Map(); // Store original field.options
627
- this.resolvedFieldOptions = new Map(); // Store resolved options per context
628
-
629
- // Initialize with empty cache objects
630
- Object.keys(this.options.fields || {}).forEach(fieldName => {
631
- this.resolvedFieldOptions.set(fieldName, {});
632
- });
633
- Object.entries(this.options.fields).forEach(([fieldName, field]) => {
634
- this.originalFieldOptions.set(fieldName, {
635
- options: field.options,
636
- searchOptions: field.searchOptions
637
- });
638
- });
639
626
  }
640
627
 
641
- // Get options for specific context
628
+ // Get options for a field, respecting context ('search' prefers searchOptions over options).
629
+ // URL-level caching and concurrent-request deduplication is handled by FTableOptionsCache
630
+ // inside resolveOptions
642
631
  async getFieldOptions(fieldName, context = 'table', params = {}) {
643
632
  const field = this.options.fields[fieldName];
644
- const stored = this.originalFieldOptions.get(fieldName);
645
633
 
646
- // Determine which options source to use for this context
647
- let originalOptions;
648
- if (context === 'search') {
649
- // Prefer searchOptions; fall back to regular options
650
- originalOptions = stored?.searchOptions ?? stored?.options;
651
- } else {
652
- originalOptions = stored?.options;
653
- }
634
+ // For search context, prefer searchOptions and fall back to options
635
+ const optionsSource = (context === 'search')
636
+ ? (field.searchOptions ?? field.options)
637
+ : field.options;
654
638
 
655
- // If no options or already resolved for this context with same params, return cached
656
- if (!originalOptions) {
657
- return null;
658
- }
639
+ if (!optionsSource) return null;
659
640
 
660
- // Determine if we should skip caching for this specific context
661
- const shouldSkipCache = this.shouldForceRefreshForContext(field, context, params);
662
- const cacheKey = this.generateOptionsCacheKey(context, params);
663
- // Skip cache if configured or forceRefresh requested
664
- if (!shouldSkipCache && !params.forceRefresh) {
665
- const cached = this.resolvedFieldOptions.get(fieldName)[cacheKey];
666
- if (cached) return cached;
667
- }
641
+ const noCache = this.shouldSkipCache(field, context, params);
668
642
 
669
643
  try {
670
- // Create temp field with original options for resolution
671
- const tempField = { ...field, options: originalOptions };
672
- const resolved = await this.resolveOptions(tempField, {
673
- ...params
674
- }, context, shouldSkipCache);
675
-
676
- // we store the resolved option always
677
- this.resolvedFieldOptions.get(fieldName)[cacheKey] = resolved;
678
- return resolved;
644
+ return await this.resolveOptions(
645
+ { ...field, options: optionsSource },
646
+ params,
647
+ context,
648
+ noCache
649
+ );
679
650
  } catch (err) {
680
651
  console.error(`Failed to resolve options for ${fieldName} (${context}):`, err);
681
- return originalOptions;
682
- }
683
- }
684
-
685
- /**
686
- * Clear resolved options for specific field or all fields
687
- * @param {string|null} fieldName - Field name to clear, or null for all fields
688
- * @param {string|null} context - Context to clear ('table', 'create', 'edit'), or null for all contexts
689
- */
690
- clearResolvedOptions(fieldName = null, context = null) {
691
- if (fieldName) {
692
- // Clear specific field
693
- if (this.resolvedFieldOptions.has(fieldName)) {
694
- if (context) {
695
- // Clear specific context for specific field
696
- this.resolvedFieldOptions.get(fieldName)[context] = null;
697
- } else {
698
- // Clear all contexts for specific field
699
- this.resolvedFieldOptions.set(fieldName, { table: null, create: null, edit: null });
700
- }
701
- }
702
- } else {
703
- // Clear all fields
704
- if (context) {
705
- // Clear specific context for all fields
706
- this.resolvedFieldOptions.forEach((value, key) => {
707
- this.resolvedFieldOptions.get(key)[context] = null;
708
- });
709
- } else {
710
- // Clear everything
711
- this.resolvedFieldOptions.forEach((value, key) => {
712
- this.resolvedFieldOptions.set(key, { table: null, create: null, edit: null });
713
- });
714
- }
652
+ return optionsSource;
715
653
  }
716
654
  }
717
655
 
718
- // Helper method to determine caching behavior
719
- shouldForceRefreshForContext(field, context, params) {
720
- // Rename to reflect what it actually does now
656
+ // Determine whether to bypass the URL cache for this field/context
657
+ shouldSkipCache(field, context, params) {
658
+ if (params.forceRefresh) return true;
721
659
  if (!field.noCache) return false;
722
-
723
660
  if (typeof field.noCache === 'boolean') return field.noCache;
724
661
  if (typeof field.noCache === 'function') return field.noCache({ context, ...params });
725
662
  if (typeof field.noCache === 'object') return field.noCache[context] === true;
726
-
727
663
  return false;
728
664
  }
729
665
 
730
- generateOptionsCacheKey(context, params) {
731
- // Create a unique key based on context and dependency values
732
- const keyParts = [context];
733
-
734
- if (params.dependedValues) {
735
- // Include relevant dependency values in the cache key
736
- Object.keys(params.dependedValues).sort().forEach(key => {
737
- keyParts.push(`${key}=${params.dependedValues[key]}`);
738
- });
739
- }
740
-
741
- return keyParts.join('|');
742
- }
743
-
744
666
  shouldIncludeField(field, formType) {
745
667
  if (formType === 'create') {
746
668
  return field.create !== false && !(field.key === true && field.create !== true);
@@ -813,12 +735,6 @@ class FTableFormBuilder {
813
735
  return form;
814
736
  }
815
737
 
816
- shouldResolveOptions(options) {
817
- return options &&
818
- (typeof options === 'function' || typeof options === 'string') &&
819
- !Array.isArray(options) &&
820
- !(typeof options === 'object' && !Array.isArray(options) && Object.keys(options).length > 0);
821
- }
822
738
 
823
739
  buildDependencyMap() {
824
740
  this.dependencies.clear();
@@ -2177,13 +2093,13 @@ class FTable extends FTableEventEmitter {
2177
2093
  }
2178
2094
 
2179
2095
  // Start resolving in background
2180
- this.resolveAsyncFieldOptions().then(() => {
2096
+ this.resolveAllFieldOptionsForTable().then(() => {
2181
2097
  // re-render dynamic options rows — no server call
2182
2098
  // this is needed so that once options are resolved, the table shows correct display values
2183
2099
  // why: load() can actually finish faster than option resolving (and calling refreshDisplayValues
2184
2100
  // there is then pointless, since the resolving hasn't finished yet),
2185
2101
  // so we need to do it when the options are actually resolved (here)
2186
- // We could call await this.resolveAsyncFieldOptions() during load, but that would slow down the loading ...
2102
+ // We could call await this.resolveAllFieldOptionsForTable() during load, but that would slow down the loading ...
2187
2103
  setTimeout(() => {
2188
2104
  this.refreshDisplayValues();
2189
2105
  }, 0);
@@ -2404,22 +2320,17 @@ class FTable extends FTableEventEmitter {
2404
2320
  }
2405
2321
  }
2406
2322
 
2407
- async resolveAsyncFieldOptions() {
2323
+ async resolveAllFieldOptionsForTable() {
2324
+ this.tableOptionsCache = new Map();
2325
+
2408
2326
  const promises = this.columnList.map(async (fieldName) => {
2409
2327
  const field = this.options.fields[fieldName];
2410
2328
  if (field.action) return; // Skip action columns
2411
- const originalOptions = this.formBuilder.originalFieldOptions.get(fieldName)?.options;
2412
-
2413
- if (this.formBuilder.shouldResolveOptions(originalOptions)) {
2414
- try {
2415
- // Check if already resolved to avoid duplicate work
2416
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2417
- if (!this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey]) {
2418
- await this.formBuilder.getFieldOptions(fieldName, 'table');
2419
- }
2420
- } catch (err) {
2421
- console.error(`Failed to resolve table options for ${fieldName}:`, err);
2422
- }
2329
+ try {
2330
+ const resolved = await this.formBuilder.getFieldOptions(fieldName, 'table');
2331
+ if (resolved) this.tableOptionsCache.set(fieldName, resolved);
2332
+ } catch (err) {
2333
+ console.error(`Failed to resolve table options for ${fieldName}:`, err);
2423
2334
  }
2424
2335
  });
2425
2336
 
@@ -2438,9 +2349,7 @@ class FTable extends FTableEventEmitter {
2438
2349
  const cell = row.querySelector(`td[data-field-name="${fieldName}"]`);
2439
2350
  if (!cell) continue;
2440
2351
 
2441
- // Get table-specific options
2442
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
2443
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
2352
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
2444
2353
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
2445
2354
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
2446
2355
  }
@@ -4026,8 +3935,7 @@ class FTable extends FTableEventEmitter {
4026
3935
 
4027
3936
  addDataCell(row, record, fieldName) {
4028
3937
  const field = this.options.fields[fieldName];
4029
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4030
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
3938
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4031
3939
  const value = this.getDisplayText(record, fieldName, resolvedOptions);
4032
3940
 
4033
3941
  const cell = FTableDOMHelper.create('td', {
@@ -4530,8 +4438,7 @@ class FTable extends FTableEventEmitter {
4530
4438
  if (!cell) return;
4531
4439
 
4532
4440
  // Get display text
4533
- const cacheKey = this.formBuilder.generateOptionsCacheKey('table', {});
4534
- const resolvedOptions = this.formBuilder.resolvedFieldOptions.get(fieldName)?.[cacheKey];
4441
+ const resolvedOptions = this.tableOptionsCache?.get(fieldName);
4535
4442
  const value = this.getDisplayText(row.recordData, fieldName, resolvedOptions);
4536
4443
  cell.innerHTML = field.listEscapeHTML ? FTableDOMHelper.escapeHtml(value) : value;
4537
4444
  cell.className = `${field.listClass || ''} ${field.listClassEntry || ''}`.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liedekef/ftable",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
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",