From 549ab0b552d8c7329248acf7af3e6cfbb87ff235 Mon Sep 17 00:00:00 2001 From: AI Engineer Date: Fri, 12 Jun 2026 00:14:59 +0800 Subject: [PATCH] fix: make inline editor overlay follow scrolling and refine menu markup By: AICoder --- dist/datatable.js | 104 ++++++++++++++++++++++++-------------- dist/datatable.min.js | 2 +- package-lock.json | 4 +- package.json | 2 +- src/DataTable.js | 96 +++++++++++++++++++++++------------ test/lib/datatable.js | 104 ++++++++++++++++++++++++-------------- test/lib/datatable.min.js | 2 +- test/lib/state.js | 2 +- 8 files changed, 199 insertions(+), 117 deletions(-) diff --git a/dist/datatable.js b/dist/datatable.js index 4583e67..f6a91ab 100644 --- a/dist/datatable.js +++ b/dist/datatable.js @@ -276,14 +276,14 @@ }; const getSelectionBounds = () => { if (!activeBounds) return null; - let minRow = activeBounds.minRow, maxRow = activeBounds.maxRow, minCol = activeBounds.minCol, maxCol = activeBounds.maxCol; + let minRow2 = activeBounds.minRow, maxRow = activeBounds.maxRow, minCol2 = activeBounds.minCol, maxCol = activeBounds.maxCol; multiSelections.forEach((s) => { - minRow = Math.min(minRow, s.minRow); + minRow2 = Math.min(minRow2, s.minRow); maxRow = Math.max(maxRow, s.maxRow); - minCol = Math.min(minCol, s.minCol); + minCol2 = Math.min(minCol2, s.minCol); maxCol = Math.max(maxCol, s.maxCol); }); - return { minRow, maxRow, minCol, maxCol }; + return { minRow: minRow2, maxRow, minCol: minCol2, maxCol }; }; const copy = async () => { const bounds = getSelectionBounds(); @@ -321,7 +321,11 @@ cells.push(current); return cells; }); - const { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + let { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + if (minRow === maxRow && minCol === maxCol) { + maxRow = Infinity; + maxCol = Infinity; + } const body = container.querySelector(".dt-body"); const rowNodes = body ? Array.from(body.childNodes).filter((n) => { var _a; @@ -615,22 +619,30 @@ }); container.editCell = (row, field, cellNode) => { var _a, _b; - const overlay = container.querySelector(".dt-editor-overlay"), rect = cellNode.getBoundingClientRect(), rootRect = container.getBoundingClientRect(); + const main = container.querySelector(".dt-main"); + const overlay = container.querySelector(".dt-editor-overlay"), rect = cellNode.getBoundingClientRect(), mainRect = main.getBoundingClientRect(); currentEditingNode = cellNode; const formType = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text"; const form = overlay.querySelector("AutoForm"); if (form) { - form.data = row; + form.data = globalThis.NewState(globalThis.Util.clone(row)); form.state.schema = [{ ...field, type: formType, options: ((_b = field.settings) == null ? void 0 : _b.options) || field.options, name: field.id, label: "" }]; } const isComplex = ["textarea", "TagsInput", "checkbox", "radio"].includes(formType); + let topPos = rect.top - mainRect.top + main.scrollTop - 1; + let leftPos = rect.left - mainRect.left + main.scrollLeft - 1; + let editorWidth = Math.max(rect.width + 2, isComplex ? 300 : 0); + const maxLeft = main.scrollWidth - editorWidth - 5; + if (leftPos > maxLeft) leftPos = Math.max(0, maxLeft); Object.assign(overlay.style, { display: "flex", - left: rect.left - rootRect.left - 1 + "px", - top: rect.top - rootRect.top - 1 + "px", - width: Math.max(rect.width + 2, isComplex ? 300 : 0) + "px", + left: leftPos + "px", + top: topPos + "px", + width: editorWidth + "px", height: "auto", minHeight: rect.height + 2 + "px", + maxHeight: Math.max(100, mainRect.height - (rect.top - mainRect.top) - 5) + "px", + overflow: "auto", padding: "0" }); setTimeout(() => { @@ -645,22 +657,31 @@ if (save && form && form.data) { const input = _editorOverlay.querySelector("input:focus, select:focus, textarea:focus"); if (input) input.dispatchEvent(new Event(input.type === "number" || input.tagName === "SELECT" ? "change" : "input", { bubbles: true })); + let hasChanges = false; const schema = form.state.schema || []; schema.forEach((field) => { var _a, _b; const row = (_b = (_a = currentEditingNode == null ? void 0 : currentEditingNode.closest(".dt-row")) == null ? void 0 : _a._ref) == null ? void 0 : _b.item; - if (row) row[field.name] = form.data[field.name]; + if (row && JSON.stringify(row[field.name]) !== JSON.stringify(form.data[field.name])) { + row[field.name] = form.data[field.name]; + hasChanges = true; + } }); if (state.isBulkEdit) { - const { minRow, maxRow, fIdx } = state.isBulkEdit; + const { minRow: minRow2, maxRow, fIdx } = state.isBulkEdit; const field = state.fields[fIdx]; const newValue = form.data[field.id]; - for (let i = minRow; i <= maxRow; i++) { - if (state.list[i]) state.list[i][field.id] = newValue; + for (let i = minRow2; i <= maxRow; i++) { + if (state.list[i] && state.list[i][field.id] !== newValue) { + state.list[i][field.id] = newValue; + hasChanges = true; + } } } - state.list = [...state.list]; - state.isDirty = true; + if (hasChanges) { + state.list = [...state.list]; + state.isDirty = true; + } } _editorOverlay.style.display = "none"; if (form) { @@ -851,7 +872,7 @@ }, globalThis.Util.makeDom( /*html*/ ` -
+
@@ -879,6 +900,7 @@
+
-
- -
- @@ -918,16 +944,14 @@ Clear Filter
-
- - - +
+ + +
- -
@@ -938,9 +962,9 @@ @@ -975,9 +999,11 @@ .dt-filter-tabs div:hover i { color: var(--bs-primary); } .menu-item-row .only-btn { opacity: 0; } .menu-item-row:hover .only-btn { opacity: 1; } - .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; } + .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; height: 100%; } .dt-editor-overlay [control-wrapper] { width: 100%; margin: 0 !important; min-height: 100% !important; align-items: stretch !important; } - .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0.375rem 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .form-switch { padding-left: 2.5rem !important; } + .dt-editor-overlay [control-wrapper] > textarea { min-height: 100px; resize: vertical; } ` )); diff --git a/dist/datatable.min.js b/dist/datatable.min.js index 2c0604a..d399d97 100644 --- a/dist/datatable.min.js +++ b/dist/datatable.min.js @@ -1 +1 @@ -!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||la?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{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)&&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:""}]);const m=["textarea","TagsInput","checkbox","radio"].includes(d);Object.assign(o.style,{display:"flex",left:a.left-r.left-1+"px",top:a.top-r.top-1+"px",width:Math.max(a.width+2,m?300:0)+"px",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()}),n.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&"c"===e.key.toLowerCase()&&(e.preventDefault(),o.copy()),(e.ctrlKey||e.metaKey)&&"v"===e.key.toLowerCase()&&(e.preventDefault(),o.paste())}),l._MODE_ICONS=t},globalThis.Util.makeDom('\n
\n
\n
\n
\n \n
\n
\n
\n \n \n \n
\n
\n\n \n\n \n\n \n
\n
\n \n \n
\n
\n\n \n
\n'),globalThis.Util.makeDom("\n\n")),globalThis.DataTable=i}); +!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||la?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{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)&&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-main"),a=n.querySelector(".dt-editor-overlay"),r=i.getBoundingClientRect(),d=o.getBoundingClientRect();c=i;const u=(null==(l=t.settings)?void 0:l.formType)||t.type||"text",m=a.querySelector("AutoForm");m&&(m.data=globalThis.NewState(globalThis.Util.clone(e)),m.state.schema=[{...t,type:u,options:(null==(s=t.settings)?void 0:s.options)||t.options,name:t.id,label:""}]);const p=["textarea","TagsInput","checkbox","radio"].includes(u);let f=r.top-d.top+o.scrollTop-1,h=r.left-d.left+o.scrollLeft-1,b=Math.max(r.width+2,p?300:0);const g=o.scrollWidth-b-5;h>g&&(h=Math.max(0,g)),Object.assign(a.style,{display:"flex",left:h+"px",top:f+"px",width:b+"px",height:"auto",minHeight:r.height+2+"px",maxHeight:Math.max(100,d.height-(r.top-d.top)-5)+"px",overflow:"auto",padding:"0"}),setTimeout(()=>{var e;return null==(e=a.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}));let i=!1;if((t.state.schema||[]).forEach(e=>{var n,l;const s=null==(l=null==(n=null==c?void 0:c.closest(".dt-row"))?void 0:n._ref)?void 0:l.item;s&&JSON.stringify(s[e.name])!==JSON.stringify(t.data[e.name])&&(s[e.name]=t.data[e.name],i=!0)}),l.isBulkEdit){const{minRow:e,maxRow:n,fIdx:s}=l.isBulkEdit,o=l.fields[s],a=t.data[o.id];for(let t=e;t<=n;t++)l.list[t]&&l.list[t][o.id]!==a&&(l.list[t][o.id]=a,i=!0)}i&&(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()}),n.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&"c"===e.key.toLowerCase()&&(e.preventDefault(),o.copy()),(e.ctrlKey||e.metaKey)&&"v"===e.key.toLowerCase()&&(e.preventDefault(),o.paste())}),l._MODE_ICONS=t},globalThis.Util.makeDom('\n
\n
\n
\n
\n \n
\n
\n
\n \n \n \n
\n \n
\n\n \n\n \n
\n
\n \n \n
\n
\n\n \n
\n'),globalThis.Util.makeDom("\n\n")),globalThis.DataTable=i}); diff --git a/package-lock.json b/package-lock.json index 06d5625..06fece3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@web/datatable", - "version": "1.0.12", + "version": "1.0.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@web/datatable", - "version": "1.0.12", + "version": "1.0.13", "devDependencies": { "@playwright/test": "^1.40.0", "@rollup/plugin-terser": "^1.0.0", diff --git a/package.json b/package.json index ef90dfe..07ec328 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@web/datatable", - "version": "1.0.12", + "version": "1.0.13", "type": "module", "main": "dist/datatable.js", "module": "dist/datatable.js", diff --git a/src/DataTable.js b/src/DataTable.js index fcfee23..502a515 100644 --- a/src/DataTable.js +++ b/src/DataTable.js @@ -229,7 +229,11 @@ const createSelectionManager = (container, state) => { } cells.push(current); return cells; }); - const { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + let { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + if (minRow === maxRow && minCol === maxCol) { + maxRow = Infinity; + maxCol = Infinity; + } const body = container.querySelector('.dt-body'); const rowNodes = body ? Array.from(body.childNodes).filter(n => n.classList?.contains('dt-body-row')) : []; let anyRowChanged = false; @@ -427,22 +431,32 @@ globalThis.Component.register('DataTable', container => { }); container.editCell = (row, field, cellNode) => { - const overlay = container.querySelector('.dt-editor-overlay'), rect = cellNode.getBoundingClientRect(), rootRect = container.getBoundingClientRect(); + const main = container.querySelector('.dt-main'); + const overlay = container.querySelector('.dt-editor-overlay'), rect = cellNode.getBoundingClientRect(), mainRect = main.getBoundingClientRect(); currentEditingNode = cellNode; const formType = field.settings?.formType || field.type || 'text'; const form = overlay.querySelector('AutoForm'); if (form) { - form.data = row; + form.data = globalThis.NewState(globalThis.Util.clone(row)); form.state.schema = [{ ...field, type: formType, options: field.settings?.options || field.options, name: field.id, label: '' }]; } const isComplex = ['textarea', 'TagsInput', 'checkbox', 'radio'].includes(formType); + let topPos = rect.top - mainRect.top + main.scrollTop - 1; + let leftPos = rect.left - mainRect.left + main.scrollLeft - 1; + let editorWidth = Math.max(rect.width + 2, isComplex ? 300 : 0); + + const maxLeft = main.scrollWidth - editorWidth - 5; + if (leftPos > maxLeft) leftPos = Math.max(0, maxLeft); + Object.assign(overlay.style, { display: 'flex', - left: (rect.left - rootRect.left - 1) + 'px', - top: (rect.top - rootRect.top - 1) + 'px', - width: Math.max(rect.width + 2, isComplex ? 300 : 0) + 'px', + left: leftPos + 'px', + top: topPos + 'px', + width: editorWidth + 'px', height: 'auto', minHeight: (rect.height + 2) + 'px', + maxHeight: Math.max(100, mainRect.height - (rect.top - mainRect.top) - 5) + 'px', + overflow: 'auto', padding: '0' }); setTimeout(() => overlay.querySelector('input, textarea, select, .form-control')?.focus(), 30); @@ -456,19 +470,30 @@ globalThis.Component.register('DataTable', container => { const input = _editorOverlay.querySelector('input:focus, select:focus, textarea:focus'); if (input) input.dispatchEvent(new Event(input.type === 'number' || input.tagName === 'SELECT' ? 'change' : 'input', { bubbles: true })); + let hasChanges = false; const schema = form.state.schema || []; schema.forEach(field => { const row = currentEditingNode?.closest('.dt-row')?._ref?.item; - if (row) row[field.name] = form.data[field.name]; + if (row && JSON.stringify(row[field.name]) !== JSON.stringify(form.data[field.name])) { + row[field.name] = form.data[field.name]; + hasChanges = true; + } }); if (state.isBulkEdit) { const { minRow, maxRow, fIdx } = state.isBulkEdit; const field = state.fields[fIdx]; const newValue = form.data[field.id]; - for (let i = minRow; i <= maxRow; i++) { if (state.list[i]) state.list[i][field.id] = newValue; } + for (let i = minRow; i <= maxRow; i++) { + if (state.list[i] && state.list[i][field.id] !== newValue) { + state.list[i][field.id] = newValue; + hasChanges = true; + } + } + } + if (hasChanges) { + state.list = [...state.list]; + state.isDirty = true; } - state.list = [...state.list]; - state.isDirty = true; } _editorOverlay.style.display = 'none'; if (form) { form.state.schema = []; form.data = null; } @@ -629,7 +654,7 @@ globalThis.Component.register('DataTable', container => { state._MODE_ICONS = MODE_ICONS; }, globalThis.Util.makeDom(/*html*/` -
+
@@ -657,6 +682,7 @@ globalThis.Component.register('DataTable', container => {
+
-
- -
- @@ -696,16 +726,14 @@ globalThis.Component.register('DataTable', container => { Clear Filter
-
- - - +
+ + +
- -
@@ -716,9 +744,9 @@ globalThis.Component.register('DataTable', container => { @@ -750,9 +778,11 @@ globalThis.Component.register('DataTable', container => { .dt-filter-tabs div:hover i { color: var(--bs-primary); } .menu-item-row .only-btn { opacity: 0; } .menu-item-row:hover .only-btn { opacity: 1; } - .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; } + .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; height: 100%; } .dt-editor-overlay [control-wrapper] { width: 100%; margin: 0 !important; min-height: 100% !important; align-items: stretch !important; } - .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0.375rem 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .form-switch { padding-left: 2.5rem !important; } + .dt-editor-overlay [control-wrapper] > textarea { min-height: 100px; resize: vertical; } `)) diff --git a/test/lib/datatable.js b/test/lib/datatable.js index 4583e67..f6a91ab 100644 --- a/test/lib/datatable.js +++ b/test/lib/datatable.js @@ -276,14 +276,14 @@ }; const getSelectionBounds = () => { if (!activeBounds) return null; - let minRow = activeBounds.minRow, maxRow = activeBounds.maxRow, minCol = activeBounds.minCol, maxCol = activeBounds.maxCol; + let minRow2 = activeBounds.minRow, maxRow = activeBounds.maxRow, minCol2 = activeBounds.minCol, maxCol = activeBounds.maxCol; multiSelections.forEach((s) => { - minRow = Math.min(minRow, s.minRow); + minRow2 = Math.min(minRow2, s.minRow); maxRow = Math.max(maxRow, s.maxRow); - minCol = Math.min(minCol, s.minCol); + minCol2 = Math.min(minCol2, s.minCol); maxCol = Math.max(maxCol, s.maxCol); }); - return { minRow, maxRow, minCol, maxCol }; + return { minRow: minRow2, maxRow, minCol: minCol2, maxCol }; }; const copy = async () => { const bounds = getSelectionBounds(); @@ -321,7 +321,11 @@ cells.push(current); return cells; }); - const { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + let { minRow: startRow, minCol: startCol, maxRow, maxCol } = bounds; + if (minRow === maxRow && minCol === maxCol) { + maxRow = Infinity; + maxCol = Infinity; + } const body = container.querySelector(".dt-body"); const rowNodes = body ? Array.from(body.childNodes).filter((n) => { var _a; @@ -615,22 +619,30 @@ }); container.editCell = (row, field, cellNode) => { var _a, _b; - const overlay = container.querySelector(".dt-editor-overlay"), rect = cellNode.getBoundingClientRect(), rootRect = container.getBoundingClientRect(); + const main = container.querySelector(".dt-main"); + const overlay = container.querySelector(".dt-editor-overlay"), rect = cellNode.getBoundingClientRect(), mainRect = main.getBoundingClientRect(); currentEditingNode = cellNode; const formType = ((_a = field.settings) == null ? void 0 : _a.formType) || field.type || "text"; const form = overlay.querySelector("AutoForm"); if (form) { - form.data = row; + form.data = globalThis.NewState(globalThis.Util.clone(row)); form.state.schema = [{ ...field, type: formType, options: ((_b = field.settings) == null ? void 0 : _b.options) || field.options, name: field.id, label: "" }]; } const isComplex = ["textarea", "TagsInput", "checkbox", "radio"].includes(formType); + let topPos = rect.top - mainRect.top + main.scrollTop - 1; + let leftPos = rect.left - mainRect.left + main.scrollLeft - 1; + let editorWidth = Math.max(rect.width + 2, isComplex ? 300 : 0); + const maxLeft = main.scrollWidth - editorWidth - 5; + if (leftPos > maxLeft) leftPos = Math.max(0, maxLeft); Object.assign(overlay.style, { display: "flex", - left: rect.left - rootRect.left - 1 + "px", - top: rect.top - rootRect.top - 1 + "px", - width: Math.max(rect.width + 2, isComplex ? 300 : 0) + "px", + left: leftPos + "px", + top: topPos + "px", + width: editorWidth + "px", height: "auto", minHeight: rect.height + 2 + "px", + maxHeight: Math.max(100, mainRect.height - (rect.top - mainRect.top) - 5) + "px", + overflow: "auto", padding: "0" }); setTimeout(() => { @@ -645,22 +657,31 @@ if (save && form && form.data) { const input = _editorOverlay.querySelector("input:focus, select:focus, textarea:focus"); if (input) input.dispatchEvent(new Event(input.type === "number" || input.tagName === "SELECT" ? "change" : "input", { bubbles: true })); + let hasChanges = false; const schema = form.state.schema || []; schema.forEach((field) => { var _a, _b; const row = (_b = (_a = currentEditingNode == null ? void 0 : currentEditingNode.closest(".dt-row")) == null ? void 0 : _a._ref) == null ? void 0 : _b.item; - if (row) row[field.name] = form.data[field.name]; + if (row && JSON.stringify(row[field.name]) !== JSON.stringify(form.data[field.name])) { + row[field.name] = form.data[field.name]; + hasChanges = true; + } }); if (state.isBulkEdit) { - const { minRow, maxRow, fIdx } = state.isBulkEdit; + const { minRow: minRow2, maxRow, fIdx } = state.isBulkEdit; const field = state.fields[fIdx]; const newValue = form.data[field.id]; - for (let i = minRow; i <= maxRow; i++) { - if (state.list[i]) state.list[i][field.id] = newValue; + for (let i = minRow2; i <= maxRow; i++) { + if (state.list[i] && state.list[i][field.id] !== newValue) { + state.list[i][field.id] = newValue; + hasChanges = true; + } } } - state.list = [...state.list]; - state.isDirty = true; + if (hasChanges) { + state.list = [...state.list]; + state.isDirty = true; + } } _editorOverlay.style.display = "none"; if (form) { @@ -851,7 +872,7 @@ }, globalThis.Util.makeDom( /*html*/ ` -
+
@@ -879,6 +900,7 @@
+
-
- -
- @@ -918,16 +944,14 @@ Clear Filter
-
- - - +
+ + +
- -
@@ -938,9 +962,9 @@ @@ -975,9 +999,11 @@ .dt-filter-tabs div:hover i { color: var(--bs-primary); } .menu-item-row .only-btn { opacity: 0; } .menu-item-row:hover .only-btn { opacity: 1; } - .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; } + .dt-editor-overlay .auto-form-root form { gap: 0 !important; margin: 0 !important; height: 100%; } .dt-editor-overlay [control-wrapper] { width: 100%; margin: 0 !important; min-height: 100% !important; align-items: stretch !important; } - .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .d-flex { padding: 0.375rem 0.5rem; justify-content: flex-start !important; align-items: center !important; } + .dt-editor-overlay [control-wrapper] > .form-switch { padding-left: 2.5rem !important; } + .dt-editor-overlay [control-wrapper] > textarea { min-height: 100px; resize: vertical; } ` )); diff --git a/test/lib/datatable.min.js b/test/lib/datatable.min.js index 2c0604a..d399d97 100644 --- a/test/lib/datatable.min.js +++ b/test/lib/datatable.min.js @@ -1 +1 @@ -!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||la?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{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)&&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:""}]);const m=["textarea","TagsInput","checkbox","radio"].includes(d);Object.assign(o.style,{display:"flex",left:a.left-r.left-1+"px",top:a.top-r.top-1+"px",width:Math.max(a.width+2,m?300:0)+"px",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()}),n.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&"c"===e.key.toLowerCase()&&(e.preventDefault(),o.copy()),(e.ctrlKey||e.metaKey)&&"v"===e.key.toLowerCase()&&(e.preventDefault(),o.paste())}),l._MODE_ICONS=t},globalThis.Util.makeDom('\n
\n
\n
\n
\n \n
\n
\n
\n \n \n \n
\n
\n\n \n\n \n\n \n
\n
\n \n \n
\n
\n\n \n
\n'),globalThis.Util.makeDom("\n\n")),globalThis.DataTable=i}); +!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||la?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{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)&&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-main"),a=n.querySelector(".dt-editor-overlay"),r=i.getBoundingClientRect(),d=o.getBoundingClientRect();c=i;const u=(null==(l=t.settings)?void 0:l.formType)||t.type||"text",m=a.querySelector("AutoForm");m&&(m.data=globalThis.NewState(globalThis.Util.clone(e)),m.state.schema=[{...t,type:u,options:(null==(s=t.settings)?void 0:s.options)||t.options,name:t.id,label:""}]);const p=["textarea","TagsInput","checkbox","radio"].includes(u);let f=r.top-d.top+o.scrollTop-1,h=r.left-d.left+o.scrollLeft-1,b=Math.max(r.width+2,p?300:0);const g=o.scrollWidth-b-5;h>g&&(h=Math.max(0,g)),Object.assign(a.style,{display:"flex",left:h+"px",top:f+"px",width:b+"px",height:"auto",minHeight:r.height+2+"px",maxHeight:Math.max(100,d.height-(r.top-d.top)-5)+"px",overflow:"auto",padding:"0"}),setTimeout(()=>{var e;return null==(e=a.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}));let i=!1;if((t.state.schema||[]).forEach(e=>{var n,l;const s=null==(l=null==(n=null==c?void 0:c.closest(".dt-row"))?void 0:n._ref)?void 0:l.item;s&&JSON.stringify(s[e.name])!==JSON.stringify(t.data[e.name])&&(s[e.name]=t.data[e.name],i=!0)}),l.isBulkEdit){const{minRow:e,maxRow:n,fIdx:s}=l.isBulkEdit,o=l.fields[s],a=t.data[o.id];for(let t=e;t<=n;t++)l.list[t]&&l.list[t][o.id]!==a&&(l.list[t][o.id]=a,i=!0)}i&&(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()}),n.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&"c"===e.key.toLowerCase()&&(e.preventDefault(),o.copy()),(e.ctrlKey||e.metaKey)&&"v"===e.key.toLowerCase()&&(e.preventDefault(),o.paste())}),l._MODE_ICONS=t},globalThis.Util.makeDom('\n
\n
\n
\n
\n \n
\n
\n
\n \n \n \n
\n \n
\n\n \n\n \n
\n
\n \n \n
\n
\n\n \n
\n'),globalThis.Util.makeDom("\n\n")),globalThis.DataTable=i}); diff --git a/test/lib/state.js b/test/lib/state.js index e161a0d..21a304b 100644 --- a/test/lib/state.js +++ b/test/lib/state.js @@ -4,7 +4,7 @@ "use strict"; var _a, _b; const Util = { - clone: globalThis.structuredClone || ((obj) => JSON.parse(JSON.stringify(obj))), + clone: globalThis.structuredClone ? (obj) => globalThis.structuredClone(obj) : (obj) => JSON.parse(JSON.stringify(obj)), base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))), unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))), urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),