tablein
Version:
Table generator library
1 lines • 72.8 kB
JavaScript
class Tablein{constructor(t={}){this.options={container:null,data:[],columns:[],freezeHeader:!0,freezeColumns:0,pageSize:10,serverSide:!1,serverUrl:"",serverParams:null,lazyLoad:!1,infiniteScroll:!1,loadThreshold:100,exportOptions:{excel:!0,pdf:!0,print:!0},searchable:!1,sortable:!0,resizableColumns:!1,theme:"default",useHTML:!1,contextMenu:null,cssClass:"",rowClassName:null,cellClassName:null,aiInsights:!1,insightsPosition:"top",insightsThreshold:.7,collaboration:!1,collaborationMode:"websocket",collaborationUrl:"",collaborationInterval:2e3,collaborationUser:null,versionHistory:!1,maxVersions:10,visualizations:!1,visualizationTypes:["sparkline","bar","pie","progress"],visualizationColors:["#4CAF50","#2196F3","#FFC107","#F44336","#9C27B0"],visualizationSize:"medium",visualizationPosition:"cell",visualizationThreshold:5,conditionalFormatting:!1,rules:[],smartFormatting:!1,formatDetection:{numbers:!0,dates:!0,urls:!0,emails:!0},businessRules:[],validateOnEdit:!0,showValidationMessages:!0,keyboardNavigation:!0,keyboardShortcuts:!0,accessibleHeaders:!0,focusableRows:!0,ariaLabels:{table:"Data Table",search:"Search table",pagination:"Table pagination",sortAsc:"Sort column ascending",sortDesc:"Sort column descending",row:t=>`Row ${t+1}`},...t},this.currentPage=1,this.totalPages=1,this.isBusy=!1,this.loadedRows=0,this.tableElement=null,this.tableContainer=null,this.paginationElement=null,this.toolbarElement=null,this.searchElement=null,this.contextMenuElement=null,this.originalData=[],this.totalRecords=0,this.searchTerm="",this.sortField="",this.sortDirection="asc",this.insights=[],this.cellVersions=new Map,this.collaborationSocket=null,this.collaborationTimer=null,this.pendingChanges=[],this.visualizationsCache=new Map,this.rulesEngine=null,this.validationErrors=new Map,this.formattingCache=new Map,this.ruleEvaluations=new Map,this.activeCell={rowIndex:-1,columnIndex:-1},this.keyboardNavigationEnabled=!1,this.shortcuts={},this.options.data&&Array.isArray(this.options.data)&&(this.originalData=[...this.options.data]),this.init()}init(){if(!this.options.container)throw new Error("Container element is required");const t="string"==typeof this.options.container?document.querySelector(this.options.container):this.options.container;if(!t)throw new Error("Container element not found");this.tableContainer=document.createElement("div"),this.tableContainer.className="advanced-table-container",this.options.theme&&this.tableContainer.classList.add(`advanced-table-theme-${this.options.theme}`),this.options.cssClass&&this.tableContainer.classList.add(this.options.cssClass),t.appendChild(this.tableContainer),this.createToolbar(),this.options.useHTML?this.initFromHTML(t):this.createTable(),this.options.infiniteScroll||this.options.lazyLoad||this.createPagination(),this.options.contextMenu&&this.createContextMenu(),this.options.aiInsights&&this.createInsightsPanel(),this.options.visualizations&&this.initVisualizations(),(this.options.conditionalFormatting||this.options.businessRules.length>0)&&this.initRulesEngine(),this.loadData(),this.attachEventListeners(),this.initCollaboration()}initFromHTML(t){let e=null;if(e="string"==typeof this.options.useHTML?document.querySelector(this.options.useHTML):this.options.useHTML instanceof HTMLTableElement?this.options.useHTML:t.querySelector("table"),!e)throw new Error("Existing HTML table not found");const n=document.createElement("div");n.className="advanced-table-wrapper",this.tableElement=e.cloneNode(!0),this.tableElement.className="advanced-table",e.className&&(this.tableElement.className+=" "+e.className);const o=this.tableElement.querySelectorAll("thead th");if(this.options.columns=[],o.forEach(((t,e)=>{const n=t.textContent.trim(),o=t.getAttribute("data-field")||`column${e}`,i=t.style.width||null,s="false"!==t.getAttribute("data-sortable");this.options.columns.push({field:o,title:n,width:i,sortable:s})})),0===this.originalData.length){const t=this.tableElement.querySelectorAll("tbody tr"),e=[];t.forEach((t=>{const n={};t.querySelectorAll("td").forEach(((t,e)=>{const o=this.options.columns[e]?this.options.columns[e].field:`column${e}`;n[o]=t.textContent.trim()})),e.push(n)})),this.originalData=e,this.options.data=e}const i=this.tableElement.querySelector("tbody");i&&(i.innerHTML=""),n.appendChild(this.tableElement),this.tableContainer.appendChild(n),this.options.freezeHeader&&n.classList.add("freeze-header"),this.options.freezeColumns>0&&(n.classList.add("freeze-columns"),n.style.setProperty("--freeze-columns",this.options.freezeColumns))}createToolbar(){if(this.toolbarElement=document.createElement("div"),this.toolbarElement.className="advanced-table-toolbar",this.options.searchable){this.searchElement=document.createElement("div"),this.searchElement.className="advanced-table-search";const t=document.createElement("input");if(t.type="text",t.placeholder="Search...",this.options.serverSide){let e;t.addEventListener("input",(t=>{clearTimeout(e),e=setTimeout((()=>{this.searchTerm=t.target.value,this.currentPage=1,this.loadedRows=0,this.loadData()}),300)}))}else t.addEventListener("input",(t=>this.search(t.target.value)));this.searchElement.appendChild(t),this.toolbarElement.appendChild(this.searchElement)}const t=document.createElement("div");t.className="toolbar-spacer",this.toolbarElement.appendChild(t);const e=this.options.exportOptions,n=document.createElement("div");if(n.className="export-buttons",e.excel){const t=document.createElement("button");t.textContent="Export to Excel",t.className="excel-btn",t.addEventListener("click",(()=>this.exportToExcel())),n.appendChild(t)}if(e.pdf){const t=document.createElement("button");t.textContent="Export to PDF",t.className="pdf-btn",t.addEventListener("click",(()=>this.exportToPdf())),n.appendChild(t)}if(e.print){const t=document.createElement("button");t.textContent="Print",t.className="print-btn",t.addEventListener("click",(()=>this.print())),n.appendChild(t)}this.toolbarElement.appendChild(n),this.tableContainer.appendChild(this.toolbarElement)}createTable(){const t=document.createElement("div");t.className="advanced-table-wrapper",this.tableElement=document.createElement("table"),this.tableElement.className="advanced-table",this.options.cssClass&&this.tableElement.classList.add(this.options.cssClass);const e=document.createElement("thead"),n=document.createElement("tr");this.options.columns.forEach((t=>{const e=document.createElement("th");e.textContent=t.title||t.field,!1!==t.sortable&&this.options.sortable&&(e.classList.add("sortable"),e.addEventListener("click",(()=>this.sortBy(t.field)))),t.width&&(e.style.width="number"==typeof t.width?`${t.width}px`:t.width),e.setAttribute("data-field",t.field),t.className&&(e.className=t.className),n.appendChild(e)})),e.appendChild(n),this.tableElement.appendChild(e);const o=document.createElement("tbody");this.tableElement.appendChild(o),t.appendChild(this.tableElement),this.tableContainer.appendChild(t),this.options.freezeHeader&&t.classList.add("freeze-header"),this.options.freezeColumns>0&&(t.classList.add("freeze-columns"),t.style.setProperty("--freeze-columns",this.options.freezeColumns))}createPagination(){this.paginationElement=document.createElement("div"),this.paginationElement.className="advanced-table-pagination";const t=document.createElement("select");t.className="page-size-selector",[5,10,20,50,100].forEach((e=>{const n=document.createElement("option");n.value=e,n.textContent=e,n.selected=this.options.pageSize===e,t.appendChild(n)})),t.addEventListener("change",(t=>{this.options.pageSize=parseInt(t.target.value,10),this.currentPage=1,this.loadData()}));const e=document.createElement("div");e.className="page-size-container",e.textContent="Rows per page: ",e.appendChild(t);const n=document.createElement("button");n.textContent="Previous",n.addEventListener("click",(()=>this.prevPage()));const o=document.createElement("span");o.className="page-info";const i=document.createElement("button");i.textContent="Next",i.addEventListener("click",(()=>this.nextPage()));const s=document.createElement("button");s.textContent="<<",s.className="first-page",s.addEventListener("click",(()=>this.goToPage(1)));const a=document.createElement("button");a.textContent=">>",a.className="last-page",a.addEventListener("click",(()=>this.goToPage(this.totalPages)));const r=document.createElement("div");r.className="pagination-controls",r.appendChild(s),r.appendChild(n),r.appendChild(o),r.appendChild(i),r.appendChild(a),this.paginationElement.appendChild(e),this.paginationElement.appendChild(r),this.tableContainer.appendChild(this.paginationElement),this.updatePaginationInfo()}createContextMenu(){this.contextMenuElement=document.createElement("div"),this.contextMenuElement.className="advanced-table-context-menu",this.contextMenuElement.style.display="none",document.body.appendChild(this.contextMenuElement)}createInsightsPanel(){this.insightsElement=document.createElement("div"),this.insightsElement.className="advanced-table-insights","top"===this.options.insightsPosition?this.tableContainer.insertBefore(this.insightsElement,this.tableContainer.firstChild):"bottom"===this.options.insightsPosition&&this.tableContainer.appendChild(this.insightsElement);const t=document.createElement("button");t.textContent="Show Insights",t.className="insights-btn",t.addEventListener("click",(()=>this.toggleInsights())),this.toolbarElement.querySelector(".export-buttons").appendChild(t)}toggleInsights(){this.insightsElement.classList.contains("active")?(this.insightsElement.classList.remove("active"),this.toolbarElement.querySelector(".insights-btn").textContent="Show Insights"):(this.insightsElement.classList.add("active"),this.toolbarElement.querySelector(".insights-btn").textContent="Hide Insights",this.generateInsights())}generateInsights(){this.insightsElement.innerHTML='<div class="insights-loading">Analyzing data...</div>',setTimeout((()=>{const t=[],e=this.originalData;e&&0!==e.length?(e.length<5&&t.push({type:"info",message:"Sample size is too small for meaningful analysis",confidence:1}),this.options.columns.forEach((n=>{const o=e.map((t=>t[n.field])).filter((t=>null!=t));if(o.length>0&&!isNaN(parseFloat(o[0]))){const e=o.map((t=>parseFloat(t))).filter((t=>!isNaN(t)));if(e.length>3){const o=e.reduce(((t,e)=>t+e),0)/e.length,i=Math.min(...e),s=Math.max(...e),a=e.reduce(((t,e)=>t+Math.pow(e-o,2)),0)/e.length,r=Math.sqrt(a),l=e.filter((t=>Math.abs(t-o)>2*r));l.length>0&&t.push({type:"warning",message:`Found ${l.length} outliers in column "${n.title||n.field}"`,detail:`Values that deviate significantly from the average (${o.toFixed(2)})`,confidence:.8}),t.push({type:"info",message:`Statistics for "${n.title||n.field}": Min=${i}, Max=${s}, Avg=${o.toFixed(2)}`,confidence:.9})}}const i=o.filter((t=>""===t||null==t)).length/e.length*100;if(i>10&&t.push({type:"warning",message:`${i.toFixed(1)}% of values in "${n.title||n.field}" are empty`,confidence:.85}),n.field.toLowerCase().includes("id")){new Set(o).size!==o.length&&t.push({type:"error",message:`Found duplicate values in "${n.title||n.field}" column`,confidence:.95})}})),this.insights=t.filter((t=>t.confidence>=this.options.insightsThreshold)),this.renderInsights()):this.insightsElement.innerHTML='<div class="insights-empty">No data to analyze</div>'}),100)}renderInsights(){if(!this.insightsElement)return void console.warn("Insights element not found");if(0===this.insights.length)return void(this.insightsElement.innerHTML='<div class="insights-empty">No significant patterns detected in the data</div>');this.insightsElement.innerHTML="";const t=document.createElement("ul");t.className="insights-list",this.insightsElement.appendChild(t),this.insights.forEach((e=>{const n=document.createElement("li");n.className=`insight-item insight-${e.type}`;const o=document.createElement("span");o.className="insight-icon",o.textContent="info"===e.type?"ℹ️":"warning"===e.type?"⚠️":"❗";const i=document.createElement("div");i.className="insight-content";const s=document.createElement("div");if(s.className="insight-message",s.textContent=e.message,i.appendChild(s),e.detail){const t=document.createElement("div");t.className="insight-detail",t.textContent=e.detail,i.appendChild(t)}n.appendChild(o),n.appendChild(i),t.appendChild(n)}))}updatePaginationInfo(){const t=this.paginationElement.querySelector(".page-info"),e=(this.currentPage-1)*this.options.pageSize+1,n=Math.min(this.currentPage*this.options.pageSize,this.totalRecords);this.options.serverSide?t.textContent=`Page ${this.currentPage} of ${this.totalPages} (${e}-${n} of ${this.totalRecords})`:t.textContent=`Page ${this.currentPage} of ${this.totalPages}`;const o=this.paginationElement.querySelector(".first-page"),i=this.paginationElement.querySelector("button:nth-child(2)"),s=this.paginationElement.querySelector("button:nth-child(4)"),a=this.paginationElement.querySelector(".last-page");o.disabled=1===this.currentPage,i.disabled=1===this.currentPage,s.disabled=this.currentPage===this.totalPages,a.disabled=this.currentPage===this.totalPages}loadData(){this.isBusy||(this.isBusy=!0,this.tableElement.classList.add("loading"),this.options.serverSide?this.loadServerData():this.loadClientData())}loadServerData(){const t=this.buildServerParams(),e=new URLSearchParams(t).toString(),n=`${this.options.serverUrl}?${e}`;fetch(n,{method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json"}}).then((t=>{if(!t.ok)throw new Error(`HTTP Error: ${t.status}`);return t.json()})).then((t=>{this.options.infiniteScroll||this.options.lazyLoad?(this.appendData(t.items||t.data||[]),this.loadedRows+=(t.items||t.data||[]).length,this.hasMoreData=(t.items||t.data||[]).length>=this.options.pageSize):(this.renderData(t.items||t.data||[]),this.totalPages=t.totalPages||Math.ceil(t.totalRecords/this.options.pageSize)||1,this.totalRecords=t.totalRecords||t.recordsTotal||t.recordsFiltered||0,this.updatePaginationInfo()),this.isBusy=!1,this.tableElement.classList.remove("loading")})).catch((t=>{console.error("Error loading data:",t),this.isBusy=!1,this.tableElement.classList.remove("loading");const e=this.tableElement.querySelector("tbody");e.innerHTML="";const n=document.createElement("tr"),o=document.createElement("td");o.colSpan=this.options.columns.length,o.className="error-message",o.textContent=`Error loading data: ${t.message}`,n.appendChild(o),e.appendChild(n)}))}buildServerParams(){let t={};if(this.options.infiniteScroll||this.options.lazyLoad?(t.start=this.loadedRows,t.length=this.options.pageSize):(t.page=this.currentPage,t.pageSize=this.options.pageSize),this.searchTerm&&(t.search=this.searchTerm),this.sortField&&(t.sortField=this.sortField,t.sortOrder=this.sortDirection),"function"==typeof this.options.serverParams){const e=this.options.serverParams(t);t={...t,...e}}return t}loadClientData(){const t=this.options.data||[];if(this.options.infiniteScroll||this.options.lazyLoad){const e=Math.min(this.options.pageSize,t.length),n=t.slice(0,e);0===this.loadedRows?this.renderData(n):this.appendData(n),this.loadedRows=e,this.hasMoreData=this.loadedRows<t.length}else{const e=(this.currentPage-1)*this.options.pageSize,n=e+this.options.pageSize,o=t.slice(e,n);this.renderData(o),this.totalRecords=t.length,this.totalPages=Math.ceil(t.length/this.options.pageSize),this.updatePaginationInfo()}this.isBusy=!1,this.tableElement.classList.remove("loading")}renderData(t){const e=this.tableElement.querySelector("tbody");if(e.innerHTML="",0===t.length){const t=document.createElement("tr"),n=document.createElement("td");return n.colSpan=this.options.columns.length,n.className="no-data-message",n.textContent="No data available",t.appendChild(n),void e.appendChild(t)}t.forEach(((t,n)=>{const o=document.createElement("tr");if(o.setAttribute("data-row-index",n),"function"==typeof this.options.rowClassName){const e=this.options.rowClassName(t,n);e&&o.classList.add(e)}this.options.accessibleHeaders&&this.options.ariaLabels?.row&&o.setAttribute("aria-label","function"==typeof this.options.ariaLabels.row?this.options.ariaLabels.row(n):this.options.ariaLabels.row),this.options.focusableRows&&o.setAttribute("tabindex","0"),this.options.columns.forEach(((e,n)=>{const i=document.createElement("td"),s=t[e.field];if("function"==typeof e.render?i.innerHTML=e.render(s,t,e):this.options.smartFormatting?i.innerHTML=this.applySmartFormatting(s,e):i.textContent=null!=s?s:"",this.options.conditionalFormatting&&this.applyConditionalFormatting(i,s,t,e),"function"==typeof this.options.cellClassName){const o=this.options.cellClassName(s,t,e,n);o&&i.classList.add(o)}o.appendChild(i)})),e.appendChild(o)}))}applyConditionalFormatting(t,e,n,o){if(this.options.rules&&this.options.rules.length)for(const i of this.options.rules)if(i.field===o.field){let o=!1;"function"==typeof i.condition?o=i.condition(e,n):i.condition instanceof RegExp&&(o=i.condition.test(String(e))),o&&i.style&&(Object.keys(i.style).forEach((e=>{t.style[e]=i.style[e]})),i.className&&t.classList.add(i.className))}}appendData(t){const e=this.tableElement.querySelector("tbody"),n=this.loadedRows;t.forEach(((t,o)=>{const i=document.createElement("tr"),s=n+o;if("function"==typeof this.options.rowClassName){const e=this.options.rowClassName(t,s);e&&(i.className=e)}i.dataset.rowIndex=s,i._data=t,this.options.columns.forEach(((e,n)=>{const o=document.createElement("td");if("function"==typeof this.options.cellClassName){const i=this.options.cellClassName(t[e.field],t,e,n);i&&(o.className=i)}e.className&&o.classList.add(e.className),"function"==typeof e.render?o.innerHTML=e.render(t[e.field],t):o.textContent=t[e.field]||"",i.appendChild(o)})),e.appendChild(i)}))}loadMore(){if(!this.isBusy&&this.hasMoreData)if(this.isBusy=!0,this.options.serverSide)this.loadServerData();else{const t=this.options.data||[],e=t.slice(this.loadedRows,this.loadedRows+this.options.pageSize);this.appendData(e),this.loadedRows+=e.length,this.hasMoreData=this.loadedRows<t.length,this.isBusy=!1}}attachEventListeners(){if(this.options.infiniteScroll||this.options.lazyLoad){const t=this.tableElement.closest(".advanced-table-wrapper"),e=()=>{t.scrollTop+t.clientHeight>t.scrollHeight-this.options.loadThreshold&&this.hasMoreData&&!this.isBusy&&this.loadMore()};t.addEventListener("scroll",e)}if(this.options.resizableColumns){this.tableElement.querySelectorAll("th").forEach((t=>{const e=document.createElement("div");let n,o;e.className="column-resizer",t.appendChild(e);const i=e=>{const i=o+(e.pageX-n);t.style.width=`${i}px`},s=()=>{t.classList.remove("resizing"),document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",s)};e.addEventListener("mousedown",(e=>{n=e.pageX,o=t.offsetWidth,t.classList.add("resizing"),document.addEventListener("mousemove",i),document.addEventListener("mouseup",s),e.preventDefault()}))}))}if(this.options.contextMenu){const t=t=>{const e=t.target.closest("tr");if(!e)return;const n=parseInt(e.getAttribute("data-row-index"),10);if(isNaN(n))return;const o=this.options.data[n];o&&(t.preventDefault(),this.showContextMenu(t.clientX,t.clientY,o,n))};this.tableElement.closest(".advanced-table-wrapper").addEventListener("contextmenu",t),document.addEventListener("click",(()=>{this.contextMenuElement.style.display="none"}))}}showContextMenu(t,e,n,o){this.contextMenuElement||(this.contextMenuElement=document.createElement("div"),this.contextMenuElement.className="advanced-table-context-menu",this.contextMenuElement.style.display="none",document.body.appendChild(this.contextMenuElement)),this.contextMenuElement.innerHTML="";const i="function"==typeof this.options.contextMenu?this.options.contextMenu(n,o):this.options.contextMenu;i.forEach((t=>{const e=document.createElement("div");if(e.className="context-menu-item",t.divider)e.className+=" divider";else{if(t.icon){const n=document.createElement("span");n.textContent=t.icon+" ",e.appendChild(n)}const i=document.createElement("span");i.textContent=t.text,e.appendChild(i),t.className&&e.classList.add(t.className),e.addEventListener("click",(e=>{"function"==typeof t.action&&(this.contextMenuElement.style.display="none",t.action(n,o,e))}))}this.contextMenuElement.appendChild(e)}));const s=35*i.length,a=window.innerWidth,r=window.innerHeight;let l=t,d=e;t+200>a&&(l=a-200-10),e+s>r&&(d=r-s-10),this.contextMenuElement.style.left=`${l}px`,this.contextMenuElement.style.top=`${d}px`,this.contextMenuElement.style.display="block"}sortBy(t){const e=this.tableElement.querySelector(`th[data-field="${t}"]`);if(!e)return;if(this.sortField===t?this.sortDirection="asc"===this.sortDirection?"desc":"asc":(this.sortField=t,this.sortDirection="asc"),this.tableElement.querySelectorAll("th").forEach((t=>{t.removeAttribute("data-sort-dir"),t.classList.remove("sorted-asc","sorted-desc")})),e.setAttribute("data-sort-dir",this.sortDirection),e.classList.add(`sorted-${this.sortDirection}`),this.options.serverSide)return this.currentPage=1,this.loadedRows=0,void this.loadData();const n=[...this.options.data];n.sort(((e,n)=>{const o=e[t],i=n[t];if(o===i)return 0;const s=!isNaN(parseFloat(o)),a=!isNaN(parseFloat(i));if(s&&a)return"asc"===this.sortDirection?parseFloat(o)-parseFloat(i):parseFloat(i)-parseFloat(o);const r=new Date(o),l=new Date(i);if(!isNaN(r)&&!isNaN(l))return"asc"===this.sortDirection?r-l:l-r;const d=String(o||""),c=String(i||"");return"asc"===this.sortDirection?d.localeCompare(c):c.localeCompare(d)})),this.options.data=n,this.options.infiniteScroll||this.options.lazyLoad?(this.loadedRows=0,this.hasMoreData=!0,this.loadData()):(this.currentPage=1,this.loadData())}search(t){if(t&&""!==t.trim()){const e=t.toLowerCase();this.options.data=this.originalData.filter((t=>this.options.columns.some((n=>{const o=t[n.field];return null!=o&&String(o).toLowerCase().includes(e)}))))}else this.options.data=[...this.originalData];this.options.infiniteScroll||this.options.lazyLoad?(this.loadedRows=0,this.hasMoreData=!0,this.loadData()):(this.currentPage=1,this.totalPages=Math.ceil(this.options.data.length/this.options.pageSize),this.loadData())}nextPage(){this.currentPage<this.totalPages&&!this.isBusy&&(this.currentPage++,this.loadData())}prevPage(){this.currentPage>1&&!this.isBusy&&(this.currentPage--,this.loadData())}goToPage(t){t>=1&&t<=this.totalPages&&!this.isBusy&&(this.currentPage=t,this.loadData())}exportToExcel(){if(this.options.serverSide&&this.totalRecords>this.options.data.length&&!confirm(`You are about to export only the current page (${this.options.data.length} rows). Do you want to continue?`))return;const t=this.getExportData(),e=XLSX.utils.json_to_sheet(t),n=XLSX.utils.book_new();XLSX.utils.book_append_sheet(n,e,"Table"),XLSX.writeFile(n,"table-export.xlsx")}exportToPdf(){if(this.options.serverSide&&this.totalRecords>this.options.data.length&&!confirm(`You are about to export only the current page (${this.options.data.length} rows). Do you want to continue?`))return;const t=this.tableElement.cloneNode(!0);html2pdf().from(t).save("table-export.pdf")}print(){const t=window.open("","_blank");t.document.write(`\n <html>\n <head>\n <title>Print Table</title>\n <style>\n table { border-collapse: collapse; width: 100%; }\n th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n th { background-color: #f2f2f2; }\n </style>\n </head>\n <body>\n ${this.tableElement.outerHTML}\n </body>\n </html>\n `),t.document.close(),t.focus(),t.print(),t.close()}getExportData(){const t=[];if(this.options.serverSide)return this.options.data.map((t=>{const e={};return this.options.columns.forEach((n=>{e[n.title||n.field]=t[n.field]})),e}));return(this.options.infiniteScroll||this.options.lazyLoad?this.originalData:this.options.data).forEach((e=>{const n={};this.options.columns.forEach((t=>{n[t.title||t.field]=e[t.field]})),t.push(n)})),t}refresh(){this.options.infiniteScroll||this.options.lazyLoad?(this.loadedRows=0,this.hasMoreData=!0):this.currentPage=1,this.loadData()}destroy(){this.tableContainer&&this.tableContainer.parentNode&&this.tableContainer.parentNode.removeChild(this.tableContainer),this.contextMenuElement&&this.contextMenuElement.parentNode&&this.contextMenuElement.parentNode.removeChild(this.contextMenuElement),this.tableElement=null,this.tableContainer=null,this.paginationElement=null,this.toolbarElement=null,this.searchElement=null,this.contextMenuElement=null,this.cleanupCollaboration()}static fromHTML(t,e={}){return new Tablein({...e,container:t,useHTML:t})}static createInfiniteTable(t,e,n,o={}){return new Tablein({container:t,columns:e,data:n,infiniteScroll:!0,pageSize:o.batchSize||20,...o})}static createServerTable(t,e,n,o={}){return new Tablein({container:t,columns:e,serverSide:!0,serverUrl:n,pageSize:o.pageSize||20,...o})}initCollaboration(){this.options.collaboration&&("websocket"===this.options.collaborationMode&&this.options.collaborationUrl?this.initWebSocketConnection():"polling"===this.options.collaborationMode&&this.options.collaborationUrl&&this.startPollingForChanges(),this.makeTableEditable())}initWebSocketConnection(){try{this.collaborationSocket=new WebSocket(this.options.collaborationUrl),this.collaborationSocket.onopen=()=>{console.log("Collaboration WebSocket connected"),this.collaborationSocket.send(JSON.stringify({type:"connect",user:this.options.collaborationUser||{id:"anonymous-"+Math.random().toString(36).substring(2,9),name:"Anonymous User"},tableId:this.options.id||"table-"+Math.random().toString(36).substring(2,9)}))},this.collaborationSocket.onmessage=t=>{try{const e=JSON.parse(t.data);this.handleCollaborationMessage(e)}catch(t){console.error("Error processing message:",t)}},this.collaborationSocket.onerror=t=>{console.error("Collaboration WebSocket error:",t)},this.collaborationSocket.onclose=()=>{console.log("Collaboration WebSocket closed"),setTimeout((()=>this.initWebSocketConnection()),5e3)}}catch(t){console.error("Failed to connect to collaboration server:",t)}}startPollingForChanges(){this.collaborationTimer&&clearInterval(this.collaborationTimer),this.collaborationTimer=setInterval((()=>{this.fetchCollaborationChanges(),this.sendPendingChanges()}),this.options.collaborationInterval||2e3)}fetchCollaborationChanges(){this.options.collaborationUrl&&fetch(this.options.collaborationUrl+"/changes?since="+(this.lastChangeTimestamp||0),{method:"GET",headers:{"Content-Type":"application/json"}}).then((t=>t.json())).then((t=>{t.changes&&Array.isArray(t.changes)&&(t.changes.forEach((t=>{this.handleCollaborationMessage(t)})),t.timestamp&&(this.lastChangeTimestamp=t.timestamp))})).catch((t=>{console.error("Error fetching collaboration changes:",t)}))}sendPendingChanges(){if(0===this.pendingChanges.length)return;const t=[...this.pendingChanges];this.pendingChanges=[],fetch(this.options.collaborationUrl+"/changes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({changes:t,user:this.options.collaborationUser||{id:"anonymous-"+Math.random().toString(36).substring(2,9),name:"Anonymous User"},tableId:this.options.id||"table-"+Math.random().toString(36).substring(2,9)})}).catch((e=>{console.error("Error sending changes:",e),this.pendingChanges.push(...t)}))}handleCollaborationMessage(t){if(t&&t.type)switch(t.type){case"cell-change":void 0!==t.rowIndex&&void 0!==t.columnField&&void 0!==t.value&&this.updateCellFromCollaboration(t.rowIndex,t.columnField,t.value,t.user);break;case"user-connected":case"user-disconnected":this.updateCollaboratorPresence(t);break;case"cursor-position":this.updateUserCursor(t);break;default:console.log("Unknown message type:",t.type)}}updateCellFromCollaboration(t,e,n,o){if(o&&this.options.collaborationUser&&o.id===this.options.collaborationUser.id)return;const i=this.options.columns.findIndex((t=>t.field===e));if(-1!==i&&this.options.data[t]){this.options.data[t][e]=n;const s=this.tableElement.querySelector("tbody").querySelector(`tr[data-row-index="${t}"]`);if(s){const e=s.querySelectorAll("td")[i];if(e){const s=this.options.columns[i];if(s&&"function"==typeof s.render?e.innerHTML=s.render(n,this.options.data[t]):e.textContent=n,e.classList.add("cell-changed"),setTimeout((()=>{e.classList.remove("cell-changed")}),2e3),o&&o.name){const t=document.createElement("div");t.className="collaboration-tooltip",t.textContent=`Changed by ${o.name}`,o.color&&(t.style.backgroundColor=o.color),e.appendChild(t),setTimeout((()=>{t.remove()}),3e3)}}}this.options.versionHistory&&this.addToVersionHistory(t,e,n,o)}}makeTableEditable(){this.tableElement.querySelector("tbody").addEventListener("dblclick",(t=>{const e=t.target.closest("td");if(!e)return;const n=e.closest("tr"),o=parseInt(n.dataset.rowIndex,10),i=Array.from(n.cells).indexOf(e),s=this.options.columns[i];if(!s||!this.options.data[o])return;if(!(!1!==s.editable))return;const a=this.options.data[o][s.field],r=document.createElement("input");r.type="text",r.value=a||"",r.className="cell-edit-input";const l=e.innerHTML;e.innerHTML="",e.appendChild(r),r.focus(),r.select();const d=()=>{const t=r.value;t!==a?(this.options.data[o][s.field]=t,"function"==typeof s.render?e.innerHTML=s.render(t,this.options.data[o]):e.textContent=t,this.sendCellChange(o,s.field,t),this.options.versionHistory&&this.addToVersionHistory(o,s.field,t,this.options.collaborationUser||{name:"Local User"})):e.innerHTML=l};r.addEventListener("blur",d),r.addEventListener("keydown",(t=>{"Enter"===t.key?(d(),t.preventDefault()):"Escape"===t.key&&(e.innerHTML=l,t.preventDefault())}))}))}sendCellChange(t,e,n){const o={type:"cell-change",rowIndex:t,columnField:e,value:n,user:this.options.collaborationUser||{name:"Local User"},timestamp:Date.now()};"websocket"===this.options.collaborationMode&&this.collaborationSocket&&this.collaborationSocket.readyState===WebSocket.OPEN?this.collaborationSocket.send(JSON.stringify(o)):this.pendingChanges.push(o)}addToVersionHistory(t,e,n,o){if(!this.options.versionHistory)return;const i=`${t}:${e}`;this.cellVersions.has(i)||this.cellVersions.set(i,[]);const s=this.cellVersions.get(i);s.push({value:n,timestamp:Date.now(),user:o||{name:"Unknown User"}}),s.length>this.options.maxVersions&&s.shift()}getCellVersionHistory(t,e){const n=`${t}:${e}`;return this.cellVersions.get(n)||[]}showVersionHistory(t,e){const n=this.getCellVersionHistory(t,e);if(!n||0===n.length)return void alert("No version history available for this cell.");const o=document.createElement("div");o.className="version-history-dialog";const i=document.createElement("div");i.className="version-history-header";const s=document.createElement("h3");s.textContent="Version History";const a=document.createElement("button");a.textContent="×",a.className="version-history-close",a.addEventListener("click",(()=>{document.body.removeChild(o)})),i.appendChild(s),i.appendChild(a);const r=document.createElement("div");r.className="version-history-content";const l=document.createElement("ul");l.className="version-history-list",n.sort(((t,e)=>e.timestamp-t.timestamp)),n.forEach(((i,s)=>{const a=document.createElement("li");a.className="version-history-item";const r=new Date(i.timestamp).toLocaleString();if(a.innerHTML=`\n <div class="version-history-item-header">\n <span class="version-number">v${n.length-s}</span>\n <span class="version-user">${i.user.name||"Unknown"}</span>\n <span class="version-time">${r}</span>\n </div>\n <div class="version-content">${i.value}</div>\n `,s>0){const n=document.createElement("button");n.textContent="Restore",n.className="version-restore-btn",n.addEventListener("click",(()=>{confirm("Are you sure you want to restore this version?")&&(this.restoreVersion(t,e,i.value),document.body.removeChild(o))})),a.appendChild(n)}else a.classList.add("current-version");l.appendChild(a)})),r.appendChild(l),o.appendChild(i),o.appendChild(r),document.body.appendChild(o)}restoreVersion(t,e,n){if(this.options.data[t]){this.options.data[t][e]=n;const o=this.options.columns.findIndex((t=>t.field===e));if(-1===o)return;const i=this.tableElement.querySelector("tbody").querySelector(`tr[data-row-index="${t}"]`);if(i){const e=i.querySelectorAll("td")[o];if(e){const i=this.options.columns[o];i&&"function"==typeof i.render?e.innerHTML=i.render(n,this.options.data[t]):e.textContent=n,e.classList.add("cell-restored"),setTimeout((()=>{e.classList.remove("cell-restored")}),2e3)}}this.sendCellChange(t,e,n),this.addToVersionHistory(t,e,n,{name:this.options.collaborationUser?.name+" (restored)",id:this.options.collaborationUser?.id})}}updateUserCursor(t){if(!t.user||!t.position)return;const e=document.querySelector(`.user-cursor[data-user-id="${t.user.id}"]`);e&&e.remove();const n=document.createElement("div");n.className="user-cursor",n.dataset.userId=t.user.id,t.user.color&&(n.style.backgroundColor=t.user.color);const o=document.createElement("div");o.className="user-cursor-label",o.textContent=t.user.name||"Anonymous",t.user.color&&(o.style.backgroundColor=t.user.color),n.appendChild(o);const{rowIndex:i,columnIndex:s}=t.position,a=this.tableElement.querySelector("tbody").querySelector(`tr[data-row-index="${i}"]`);if(a){const t=a.querySelectorAll("td")[s];t&&(t.appendChild(n),setTimeout((()=>{n.parentNode&&n.remove()}),5e3))}}updateCollaboratorPresence(t){const{type:e,user:n}=t;if(this.collaboratorsContainer||(this.collaboratorsContainer=document.createElement("div"),this.collaboratorsContainer.className="collaborators-container",this.tableContainer.appendChild(this.collaboratorsContainer)),"user-connected"===e){let t=this.collaboratorsContainer.querySelector(`.collaborator[data-user-id="${n.id}"]`);if(!t){t=document.createElement("div"),t.className="collaborator",t.dataset.userId=n.id;const e=document.createElement("div");e.className="collaborator-avatar",e.textContent=n.name.substring(0,1).toUpperCase(),n.color&&(e.style.backgroundColor=n.color);const o=document.createElement("div");o.className="collaborator-name",o.textContent=n.name,t.appendChild(e),t.appendChild(o),this.collaboratorsContainer.appendChild(t)}}else if("user-disconnected"===e){const t=this.collaboratorsContainer.querySelector(`.collaborator[data-user-id="${n.id}"]`);t&&(t.classList.add("disconnected"),setTimeout((()=>{t.parentNode&&t.remove()}),5e3))}}sendCursorPosition(t,e){if(!this.options.collaboration||!this.options.collaborationUser||"websocket"===this.options.collaborationMode&&(!this.collaborationSocket||this.collaborationSocket.readyState!==WebSocket.OPEN))return;const n={type:"cursor-position",position:{rowIndex:t,columnIndex:e},user:this.options.collaborationUser,timestamp:Date.now()};"websocket"===this.options.collaborationMode?this.collaborationSocket.send(JSON.stringify(n)):this.pendingChanges.push(n)}cleanupCollaboration(){this.collaborationSocket&&(this.collaborationSocket.close(),this.collaborationSocket=null),this.collaborationTimer&&(clearInterval(this.collaborationTimer),this.collaborationTimer=null)}initVisualizations(){const t=document.createElement("button");t.textContent="Toggle Visualizations",t.className="visualizations-btn",t.addEventListener("click",(()=>this.toggleVisualizations())),this.toolbarElement.querySelector(".export-buttons").appendChild(t);const e=document.createElement("div");e.className="visualization-mode-container",e.style.display="none";const n=document.createElement("span");n.textContent="Visualization Mode: ";const o=document.createElement("select");o.className="vis-mode-selector",["cell","row","column","summary"].forEach((t=>{const e=document.createElement("option");e.value=t,e.textContent=t.charAt(0).toUpperCase()+t.slice(1),e.selected=this.options.visualizationPosition===t,o.appendChild(e)})),o.addEventListener("change",(t=>{this.options.visualizationPosition=t.target.value,this.renderVisualizations()})),e.appendChild(n),e.appendChild(o),this.toolbarElement.appendChild(e),this.visModeContainer=e}toggleVisualizations(){this.tableContainer.classList.toggle("show-visualizations")?(this.renderVisualizations(),this.visModeContainer.style.display="flex"):(this.clearVisualizations(),this.visModeContainer.style.display="none")}renderVisualizations(){switch(this.clearVisualizations(),this.options.visualizationPosition){case"cell":this.renderCellVisualizations();break;case"row":this.renderRowVisualizations();break;case"column":this.renderColumnVisualizations();break;case"summary":this.renderSummaryVisualizations()}}clearVisualizations(){this.tableContainer.querySelectorAll(".visualization").forEach((t=>t.remove())),this.tableElement.querySelectorAll("td.has-visualization").forEach((t=>{t.classList.remove("has-visualization")})),this.summaryVisualizationsElement&&(this.summaryVisualizationsElement.innerHTML="")}renderCellVisualizations(){this.tableElement.querySelectorAll("tbody tr").forEach((t=>{const e=t._data;e&&this.options.columns.forEach(((n,o)=>{const i=e[n.field];if(null!=i&&!isNaN(parseFloat(i))){const e=parseFloat(i),s=t.querySelectorAll("td")[o];if(!s)return;!1!==n.visualization&&this.addCellVisualization(s,e,n)}}))}))}addCellVisualization(t,e,n){let o=n.visualizationType||this.options.visualizationTypes[0];this.options.visualizationTypes.includes(o)||(o="bar");t.innerHTML,t.offsetWidth,t.offsetHeight;t.classList.add("has-visualization");let i=[];this.tableElement.querySelectorAll("tbody tr").forEach((t=>{const e=t._data;if(e){const t=e[n.field];null==t||isNaN(parseFloat(t))||i.push(parseFloat(t))}}));const s=Math.min(...i),a=Math.max(...i);let r;switch(o){case"bar":r=this.createBarVisualization(e,s,a);break;case"progress":r=this.createProgressVisualization(e,0,100);break;case"sparkline":r=this.createSparklineVisualization(n.field);break;case"pie":r=this.createPieVisualization(e,100)}r&&(r.style.bottom="0",r.style.left="0",r.style.right="0",r.style.pointerEvents="none",r.style.opacity="0.7",t.style.position="relative",t.appendChild(r))}createBarVisualization(t,e,n){const o=document.createElement("div");o.className="visualization bar-visualization";const i=n-e,s=0===i?50:(t-e)/i*100,a=document.createElement("div");return a.className="vis-bar",a.style.width=`${s}%`,a.style.backgroundColor=this.getColorForValue(s),a.style.height="4px",o.appendChild(a),o}createProgressVisualization(t,e,n){const o=document.createElement("div");o.className="visualization progress-visualization";const i=Math.min(100,Math.max(0,t)),s=document.createElement("div");return s.className="vis-progress",s.style.width=`${i}%`,s.style.height="4px",s.style.backgroundColor=this.getColorForValue(i),o.appendChild(s),o}createSparklineVisualization(t){const e=document.createElement("div");e.className="visualization sparkline-visualization";const n=[];if(this.tableElement.querySelectorAll("tbody tr").forEach((e=>{const o=e._data;o&&void 0!==o[t]&&!isNaN(parseFloat(o[t]))&&n.push(parseFloat(o[t]))})),n.length<2)return e;const o=Math.min(...n),i=Math.max(...n)-o,s=document.createElementNS("http://www.w3.org/2000/svg","svg");s.setAttribute("width","100%"),s.setAttribute("height","20"),s.setAttribute("viewBox",`0 0 ${n.length} 100`),s.style.display="block";let a="";n.forEach(((t,e)=>{const n=0===i?50:100-(t-o)/i*100;a+=0===e?`M ${e},${n}`:` L ${e},${n}`}));const r=document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d",a),r.setAttribute("stroke","#2196F3"),r.setAttribute("stroke-width","2"),r.setAttribute("fill","none"),s.appendChild(r),e.appendChild(s),e}createPieVisualization(t,e){const n=document.createElement("div");n.className="visualization pie-visualization";const o=t/e*100,i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","20"),i.setAttribute("height","20"),i.setAttribute("viewBox","0 0 100 100");const s=document.createElementNS("http://www.w3.org/2000/svg","circle");s.setAttribute("cx","50"),s.setAttribute("cy","50"),s.setAttribute("r","40"),s.setAttribute("fill","#e0e0e0"),i.appendChild(s);const a=2*Math.PI*(o/100),r=50+40*Math.sin(a),l=50-40*Math.cos(a),d=o>50?1:0,c=document.createElementNS("http://www.w3.org/2000/svg","path");return c.setAttribute("d",`M 50 50 L 50 10 A 40 40 0 ${d} 1 ${r} ${l} Z`),c.setAttribute("fill",this.getColorForValue(o)),i.appendChild(c),n.appendChild(i),n}renderRowVisualizations(){this.tableElement.querySelectorAll("tbody tr").forEach((t=>{const e=t._data;if(!e)return;const n=[],o=[];if(this.options.columns.forEach((t=>{const i=e[t.field];null==i||isNaN(parseFloat(i))||(n.push(t.title||t.field),o.push(parseFloat(i)))})),o.length<2)return;const i=document.createElement("div");i.className="visualization row-visualization";const s=this.createHorizontalBarChart(n,o);i.appendChild(s);const a=t.nextElementSibling;a?a.parentNode.insertBefore(i,a):t.parentNode.appendChild(i)}))}createHorizontalBarChart(t,e){const n=document.createElement("div");n.className="horizontal-bar-chart",n.style.width="100%",n.style.padding="10px",n.style.boxSizing="border-box";const o=Math.max(...e);return t.forEach(((t,i)=>{const s=document.createElement("div");s.className="bar-container",s.style.display="flex",s.style.alignItems="center",s.style.marginBottom="5px";const a=document.createElement("div");a.className="bar-label",a.textContent=t,a.style.width="100px",a.style.overflow="hidden",a.style.textOverflow="ellipsis",a.style.whiteSpace="nowrap",a.style.marginRight="10px";const r=document.createElement("div");r.className="bar-wrapper",r.style.flex="1",r.style.height="20px",r.style.backgroundColor="#f5f5f5",r.style.borderRadius="4px",r.style.overflow="hidden";const l=document.createElement("div");l.className="bar",l.style.height="100%",l.style.width=e[i]/o*100+"%",l.style.backgroundColor=this.getColorForIndex(i);const d=document.createElement("div");d.className="bar-value",d.textContent=e[i].toLocaleString(),d.style.marginLeft="5px",d.style.fontSize="12px",r.appendChild(l),s.appendChild(a),s.appendChild(r),s.appendChild(d),n.appendChild(s)})),n}renderColumnVisualizations(){const t=[];this.options.columns.forEach(((e,n)=>{let o=0;this.tableElement.querySelectorAll("tbody tr").forEach((t=>{const n=t._data;n&&void 0!==n[e.field]&&!isNaN(parseFloat(n[e.field]))&&o++})),o>=this.options.visualizationThreshold&&t.push({column:e,index:n})})),t.forEach((({column:t,index:e})=>{this.createColumnVisualization(t,e)}))}createColumnVisualization(t,e){const n=[];if(this.tableElement.querySelectorAll("tbody tr").forEach((e=>{const o=e._data;o&&void 0!==o[t.field]&&!isNaN(parseFloat(o[t.field]))&&n.push(parseFloat(o[t.field]))})),0===n.length)return;const o=Math.min(...n),i=Math.max(...n),s=n.reduce(((t,e)=>t+e),0)/n.length,a=document.createElement("div");a.className="visualization column-visualization",a.style.position="absolute",a.style.top="-40px",a.style.left="0",a.style.right="0",a.style.height="40px",a.style.backgroundColor="rgba(255, 255, 255, 0.9)",a.style.borderBottom="1px solid #ddd",a.style.display="flex",a.style.alignItems="center",a.style.justifyContent="center",a.style.fontSize="12px";const r=document.createElement("div");r.style.width="80px",r.style.height="30px",r.style.marginRight="10px";const l=document.createElementNS("http://www.w3.org/2000/svg","svg");l.setAttribute("width","80"),l.setAttribute("height","30"),l.setAttribute("viewBox",`0 0 ${n.length} 100`);let d="";n.forEach(((t,e)=>{const s=e*(80/n.length),a=30-(t-o)/(i-o)*30;d+=0===e?`M ${s},${a}`:` L ${s},${a}`}));const c=document.createElementNS("http://www.w3.org/2000/svg","path");c.setAttribute("d",d),c.setAttribute("stroke","#2196F3"),c.setAttribute("stroke-width","2"),c.setAttribute("fill","none"),l.appendChild(c),r.appendChild(l);const h=document.createElement("div");h.style.display="flex",h.style.flexDirection="column",h.style.fontSize="10px",h.style.textAlign="left";const p=document.createElement("div");p.textContent=`Avg: ${s.toFixed(2)}`;const u=document.createElement("div");u.textContent=`Range: ${o.toFixed(2)} - ${i.toFixed(2)}`,h.appendChild(p),h.appendChild(u),a.appendChild(r),a.appendChild(h);const m=this.tableElement.querySelector(`th:nth-child(${e+1})`);m&&(m.style.position="relative",m.appendChild(a))}renderSummaryVisualizations(){this.summaryVisualizationsElement?this.summaryVisualizationsElement.innerHTML="":(this.summaryVisualizationsElement=document.createElement("div"),this.summaryVisualizationsElement.className="summary-visualizations",this.summaryVisualizationsElement.style.padding="20px",this.summaryVisualizationsElement.style.backgroundColor="#fff",this.summaryVisualizationsElement.style.border="1px solid #ddd",this.summaryVisualizationsElement.style.borderRadius="4px",this.summaryVisualizationsElement.style.marginTop="20px",this.tableContainer.appendChild(this.summaryVisualizationsElement));const t=this.options.columns.filter((t=>{let e=!1;for(const n of this.originalData)if(void 0!==n[t.field]&&!isNaN(parseFloat(n[t.field]))){e=!0;break}return e}));if(0===t.length)return void(this.summaryVisualizationsElement.textContent="No numeric data to visualize");const e=document.createElement("h3");e.textContent="Data Visualizations",e.style.margin="0 0 20px 0",this.summaryVisualizationsElement.appendChild(e);const n=document.createElement("div");n.className="tabs-container",n.style.marginBottom="20px";const o=document.createElement("div");o.className="tab-content";const i=["Bar Chart","Line Chart","Distribution"].map(((e,n)=>{const o=document.createElement("button");return o.textContent=e,o.className=0===n?"active":"",o.style.padding="10px 15px",o.style.border="1px solid #ddd",o.style.borderBottom="none",o.style.backgroundColor=0===n?"#fff":"#f5f5f5",o.style.borderRadius="4px 4px 0 0",o.style.marginRight="5px",o.style.cursor="pointer",o.addEventListener("click",(()=>{i.forEach((t=>{t.classList.remove("active"),t.style.backgroundColor="#f5f5f5"})),o.classList.add("active"),o.style.backgroundColor="#fff",this.showTabContent(e,t)})),o}));i.forEach((t=>n.appendChild(t))),this.summaryVisualizationsElement.appendChild(n),this.summaryVisualizationsElement.appendChild(o),this.showTabContent("Bar Chart",t)}showTabContent(t,e){const n=this.summaryVisualizationsElement.querySelector(".tab-content");switch(n.innerHTML="",t){case"Bar Chart":this.createSummaryBarChart(n,e);break;case"Line Chart":this.createSummaryLineChart(n,e);break;case"Distribution":this.createSummaryDistribution(n,e)}}createSummaryBarChart(t,e){const n=document.createElement("div");n.style.marginBottom="20px";const o=document.createElement("select");o.className="column-select",e.forEach(((t,e)=>{const n=document.createElement("option");n.value=t.field,n.textContent=t.title||t.field,n.selected=0===e,o.appendChild(n)})),n.appendChild(o),t.appendChild(n);const i=document.createElement("div");i.className="bar-chart-container",i.style.height="300px",i.style.width="100%",i.style.overflowX="auto",i.style.overflowY="hidden",t.appendChild(i);const s=t=>{i.innerHTML="";const e=this.originalData.filter((e=>void 0!==e[t]&&!isNaN(parseFloat(e[t])))).map((e=>({label:e[this.options.columns[0].field]||"",value:parseFloat(e[t])}))).sort(((t,e)=>e.value-t.value)).slice(0,20);if(0===e.length)return void(i.textContent="No numeric data to display");const n=Math.max(...e.map((t=>t.value))),o=document.createElementNS("http://www.w3.org/2000/svg","svg");o.setAttribute("width","100%"),o.setAttribute("height","300"),o.style.display="block";for(let t=0;t<=4;t++){const e=250-250*t/4,n=document.createElementNS("http://www.w3.org/2000/svg","line");n.setAttribute("x1","40"),n.setAttribute("y1",e),n.setAttribute("x2","100%"),n.setAttribute("y2",e),n.setAttribute("stroke","#e0e0e0"),n.setAttribute("stroke-width","1"),o.appendChild(n)}const s=Math.min(40,(i.offsetWidth-50)/e.length-10);e.forEach(((t,a)=>{const r=40+a*((i.offsetWidth-50)/e.length),l=t.value/n*250,d=250-l,c=document.createElementNS("http://www.w3.org/2000/svg","rect");c.setAttribute("x",r),c.setAttribute("y",d),c.setAttribute("width",s),c.setAttribute("height",l),c.setAttribute("fill",this.getColorForIndex(a));const h=document.createElementNS("http://www.w3.org/2000/svg","text");h.setAttribute("x",r+s/2),h.setAttribute("y",d-5),h.setAttribute("text-anchor","middle"),h.setAttribute("font-size","12"),h.textContent=t.value.toLocaleString();const p=document.createElementNS("http://www.w3.org/2000/svg","text");p.setAttribute("x",r+s/2),p.setAttribute("y",295),p.setAttribute("text-anchor","middle"),p.setAttribute("font-size","10"),p.setAttribute("transform",`rotate(45, ${r+s/2}, 295)`),p.textContent=t.label.toString().substring(0,15),o.appendChild(c),o.appendChild(h),o.appendChild(p)})),i.appendChild(o)};s(o.value),o.addEventListener("change",(t=>{s(t.target.value)}))}createSummaryLineChart(t,e){const n=document.createElement("div");n.style.marginBottom="20px",n.style.display="flex",n.style.flexWrap="wrap",n.style.gap="10px";const o=[];e.forEach(((t,e)=>{const i=document.createElement("label");i.style.display="flex",i.style.alignItems="center";const a=document.createElement("input");a.type="checkbox",a.value=t.field,a.checked=e<3,a.checked&&o.push(t.field);const r=document.createElement("span");r.style.display="inline-block",r.style.width="12px",r.style.height="12px",r.style.backgroundColor=this.getColorForIndex(e),r.style.marginRight="5px",r.style.marginLeft="5px";const l=document.createElement("span");l.textContent=t.title||t.field,a.addEventListener("change",(()=>{if(a.checked)o.push(t.field);else{const e=o.indexOf(t.field);-1!==e&&o.splice(e,1)}s()})),i.appendChild(a),i.appendChild(r),i.appendChild(l),n.appendChild(i)})),t.appendChild(n);const i=document.createElement("div");i.className="line-chart-container",i.style.height="300px",i.style.width="100%",t.appendChild(i);const s=()=>{if(i.innerHTML="",0===o.length)return void(i.textContent="Select at least one column to display");const t=[];o.forEach((e=>{const n=this.originalData.filter((t=>void 0!==t[e]&&!isNaN(parseFloat(t[e])))).map(((t,n)=>({x:n,y:parseFloat(t[e])})));t.push({field:e,data:n})}));let n=[];t.forEach((t=>{n=n.concat(t.data.map((