dataTable/dist/datatable.min.js

2 lines
9.4 KiB
JavaScript

import{Component as t,NewState as e,Util as i,RefreshState as n}from"@web/state";import{VirtualScroll as s}from"@web/base";t.register("DataTable",t=>{const i=s();t.state||(t.state=e({}));const n=t.state;Object.assign(n,{list:[],fields:[],renderedList:[],prevHeight:0,postHeight:0,_listStartIndex:0,selStartR:-1,selStartF:-1,selEndR:-1,selEndF:-1,multiSelections:[],isSelecting:!1});const d=()=>{const s=t.querySelector(".dt-body");if(!s)return;const d=i.calc(s,n.list);d&&(d.renderedList.forEach((t,i)=>{if(t&&!t.__watch){const s=e(t);d.renderedList[i]=s,n.list[d.listStartIndex+i]=s}}),Object.assign(n,{prevHeight:d.prevHeight,postHeight:d.postHeight,_listStartIndex:d.listStartIndex,renderedList:d.renderedList}))};t.refresh=d,n.__watch("fields",t=>{if(!t)return;const e=[],i=[];let s=0;t.forEach((t,i)=>{"left"===t.pinned&&(e[i]=s,s+=t.width||150)}),t.forEach((e,n)=>{if("right"===e.pinned){let e=0;for(let i=n+1;i<t.length;i++)"right"===t[i].pinned&&(e+=t[i].width||150);i[n]=e}}),n._leftOffsets=e,n._rightOffsets=i}),n.__watch("list",e=>{n._listStartIndex=0;const s=t.querySelector(".dt-body");n.renderedList=i.reset(e,s||{clientHeight:800})||[],s&&(i.init(e,d),requestAnimationFrame(d))}),t.onItemUpdate=(t,e)=>i.update(t+n._listStartIndex,e),t.getOffset=(t,e)=>(n._leftOffsets||[])[t]||(n._rightOffsets||[])[t]||0,t.isCellSelected=(t,e)=>{const i=Math.min(n.selStartR,n.selEndR),s=Math.max(n.selStartR,n.selEndR),d=Math.min(n.selStartF,n.selEndF),r=Math.max(n.selStartF,n.selEndF);return t>=i&&t<=s&&e>=d&&e<=r||n.multiSelections.some(i=>t>=i.r1&&t<=i.r2&&e>=i.f1&&e<=i.f2)},t.clearAllActive=(t=!1)=>{n.list.forEach(t=>{t&&t.__watch&&(null!==t._editingF&&(t._editingF=null),null!==t._activeF&&(t._activeF=null))}),t||(n.selStartR=-1,n.multiSelections=[])},t.startSelect=(e,i,s)=>{const d=t.isCellSelected(e,i);n.editingCell&&(n.editingCell=null),s.shiftKey&&-1!==n.selStartR?(n.selEndR=e,n.selEndF=i):(d||(s.ctrlKey||s.metaKey?-1!==n.selStartR&&n.multiSelections.push({r1:Math.min(n.selStartR,n.selEndR),r2:Math.max(n.selStartR,n.selEndR),f1:Math.min(n.selStartF,n.selEndF),f2:Math.max(n.selStartF,n.selEndF)}):t.clearAllActive(),n.selStartR=n.selEndR=e,n.selStartF=n.selEndF=i),n.isSelecting=!0,n.list[e]&&n.list[e].__watch&&(n.list[e]._activeF=i))},t.updateSelect=(t,e)=>n.isSelecting&&(n.selEndR=t,n.selEndF=e),t.endSelect=()=>n.isSelecting=!1,t.editCell=(i,s,d)=>{var r;const l=Math.min(n.selStartR,n.selEndR),a=Math.max(n.selStartR,n.selEndR),o=Math.min(n.selStartF,n.selEndF),c=Math.max(n.selStartF,n.selEndF),h=n.list.indexOf(i),f=-1!==n.selStartR&&h>=l&&h<=a&&d>=o&&d<=c?a-l+1:0;if(f>1&&(null==(r=globalThis.UI)?void 0:r.toast)&&UI.toast(`{#Bulk Editing {num} rows... || ${f}#}`),t.clearAllActive(!0),i._editingF=s.id,i._activeF=d,f>1){const t=i.__watch(s.id,d=>{for(let t=l;t<=a;t++){const r=n.list[t];if(r!==i){const i=r.__watch?r:e(r);n.list[t]=i,i[s.id]=d}}t()})}};t.copy=async()=>{const t=Math.min(n.selStartR,n.selEndR),e=Math.max(n.selStartR,n.selEndR),i=Math.min(n.selStartF,n.selEndF),s=Math.max(n.selStartF,n.selEndF);if(-1===t)return;const d=n.list.slice(t,e+1).map(t=>n.fields.slice(i,s+1).map(e=>(t=>{const e=String(t??"");return e.includes("\t")||e.includes("\n")||e.includes('"')?'"'+e.replace(/"/g,'""')+'"':e})(t[e.id])).join("\t")).join("\n");await navigator.clipboard.writeText(d)},t.paste=async()=>{const t=(t=>{const e=[];let i=[],n="",s=!1;for(let d=0;d<t.length;d++){const r=t[d],l=t[d+1];s?'"'===r&&'"'===l?(n+='"',d++):'"'===r?s=!1:n+=r:'"'===r?s=!0:"\t"===r?(i.push(n),n=""):"\n"===r?(i.push(n),e.push(i),i=[],n=""):"\r"!==r&&(n+=r)}return i.push(n),e.push(i),e})(await navigator.clipboard.readText()),i=Math.min(n.selStartR,n.selEndR),s=Math.min(n.selStartF,n.selEndF);-1!==i&&t.forEach((t,d)=>{let r=n.list[i+d];r&&(r.__watch||(r=e(r),n.list[i+d]=r),t.forEach((t,e)=>{const i=n.fields[s+e];i&&("boolean"==typeof r[i.id]?r[i.id]="true"===t.toLowerCase():"number"==typeof r[i.id]?r[i.id]=Number(t):r[i.id]=t)}))})},t.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&("c"===e.key&&(e.preventDefault(),t.copy()),"v"===e.key&&(e.preventDefault(),t.paste()))});const r=e=>!t.contains(e.target)&&t.clearAllActive();document.addEventListener("mousedown",r),window.addEventListener("mouseup",t.endSelect),t._onUnload=()=>{document.removeEventListener("mousedown",r),window.removeEventListener("mouseup",t.endSelect)}},i.makeDom("\n<div class=\"dt-root d-flex flex-column h-100 border bg-body text-body overflow-hidden\" style=\"position:relative; user-select:none\" tabindex=\"0\" onunload=\"this._onUnload()\">\n\t<div class=\"dt-header d-flex flex-shrink-0 border-bottom bg-body-tertiary fw-bold text-muted small\" style=\"overflow:hidden; position:sticky; top:0; z-index:20; height:48px\">\n\t\t<div $each=\"this.state.fields\" as=\"f\" class=\"dt-col border-end d-flex align-items-center px-2 bg-body-tertiary\"\n\t\t\t$style=\"'width: var(--w-' + f.id + ', ' + (f.width || 150) + 'px); min-width: var(--w-' + f.id + ', ' + (f.width || 150) + 'px); ' + (f.pinned ? 'position:sticky; z-index:11;' : '') + (f.pinned === 'left' ? 'left:' + this.getOffset(index, 'left') + 'px;' : '') + (f.pinned === 'right' ? 'right:' + this.getOffset(index, 'right') + 'px;' : '')\">\n\t\t\t<span $text=\"f.name\" $class=\"'text-truncate flex-grow-1 ' + (f.type === 'number' ? 'text-end' : '')\"></span>\n\t\t\t<Resizer class=\"dt-resizer\" $.target=\"thisNode.parentNode\" min=\"50\" max=\"600\" $bind=\"f.width\" $onresizing=\"thisNode.closest('.dt-root').style.setProperty('--w-' + f.id, event.detail.newSize + 'px')\"/>\n\t\t</div>\n\t</div>\n\t<div class=\"dt-body flex-grow-1 overflow-auto bg-body\" $onscroll=\"requestAnimationFrame(() => this.refresh())\" style=\"overflow-anchor:none\">\n\t\t<div $if=\"this.state.prevHeight>0\" $style=\"'height:' + this.state.prevHeight + 'px;'\"></div>\n\t\t<div $each=\"this.state.renderedList\" as=\"row\" class=\"dt-row d-flex border-bottom\" $onupdate=\"this.onItemUpdate(rIdx, thisNode)\" index=\"rIdx\">\n\t\t\t<div $each=\"this.state.fields\" as=\"f\" class=\"dt-cell border-end d-flex align-items-center bg-body\"\n\t\t\t\t$class=\"'dt-cell border-end d-flex align-items-center bg-body' + (this.isCellSelected(rIdx + this.state._listStartIndex, index) ? ' bg-primary-subtle' : '') + (row._activeF === index ? ' dt-cell-active' : '')\"\n\t\t\t\t$style=\"'width: var(--w-' + f.id + ', ' + (f.width || 150) + 'px); min-width: var(--w-' + f.id + ', ' + (f.width || 150) + 'px); height:40px; ' + (f.pinned ? 'position:sticky; z-index:10;' : '') + (f.pinned === 'left' ? 'left:' + this.getOffset(index, 'left') + 'px;' : '') + (f.pinned === 'right' ? 'right:' + this.getOffset(index, 'right') + 'px;' : '')\"\n\t\t\t\t$onmousedown=\"this.startSelect(rIdx + this.state._listStartIndex, index, event)\"\n\t\t\t\t$onmouseenter=\"this.updateSelect(rIdx + this.state._listStartIndex, index)\"\n\t\t\t\t$ondblclick=\"this.editCell(row, f, index)\">\n\t\t\t\t\n\t\t\t\t<div $if=\"row._editingF !== f.id\" $class=\"'px-2 text-truncate w-100 h-100 d-flex align-items-center ' + (f.type === 'number' ? 'justify-content-end' : (f.type === 'switch' ? 'justify-content-center' : ''))\">\n\t\t\t\t\t<span $if=\"typeof row[f.id] !== 'boolean'\" $text=\"row[f.id] ?? ''\" class=\"text-truncate\"></span>\n\t\t\t\t\t<div $if=\"typeof row[f.id] === 'boolean'\" class=\"form-switch fs-5 m-0 d-flex align-items-center justify-content-center\" style=\"padding-left:0\">\n\t\t\t\t\t\t<input class=\"form-check-input m-0\" type=\"checkbox\" $checked=\"row[f.id]\" disabled>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div $if=\"row._editingF === f.id\" $class=\"'dt-editor-container' + (f.type === 'textarea' ? ' dt-editor-textarea' : '')\" $onclick=\"event.stopPropagation()\" $onmousedown=\"event.stopPropagation()\">\n\t\t\t\t\t<AutoForm inline class=\"dt-editor h-100 w-100\" $.state.schema=\"[{ ...f, name: f.id, label: f.name }]\" $.data=\"row\" \n\t\t\t\t\t\t$onkeydown=\"(event.key === 'Enter' && f.type !== 'textarea') && (row._editingF = null); event.key === 'Escape' && (row._editingF = null)\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<div $if=\"this.state.postHeight>0\" $style=\"'height:' + this.state.postHeight + 'px;'\"></div>\n\t</div>\n\t<style>\n\t\t.dt-root { font-size: 0.875rem; --dt-active-border: var(--bs-primary); outline: none; }\n\t\t.dt-row:hover .dt-cell { background-color: var(--bs-secondary-bg) !important; }\n\t\t.dt-cell { position: relative; transition: background 0.05s; border-color: var(--bs-border-color) !important; }\n\t\t.dt-cell.bg-primary-subtle { background-color: var(--bs-primary-bg-subtle) !important; }\n\t\t.dt-cell-active::after { content: ''; position: absolute; inset: 0; border: 2px solid var(--dt-active-border); pointer-events: none; z-index: 12; }\n\t\t.dt-col { position: relative; }\n\t\t.dt-editor-container { position: absolute; left: -1px; top: -1px; width: fit-content; min-width: calc(100% + 2px); height: auto; min-height: calc(100% + 2px); background: var(--bs-body-bg); z-index: 100; box-shadow: 0 4px 12px rgba(0,0,0,.3); border: 1px solid var(--dt-active-border); display: flex; align-items: center; }\n\t\t.dt-editor-textarea { height: auto; min-height: 100%; min-width: 260px; align-items: flex-start; }\n\t\t.dt-resizer { width: 4px !important; opacity: 0; transition: opacity 0.2s; position: absolute; right: 0; top: 0; height: 100%; background: var(--bs-primary); cursor: col-resize; z-index: 15; }\n\t\t.dt-col:hover .dt-resizer { opacity: 0.5; }\n\t\t.dt-resizer:hover { opacity: 1 !important; }\n\t</style>\n</div>\n")),"undefined"!=typeof document&&n(document.documentElement);