@liedekef/ftable 1.0.0
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/LICENSE +21 -0
- package/README.md +77 -0
- package/ftable.esm.js +4749 -0
- package/ftable.js +4749 -0
- package/ftable.min.js +54 -0
- package/ftable.umd.js +4750 -0
- package/localization/ftable.ar.js +35 -0
- package/localization/ftable.bd.js +33 -0
- package/localization/ftable.ca.js +33 -0
- package/localization/ftable.cz.js +33 -0
- package/localization/ftable.de.js +33 -0
- package/localization/ftable.el.js +33 -0
- package/localization/ftable.es.js +33 -0
- package/localization/ftable.fa.js +33 -0
- package/localization/ftable.fr.js +33 -0
- package/localization/ftable.hr.js +33 -0
- package/localization/ftable.hu.js +33 -0
- package/localization/ftable.id.js +34 -0
- package/localization/ftable.it.js +33 -0
- package/localization/ftable.kr.js +33 -0
- package/localization/ftable.lt.js +33 -0
- package/localization/ftable.nl.js +33 -0
- package/localization/ftable.no.js +33 -0
- package/localization/ftable.pl.js +33 -0
- package/localization/ftable.pt-BR.js +33 -0
- package/localization/ftable.pt-PT.js +32 -0
- package/localization/ftable.ro.js +33 -0
- package/localization/ftable.ru.js +34 -0
- package/localization/ftable.se.js +33 -0
- package/localization/ftable.ta.js +33 -0
- package/localization/ftable.tr.js +33 -0
- package/localization/ftable.ua.js +33 -0
- package/localization/ftable.vi.js +33 -0
- package/localization/ftable.zh-CN.js +33 -0
- package/package.json +44 -0
- package/themes/basic/clone.png +0 -0
- package/themes/basic/close.png +0 -0
- package/themes/basic/column-asc.png +0 -0
- package/themes/basic/column-desc.png +0 -0
- package/themes/basic/column-sortable.png +0 -0
- package/themes/basic/delete.png +0 -0
- package/themes/basic/edit.png +0 -0
- package/themes/basic/ftable_basic.css +358 -0
- package/themes/basic/ftable_basic.less +89 -0
- package/themes/basic/ftable_basic.min.css +1 -0
- package/themes/ftable_theme_base.less +594 -0
- package/themes/lightcolor/add.png +0 -0
- package/themes/lightcolor/bg-thead.png +0 -0
- package/themes/lightcolor/blue/ftable.css +597 -0
- package/themes/lightcolor/blue/ftable.less +88 -0
- package/themes/lightcolor/blue/ftable.min.css +1 -0
- package/themes/lightcolor/blue/loading.gif +0 -0
- package/themes/lightcolor/clone.png +0 -0
- package/themes/lightcolor/close.png +0 -0
- package/themes/lightcolor/column-asc.png +0 -0
- package/themes/lightcolor/column-desc.png +0 -0
- package/themes/lightcolor/column-sortable.png +0 -0
- package/themes/lightcolor/delete.png +0 -0
- package/themes/lightcolor/edit.png +0 -0
- package/themes/lightcolor/ftable_lightcolor_base.less +337 -0
- package/themes/lightcolor/gray/ftable.css +597 -0
- package/themes/lightcolor/gray/ftable.less +88 -0
- package/themes/lightcolor/gray/ftable.min.css +1 -0
- package/themes/lightcolor/gray/loading.gif +0 -0
- package/themes/lightcolor/green/ftable.css +597 -0
- package/themes/lightcolor/green/ftable.less +88 -0
- package/themes/lightcolor/green/ftable.min.css +1 -0
- package/themes/lightcolor/green/loading.gif +0 -0
- package/themes/lightcolor/orange/ftable.css +597 -0
- package/themes/lightcolor/orange/ftable.less +88 -0
- package/themes/lightcolor/orange/ftable.min.css +1 -0
- package/themes/lightcolor/orange/loading.gif +0 -0
- package/themes/lightcolor/red/ftable.css +597 -0
- package/themes/lightcolor/red/ftable.less +88 -0
- package/themes/lightcolor/red/ftable.min.css +1 -0
- package/themes/lightcolor/red/loading.gif +0 -0
- package/themes/metro/add.png +0 -0
- package/themes/metro/blue/ftable.css +574 -0
- package/themes/metro/blue/ftable.less +9 -0
- package/themes/metro/blue/ftable.min.css +1 -0
- package/themes/metro/blue/loading.gif +0 -0
- package/themes/metro/brown/ftable.css +574 -0
- package/themes/metro/brown/ftable.less +9 -0
- package/themes/metro/brown/ftable.min.css +1 -0
- package/themes/metro/brown/loading.gif +0 -0
- package/themes/metro/clone.png +0 -0
- package/themes/metro/close.png +0 -0
- package/themes/metro/column-asc.png +0 -0
- package/themes/metro/column-desc.png +0 -0
- package/themes/metro/column-sortable.png +0 -0
- package/themes/metro/crimson/ftable.css +574 -0
- package/themes/metro/crimson/ftable.less +9 -0
- package/themes/metro/crimson/ftable.min.css +1 -0
- package/themes/metro/crimson/loading.gif +0 -0
- package/themes/metro/darkgray/ftable.css +574 -0
- package/themes/metro/darkgray/ftable.less +9 -0
- package/themes/metro/darkgray/ftable.min.css +1 -0
- package/themes/metro/darkgray/loading.gif +0 -0
- package/themes/metro/darkorange/ftable.css +574 -0
- package/themes/metro/darkorange/ftable.less +9 -0
- package/themes/metro/darkorange/ftable.min.css +1 -0
- package/themes/metro/darkorange/loading.gif +0 -0
- package/themes/metro/delete.png +0 -0
- package/themes/metro/edit.png +0 -0
- package/themes/metro/ftable_metro_base.less +450 -0
- package/themes/metro/green/ftable.css +574 -0
- package/themes/metro/green/ftable.less +9 -0
- package/themes/metro/green/ftable.min.css +1 -0
- package/themes/metro/green/loading.gif +0 -0
- package/themes/metro/lightgray/ftable.css +574 -0
- package/themes/metro/lightgray/ftable.less +9 -0
- package/themes/metro/lightgray/ftable.min.css +1 -0
- package/themes/metro/lightgray/loading.gif +0 -0
- package/themes/metro/pink/ftable.css +574 -0
- package/themes/metro/pink/ftable.less +9 -0
- package/themes/metro/pink/ftable.min.css +1 -0
- package/themes/metro/pink/loading.gif +0 -0
- package/themes/metro/purple/ftable.css +574 -0
- package/themes/metro/purple/ftable.less +9 -0
- package/themes/metro/purple/ftable.min.css +1 -0
- package/themes/metro/purple/loading.gif +0 -0
- package/themes/metro/red/ftable.css +574 -0
- package/themes/metro/red/ftable.less +9 -0
- package/themes/metro/red/ftable.min.css +1 -0
- package/themes/metro/red/loading.gif +0 -0
package/ftable.min.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
let JTABLE_DEFAULT_MESSAGES={serverCommunicationError:"An error occurred while communicating to the server.",loadingMessage:"Loading records...",noDataAvailable:"No data available!",addNewRecord:"Add new record",editRecord:"Edit record",areYouSure:"Are you sure?",deleteConfirmation:"This record will be deleted. Are you sure?",save:"Save",saving:"Saving",cancel:"Cancel",deleteText:"Delete",deleting:"Deleting",error:"Error",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 FTableOptionsCache{constructor(){this.cache=new Map}generateKey(e,t){return e+"?"+Object.keys(t||{}).sort().map(e=>e+"="+t[e]).join("&")}get(e,t){e=this.generateKey(e,t);return this.cache.get(e)}set(e,t,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()}size(){return this.cache.size}}class FTableEventEmitter{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}}class FTableLogger{static LOG_LEVELS={DEBUG:0,INFO:1,WARN:2,ERROR:3,NONE:4};constructor(e=FTableLogger.LOG_LEVELS.WARN){this.level=e}log(t,e){var a;!window.console||t<this.level||(a=Object.keys(FTableLogger.LOG_LEVELS).find(e=>FTableLogger.LOG_LEVELS[e]===t),console.log(`fTable ${a}: `+e))}debug(e){this.log(FTableLogger.LOG_LEVELS.DEBUG,e)}info(e){this.log(FTableLogger.LOG_LEVELS.INFO,e)}warn(e){this.log(FTableLogger.LOG_LEVELS.WARN,e)}error(e){this.log(FTableLogger.LOG_LEVELS.ERROR,e)}}class FTableDOMHelper{static create(e,t={}){let a=document.createElement(e);return t.className&&(a.className=t.className),t.attributes&&Object.entries(t.attributes).forEach(([e,t])=>{a.setAttribute(e,t)}),t.text&&(a.textContent=t.text),t.html&&(a.innerHTML=t.html),t.parent&&t.parent.appendChild(a),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={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>t[e])}}class FTableHttpClient{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 r=i.headers.get("content-type");if(r&&r.includes("application/json"))return await i.json();var o=await i.text();try{return JSON.parse(o)}catch{return{Result:"OK",Message:o}}}catch(e){throw e}}static async get(e,t={}){let a=new URL(e,window.location.href);return Object.entries(t).forEach(([t,e])=>{null!=e&&(Array.isArray(e)?e.forEach(e=>{null!=e&&a.searchParams.append(t,e)}):a.searchParams.append(t,e))}),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(([t,e])=>{null!=e&&(Array.isArray(e)?e.forEach(e=>{null!=e&&a.append(t+"[]",e)}):a.append(t,e))}),this.request(e.toString(),{method:"POST",body:a})}}class FTableUserPreferences{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 JtableModal{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=FTableDOMHelper.create("div",{className:"ftable-modal-overlay",parent:this.options.parent}),this.modal=FTableDOMHelper.create("div",{className:"ftable-modal "+this.options.className,parent:this.overlay});FTableDOMHelper.create("h2",{className:"ftable-modal-header",text:this.options.title,parent:this.modal});FTableDOMHelper.create("span",{className:"ftable-modal-close",html:"×",parent:this.modal}).addEventListener("click",()=>this.close());var e=FTableDOMHelper.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=FTableDOMHelper.create("div",{className:"ftable-modal-footer",parent:this.modal});this.options.buttons.forEach(e=>{var t=FTableDOMHelper.create("button",{className:"ftable-dialog-button "+(e.className||""),html:`<span>${e.text}</span>`,parent:a});e.onClick&&t.addEventListener("click",e.onClick)})}return this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.hide(),this}show(){return this.modal||this.create(),this.overlay.style.display="flex",this.isOpen=!0,this}hide(){return this.overlay&&(this.overlay.style.display="none"),this.isOpen=!1,this}close(){return this.hide(),this.options.onClose&&this.options.onClose(),this}destroy(){return this.overlay&&this.overlay.remove(),this.isOpen=!1,this}setContent(e){this.options.content=e;var t=this.modal.querySelector(".ftable-modal-body");t&&(t.innerHTML="","string"==typeof e?t.innerHTML=e:t.appendChild(e))}}class FTableFormBuilder{constructor(e){this.options=e,this.dependencies=new Map,this.optionsCache=new FTableOptionsCache,this.originalFieldOptions=new Map}storeOriginalFieldOptions(){0<this.originalFieldOptions.size||Object.entries(this.options.fields).forEach(([e,t])=>{!t.options||"function"!=typeof t.options&&"string"!=typeof t.options||this.originalFieldOptions.set(e,t.options)})}shouldIncludeField(e,t){return"create"===t?!1!==e.create&&!(!0===e.key&&!0!==e.create):"edit"!==t||!1!==e.edit}createFieldContainer(e,t,a,s){var i=FTableDOMHelper.create("div",{className:"ftable-input-field-container",attributes:{id:"ftable-input-field-container-div-"+e}}),t=(FTableDOMHelper.create("div",{className:"ftable-input-label",text:t.inputTitle||t.title,parent:i}),this.createInput(e,t,a[e],s));return i.appendChild(t),i}async resolveNonDependantFieldOptions(o){this.storeOriginalFieldOptions();var e=Object.entries(this.options.fields).map(async([t,e])=>{if(!e.dependsOn){var a=this.originalFieldOptions.get(t)||e.options;if(a&&("function"==typeof a||"string"==typeof a))try{var s={dependedValues:o},i={...e,options:a},r=await this.resolveOptions(i,s);e.options=r}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}});await Promise.all(e)}async createForm(a="create",s={}){this.currentFormRecord=s,await this.resolveNonDependantFieldOptions(s);let i=FTableDOMHelper.create("form",{className:`ftable-dialog-form ftable-${a}-form`});return this.buildDependencyMap(),Object.entries(this.options.fields).forEach(([e,t])=>{this.shouldIncludeField(t,a)&&(e=this.createFieldContainer(e,t,s,a),i.appendChild(e))}),this.setupDependencyListeners(i),i}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(t,e={}){if(!t.options)return[];if(Array.isArray(t.options)||"object"==typeof t.options)return t.options;let a,s=!1;e={...e,clearCache:()=>{s=!0}};if("function"==typeof t.options)a=await t.options(e);else{if("string"!=typeof t.options)return[];a=t.options}e=a&&"object"==typeof a&&a.url,t=e?a.url:a;if(s=e&&void 0!==a.noCache?a.noCache:s,"string"!=typeof t)return[];if(!s){e=this.optionsCache.get(t,{});if(e)return e}try{var i=await FTableHttpClient.get(t),r=i.Options||i.options||i||[];return s||this.optionsCache.set(t,{},r),r}catch(e){return console.error(`Failed to load options from ${t}:`,e),[]}}clearOptionsCache(e=null,t=null){this.optionsCache.clear(e,t)}async handleDependencyChange(e,t=""){var a,s,i={};for([a,s]of Object.entries(this.options.fields)){var r=e.querySelector(`[name="${a}"]`);r&&("checkbox"===r.type?i[a]=r.checked?"1":"0":i[a]=r.value)}var o,l,n=e.classList.contains("ftable-create-form")?"create":"edit",c={record:this.currentFormRecord||{},source:n,form:e,dependedValues:i};for([o,l]of Object.entries(this.options.fields))if(l.dependsOn){if(""!==t)if(!l.dependsOn.split(",").map(e=>e.trim()).filter(e=>e).includes(t))continue;var d=e.querySelector(`[name="${o}"]`);if(d&&this.shouldIncludeField(l,n))try{"SELECT"===d.tagName?d.innerHTML='<option value="">Loading...</option>':"INPUT"===d.tagName&&d.list&&(h=document.getElementById(d.list.id))&&(h.innerHTML="");var h,p={...c,dependsOnField:l.dependsOn,dependsOnValue:i[l.dependsOn]},m=this.originalFieldOptions.get(o)||l.options,u={...l,options:m},b=await this.resolveOptions(u,p);"SELECT"===d.tagName?this.populateSelectOptions(d,b,""):"INPUT"===d.tagName&&d.list&&this.populateDatalistOptions(d.list,b)}catch(e){console.error(`Error loading options for ${o}:`,e),"SELECT"===d.tagName&&(d.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=FTableDOMHelper.create("div",{className:`ftable-input ftable-${t.type||"text"}-input`});let r;switch(null==a&&(a=t.defaultValue),!t.type&&t.options&&(t.type="select"),t.type){case"hidden":r=this.createHiddenInput(e,t,a);break;case"textarea":r=this.createTextarea(e,t,a);break;case"select":r=this.createSelect(e,t,a);break;case"checkbox":r=this.createCheckbox(e,t,a);break;case"radio":r=this.createRadioGroup(e,t,a);break;case"datalist":r=this.createDatalistInput(e,t,a);break;case"file":r=this.createFileInput(e,t,a);break;default:r=this.createTypedInput(e,t,a)}return"function"==typeof t.input?(s={field:t,record:this.currentFormRecord,inputField:r,formType:s},"string"==typeof(s=t.input(s))?i.innerHTML=s:s instanceof Node?i.appendChild(s):i.appendChild(r)):i.appendChild(r),t.explain&&FTableDOMHelper.create("div",{className:"ftable-field-explain",html:`<small>${t.explain}</small>`,parent:i}),i}createTypedInput(e,t,a){var s,a={type:t.type||"text",id:"Edit-"+e,placeholder:t.placeholder||"",value:a||"",class:t.inputClass||""};let i=e,r=(t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(a,s),void 0!==s.multiple&&!1!==s.multiple)&&(i=e+"[]"),a.name=i,t.required&&(a.required="required"),t.readonly&&(a.readonly="readonly"),t.disabled&&(a.disabled="disabled"),FTableDOMHelper.create("input",{attributes:a}));return r.addEventListener("keypress",e=>{if(13===(e.keyCode||e.which))return e.preventDefault(),r.dispatchEvent(new Event("change",{bubbles:!0})),!1}),r}createDatalistInput(e,t,a){a=FTableDOMHelper.create("input",{attributes:{type:"text",name:e,id:"Edit-"+e,placeholder:t.placeholder||"",value:a||"",class:t.inputClass||"",list:e+"-datalist"}}),e=FTableDOMHelper.create("datalist",{attributes:{id:e+"-datalist"}});return t.options&&this.populateDatalistOptions(e,t.options),document.body.appendChild(e),a.datalistElement=e,a}populateDatalistOptions(a,e){a.innerHTML="",Array.isArray(e)?e.forEach(e=>{FTableDOMHelper.create("option",{attributes:{value:e.Value||e.value||e},text:e.DisplayText||e.text||e,parent:a})}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{FTableDOMHelper.create("option",{attributes:{value:e},text:t,parent:a})})}createHiddenInput(e,t,a){e={type:"hidden",name:e,id:"Edit-"+e,value:a||""};return t.inputAttributes&&(a=this.parseInputAttributes(t.inputAttributes),Object.assign(e,a)),FTableDOMHelper.create("input",{attributes:e})}createTextarea(e,t,a){e={name:e,id:"Edit-"+e,class:t.inputClass||"",placeholder:t.placeholder||""},t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(e,t)),t=FTableDOMHelper.create("textarea",{attributes:e});return t.value=a||"",t}createSelect(e,t,a){var e={name:e,id:"Edit-"+e,class:t.inputClass||""},s=(t.inputAttributes&&(s=this.parseInputAttributes(t.inputAttributes),Object.assign(e,s)),FTableDOMHelper.create("select",{attributes:e}));return t.options&&this.populateSelectOptions(s,t.options,a),s}createRadioGroup(r,o,l){let n=FTableDOMHelper.create("div",{className:"ftable-radio-group"});return o.options&&(Array.isArray(o.options)?o.options:"object"==typeof o.options?Object.entries(o.options).map(([e,t])=>({Value:e,DisplayText:t})):[]).forEach((e,t)=>{var a=FTableDOMHelper.create("div",{className:"ftable-radio-wrapper",parent:n}),s=r+"_"+t,i={type:"radio",name:r,id:s,value:e.Value||e.value||e,class:o.inputClass||""},t=(o.required&&0===t&&(i.required="required"),o.disabled&&(i.disabled="disabled"),o.inputAttributes&&(t=this.parseInputAttributes(o.inputAttributes),Object.assign(attributes,t)),FTableDOMHelper.create("input",{attributes:i,parent:a}));i.value===l&&(t.checked=!0),FTableDOMHelper.create("label",{attributes:{for:s},text:e.DisplayText||e.text||e,parent:a})}),n}createCheckbox(e,a,s){function i(e,t){return null==t&&(t=0),e.values&&void 0!==e.values[t]?e.values[t]:t?"Yes":"No"}var t=FTableDOMHelper.create("div",{className:"ftable-checkbox-wrapper"}),r=[1,"1",!0,"true"].includes(s),s=i(a,s);let o=FTableDOMHelper.create("input",{attributes:{type:"checkbox",name:e,id:"Edit-"+e,class:a.inputClass||"",value:"1"},parent:t});o.checked=r;r=FTableDOMHelper.create("label",{attributes:{for:"Edit-"+e},parent:t});if(a.formText&&FTableDOMHelper.create("span",{text:a.formText,parent:r}),a.values){let t=FTableDOMHelper.create("span",{className:"ftable-checkbox-dynamic-value",text:" "+s,parent:r});o.addEventListener("change",()=>{var e=o.checked?"1":"0",e=i(a,e);t.textContent=" "+e})}return t}createDateInput(e,t,a){return FTableDOMHelper.create("input",{attributes:{type:"date",name:e,id:"Edit-"+e,class:t.inputClass||"",value:a||""}})}populateSelectOptions(s,e,i){s.innerHTML="",Array.isArray(e)?e.forEach(e=>{var t=void 0!==e.Value?e.Value:void 0!==e.value?e.value:e;let a=FTableDOMHelper.create("option",{attributes:{value:t},text:e.DisplayText||e.text||e,parent:s});e.Data&&"object"==typeof e.Data&&Object.entries(e.Data).forEach(([e,t])=>{a.setAttribute("data-"+e,t)}),a.value==i&&(a.selected=!0)}):"object"==typeof e&&Object.entries(e).forEach(([e,t])=>{t=FTableDOMHelper.create("option",{attributes:{value:e},text:t,parent:s});e==i&&(t.selected=!0)})}createFileInput(e,t,a){var s={type:"file",id:"Edit-"+e,class:t.inputClass||""};let i=e;return t.inputAttributes&&(t=this.parseInputAttributes(t.inputAttributes),Object.assign(s,t),void 0!==t.multiple&&!1!==t.multiple)&&(i=e+"[]"),s.name=i,FTableDOMHelper.create("input",{attributes:s})}}class FTable extends FTableEventEmitter{constructor(e,t={}){if(super(),this.element="string"==typeof e?document.querySelector(e):e,e.ftableInstance)return e.ftableInstance;this.options=this.mergeOptions(t),this.logger=new FTableLogger(this.options.logLevel),this.userPrefs=new FTableUserPreferences("",this.options.saveFTableUserPreferencesMethod),this.formBuilder=new FTableFormBuilder(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._recalculatedOnce=!1,(this.element.ftableInstance=this).init()}mergeOptions(e){var t={tableId:void 0,logLevel:FTableLogger.LOG_LEVELS.WARN,actions:{},fields:{},animationsEnabled:!0,loadingAnimationDelay:1e3,defaultDateFormat:"yyyy-mm-dd",saveFTableUserPreferences:!0,saveFTableUserPreferencesMethod:"localStorage",defaultSorting:"",paging:!1,pageSize:10,gotoPageArea:"combobox",sorting:!1,multiSorting:!1,selecting:!1,multiselect:!1,toolbarsearch:!1,toolbarreset:!0,searchDebounceMs:300,listCache:3e4,messages:{...JTABLE_DEFAULT_MESSAGES}};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}static setMessages(e){Object.assign(JTABLE_DEFAULT_MESSAGES,e)}init(){this.processFieldDefinitions(),this.createMainStructure(),this.setupFTableUserPreferences(),this.createTable(),this.createModals(),this.options.paging&&this.createPagingUI(),this.resolveAsyncFieldOptions().then(()=>{setTimeout(()=>{this.refreshDisplayValues()},0)}).catch(console.error),this.bindEvents(),this.renderSortingInfo()}parseDefaultSorting(e){let r=[];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&&r.push({fieldName:t,direction:e})}}),r}addEssentialCSS(){var e;document.querySelector("#ftable-essential-css")||((e=document.createElement("style")).id="ftable-essential-css",e.textContent=`
|
|
2
|
+
.ftable-row-animation {
|
|
3
|
+
transition: background-color 0.3s ease;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.ftable-row-added {
|
|
7
|
+
background-color: #d4edda !important;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.ftable-row-edited {
|
|
11
|
+
background-color: #d1ecf1 !important;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ftable-row-deleted {
|
|
15
|
+
opacity: 0;
|
|
16
|
+
transform: translateY(-10px);
|
|
17
|
+
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ftable-toolbarsearch {
|
|
21
|
+
width: 90%;
|
|
22
|
+
}
|
|
23
|
+
`,document.head.appendChild(e))}createPagingUI(){this.elements.bottomPanel=FTableDOMHelper.create("div",{className:"ftable-bottom-panel",parent:this.elements.mainContainer}),this.elements.leftArea=FTableDOMHelper.create("div",{className:"ftable-left-area",parent:this.elements.bottomPanel}),this.elements.rightArea=FTableDOMHelper.create("div",{className:"ftable-right-area",parent:this.elements.bottomPanel}),this.elements.pagingListArea=FTableDOMHelper.create("div",{className:"ftable-page-list",parent:this.elements.leftArea}),this.elements.pagingGotoArea=FTableDOMHelper.create("div",{className:"ftable-page-goto",parent:this.elements.leftArea}),this.elements.pageInfoSpan=FTableDOMHelper.create("div",{className:"ftable-page-info",parent:this.elements.rightArea}),!1!==this.options.pageSizeChangeArea&&this.createPageSizeSelector()}createPageSizeSelector(){var e=FTableDOMHelper.create("span",{className:"ftable-page-size-change",parent:this.elements.leftArea});FTableDOMHelper.create("span",{text:this.options.messages.pageSizeChangeLabel,parent:e});let a=FTableDOMHelper.create("select",{className:"ftable-page-size-select",parent:e});(this.options.pageSizes||[10,25,50,100]).forEach(e=>{var t=FTableDOMHelper.create("option",{attributes:{value:e},text: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=>{e=this.options.fields[e];!0===e.key?(void 0!==e.create&&e.create||(e.create=!0,e.type="hidden"),void 0!==e.edit&&e.edit||(e.edit=!0,e.type="hidden"),e.hasOwnProperty("visibility")||(e.visibility="hidden")):(void 0===e.create&&(e.create=!0),void 0===e.edit&&(e.edit=!0),void 0===e.list&&(e.list=!0),e.hasOwnProperty("visibility")||(e.visibility="visible"))}),this.columnList=this.fieldList.filter(e=>{e=this.options.fields[e];return!1!==e.list&&"hidden"!==e.type}),this.keyField=this.fieldList.find(e=>!0===this.options.fields[e].key),this.keyField||this.logger.warn("No key field defined")}async resolveAsyncFieldOptions(){this.formBuilder.storeOriginalFieldOptions();for(var t of this.columnList){var e=this.options.fields[t],a=this.formBuilder.originalFieldOptions.get(t)||e.options;if(a&&("function"==typeof a||"string"==typeof a)&&!Array.isArray(a)&&("object"!=typeof a||Array.isArray(a)||!(0<Object.keys(a).length)))try{var s={...e,options:a},i=await this.formBuilder.resolveOptions(s);e.options=i}catch(e){console.error(`Failed to resolve options for ${t}:`,e)}}}refreshDisplayValues(){var e=this.elements.tableBody.querySelectorAll(".ftable-data-row");0!==e.length&&e.forEach(s=>{this.columnList.forEach(e=>{var t,a=this.options.fields[e];a.options&&"function"!=typeof a.options&&"string"!=typeof a.options&&(t=s.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(s.recordData,e),t.innerHTML=a.listEscapeHTML?FTableDOMHelper.escapeHtml(e):e)})})}createMainStructure(){this.elements.mainContainer=FTableDOMHelper.create("div",{className:"ftable-main-container",parent:this.element}),this.options.title&&(this.elements.titleDiv=FTableDOMHelper.create("div",{className:"ftable-title",parent:this.elements.mainContainer}),FTableDOMHelper.create("div",{className:"ftable-title-text",text:this.options.title,parent:this.elements.titleDiv})),this.elements.toolbarDiv=FTableDOMHelper.create("div",{className:"ftable-toolbar",parent:this.elements.titleDiv||this.elements.mainContainer}),this.elements.tableDiv=FTableDOMHelper.create("div",{className:"ftable-table-div",parent:this.elements.mainContainer})}createTable(){this.elements.table=FTableDOMHelper.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=FTableDOMHelper.create("thead",{parent:this.elements.table});let i=FTableDOMHelper.create("tr",{parent:e});if(this.options.selecting){var t=FTableDOMHelper.create("th",{className:"ftable-column-header ftable-column-header-select",parent:i});if(this.options.multiselect){let e=FTableDOMHelper.create("input",{attributes:{type:"checkbox"},parent:t});e.addEventListener("change",()=>{this.toggleSelectAll(e.checked)})}}this.columnList.forEach(e=>{var t=this.options.fields[e],a=FTableDOMHelper.create("th",{className:"ftable-column-header",attributes:{"data-field-name":e},parent:i}),s=(t.width&&(a.style.width=t.width),FTableDOMHelper.create("div",{className:"ftable-column-header-container",parent:a}));FTableDOMHelper.create("span",{className:"ftable-column-header-text",text:t.title||e,parent:s}),this.options.sorting&&!1!==t.sorting&&(FTableDOMHelper.addClass(a,"ftable-column-header-sortable"),a.addEventListener("click",()=>this.sortByColumn(e))),!1!==this.options.columnResizable&&!1!==t.columnResizable&&this.makeColumnResizable(a,s),"hidden"===t.visibility&&FTableDOMHelper.hide(a)}),this.options.actions.updateAction&&FTableDOMHelper.create("th",{className:"ftable-command-column-header ftable-column-header-edit",parent:i}),this.options.actions.cloneAction&&FTableDOMHelper.create("th",{className:"ftable-command-column-header ftable-column-header-clone",parent:i}),this.options.actions.deleteAction&&FTableDOMHelper.create("th",{className:"ftable-command-column-header ftable-column-header-delete",parent:i}),this.options.toolbarsearch&&this.createSearchHeaderRow(e).catch(e=>{console.error("Failed to create search header row:",e)})}async createSearchHeaderRow(e){var t,a,s=FTableDOMHelper.create("tr",{className:"ftable-toolbarsearch-row",parent:e});this.options.selecting&&FTableDOMHelper.create("th",{parent:s});for(t of this.columnList){var i=this.options.fields[t],r=!1!==i.searchable,o=FTableDOMHelper.create("th",{className:"ftable-toolbarsearch-column-header",parent:s});if(r){r=FTableDOMHelper.create("div",{className:"ftable-column-header-container",parent:o});let e;switch(!i.type&&i.options&&(i.type="select"),i.type){case"date":e=FTableDOMHelper.create("input",{attributes:{type:"date","data-field-name":t,class:"ftable-toolbarsearch"}});break;case"checkbox":e=i.values?await this.createSelectForSearch(t,i,!0):FTableDOMHelper.create("input",{attributes:{type:"text","data-field-name":t,class:"ftable-toolbarsearch",placeholder:"Search..."}});break;case"select":e=i.options?await this.createSelectForSearch(t,i,!1):FTableDOMHelper.create("input",{attributes:{type:"text","data-field-name":t,class:"ftable-toolbarsearch",placeholder:"Search..."}});break;default:e=FTableDOMHelper.create("input",{attributes:{type:"text","data-field-name":t,class:"ftable-toolbarsearch",placeholder:"Search..."}})}e&&(r.appendChild(e),"SELECT"===e.tagName?e.addEventListener("change",e=>{this.handleSearchInputChange(e)}):e.addEventListener("input",e=>{this.handleSearchInputChange(e)}))}"hidden"===i.visibility&&FTableDOMHelper.hide(o)}this.options.toolbarsearch&&this.options.toolbarreset&&(e=FTableDOMHelper.create("th",{className:"ftable-toolbarsearch-reset",parent:s}),0<(a=(this.options.actions.updateAction?1:0)+(this.options.actions.deleteAction?1:0))?e.colSpan=a:FTableDOMHelper.addClass(e,"ftable-command-column-header"),FTableDOMHelper.create("button",{className:"ftable-toolbarsearch-reset-button",text:this.options.messages.resetSearch,parent:e}).addEventListener("click",()=>this.resetSearch()))}async createSelectForSearch(e,t,a){let s=FTableDOMHelper.create("select",{attributes:{"data-field-name":e,class:"ftable-toolbarsearch"}}),i;return a&&t.values?i=Object.entries(t.values).map(([e,t])=>({Value:e,DisplayText:t})):t.options&&(i=await this.formBuilder.resolveOptions(t)),0<i?.length&&(""===i[0].Value||""===i[0].value||""===i[0]||""===i[0].DisplayText&&null==i[0].Value)||FTableDOMHelper.create("option",{attributes:{value:""},text:"",parent:s}),i&&Array.isArray(i)?i.forEach(e=>{FTableDOMHelper.create("option",{attributes:{value:void 0!==e.Value?e.Value:void 0!==e.value?e.value:e},text:e.DisplayText||e.text||e,parent:s})}):i&&"object"==typeof i&&Object.entries(i).forEach(([e,t])=>{FTableDOMHelper.create("option",{attributes:{value:e},text:t,parent:s})}),s}handleSearchInputChange(e){var e=e.target,t=e.getAttribute("data-field-name"),e=e.value.trim();e?this.state.searchQueries[t]=e:delete this.state.searchQueries[t],clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.load()},this.options.searchDebounceMs)}resetSearch(){this.state.searchQueries={},this.elements.table.querySelectorAll(".ftable-toolbarsearch").forEach(e=>{"SELECT"===e.tagName?e.selectedIndex=0:e.value=""}),this.load()}makeColumnResizable(a,e){this.elements.resizeBar||(this.elements.resizeBar=FTableDOMHelper.create("div",{className:"ftable-column-resize-bar",parent:this.elements.mainContainer}),FTableDOMHelper.hide(this.elements.resizeBar));e=FTableDOMHelper.create("div",{className:"ftable-column-resize-handler",parent:e});let s=!1,i=0,r=0,o=(e.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),s=!0,i=e.clientX,r=a.offsetWidth;var e=a.getBoundingClientRect(),t=this.elements.mainContainer.getBoundingClientRect();this.elements.resizeBar.style.left=e.right-t.left+"px",this.elements.resizeBar.style.top=e.top-t.top+"px",this.elements.resizeBar.style.height=this.elements.table.offsetHeight+"px",FTableDOMHelper.show(this.elements.resizeBar),document.addEventListener("mousemove",o),document.addEventListener("mouseup",l)}),e=>{var t;s&&(t=e.clientX-i,Math.max(50,r+t),t=this.elements.mainContainer.getBoundingClientRect(),this.elements.resizeBar.style.left=e.clientX-t.left+"px")}),l=e=>{s&&(s=!1,e=e.clientX-i,e=Math.max(50,r+e),a.style.width=e+"px",FTableDOMHelper.hide(this.elements.resizeBar),document.removeEventListener("mousemove",o),document.removeEventListener("mouseup",l),this.options.saveFTableUserPreferences)&&this.saveColumnSettings()}}saveColumnSettings(){if(this.options.saveFTableUserPreferences){let s={};this.columnList.forEach(e=>{var t,a=this.elements.table.querySelector(`[data-field-name="${e}"]`);a&&(t=this.options.fields[e],s[e]={width:a.style.width||t.width||"auto",visibility:t.visibility||"visible"})}),this.userPrefs.set("column-settings",JSON.stringify(s))}}saveState(){var e;this.options.saveFTableUserPreferences&&(e={sorting:this.state.sorting,pageSize:this.state.pageSize},this.userPrefs.set("table-state",JSON.stringify(e)))}loadColumnSettings(){if(this.options.saveFTableUserPreferences){var e=this.userPrefs.get("column-settings");if(e)try{var t=JSON.parse(e);Object.entries(t).forEach(([e,t])=>{e=this.options.fields[e];e&&(t.width&&(e.width=t.width),t.visibility)&&(e.visibility=t.visibility)})}catch(e){this.logger.warn("Failed to load column settings:",e)}}}loadState(){if(this.options.saveFTableUserPreferences){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.state.pageSize=t.pageSize)}catch(e){this.logger.warn("Failed to load table state:",e)}}}createTableBody(){this.elements.tableBody=FTableDOMHelper.create("tbody",{parent:this.elements.table})}addNoDataRow(){var e,t;this.elements.tableBody.querySelector(".ftable-no-data-row")||(e=FTableDOMHelper.create("tr",{className:"ftable-no-data-row",parent:this.elements.tableBody}),t=this.elements.table.querySelector("thead tr").children.length,FTableDOMHelper.create("td",{attributes:{colspan:t},text:this.options.messages.noDataAvailable,parent:e}))}removeNoDataRow(){var e=this.elements.tableBody.querySelector(".ftable-no-data-row");e&&e.remove()}createModals(){this.options.actions.createAction&&this.createAddRecordModal(),this.options.actions.updateAction&&this.createEditRecordModal(),this.options.actions.deleteAction&&this.createDeleteConfirmModal(),this.createErrorModal(),this.createInfoModal(),this.createLoadingModal(),Object.values(this.modals).forEach(e=>e.create())}createAddRecordModal(){this.modals.addRecord=new JtableModal({parent:this.elements.mainContainer,title:this.options.messages.addNewRecord,className:"ftable-add-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.modals.addRecord.close(),this.emit("formClosed",{form:this.currentForm,formType:"create",record:null})}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveNewRecord()}]})}createEditRecordModal(){this.modals.editRecord=new JtableModal({parent:this.elements.mainContainer,title:this.options.messages.editRecord,className:"ftable-edit-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>{this.emit("formClosed",{form:this.currentForm,formType:"edit",record:null}),this.modals.editRecord.close()}},{text:this.options.messages.save,className:"ftable-dialog-savebutton",onClick:()=>this.saveEditedRecord()}]})}createDeleteConfirmModal(){this.modals.deleteConfirm=new JtableModal({parent:this.elements.mainContainer,title:this.options.messages.areYouSure,className:"ftable-delete-modal",buttons:[{text:this.options.messages.cancel,className:"ftable-dialog-cancelbutton",onClick:()=>this.modals.deleteConfirm.close()},{text:this.options.messages.deleteText,className:"ftable-dialog-deletebutton",onClick:()=>this.confirmDelete()}]})}createErrorModal(){this.modals.error=new JtableModal({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-error-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.error.close()}]})}createInfoModal(){this.modals.info=new JtableModal({parent:this.elements.mainContainer,title:this.options.messages.error,className:"ftable-info-modal",buttons:[{text:this.options.messages.close,className:"ftable-dialog-closebutton",onClick:()=>this.modals.info.close()}]})}createLoadingModal(){this.modals.loading=new JtableModal({parent:this.elements.mainContainer,title:"",className:"ftable-loading-modal",content:`<div class="ftable-loading-message">${this.options.messages.loadingMessage}</div>`})}bindEvents(){this.subscribeOptionEvents(),this.createToolbarButtons(),this.createCustomToolbarItems(),this.handlePageUnload(),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=FTableDOMHelper.create("div",{className:"ftable-contextmenu-overlay",parent:this.elements.mainContainer}),this.elements.columnSelectionMenu=FTableDOMHelper.create("div",{className:"ftable-column-selection-container",parent:this.elements.columnSelectionOverlay}),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 n=FTableDOMHelper.create("ul",{className:"ftable-column-select-list",parent:this.elements.columnSelectionMenu});this.columnList.forEach(e=>{var t=this.options.fields[e],a="hidden"!==t.visibility,s="fixed"===t.visibility,i=this.isFieldSorted(e),r=FTableDOMHelper.create("li",{className:"ftable-column-select-item",parent:n}),o=FTableDOMHelper.create("label",{className:"ftable-column-select-label",parent:r});let l=FTableDOMHelper.create("input",{attributes:{type:"checkbox",id:"column-"+e},parent:o});l.checked=a,(s||i&&a)&&(l.disabled=!0,r.style.opacity="0.6");s=FTableDOMHelper.create("span",{text:t.title||e,parent:o});i&&((a=FTableDOMHelper.create("span",{className:"ftable-sort-indicator",text:" (sorted)",parent:s})).style.fontSize="0.8em",a.style.color="#666"),l.disabled||l.addEventListener("change",()=>{this.setColumnVisibility(e,l.checked)})})}positionColumnSelectionMenu(e){var t=this.elements.mainContainer.getBoundingClientRect(),a=30*this.columnList.length+20;let s=e.clientX-t.left,i=e.clientY-t.top;s+200>t.width&&(s=Math.max(0,t.width-200)),i+a>t.height&&(i=Math.max(0,t.height-a)),this.elements.columnSelectionMenu.style.left=s+"px",this.elements.columnSelectionMenu.style.top=i+"px"}hideColumnSelectionMenu(){this.elements.columnSelectionOverlay&&(this.elements.columnSelectionOverlay.remove(),this.elements.columnSelectionOverlay=null,this.elements.columnSelectionMenu=null)}isFieldSorted(t){return this.state.sorting.some(e=>e.fieldName===t)}createToolbarButtons(){this.options.csvExport&&this.addToolbarButton({text:this.options.messages.csvExport,className:"ftable-toolbar-item-csv",onClick:()=>{var e=this.options.title?this.options.title.replace(/[^a-z0-9]/gi,"-").toLowerCase()+".csv":"table-export.csv";this.exportToCSV(e)}}),this.options.printTable&&this.addToolbarButton({text:this.options.messages.printTable,className:"ftable-toolbar-item-print",onClick:()=>{this.printTable()}}),this.options.actions.createAction&&this.addToolbarButton({text:this.options.messages.addNewRecord,className:"ftable-toolbar-item-add-record",addIconSpan:!0,onClick:()=>this.showAddRecordForm()})}addToolbarButton(e){var t=FTableDOMHelper.create("span",{className:"ftable-toolbar-item "+(e.className||""),parent:this.elements.toolbarDiv});if(e.addIconSpan)FTableDOMHelper.create("span",{className:"ftable-toolbar-item-icon "+(e.className||""),parent:t});let a=FTableDOMHelper.create("span",{className:"ftable-toolbar-item-text "+(e.className||""),text:e.text,parent:t});return e.onClick&&t.addEventListener("click",e.onClick),t}createCustomToolbarItems(){this.options.toolbar&&this.options.toolbar.items&&this.options.toolbar.items.forEach(t=>{var e=FTableDOMHelper.create("button",{className:"ftable-toolbar-item ftable-toolbar-item-custom "+(t.buttonClass||""),parent:this.elements.toolbarDiv});t.icon&&FTableDOMHelper.create("img",{attributes:{src:t.icon,alt:"",width:16,height:16,style:"margin-right: 6px; vertical-align: middle;"},parent:e}),t.text&&FTableDOMHelper.create("span",{text:t.text,parent:e}),"function"==typeof t.click&&e.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),t.click()})})}handlePageUnload(){let e=!1;window.addEventListener("beforeunload",()=>{e=!0}),window.addEventListener("unload",()=>{e=!1}),this.unloadingPage=()=>e}bindKeyboardEvents(){this.options.selecting&&(this.shiftKeyDown=!1,document.addEventListener("keydown",e=>{"Shift"===e.key&&(this.shiftKeyDown=!0)}),document.addEventListener("keyup",e=>{"Shift"===e.key&&(this.shiftKeyDown=!1)}))}setupFTableUserPreferences(){var e;this.options.saveFTableUserPreferences&&(e=this.userPrefs.generatePrefix(this.options.tableId||"",this.fieldList),this.userPrefs=new FTableUserPreferences(e,this.options.saveFTableUserPreferencesMethod),this.loadState(),this.loadColumnSettings())}async load(e={}){if(!this.state.isLoading){this.state.isLoading=!0,this.showLoadingIndicator();try{var t={...e,...this.buildLoadParams()},a=await this.performLoad(t);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()}}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(([e,t])=>{""!==t&&(a.push(t),s.push(e))}),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=await FTableHttpClient.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.renderTableData(),this.updatePagingInfo())}renderTableData(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach(e=>e.remove()),0===this.state.records.length?this.addNoDataRow():(this.removeNoDataRow(),this.state.records.forEach(e=>{e=this.createTableRow(e);this.elements.tableBody.appendChild(e)}),this.refreshRowStyles(),this.refreshDisplayValues())}createTableRow(t){let a=FTableDOMHelper.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":this.getKeyValue(t)}}),e=(a.recordData=t,this.options.selecting&&this.addSelectingCell(a),this.columnList.forEach(e=>{this.addDataCell(a,t,e)}),0);return this.options.actions.updateAction&&(this.addEditCell(a),e++),this.options.actions.cloneAction&&(this.addCloneCell(a),e++),this.options.actions.deleteAction&&(this.addDeleteCell(a),e++),this.options.selecting&&this.makeRowSelectable(a),a}addSelectingCell(e){var t=FTableDOMHelper.create("td",{className:"ftable-command-column ftable-selecting-column",parent:e});FTableDOMHelper.create("input",{attributes:{type:"checkbox"},parent:t}).addEventListener("change",()=>{this.toggleRowSelection(e)})}addDataCell(e,t,a){var s=this.options.fields[a],t=this.getDisplayText(t,a),t=FTableDOMHelper.create("td",{className:`${s.listClass||""} `+(s.listClassEntry||""),html:s.listEscapeHTML?FTableDOMHelper.escapeHtml(t):t,attributes:{"data-field-name":a},parent:e});"fixed"!==s.visibility&&"hidden"===s.visibility&&FTableDOMHelper.hide(t)}addEditCell(t){var e=FTableDOMHelper.create("td",{className:"ftable-command-column",parent:t});FTableDOMHelper.create("button",{className:"ftable-command-button ftable-edit-command-button",attributes:{title:this.options.messages.editRecord},html:`<span>${this.options.messages.editRecord}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.editRecord(t)})}addCloneCell(t){var e=FTableDOMHelper.create("td",{className:"ftable-command-column",parent:t});FTableDOMHelper.create("button",{className:"ftable-command-button ftable-clone-command-button",attributes:{title:this.options.messages.cloneRecord||"Clone"},html:`<span>${this.options.messages.cloneRecord||"Clone"}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.cloneRecord(t)})}addDeleteCell(t){var e=FTableDOMHelper.create("td",{className:"ftable-command-column",parent:t});FTableDOMHelper.create("button",{className:"ftable-command-button ftable-delete-command-button",attributes:{title:this.options.messages.deleteText},html:`<span>${this.options.messages.deleteText}</span>`,parent:e}).addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),this.deleteRecord(t)})}getDisplayText(e,t){var a=this.options.fields[t],s=e[t];return a.display&&"function"==typeof a.display?a.display({record:e}):"date"===a.type&&s?this.formatDate(s,a.dateFormat):"checkbox"===a.type?this.getCheckboxText(t,s):a.options?(e=this.findOptionByValue(a.options,s))?e.DisplayText||e.text||e:s:s||""}formatDate(e,t){var a;return e?(a=new Date(e),isNaN(a.getTime())?e:a.getFullYear()+`-${String(a.getMonth()+1).padStart(2,"0")}-`+String(a.getDate()).padStart(2,"0")):""}getCheckboxText(e,t){e=this.options.fields[e];return e.values&&e.values[t]?e.values[t]:t?"Yes":"No"}findOptionByValue(e,t){return Array.isArray(e)?e.find(e=>(e.Value||e.value)===t||e===t):null}refreshRowStyles(){this.elements.tableBody.querySelectorAll(".ftable-data-row").forEach((e,t)=>{t%2==0?FTableDOMHelper.addClass(e,"ftable-row-even"):FTableDOMHelper.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.options.formClosed&&this.options.formClosed(this.currentForm,"create",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.options.formClosed&&this.options.formClosed(this.currentForm,"edit",this.currentEditingRow.recordData),this.updateRowData(this.currentEditingRow,t.Record||e),t.Message&&this.showInfo(t.Message),this.emit("recordUpdated",{record:t.Record||e})):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 FTableHttpClient.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 FTableHttpClient.post(t,e);throw new Error("No valid updateAction provided")}async performDelete(e){var t=this.options.actions.deleteAction,e={[this.keyField]:e};if("function"==typeof t)return t(e);if("string"==typeof t)return FTableHttpClient.post(t,e);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(s,e){s.recordData={...s.recordData,...e},Object.keys(e).forEach(e=>{var t,a=this.options.fields[e];a&&(t=s.querySelector(`td[data-field-name="${e}"]`))&&(e=this.getDisplayText(s.recordData,e),t.innerHTML=a.listEscapeHTML?FTableDOMHelper.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=>{e.target.classList.contains("norowselectonclick")||this.toggleRowSelection(t)})}toggleRowSelection(e){var t=e.classList.contains("ftable-row-selected");this.options.multiselect||this.clearAllSelections(),t?this.deselectRow(e):this.selectRow(e),this.emit("selectionChanged",{selectedRows:this.getSelectedRows()})}selectRow(e){FTableDOMHelper.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){FTableDOMHelper.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(t){var e,a=this.state.sorting.findIndex(e=>e.fieldName===t);this.options.multiSorting||(this.state.sorting=[]),0<=a?"ASC"===(e=this.state.sorting[a]).direction?e.direction="DESC":this.state.sorting.splice(a,1):this.state.sorting.push({fieldName:t,direction:"ASC"}),this.updateSortingHeaders(),this.load(),this.saveState()}updateSortingHeaders(){this.elements.table.querySelectorAll(".ftable-column-header-sortable").forEach(e=>{FTableDOMHelper.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&&FTableDOMHelper.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)){this.createPageButton("«",1,1===this.state.currentPage,"ftable-page-number-first"),this.createPageButton("‹",this.state.currentPage-1,1===this.state.currentPage,"ftable-page-number-previous");var a=this.calculatePageNumbers(e);let t=0;a.forEach(e=>{1<e-t&&FTableDOMHelper.create("span",{className:"ftable-page-number-space",text:"...",parent:this.elements.pagingListArea}),this.createPageButton(e.toString(),e,!1,e===this.state.currentPage?"ftable-page-number ftable-page-number-active":"ftable-page-number"),t=e}),this.createPageButton("›",this.state.currentPage+1,this.state.currentPage>=e,"ftable-page-number-next"),this.createPageButton("»",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="";FTableDOMHelper.create("span",{text:this.options.messages.gotoPageLabel+": ",parent:this.elements.pagingGotoArea});var e="ftable-goto-page-"+(this.options.tableId||"default");if("combobox"===this.options.gotoPageArea){this.elements.gotoPageSelect=FTableDOMHelper.create("select",{id:e,className:"ftable-page-goto-select",parent:this.elements.pagingGotoArea});for(let e=1;e<=a;e++)FTableDOMHelper.create("option",{attributes:{value:e},text:e,parent:this.elements.gotoPageSelect});this.elements.gotoPageSelect.value=this.state.currentPage,this.elements.gotoPageSelect.addEventListener("change",e=>{e=parseInt(e.target.value);1<=e&&e<=a&&this.changePage(e)})}else"textbox"===this.options.gotoPageArea&&(this.elements.gotoPageInput=FTableDOMHelper.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=FTableDOMHelper.create("span",{className:s+(a?" ftable-page-number-disabled":""),html: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(`<p>${e}</p>`),this.modals.error.show()):alert(e)}showInfo(e){this.modals.info?(this.modals.info.setContent(`<p>${e}</p>`),this.modals.info.show()):alert(e)}reload(e=!1){return e&&this.clearListCache(),this.load()}clearListCache(){this.options.actions.listAction&&"string"==typeof this.options.actions.listAction&&this.formBuilder.optionsCache.clear(this.options.actions.listAction)}getRowByKey(e){return this.elements.tableBody.querySelector(`[data-record-key="${e}"]`)}destroy(){this.element&&this.element.ftableInstance&&(this.element.ftableInstance=null),Object.values(this.modals).forEach(e=>e.destroy()),this.elements.mainContainer&&this.elements.mainContainer.remove(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.loadingTimeout&&clearTimeout(this.loadingTimeout),window.removeEventListener("resize",this.handleResize),this.options=null,this.state=null,this.elements=null,this.formBuilder=null,this.modals=null}setOption(e,t){return this.options[e]=t,this}getState(){return{...this.state}}addFilter(t,e,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=this.columnList.map(e=>this.options.fields[e].title||e),a=this.state.records.map(t=>this.columnList.map(e=>{e=this.getDisplayText(t,e);return`"${String(e).replace(/"/g,'""')}"`})),t=[t.map(e=>`"${e}"`).join(","),...a.map(e=>e.join(","))].join("\n"),a=new Blob(["\ufeff"+t],{type:"text/csv;charset=utf-8;"}),t=document.createElement("a");t.href=URL.createObjectURL(a),t.download=e,t.click(),t.remove()}printTable(){var e=window.open("","_blank","width=800,height=600"),t=this.elements.table.outerHTML,t=`
|
|
24
|
+
<!DOCTYPE html>
|
|
25
|
+
<html>
|
|
26
|
+
<head>
|
|
27
|
+
<title>${this.options.title||"Table Data"}</title>
|
|
28
|
+
<style>
|
|
29
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
30
|
+
table { width: 100%; border-collapse: collapse; }
|
|
31
|
+
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
32
|
+
th { background-color: #f2f2f2; font-weight: bold; }
|
|
33
|
+
.ftable-command-column { display: none !important; }
|
|
34
|
+
.ftable-command-column-header { display: none !important; }
|
|
35
|
+
.ftable-selecting-column { display: none !important; }
|
|
36
|
+
.ftable-column-header-select { display: none !important; }
|
|
37
|
+
@media print {
|
|
38
|
+
body { margin: 0; }
|
|
39
|
+
table { font-size: 12px; }
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<h1>${this.options.title||"Table Data"}</h1>
|
|
45
|
+
${t}
|
|
46
|
+
<script>
|
|
47
|
+
window.onload = function() {
|
|
48
|
+
window.print();
|
|
49
|
+
setTimeout(() => window.close(), 100);
|
|
50
|
+
};
|
|
51
|
+
</script>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
54
|
+
`;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&&(e+=1);t=`th:nth-child(${e}), td:nth-child(${e})`;this.elements.table.querySelectorAll(t).forEach(e=>{a?FTableDOMHelper.show(e):FTableDOMHelper.hide(e)})}this.options.saveFTableUserPreferences&&(this.saveColumnSettings(),this.saveState())}}makeResponsive(){FTableDOMHelper.addClass(this.elements.mainContainer,"ftable-responsive");var e=()=>{this.elements.mainContainer.offsetWidth<768?(FTableDOMHelper.addClass(this.elements.table,"ftable-mobile"),this.handleMobileView()):(FTableDOMHelper.removeClass(this.elements.table,"ftable-mobile"),this.handleDesktopView())};window.addEventListener("resize",e),e()}handleMobileView(){this.columnList.filter(e=>{e=this.options.fields[e];return"low"===e.priority||!0===e.mobileHidden}).forEach(e=>{this.setColumnVisibility(e,!1)})}handleDesktopView(){this.columnList.forEach(e=>{"hidden"!==this.options.fields[e].visibility&&this.setColumnVisibility(e,!0)})}validateRecord(i,e=0){let r=[];return Object.entries(this.options.fields).forEach(([e,t])=>{var a,s=i[e];if(!t.required||s&&""!==s.toString().trim()||r.push(`${t.title||e} is required`),s&&t.validate&&"function"==typeof t.validate&&!0!==(a=t.validate(s,i))&&r.push(a||`${t.title||e} is invalid`),s)switch(t.type){case"email":/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)||r.push(`${t.title||e} must be a valid email`);break;case"number":isNaN(s)&&r.push(`${t.title||e} must be a number`);break;case"date":isNaN(new Date(s).getTime())&&r.push(`${t.title||e} must be a valid date`)}}),{isValid:0===r.length,errors:r}}enableSearch(e={}){let t={placeholder:"Search...",debounceMs:300,searchFields:this.columnList,...e};e=FTableDOMHelper.create("div",{className:"ftable-search-container",parent:this.elements.toolbarDiv}),e=FTableDOMHelper.create("input",{attributes:{type:"text",placeholder:t.placeholder,class:"ftable-search-input"},parent:e});let a;return e.addEventListener("input",e=>{clearTimeout(a),a=setTimeout(()=>{this.performSearch(e.target.value,t.searchFields)},t.debounceMs)}),e}async performSearch(e,t){return e.trim()?(e={search:e,searchFields:t.join(",")},this.load(e)):this.load()}enableKeyboardShortcuts(){document.addEventListener("keydown",e=>{if(this.elements.mainContainer.contains(document.activeElement))switch(e.key){case"n":e.ctrlKey&&this.options.actions.createAction&&(e.preventDefault(),this.showAddRecordForm());break;case"r":e.ctrlKey&&(e.preventDefault(),this.reload());break;case"Delete":this.options.actions.deleteAction&&0<this.getSelectedRows().length&&(e.preventDefault(),this.bulkDelete());break;case"a":e.ctrlKey&&this.options.selecting&&this.options.multiselect&&(e.preventDefault(),this.toggleSelectAll(!0));break;case"Escape":Object.values(this.modals).forEach(e=>{e.isOpen&&e.close()})}})}enableVirtualScrolling(e={}){e={rowHeight:40,overscan:5,...e};this.virtualScrolling={enabled:!0,...e,visibleRange:{start:0,end:0},scrollContainer:null}}enableRealTimeUpdates(e){e&&(this.websocket=new WebSocket(e),this.websocket.onmessage=e=>{try{var t=JSON.parse(e.data);this.handleRealTimeUpdate(t)}catch(e){this.logger.error("Failed to parse WebSocket message",e)}},this.websocket.onerror=e=>{this.logger.error("WebSocket error",e)},this.websocket.onclose=()=>{this.logger.info("WebSocket connection closed"),setTimeout(()=>{this.websocket.readyState===WebSocket.CLOSED&&this.enableRealTimeUpdates(e)},5e3)})}handleRealTimeUpdate(e){switch(e.type){case"record_added":this.addRecordToTable(e.record);break;case"record_updated":this.updateRecordInTable(e.record);break;case"record_deleted":this.removeRecordFromTable(e.recordKey);break;case"refresh":this.reload()}}addRecordToTable(e){var t=this.createTableRow(e);this.state.sorting.length,this.elements.tableBody.appendChild(t),this.state.records.push(e),this.removeNoDataRow(),this.refreshRowStyles(),this.options.animationsEnabled&&this.showRowAnimation(t,"added")}updateRecordInTable(e){var t=this.getKeyValue(e),t=this.getRowByKey(t);t&&(this.updateRowData(t,e),this.options.animationsEnabled)&&this.showRowAnimation(t,"updated")}removeRecordFromTable(t){var e=this.getRowByKey(t);e&&(this.removeRowFromTable(e),this.state.records=this.state.records.filter(e=>this.getKeyValue(e)!==t))}showRowAnimation(e,t){let a="ftable-row-"+t;FTableDOMHelper.addClass(e,a),setTimeout(()=>{FTableDOMHelper.removeClass(e,a)},2e3)}use(e,t={}){return"function"==typeof e?e(this,t):e&&"function"==typeof e.install&&e.install(this,t),this}delegate(a,e,s){return this.elements.mainContainer.addEventListener(e,e=>{var t=e.target.closest(a);t&&s.call(t,e)}),this}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},r=await FTableHttpClient.get(t,i);if(!r||!r.Record)throw new Error("Invalid response or missing Record");var o=r.Record,l=this.getRowByKey(e)||FTableDOMHelper.create("tr",{className:"ftable-data-row",attributes:{"data-record-key":e}});l.recordData={...o},await this.editRecord(l)}catch(e){this.showError("Failed to load record for editing."),this.logger.error("editRecordViaAjax failed: "+e.message)}}openChildTable(e,t,a){this.closeChildTable(e);var s=FTableDOMHelper.create("tr",{className:"ftable-child-row"}),i=FTableDOMHelper.create("td",{attributes:{colspan:this.getVisibleColumnCount()},parent:s}),i=FTableDOMHelper.create("div",{className:"ftable-child-table-container",parent:i}),s=(e.parentNode.insertBefore(s,e.nextSibling),(e.childRow=s).parentRow=e,new FTable(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)}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.state.sorting.map(e=>(this.options.fields[e.fieldName]?.title||e.fieldName)+` (${"ASC"===e.direction?t.ascending||"ascending":t.descending||"descending"})`).join(", "),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=>{FTable._waitForFieldReady(t,a,e,s)})}}window.FTable=FTable;
|