dataTable/test/lib/datatable.min.js

2 lines
36 KiB
JavaScript

!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";const e={text:["contains","equals","starts","ends"],textarea:["contains","equals","starts","ends"],number:["=",">","<","between"],date:["=",">","<","between"],select:["contains","equals"],TagsInput:["contains","equals","starts","ends"]},t={contains:"bi-search",equals:"bi-distribute-vertical",starts:"bi-align-start",ends:"bi-align-end","=":"bi-calculator",">":"bi-chevron-right","<":"bi-chevron-left",between:"bi-arrows-expand"},i={_fieldTypes:new Map,registerFieldType:e=>{i._fieldTypes.set(e.value,e)},getFieldTypes:()=>Array.from(i._fieldTypes.values())};i.registerFieldType({value:"text",label:"{#Text#}",typeForDB:"v4096",schema:[{name:"placeholder",label:"Placeholder",type:"text",if:'this.data.user_type=="text"'}]}),i.registerFieldType({value:"number",label:"{#Number#}",typeForDB:"ff",schema:[{name:"decimals",label:"Decimals",type:"number",setting:{min:0,max:10},if:'this.data.user_type=="number"'},{name:"prefix",label:"Prefix (e.g. $)",type:"text",if:'this.data.user_type=="number"'},{name:"suffix",label:"Suffix (e.g. %)",type:"text",if:'this.data.user_type=="number"'},{name:"thousandSep",label:"Thousand Sep",type:"switch",if:'this.data.user_type=="number"'}],formatter:(e,t)=>{if(null==e||""===e)return"";let i=Number(e);if(isNaN(i))return e;const n=t.settings||{};void 0!==n.decimals&&(i=i.toFixed(n.decimals));let l=String(i);if(n.thousandSep){const e=l.split(".");e[0]=e[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),l=e.join(".")}return(n.prefix||"")+l+(n.suffix||"")}}),i.registerFieldType({value:"select",label:"{#Single Select#}",typeForDB:"v1024",schema:[{name:"options_str",label:"Options",type:"textarea",setting:{rows:3,placeholder:"Label:Value per line"},if:'this.data.user_type=="select"'}],formatter:(e,t)=>{var i;if(null==e||""===e)return"";const n=((null==(i=t.settings)?void 0:i.options)||[]).find(t=>"object"==typeof t?t.value==e:t==e);return n?"object"==typeof n?n.label:n:e}}),i.registerFieldType({value:"checkbox",label:"{#Multi Select#}",typeForDB:"v4096",schema:[{name:"options_str",label:"Options",type:"textarea",setting:{rows:3,placeholder:"Label:Value per line"},if:'this.data.user_type=="checkbox"'}],formatter:(e,t)=>{var i;if(!Array.isArray(e))return null==e?"":String(e);const n=(null==(i=t.settings)?void 0:i.options)||[];return e.map(e=>{const t=n.find(t=>"object"==typeof t?t.value==e:t==e);return t?"object"==typeof t?t.label:t:e}).join(", ")}}),i.registerFieldType({value:"switch",label:"{#Switch#}",typeForDB:"b",schema:[{name:"labelOn",label:"Label On",type:"text",if:'this.data.user_type=="switch"'},{name:"labelOff",label:"Label Off",type:"text",if:'this.data.user_type=="switch"'}],formatter:(e,t)=>{const i=t.settings||{};return e?i.labelOn||"Yes":i.labelOff||"No"}}),i.registerFieldType({value:"datetime",label:"{#DateTime#}",typeForDB:"dt",schema:[{name:"format",label:"Format",type:"text",setting:{placeholder:"YYYY-MM-DD"},if:'this.data.user_type=="datetime"'}]}),i.registerFieldType({value:"textarea",label:"{#Long Text#}",typeForDB:"t",schema:[{name:"placeholder",label:"Placeholder",type:"text",if:'this.data.user_type=="textarea"'}]});globalThis.Component.register("DataTable",n=>{n.state||(n.state=globalThis.NewState({}));const l=n.state;Object.assign(l,{list:[],fields:[],_renderedList:[],prevHeight:0,postHeight:0,_listStartIndex:0,selectedRowCount:0,_originalList:[],sortConfig:{fieldId:null,direction:null},filterConfig:{},activeFieldId:null,activeField:null,activeModes:[],_columnStats:{},_internalUpdate:!1,_appliedHash:"",_fieldsDirty:!1,_masterCellNodes:null,isDirty:!1,isBulkEdit:null});const s=(()=>{let e=!!globalThis.__DT_PERF_MODE__;const t={refreshTime:0,refreshCount:0,scrollCount:0,totalNodes:0};return e&&!globalThis.__statePerformanceTelemetry&&(globalThis.__statePerformanceTelemetry={scanCount:0,reuseCount:0,moveCount:0}),{get stats(){return t},enable:()=>{e=!0},disable:()=>{e=!1},onScroll:()=>{e&&t.scrollCount++},startFrame:()=>{var t,i,n;return e?{start:performance.now(),scan:(null==(t=globalThis.__statePerformanceTelemetry)?void 0:t.scanCount)||0,move:(null==(i=globalThis.__statePerformanceTelemetry)?void 0:i.moveCount)||0,reuse:(null==(n=globalThis.__statePerformanceTelemetry)?void 0:n.reuseCount)||0}:null},endFrame:(i,n)=>{if(!e||!i)return;t.refreshCount++,t.totalNodes+=n;const l=performance.now()-i.start;t.refreshTime+=l;const s=globalThis.__statePerformanceTelemetry;if(s){const e=s.scanCount-i.scan,t=s.moveCount-i.move,o=s.reuseCount-i.reuse;(e>0||l>2)&&console.log(`[DataTable Frame] Time: ${l.toFixed(2)}ms, Scans: ${e}, Moves: ${t}, Reuses: ${o}, Rows: ${n}`)}}}})();l.perf=s.stats;const o=((e,t)=>{let i=null,n=null,l=[];const s=(e,t)=>!!(i&&e>=i.minRow&&e<=i.maxRow&&t>=i.minCol&&t<=i.maxCol)||l.some(i=>e>=i.minRow&&e<=i.maxRow&&t>=i.minCol&&t<=i.maxCol);let o=!1;const a=()=>{if(globalThis.__DT_FEATURES__&&!globalThis.__DT_FEATURES__.selection)return;let n=1/0,a=-1/0;i&&(n=Math.min(n,i.minRow),a=Math.max(a,i.maxRow)),l.forEach(e=>{n=Math.min(n,e.minRow),a=Math.max(a,e.maxRow)});const r=n!==1/0;if(!r&&!o)return;o=r;const d=e.querySelector(".dt-body");d&&d.querySelectorAll(".dt-body-row").forEach(e=>{var i;const l=((null==(i=e._ref)?void 0:i.rIdx)??-1)+t._listStartIndex,o=e.querySelectorAll(".dt-cell");!r||l<n||l>a?o.forEach(e=>e.classList.remove("dt-cell-selected")):o.forEach((e,t)=>{s(l,t)?e.classList.add("dt-cell-selected"):e.classList.remove("dt-cell-selected")})})},r=()=>{let e=0;i&&(e+=i.maxRow-i.minRow+1),l.forEach(t=>e+=t.maxRow-t.minRow+1),t.selectedRowCount=e},d=(e=!1)=>{e||(i=null,n=null,l=[],a(),r())},c=()=>{if(!i)return null;let e=i.minRow,t=i.maxRow,n=i.minCol,s=i.maxCol;return l.forEach(i=>{e=Math.min(e,i.minRow),t=Math.max(t,i.maxRow),n=Math.min(n,i.minCol),s=Math.max(s,i.maxCol)}),{minRow:e,maxRow:t,minCol:n,maxCol:s}};return{applySelectionUI:a,clearAllActive:d,startSelect:(o,c,u)=>{const m=s(o,c),p=i&&(i.minRow!==i.maxRow||i.minCol!==i.maxCol)||l.length>0;u.shiftKey&&n?i={minRow:Math.min(n.row,o),maxRow:Math.max(n.row,o),minCol:Math.min(n.col,c),maxCol:Math.max(n.col,c)}:(!m||u.ctrlKey||u.metaKey?(u.ctrlKey||u.metaKey?i&&!m&&l.push(i):d(),n={row:o,col:c},i={minRow:o,maxRow:o,minCol:c,maxCol:c}):p||(e._potentialCancel={row:o,col:c}),t.isSelecting=!0),a(),r(),e.focus()},updateSelect:(l,s)=>{t.isSelecting&&n&&(i={minRow:Math.min(n.row,l),maxRow:Math.max(n.row,l),minCol:Math.min(n.col,s),maxCol:Math.max(n.col,s)},e._potentialCancel=null,a(),r())},endSelect:()=>{if(e._potentialCancel){const{row:t,col:i}=e._potentialCancel;s(t,i)&&d(),e._potentialCancel=null}t.isSelecting=!1},getSelectionBounds:c,copy:async()=>{const e=c();if(!e)return;const i=t.list.slice(e.minRow,e.maxRow+1).map(i=>t.fields.slice(e.minCol,e.maxCol+1).map(e=>{let t=String(i[e.id]??"");return(t.includes("\t")||t.includes("\n")||t.includes('"'))&&(t='"'+t.replace(/"/g,'""')+'"'),t}).join("\t")).join("\n");await navigator.clipboard.writeText(i)},paste:async()=>{try{const i=await navigator.clipboard.readText();if(!i)return;const n=c();if(!n)return;const l=i.split(/\r?\n/).filter(e=>e.length>0).map(e=>{const t=[];let i="",n=!1;for(let l=0;l<e.length;l++){const s=e[l];'"'===s?n&&'"'===e[l+1]?(i+='"',l++):n=!n:"\t"!==s||n?i+=s:(t.push(i),i="")}return t.push(i),t}),{minRow:s,minCol:o,maxRow:a,maxCol:r}=n,d=e.querySelector(".dt-body");d&&Array.from(d.childNodes).filter(e=>{var t;return null==(t=e.classList)?void 0:t.contains("dt-body-row")});let u=!1;l.forEach((e,i)=>{const n=s+i;if(n>a||n>=t.list.length)return;const l=t.list[n];let d=!1;e.forEach((e,i)=>{const n=o+i;if(n>r||n>=t.fields.length)return;const s=t.fields[n];l[s.id]=e,d=!0}),d&&(u=!0)}),u&&(t.list=[...t.list])}catch(e){console.error("Paste Error:",e)}}}})(n,l),a=((e,t,i)=>{const n=globalThis.VirtualScroll({itemHeight:40});let l=null;const s=(e=!1)=>{if(!l)return;const s=n.calc(l,t.list);if(s){if(!e&&t.prevHeight===s.prevHeight&&t.postHeight===s.postHeight&&t._listStartIndex===s.listStartIndex&&t._renderedList.length===s.renderedList.length)return;Object.assign(t,{prevHeight:s.prevHeight,postHeight:s.postHeight,_listStartIndex:s.listStartIndex,_renderedList:s.renderedList}),null==i||i(s.renderedList.length,e)}};return{init:()=>{l=e.querySelector(".dt-main")},reset:i=>{t._listStartIndex=0,n.reset(i,l||e),t.list===i&&n.init(i,()=>s(!0))},refresh:s,onScroll:()=>s(!1)}})(n,l,()=>o.applySelectionUI()),r=n.querySelector(".dt-column-menu");r&&(r._thisObj=n),n.onColumnResizing=(e,t)=>n.style.setProperty(`--w-${e.id}`,t.detail.newSize+"px"),n.onColumnResize=(e,t)=>{const i=l.fields.findIndex(t=>t.id===e.id);-1!==i&&(l.fields[i].width=t.detail.newSize,l.fields=[...l.fields])};let d,c=null;n.format=(e,t)=>{var n;if(t.formatter)return t.formatter(e,t);const l=i._fieldTypes.get((null==(n=t.settings)?void 0:n.formType)||t.type||"text");return l&&l.formatter?l.formatter(e,t):null==e?"":"object"==typeof e?JSON.stringify(e):String(e)},n.onScroll=()=>{s.onScroll(),a.refresh(),n.hideColumnMenu();const e=n.querySelector(".dt-spacer-prev"),t=n.querySelector(".dt-spacer-post");e&&(e.style.height=(l.prevHeight||0)+"px",e.style.display=l.prevHeight>0?"block":"none"),t&&(t.style.height=(l.postHeight||0)+"px",t.style.display=l.postHeight>0?"block":"none")},n.applySortFilter=(e={})=>{if(l._internalUpdate)return;const t={...l.filterConfig,...e.filters||{}},i=void 0!==e.sort?e.sort?{fieldId:l.activeFieldId,direction:e.sort}:{fieldId:null,direction:null}:l.sortConfig;let n=[...l._originalList];if(Object.entries(t).forEach(([e,t])=>{(t.value||t.selectedValues&&0!==t.selectedValues.length)&&(n=n.filter(i=>{var n;const l=i[e];if((null==(n=t.selectedValues)?void 0:n.length)>0)return t.selectedValues.includes(String(l));const s=String(t.value).toLowerCase(),o=String(l??"").toLowerCase();switch(t.mode){case"contains":return o.includes(s);case"equals":return o===s;case"starts":return o.startsWith(s);case"ends":return o.endsWith(s);case"=":return Number(l)===Number(t.value);case">":return Number(l)>Number(t.value);case"<":return Number(l)<Number(t.value);case"between":return Number(l)>=Number(t.value)&&Number(l)<=Number(t.value2);default:return!0}}))}),i.fieldId&&i.direction){const e=i.fieldId,t="asc"===i.direction?1:-1;n.sort((i,n)=>i[e]==n[e]?0:i[e]>n[e]?t:-t)}l._internalUpdate=!0,l.filterConfig=t,l.sortConfig=i,l.list=n,l._internalUpdate=!1},n.showColumnMenu=(t,i)=>{var s;const o=i.currentTarget,a=n.querySelector(".dt-column-menu"),r=(null==(s=t.settings)?void 0:s.formType)||t.type||"text";l.activeModes=e[r]||(["boolean","switch","checkbox","radio"].includes(r)?[]:e.text),l.filterConfig[t.id]||(l.filterConfig[t.id]={mode:l.activeModes[0]||"contains",value:"",selectedValues:[]}),l.activeField=t,l.activeFieldId=t.id,a.style.display="block";const d=o.closest(".dt-cell").getBoundingClientRect(),c=n.getBoundingClientRect(),u=a.offsetWidth||260;let m=d.right-c.left-u;m<0&&(m=Math.max(0,d.left-c.left)),a.style.left=m+"px",a.style.top=d.bottom-c.top+5+"px";const p=e=>{a.contains(e.target)||o.contains(e.target)||(n.hideColumnMenu(),n.applySortFilter(),document.removeEventListener("mousedown",p))};document.addEventListener("mousedown",p),setTimeout(()=>{var e;return null==(e=a.querySelector("input"))?void 0:e.focus()},50)},n.toggleSelectedValue=e=>{const t=l.filterConfig[l.activeFieldId];if(!t)return;const i=t.selectedValues.indexOf(e);-1===i?t.selectedValues.push(e):t.selectedValues.splice(i,1),l.filterConfig={...l.filterConfig},n.applySortFilter()},n.filterOnlyThis=e=>{l.filterConfig[l.activeFieldId]={mode:"contains",value:"",selectedValues:[String(e)]},l.filterConfig={...l.filterConfig},n.applySortFilter()},n.hideColumnMenu=()=>{const e=n.querySelector(".dt-column-menu");e&&(e.style.display="none")},n.setSort=e=>{const t=l.sortConfig.direction===e&&l.sortConfig.fieldId===l.activeFieldId?null:e;n.applySortFilter({sort:t})},n.clearColumnSettings=()=>{l.activeFieldId&&(delete l.filterConfig[l.activeFieldId],l.filterConfig={...l.filterConfig},n.applySortFilter())},n._initRow=e=>{var t;const i=null==(t=e._ref)?void 0:t.item;i&&void 0===i._editingF&&Object.defineProperty(i,"_editingF",{set:e=>{null===e&&n.hideEditor(!0)},configurable:!0}),Array.from(e.children).forEach(t=>{const i=parseInt(t.dataset.fidx);isNaN(i)||(t._ref={...t._ref||e._ref,f:l.fields[i],fIdx:i})})},l.__watch("fields",e=>{if(!e)return;l._fieldsDirty=!0,l._masterCellNodes=null,n.style.setProperty("--dt-grid-template",e.map(e=>{var t;return`var(--w-${e.id}, ${(null==(t=e.settings)?void 0:t.width)||e.width||150}px)`}).join(" ")),n.style.setProperty("--dt-row-width",e.reduce((e,t)=>{var i;return e+((null==(i=t.settings)?void 0:i.width)||t.width||150)},0)+"px");let t=0;e.forEach(e=>{var i,l;"left"===((null==(i=e.settings)?void 0:i.pinned)||e.pinned)&&(n.style.setProperty(`--l-${e.id}`,t+"px"),t+=(null==(l=e.settings)?void 0:l.width)||e.width||150)});let i=0;[...e].reverse().forEach(e=>{var t,l;"right"===((null==(t=e.settings)?void 0:t.pinned)||e.pinned)&&(n.style.setProperty(`--r-${e.id}`,i+"px"),i+=(null==(l=e.settings)?void 0:l.width)||e.width||150)})}),l.__watch("list",e=>{var t;if(l._fieldsDirty){l._fieldsDirty=!1;const e=null==(t=n.querySelector('.dt-body template[index="rIdx"]'))?void 0:t.content.querySelector('template[as="f"]');if(e){const t=l._masterCellNodes||(l._masterCellNodes=Array.from(e.content.childNodes).map(e=>e.cloneNode(!0)));e.removeAttribute("$each"),e.setAttribute("$if","true"),e.content.textContent="",l.fields.forEach((i,n)=>t.forEach(t=>{var l;const s=t.cloneNode(!0);if(1===s.nodeType){s.dataset.fidx=n;const e=(null==(l=i.settings)?void 0:l.pinned)||i.pinned;e&&(s.classList.add("pinned-"+e),s.style.position="sticky",s.style.zIndex="1",s.style.backgroundColor="inherit","left"===e?(s.style.left=`var(--l-${i.id})`,s.style.borderRight="1px solid var(--bs-border-color)",s.style.boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)"):(s.style.right=`var(--r-${i.id})`,s.style.borderLeft="1px solid var(--bs-border-color)",s.style.boxShadow="-2px 0 5px -2px rgba(0,0,0,0.1)"))}e.content.appendChild(s)}))}}l._internalUpdate||(l._originalList=[...e||[]],setTimeout(()=>{const e={};l.fields.forEach(t=>{const i={};l._originalList.forEach(e=>{const n=e[t.id],l=null==n||""===n?"":String(n);i[l]=(i[l]||0)+1}),e[t.id]=Object.entries(i).sort((e,t)=>t[1]-e[1]).slice(0,20).map(([e,t])=>({val:e,count:t}))}),l._columnStats=e},200)),a.init(),a.reset(e)}),n.editCell=(e,t,i)=>{var l,s;const o=n.querySelector(".dt-editor-overlay"),a=i.getBoundingClientRect(),r=n.getBoundingClientRect();c=i;const d=(null==(l=t.settings)?void 0:l.formType)||t.type||"text",u=o.querySelector("AutoForm");u&&(u.data=e,u.state.schema=[{...t,type:d,options:(null==(s=t.settings)?void 0:s.options)||t.options,name:t.id,label:""}]),Object.assign(o.style,{display:"flex",left:a.left-r.left-1+"px",top:a.top-r.top-1+"px",minWidth:a.width+2+"px",width:"max-content",maxWidth:"400px",height:"auto",minHeight:a.height+2+"px",padding:"0"}),setTimeout(()=>{var e;return null==(e=o.querySelector("input, textarea, select, .form-control"))?void 0:e.focus()},30)},n.hideEditor=(e=!0)=>{if(d||(d=n.querySelector(".dt-editor-overlay")),!d||"none"===d.style.display)return;const t=d.querySelector("AutoForm");if(e&&t&&t.data){const e=d.querySelector("input:focus, select:focus, textarea:focus");e&&e.dispatchEvent(new Event("number"===e.type||"SELECT"===e.tagName?"change":"input",{bubbles:!0}));if((t.state.schema||[]).forEach(e=>{var i,n;const l=null==(n=null==(i=null==c?void 0:c.closest(".dt-row"))?void 0:i._ref)?void 0:n.item;l&&(l[e.name]=t.data[e.name])}),l.isBulkEdit){const{minRow:e,maxRow:i,fIdx:n}=l.isBulkEdit,s=l.fields[n],o=t.data[s.id];for(let t=e;t<=i;t++)l.list[t]&&(l.list[t][s.id]=o)}l.list=[...l.list],l.isDirty=!0}d.style.display="none",t&&(t.state.schema=[],t.data=null),c=null,l.isBulkEdit=null,n.focus()},n.onMainMouseDown=e=>{var t;const i=e.target.closest(".dt-cell"),s=null==i?void 0:i.closest(".dt-row");if(!s||s.classList.contains("dt-header-row"))return;const a=i.dataset.fidx?parseInt(i.dataset.fidx):Array.from(s.querySelectorAll(".dt-cell")).indexOf(i),r=(null==(t=s._ref)?void 0:t.rIdx)??Array.from(n.querySelectorAll(".dt-body-row")).indexOf(s);o.startSelect(r+l._listStartIndex,a,e)},n.onMainMouseOver=e=>{var t;if(l.isSelecting){const i=e.target.closest(".dt-cell"),s=null==i?void 0:i.closest(".dt-row");if(s&&!s.classList.contains("dt-header-row")){const e=i.dataset.fidx?parseInt(i.dataset.fidx):Array.from(s.querySelectorAll(".dt-cell")).indexOf(i),a=(null==(t=s._ref)?void 0:t.rIdx)??Array.from(n.querySelectorAll(".dt-body-row")).indexOf(s);o.updateSelect(a+l._listStartIndex,e)}}},n.onMainDblClick=e=>{var t,i,s;const a=e.target.closest(".dt-cell"),r=null==a?void 0:a.closest(".dt-row");if(r&&!r.classList.contains("dt-header-row")){const e=null==(t=r._ref)?void 0:t.item,d=a.dataset.fidx?parseInt(a.dataset.fidx):Array.from(r.querySelectorAll(".dt-cell")).indexOf(a),c=((null==(i=r._ref)?void 0:i.rIdx)??Array.from(n.querySelectorAll(".dt-body-row")).indexOf(r))+l._listStartIndex;if(e&&l.fields[d]){const t=o.getSelectionBounds();if(t&&c>=t.minRow&&c<=t.maxRow&&d>=t.minCol&&d<=t.maxCol){const e=t.maxRow-t.minRow+1;e>1&&(l.isBulkEdit={...t,fIdx:d},(null==(s=globalThis.UI)?void 0:s.toast)&&globalThis.UI.toast(`Bulk Edit: Updating ${e} rows in column "${l.fields[d].name}"`,{type:"warning"}))}n.editCell(e,l.fields[d],a)}}},n.addRow=()=>{const e={};l.fields.forEach(t=>e[t.id]=""),l._originalList.push(e),l.list=[...l._originalList],l.isDirty=!0,setTimeout(()=>{a.reset(l.list),n.querySelector(".dt-main").scrollTop=n.querySelector(".dt-main").scrollHeight},50)},n.deleteSelectedRow=async()=>{const e=o.getSelectionBounds();if(!e)return;const t=e.maxRow-e.minRow+1;if(await globalThis.UI.confirm(`Are you sure you want to delete ${t} row(s)?`)){const t=e.minRow,i=e.maxRow,s=l.list.slice(t,i+1);l.list=l.list.filter((e,n)=>!(n>=t&&n<=i)),l._originalList=l._originalList.filter(e=>!s.includes(e)),l.isDirty=!0,o.clearAllActive(),n.dispatchEvent(new CustomEvent("remove",{detail:{items:s}}))}},n.saveChanges=()=>{n.dispatchEvent(new CustomEvent("save",{detail:{list:l._originalList,fields:l.fields}})),l.isDirty=!1};const u=()=>{const e=globalThis.DataTable.getFieldTypes(),t=[{name:"id",label:"Field ID",type:"text",setting:{required:!0,placeholder:"e.g. user_name"}},{name:"name",label:"Display Name",type:"text",setting:{required:!0,placeholder:"e.g. 用户名"}},{name:"user_type",label:"Field Type",type:"select",options:e.map(e=>({label:e.label,value:e.value}))}],i=e.reduce((e,t)=>e.concat(t.schema||[]),[]);return t.concat(i,[{name:"isIndex",label:"Index",type:"switch"},{name:"memo",label:"Memo",type:"text"}])},m=e=>{if(e)return e.split("\n").map(e=>e.trim()).filter(Boolean).map(e=>{const t=e.indexOf(":");return t>-1?{label:e.slice(0,t).trim(),value:e.slice(t+1).trim()}:e})};n.addField=async()=>{n.hideColumnMenu();const e=globalThis.NewState({id:"c"+Date.now().toString().slice(-4),name:"New Field",user_type:"text",decimals:0,isIndex:!1,memo:"",options_str:""}),t=n.querySelector(`Modal[id="${n.id}_field_modal"]`);if(!t)return;Object.assign(t.state,{title:"Add Field",buttons:["Cancel","Save"]});const i=t.querySelector("AutoForm");i&&(i.data=e,i.state.schema=u()),t.show();if(2===await new Promise(e=>t.addEventListener("change",i=>e(t.result),{once:!0}))){const t=globalThis.DataTable.getFieldTypes().find(t=>t.value===e.user_type);let i=(null==t?void 0:t.typeForDB)||"v1024";"number"===e.user_type&&(i=e.decimals>0?"ff":"bi");const s={id:e.id,name:e.name,memo:e.memo,isIndex:!!e.isIndex,type:i,settings:{formType:e.user_type,decimals:e.decimals,prefix:e.prefix,suffix:e.suffix,thousandSep:e.thousandSep,labelOn:e.labelOn,labelOff:e.labelOff,format:e.format,placeholder:e.placeholder,options:m(e.options_str)}};l.fields=[...l.fields,s],l.isDirty=!0,n.dispatchEvent(new CustomEvent("savefields",{detail:l.fields})),l.list=[...l.list]}},n.editField=async()=>{if(!l.activeField)return;n.hideColumnMenu();const e=l.activeField,t=e.settings||{},i=globalThis.NewState({id:e.id,name:e.name,memo:e.memo||"",isIndex:!!e.isIndex,user_type:t.formType||"text",decimals:t.decimals||0,prefix:t.prefix||"",suffix:t.suffix||"",thousandSep:!!t.thousandSep,labelOn:t.labelOn||"",labelOff:t.labelOff||"",format:t.format||"",placeholder:t.placeholder||"",options_str:(s=t.options,s?s.map(e=>"object"==typeof e?`${e.label}:${e.value}`:e).join("\n"):"")});var s;const o=n.querySelector(`Modal[id="${n.id}_field_modal"]`);if(!o)return;Object.assign(o.state,{title:"Edit Field",buttons:["Cancel","Save"]});const a=o.querySelector("AutoForm");a&&(a.data=i,a.state.schema=u()),o.show();if(2===await new Promise(e=>o.addEventListener("change",t=>e(o.result),{once:!0}))){const t=l.fields.findIndex(t=>t.id===e.id);if(-1!==t){const s=globalThis.DataTable.getFieldTypes().find(e=>e.value===i.user_type);let o=(null==s?void 0:s.typeForDB)||"v1024";"number"===i.user_type&&(o=i.decimals>0?"ff":"bi");const a={...e,id:i.id,name:i.name,memo:i.memo,isIndex:!!i.isIndex,type:o,settings:{...e.settings,formType:i.user_type,decimals:i.decimals,prefix:i.prefix,suffix:i.suffix,thousandSep:i.thousandSep,labelOn:i.labelOn,labelOff:i.labelOff,format:i.format,placeholder:i.placeholder,options:m(i.options_str)}};l.fields[t]=a,l.fields=[...l.fields],l.isDirty=!0,n.dispatchEvent(new CustomEvent("savefields",{detail:l.fields})),l.list=[...l.list]}}},n.deleteField=async()=>{if(l.activeField&&(n.hideColumnMenu(),await globalThis.UI.confirm(`Are you sure you want to delete field "${l.activeField.name}"?`))){const e=l.fields.findIndex(e=>e.id===l.activeField.id);-1!==e&&(l.fields.splice(e,1),l.fields=[...l.fields],l.isDirty=!0,n.dispatchEvent(new CustomEvent("savefields",{detail:l.fields})),l.list=[...l.list])}},window.addEventListener("mouseup",o.endSelect),document.addEventListener("mousedown",e=>{const t=n.querySelector(".dt-editor-overlay"),i=n.querySelector(".dt-column-menu");"none"===(null==t?void 0:t.style.display)||t.contains(e.target)||n.hideEditor(!0),n.contains(e.target)||(null==t?void 0:t.contains(e.target))||(null==i?void 0:i.contains(e.target))||o.clearAllActive()}),l._MODE_ICONS=t},globalThis.Util.makeDom('\n<div class="dt-root d-flex flex-column h-100 border bg-body text-body overflow-hidden" style="position:relative; user-select:none; outline: none; min-height: 0" tabindex="0">\n <div class="dt-main flex-grow-1 overflow-auto" $onscroll="this.onScroll()" \n $onmousedown="this.onMainMouseDown(event)" $onmouseover="this.onMainMouseOver(event)" $ondblclick="this.onMainDblClick(event)"\n style="overflow-anchor:none; min-height: 0">\n <div class="dt-header border-bottom bg-light sticky-top" style="z-index:20">\n <div class="dt-header-row fw-bold text-muted small">\n <template $each="this.state?.fields || []">\n <div $data-id="item.id" $class="dt-cell dt-col border-end d-flex align-items-center header-cell ${(item.settings?.pinned || item.pinned) ? \'pinned-\' + (item.settings?.pinned || item.pinned) : \'\'}" $style="((item.settings?.pinned || item.pinned) ? \'position: sticky; z-index: 11; background-color: inherit; \' : \'position:relative; \') + \'padding: 0; \' + ((item.settings?.pinned || item.pinned) === \'left\' ? \'left: var(--l-\' + item.id + \'); border-right: 1px solid var(--bs-border-color); box-shadow: 2px 0 5px -2px rgba(0,0,0,0.1);\' : ((item.settings?.pinned || item.pinned) === \'right\' ? \'right: var(--r-\' + item.id + \'); border-left: 1px solid var(--bs-border-color); box-shadow: -2px 0 5px -2px rgba(0,0,0,0.1);\' : \'\'))">\n <div class="d-flex align-items-center overflow-hidden flex-grow-1 h-100 px-2 cursor-pointer" $onclick="this.showColumnMenu(item, event)">\n <i $if="this.state?.filterConfig?.[item.id] && (this.state.filterConfig[item.id].value || this.state.filterConfig[item.id].selectedValues?.length)" class="bi bi-filter me-1 text-primary"></i>\n <i $if="this.state?.sortConfig?.fieldId === item.id && this.state.sortConfig.direction" $class="bi bi-sort-${this.state.sortConfig.direction === \'asc\' ? \'down\' : \'up-alt\'} me-1 text-primary"></i>\n <span $text="item.name" class="text-truncate flex-grow-1"></span>\n </div>\n <button class="btn btn-xs btn-link text-muted p-0 border-0 me-1 header-menu-btn" $onclick="this.showColumnMenu(item, event)"><i class="bi bi-chevron-down"></i></button>\n <Resizer $.target="thisNode.parentElement" style="position:absolute; right:0; top:0; bottom:0; width:4px; z-index:10" min="50" max="1000" $onresizing="this.onColumnResizing(item, event)" $onresize="this.onColumnResize(item, event)"></Resizer>\n </div>\n </template>\n </div>\n </div>\n <div class="dt-body" style="position:relative">\n <div class="dt-spacer-prev flex-shrink-0" style="display:none"></div>\n <template $each="this.state?._renderedList || []" key="id" index="rIdx">\n <div class="dt-row dt-body-row border-bottom bg-white" $.="this._initRow(thisNode)">\n <template as="f"><div $class="dt-cell border-end px-2 d-flex align-items-center ${(f.settings?.pinned || f.pinned) ? \'pinned-\' + (f.settings?.pinned || f.pinned) : \'\'}" $style="((f.settings?.pinned || f.pinned) ? \'position: sticky; z-index: 1; background-color: inherit; \' : \'\') + ((f.settings?.pinned || f.pinned) === \'left\' ? \'left: var(--l-\' + f.id + \'); border-right: 1px solid var(--bs-border-color); box-shadow: 2px 0 5px -2px rgba(0,0,0,0.1);\' : ((f.settings?.pinned || f.pinned) === \'right\' ? \'right: var(--r-\' + f.id + \'); border-left: 1px solid var(--bs-border-color); box-shadow: -2px 0 5px -2px rgba(0,0,0,0.1);\' : \'\'))"><span $text="this.format(item[f.id], f)" class="text-truncate"></span></div></template>\n </div>\n </template>\n <div class="dt-spacer-post flex-shrink-0" style="display:none"></div>\n </div>\n </div>\n\n <div class="dt-column-menu bg-body shadow-lg rounded p-2" style="display:none; position:absolute; z-index:2000; min-width:240px; max-width:300px; border: 1px solid var(--bs-primary)">\n <template $if="this.state?.activeFieldId">\n <div class="d-flex gap-1 mb-2">\n <button $class="btn btn-xs flex-grow-1 d-flex align-items-center justify-content-center ${this.state?.sortConfig?.direction === \'asc\' && this.state?.sortConfig?.fieldId === this.state?.activeFieldId ? \'btn-primary\' : \'btn-outline-secondary border\'}" $onclick="this.setSort(\'asc\')"><i class="bi bi-sort-alpha-down me-1"></i> ASC</button>\n <button $class="btn btn-xs flex-grow-1 d-flex align-items-center justify-content-center ${this.state?.sortConfig?.direction === \'desc\' && this.state?.sortConfig?.fieldId === this.state?.activeFieldId ? \'btn-primary\' : \'btn-outline-secondary border\'}" $onclick="this.setSort(\'desc\')"><i class="bi bi-sort-alpha-up-alt me-1"></i> DESC</button>\n </div>\n\n <div $if="this.state?.activeModes?.length" class="dt-filter-tabs d-flex overflow-auto border-bottom bg-light-subtle rounded-top py-1" style="white-space:nowrap; scrollbar-width: none;">\n <template $each="this.state?.activeModes || []" as="m">\n <div $class="px-2 py-1 cursor-pointer fs-5 ${this.state?.filterConfig?.[this.state?.activeFieldId]?.mode === m ? \'text-primary border-bottom border-primary border-2\' : \'text-muted\'}" $title="m.toUpperCase()" $onclick="this.state.filterConfig[this.state.activeFieldId].mode = m; this.state.filterConfig = {...this.state.filterConfig}">\n <i $class="bi ${this.state?._MODE_ICONS?.[m] || \'bi-filter\'}"></i>\n </div>\n </template>\n </div>\n\n <template $if="this.state?.activeModes?.length">\n <div class="py-2 border-bottom" style="min-height: 48px">\n <input type="text" class="form-control form-control-sm mb-1" $placeholder="(this.state?.filterConfig?.[this.state?.activeFieldId]?.mode || \'Search\').toUpperCase() + \'...\'" $bind="this.state?.filterConfig?.[this.state?.activeFieldId].value" $onkeydown="if(event.key===\'Enter\'){this.applySortFilter();this.hideColumnMenu();}">\n <input $if="this.state?.filterConfig?.[this.state?.activeFieldId]?.mode === \'between\'" type="text" class="form-control form-control-sm" placeholder="And..." $bind="this.state?.filterConfig?.[this.state?.activeFieldId].value2" $onkeydown="if(event.key===\'Enter\'){this.applySortFilter();this.hideColumnMenu();}">\n </div>\n </template>\n\n <div class="mt-2" style="max-height: 180px; overflow-y: auto;">\n <div class="text-muted fw-bold mb-1" style="font-size: 9px; letter-spacing: 0.5px">TOP FREQUENT VALUES</div>\n <template $each="this.state?._columnStats?.[this.state?.activeFieldId] || []">\n <label class="d-flex align-items-center mb-1 small cursor-pointer p-1 rounded-1 menu-item-row" onmouseover="this.style.background=\'var(--bs-light)\'" onmouseout="this.style.background=\'transparent\'">\n <input type="checkbox" class="form-check-input me-2" $checked="this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.includes(String(item.val))" $onclick="this.toggleSelectedValue(String(item.val))">\n <span class="text-truncate flex-grow-1"><span $text="item.val || \'(Empty)\'"></span> <span class="text-muted ms-1" style="font-size: 0.7rem" $text="\'(\' + item.count + \')\'"></span></span>\n <button class="btn btn-xs btn-link p-0 text-primary only-btn" style="font-size: 10px; text-decoration: none" $onclick="this.filterOnlyThis(item.val); event.preventDefault(); event.stopPropagation();">Only</button>\n </label>\n </template>\n </div>\n\n <div $if="this.state?.filterConfig?.[this.state?.activeFieldId]?.value || this.state?.filterConfig?.[this.state?.activeFieldId]?.selectedValues?.length" class="mt-2 pt-1 border-top text-center">\n <span class="cursor-pointer text-primary small fw-bold" $onclick="this.clearColumnSettings()"><i class="bi bi-x-circle me-1"></i> Clear Filter</span>\n </div>\n\n <div class="mt-3 pt-2 border-top d-flex flex-column gap-1">\n <button class="btn btn-xs btn-outline-secondary border d-flex align-items-center px-2 py-1" $onclick="this.editField()"><i class="bi bi-pencil me-2"></i> Edit Field</button>\n <button class="btn btn-xs btn-outline-secondary border d-flex align-items-center px-2 py-1" $onclick="this.addField()"><i class="bi bi-plus-lg me-2"></i> Add Field</button>\n <button class="btn btn-xs btn-outline-danger border d-flex align-items-center px-2 py-1" $onclick="this.deleteField()"><i class="bi bi-trash me-2"></i> Delete Field</button>\n </div>\n </template>\n </div>\n\n <div class="dt-editor-overlay dt-editor-container" style="display: none; position: absolute; z-index: 1000; background: var(--bs-body-bg); box-shadow: 0 4px 16px rgba(0,0,0,0.25); border: 1px solid var(--bs-primary); padding: 0;"><AutoForm nobutton inline class="h-100 w-100" $onsubmit="event.preventDefault(); thisNode.closest(\'DataTable\').hideEditor(true)"></AutoForm></div>\n\n <Modal $.id="this.id + \'_field_modal\'">\n <div slot="body"><AutoForm nobutton class="p-3"></AutoForm></div>\n <div slot="footer">\n <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" $onclick="thisNode.closest(\'Modal\').result=1">Cancel</button>\n <button type="button" class="btn btn-primary" data-bs-dismiss="modal" $onclick="thisNode.closest(\'Modal\').result=2">Save</button>\n </div>\n </Modal>\n\n <div class="dt-footer border-top bg-light d-flex align-items-center px-3 py-1 shadow-sm" style="height:40px; z-index: 10">\n <div class="d-flex align-items-center gap-3 flex-grow-1">\n <div class="btn-group shadow-sm">\n <button class="btn btn-xs btn-white border d-flex align-items-center px-2" style="background:white" $onclick="this.addRow()" title="Add Row"><i class="bi bi-plus-lg text-primary me-1"></i> Add</button>\n <button class="btn btn-xs btn-white border d-flex align-items-center px-2" style="background:white" $onclick="this.deleteSelectedRow()" $disabled="!this.state?.selectedRowCount" title="Delete Selected Rows"><i class="bi bi-trash text-danger me-1"></i> Delete</button>\n </div>\n <div class="vr h-50 my-auto text-muted opacity-25"></div>\n <div class="d-flex align-items-center gap-2 text-muted" style="font-size: 0.75rem">\n <i class="bi bi-check-all fs-6"></i>\n <span $text="(this.state?.selectedRowCount || 0) + \' selected / \' + (this.state?.list?.length || 0) + \' total\'"></span>\n </div>\n </div>\n <div class="d-flex align-items-center gap-2">\n <button $if="this.state?.isDirty" class="btn btn-xs btn-primary px-3 shadow-sm d-flex align-items-center fw-bold" $onclick="this.saveChanges()"><i class="bi bi-cloud-upload me-1"></i> Save Changes</button>\n <button $if="!this.state?.isDirty" class="btn btn-xs btn-light border px-3 text-muted disabled d-flex align-items-center" disabled><i class="bi bi-cloud-check me-1"></i> Up to date</button>\n </div>\n </div>\n</div>\n'),globalThis.Util.makeDom("\n<style>\n DataTable { display: block; }\n .dt-root { font-size: 0.875rem; }\n .dt-row, .dt-header-row { display: grid; grid-template-columns: var(--dt-grid-template); width: var(--dt-row-width, max-content); min-width: 100%; height: 40px; contain: paint layout; }\n .dt-header-row { background-color: var(--bs-tertiary-bg); border-bottom: 1px solid var(--bs-border-color); }\n .dt-cell { background: inherit; white-space: nowrap; flex-shrink: 0; contain: content; }\n .dt-cell-selected { background-color: rgba(var(--bs-primary-rgb), 0.15) !important; outline: 1px solid var(--bs-primary); outline-offset: -1px; }\n .dt-body-row:hover { background-color: var(--bs-secondary-bg) !important; }\n .header-cell .header-menu-btn { opacity: 0; transition: opacity 0.2s; }\n .header-cell:hover .header-menu-btn { opacity: 1; }\n .dt-column-menu { background-color: var(--bs-body-bg); border: 1px solid var(--bs-primary); box-shadow: 0 10px 40px rgba(0,0,0,0.2) !important; z-index: 2100 !important; }\n .btn-xs { padding: 1px 5px; line-height: 1.5; }\n .cursor-pointer { cursor: pointer; }\n .dt-filter-tabs i { font-size: 1.1rem; }\n .dt-filter-tabs div:hover i { color: var(--bs-primary); }\n .menu-item-row .only-btn { opacity: 0; }\n .menu-item-row:hover .only-btn { opacity: 1; }\n .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; }\n .dt-editor-overlay [control-wrapper] { width: 100%; margin: 0 !important; min-height: 100% !important; align-items: stretch !important; }\n</style>\n")),globalThis.DataTable=i});