@evotecit/canopyx 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CanopyX.Html/Assets/canopyx-export.js +8 -4
- package/CanopyX.Html/Assets/canopyx-facets.js +6 -6
- package/CanopyX.Html/Assets/canopyx-filter-editor.js +10 -8
- package/CanopyX.Html/Assets/canopyx-grid-module.mjs +48 -34
- package/CanopyX.Html/Assets/canopyx-grid.js +48 -34
- package/CanopyX.Html/Assets/canopyx-grouping.js +2 -2
- package/CanopyX.Html/Assets/canopyx-interactive.js +27 -12
- package/CanopyX.Html/Assets/canopyx-layouts.css +1 -1
- package/CanopyX.Html/Assets/canopyx-layouts.js +3 -3
- package/CanopyX.Html/Assets/canopyx-module.mjs +27 -12
- package/CanopyX.Html/Assets/canopyx-presenters.js +11 -0
- package/CanopyX.Html/Assets/canopyx-record-panel.js +12 -10
- package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +52 -38
- package/CanopyX.Html/Assets/canopyx-reporting.js +52 -38
- package/CanopyX.Html/Assets/canopyx-tree-tools.css +1 -0
- package/CanopyX.Html/Assets/canopyx-tree-tools.js +3 -2
- package/CanopyX.Html/Assets/canopyx.js +27 -12
- package/JavaScript/grid.d.ts +3 -1
- package/JavaScript/hosts.d.ts +11 -0
- package/JavaScript/protocol.d.ts +13 -0
- package/JavaScript/records.d.ts +2 -0
- package/README.md +2 -2
- package/package.json +3 -1
|
@@ -44,9 +44,10 @@ if(typeof value==="boolean"){return value?fmt.labels.yes:fmt.labels.no}
|
|
|
44
44
|
if(typeof value==="number"&&kind==="number"){return numberText(value,fmt.lang,format)}
|
|
45
45
|
if(typeof value==="string"&&kind==="datetime"){return formatDate(value,fmt)}
|
|
46
46
|
return String(value)}
|
|
47
|
-
function cellText(cell,column,fmt){if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
|
|
47
|
+
function cellText(cell,column,fmt){const raw=cellValue(cell);if(typeof raw==="string"&&Object.hasOwn(column.valueLabels||{},raw))return column.valueLabels[raw];if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
|
|
48
48
|
return formatValue(cellValue(cell),column.kind,fmt,column.format)}
|
|
49
|
-
const collator=new Intl.Collator(undefined,{numeric:true,sensitivity:"base"});const safeGridNumber=value=>Number.isFinite(value)&&Math.abs(value)<=Number.MAX_SAFE_INTEGER;function sortKey(cell,column){
|
|
49
|
+
const collator=new Intl.Collator(undefined,{numeric:true,sensitivity:"base"});const safeGridNumber=value=>Number.isFinite(value)&&Math.abs(value)<=Number.MAX_SAFE_INTEGER;function sortKey(cell,column){if(column.valueOrder?.length){const raw=cellValue(cell);if(raw==null)return{rank:2,value:0};const at=typeof raw==="string"?column.valueOrder.indexOf(raw):-1;return{rank:1,category:at<0?column.valueOrder.length:at,type:typeof raw,value:raw}}
|
|
50
|
+
let value=isCellObject(cell)&&(typeof cell.sort==="string"||safeGridNumber(cell.sort))?cell.sort:cellValue(cell);if((value===null||value==="")&&isCellObject(cell)&&typeof cell.text==="string"&&cell.text!==""){value=cell.text}
|
|
50
51
|
if(value===null||value===""){return{rank:2,value:0}}
|
|
51
52
|
if(typeof value==="boolean"){return{rank:0,value:value?1:0}}
|
|
52
53
|
if(typeof value==="number"){return{rank:0,value}}
|
|
@@ -54,7 +55,20 @@ if(column.kind==="datetime"){const time=Date.parse(value);if(!isNaN(time)){retur
|
|
|
54
55
|
return{rank:1,value:String(value)}}
|
|
55
56
|
function compareKeys(a,b,direction){if(a.rank!==b.rank){return a.rank-b.rank}
|
|
56
57
|
if(a.rank===2){return 0}
|
|
57
|
-
const order=a.
|
|
58
|
+
const order=a.category!==undefined?a.category-b.category||
|
|
59
|
+
(a.type<b.type?-1:a.type>b.type?1:a.value<b.value?-1:a.value>b.value?1:0):
|
|
60
|
+
a.rank===0?(a.value<b.value?-1:a.value>b.value?1:0):collator.compare(a.value,b.value);return order*direction}
|
|
61
|
+
function columnNumericTone(column,raw){return typeof raw==="number"&&Number.isFinite(raw)?column.numericTones?.find(rule=>
|
|
62
|
+
rule.operator==="atMost"?raw<=rule.value:rule.operator==="atLeast"?raw>=rule.value:
|
|
63
|
+
rule.operator==="below"?raw<rule.value:raw>rule.value):undefined}
|
|
64
|
+
function columnValueTone(column,cell){const raw=cellValue(cell);return columnNumericTone(column,raw)?.tone||(typeof raw==="string"&&Object.hasOwn(column.valueTones||{},raw)?column.valueTones[raw]:undefined)}
|
|
65
|
+
function validateColumnValues(column){const fail=()=>{throw new Error("CanopyX: invalid column value labels, order, tones or line limit.")};const tone=value=>typeof value==="string"&&/^[a-z][a-z0-9-]{0,31}$/.test(value) && !value.endsWith("-bg");
|
|
66
|
+
if(column.maxLines!==undefined&&(!Number.isInteger(column.maxLines)||column.maxLines<1||column.maxLines>12))fail();for(const name of["valueLabels","valueTones"])if(column[name]!==undefined){const map=column[name];if(column.kind!=="text"||!map||typeof map!=="object"||Array.isArray(map)||Object.keys(map).length>512||
|
|
67
|
+
Object.entries(map).some(([key,value])=>key.length>4096||(name==="valueTones"?!tone(value):typeof value!=="string"||value.length>4096)))fail()}
|
|
68
|
+
if(column.valueOrder!==undefined&&(column.kind!=="text"||!Array.isArray(column.valueOrder)||column.valueOrder.length>512||
|
|
69
|
+
new Set(column.valueOrder).size!==column.valueOrder.length||column.valueOrder.some(value=>typeof value!=="string"||value.length>4096)))fail();if(column.numericTones!==undefined&&(column.kind!=="number"||!Array.isArray(column.numericTones)||column.numericTones.length>32||
|
|
70
|
+
column.numericTones.some(rule=>!rule||!["atMost","atLeast","below","above"].includes(rule.operator)||!Number.isFinite(rule.value)||
|
|
71
|
+
!tone(rule.tone)||typeof rule.label!=="string"||!rule.label.trim()||rule.label.length>4096)))fail()}
|
|
58
72
|
function fill(template,values){return template.replace(/\{(\w+)\}/g, (match, name) => (values && Object.hasOwn(values, name) ? String(values[name]) : match));
|
|
59
73
|
}
|
|
60
74
|
const pluralRules=new Map();function plural(template,count,lang){if(!template.startsWith("["))return template;const forms={};for(const match of template.matchAll(/\[(zero|one|two|few|many|other)\]([^[]*)/g)) forms[match[1]] = match[2];
|
|
@@ -117,7 +131,8 @@ if(column.kind==="datetime"){const date=typeof value==="string"&&/^\d{4}-\d\d-\d
|
|
|
117
131
|
if(!Number.isFinite(date))
|
|
118
132
|
throw new Error("CanopyX: date grid cells need ISO dates with an explicit time zone.");return date}
|
|
119
133
|
if(typeof value!=="string"&&typeof value!=="boolean")throw new Error("CanopyX: text grid cells need strings or booleans.");return value}
|
|
120
|
-
function
|
|
134
|
+
function gridExactTokens(column){return column.kind==="text"&&(column.valueOrder?.length||Object.keys(column.valueLabels||{}).length)}
|
|
135
|
+
function cellMatches(cell,predicate,column){const scalar=gridScalar(cell,column),op=predicate.operator;if(op==="isNull")return scalar===null;if(op==="isNotNull")return scalar!==null;if(scalar===null)return false;const normalize=value=>column.kind==="text"&&!gridExactTokens(column)&&typeof value==="string"?foldText(value):value;const value=normalize(scalar),values=predicate.values.map(operand=>normalize(gridScalar(operand,column))),operand=values[0];switch(op){case "eq":return value===operand;case "ne":return value!==operand;case "in":return values.includes(value);case "contains":return String(value).includes(String(operand));case "startsWith":return String(value).startsWith(String(operand));case "gt":return value>operand;case "ge":return value>=operand;case "lt":return value<operand;case "le":return value<=operand}
|
|
121
136
|
return false}
|
|
122
137
|
function validateGridRows(rows,columns,ids=new Set()){if(!Array.isArray(rows))throw new Error("CanopyX: grid rows must be an array.");const declared=new Map(columns.map(column=>[column.id,column]));for(const row of rows){requireIdentifier(row&&row.id,"grid row ID");if(ids.has(row.id))throw new Error("CanopyX: duplicate grid row ID "+row.id);ids.add(row.id);if(!row.cells||typeof row.cells!=="object"||Array.isArray(row.cells))
|
|
123
138
|
throw new Error("CanopyX: invalid flat row fields.");gridDecoration(row.tone,row.className);for(const id of Object.keys(row.cells)){if(!declared.has(id))throw new Error("CanopyX: undeclared grid column "+id);const cell=row.cells[id];if(isCellObject(cell)){if(Array.isArray(cell)||
|
|
@@ -191,7 +206,7 @@ return checkDocument(await response.json(),type)}catch(error){if(timedOut)throw
|
|
|
191
206
|
class TreeGrid{constructor(host,options){const view=checkDocument(options.view,"view");requireIdentifier(view.id,"view ID");if(view.columns.some(column=>column.format!==undefined))throw new Error("CanopyX: number formats apply to flat grids only.");this.host=host;this.view=view;this.opts=options;for(const name of["isSelectable","beforeSelect","sanitizeHtml"]){if(options[name]!==undefined&&typeof options[name]!=="function")throw new Error("CanopyX: "+name+" must be a function.")}
|
|
192
207
|
this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.source=options.source||sourceFor(view,{signal:this.lifetime.signal,timeoutMs:options.requestTimeoutMs});this.queryAware=this.source.queryAware===true;this.dataLifetime=new AbortController();this.acceptedQuery=Object.freeze({version:1,sort:null,filters:Object.freeze([])});this.datasetRevision=null;this.rowH=view.rowHeight||28;this.pageSize=view.pageSize||100;this.retainedNodeLimit=options.retainedNodeLimit===undefined?1024:options.retainedNodeLimit;if(!validStructuralCount(this.retainedNodeLimit))throw new Error("CanopyX: retainedNodeLimit must be a nonnegative 32-bit integer.");this.inactiveNodeLimit=options.inactiveNodeLimit===undefined?4096:options.inactiveNodeLimit;if(!validStructuralCount(this.inactiveNodeLimit))throw new Error("CanopyX: inactiveNodeLimit must be a nonnegative 32-bit integer.");this.multi=view.selection==="multiple";this.lang=document.documentElement.lang||undefined;this.labels=labelsFor(view.labels,options.labels);this.tools=Object.assign({},view.toolbar,options.toolbar);if(Object.entries(this.tools).some(([name,value])=>!/^(search|filters|columns|views|export|more|matches|layout)$/.test(name) || typeof value !== "boolean"))
|
|
193
208
|
throw new Error("CanopyX: toolbar options are booleans by control name.");this.local=view.timeZone==="local";this.fmt=formatting(this.lang,this.local,this.labels);this.kind="tree";this.plugins=viewPlugins(options,this.kind);const renderers=hostRenderers(options.renderers||{},view.columns,this.plugins);if(!options.formatLink!==!options.parseLink){throw new Error("CanopyX: formatLink and parseLink define one link scheme and are given together.")}
|
|
194
|
-
this.columns=view.columns.map((column,index)=>({...column,hidden:index>0&&!!column.hidden,render:Object.hasOwn(renderers,column.id)?renderers[column.id]:null}));this.columns.forEach(prepareWidth);this.keyMap=new Map();this.root={key:null,h:null,parent:null,level:0,idx:0,expanded:true,children:null,total:null,next:null,loading:false,error:null};if(!options.source&&(!view.source||view.source.kind==="inline")){this.root.inlineItems=view.roots||[]}
|
|
209
|
+
this.columns=view.columns.map((column,index)=>({...column,hidden:index>0&&!!column.hidden,render:Object.hasOwn(renderers,column.id)?renderers[column.id]:null}));this.columns.forEach(prepareWidth);this.columns.forEach(validateColumnValues);this.keyMap=new Map();this.root={key:null,h:null,parent:null,level:0,idx:0,expanded:true,children:null,total:null,next:null,loading:false,error:null};if(!options.source&&(!view.source||view.source.kind==="inline")){this.root.inlineItems=view.roots||[]}
|
|
195
210
|
this.rows=[];this.tops=[0];this.total=0;this.version=1;this.rendered=new Map();this.pool=[];this.focused=null;this.selected=new Set();this.anchor=null;this.filter=null;this.declaredFilter=null;this.filterExpand=false;this.activeFilters=new Set();this.sortState=null;this.typeBuf="";this.typeAt=0;this.rafId=0;this.iconTemplates=this.buildIcons(view.icons||{});this.initializing=true;this.prepareViewModes();this.build();this.buildToolbar();if(view.deepLink)loadPart(LINKS).catch(()=>{});this.ready=this.modesReady?Promise.all([this.init(),this.modesReady]).then(([result])=>result):this.init()}
|
|
196
211
|
async search(query,limit){if(this.destroyed)throw new DOMException("Grid was destroyed.","AbortError");const navigation=navigationScope(this,this.dataLifetime.signal);try{const result=await navigation.wait(this.source.search(query,limit,this.sourceRequest(this.dataLifetime.signal)));if(navigation.cancelled())throw new DOMException("Search snapshot was retired.","AbortError");if(this.queryAware)snapshotRevision(result,this.datasetRevision);return validateSearchResult(result)}finally{navigation.dispose()}}
|
|
197
212
|
buildIcons(icons){const templates=new Map();Object.keys(icons).forEach((key)=>{const holder=h("span","cx-icon");holder.setAttribute("aria-hidden","true");hostHtml(holder,icons[key],this.opts.sanitizeHtml,"icon");// trusted host SVG, declared once per view
|
|
@@ -259,7 +274,7 @@ function snapshotRevision(value,expected){requireIdentifier(value&&value.revisio
|
|
|
259
274
|
Object.assign(TreeGrid.prototype,{getQuery(){return{version:1,sort:this.sortState&&Object.assign({},this.sortState),filters:Array.from(this.activeFilters)}},sourceRequest(signal){return this.queryAware?{signal:signal||this.dataLifetime.signal,query:this.acceptedQuery,revision:this.datasetRevision}:{signal}},syncQueryControls(){this.toolbar.querySelectorAll("[data-cx-filter]").forEach(input=>{input.checked=this.activeFilters.has(input.getAttribute("data-cx-filter"))})},querySortHeader(id){const query=this.pendingQuery||this.acceptedQuery,state=query.sort&&query.sort.column===id?query.sort.direction:null;this.sort(id,state==="asc"?"desc":state==="desc"?null:"asc").catch(()=>{})}});Object.assign(TreeGrid.prototype,{retireWrapper(w){w._invalidated=true;this.retirePage(w);if(this.inlineRetained&&this.inlineRetained.get(w.key)===w)this.inlineRetained.delete(w.key);if(this.inactiveCache)this.inactiveCache.delete(w);if(this.keyMap.get(w.key)===w)this.keyMap.delete(w.key);w.children=null;w.inlineCache=null;w.inlineOrder=null;const selected=this.selected.delete(w);if(this.anchor===w)this.anchor=null;return selected?w:null}});Object.assign(TreeGrid.prototype,{build(){const host=this.host;host.classList.add("cx-host");if(!host.hasAttribute("data-cx-theme")){host.setAttribute("data-cx-theme","auto")}
|
|
260
275
|
host.style.setProperty("--cx-row-h",this.rowH+"px");this.setTreeColumnPinned(this.view.pinTreeColumn);this.toolbar=h("div","cx-toolbar");this.toolbar.hidden=true;const grid=this.grid=h("div","cx-grid");grid.id=this.id;grid.setAttribute("role","treegrid");grid.setAttribute("aria-label",this.view.label);if(this.multi){grid.setAttribute("aria-multiselectable","true")}
|
|
261
276
|
this.head=h("div","cx-head");this.head.setAttribute("role","rowgroup");this.headRow=h("div","cx-hrow");this.headRow.setAttribute("role","row");this.headRow.setAttribute("aria-rowindex","1");this.head.appendChild(this.headRow);this.canvas=h("div","cx-canvas");this.canvas.setAttribute("role","rowgroup");grid.appendChild(this.head);grid.appendChild(this.canvas);this.live=h("div","cx-live cx-sr-only");this.live.setAttribute("aria-live","polite");this.outline=h("div","cx-outline");host.appendChild(this.toolbar);host.appendChild(grid);host.appendChild(this.live);host.appendChild(this.outline);this.buildHeader();this.onScroll=()=>{this.scheduleRender();this.stateChanged()};this.onPrint=()=>{const table=this.outlineElement();this.outline.replaceChildren(...table?[table]:[])};grid.addEventListener("scroll",this.onScroll,{passive:true});grid.addEventListener("click",(e)=>this.onClick(e));grid.addEventListener("dblclick",(e)=>this.onDblClick(e));grid.addEventListener("pointerover",(e)=>this.cellTip(e));grid.addEventListener("keydown",(e)=>this.onKey(e));this.canvas.addEventListener("focusin",(e)=>{const rowEl=e.target.closest(".cx-row");if(rowEl&&rowEl._w&&this.focused!==rowEl._w){this.focusRevision=(this.focusRevision||0)+ 1;this.focused=rowEl._w;this.scheduleRender()}});this.canvas.addEventListener("focusout",(e)=>this.settleCell(e.relatedTarget));global.addEventListener("beforeprint",this.onPrint);this.onHash=(e)=>{const href=global.location.href;const last=this.locationEvent;this.locationEvent=last&&last.href===href&&last.type!==e.type?null:{href,type:e.type};if(this.locationEvent)this.readLocation()};global.addEventListener("hashchange",this.onHash);global.addEventListener("popstate",this.onHash);const viewWidth=()=>{if(grid.clientWidth)host.style.setProperty("--cx-view-w",grid.clientWidth+"px")};viewWidth();this.resizeObserver=new ResizeObserver(()=>{viewWidth();this.scheduleRender()});this.resizeObserver.observe(grid)},visibleColumns(){return this.columns.filter((column)=>!column.hidden)},buildHeader(){const active=document.activeElement;const focusedColumn=active&&this.headRow.contains(active)?active.closest(".cx-hcell").getAttribute("data-cx-column"):null;const focusedResize=active&&active.classList.contains("cx-resize");const nextCols=this.visibleColumns();const layoutChanged=!this.cols||this.cols.length!==nextCols.length||nextCols.some((column,i)=>column!==this.cols[i]);this.cols=nextCols;this.columnIndex=this.cols.map((column)=>this.columns.indexOf(column));if(layoutChanged){this.layout=(this.layout||0)+ 1;this.version++}
|
|
262
|
-
this.grid.setAttribute("aria-colcount",String(this.cols.length));this.headRow.textContent="";this.headCells=this.cols.map((column,i)=>{const cell=h("div","cx-hcell cx-kind-" +(column.kind||"text"));cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",column.title);cell.setAttribute("data-cx-column",column.id);cell.setAttribute("aria-colindex",String(i+1));if(column.sortable){const sorted=this.sortState&&this.sortState.column===column.id?this.sortState.direction:null;cell.setAttribute("aria-sort",sorted==="asc"?"ascending":sorted==="desc"?"descending":"none");const button=h("button","cx-sort");button.type="button";setText(button,column.title);button.addEventListener("click",(event)=>this.queryAware?this.querySortHeader(column.id,event):this.sort(column.id,sorted==="asc"?"desc":sorted==="desc"?null:"asc"));cell.appendChild(button)}else{const title=h("span","cx-htext");setText(title,column.title);cell.appendChild(title)}
|
|
277
|
+
this.grid.setAttribute("aria-colcount",String(this.cols.length));this.headRow.textContent="";this.headCells=this.cols.map((column,i)=>{const cell=h("div","cx-hcell cx-kind-" +(column.kind||"text"));cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",column.title);if(column.headerDescription)cell.setAttribute("aria-description",column.headerDescription);cell.title=column.headerDescription??column.title;cell.setAttribute("data-cx-column",column.id);cell.setAttribute("aria-colindex",String(i+1));if(column.sortable){const sorted=this.sortState&&this.sortState.column===column.id?this.sortState.direction:null;cell.setAttribute("aria-sort",sorted==="asc"?"ascending":sorted==="desc"?"descending":"none");const button=h("button","cx-sort");button.type="button";button.title=column.headerDescription??column.title;setText(button,column.title);button.addEventListener("click",(event)=>this.queryAware?this.querySortHeader(column.id,event):this.sort(column.id,sorted==="asc"?"desc":sorted==="desc"?null:"asc"));cell.appendChild(button)}else{const title=h("span","cx-htext");title.title=column.headerDescription??column.title;setText(title,column.title);cell.appendChild(title)}
|
|
263
278
|
const grip=h("span","cx-resize");grip.setAttribute("aria-label",fill(this.labels.resizeColumn,{column:column.title}));grip.tabIndex=0;grip.setAttribute("role","separator");grip.setAttribute("aria-orientation","vertical");grip.setAttribute("aria-valuemin",column.minW);grip.setAttribute("aria-valuemax",column.maxW);grip.addEventListener("keydown",(e)=>{if(!["ArrowLeft","ArrowRight","Home"].includes(e.key))return;e.preventDefault();e.stopPropagation();column.width=columnWidth(column,e.key==="Home"?40:column.width +(e.key==="ArrowLeft"?-1:1)*(e.shiftKey?50:10));this.applyWidths();this.stateChanged()});grip.addEventListener("pointerdown",(e)=>this.startResize(e,column));cell.appendChild(grip);this.headRow.appendChild(cell);return cell});this.applyWidths();if(focusedColumn){const index=this.cols.findIndex((c)=>c.id===focusedColumn);const button=index>=0?this.headCells[index].querySelector(focusedResize?".cx-resize":".cx-sort"):null;if(button){button.focus()}}},rowCount(){return this.rows.length},rowItem(index){return this.rows[index]},rowTop(index){return this.tops[index]},rowAt(y){const tops=this.tops;let lo=0;let hi=this.rows.length-1;while(lo<hi){const mid=(lo+hi+1)>>1;if(tops[mid]<=y){lo=mid}else{hi=mid-1}}
|
|
264
279
|
return Math.max(0,lo)},indexOf(w){const i=w?w._ri:undefined;return i!==undefined&&this.rows[i]===w?i:-1},render(){let measured=false;for(let pass=0;!this.destroyed;pass++){this.renderPass();if(!this.measureDetails())break;measured=true;if(pass===3){this.scheduleRender();break}}
|
|
265
280
|
return measured}});function columnWidth(column,width){return Math.min(column.maxW,Math.max(column.minW,width))}
|
|
@@ -309,13 +324,13 @@ this.paintSlot(slot,node,this.cols[i],this.columnIndex[i],w)}},paintRowState(row
|
|
|
309
324
|
const expander=this.expandable(w)?"cx-exp":"cx-exp cx-leaf";if(slot.expCls!==expander){slot.exp.className=expander;slot.expCls=expander}
|
|
310
325
|
const key=w.h.icon&&this.iconTemplates.has(w.h.icon)?w.h.icon:null;if(slot.iconKey!==key){if(slot.iconEl){slot.iconEl.remove()}
|
|
311
326
|
slot.iconEl=key?this.iconTemplates.get(key).cloneNode(true):null;if(slot.iconEl){slot.cell.insertBefore(slot.iconEl,slot.content)}
|
|
312
|
-
slot.iconKey=key}},cellTip(event){const cell=event.target.closest?.(".cx-cell"),row=cell?.parentNode._kind==="node"&&cell.parentNode._w;const column=row&&!row.status&&this.cols[[...cell.parentNode.children].indexOf(cell)],tip=column?.tooltip;const source=tip==="auto"?column:this.columns.find(item=>item.id===tip);if(!source||cell.title&&!cell._cxTip)return;cell._cxTip=true;cell.title=tip!=="auto"||[cell,...cell.querySelectorAll("*")].some(item=>item.scrollWidth>item.clientWidth)?
|
|
327
|
+
slot.iconKey=key}},cellTip(event){const cell=event.target.closest?.(".cx-cell"),row=cell?.parentNode._kind==="node"&&cell.parentNode._w;const column=row&&!row.status&&this.cols[[...cell.parentNode.children].indexOf(cell)],tip=column?.tooltip;const source=tip==="auto"?column:this.columns.find(item=>item.id===tip);if(!source||cell.title&&!cell._cxTip)return;cell._cxTip=true;cell.title=tip!=="auto"||[cell,...cell.querySelectorAll("*")].some(item=>item.scrollWidth>item.clientWidth||item.scrollHeight>item.clientHeight)?
|
|
313
328
|
cellText(this.cellOf(row.h,source,this.columns.indexOf(source)),source,this.fmt):""},paintSlot(slot,node,column,index,w){const value=this.cellOf(node,column,index);if(slot.cell._cxTip){slot.cell._cxTip=false;slot.cell.removeAttribute("title");slot.title=null}
|
|
314
329
|
const hosted=column.render?this.paintHostSlot(slot,node,column,index,w):null;if(hosted==="host"){return}
|
|
315
330
|
const decorated=hosted==="decorated";const text=cellText(value,column,this.fmt);if(slot.text.data!==text){slot.text.data=text}
|
|
316
|
-
const object=isCellObject(value);const tone=
|
|
331
|
+
const object=isCellObject(value);const rule=columnNumericTone(column,cellValue(value));const tone=toneOf(columnValueTone(column,value)||(object?value.tone:null));const cls=slot.base+tone.cls;if(slot.cls!==cls){if(decorated){if(tone.cls)slot.cell.className +=tone.cls}else{slot.cell.className=cls}
|
|
317
332
|
slot.cls=cls}
|
|
318
|
-
toneColors(slot.cell,tone);const title=object&&value.title?value.title:decorated?null:otherZone(value,column,this.fmt);if(slot.title!==title){if(title){slot.cell.title=title}else{slot.cell.removeAttribute("title")}
|
|
333
|
+
toneColors(slot.cell,tone);const title=object&&value.title?value.title:decorated?null:rule?.label||otherZone(value,column,this.fmt);setAttr(slot.cell,"aria-description",rule?.label||null);if(slot.title!==title){if(title){slot.cell.title=title}else{slot.cell.removeAttribute("title")}
|
|
319
334
|
slot.title=title}
|
|
320
335
|
this.paintBadges(slot,(index===0&&node.badges)||null,object&&value.badges?value.badges:null)},paintBadges(slot,first,second){const count=(first?first.length:0)+(second?second.length:0);for(let k=0;k<count;k++){const badge=first&&k<first.length?first[k]:second[k -(first?first.length:0)];let span=slot.badges[k];if(!span){span=slot.content.appendChild(h("span"));span._text=span.appendChild(document.createTextNode(""));slot.badges.push(span)}
|
|
321
336
|
const tone=toneOf(badge.tone||"neutral");if(span._cls!==tone.cls){applyTone(span,"cx-badge",tone);span._cls=tone.cls}
|
|
@@ -504,7 +519,7 @@ if(active>=0){list.children[active].setAttribute("aria-selected","false")}
|
|
|
504
519
|
active=active<0?(delta<0?hits.length-1:0):(active+delta+hits.length)%hits.length;const item=list.children[active];item.setAttribute("aria-selected","true");input.setAttribute("aria-activedescendant",item.id);item.scrollIntoView({block:"nearest"})};input.addEventListener("input",()=>{cancelNavigation();sequence++;clearTimeout(timer);hits=[];close();timer=setTimeout(run,150)});input.addEventListener("keydown",(e)=>{if(e.defaultPrevented||e.isComposing)return;if(e.key==="ArrowDown"||e.key==="ArrowUp"){move(e.key==="ArrowDown"?1:-1)}else if(e.key==="Enter"){if(!list.hidden){choose(active>=0?active:0)}}else if(e.key==="Escape"){cancelNavigation();sequence++;clearTimeout(timer);if(list.hidden){input.value=""}
|
|
505
520
|
close()}else{return}
|
|
506
521
|
e.preventDefault()});input.addEventListener("blur",()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);blurTimer=setTimeout(close,150)});this.cancelSearch=()=>{cancelNavigation();sequence++;clearTimeout(timer);clearTimeout(blurTimer);hits=[];close()};box.appendChild(input);box.appendChild(list);box.appendChild(status);bar.appendChild(box);this.searchInput=input}});function watchFlyout(anchorElement,panel,isOpen){const position=()=>{if(!isOpen())return;const anchor=anchorElement.getBoundingClientRect(),fixed=getComputedStyle(panel).position==="fixed";const below=Math.max(0,global.innerHeight-anchor.bottom-8);const above=Math.max(0,anchor.top-8);const opensAbove=below<120&&above>below,room=opensAbove?above:below;panel.style.maxHeight=(panel.classList.contains("cx-fb")?room:Math.min(320,room))+ "px";panel.style.top=opensAbove?"auto":fixed?anchor.bottom+"px":"100%";panel.style.bottom=opensAbove?fixed?global.innerHeight-anchor.top+"px":"100%":"auto";const width=panel.getBoundingClientRect().width;panel.style.left=Math.max(8,Math.min(anchor.left,global.innerWidth-width-8))-(fixed?0:anchor.left)+ "px"};global.addEventListener("resize",position);global.addEventListener("scroll",position,true);return{position,dispose:()=>{global.removeEventListener("resize",position);global.removeEventListener("scroll",position,true)}}}
|
|
507
|
-
const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["
|
|
522
|
+
const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["c68e6612a9ea6eb0","canopyx-tree-tools.b8ee5c807c1d4fcd.js","canopyx-tree-tools.aae203232147f116.css"],"presenters":["b6a65af41d9187d9","canopyx-presenters.c48eacff1e9be0cd.js"],"filter-editor":["ad3c3d19c0c13c6d","canopyx-filter-editor.a52d28e96aadf798.js","canopyx-filter-editor.01b7bb6820dc9edb.css"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"history":["7d9901d2fe04df72","canopyx-history.9432e724bf14c9ed.js"],"pager":["8f804f70b96409f2","canopyx-pager.ac543250cf2f6e8b.js","canopyx-pager.08ad67c69026852e.css"],"enhance":["31162b1ffa622bf8","canopyx-enhance.65868addbc5c4a1a.js"],"data":["f07aebe37f3d1bb4","canopyx-data.401d09bc34c61d2f.js"],"forms":["a8c60f205d9babca","canopyx-forms.16987de1cdf9bda9.js","canopyx-forms.29058ce3c88af96e.css"],"flow":["842e1f1956f6213f","canopyx-flow.efc6250968e8b10a.js","canopyx-flow.3152e616c5557452.css"],"flow-host":["de4f9b11ab881eca","canopyx-flow-host.aea5ed35816df2af.js","canopyx-flow-host.1301fcf3454a723a.css"],"flow-checks":["ec2451183901867b","canopyx-flow-checks.29c4586a80f04b6a.js","canopyx-flow-checks.4502d6f7f7487b73.css"],"flow-options":["60450342239ded26","canopyx-flow-options.d31458a54aa4b1e7.js"],"flow-pick":["426718e2fa1f3cd0","canopyx-flow-pick.379205e09325bca3.js","canopyx-flow-pick.771b06ac50c141a1.css"],"flow-records":["f3c09661bdffb8d0","canopyx-flow-records.fddf130ace0764b1.js","canopyx-flow-records.e362111fb5f85732.css"],"flow-drafts":["4f112f64736ca8e3","canopyx-flow-drafts.09b88e275c7bc3b9.js","canopyx-flow-drafts.2dd86fb31fc10458.css"],"flow-preview":["f4fb5c42743873c0","canopyx-flow-preview.5778d5fce9ae0d78.js","canopyx-flow-preview.7928e22901da2088.css"],"flow-command":["39472118ca80ef02","canopyx-flow-command.78f4f931c52b1bfc.js","canopyx-flow-command.0c1247a371b7e775.css"],"flow-tasks":["147dd31638a9cb94","canopyx-flow-tasks.f012a521560f7075.js","canopyx-flow-tasks.524df90f908f81dd.css"],"flow-dialog":["ebb432cd6e34aba6","canopyx-flow-dialog.b00addd6a176198e.js","canopyx-flow-dialog.e6192e827eca25d2.css"],"flow-links":["2c14b19c9236e90d","canopyx-flow-links.7b6cfe42d28b6067.js"],"flow-endpoint":["f5cddfc9545e0920","canopyx-flow-endpoint.b31146202bd76aac.js"],"flow-consent":["22121778bc0d07c5","canopyx-flow-consent.749b97f13039bc71.js","canopyx-flow-consent.9f6580d3673ae8bf.css"],"matrix":["16ab7faa98c96b46","canopyx-matrix.4d417eaeba54ca4f.js","canopyx-matrix.9b3f57c1d0f090b6.css"],"changes":["2db8e138da4b5658","canopyx-changes.053104f8f56b0a87.js","canopyx-changes.dfbdb3d6c468ccb1.css"],"editing":["05fcb2c8be754b50","canopyx-editing.d96e5d0bee7fb477.js","canopyx-editing.b6bfd3c6c383bcbd.css"],"column-groups":["b42238fd108a8614","canopyx-column-groups.d8ad6322f769b915.js","canopyx-column-groups.37e177d74cebb516.css"],"cell-range":["e99a39e7cccc57b1","canopyx-cell-range.647da96e57924f3e.js","canopyx-cell-range.23f3222652588441.css"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"formatting":["1a28068597f435de","canopyx-formatting.68c501f97b71f1ec.js","canopyx-formatting.a59507e4e8334891.css"],"format-editor":["24f176a39c02944a","canopyx-format-editor.3b1dec2527e53988.js","canopyx-format-editor.1ba153c82aa87b04.css"],"link":["fa0c9e888463553b","canopyx-link.4ec39bc39fa6cf50.js","canopyx-link.8435c892613926ac.css"],"detail-rows":["4908d1d2b7f67aa8","canopyx-detail-rows.fe29b1759c962565.js","canopyx-detail-rows.8e38a8ad01fded76.css"],"grouping":["0e0a3529c0b099d7","canopyx-grouping.95b3f72fc66f2bea.js","canopyx-grouping.6c93259b4b89e523.css"],"highlight":["f39423961654c1e2","canopyx-highlight.a6f93893d36ab343.js","canopyx-highlight.5b6d2e0d979f9f9b.css"],"layouts":["dd1076d5684bfc6e","canopyx-layouts.670fd555e6e08904.js","canopyx-layouts.b1df38a90cb3215d.css"],"facets":["b46aac5ddb8be693","canopyx-facets.1709d78a83f05966.js","canopyx-facets.648a88d2f36d4999.css"],"live":["a27c818b731c22e3","canopyx-live.d19df9edc92e7d09.js","canopyx-live.cc4b94a2dec6f064.css"],"record-panel":["e78e0e62d74d6811","canopyx-record-panel.2fe5e43bb99cc818.js","canopyx-record-panel.f3691d54cefaab04.css"],"calendar":["762f4b4b62ecb4d8","canopyx-calendar.dc45ebdeb704d9c3.js","canopyx-calendar.1099197a45632f63.css"],"calendar-recurrence":["64bcc24d785bd1af","canopyx-calendar-recurrence.4b7f430c2a64de23.js"],"calendar-edit":["bdde26d4b7de2096","canopyx-calendar-edit.4ab2cf55e84f310f.js"],"calendar-ics":["feb3ed2cd67d057f","canopyx-calendar-ics.2a3af9eb3bf444fc.js"],"timeline":["3f04ba99401e9ebd","canopyx-timeline.76928f089774b3de.js","canopyx-timeline.0393f92746f8fa09.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
|
|
508
523
|
function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
|
|
509
524
|
part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
|
|
510
525
|
function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
|
|
@@ -514,7 +529,7 @@ const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const u
|
|
|
514
529
|
.catch(error=>{part.styleReady=null;throw error}));const code=PART_CODE.get(part.name)?.version===part.version||(part.scriptReady||=load(script,"src",hashed?scriptFile:"canopyx-"+part.name+".js","script")
|
|
515
530
|
.finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
|
|
516
531
|
const code=PART_CODE.get(part.name);if(code?.version!==part.version)throw new Error("CanopyX: "+part.label+" and runtime must come from the same build.");for(const name of code.requires||[])await loadPart(part.parts[name]);code.install(part.context())}).catch(error=>{part.ready=null;throw error})}
|
|
517
|
-
const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
|
|
532
|
+
const partQueue=global.CanopyXParts=global.CanopyXParts||[];partQueue.forEach(entry=>registerPart(...entry));partQueue.length=0;partQueue.push=(...entries)=>{entries.forEach(entry=>registerPart(...entry));return 0};const TREE_TOOLS=definePart(TreeGrid,"tree-tools","tree tools",()=>({TreeGrid,h,setText,fill,numberFormat,watchFlyout,columnWidth,prepareWidth,cellText,cellValue,isCellObject,foldText,formatting,sortKey,compareKeys,EXPORT_FORMATS,exportFormat,exportTimeout,exportFormatsOf:EXPORT_IMPL.formatsOf,INDENT,MAX_PROTOCOL_INTEGER,hostControl,detailCell,HostCellContext,disposeHostSlot,loadPart,definePart,pluginItems,applyTone,toneOf,badgeElement,RECORD_IMPL,svgIcon,gridExportField,columnNumericTone,columnValueTone}));const SEARCH_IMPL={},SEARCH_PART=definePart(TreeGrid,"search","sidecar search",()=>({SEARCH_IMPL,checkDocument,badIndex,isCount,isIdentifier,recentCache,packBytes,shardKey,foldText,trimSeparators,rankHits,validateSearchHit,PACK_CACHE,PACK_CACHE_BYTES,SHARD_CACHE,ENTRY_CACHE,ENTRY_BATCH,SEARCH_CANDIDATES}));async function requirePart(name){await this.toolsReady;const part=Object.hasOwn(this.parts,name)?this.parts[name]:null;if(!part)throw new Error("CanopyX: unknown part '"+name+"'.");return loadPart(part)}
|
|
518
533
|
TreeGrid.prototype.requirePart=requirePart;function readStateColumn(c,seen){requireIdentifier(c&&c.id,"state column ID");if(seen.has(c.id)||!Number.isFinite(c.width)||c.width<40||c.width>MAX_COLUMN_WIDTH||typeof c.hidden!=="boolean")
|
|
519
534
|
throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
|
|
520
535
|
function statePaths(value){if(!Array.isArray(value))throw new Error("CanopyX: state paths must be arrays.");return value.map(path=>{if(!Array.isArray(path)||!path.length)throw new Error("CanopyX: state paths cannot be empty.");return path.map(id=>{requireIdentifier(id,"state path ID");return id})})}
|
|
@@ -573,7 +588,7 @@ return this.openDeepLink()};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAUL
|
|
|
573
588
|
linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
|
|
574
589
|
function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
|
|
575
590
|
function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
|
|
576
|
-
const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField}));function loadRecordPanel(){return loadPart(RECORD_PART)}
|
|
591
|
+
const RECORD_IMPL={},RECORD_PART=definePart(TreeGrid,"record-panel","record panel",()=>({RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,badgeElement,loadSidecar,requireIdentifier,validateGridRows,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField,columnNumericTone,columnValueTone,validateColumnValues}));function loadRecordPanel(){return loadPart(RECORD_PART)}
|
|
577
592
|
const RECORD_STRUCTURE=["items","fields","records","events","changes","ref"];TreeGrid.prototype.recordNeeded=function(node){return!!this.view.record||!!node&&(!!node.fields||Object.values(node.cells||{}).some(cell=>isCellObject(cell)&&RECORD_STRUCTURE.some(name=>cell[name]!==undefined)))};TreeGrid.prototype.openRecord=function(id,options){return loadRecordPanel().then(()=>RECORD_IMPL.open(this,id,options))};function recordStart(grid){if(grid.view.record?.deepLink)loadRecordPanel().then(()=>RECORD_IMPL.start(grid),error=>grid.emit("error",{error}))}
|
|
578
593
|
DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{matchesHighlight:"Highlight matches",matchesCount:"[one]{count} match[other]{count} matches",matchesPosition:"{current} of {count}",matchesNone:"No matches",matchesLoaded:"[one]{count} match in loaded rows[other]{count} matches in loaded rows",matchesPrevious:"Previous match",matchesNext:"Next match",matchesAnnounce:"Match {current} of {count}, {column}",layoutMenu:"Layout",layoutFit:"Fit to width",layoutScroll:"All columns, scroll sideways",layoutCards:"Cards",layoutDensity:"Density",layoutCompact:"Compact",layoutNormal:"Normal",layoutComfortable:"Comfortable",layoutChanged:"Layout: {mode}, {density}",layoutSort:"Sort by"}));const LAYOUT_MODES=["fit","scroll","cards"],LAYOUT_DENSITIES=["compact","default","comfortable"];const DENSITY_STEP={tree:{compact:-4,default:0,comfortable:8},grid:{compact:-6,default:0,comfortable:8}};const VIEW_MODES={};const HIGHLIGHT_KEYS=["enabled","search","filters","matchCase","ignoreAccents","minLength","filterTones"];function readSearchHighlight(value,columns){if(value===undefined||value===false)return null;const options=value===true?{}:value,tone=name=>typeof name==="string"&&/^[a-z][a-z0-9-]{0,31}$/.test(name) && !name.endsWith("-bg");
|
|
579
594
|
if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
|
|
@@ -631,12 +646,13 @@ throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live upd
|
|
|
631
646
|
throw new Error("CanopyX: ordinal row identity is snapshot-local; record deep links require stable row keys.");if(typeof view.label!=="string"||!view.label.trim()||!Array.isArray(view.columns)||!view.columns.length)
|
|
632
647
|
throw new Error("CanopyX: a grid needs a label and columns.");if(view.reporting!==undefined){if(!GRID_REPORTING.validate)throw new Error("CanopyX: this view needs the reporting runtime.");GRID_REPORTING.validate(view)}
|
|
633
648
|
const ids=new Set();for(const column of view.columns){requireIdentifier(column&&column.id,"grid column ID");if(ids.has(column.id)||typeof column.title!=="string"||!["text","number","datetime"].includes(column.kind)||
|
|
649
|
+
column.headerDescription!==undefined&&typeof column.headerDescription!=="string"||
|
|
634
650
|
column.width!==undefined&&(!Number.isInteger(column.width)||column.width<40)||
|
|
635
651
|
["wrap","autoWidth","fixed","rowHeader","alwaysVisible","editable","filterable","exportable"].some(name=>column[name]!==undefined&&typeof column[name]!=="boolean")||
|
|
636
652
|
column.flex!==undefined&&!(typeof column.flex==="number"&&column.flex>=0&&column.flex<=100)||column.autoSize!==undefined&&!["content","header","none"].includes(column.autoSize)||
|
|
637
653
|
column.pinned!==undefined&&![null,"left","right"].includes(column.pinned)||column.priority!==undefined&&!gridPriority(column.priority)||
|
|
638
654
|
column.fixed&&column.width===undefined||column.tooltip!==undefined&&column.tooltip!=="auto"&&!view.columns.some(item=>item.id===column.tooltip))
|
|
639
|
-
throw new Error("CanopyX: invalid or duplicate grid column.");ids.add(column.id);if(column.presenter!==undefined)gridPresenter(column.presenter,column,view.columns);if(column.format!==undefined){if(column.kind!=="number")throw new Error("CanopyX: number formats need number columns.");gridNumberFormat(column.format)}
|
|
655
|
+
throw new Error("CanopyX: invalid or duplicate grid column.");ids.add(column.id);validateColumnValues(column);if(column.presenter!==undefined)gridPresenter(column.presenter,column,view.columns);if(column.format!==undefined){if(column.kind!=="number")throw new Error("CanopyX: number formats need number columns.");gridNumberFormat(column.format)}
|
|
640
656
|
if(column.aggregatable!==undefined&&(typeof column.aggregatable!=="boolean"||column.aggregatable&&column.kind!=="number")||
|
|
641
657
|
column.section!==undefined&&(typeof column.section!=="string"||!column.section.trim()||column.section.length>256))
|
|
642
658
|
throw new Error("CanopyX: invalid column aggregate or drawer section.")}
|
|
@@ -676,9 +692,10 @@ function gridOrder(left,right){return left===right?0:left<right?-1:1}
|
|
|
676
692
|
function gridIntegerId(id){if(id.length>1&&id.charCodeAt(0)===48)return false;for(let index=0;index<id.length;index++){const code=id.charCodeAt(index);if(code<48||code>57)return false}
|
|
677
693
|
return id.length>0}
|
|
678
694
|
function gridIdOrder(left,right){if(left===right)return 0;const a=gridIntegerId(left),b=gridIntegerId(right);if(a!==b)return a?-1:1;return a&&left.length!==right.length?left.length-right.length:left<right?-1:1}
|
|
679
|
-
function gridSortScalar(cell,column){return
|
|
695
|
+
function gridSortScalar(cell,column){return!column.valueOrder?.length&&isCellObject(cell)&&cell.sort!=null?cell.sort:gridScalar(cell,column)}
|
|
680
696
|
function gridCompare(left,right,column,direction){return gridKeyCompare(gridSortScalar(left.cells[column.id],column),gridSortScalar(right.cells[column.id],column),column,direction)}
|
|
681
|
-
function gridKeyCompare(a,b,column,direction){if(a===null||b===null)return a===b?0:a===null?1:-1;const
|
|
697
|
+
function gridKeyCompare(a,b,column,direction){if(a===null||b===null)return a===b?0:a===null?1:-1;if(column.valueOrder?.length){const at=value=>{const index=typeof value==="string"?column.valueOrder.indexOf(value):-1;return index<0?column.valueOrder.length:index};const rank=at(a)- at(b),result=rank||gridOrder(typeof a,typeof b)||gridOrder(a,b);return direction==="desc"?-result:result}
|
|
698
|
+
const x=column.kind==="text"&&typeof a!=="number"?String(a):a,y=column.kind==="text"&&typeof b!=="number"?String(b):b;const rank=gridOrder(typeof x,typeof y);if(rank)return rank;const result=gridOrder(x,y);return direction==="desc"?-result:result}
|
|
682
699
|
function gridMatches(row,predicate,column){return cellMatches(row.cells[column.id],predicate,column)}
|
|
683
700
|
function gridQueryRows(view,query,columns,compare=gridCompare){const terms=gridSearchTerms(query.search,query.searchMode),searchColumns=view.searchColumns?view.searchColumns.map(id=>columns.get(id)):view.columns;const rows=view.rows.filter(row=>gridMatchesSearch(row,terms,searchColumns)&&
|
|
684
701
|
query.filters.every(predicate=>gridMatches(row,predicate,columns.get(predicate.column)))&&gridMatchesGroup(row,query.filterGroup,columns));if(compare!==gridCompare||!query.sort.length)return compare?rows.sort((a,b)=>{for(const sort of query.sort){const compared=compare(a,b,columns.get(sort.column),sort.direction);if(compared)return compared}
|
|
@@ -695,7 +712,7 @@ page.total!==null&&page.matched!==null&&page.matched>page.total||
|
|
|
695
712
|
!page.items.length&&(page.offset!==0||next)||!page.offset&&previous||
|
|
696
713
|
page.matched!==null&&next!==(end<page.matched)||page.total!==null&&next&&end>=page.total||
|
|
697
714
|
query.cursor===undefined&&page.offset!==0)throw new Error("CanopyX: inconsistent cursor page.");const tokens=[page.nextCursor,page.previousCursor].filter(token=>token!==undefined);tokens.forEach(gridCursor);if(new Set(tokens).size!==tokens.length||tokens.includes(query.cursor))throw new Error("CanopyX: repeated cursor.");return checkedGridPage(page,view,query,accepted)}
|
|
698
|
-
function gridFacetKey(value,column){if(value!==null&&typeof value==="object"||value===undefined)throw new Error("CanopyX: facet values are raw scalars.");const scalar=gridScalar(value,column);if(scalar===null)return "null";return column.kind==="datetime"?"d:"+scalar:typeof scalar==="string"?"s:"+foldText(scalar):
|
|
715
|
+
function gridFacetKey(value,column){if(value!==null&&typeof value==="object"||value===undefined)throw new Error("CanopyX: facet values are raw scalars.");const scalar=gridScalar(value,column);if(scalar===null)return "null";return column.kind==="datetime"?"d:"+scalar:typeof scalar==="string"?"s:" +(gridExactTokens(column)?scalar:foldText(scalar)):
|
|
699
716
|
typeof scalar==="boolean"?"b:"+scalar:"n:"+scalar}
|
|
700
717
|
function validateGridFacetPage(input,view,request,snapshot){checkDocument(input,"gridFacetPage");const column=view.columns.find(item=>item.id===request.column);if(input.view!==view.id||input.revision!==request.query.revision||input.column!==request.column||
|
|
701
718
|
input.search!==request.search||input.includeCurrentFilter!==request.includeCurrentFilter||
|
|
@@ -712,7 +729,8 @@ throw new Error("CanopyX: facet buckets contradict the matching row count.");ret
|
|
|
712
729
|
class DataGrid{constructor(host,options){const{rows,rowData,...definition}=validateGridView(options.view),owned=parsedViews.has(options.view);this.view=JSON.parse(JSON.stringify(definition));if(this.view.rowIdentity==="ordinal"&&options.live)
|
|
713
730
|
throw new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys.");if(rows)this.view.rows=owned?rows:JSON.parse(JSON.stringify(rows));if(rowData){this.view.rowData=owned?rowData:structuredClone(rowData);this.view.rows=[]}
|
|
714
731
|
this.host=host;this.opts=options;this.id="cx" + ++instanceSeq;this.lifetime=new AbortController();this.dataLifetime=new AbortController();this.source=options.source||(this.view.source.kind==="inline"?this.view.rowData?rowDataSource(this):inlineGridSource(this.view):null);if(!this.source||typeof this.source.query!=="function")throw new Error("CanopyX: host grids need a query source.");this.cursor=this.view.source.navigation==="cursor";if(this.source.navigation!==undefined&&this.source.navigation!==(this.cursor?"cursor":"offset"))
|
|
715
|
-
throw new Error("CanopyX: source navigation must match the grid definition.");this.pageSize=this.view.pageSize;this.authoredAutoRows=this.view.rowHeight==="auto"||!!this.view.autoRowHeight
|
|
732
|
+
throw new Error("CanopyX: source navigation must match the grid definition.");this.pageSize=this.view.pageSize;this.authoredAutoRows=this.view.rowHeight==="auto"||!!this.view.autoRowHeight||
|
|
733
|
+
this.view.autoRowHeight!==false&&this.view.columns.some(column=>column.wrap);this.autoRows=this.authoredAutoRows;this.rowH=this.view.rowHeight==="auto"?this.view.estimatedRowHeight||28:this.view.rowHeight;this.rowHeights=new Map();this.paged=this.view.presentation==="paged";this.pageLength=this.view.pageLength||50;this.pageOffset=0;this.searchDelayMs=options.searchDelayMs===undefined?this.view.searchDelayMs===undefined?
|
|
716
734
|
this.view.source.kind==="inline"?0:300:this.view.searchDelayMs:options.searchDelayMs;if(!Number.isInteger(this.searchDelayMs)||this.searchDelayMs<0||this.searchDelayMs>5000)
|
|
717
735
|
throw new Error("CanopyX: search delay must be an integer from 0 to 5000 milliseconds.");this.cachePageLimit=options.cachePageLimit===undefined?40:options.cachePageLimit;this.requestTimeoutMs=options.requestTimeoutMs===undefined?rowData&&!options.source?2147483647:30000:options.requestTimeoutMs;if(!Number.isInteger(this.cachePageLimit)||this.cachePageLimit<2||this.cachePageLimit>1000||
|
|
718
736
|
!Number.isInteger(this.requestTimeoutMs)||this.requestTimeoutMs<1||this.requestTimeoutMs>2147483647)
|
|
@@ -804,7 +822,7 @@ button.setAttribute("aria-label",cell.getAttribute("aria-label")+ ", "+sorts[ind
|
|
|
804
822
|
this.buildHeaderSelection?.();this.buildColumnMenus?.()},cellOf(row,column){return row.cells[column.id]},refreshRowState(element,row){setAttr(element,"aria-selected",row.status||this.view.selection==="none"?null:String(this.selected.has(row.key)))},fillRow(element,row){const kind=row.status?"status":"node";element._w=row;if(element._kind!==kind||element._layout!==this.layout){disposeRowHostCells(element);element.textContent="";element._kind=kind;element._layout=this.layout;element._attrs={};element._cls=null;element.setAttribute("role","row");element.style.height=this.rowH+"px";element.style.width=this.rowWidth+"px";element._cells=(row.status?[null]:this.cols).map((column,index)=>{const cell=this.cell(element,index,column?column.width:this.rowWidth,column?column.kind:null);if(!column)cell.setAttribute("aria-colspan",String(this.cols.length));const content=index===0&&column?.render&&this.view.reporting?.selectionControls?cell.appendChild(h("span","cx-content")):cell;const slot={cell,content,base:cell.className +(column?.wrap?" cx-wrap":""),cls:null,title:null,badges:[],mode:"default"};slot.textSpan=content.appendChild(h("span","cx-text"));slot.text=slot.textSpan.appendChild(document.createTextNode(""));return slot})}
|
|
805
823
|
setClass(element,"cx-row" +(row.status?" cx-status cx-"+row.status:this.autoRows?" cx-auto-row":""));if(this.autoRows){element.style.height=row.status?this.rowH+"px":"auto";this.observeDetail(element,!row.status);this.measureNeeded=true}else element.style.height=this.rowH+"px";setAttr(element,"data-cx-id",row.key||null);setAttr(element,"data-cx-status",row.status||null);setAttr(element,"draggable",this.view.dragRows&&!row.status?"true":null);setAttr(element,"aria-busy",row.status==="loading"?"true":null);this.refreshRowState(element,row);if(row.status)element._cells[0].text.data=row.status==="error"?fill(this.labels.loadError,{error:((this.pages.get(Math.floor(row._ri / this.pageSize) * this.pageSize) || {}).error || {}).message || ""
|
|
806
824
|
}):this.labels.loading;else for(let i=0;i<this.cols.length;i++){const slot=element._cells[i];if(slot.highlighted){slot.cls=null;slot.highlighted=false}
|
|
807
|
-
const column=this.cols[i];this.paintSlot(slot,row.h,column,this.columnIndex[i],row);if(!column.render&&!slot.text.data){slot.text.data="—";slot.cell.classList.add("p-missing");slot.missing=true}
|
|
825
|
+
const column=this.cols[i],cell=row.h.cells[column.id];this.paintSlot(slot,row.h,column,this.columnIndex[i],row);if(!column.render&&!slot.text.data&&!(isCellObject(cell)&&cellValue(cell)==null&&cell.text==="")){slot.text.data="—";slot.cell.classList.add("p-missing");slot.missing=true}
|
|
808
826
|
else if(slot.missing){slot.cell.classList.remove("p-missing");slot.missing=false}
|
|
809
827
|
if(this.phone||slot.hiddenFields||slot.phonePrimary)this.paintHiddenFields?.(slot,row.h,column,this.columnIndex[i])}
|
|
810
828
|
this.paintGridHighlights(element,row);if(row.status)this.paintGridSkeleton(element,row)}});class AxisWindow{constructor(){this.count=0;this.uniform=0;this.offsets=null;this.total=0}
|
|
@@ -870,7 +888,7 @@ Object.assign(DataGrid.prototype,COLUMN_FIT,{fitAvailableWidth(){const grid=this
|
|
|
870
888
|
for(const column of peers)if(!column.fixed&&!column.sized&&!column.alwaysVisible)column.fitHidden=true},fitSize(column,level){if(column.fixed||column.sized)return columnWidth(column,column.width);const need=column.need??column.width,content=column.autoSize==="header"?need:column.contentNeed??need;const header=column.headWrapNeed||0;const floor=Math.max(level===undefined?need:content,header);let width=Math.max(floor,level===undefined?column.pref||0:0);if(column.identity&&this.host.clientWidth<=640&&(this.layoutMode||"fit")==="fit"){const available=this.fitAvailableWidth(),minimum=Math.min(content,available*.4);width=Math.max(header,minimum,Math.min(width,Math.max(minimum,available*.5)))}
|
|
871
889
|
return Math.ceil(columnWidth(column,width))},fitShrink(cols,excess){const slack=cols.map(column=>Math.max(0,column.renderWidth-this.fitSize(column,1)));const total=slack.reduce((sum,width)=>sum+width,0),ratio=total?Math.min(1,excess / total) : 0;
|
|
872
890
|
cols.forEach((column,index)=>column.renderWidth -=slack[index]*ratio);return Math.max(0,excess-total)},fitSpare(columns,spare){const flex=columns.filter(column=>column.flexWeight);const first=gridFitGrow(flex,spare,column=>column.flexWeight);return gridFitGrow(columns.filter(gridTextual),first.spare,column=>column.contentNeed||column.need).target||first.target},visibleColumns(){return FIT.visibleColumns.call(this).filter(column=>!column.fitHidden)},newCell(index,width,kind){return FIT.newCell.call(this,index,kind?this.cols[index].renderWidth??width:width,kind)},buildHeader(){this.fitLayout();this.fitBuilding=true;try{FIT.buildHeader.call(this)}finally{this.fitBuilding=false}
|
|
873
|
-
this.headCells.forEach((cell,index)=>{cell.querySelector(".cx-sort,.cx-htext").title=this.cols[index].title;cell.querySelector(".cx-resize").addEventListener("keydown",event=>{if(["ArrowLeft","ArrowRight","Home"].includes(event.key))this.fitManual(this.cols[index])},true)})},startResize(event,column){if(!this.destroyed&&!event.button){this.fitManual(column);global.addEventListener("pointerup",()=>this.emit("columnResize",{column:column.id,width:column.width}),{once:true,signal:this.lifetime.signal})}
|
|
891
|
+
this.headCells.forEach((cell,index)=>{cell.querySelector(".cx-sort,.cx-htext").title=this.cols[index].headerDescription??this.cols[index].title;cell.querySelector(".cx-resize").addEventListener("keydown",event=>{if(["ArrowLeft","ArrowRight","Home"].includes(event.key))this.fitManual(this.cols[index])},true)})},startResize(event,column){if(!this.destroyed&&!event.button){this.fitManual(column);global.addEventListener("pointerup",()=>this.emit("columnResize",{column:column.id,width:column.width}),{once:true,signal:this.lifetime.signal})}
|
|
874
892
|
return FIT.startResize.call(this,event,column)},setColumnWidth(id,width){const column=this.columns.find(item=>item.id===id);if(column&&Number.isFinite(width))column.sized=true;FIT.setColumnWidth.call(this,id,width);this.emit("columnResize",{column:id,width:column.width})},applyWidths(){this.fitLayout();if(this.phone!==undefined)this.updateGridPhone();const visible=this.visibleColumns(),cols=this.cols,width=this.fitAvailableWidth();if(cols&&(visible.length!==cols.length||visible.some((column,index)=>column!==cols[index]))){if(!this.fitBuilding){this.buildHeader();this.syncColumnControls();this.render();return}
|
|
875
893
|
queueMicrotask(()=>this.destroyed||this.applyWidths())}
|
|
876
894
|
FIT.applyWidths.call(this,this.fitWidths(cols,width));if(this.headRow.matches(":hover"))this.syncColumnMenuRoom?.();this.fitHeight()},fitLayout(){const width=this.fitAvailableWidth(),phone=this.host.clientWidth<=640,shown=FIT.visibleColumns.call(this).filter(column=>!column.responsiveHidden);if(!width)return;const key=this.pendingQuery?this.fitKey:this.queryEpoch+":"+phone;if(key!==this.fitKey||!this.fitCh){this.fitKey=key;this.fitFont=null;for(const column of this.columns)column.need=this.measureGridColumn(column).width}
|
|
@@ -878,7 +896,7 @@ for(const column of this.columns){if(!column.fixed&&!column.sized)column.width=t
|
|
|
878
896
|
this.fitHide(shown,width,phone)},measureGridColumn(column){const context=this.fitContext||=document.createElement("canvas").getContext("2d"),query=this.acceptedQuery;if(!context)throw new Error("CanopyX: no canvas context.");if(!this.fitFont){const style=getComputedStyle(this.grid),head=this.headCells?.[0]&&getComputedStyle(this.headCells[0]),family=" "+style.fontFamily;this.fitFont=[style.fontWeight+" "+style.fontSize+family,"700 12.5px"+family,(head?head.fontWeight+" "+head.fontSize:"700 13px")+ family,parseFloat(getComputedStyle(this.host).getPropertyValue("--cx-cell-px"))||12];this.fitFont.push(gridClassFont(this.grid,"p-mono"),gridClassFont(this.grid,"p-sub"),gridClassFont(this.grid,"p-pill",this.fitPill={}),gridClassFont(this.grid,"cx-sort-priority"));this.fitNumericVariant=gridNumericVariant(this.grid);context.font=this.fitFont[0];this.fitCh=Math.ceil(gridMeasureText(context,"00000000000",this.fitNumericVariant))}
|
|
879
897
|
const[,,headFont,pad,mono,sub,pillFont,priorityFont]=this.fitFont,first=column===FIT.visibleColumns.call(this)[0],options=gridOptions(column),kind=options.kind;const text=(value,font=this.fitFont[0],numeric=true)=>{context.font=font;return gridMeasureText(context,value,numeric?this.fitNumericVariant:"normal")};const move=this.view.reporting?.columnReorder?Math.max(32,Math.ceil(text("⋮⋮",headFont,false))+ 8):0,target=this.host.clientWidth<=640?44:24;const sort=query?.sort.findIndex(sort=>sort.column===column.id)??-1;const chrome=2*pad+8+move +(sort<0?0:22 +(query.sort.length>1?text(sort+1,priorityFont,false)+ 4:0))+
|
|
880
898
|
(gridColumnFiltered(query,column.id)?target:0)+(first&&this.selectionControls?target+2:0);const title=text(column.title,headFont,false),head=Math.ceil(Math.max(24,title)+ chrome);const words=column.title.trim().split(/\s+/);
|
|
881
|
-
let balanced=title;for(let split=1;split<words.length;split++)balanced=Math.min(balanced,Math.max(text(words.slice(0,split).join(" "),headFont,false),text(words.slice(split).join(" "),headFont,false)));column.headWrapNeed=Math.ceil(Math.max(24,balanced)+ chrome);let values=0,sampled=0;const none=column.autoSize==="none"||column.pref&&(column.wrap||["longText","tags","list"].includes(kind));if(!none&&column.autoSize!=="header")for(const row of this.rowCache.values()){if(sampled===200)break;const cell=row.h.cells[column.id],value=cellText(cell,column,this.fmt)||"—",series=gridSeries(cell).length;const tone=gridPresenterTone(options,cellValue(cell),isCellObject(cell)&&cell.tone),quiet=options.quietTones?.includes(tone);const secondary=kind==="identifier"&&(options.secondaryColumn?cellText(row.h.cells[options.secondaryColumn],this.columns.find(item=>item.id===options.secondaryColumn),this.fmt):isCellObject(cell)&&cell.secondary);const atomic=kind==="enum"||kind==="state";const pill=kind==="enum"&&!quiet&&tone!=="success";const atomicWidth=atomic?text(value,pill?pillFont:undefined)+
|
|
899
|
+
let balanced=title;for(let split=1;split<words.length;split++)balanced=Math.min(balanced,Math.max(text(words.slice(0,split).join(" "),headFont,false),text(words.slice(split).join(" "),headFont,false)));column.headWrapNeed=Math.ceil(Math.max(24,balanced)+ chrome);let values=0,sampled=0;const none=column.autoSize==="none"||column.pref&&(column.wrap||["longText","tags","list"].includes(kind));if(!none&&column.autoSize!=="header")for(const row of this.rowCache.values()){if(sampled===200)break;const cell=row.h.cells[column.id],value=cellText(cell,column,this.fmt)||"—",series=gridSeries(cell).length;const tone=columnValueTone(column,cell)||gridPresenterTone(options,cellValue(cell),isCellObject(cell)&&cell.tone),quiet=options.quietTones?.includes(tone);const secondary=kind==="identifier"&&(options.secondaryColumn?cellText(row.h.cells[options.secondaryColumn],this.columns.find(item=>item.id===options.secondaryColumn),this.fmt):isCellObject(cell)&&cell.secondary);const atomic=kind==="enum"||kind==="state";const pill=kind==="enum"&&!quiet&&tone!=="success";const atomicWidth=atomic?text(value,pill?pillFont:undefined)+
|
|
882
900
|
(pill?this.fitPill.extra+this.fitPill.spacing*Array.from(value).length:quiet&&kind==="enum"?16:quiet?0:kind==="state"&&tone!=="success"?15:13):0;values=Math.max(values,atomic?atomicWidth:kind==="identifier"?Math.min(420,text(value,options.mono?mono:undefined,!options.mono)+(secondary?6+text(secondary,sub):0)):kind==="statusStrip"?Math.min(series,12)*7:kind==="sparklineBars"?Math.min(series,12)*6:kind==="sparklineLine"?80:kind==="boolean"?16:
|
|
883
901
|
Math.min(kind==="longText"||kind==="tags"||kind==="list"||column.wrap?320:420,text(value))+
|
|
884
902
|
(kind==="progress"?80:kind==="tags"||kind==="list"?48:0));sampled++}
|
|
@@ -889,7 +907,9 @@ rule.target!==undefined&&!["row","cell"].includes(rule.target)||rule.tone===unde
|
|
|
889
907
|
throw new Error("CanopyX: invalid highlight rule.");const{column,operator,values}=rule;gridPredicate({column,operator,values},columns,budget);gridDecoration(rule.tone,rule.className)}}
|
|
890
908
|
DataGrid.prototype.paintGridHighlights=function(element,row){if(!this.view.highlightRules?.length&&!row.h.tone&&!row.h.className&&!element._cxHighlight)return;const matches=new Map();if(!row.status)for(const rule of this.view.highlightRules||[]){const key=rule.target==="cell"?rule.column:null;if(!matches.has(key)&&gridMatches(row.h,rule,this.columns.find(column=>column.id===rule.column)))matches.set(key,rule)}
|
|
891
909
|
const mark=matches.get(null),name=row.status?null:mark?.tone??row.h.tone;const tone=toneOf(name),classes=row.status?"":[row.h.className,mark?.className].filter(Boolean).join(" ");setClass(element,(element._cls??element.className)+(classes?" "+classes:"")+ tone.cls);toneColors(element,tone);setAttr(element,"data-cx-tone",name||null);if(name)element.style.setProperty("--cx-row-tone","var(--cx-tone-"+name+",var(--cx-text))");else element.style.removeProperty("--cx-row-tone");element._cxHighlight=!!(name||classes);for(const[id,rule]of matches)if(id!==null){const index=this.cols.findIndex(column=>column.id===id),slot=element._cells[index];if(!slot)continue;const base=rule.tone?slot.cell.className.replace(/(?:^|\s)cx-tone-[a-z0-9-]+|(?:^|\s)cx-toned/g, "") : slot.cell.className;
|
|
892
|
-
slot.cell.className=base +(rule.className?" "+rule.className:"")+(rule.tone?toneOf(rule.tone).cls:"");if(rule.tone)toneColors(slot.cell,toneOf(rule.tone));slot.highlighted=true}};
|
|
910
|
+
slot.cell.className=base +(rule.className?" "+rule.className:"")+(rule.tone?toneOf(rule.tone).cls:"");if(rule.tone)toneColors(slot.cell,toneOf(rule.tone));slot.highlighted=true}};const VALUE_PAINT=DataGrid.prototype.paintSlot;DataGrid.prototype.paintSlot=function(slot,row,column,index,wrapper){VALUE_PAINT.call(this,slot,row,column,index,wrapper);if(!column.render){const cell=row.cells[column.id],rule=columnNumericTone(column,cellValue(cell)),tone=columnValueTone(column,cell);if(tone){applyTone(slot.cell,slot.base,toneOf(tone));slot.cls=slot.cell.className}
|
|
911
|
+
if(rule){slot.cell.title=rule.label;slot.title=rule.label}
|
|
912
|
+
setAttr(slot.cell,"aria-description",rule?.label||null)}};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridExpandCell:"{column}: show complete text",gridCloseCell:"Close complete text"}));const GRID_PRESENTERS_BUILD=DataGrid.prototype.build;function gridPresenter(options,column,columns){const kinds=["link","icon","progress","boolean","list","longText","enum","state","change","statusStrip","sparklineBars","sparklineLine","identifier","tags","missing","structured"];const invalid=()=>{throw new Error("CanopyX: invalid grid presenter or raw column binding.")};if(!options||typeof options!=="object"||Array.isArray(options)||!kinds.includes(options.kind))invalid();if(["progress","change"].includes(options.kind)&&column.kind!=="number"||
|
|
893
913
|
["boolean","list","tags","link"].includes(options.kind)&&column.kind!=="text")invalid();for(const name of["newWindow","inverted","mono","higherIsGood"])if(options[name]!==undefined&&typeof options[name]!=="boolean")invalid();for(const name of["hrefColumn","deltaColumn","secondaryColumn"])if(options[name]!==undefined){const target=columns.find(item=>item.id===options[name]);if(!target||name==="hrefColumn"&&target.kind!=="text"||name==="deltaColumn"&&target.kind!=="number")invalid()}
|
|
894
914
|
if(options.kind==="change"&&!options.deltaColumn||options.kind==="icon"&&(typeof options.glyph!=="string"||!options.glyph.trim()||options.glyph.length>32))invalid();if(options.maximum!==undefined&&(!Number.isFinite(options.maximum)||options.maximum<=0||options.maximum>Number.MAX_SAFE_INTEGER))invalid();if(["list","tags"].includes(options.kind)&&(typeof options.separator!=="string"||!options.separator.length||options.separator.length>16||
|
|
895
915
|
options.limit!==undefined&&(!Number.isInteger(options.limit)||options.limit<1||options.limit>16)))invalid();if((options.minimum===undefined)!==(options.scaleMaximum===undefined)||options.minimum!==undefined&&
|
|
@@ -906,14 +926,8 @@ const value=raw.trim();try{const url=new URL(value,document.baseURI);if(["http:"
|
|
|
906
926
|
}catch(_){/* Invalid destinations retain plain text. */ }
|
|
907
927
|
return null}
|
|
908
928
|
DataGrid.prototype.build=function(){for(const column of this.columns){const options=column.presenter||(column.wrap?{kind:"longText"}:null);if(options&&!column.render){column.render=gridCellRenderer(this,column,options);column.hostRenderer=false}}
|
|
909
|
-
return GRID_PRESENTERS_BUILD.call(this)};
|
|
910
|
-
|
|
911
|
-
}else if(options.kind==="identifier"){add(text,options.mono?"p-mono":"cx-presenter-text");const secondary=options.secondaryColumn?cellText(row.cells[options.secondaryColumn],grid.columns.find(item=>item.id===options.secondaryColumn),grid.fmt):object&&cell.secondary;if(secondary)add(secondary,"p-sub")}else if(options.kind==="tags"||options.kind==="list"){const values=text.split(options.separator).map(item=>item.trim()).filter(Boolean),limit=options.kind==="tags"?3:options.limit||3;const preview=add("","cx-tag-list");element.classList.add("cx-list-cell");for(const value of values.slice(0,limit)){const tag=h("span","p-tag");setText(tag,value);preview.appendChild(tag)}
|
|
912
|
-
if(values.length>limit||options.kind==="list")more(text,values.length>limit?"+"+(values.length-limit):grid.labels.gridShowMore)}else if(options.kind==="longText"){const budget=Math.max(256,Math.ceil((column.renderWidth||column.width)/7*5));
|
|
913
|
-
const preview=add(text.length>budget?text.slice(0,budget).replace(/[\uD800-\uDBFF]$/,"")+" …":text,"cx-wrapped-text"+(options.mono?" p-mono":""));
|
|
914
|
-
if(!grid.autoRows)element.classList.add("cx-fixed-text");if(!column.wrap||text.length>Math.max(40,(column.renderWidth||column.width)/7*4)||text.split("\n").length>4){element.classList.add("cx-clamped");more(text);}
|
|
915
|
-
}else add(text);if(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge));return true}}
|
|
916
|
-
Object.assign(DataGrid.prototype,{setNotice(text,error){clearTimeout(this.gridLoadingTimer);this.notice.replaceChildren();this.notice.hidden=true;this.host.insertBefore(this.notice,this.grid);this.host.classList.remove("cx-grid-awaiting");if(!this.stateCleanup){this.stateCleanup=true;this.lifetime.signal.addEventListener("abort",()=>{clearTimeout(this.gridLoadingTimer);clearTimeout(this.gridSkeletonTimer)},{once:true})}
|
|
929
|
+
return GRID_PRESENTERS_BUILD.call(this)};const GRID_PRESENTER_IMPL={},GRID_PRESENTERS=definePart(DataGrid,"presenters","cell presenters",()=>({GRID_PRESENTER_IMPL,h,setText,fill,cellValue,cellText,isCellObject,columnNumericTone,columnValueTone,gridPresenterTone,gridPresenterLink,numberFormat,toneColors,toneOf,applyTone,gridIcon,badgeElement,GRID_HISTORY_KINDS,GRID_HISTORY_IMPL,RECORD_IMPL}));function gridCellRenderer(grid,column,options,record=false,complete=false){let paint;return(row,element)=>{if(!GRID_PRESENTER_IMPL.create)return false;return(paint||=GRID_PRESENTER_IMPL.create(grid,column,options,record,complete))(row,element)}}
|
|
930
|
+
DataGrid.prototype.loadPresenters=function(){return this.presenterLoad||=loadPart(GRID_PRESENTERS).then(()=>{this.version++;this.scheduleRender()})};Object.assign(DataGrid.prototype,{setNotice(text,error){clearTimeout(this.gridLoadingTimer);this.notice.replaceChildren();this.notice.hidden=true;this.host.insertBefore(this.notice,this.grid);this.host.classList.remove("cx-grid-awaiting");if(!this.stateCleanup){this.stateCleanup=true;this.lifetime.signal.addEventListener("abort",()=>{clearTimeout(this.gridLoadingTimer);clearTimeout(this.gridSkeletonTimer)},{once:true})}
|
|
917
931
|
this.notice.className="cx-grid-notice";this.notice.setAttribute("role",error?"alert":"status");if(this.pendingQuery&&!error){const epoch=this.queryEpoch;this.gridLoadingTimer=setTimeout(()=>{if(this.destroyed||epoch!==this.queryEpoch||!this.pendingQuery)return;setText(this.live,this.labels.loading);if(!this.snapshot){this.host.classList.add("cx-grid-awaiting");this.notice.classList.add("cx-initial-skeleton");this.notice.hidden=false;this.host.insertBefore(this.notice,this.grid.nextSibling);for(let index=0;index<6;index++){const row=h("div","cx-skel");row.setAttribute("aria-hidden","true");for(const column of this.visibleColumns()){const cell=h("span"),bar=h("i");cell.style.flex=column.renderWidth||column.width;cell.appendChild(bar);row.appendChild(cell)}this.notice.appendChild(row)}}},150);return}
|
|
918
932
|
if(error){this.notice.classList.add("cx-banner");const message=h("div"),title=h("b"),detail=h("span","d");setText(title,this.labels.gridLoadFailed);setText(detail,text);message.append(title,document.createTextNode(" "),detail);const retry=gridDecorateButton(gridButton(this.labels.gridRetry,()=>this.retry().catch(()=>{})),"retry",true);retry.classList.add("cx-grid-retry");this.notice.append(message,retry);this.notice.hidden=false;setText(this.live,this.labels.gridLoadFailed+" "+text);return}
|
|
919
933
|
if(this.snapshot&&(this.cursor?this.cursorWindow.end===this.pageOffset:this.snapshot.matched===0)){const query=this.acceptedQuery,active=!!query.search||gridFilterCount(query)>0,title=h("h4"),reason=h("p"),actions=h("div","acts");this.host.classList.add("cx-grid-awaiting");this.notice.classList.add("cx-state");this.host.insertBefore(this.notice,this.grid.nextSibling);title.setAttribute("aria-level","2");setText(title,fill(active?this.labels.gridNoMatches:this.labels.gridEmpty,{noun:this.noun}));setText(reason,active?fill(this.labels.gridNoMatchesReason,{search:query.search||"—",count:gridFilterCount(query)}):this.view.emptyReason||this.labels.gridEmptyReason);if(active)actions.appendChild(gridButton(this.labels.gridClearAll,()=>this.setQuery(gridQueryStart(this.queryForChange(true),{search:"",filters:[],filterGroup:undefined})).catch(()=>{})));this.notice.append(title,reason,actions);this.notice.hidden=false;setText(this.live,title.textContent+" "+reason.textContent)}else if(text){setText(this.notice,text);this.notice.hidden=false}},paintGridSkeleton(element,row){if(row.status!=="loading"){element._skeleton?.remove();element._skeleton=null;return}
|
|
@@ -965,11 +979,11 @@ for(const field of CAL_FIELDS)if(field!=="allDay"&&event[field]!=null){cells[fie
|
|
|
965
979
|
return{id,cells}});if(options.resources)used.add("resource");if(pick("sources"))used.add("source");if(drop||create&&!(typeof create==="object"&&create.allDay===false))used.add("allDay");const writable=editable||!!create||drop;const columns=[{id:"title",title:"Title",kind:"text",rowHeader:true,sortable:true,editable:writable},{id:"start",title:"Start",kind:"datetime",sortable:true,editable:writable},{id:"end",title:"End",kind:"datetime",sortable:true,editable:writable},...CAL_FIELDS.filter(field=>used.has(field)).map(field=>({id:field,title:CAL_TITLES[field],kind:"text",hidden:field!=="description",editable:writable&&(field==="resource"||field==="allDay"||field==="recurrence"||field==="exceptions")}))];let toolbar=pick("toolbar");if(options.export===true&&toolbar!==true)toolbar=toolbar===false?["export"]:toolbar.includes("export")?toolbar:[...toolbar,"export"];if(options.export===false&&toolbar!==false)toolbar=(toolbar===true?["search","filters","columns","views","more"]:toolbar.filter(item=>item!=="export"));if(Array.isArray(toolbar)&&!toolbar.length)toolbar=false;const calendar={start:"start",end:"end",title:"title",views:pick("views"),toolbar,details:options.drawer===true?"drawer":options.drawer===false?"popover":pick("details")};for(const field of CAL_FIELDS)if(used.has(field))calendar[field]=field;for(const name of["view","date","timeZone","firstDay","sources"])if(options[name]!==undefined)calendar[name]=options[name];if(editable)calendar.editable=typeof pick("editable")==="object"?pick("editable"):true;if(create)calendar.create=create;if(drop)calendar.drop=true;if(pick("print"))calendar.print=true;const ownViews=own.views!==undefined||options.views!==undefined,addTimeline=()=>{if(!ownViews&&!calendar.views.includes("timeline"))calendar.views=[...calendar.views,"timeline"]};if(options.resources){const list=options.resources,tree=Array.isArray(list)?{protocol:PROTOCOL,type:"view",id:"resources",label:"Resources",rowHeight:34,pageSize:200,selection:"single",columns:[{id:"name",title:"Resource",kind:"text",width:200}],source:{kind:"inline"},roots:calResourceRoots(list)}:list;calendar.resources={view:tree};if(options.timeline!==false&&(options.timeline||options.preset==="scheduler"))addTimeline();if(options.preset==="scheduler")calendar.capacity={thresholds:[{at:3,tone:"warning"},{at:5,tone:"danger"}]}}else if(options.timeline)addTimeline();for(const[name,value]of Object.entries(own))if(!["toolbar","editable","create","drop"].includes(name))calendar[name]=value;if(calendar.toolbar===true)delete calendar.toolbar;if(calendar.details==="drawer")delete calendar.details;const search=calendar.toolbar===undefined||calendar.toolbar!==false&&calendar.toolbar.includes("search");const view={protocol:PROTOCOL,type:"grid",id:options.id??"calendar",label:options.label??"Calendar",rowHeight:34,pageSize:200,selection:"single",search,columns,source:{kind:"inline"},rows,calendar};if(options.live)view.live=options.live===true?{}:options.live;if(options.facets)view.facets=Array.isArray(options.facets)?{columns:options.facets}:options.facets;const hostOptions=Object.fromEntries(Object.entries(options).filter(([name])=>!CAL_OWN.has(name)));if(options.links)hostOptions.linkEvents=true;if(Object.keys(hooks).length)hostOptions.calendar=hooks;return createDataGrid(host,{...hostOptions,view})}
|
|
966
980
|
function calResourceRoots(list){const nodes=new Map(list.map(item=>[String(item.id),{id:String(item.id),label:String(item.label??item.id),cells:{name:String(item.label??item.id)},expanded:true}])),roots=[];for(const item of list){const node=nodes.get(String(item.id)),parent=item.parent==null?null:nodes.get(String(item.parent));if(parent)(parent.children||=[]).push(node);else roots.push(node)}
|
|
967
981
|
return roots}
|
|
968
|
-
const GRID_EDITING=definePart(DataGrid,"editing","editing",()=>({DataGrid,FORMS_IMPL,h,setText,fill,gridButton,gridDecorateButton,GRID_ICONS,cellValue,cellText,isCellObject,gridFreeze,gridMomentFromParts,numberFormat,gridQuery,foldText,requireIdentifier,checkDocument,validateGridRows,inlineGridSource,PROTOCOL,boundedPattern,validateGridFacetPage,RECORD_IMPL}));const GRID_EDIT_INIT=DataGrid.prototype.initializeState;const GRID_EDIT_API=["beginEdit","endEdit","setCellValue","validate","commitRow","commitChanges","insertRow","isEditing","hasChanges","undo","redo","canUndo","canRedo","cancelEdit","revertChanges","getChanges","setReadOnly"];GRID_EDIT_API.forEach((name,index)=>{DataGrid.prototype[name]=index<7?function(...args){return this.loadEditing().then(()=>this[name](...args))}:index<15?()=>false:()=>[]});DataGrid.prototype.setReadOnly=function(value){this.editReadOnly=!!value};DataGrid.prototype.loadEditing=function(){return this.editLoad||=loadPart(GRID_EDITING).then(()=>this.startEditing()).catch(error=>{this.editLoad=null;this.emit("error",{error});throw error})};DataGrid.prototype.initializeState=function(){const ready=GRID_EDIT_INIT.call(this);return this.columns.some(column=>column.editable)?Promise.all([ready,this.loadEditing().catch(()=>{})]).then(([result])=>result):ready};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridFacetPanel:"Filter by",gridFacetPanelHide:"Hide the filter panel",gridFacetPanelShow:"Show the filter panel",gridFacetShowMore:"Show {count} more",gridFacetShowFewer:"Show fewer",gridFacetEmptyValue:"(Empty)",gridFacetFrom:"From",gridFacetTo:"To",gridFacetHistogram:"Distribution of {column}",gridFacetBin:"{from} to {to}: {count} rows",gridFacetNoChart:"Too many values to chart",gridFacetClear:"Clear {column}",gridFacetCustom:"Another condition filters this column.",gridFacetResult:"{count} matching rows",gridFacetSelected:"{count} selected",gridFacetValueCount:"{value}, {count} rows",gridFacetCollapse:"Collapse {column}",gridFacetExpand:"Expand {column}",gridFacetInvalid:"Enter a valid value.",gridFacetReversed:"From must not be after To."}));const GRID_FACETS=definePart(DataGrid,"facets","facet panel",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQueryStart,gridQueryRows,gridColumnProjection,gridScalar,gridOrder,cellText,foldText,numberFormat,gridCellRenderer,gridFreeze}));Object.assign(DataGrid.prototype,{loadFacets(){return this.facetLoad||=loadPart(GRID_FACETS).then(()=>this.destroyed||this.startFacets()).catch(error=>{this.facetLoad=null;throw error})},setFacetPanelOpen(open){return this.loadFacets().then(()=>this.setFacetPanelOpen(open))},getFacetPanel(){return gridFreeze({open:this.facetOpen??null,columns:(this.facetColumns||[]).map(facet=>facet.column)})}});const FACET_STATE={get:DataGrid.prototype.getState,read:DataGrid.prototype.readGridState,apply:DataGrid.prototype.applyStatePresentation,init:DataGrid.prototype.initializeState};Object.assign(DataGrid.prototype,{getState(){const state=FACET_STATE.get.call(this);if((this.view.facets||this.opts.facets)&&this.facetOpen!==undefined)state.facets={open:this.facetOpen};return state},readGridState(input){const state=FACET_STATE.read.call(this,input);if(input.facets!==undefined){const facets=input.facets;if(!facets||typeof facets!=="object"||Array.isArray(facets)||Object.keys(facets).some(key=>key!=="open")||typeof facets.open!=="boolean")
|
|
982
|
+
const GRID_EDITING=definePart(DataGrid,"editing","editing",()=>({DataGrid,FORMS_IMPL,h,setText,fill,gridButton,gridDecorateButton,GRID_ICONS,cellValue,cellText,isCellObject,gridFreeze,gridMomentFromParts,numberFormat,gridQuery,foldText,requireIdentifier,checkDocument,validateGridRows,inlineGridSource,PROTOCOL,boundedPattern,validateGridFacetPage,RECORD_IMPL}));const GRID_EDIT_INIT=DataGrid.prototype.initializeState;const GRID_EDIT_API=["beginEdit","endEdit","setCellValue","validate","commitRow","commitChanges","insertRow","isEditing","hasChanges","undo","redo","canUndo","canRedo","cancelEdit","revertChanges","getChanges","setReadOnly"];GRID_EDIT_API.forEach((name,index)=>{DataGrid.prototype[name]=index<7?function(...args){return this.loadEditing().then(()=>this[name](...args))}:index<15?()=>false:()=>[]});DataGrid.prototype.setReadOnly=function(value){this.editReadOnly=!!value};DataGrid.prototype.loadEditing=function(){return this.editLoad||=loadPart(GRID_EDITING).then(()=>this.startEditing()).catch(error=>{this.editLoad=null;this.emit("error",{error});throw error})};DataGrid.prototype.initializeState=function(){const ready=GRID_EDIT_INIT.call(this);return this.columns.some(column=>column.editable)?Promise.all([ready,this.loadEditing().catch(()=>{})]).then(([result])=>result):ready};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridFacetPanel:"Filter by",gridFacetPanelHide:"Hide the filter panel",gridFacetPanelShow:"Show the filter panel",gridFacetShowMore:"Show {count} more",gridFacetShowFewer:"Show fewer",gridFacetEmptyValue:"(Empty)",gridFacetFrom:"From",gridFacetTo:"To",gridFacetHistogram:"Distribution of {column}",gridFacetBin:"{from} to {to}: {count} rows",gridFacetNoChart:"Too many values to chart",gridFacetClear:"Clear {column}",gridFacetCustom:"Another condition filters this column.",gridFacetResult:"{count} matching rows",gridFacetSelected:"{count} selected",gridFacetValueCount:"{value}, {count} rows",gridFacetCollapse:"Collapse {column}",gridFacetExpand:"Expand {column}",gridFacetInvalid:"Enter a valid value.",gridFacetReversed:"From must not be after To."}));const GRID_FACETS=definePart(DataGrid,"facets","facet panel",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQueryStart,gridQueryRows,gridColumnProjection,gridScalar,gridOrder,gridKeyCompare,gridFacetKey,cellText,foldText,numberFormat,gridCellRenderer,gridFreeze}));Object.assign(DataGrid.prototype,{loadFacets(){return this.facetLoad||=loadPart(GRID_FACETS).then(()=>this.destroyed||this.startFacets()).catch(error=>{this.facetLoad=null;throw error})},setFacetPanelOpen(open){return this.loadFacets().then(()=>this.setFacetPanelOpen(open))},getFacetPanel(){return gridFreeze({open:this.facetOpen??null,columns:(this.facetColumns||[]).map(facet=>facet.column)})}});const FACET_STATE={get:DataGrid.prototype.getState,read:DataGrid.prototype.readGridState,apply:DataGrid.prototype.applyStatePresentation,init:DataGrid.prototype.initializeState};Object.assign(DataGrid.prototype,{getState(){const state=FACET_STATE.get.call(this);if((this.view.facets||this.opts.facets)&&this.facetOpen!==undefined)state.facets={open:this.facetOpen};return state},readGridState(input){const state=FACET_STATE.read.call(this,input);if(input.facets!==undefined){const facets=input.facets;if(!facets||typeof facets!=="object"||Array.isArray(facets)||Object.keys(facets).some(key=>key!=="open")||typeof facets.open!=="boolean")
|
|
969
983
|
throw new Error("CanopyX: invalid saved facet panel state.");if(this.view.facets||this.opts.facets)state.facets={open:facets.open}}
|
|
970
984
|
return state},applyStatePresentation(state){const applied=FACET_STATE.apply.call(this,state);if(state.facets&&state.facets.open!==this.facetOpen&&!this.destroyed){if(this.facetPanel)this.setFacetPanelOpen(state.facets.open).catch(error=>this.emit("error",{error}));else this.facetOpen=state.facets.open}
|
|
971
985
|
return applied},initializeState(){if(this.initialState?.facets)this.facetOpen=this.initialState.facets.open;const ready=FACET_STATE.init.call(this);return this.view.facets||this.opts.facets?Promise.all([ready,this.loadFacets().catch(error=>this.emit("error",{error}))]).then(([result])=>result):ready}});const GRID_FORMAT=definePart(DataGrid,"formatting","conditional formatting",()=>({DataGrid,h,setText,setClass,fill,gridFreeze,gridDateInputMoment,cellValue,cellText,foldText,toneOf,numberFormat,gridButton,gridOption,gridInputLabel,gridIcon,gridDecorateButton,GRID_REPORTING,loadPart,definePart,announceMenu,boundedPattern,wildcardMatch,svgIcon}));Object.assign(DataGrid.prototype,{loadFormatting(){return this.formatLoad||=loadPart(GRID_FORMAT).then(()=>this.startFormatting(),error=>{this.formatLoad=null;throw error})},setFormatRules(rules){return this.loadFormatting().then(()=>this.setFormatRules(rules))},validateFormatRules(rules){return this.loadFormatting().then(()=>this.validateFormatRules(rules))},openFormatRules(){return this.loadFormatting().then(()=>this.openFormatRules())},getFormatRules(){return gridFreeze(JSON.parse(JSON.stringify(this.formatRules||this.view.formatRules||[])))}});DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridLiveOrderChanged:"Order changed",gridLiveResort:"Re-sort",gridLiveNewData:"New data",gridLiveRefresh:"Refresh",gridLiveOrderHint:"Rows keep their places while data changes. Re-sort to move them where the sort puts them.",gridLiveChanged:"Rows changed: {added} added, {updated} updated, {removed} removed",gridLiveSorted:"Rows moved to their sorted places.",gridLiveRecordRemoved:"This record was removed."}));const GRID_LIVE=definePart(DataGrid,"live","live data",()=>({DataGrid,h,setText,fill,gridButton,gridIcon,gridQuery,gridResultShape,gridQueryRows,gridCompare,gridOrder,gridIdOrder,validateGridRows,validateGridPage,validateGridCursorPage,gridFreeze,requireIdentifier,checkDocument,cellValue,PROTOCOL,GRID_REPORTING,VIEW_MODES,inlineGridSource}));const GRID_LIVE_API=["applyTransaction","addRows","updateRows","removeRows","setRows","flushTransactions","refreshRows","resort","poll"];for(const name of GRID_LIVE_API)DataGrid.prototype[name]=function(...args){return this.loadLive().then(()=>this[name](...args))};Object.assign(DataGrid.prototype,{loadLive(){if(this.view.rowIdentity==="ordinal")return Promise.reject(new Error("CanopyX: ordinal row identity is snapshot-local; keyed live updates require stable row keys."));return this.liveLoad||=loadPart(GRID_LIVE).then(()=>this.destroyed||this.startLive()).catch(error=>{this.liveLoad=null;throw error})},getLiveState(){return this.liveStatus?this.liveStatus():gridFreeze({orderChanged:false,newData:false,pending:0,polling:false,revision:this.snapshot?.revision??null})}});const GRID_LIVE_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_LIVE_INIT.call(this);return this.view.live&&this.opts.live!==false||this.opts.live?Promise.all([ready,this.loadLive().catch(error=>this.emit("error",{error}))]).then(([result])=>result):ready};const GRID_PAGER_IMPL={},GRID_PAGER=definePart(DataGrid,"pager","pager controls",()=>({DataGrid,GRID_PAGER_IMPL,h,setText,fill,gridButton,gridOption,numberFormat,gridCountLabel}));const GRID_PAGER_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_PAGER_INIT.call(this);return!this.pager||!this.view.pager||GRID_PAGER_IMPL.installed?ready:Promise.all([ready,loadPart(GRID_PAGER).then(()=>this.destroyed||this.buildPager())
|
|
972
|
-
.catch(error=>{this.pager.hidden=this.opts.toolbar===false;this.emit("error",{error})})]).then(([result])=>result)};DataGrid.prototype.parts["record-panel"]=RECORD_PART;RECORD_IMPL.grid={DataGrid,gridCellRenderer,createDataGrid,gridFreeze,gridQuery,gridResultShape,validatePresenter:gridPresenter};DataGrid.prototype.openRecord=TreeGrid.prototype.openRecord;DataGrid.prototype.loadRecordPanel=function(){return this.recordLoad||=loadRecordPanel().then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.recordNeeded=function(row){return!!this.view.record||this.columns.some(column=>column.presenter?.kind==="structured")||
|
|
986
|
+
.catch(error=>{this.pager.hidden=this.opts.toolbar===false;this.emit("error",{error})})]).then(([result])=>result)};const PRESENTERS_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=PRESENTERS_INIT.call(this);return[...this.columns,...(this.view.record?.fields||[])].some(column=>column.presenter||column.wrap)?Promise.all([ready,this.loadPresenters()]).then(([result])=>result):ready};DataGrid.prototype.parts["record-panel"]=RECORD_PART;RECORD_IMPL.grid={DataGrid,gridCellRenderer,createDataGrid,gridFreeze,gridQuery,gridResultShape,validatePresenter:gridPresenter};DataGrid.prototype.openRecord=TreeGrid.prototype.openRecord;DataGrid.prototype.loadRecordPanel=function(){return this.recordLoad||=loadRecordPanel().then(()=>{this.version++;this.scheduleRender()},error=>this.emit("error",{error}))};DataGrid.prototype.recordNeeded=function(row){return!!this.view.record||this.columns.some(column=>column.presenter?.kind==="structured")||
|
|
973
987
|
!!row&&Object.values(row.cells).some(cell=>isCellObject(cell)&&RECORD_STRUCTURE.some(name=>cell[name]!==undefined))};const GRID_RECORD_INIT=DataGrid.prototype.initializeState;DataGrid.prototype.initializeState=function(){const ready=GRID_RECORD_INIT.call(this);return this.columns.some(column=>column.presenter?.kind==="structured")?Promise.all([ready,this.loadRecordPanel()]).then(([result])=>result):ready};const GRID_DATA_IMPL={},GRID_DATA=definePart(DataGrid,"data","row data",()=>({GRID_DATA_IMPL,PROTOCOL,validateGridRows,inlineGridSource,loadSidecar,gridIdOrder}));function rowDataSource(grid){let inner=null;const source={reset:()=>{inner=null},query:(query,options)=>
|
|
974
988
|
(inner||=loadPart(GRID_DATA).then(()=>GRID_DATA_IMPL.source(grid,source)).catch(error=>{inner=null;throw error})).then(rows=>rows.query(query,options))};return source}
|
|
975
989
|
class MatrixHost{}
|
|
@@ -1000,7 +1014,7 @@ this.runGridHook(signal=>this.opts.onChart({query:this.getQuery(),selection:this
|
|
|
1000
1014
|
{kind:"ids",ids:[...this.selected],revision:this.snapshot?.revision},signal}),this.dataLifetime.signal))),"chart",true));const clear=gridDecorateButton(gridButton("",()=>this.setSelection([])),"close",true);clear.classList.add("icon");clear.setAttribute("aria-label",this.labels.gridClearSelection);this.selectionBar.appendChild(clear);this.toolbarSeparator=h("span","cx-sep");const overflow=this.overflow=this.controlPanel(this.labels.gridMore,"cx-grid-overflow");const summary=overflow.details.firstChild;summary.replaceChildren(gridIcon("more"));summary.classList.add("icon");summary.setAttribute("aria-label",this.labels.gridMore);for(const action of[...this.opts.actions||[],...pluginItems(this,"menuItems")])overflow.panel.appendChild(this.gridAction(action,act));overflow.panel.append(this.toolbar.querySelector(".cx-grid-details"),this.toolbar.querySelector(".cx-grid-print")||
|
|
1001
1015
|
Object.assign(gridButton(this.labels.gridPrint,()=>global.print()),{className:"cx-button cx-grid-print"}));(this.toolbar.querySelector(".cx-grid-export")||overflow.details).before(this.spacer,this.selectionBar,this.toolbarSeparator);for(const item of pluginItems(this,"toolbarItems"))this.spacer.before(this.gridAction(item,act));if(this.tools.more===false){overflow.details.remove();this.overflow=null}
|
|
1002
1016
|
this.host.addEventListener("canopyx:select",()=>this.syncGridChrome(),{signal});this.syncGridChrome();signal.addEventListener("abort",()=>{this.headerSelectionFlyout?.dispose();this.headerMenusLifetime?.abort();this.closeGridPopover(false)},{once:true})},syncGridChrome(){if(!this.selectionBar)return;const count=this.querySelection?this.querySelection.matched===null?null:Math.max(0,this.querySelection.matched-this.selectionExcluded.size):this.selected.size;const selected=count===null||count>0;this.selectionBar.hidden=!selected;this.toolbarSeparator.hidden=!selected;this.host.classList.toggle("cx-has-selection",selected);gridCountLabel(this.selectedCount,count===null?this.labels.gridSelectionQueryUnknown:this.labels.gridSelectionCount,{count:numberFormat(this.lang).format(count),excluded:String(this.selectionExcluded?.size||0)});const filterSummary=this.toolbar.querySelector(".cx-grid-filters > summary"),active=gridFilterCount(this.acceptedQuery);if(filterSummary){filterSummary.classList.toggle("active",!!active);filterSummary.querySelector(".badge")?.remove();if(active){const badge=h("span","badge");setText(badge,String(active));filterSummary.appendChild(badge)}}
|
|
1003
|
-
for(const button of this.selectionBar.querySelectorAll("button"))button.disabled=!!this.pendingQuery||!this.acceptedQuery;this.syncGridStatus?.()},updateGridPhone(){const phone=this.host.clientWidth<=640,
|
|
1017
|
+
for(const button of this.selectionBar.querySelectorAll("button"))button.disabled=!!this.pendingQuery||!this.acceptedQuery;this.syncGridStatus?.()},updateGridPhone(){const phone=this.host.clientWidth<=640,mode=this.layoutMode||"fit",autoRows=mode!=="cards"&&(this.authoredAutoRows||phone&&mode==="fit");this.host.classList.toggle("cx-phone",phone);if(phone===this.phone&&autoRows===this.autoRows)return;const anchor=this.gridRowAnchor();const changedRows=autoRows!==this.autoRows;this.phone=phone;this.autoRows=autoRows;if(changedRows){this.rowOffsets=null;this.rowHeights?.clear()}
|
|
1004
1018
|
this.rowWidthShape=null;if(!this.autoRows&&!this.rowProjection){const bounds=this.rowBounds();this.total=Math.max(0,bounds.last-bounds.first+1)*this.rowH;this.syncScrollRange(this.rowTop(anchor.index)+ Math.min(anchor.offset,this.rowH-1))}
|
|
1005
1019
|
this.version++;this.scheduleRender();this.placeMenus(phone);this.syncPinnedShadows()},syncPinnedShadows(){const overflow=this.grid.scrollWidth>this.grid.clientWidth+1,pins=overflow&&(this.pinnedLeftWidth||this.pinnedRightWidth);this.host.classList.toggle("cx-scroll-x",overflow);this.host.classList.toggle("cx-scroll-left",!!pins&&this.grid.scrollLeft>0);this.host.classList.toggle("cx-scroll-right",!!pins&&this.grid.scrollLeft+this.grid.clientWidth<this.grid.scrollWidth-1)},gridAction(action,act){if(!action||typeof action.label!=="string"||typeof action.run!=="function")throw new Error("CanopyX: actions need a label and handler.");return gridButton(action.label,()=>act(()=>this.runGridHook(signal=>action.run({query:this.getQuery(),signal,api:this.host.canopyx}),this.dataLifetime.signal)))}});function gridColumnFiltered(query,id){const has=group=>group&&(group.filters.some(item=>item.column===id)||group.groups.some(has));return!!query&&(query.filters.some(item=>item.column===id)||!!has(query.filterGroup))}
|
|
1006
1020
|
function gridColumnProjection(query,id){const project=group=>{if(!group)return undefined;const filters=group.filters.filter(item=>item.column!==id),groups=group.groups.map(project);if(group.operator==="or"&&(filters.length!==group.filters.length||groups.some(child=>!child)))return undefined;const children=groups.filter(Boolean);return filters.length||children.length?{operator:group.operator,filters,groups:children}:undefined};return{...query,filters:(query.filters||[]).filter(item=>item.column!==id),filterGroup:project(query.filterGroup)}}
|
|
@@ -1009,7 +1023,7 @@ if(this.gridPopover)this.gridPopover.position()}});const GRID_PIN_PREPARE=DataGr
|
|
|
1009
1023
|
let start=0,end=0;for(const column of grid.cols){column.pinOffset=column.effectivePin==="left"?start:0;if(column.effectivePin==="left")start+=width(column)}
|
|
1010
1024
|
for(const column of[...grid.cols].reverse())if(column.effectivePin==="right"){column.pinOffset=end;end+=width(column)}
|
|
1011
1025
|
grid.pinnedLeftWidth=start;grid.pinnedRightWidth=end;grid.host.classList.toggle("cx-pins",used>0);grid.cols.forEach((column,index)=>grid.applyColumnPin(grid.headCells[index],column));for(const row of[...grid.rendered.values(),...grid.pool])if(row._kind==="node")grid.cols.forEach((column,index)=>{if(row.children[index])grid.applyColumnPin(row.children[index],column)})}
|
|
1012
|
-
DataGrid.prototype.prepareState=function(){gridFitPrepare(this);return GRID_PIN_PREPARE.call(this)};DataGrid.prototype.applyWidths=function(widths){GRID_PIN_WIDTHS.call(this,widths);if(!this.view.reporting)gridPinGeometry(this);this.syncPinnedShadows()};DataGrid.prototype.applyColumnPin=function(cell,column){const pin=column.effectivePin||"none";if(pin==="none")cell.removeAttribute("data-cx-pin");else cell.dataset.cxPin=pin;cell.style.left=pin==="left"?column.pinOffset+"px":"";cell.style.right=pin==="right"?column.pinOffset+"px":"";const side=pin==="left"?this.cols.filter(item=>item.effectivePin==="left").at(-1):this.cols.find(item=>item.effectivePin==="right");cell.classList.toggle("cx-pin-edge",side===column)};DataGrid.prototype.newCell=function(index,width,kind){const cell=GRID_PIN_CELL.call(this,index,width,kind);if(kind&&this.cols[index])this.applyColumnPin(cell,this.cols[index]);return cell};DataGrid.prototype.setColumnPinned=function(id,pin){const column=this.columns.find(item=>item.id===id);if(!column||!["none","left","right"].includes(pin)||this.destroyed)throw new Error("CanopyX: invalid column pin.");column.pin=pin;this.columns=["left","none","right"].flatMap(side=>this.columns.filter(item=>(item.pin||"none")===side));this.buildHeader();this.render();this.syncColumnControls();this.stateChanged();this.emit("columnPin",{column:id,pin})};const GRID_PIN_STATE_COLUMN=gridStateColumn,GRID_PIN_STATE_COLUMNS=gridStateColumns;gridStateColumn=column=>({...GRID_PIN_STATE_COLUMN(column),pin:column.pin||"none"});gridStateColumns=(grid,input)=>{const result=GRID_PIN_STATE_COLUMNS(grid,input),sources=new Map(input.map(column=>[column.id,column]));for(const saved of result){const pin=sources.get(saved.id)?.pin??saved.pin??"none";if(!["none","left","right"].includes(pin))throw new Error("CanopyX: invalid saved pin.");saved.pin=pin}return result};const FILTER_EDITOR=definePart(DataGrid,"filter-editor","filter editor",()=>({DataGrid,h,setText,gridButton,gridInputLabel,gridOption,gridScalar,gridDateInputMoment,gridQuery,gridQueryStart,GRID_FILTER_LABELS,gridResultShape,gridQueryRows,gridOrder,gridColumnProjection,gridCellRenderer,cellValue,cellText,foldText,reachable,gridMatchesGroup,gridDecorateButton,gridIcon,numberFormat,numberText,fill,announceMenu,applyTone,toneOf,badgeElement,isCellObject,RECORD_IMPL,GRID_REPORTING,reportingRangeRows:typeof reportingRangeRows==="function"?reportingRangeRows:null}));function loadGridFilterEditor(){return loadPart(FILTER_EDITOR)}
|
|
1026
|
+
DataGrid.prototype.prepareState=function(){gridFitPrepare(this);return GRID_PIN_PREPARE.call(this)};DataGrid.prototype.applyWidths=function(widths){GRID_PIN_WIDTHS.call(this,widths);if(!this.view.reporting)gridPinGeometry(this);this.syncPinnedShadows()};DataGrid.prototype.applyColumnPin=function(cell,column){const pin=column.effectivePin||"none";if(pin==="none")cell.removeAttribute("data-cx-pin");else cell.dataset.cxPin=pin;cell.style.left=pin==="left"?column.pinOffset+"px":"";cell.style.right=pin==="right"?column.pinOffset+"px":"";const side=pin==="left"?this.cols.filter(item=>item.effectivePin==="left").at(-1):this.cols.find(item=>item.effectivePin==="right");cell.classList.toggle("cx-pin-edge",side===column)};DataGrid.prototype.newCell=function(index,width,kind){const cell=GRID_PIN_CELL.call(this,index,width,kind);if(kind&&this.cols[index])this.applyColumnPin(cell,this.cols[index]);return cell};DataGrid.prototype.setColumnPinned=function(id,pin){const column=this.columns.find(item=>item.id===id);if(!column||!["none","left","right"].includes(pin)||this.destroyed)throw new Error("CanopyX: invalid column pin.");column.pin=pin;this.columns=["left","none","right"].flatMap(side=>this.columns.filter(item=>(item.pin||"none")===side));this.buildHeader();this.render();this.syncColumnControls();this.stateChanged();this.emit("columnPin",{column:id,pin})};const GRID_PIN_STATE_COLUMN=gridStateColumn,GRID_PIN_STATE_COLUMNS=gridStateColumns;gridStateColumn=column=>({...GRID_PIN_STATE_COLUMN(column),pin:column.pin||"none"});gridStateColumns=(grid,input)=>{const result=GRID_PIN_STATE_COLUMNS(grid,input),sources=new Map(input.map(column=>[column.id,column]));for(const saved of result){const pin=sources.get(saved.id)?.pin??saved.pin??"none";if(!["none","left","right"].includes(pin))throw new Error("CanopyX: invalid saved pin.");saved.pin=pin}return result};const FILTER_EDITOR=definePart(DataGrid,"filter-editor","filter editor",()=>({DataGrid,h,setText,gridButton,gridInputLabel,gridOption,gridScalar,gridDateInputMoment,gridQuery,gridQueryStart,GRID_FILTER_LABELS,gridResultShape,gridQueryRows,gridOrder,gridKeyCompare,gridFacetKey,columnNumericTone,columnValueTone,gridColumnProjection,gridCellRenderer,cellValue,cellText,foldText,reachable,gridMatchesGroup,gridDecorateButton,gridIcon,numberFormat,numberText,fill,announceMenu,applyTone,toneOf,badgeElement,isCellObject,RECORD_IMPL,GRID_REPORTING,reportingRangeRows:typeof reportingRangeRows==="function"?reportingRangeRows:null}));function loadGridFilterEditor(){return loadPart(FILTER_EDITOR)}
|
|
1013
1027
|
DataGrid.prototype.requirePart=requirePart;Object.assign(DataGrid.prototype,{buildGridFilters(){this.reportingFacetStops=new Set();this.reportingFacetSequence=0;if(this.tools.filters===false||!this.columns.some(column=>column.filterable!==false))return;this.reportingFilters=this.controlPanel(this.labels.gridFilters,"cx-grid-filters",panel=>this.renderGridFilters(panel))},async renderGridFilters(panel){const epoch=this.queryEpoch;setText(panel,this.labels.loading);try{await loadGridFilterEditor();if(epoch!==this.queryEpoch){panel.parentElement.open=false;return}if(!this.destroyed&&panel.isConnected&&panel.parentElement.open){this.renderGridFilters(panel);this.controlFlyouts.forEach(item=>item.position())}}
|
|
1014
1028
|
catch(error){if(!this.destroyed&&panel.isConnected){setText(panel,this.labels.gridLoadFailed);panel.appendChild(gridButton(this.labels.gridRetry,()=>this.renderGridFilters(panel)));this.emit("error",{error})}}},async showReportingText(...args){const epoch=this.queryEpoch;try{await loadGridFilterEditor();if(!this.destroyed&&epoch===this.queryEpoch)this.showReportingText(...args)}catch(error){this.emit("error",{error})}},});for(const method of["openColumnMenu","openColumnFilter"])DataGrid.prototype[method]=async function(id,anchor){try{await loadGridFilterEditor();if(!this.destroyed)this[method](id,anchor?.isConnected?anchor:this.headRow.querySelector('[data-cx-column-menu="'+CSS.escape(id)+'"]'))}
|
|
1015
1029
|
catch(error){this.setNotice(this.labels.gridLoadFailed,true);this.emit("error",{error})}};function gridOperationActive(grid,signal){if(grid.destroyed||signal?.aborted)throw new DOMException("Grid cancelled.","AbortError")}
|
|
@@ -1019,7 +1033,7 @@ const prepared=grid.calIcsFormatWriter&&provider?.write===grid.calIcsFormatWrite
|
|
|
1019
1033
|
const gridExportSignal=(signal,options)=>AbortSignal.any([signal,options?.signal].filter(Boolean));Object.assign(DataGrid.prototype,{defaultExportColumns(){return this.visibleColumns().filter(column=>column.exportable!==false)},prepareExport(options){if(!this.view.reporting&&["fileName","locale","timeZone","onProgress"].some(key=>options?.[key]!==undefined))
|
|
1020
1034
|
throw new Error("CanopyX: export metadata requires reporting.");if(this.destroyed||!this.acceptedQuery)throw new Error("CanopyX: export needs an accepted query.");if(!options||!["filtered","selected","all"].includes(options.scope))throw new Error("CanopyX: explicit export scope required.");const{scope,values,signal}=options,filtered=scope==="filtered";const selection=scope==="selected"?[...this.selected]:[];const columnIds=options.columns===undefined?this.defaultExportColumns().map(column=>column.id):options.columns;if(options.columns===undefined&&!columnIds.length)throw new Error(this.labels.gridNoExportColumns);const columns=Array.isArray(columnIds)?columnIds.map(id=>this.columns.find(column=>column.id===id)):[];if(!Array.isArray(columnIds)||!columnIds.length||new Set(columnIds).size!==columnIds.length||
|
|
1021
1035
|
columns.some(column=>!column||column.exportable===false))throw new Error("CanopyX: invalid or unsupported export columns.");if(values!==undefined&&!["raw","display"].includes(values))throw new Error("CanopyX: export values must be raw/display.");if(signal!==undefined&&!(signal instanceof AbortSignal))throw new Error("CanopyX: export requires AbortSignal.");const query=gridQuery(this.view,{...this.acceptedQuery,offset:0,cursor:undefined,limit:this.pageSize,search:filtered?this.acceptedQuery.search:"",filterGroup:filtered?this.acceptedQuery.filterGroup:undefined,filters:filtered?this.acceptedQuery.filters:[]});const{revision,total,matched}=this.snapshot;const request=gridFreeze({scope,query,revision,total,matched,recordCount:scope==="selected"?selection.length:
|
|
1022
|
-
filtered?matched:total,selection,columns:columns.map(({id,title,kind,format})=>({id,title,kind,...(format?{format:{...format}}:{})})),presentation:GRID_REPORTING.exportRecord?"semantic":"text",values:values||"display",timeZone:this.local?"local":"utc",...GRID_REPORTING.exportRequest?.(this,options)});return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})}});DataGrid.drawerHooks=[];DataGrid.activeDrawers=new Map();DataGrid.applyDrawerHooks=(grid,dialog)=>{const applied=dialog._cxDrawerHooks||=new Set();for(const entry of DataGrid.drawerHooks)if(!applied.has(entry)){applied.add(entry);try{entry.hook.call(grid,dialog)}catch(error){grid.emit("error",{error})}}};DataGrid.refreshDrawerHooks=(grid,dialog)=>{if(dialog._cxHooksFrame)return;dialog._cxHooksFrame=requestAnimationFrame(()=>{dialog._cxHooksFrame=0;if(grid.destroyed||!dialog.isConnected)return;DataGrid.applyDrawerHooks(grid,dialog);if(dialog._cxRecord)dialog.dispatchEvent(new CustomEvent("cx-drawer-paint",{detail:{id:dialog._cxRecord.id,index:dialog._cxIndex??null}}))})};DataGrid.drawerHook=(order,hook)=>{DataGrid.drawerHooks.push({order,hook});DataGrid.drawerHooks.sort((a,b)=>a.order-b.order);for(const[dialog,grid]of DataGrid.activeDrawers)DataGrid.refreshDrawerHooks(grid,dialog)};Object.assign(DataGrid.prototype,{focusRing:focusDrawerTitle,scrollToRow(index){if(this.destroyed||!this.acceptedQuery||this.pendingQuery||!Number.isInteger(index)||
|
|
1036
|
+
filtered?matched:total,selection,columns:columns.map(({id,title,kind,format,valueLabels})=>({id,title,kind,...(valueLabels?{valueLabels:{...valueLabels}}:{}),...(format?{format:{...format}}:{})})),presentation:GRID_REPORTING.exportRecord?"semantic":"text",values:values||"display",timeZone:this.local?"local":"utc",...GRID_REPORTING.exportRequest?.(this,options)});return Object.freeze({request,rows:options=>this.exportRows(request,gridExportSignal(signal,options))})}});DataGrid.drawerHooks=[];DataGrid.activeDrawers=new Map();DataGrid.applyDrawerHooks=(grid,dialog)=>{const applied=dialog._cxDrawerHooks||=new Set();for(const entry of DataGrid.drawerHooks)if(!applied.has(entry)){applied.add(entry);try{entry.hook.call(grid,dialog)}catch(error){grid.emit("error",{error})}}};DataGrid.refreshDrawerHooks=(grid,dialog)=>{if(dialog._cxHooksFrame)return;dialog._cxHooksFrame=requestAnimationFrame(()=>{dialog._cxHooksFrame=0;if(grid.destroyed||!dialog.isConnected)return;DataGrid.applyDrawerHooks(grid,dialog);if(dialog._cxRecord)dialog.dispatchEvent(new CustomEvent("cx-drawer-paint",{detail:{id:dialog._cxRecord.id,index:dialog._cxIndex??null}}))})};DataGrid.drawerHook=(order,hook)=>{DataGrid.drawerHooks.push({order,hook});DataGrid.drawerHooks.sort((a,b)=>a.order-b.order);for(const[dialog,grid]of DataGrid.activeDrawers)DataGrid.refreshDrawerHooks(grid,dialog)};Object.assign(DataGrid.prototype,{focusRing:focusDrawerTitle,scrollToRow(index){if(this.destroyed||!this.acceptedQuery||this.pendingQuery||!Number.isInteger(index)||
|
|
1023
1037
|
index<(this.cursor?this.pageOffset:0)||index>=this.rowCount())
|
|
1024
1038
|
throw new Error("CanopyX: invalid accepted row position.");return this.focusResult(index,false)},async runGridHook(run,signal,timeout=this.requestTimeoutMs){const controller=new AbortController();let rejectHook;const cancelled=new Promise((resolve,reject)=>{rejectHook=reject});const abort=()=>{controller.abort();rejectHook(new DOMException("Grid cancelled.","AbortError"))};this.lifetime.signal.addEventListener("abort",abort,{once:true});signal?.addEventListener("abort",abort,{once:true});const timer=setTimeout(()=>{controller.abort();rejectHook(new Error("CanopyX: operation timed out."))},timeout);try{if(this.destroyed||signal?.aborted)abort();return await Promise.race([Promise.resolve().then(()=>{gridOperationActive(this,controller.signal);return run(controller.signal)}),cancelled])}finally{clearTimeout(timer);controller.abort();this.lifetime.signal.removeEventListener("abort",abort);signal?.removeEventListener("abort",abort)}},openDetails(id){requireIdentifier(id,"detail row ID");if(this.destroyed||!this.acceptedQuery||this.pendingQuery)
|
|
1025
1039
|
throw new Error("CanopyX: details require an accepted query.");const row=[...this.rowCache.values()].find(item=>item.key===id);if(!row)throw new Error("CanopyX: details require a loaded record.");if(typeof this.opts.onDetails!=="function"){const epoch=this.queryEpoch,returnFocus=document.activeElement;return Promise.all([loadGridFilterEditor(),this.recordNeeded(row.h)&&loadRecordPanel()]).then(()=>{if(!this.destroyed&&!this.pendingQuery&&epoch===this.queryEpoch)this.openGridDrawer(row.h,row._ri,returnFocus)})}
|
|
@@ -1185,7 +1199,7 @@ throw new Error("CanopyX: reporting selection controls need an enabled selection
|
|
|
1185
1199
|
throw new Error("CanopyX: durable reporting preferences need session/local storage and an explicit bounded state key.");if(options.facetColumns!==undefined&&(!Array.isArray(options.facetColumns)||
|
|
1186
1200
|
new Set(options.facetColumns).size!==options.facetColumns.length||options.facetColumns.some(id=>!view.columns.some(column=>column?.id===id))))
|
|
1187
1201
|
throw new Error("CanopyX: facets need unique declared column identities.");if(options.ordering===undefined)return;if(!options.ordering||typeof options.ordering!=="object"||Array.isArray(options.ordering))
|
|
1188
|
-
throw new Error("CanopyX: reporting ordering is keyed by column identity.");for(const[id,policy]of Object.entries(options.ordering)){const column=view.columns.find(item=>item&&item.id===id);if(!column||column.kind!=="text"||!column.sortable)throw new Error("CanopyX: ordering needs a sortable text column.");reportingTextOrder(policy)}};GRID_REPORTING.compare=view=>{const policies=new Map(Object.entries(view.reporting&&view.reporting.ordering||{}).map(([id,policy])=>[id,reportingTextOrder(policy)]));if(!policies.size)return gridCompare;return(left,right,column,direction)=>{const compare=policies.get(column.id);if(!compare)return gridCompare(left,right,column,direction);const a=gridScalar(left.cells[column.id],column),b=gridScalar(right.cells[column.id],column);if(a===null||b===null)return a===b?0:a===null?1:-1;const result=compare(String(a),String(b));return direction==="desc"?-result:result}};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridPinColumn:"{column}: pinned region",gridPinNone:"Scroll",gridFilterGroupTitle:"Additional grouped conditions",gridAddFilterGroup:"Add condition group",gridFacetValues:"Values and counts from applied filters",gridFacetIncludeCurrent:"Include this column's applied filters",gridFacetLoad:"Load values",gridFacetReload:"Values changed or the request was cancelled. Load values again.",gridBetween:"between (inclusive)",gridRangeEnd:"Upper value (UTC for dates)",gridInvalidRange:"Enter an upper value greater than or equal to the lower value.",gridSuggestedCategory:"Suggested category",gridChooseCategory:"Choose a category",gridBooleanValue:"Boolean value",gridHealthy:"Healthy",gridValue:"Value (UTC for dates)",gridAddFilter:"Add filter",gridMoveEarlier:"Move {column} earlier",gridMoveLater:"Move {column} later",gridFitColumn:"Fit {column}"}));function reportingRangeRows(filters){const rows=[];for(let index=0;index<filters.length;index++){const lower=filters[index],upper=filters[index+1];if(lower.operator==="ge"&&upper&&upper.operator==="le"&&lower.column===upper.column){rows.push({column:lower.column,operator:"between",values:[lower.values[0],upper.values[0]]});index++}else rows.push(lower)}
|
|
1202
|
+
throw new Error("CanopyX: reporting ordering is keyed by column identity.");for(const[id,policy]of Object.entries(options.ordering)){const column=view.columns.find(item=>item&&item.id===id);if(!column||column.kind!=="text"||!column.sortable)throw new Error("CanopyX: ordering needs a sortable text column.");reportingTextOrder(policy)}};GRID_REPORTING.compare=view=>{const policies=new Map(Object.entries(view.reporting&&view.reporting.ordering||{}).map(([id,policy])=>[id,reportingTextOrder(policy)]));if(!policies.size)return gridCompare;return(left,right,column,direction)=>{const compare=policies.get(column.id);if(!compare||column.valueOrder?.length)return gridCompare(left,right,column,direction);const a=gridScalar(left.cells[column.id],column),b=gridScalar(right.cells[column.id],column);if(a===null||b===null)return a===b?0:a===null?1:-1;const result=compare(String(a),String(b));return direction==="desc"?-result:result}};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAULT_LABELS,{gridPinColumn:"{column}: pinned region",gridPinNone:"Scroll",gridFilterGroupTitle:"Additional grouped conditions",gridAddFilterGroup:"Add condition group",gridFacetValues:"Values and counts from applied filters",gridFacetIncludeCurrent:"Include this column's applied filters",gridFacetLoad:"Load values",gridFacetReload:"Values changed or the request was cancelled. Load values again.",gridBetween:"between (inclusive)",gridRangeEnd:"Upper value (UTC for dates)",gridInvalidRange:"Enter an upper value greater than or equal to the lower value.",gridSuggestedCategory:"Suggested category",gridChooseCategory:"Choose a category",gridBooleanValue:"Boolean value",gridHealthy:"Healthy",gridValue:"Value (UTC for dates)",gridAddFilter:"Add filter",gridMoveEarlier:"Move {column} earlier",gridMoveLater:"Move {column} later",gridFitColumn:"Fit {column}"}));function reportingRangeRows(filters){const rows=[];for(let index=0;index<filters.length;index++){const lower=filters[index],upper=filters[index+1];if(lower.operator==="ge"&&upper&&upper.operator==="le"&&lower.column===upper.column){rows.push({column:lower.column,operator:"between",values:[lower.values[0],upper.values[0]]});index++}else rows.push(lower)}
|
|
1189
1203
|
return rows}
|
|
1190
1204
|
function reportingRangeValue(raw,column,labels,local){if(column.kind==="number"){if(!raw.trim())throw new Error(labels.gridInvalidFilter);const value=Number(raw);gridScalar(value,column);return value}
|
|
1191
1205
|
let value=raw;if(!/(?:Z|[+-]\d\d:\d\d)$/.test(raw)) {
|
|
@@ -1198,7 +1212,7 @@ fields.input.closest("label").hidden=!booleanField.hidden||["isNull","isNotNull"
|
|
|
1198
1212
|
original.values[index]:reportingRangeValue(raw,column,this.labels,this.local));if(gridScalar(values[0],column)>gridScalar(values[1],column))throw new Error(this.labels.gridInvalidRange);return[{column:column.id,operator:"ge",values:[values[0]]},{column:column.id,operator:"le",values:[values[1]]}]}})};function reportingColumnFiltered(query,id){return gridColumnFiltered(query,id)}
|
|
1199
1213
|
DataGrid.prototype.syncReportingFilterHeaders=function(){};DataGrid.prototype.openReportingColumnFilter=function(id){return this.openColumnFilter(id,this.headRow.querySelector('[data-cx-filter-column="'+CSS.escape(id)+'"]:not([hidden]),[data-cx-column-menu="'+CSS.escape(id)+'"]'))};DataGrid.prototype.focusReportingFilterHeader=function(){this.headRow.querySelector('[data-cx-filter-column="'+CSS.escape(this.reportingFilterReturn||"")+'"]:not([hidden]),[data-cx-column-menu="'+CSS.escape(this.reportingFilterReturn||"")+'"]')?.focus({preventScroll:true})};const reportingFacetKey=gridFacetKey;const reportingFacetPage=(input,grid,request)=>validateGridFacetPage(input,grid.view,request,grid.snapshot);const reportingFacetProjection=(query,column)=>gridColumnProjection(query,column);const FACET_INLINE_SOURCE=inlineGridSource;inlineGridSource=view=>{const source=FACET_INLINE_SOURCE(view);if(!view.reporting?.facetColumns?.length)return source;const columns=new Map(view.columns.map(column=>[column.id,column]));source.facet=(request,options)=>{if(options.signal.aborted)throw new DOMException("Facet request cancelled.","AbortError");const column=view.columns.find(item=>item.id===request.column),query=request.includeCurrentFilter?request.query:
|
|
1200
1214
|
reportingFacetProjection(request.query,column.id);const rows=gridQueryRows(view,query,columns,false),buckets=new Map(),needle=foldText(request.search);for(const row of rows){const scalar=gridScalar(row.cells[column.id],column),value=column.kind==="datetime"&&scalar!==null?new Date(scalar).toISOString():scalar;const key=reportingFacetKey(value,column),existing=buckets.get(key);if(existing){existing.count++;if(typeof value==="string"&&value<existing.value)existing.value=value}else buckets.set(key,{value,count:1})}
|
|
1201
|
-
const items=[...buckets.values()].filter(item=>foldText(item.value).includes(needle));items.sort((a,b)=>{if(a.value===null||b.value===null)return a.value===b.value?0:a.value===null?1:-1;if(column.kind!=="text")return gridOrder(gridScalar(a.value,column),gridScalar(b.value,column));if(typeof a.value!==typeof b.value)return typeof a.value==="boolean"?-1:1;return gridOrder(typeof a.value==="string"?foldText(a.value):a.value,typeof b.value==="string"?foldText(b.value):b.value)});return{protocol:PROTOCOL,type:"gridFacetPage",view:view.id,revision:"inline",column:column.id,search:request.search,includeCurrentFilter:request.includeCurrentFilter,matched:rows.length,totalValues:items.length,truncated:items.length>request.limit,items:items.slice(0,request.limit)}};return source};const LAYOUT_VALIDATE=GRID_REPORTING.validate,LAYOUT_PREPARE=DataGrid.prototype.prepareState;GRID_REPORTING.api=(api,grid)=>{api.autoFitColumn=id=>GRID_REPORTING.fitColumn(grid,id)};function reportingLayout(grid,column){const declared=column.kind?column:grid.columns.find(item=>item.id===column.id)||column,policy=grid.columnLayouts.get(column.id)||{};return{minimum:declared.minWidth??policy.minimum??40,maximum:declared.maxWidth??policy.maximum??MAX_COLUMN_WIDTH,flex:declared.flexWeight??(typeof declared.flex==="number"?declared.flex:policy.flex||0),priority:declared.priority===undefined?policy.priority:gridRank(declared),alwaysVisible:declared.alwaysVisible??policy.alwaysVisible,pin:declared.pinned===undefined?policy.pin:declared.pinned||"none"}}
|
|
1215
|
+
const items=[...buckets.values()].filter(item=>foldText(cellText(item.value,column,formatting(undefined,false,DEFAULT_LABELS))).includes(needle));items.sort((a,b)=>{if(a.value===null||b.value===null)return a.value===b.value?0:a.value===null?1:-1;if(column.kind!=="text")return gridOrder(gridScalar(a.value,column),gridScalar(b.value,column));if(column.valueOrder?.length)return gridKeyCompare(a.value,b.value,column,"asc");if(typeof a.value!==typeof b.value)return typeof a.value==="boolean"?-1:1;return gridOrder(typeof a.value==="string"?foldText(a.value):a.value,typeof b.value==="string"?foldText(b.value):b.value)});return{protocol:PROTOCOL,type:"gridFacetPage",view:view.id,revision:"inline",column:column.id,search:request.search,includeCurrentFilter:request.includeCurrentFilter,matched:rows.length,totalValues:items.length,truncated:items.length>request.limit,items:items.slice(0,request.limit)}};return source};const LAYOUT_VALIDATE=GRID_REPORTING.validate,LAYOUT_PREPARE=DataGrid.prototype.prepareState;GRID_REPORTING.api=(api,grid)=>{api.autoFitColumn=id=>GRID_REPORTING.fitColumn(grid,id)};function reportingLayout(grid,column){const declared=column.kind?column:grid.columns.find(item=>item.id===column.id)||column,policy=grid.columnLayouts.get(column.id)||{};return{minimum:declared.minWidth??policy.minimum??40,maximum:declared.maxWidth??policy.maximum??MAX_COLUMN_WIDTH,flex:declared.flexWeight??(typeof declared.flex==="number"?declared.flex:policy.flex||0),priority:declared.priority===undefined?policy.priority:gridRank(declared),alwaysVisible:declared.alwaysVisible??policy.alwaysVisible,pin:declared.pinned===undefined?policy.pin:declared.pinned||"none"}}
|
|
1202
1216
|
function reportingWidth(grid,column,width){const policy=reportingLayout(grid,column);return Math.min(policy.maximum,Math.max(policy.minimum,width))}
|
|
1203
1217
|
GRID_REPORTING.validate=view=>{LAYOUT_VALIDATE(view);const options=view.reporting;if(options.columnReorder!==undefined&&typeof options.columnReorder!=="boolean")throw new Error("CanopyX: columnReorder must be boolean.");if(options.layout===undefined)return;if(!options.layout||typeof options.layout!=="object"||Array.isArray(options.layout))throw new Error("CanopyX: layout is keyed by column ID.");for(const[id,policy]of Object.entries(options.layout)){const column=view.columns.find(item=>item&&item.id===id);if(!column||!policy||typeof policy!=="object"||Array.isArray(policy)||
|
|
1204
1218
|
!Number.isInteger(policy.minimum)||policy.minimum<40||!Number.isInteger(policy.maximum)||
|
|
@@ -1342,13 +1356,13 @@ if(!numbers)return null;grid.aggregatePrecision.columns.set(column.id,digits);re
|
|
|
1342
1356
|
function reportingAggregateParts(grid,column,aggregates,values){const precision=aggregates.some(item=>!item.format&&!column.format&&!reportingCounting(item.operation))?reportingColumnPrecision(grid,column):0;const text=[],titles=[];for(const aggregate of aggregates){const value=values[aggregate.id];if(value===null||value===undefined)continue;const known=precision!==null,digits=reportingCounting(aggregate.operation)?0:!known?3:aggregate.operation==="average"?Math.min(3,precision+1):precision;const explicit=aggregate.format||(!reportingCounting(aggregate.operation)&&column.format);const shown=explicit?numberText(value,grid.lang,explicit):reportingAggregateFormat(grid.lang,digits,Math.abs(value)>=1e6,known||reportingCounting(aggregate.operation)).format(value);const label=AGGREGATE_LABELS[aggregate.operation];text.push(fill(label?grid.labels[label]:grid.groupAggregates?.get(aggregate.operation)?.label||aggregate.operation+" {value}",{value:shown}));titles.push(aggregate.label+": " +(explicit?shown:reportingAggregateFormat(grid.lang,3,false,false).format(value)))}
|
|
1343
1357
|
return{text:text.join(" · "),title:titles.join(" · ")}}
|
|
1344
1358
|
const GRID_EXPORT_PRESENTATION=new WeakMap();function gridCopyExportPresentation(from,to){const capture=GRID_EXPORT_PRESENTATION.get(from);if(capture)GRID_EXPORT_PRESENTATION.set(to,capture)}
|
|
1345
|
-
GRID_REPORTING.captureExport=(grid,request)=>GRID_EXPORT_PRESENTATION.set(request,JSON.parse(JSON.stringify({rules:grid.view.highlightRules||[],columns:grid.view.columns,labels:grid.labels,locale:grid.lang})));GRID_REPORTING.exportColumn=function(grid,column){const policy=grid.columnLayouts?.get(column.id),presenter=column.presenter||grid.view.reporting?.presenters?.[column.id];const minimum=column.minWidth??policy?.minimum??40,maximum=column.maxWidth??policy?.maximum;return{id:column.id,title:column.title,kind:column.kind,width:{unit:"css-px",preferred:column.width,minimum,...(maximum===undefined?{}:{maximum})},wrap:!!column.wrap,alignment:column.kind==="number"?"right":"left",...(column.format?{format:{...column.format}}:{}),...(presenter?{presenter:JSON.parse(JSON.stringify(presenter))}:{}),...(column.render&&column.hostRenderer!==false?{diagnostics:["custom-renderer"]}:{})}};GRID_REPORTING.exportRecord=function(grid,request,row){const capture=GRID_EXPORT_PRESENTATION.get(request),matches=new Map(),cells=Object.create(null);for(const rule of capture.rules){const key=rule.target==="cell"?rule.column:null;if(!matches.has(key)&&gridMatches(row,rule,capture.columns.find(column=>column.id===rule.column)))matches.set(key,rule)}
|
|
1359
|
+
GRID_REPORTING.captureExport=(grid,request)=>GRID_EXPORT_PRESENTATION.set(request,JSON.parse(JSON.stringify({rules:grid.view.highlightRules||[],columns:grid.view.columns,labels:grid.labels,locale:grid.lang})));GRID_REPORTING.exportColumn=function(grid,column){const policy=grid.columnLayouts?.get(column.id),presenter=column.presenter||grid.view.reporting?.presenters?.[column.id];const minimum=column.minWidth??policy?.minimum??40,maximum=column.maxWidth??policy?.maximum;return{id:column.id,title:column.title,kind:column.kind,width:{unit:"css-px",preferred:column.width,minimum,...(maximum===undefined?{}:{maximum})},wrap:!!column.wrap,alignment:column.kind==="number"?"right":"left",...(column.format?{format:{...column.format}}:{}),...(presenter?{presenter:JSON.parse(JSON.stringify(presenter))}:{}),...JSON.parse(JSON.stringify({valueLabels:column.valueLabels,valueTones:column.valueTones,numericTones:column.numericTones})),...(column.render&&column.hostRenderer!==false?{diagnostics:["custom-renderer"]}:{})}};GRID_REPORTING.exportRecord=function(grid,request,row){const capture=GRID_EXPORT_PRESENTATION.get(request),matches=new Map(),cells=Object.create(null);for(const rule of capture.rules){const key=rule.target==="cell"?rule.column:null;if(!matches.has(key)&&gridMatches(row,rule,capture.columns.find(column=>column.id===rule.column)))matches.set(key,rule)}
|
|
1346
1360
|
const fmt=formatting(request.locale||capture.locale,request.timeZone==="local",capture.labels);for(const column of request.columns){const cell=row.cells[column.id],object=isCellObject(cell),value=cellValue(cell)??null,presenter=column.presenter;let text=cellText(cell,column,fmt);const missing=presenter&&(value===null&&(!object||cell.text===undefined)||text==="");const diagnostics=[...(column.diagnostics||[])];if(object&&cell.className)diagnostics.push("custom-class");if(object&&cell.badges?.length)diagnostics.push("badges");if(object&&cell.series)diagnostics.push("history-series");if(missing)text="—";if(!missing&&presenter?.kind==="boolean"&&typeof value==="boolean")text=value?capture.labels.yes:capture.labels.no;if(!missing&&presenter?.kind==="identifier"){const secondary=presenter.secondaryColumn?cellText(row.cells[presenter.secondaryColumn],capture.columns.find(item=>item.id===presenter.secondaryColumn),fmt):object&&cell.secondary;if(secondary)text +="\n"+secondary}
|
|
1347
1361
|
if(!missing&&presenter?.kind==="change"){const delta=cellValue(row.cells[presenter.deltaColumn]);if(typeof delta==="number"&&Number.isFinite(delta)){text=(delta===0?"":delta>0?"↑ ":"↓ ")+ numberFormat(request.locale||capture.locale).format(Math.abs(delta))+ " "+text;if(delta!==0)diagnostics.push("partial-tone")}}
|
|
1348
1362
|
let link;if(!missing&&presenter?.kind==="link"){const target=cellValue(presenter.hrefColumn?row.cells[presenter.hrefColumn]:cell);if(typeof target==="string"&&/^[a-z][a-z\d+.-]*:/i.test(target.trim())) {
|
|
1349
1363
|
const safe=gridPresenterLink(target);if(safe&&/^(https?:|mailto:)/i.test(safe)) link = { target: safe, ...(object && cell.title ? { tooltip: cell.title } : {}) };
|
|
1350
1364
|
else diagnostics.push("unsafe-link")}else if(target)diagnostics.push("relative-link")}
|
|
1351
|
-
const mark=matches.get(column.id),tone=mark?.tone??(presenter?.kind==="boolean"&&value===true&&presenter.inverted?"danger":
|
|
1365
|
+
const mark=matches.get(column.id),tone=mark?.tone??columnValueTone(column,cell)??(presenter?.kind==="boolean"&&value===true&&presenter.inverted?"danger":
|
|
1352
1366
|
presenter?gridPresenterTone(presenter,value,object?cell.tone:null):object?cell.tone:undefined);if(mark?.className)diagnostics.push("custom-class");cells[column.id]={value,text,...(tone?{tone}:{}),...(link?{link}:{}),...(diagnostics.length?{diagnostics:[...new Set(diagnostics)]}:{})}}
|
|
1353
1367
|
const mark=matches.get(null),tone=mark?.tone??row.tone,diagnostics=row.className||mark?.className?["custom-class"]:[];return gridFreeze({id:row.id,cells,...(tone?{tone}:{}),...(diagnostics.length?{diagnostics}:{})})};const DELIVERY_PREPARE=DataGrid.prototype.prepareExport,DELIVERY_TEXT=DataGrid.prototype.exportText,DELIVERY_API=GRID_REPORTING.api,DELIVERY_CALLBACKS=new WeakMap();function reportingExportTotal(request){return request.recordCount}
|
|
1354
1368
|
function reportingFileName(value){if(typeof value!=="string"||!value||value.length>100||value!==value.trim()||
|
|
@@ -101,3 +101,4 @@ body .cx-host.cx-grid-overlay{height:auto;min-height:0;padding:0;}
|
|
|
101
101
|
.cx-tree-tools .cx-hidden-fields{color:var(--cx-muted);font:var(--cx-size-12d5px) var(--cx-font);border:0;background:transparent;padding:0;flex:none;height:auto;min-height:var(--cx-size-24px);min-width:var(--cx-size-24px);margin-left:var(--cx-size-4px);position:relative;}
|
|
102
102
|
.cx-tree-tools.cx-drawer :focus-visible{outline:var(--cx-size-2px) solid var(--cx-accent);outline-offset:var(--cx-size-2px);}
|
|
103
103
|
.cx-tree-tools.cx-drawer [data-cx-pointer-focus]:focus-visible{outline:none;}
|
|
104
|
+
.cx-tree-tools.cx-drawer .p-sub{margin-inline-start:var(--cx-size-6px);color:var(--cx-muted);font-size:var(--cx-size-12d5px);}
|