@evotecit/canopyx 0.3.10 → 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-editing.css +1 -1
- package/CanopyX.Html/Assets/canopyx-editing.js +5 -4
- 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 +13 -10
- package/CanopyX.Html/Assets/canopyx-grid-module.mjs +75 -59
- package/CanopyX.Html/Assets/canopyx-grid.css +20 -15
- package/CanopyX.Html/Assets/canopyx-grid.js +75 -59
- 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 +79 -63
- package/CanopyX.Html/Assets/canopyx-reporting.css +20 -15
- package/CanopyX.Html/Assets/canopyx-reporting.js +79 -63
- package/CanopyX.Html/Assets/canopyx-tree-tools.css +1 -0
- package/CanopyX.Html/Assets/canopyx-tree-tools.js +10 -6
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"0e0a3529c0b099d7",requires:["detail-rows"],install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,GRID_ROWS,GRID_REPORTING,h,setText,fill,numberFormat,formatValue,cellValue,cellText,isCellObject,gridScalar,gridQuery,gridFreeze,gridOrder,gridIdOrder,gridQueryRows,gridButton,gridDecorateButton,gridCellRenderer,gridPresenterTone,GRID_TONE_RANK,validateGridRows,validateGridPage,checkDocument,requireIdentifier,validStructuralCount,PROTOCOL,gridOperationActive,reportingGroupKey,reportingGroupCompare,reportingSummaryEnabled,reportingDynamicGroups,GROUP_OPERATIONS,reportingAggregateParts,disposeRowHostCells,quietControls,TreeGrid}=context;const groupCounting=operation=>operation==="count"||operation==="distinctCount";function groupCustomAggregates(grid){const found=new Map();for(const plugin of grid.plugins)for(const[name,entry]of Object.entries(plugin.aggregates||{})){const definition=typeof entry==="function"?{compute:entry}:entry;if(!/^[a-z][a-zA-Z\d]{0,31}$/.test(name) || GROUP_OPERATIONS.includes(name) || !definition || typeof definition.compute !== "function" ||
|
|
2
2
|
definition.label!==undefined&&(typeof definition.label!=="string"||!definition.label.includes("{value}")||definition.label.length>64))
|
|
3
3
|
throw new Error("CanopyX: plugin '"+plugin.name+"' registers an invalid aggregate '"+name+"'.");found.set(name,definition)}
|
|
4
4
|
return found}
|
|
@@ -56,7 +56,7 @@ const group=row.group,level=row.level,collapsed=this.collapsedGroups.has(group.k
|
|
|
56
56
|
else{element.removeAttribute("aria-level");element.removeAttribute("aria-expanded")}
|
|
57
57
|
element.style.height=this.rowH+"px";element.style.width=this.rowWidth+"px";element.style.setProperty("--cx-group-level",String(level-1));const priorButton=previous?.[0].cell.querySelector(".cx-grid-group-toggle"),button=priorButton||h("button","cx-grid-group-toggle");if(!priorButton){button.type="button";button.tabIndex=-1}
|
|
58
58
|
if(button.disabled!==!!this.pendingQuery)button.disabled=!!this.pendingQuery;button.setAttribute("aria-expanded",String(!collapsed));button.setAttribute("aria-label",collapsed?this.labels.gridGroupExpand:this.labels.gridGroupCollapse);if(button.textContent!==(collapsed?"▸":"▾"))setText(button,collapsed?"▸":"▾");if(!priorButton)button.addEventListener("click",()=>{if(this.pendingQuery)return;try{this.setFocus(row,false);this.setGroupCollapsed(group.key,!this.collapsedGroups.has(group.key));this.setFocus(this.focused,true)}
|
|
59
|
-
catch(error){this.emit("error",{error})}});const value=group.value===null?this.labels.gridGroupMissing:
|
|
59
|
+
catch(error){this.emit("error",{error})}});const value=group.value===null?this.labels.gridGroupMissing:cellText(group.value,groupColumn,this.fmt),count=numberFormat(this.lang).format(group.count);const label=fill(this.labels.gridGroupHeading,{column:groupColumn.title,value,count}),cells=[];this.cols.forEach((column,index)=>{const cell=previous?.[index].cell||this.cell(element,index,column.width,column.kind);cells.push({cell,content:cell});if(index===0){const priorHeading=cell.querySelector(".cx-grid-group-label"),heading=priorHeading||h("span","cx-grid-group-label");const text=heading.querySelector(".cx-grid-group-text")||h("span","cx-grid-group-text"),badge=heading.querySelector(".cx-grid-group-count")||h("span","cx-grid-group-count");text.replaceChildren();if(levels.length>1){const name=h("span","cx-grid-group-column");setText(name,groupColumn.title);text.append(name,document.createTextNode(" "))}
|
|
60
60
|
text.appendChild(document.createTextNode(value));setText(badge,count);if(!priorHeading)heading.append(text,badge);if(!priorButton)cell.append(button);this.paintGroupSelection(cell,group);if(!priorHeading)cell.append(heading);cell.title=label;this.paintHiddenAggregates(heading,group.aggregates,cell,column.id,label);return}
|
|
61
61
|
const aggregates=(this.view.reporting.aggregates||[]).filter(item=>item.column===column.id);if(aggregates.length)this.paintAggregates(cell,column,aggregates,group.aggregates);else{cell.replaceChildren();if(Object.hasOwn(group.cells||{},column.id)){const options=column.presenter||this.view.reporting.presenters?.[column.id];if(options)gridCellRenderer(this,column,options)({id:group.key,cells:group.cells},cell);else setText(cell,cellText(group.cells[column.id],column,this.fmt))}}});let room=this.cols[0].renderWidth??this.cols[0].width;for(let index=1;index<cells.length&&!cells[index].cell.textContent;index++)room +=this.cols[index].renderWidth??this.cols[index].width;const heading=cells[0].cell.querySelector(".cx-grid-group-label");heading.style.maxWidth=Math.max(40,room-44 -(level-1)*16 -(this.view.reporting.selectionControls&&this.multi?22:0))+ "px";element._cells=cells;quietControls(element);this.paintGridHighlights(element,row)},paintGroupSelection(cell,group){if(!this.view.reporting.selectionControls||!this.multi)return;const previous=cell.querySelector(".cx-grid-group-select"),check=previous||h("input","cx-grid-row-select cx-grid-group-select");if(!previous){check.type="checkbox";check.tabIndex=-1}
|
|
62
62
|
const state=this.groupSelection(group);check.checked=state===true;check.indeterminate=state==="mixed";check.disabled=!!this.pendingQuery;check.setAttribute("aria-label",fill(this.labels.gridSelectGroup,{group:group.value===null?this.labels.gridGroupMissing:String(group.value)}));if(!previous)check.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.runReportingSelection(()=>this.selectRange(group.offset,group.offset+group.count-1,{selected:this.groupSelection(group)!==true,additive:true}))});if(!previous)cell.appendChild(check)},groupSelection(group){let selected=0,loaded=0;for(const[ordinal,record]of this.rowCache){if(ordinal<group.offset||ordinal>=group.offset+group.count)continue;loaded++;if(this.reportingRowSelected(record))selected++}
|
|
@@ -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"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"link":["fa0c9e888463553b","canopyx-link.4ec39bc39fa6cf50.js","canopyx-link.8435c892613926ac.css"],"highlight":["f39423961654c1e2","canopyx-highlight.a6f93893d36ab343.js","canopyx-highlight.5b6d2e0d979f9f9b.css"],"layouts":["dd1076d5684bfc6e","canopyx-layouts.670fd555e6e08904.js","canopyx-layouts.b1df38a90cb3215d.css"],"record-panel":["e78e0e62d74d6811","canopyx-record-panel.2fe5e43bb99cc818.js","canopyx-record-panel.f3691d54cefaab04.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))||
|
|
@@ -39,7 +39,7 @@ flex-direction:column;align-items:flex-start;justify-content:center;gap:var(--cx
|
|
|
39
39
|
}
|
|
40
40
|
.cx-data-grid[data-cx-layout="cards"] .cx-row:not(.cx-status):not(.cx-grid-group) > .cx-cell:first-child{grid-column:1/-1;height:var(--cx-card-title);flex-direction:row;align-items:center;justify-content:flex-start;gap:var(--cx-size-6px);font-weight:600;font-size:calc(var(--cx-font-size) + 1px);}
|
|
41
41
|
.cx-data-grid[data-cx-layout="cards"] .cx-row:not(.cx-status):not(.cx-grid-group) > .cx-cell[data-cx-card="wide"]{grid-column:span var(--cx-card-span,1);}
|
|
42
|
-
.cx-data-grid[data-cx-layout="cards"] .cx-cell[data-cx-label]::before{content:attr(data-cx-label) / "";display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--cx-size-11d5px);font-weight:600;line-height:1.35;color:var(--cx-muted);}
|
|
42
|
+
.cx-data-grid[data-cx-layout="cards"] .cx-cell[data-cx-label]::before{content:attr(data-cx-label) / "";display:block;flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--cx-size-11d5px);font-weight:600;line-height:1.35;color:var(--cx-muted);}
|
|
43
43
|
.cx-data-grid[data-cx-layout="cards"] .cx-cell > :is(.cx-text,.cx-presenter-text){max-width:100%;}
|
|
44
44
|
.cx-data-grid[data-cx-layout="cards"] .cx-row:not(.cx-status):not(.cx-grid-group) > .cx-cell:first-child::before{content:none;}
|
|
45
45
|
.cx-data-grid[data-cx-layout="cards"] .cx-row[aria-selected="true"]{box-shadow:inset var(--cx-size-3px) 0 0 var(--cx-accent);}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
2
|
-
function cardGeometry(view){const metrics=CARD_METRICS[view.density],width=Math.max(0,(view.grid.clientWidth||view.host.clientWidth)- 2*CARD_GUTTER);const fields=(view.cols||[]).slice(1),most=Math.max(1,Math.floor((width+CARD_COLUMN_GAP)/ (CARD_FIELD + CARD_COLUMN_GAP)));
|
|
3
|
-
const slots=fields.reduce((sum,field)=>sum +(cardWide(field)&&most>1?2:1),0)||1;const columns=Math.min(most,Math.ceil(slots / Math.ceil(slots / most))), span = Math.min(2, columns), rows = [];
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"dd1076d5684bfc6e",install(context){if(installed.has(context.VIEW_MODES))return;const{VIEW_MODES,TreeGrid,h,setText,fill,numberFormat,foldText,cellText,cellValue,isCellObject,setAttr,toneOf,watchFlyout,densityRowHeight,MAX_PROTOCOL_INTEGER,LAYOUT_DENSITIES,plural,svgIcon}=context;const CARD_METRICS={compact:{pad:8,field:36,gap:4,title:24},default:{pad:12,field:40,gap:6,title:26},comfortable:{pad:16,field:44,gap:8,title:28}};const CARD_FIELD=140,CARD_GUTTER=16,CARD_COLUMN_GAP=16,CARD_WIDE=["longText","tags","list"];function cardWide(column){return!!column.wrap||!!column.flex||CARD_WIDE.includes(column.presenter?.kind)}
|
|
2
|
+
function cardGeometry(view){const metrics={...CARD_METRICS[view.density]},width=Math.max(0,(view.grid.clientWidth||view.host.clientWidth)- 2*CARD_GUTTER);const fields=(view.cols||[]).slice(1),most=Math.max(1,Math.floor((width+CARD_COLUMN_GAP)/ (CARD_FIELD + CARD_COLUMN_GAP)));
|
|
3
|
+
const font=parseFloat(getComputedStyle(view.grid).fontSize),clampLines=column=>Math.min(column.maxLines??2,2);if(fields.some(column=>column.wrap))metrics.field=Math.max(metrics.field,Math.ceil(11.5*1.35+1+font*1.4*Math.max(...fields.filter(column=>column.wrap).map(clampLines))));if(view.cols?.[0]?.wrap)metrics.title=Math.max(metrics.title,Math.ceil((font+1)*1.4*clampLines(view.cols[0])));const slots=fields.reduce((sum,field)=>sum +(cardWide(field)&&most>1?2:1),0)||1;const columns=Math.min(most,Math.ceil(slots / Math.ceil(slots / most))), span = Math.min(2, columns), rows = [];
|
|
4
4
|
for(const field of fields){const size=cardWide(field)?span:1;for(let row=0,placed=false;!placed;row++){const cells=rows[row]||=new Array(columns).fill(false);for(let at=0;at+size<=columns&&!placed;at++)if(cells.slice(at,at+size).every(used=>!used)){cells.fill(true,at,at+size);placed=true}}}
|
|
5
5
|
const lines=rows.length;return{columns,span,metrics,height:2*metrics.pad+metrics.title +(lines?metrics.gap+lines*metrics.field +(lines-1)*metrics.gap:0)+ 1}}
|
|
6
6
|
function cardStyle(view,geometry){const style=view.host.style,{metrics}=geometry;style.setProperty("--cx-card-cols",String(geometry.columns));style.setProperty("--cx-card-span",String(geometry.span));style.setProperty("--cx-card-pad",metrics.pad+"px");style.setProperty("--cx-card-field",metrics.field+"px");style.setProperty("--cx-card-gap",metrics.gap+"px");style.setProperty("--cx-card-title",metrics.title+"px")}
|
|
@@ -46,9 +46,10 @@ if(typeof value==="boolean"){return value?fmt.labels.yes:fmt.labels.no}
|
|
|
46
46
|
if(typeof value==="number"&&kind==="number"){return numberText(value,fmt.lang,format)}
|
|
47
47
|
if(typeof value==="string"&&kind==="datetime"){return formatDate(value,fmt)}
|
|
48
48
|
return String(value)}
|
|
49
|
-
function cellText(cell,column,fmt){if(isCellObject(cell)&&typeof cell.text==="string"){return cell.text}
|
|
49
|
+
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}
|
|
50
50
|
return formatValue(cellValue(cell),column.kind,fmt,column.format)}
|
|
51
|
-
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){
|
|
51
|
+
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}}
|
|
52
|
+
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}
|
|
52
53
|
if(value===null||value===""){return{rank:2,value:0}}
|
|
53
54
|
if(typeof value==="boolean"){return{rank:0,value:value?1:0}}
|
|
54
55
|
if(typeof value==="number"){return{rank:0,value}}
|
|
@@ -56,7 +57,20 @@ if(column.kind==="datetime"){const time=Date.parse(value);if(!isNaN(time)){retur
|
|
|
56
57
|
return{rank:1,value:String(value)}}
|
|
57
58
|
function compareKeys(a,b,direction){if(a.rank!==b.rank){return a.rank-b.rank}
|
|
58
59
|
if(a.rank===2){return 0}
|
|
59
|
-
const order=a.
|
|
60
|
+
const order=a.category!==undefined?a.category-b.category||
|
|
61
|
+
(a.type<b.type?-1:a.type>b.type?1:a.value<b.value?-1:a.value>b.value?1:0):
|
|
62
|
+
a.rank===0?(a.value<b.value?-1:a.value>b.value?1:0):collator.compare(a.value,b.value);return order*direction}
|
|
63
|
+
function columnNumericTone(column,raw){return typeof raw==="number"&&Number.isFinite(raw)?column.numericTones?.find(rule=>
|
|
64
|
+
rule.operator==="atMost"?raw<=rule.value:rule.operator==="atLeast"?raw>=rule.value:
|
|
65
|
+
rule.operator==="below"?raw<rule.value:raw>rule.value):undefined}
|
|
66
|
+
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)}
|
|
67
|
+
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");
|
|
68
|
+
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||
|
|
69
|
+
Object.entries(map).some(([key,value])=>key.length>4096||(name==="valueTones"?!tone(value):typeof value!=="string"||value.length>4096)))fail()}
|
|
70
|
+
if(column.valueOrder!==undefined&&(column.kind!=="text"||!Array.isArray(column.valueOrder)||column.valueOrder.length>512||
|
|
71
|
+
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||
|
|
72
|
+
column.numericTones.some(rule=>!rule||!["atMost","atLeast","below","above"].includes(rule.operator)||!Number.isFinite(rule.value)||
|
|
73
|
+
!tone(rule.tone)||typeof rule.label!=="string"||!rule.label.trim()||rule.label.length>4096)))fail()}
|
|
60
74
|
function fill(template,values){return template.replace(/\{(\w+)\}/g, (match, name) => (values && Object.hasOwn(values, name) ? String(values[name]) : match));
|
|
61
75
|
}
|
|
62
76
|
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];
|
|
@@ -119,7 +133,8 @@ if(column.kind==="datetime"){const date=typeof value==="string"&&/^\d{4}-\d\d-\d
|
|
|
119
133
|
if(!Number.isFinite(date))
|
|
120
134
|
throw new Error("CanopyX: date grid cells need ISO dates with an explicit time zone.");return date}
|
|
121
135
|
if(typeof value!=="string"&&typeof value!=="boolean")throw new Error("CanopyX: text grid cells need strings or booleans.");return value}
|
|
122
|
-
function
|
|
136
|
+
function gridExactTokens(column){return column.kind==="text"&&(column.valueOrder?.length||Object.keys(column.valueLabels||{}).length)}
|
|
137
|
+
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}
|
|
123
138
|
return false}
|
|
124
139
|
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))
|
|
125
140
|
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)||
|
|
@@ -193,7 +208,7 @@ return checkDocument(await response.json(),type)}catch(error){if(timedOut)throw
|
|
|
193
208
|
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.")}
|
|
194
209
|
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"))
|
|
195
210
|
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.")}
|
|
196
|
-
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||[]}
|
|
211
|
+
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||[]}
|
|
197
212
|
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()}
|
|
198
213
|
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()}}
|
|
199
214
|
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
|
|
@@ -261,7 +276,7 @@ function snapshotRevision(value,expected){requireIdentifier(value&&value.revisio
|
|
|
261
276
|
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")}
|
|
262
277
|
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")}
|
|
263
278
|
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++}
|
|
264
|
-
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)}
|
|
279
|
+
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)}
|
|
265
280
|
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}}
|
|
266
281
|
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}}
|
|
267
282
|
return measured}});function columnWidth(column,width){return Math.min(column.maxW,Math.max(column.minW,width))}
|
|
@@ -311,13 +326,13 @@ this.paintSlot(slot,node,this.cols[i],this.columnIndex[i],w)}},paintRowState(row
|
|
|
311
326
|
const expander=this.expandable(w)?"cx-exp":"cx-exp cx-leaf";if(slot.expCls!==expander){slot.exp.className=expander;slot.expCls=expander}
|
|
312
327
|
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()}
|
|
313
328
|
slot.iconEl=key?this.iconTemplates.get(key).cloneNode(true):null;if(slot.iconEl){slot.cell.insertBefore(slot.iconEl,slot.content)}
|
|
314
|
-
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)?
|
|
329
|
+
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)?
|
|
315
330
|
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}
|
|
316
331
|
const hosted=column.render?this.paintHostSlot(slot,node,column,index,w):null;if(hosted==="host"){return}
|
|
317
332
|
const decorated=hosted==="decorated";const text=cellText(value,column,this.fmt);if(slot.text.data!==text){slot.text.data=text}
|
|
318
|
-
const object=isCellObject(value);const tone=
|
|
333
|
+
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}
|
|
319
334
|
slot.cls=cls}
|
|
320
|
-
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")}
|
|
335
|
+
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")}
|
|
321
336
|
slot.title=title}
|
|
322
337
|
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)}
|
|
323
338
|
const tone=toneOf(badge.tone||"neutral");if(span._cls!==tone.cls){applyTone(span,"cx-badge",tone);span._cls=tone.cls}
|
|
@@ -506,7 +521,7 @@ if(active>=0){list.children[active].setAttribute("aria-selected","false")}
|
|
|
506
521
|
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=""}
|
|
507
522
|
close()}else{return}
|
|
508
523
|
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)}}}
|
|
509
|
-
const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["
|
|
524
|
+
const PART_URL=typeof document!=="undefined"&&document.currentScript?.src;const PARTS={"tree-tools":["c68e6612a9ea6eb0","canopyx-tree-tools.b8ee5c807c1d4fcd.js","canopyx-tree-tools.aae203232147f116.css"],"export":["9203882f58fa0155","canopyx-export.cedfec6462c161b4.js"],"links":["f1ab7e32b501ce37","canopyx-links.d96addeefb3eccf5.js"],"search":["521eebd6e1bbbd35","canopyx-search.14c69f4551c69f23.js"],"link":["fa0c9e888463553b","canopyx-link.4ec39bc39fa6cf50.js","canopyx-link.8435c892613926ac.css"],"highlight":["f39423961654c1e2","canopyx-highlight.a6f93893d36ab343.js","canopyx-highlight.5b6d2e0d979f9f9b.css"],"layouts":["dd1076d5684bfc6e","canopyx-layouts.670fd555e6e08904.js","canopyx-layouts.b1df38a90cb3215d.css"],"record-panel":["e78e0e62d74d6811","canopyx-record-panel.2fe5e43bb99cc818.js","canopyx-record-panel.f3691d54cefaab04.css"]},PART_CODE=new Map(),partName=name=>typeof name==="string"&&/^[a-z][a-z\d-]{0,31}$/.test(name);
|
|
510
525
|
function registerPart(name,part){if(!partName(name)||!part||typeof part.version!=="string"||typeof part.install!=="function"||
|
|
511
526
|
part.requires!==undefined&&!(Array.isArray(part.requires)&&part.requires.every(partName)))throw new Error("CanopyX: invalid part.");PART_CODE.set(name,part)}
|
|
512
527
|
function definePart(View,name,label,context){const parts=View.prototype.parts||={};return parts[name]={name,label,context,parts}}
|
|
@@ -516,7 +531,7 @@ const load=(element,attribute,file,kind)=>new Promise((resolve,reject)=>{const u
|
|
|
516
531
|
.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")
|
|
517
532
|
.finally(()=>script.remove()).catch(error=>{part.scriptReady=null;throw error}));await Promise.all([style,code])}}
|
|
518
533
|
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})}
|
|
519
|
-
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)}
|
|
534
|
+
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)}
|
|
520
535
|
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")
|
|
521
536
|
throw new Error("CanopyX: invalid state column.");seen.add(c.id);return{id:c.id,width:c.width,hidden:c.hidden}}
|
|
522
537
|
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})})}
|
|
@@ -575,7 +590,7 @@ return this.openDeepLink()};DEFAULT_LABELS=Object.freeze(Object.assign({},DEFAUL
|
|
|
575
590
|
linkMethods(TreeGrid);function linkGridPart(View){(Object.hasOwn(View.prototype,"parts")?View.prototype.parts:View.prototype.parts={}).link=LINK_PART}
|
|
576
591
|
function linkReady(grid,ready){return Promise.all([ready,grid.linkStart()]).then(([result])=>result)}
|
|
577
592
|
function linkApi(grid){const api={};for(const name of LINK_METHODS.concat("getExternalFilters","getHighlight"))api[name]=(...args)=>grid[name](...args);return api}
|
|
578
|
-
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)}
|
|
593
|
+
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)}
|
|
579
594
|
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}))}
|
|
580
595
|
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");
|
|
581
596
|
if(!options||typeof options!=="object"||Array.isArray(options)||Object.keys(options).some(key=>!HIGHLIGHT_KEYS.includes(key))||
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"b6a65af41d9187d9",install(context){if(installed.has(context.GRID_PRESENTER_IMPL))return;const{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}=context;function gridRenderPresenter(grid,column,options,record,complete){return(row,element)=>{const cell=row.cells[column.id],raw=cellValue(cell),text=cellText(cell,column,grid.fmt),object=isCellObject(cell);const rule=columnNumericTone(column,raw),declaredTone=columnValueTone(column,cell),tone=declaredTone||gridPresenterTone(options,raw,object?cell.tone:null);element.classList.add("cx-presented-cell");if(rule||object&&cell.title)element.title=rule?.label||cell.title;if(declaredTone)applyTone(element,element.className,toneOf(declaredTone));if(rule)element.setAttribute("aria-description",rule.label);const add=(value,cls="cx-presenter-text",tag="span")=>{const item=h(tag,cls),textItem=/^(cx-presenter-text|p-mono|p-link|cx-wrapped-text|p-muted)\b/.test(cls);setText(item,value);
|
|
2
|
+
if(declaredTone&&textItem)item.style.color="inherit";if(column.wrap&&textItem){item.classList.add("cx-wrapped-text");item.style.maxWidth="100%";item.style.flex="none";item.title=rule?.label||String(value);if(complete){item.style.webkitLineClamp="unset";item.style.maxHeight="none"}
|
|
3
|
+
else{const lines=record?column.maxLines??2:grid.layoutMode==="cards"?Math.min(column.maxLines??2,2):grid.autoRows?column.maxLines??2:1;item.style.webkitLineClamp=String(lines);item.style.maxHeight=lines*1.4+"em"}}
|
|
4
|
+
element.appendChild(item);return item};const more=(value,label=grid.labels.gridShowMore)=>{const button=add(label,"cx-link cx-presenter-expand","button");button.type="button";button.setAttribute("aria-haspopup","dialog");button.setAttribute("aria-label",fill(grid.labels.gridExpandCell,{column:column.title}));button.addEventListener("click",()=>grid.showReportingText(column,value,button,row.id,options.mono));return button};if(GRID_HISTORY_KINDS.includes(options.kind)){if(GRID_HISTORY_IMPL.render)GRID_HISTORY_IMPL.render(grid,column,options,cell,element,text);else grid.loadHistory()}else if(options.kind==="structured"){if(RECORD_IMPL.summary)RECORD_IMPL.summary(grid,column,options,row,element,text);else{add(text);grid.loadRecordPanel()}}else if(raw==null&&object&&cell.text==="")add("");else if(raw==null&&(!object||cell.text===undefined)||text==="")add("—","p-missing");else if(options.kind==="link"){const href=gridPresenterLink(cellValue(options.hrefColumn?row.cells[options.hrefColumn]:cell));const link=add(text,"p-link",href?"a":"span");if(href){link.href=href;if(options.newWindow){link.target="_blank";link.rel="noopener noreferrer"}}}else if(options.kind==="icon"){add(options.glyph,"cx-presenter-icon").setAttribute("aria-hidden","true");add(text)}
|
|
5
|
+
else if(options.kind==="boolean"&&typeof raw==="boolean"){const value=add(raw?"":"—",raw?"p-bool-yes"+(options.inverted?" cx-bool-bad":""):"p-bool-no");value.setAttribute("role","img");value.setAttribute("aria-label",raw?grid.labels.yes:grid.labels.no);if(raw)value.appendChild(gridIcon("check"))}else if(options.kind==="state"||options.kind==="enum"){if(options.quietTones?.includes(tone))add(text,(options.quietStyle==="plain"?"cx-presenter-text":"p-muted")+(options.kind==="enum"?" p-inset":""));else if(options.kind==="state"||tone==="success"){const state=add("","p-state"+(tone==="success"?" quiet":""));const dot=h("span","p-dot "+(tone==="success"?"quiet":tone));toneColors(dot,toneOf(tone));state.append(dot,document.createTextNode(text))}else{const pill=add(text,"p-pill "+tone);applyTone(pill,pill.className,toneOf(tone))}}else if(options.kind==="change"){const delta=cellValue(row.cells[options.deltaColumn]);if(typeof delta==="number")add((delta===0?"":delta>0?"↑ ":"↓ ")+numberFormat(grid.lang).format(Math.abs(delta)),"p-delta "+(delta===0?"flat":(delta>0)===!!options.higherIsGood?"good":"bad"));add(text)}else if(options.kind==="progress"&&typeof raw==="number"){const box=add("","p-progress"),track=h("span","track"),bar=h("span","fill "+tone),maximum=options.maximum||100;track.setAttribute("role","progressbar");track.setAttribute("aria-label",column.title);track.setAttribute("aria-valuemin","0");track.setAttribute("aria-valuemax",String(maximum));track.setAttribute("aria-valuenow",String(Math.min(maximum,Math.max(0,raw))));track.setAttribute("aria-valuetext",text);bar.style.width=Math.min(100,Math.max(0,raw/maximum*100))+"%";toneColors(bar,toneOf(tone));track.appendChild(bar);box.append(track,document.createTextNode(text));
|
|
6
|
+
}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)}
|
|
7
|
+
if(values.length>limit||options.kind==="list")more(text,values.length>limit?"+"+(values.length-limit):grid.labels.gridShowMore)}else if(options.kind==="longText"){if(column.wrap){add(text,"cx-wrapped-text"+(options.mono?" p-mono":""))}else{const budget=Math.max(256,Math.ceil((column.renderWidth||column.width)/7*5));
|
|
8
|
+
const preview=add(text.length>budget?text.slice(0,budget).replace(/[\uD800-\uDBFF]$/,"")+" …":text,"cx-wrapped-text"+(options.mono?" p-mono":""));
|
|
9
|
+
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);}
|
|
10
|
+
}}else add(text);if(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge));return true}}
|
|
11
|
+
GRID_PRESENTER_IMPL.create=gridRenderPresenter;installed.add(context.GRID_PRESENTER_IMPL)}};(global.CanopyXParts||=[]).push(["presenters",part])})(typeof window!=="undefined"?window:globalThis);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"e78e0e62d74d6811",install(context){if(installed.has(context.RECORD_IMPL))return;const{RECORD_IMPL,TreeGrid,h,setText,fill,cellText,cellValue,isCellObject,formatValue,toneOf,applyTone,toneColors,validateGridRows,badgeElement,loadSidecar,requireIdentifier,PROTOCOL,foldText,createTreeGrid,svgIcon,gridExportField,columnNumericTone,columnValueTone,validateColumnValues}=context;const RECORD_KINDS=["items","fields","records","events","changes"],RECORD_LINK_KEY=/^[A-Za-z][\w.-]{0,31}$/, RECORD_MAX_STRUCTURE_DEPTH = 8;
|
|
2
2
|
const recordKind=cell=>{const kinds=isCellObject(cell)&&!Array.isArray(cell)?RECORD_KINDS.filter(name=>cell[name]!==undefined):[];if(kinds.length>1)recordFail("a cell carries at most one structured value.");return kinds[0]||null};const recordFail=message=>{throw new Error("CanopyX: "+message)};const recordText=(value,max=256)=>typeof value==="string"&&!!value.trim()&&value.length<=max;const recordGridHelpers=()=>RECORD_IMPL.grid||{};function recordCheckValue(cell,depth=0){if(cell==null)return;if(depth>RECORD_MAX_STRUCTURE_DEPTH)recordFail("structured values nest at most "+RECORD_MAX_STRUCTURE_DEPTH+" levels.");const kind=recordKind(cell);if(kind==="items")for(const item of cell.items||[])recordCheckValue(item,depth+1);if(kind==="fields")for(const field of cell.fields||[])recordCheckValue(field.value,depth+1);if(kind==="changes")for(const change of cell.changes||[]){recordCheckValue(change.before,depth+1);recordCheckValue(change.after,depth+1)}
|
|
3
3
|
if(kind==="events")for(const event of cell.events||[])for(const change of event.changes||[]){recordCheckValue(change.before,depth+1);recordCheckValue(change.after,depth+1)}
|
|
4
4
|
if(kind==="records")recordCheckRows(cell.records.rows||cell.records.roots,depth+1)}
|
|
5
5
|
function recordCheckRows(rows,depth){const pending=[...rows||[]],seen=new Set();while(pending.length){const row=pending.pop();if(!row||seen.has(row))continue;seen.add(row);for(const cells of[row.cells,row.fields])if(cells)Object.values(cells).forEach(cell=>recordCheckValue(cell,depth));const detail=row.detail;if(detail){if(depth>RECORD_MAX_STRUCTURE_DEPTH)recordFail("structured values nest at most "+RECORD_MAX_STRUCTURE_DEPTH+" levels.");if(detail.type==="properties")for(const item of detail.items||[])recordCheckValue(item.value,depth);if(detail.type==="table")for(const cells of detail.rows||[])for(const cell of cells)recordCheckValue(cell,depth);if(detail.type==="grid"||detail.type==="tree")recordCheckRows(detail.rows||detail.roots,depth+1)}
|
|
6
6
|
for(const child of row.children||[])pending.push(child)}}
|
|
7
7
|
function recordSpec(view){if(view._recordSpec)return view._recordSpec;const spec=view.view.record||{},columns=new Set(view.columns.map(column=>column.id)),fields=new Set(),sections=new Set();if(typeof spec!=="object"||Array.isArray(spec))recordFail("a record panel is an object.");for(const field of spec.fields||[]){requireIdentifier(field?.id,"record field ID");if(field.id==="__proto__")recordFail("a record field cannot be named __proto__.");if(columns.has(field.id)||fields.has(field.id)||!recordText(field.title)||field.kind!==undefined&&!["text","number","datetime"].includes(field.kind)||
|
|
8
|
-
field.section!==undefined&&!recordText(field.section))recordFail("record field "+field.id+" needs a unique id, a title and a text, number or datetime kind.");if(field.
|
|
8
|
+
field.section!==undefined&&!recordText(field.section))recordFail("record field "+field.id+" needs a unique id, a title and a text, number or datetime kind.");if(field.maxLines!==undefined&&(!Number.isInteger(field.maxLines)||field.maxLines<1||field.maxLines>12))
|
|
9
|
+
recordFail("record maxLines must be an integer from 1 to 12.");if(field.presenter!==undefined&&recordGridHelpers().validatePresenter)recordGridHelpers().validatePresenter(field.presenter,{kind:"text",...field},view.columns);validateColumnValues({kind:"text",...field});fields.add(field.id)}
|
|
9
10
|
const known=id=>columns.has(id)||fields.has(id),top=new Set();const walk=(list,depth)=>{if(!Array.isArray(list)||depth>2)recordFail("record sections are an array, nested at most three levels.");for(const section of list){requireIdentifier(section?.id,"record section ID");if(sections.has(section.id)||!recordText(section.label)||section.fields!==undefined&&(!Array.isArray(section.fields)||!section.fields.every(known))||
|
|
10
11
|
section.renderer!==undefined&&!/^[a-z][a-z0-9-]{0,31}$/.test(section.renderer) || section.collapsed !== undefined && typeof section.collapsed !== "boolean")
|
|
11
12
|
recordFail("record section "+section.id+" needs a unique id, a label and declared fields.");sections.add(section.id);if(!depth)top.add(section.id);walk(section.sections||[],depth+1)}};walk(spec.sections||[],0);const tabs=new Set();for(const tab of spec.tabs||[]){requireIdentifier(tab?.id,"record tab ID");if(tabs.has(tab.id)||!recordText(tab.label)||!Array.isArray(tab.sections)||!tab.sections.every(id=>top.has(id)))recordFail("record tab "+tab.id+" needs a unique id, a label and declared top-level sections.");tabs.add(tab.id)}
|
|
@@ -16,7 +17,7 @@ recordFail("a record sidecar base must be a non-empty folder path without a quer
|
|
|
16
17
|
recordFail("record actions switch copy, print, export and link on or off.");return view._recordSpec=spec}
|
|
17
18
|
const recordPrimary=view=>view.kind==="tree"?view.columns[0]:view.visibleColumns()[0];function recordFields(view){const spec=recordSpec(view),primary=recordPrimary(view),fields=[];view.columns.forEach((column,index)=>{if(column.drawer===false||view.kind==="tree"&&!index)return;fields.push({id:column.id,title:column.title,kind:column.kind,presenter:column.presenter,wrap:column.wrap,section:column.section,column,primary:column===primary})});for(const field of spec.fields||[])fields.push({...field,kind:field.kind||"text",column:null,primary:false});return fields}
|
|
18
19
|
function recordCell(view,record,payload,field){const own=(values,id)=>values&&Object.hasOwn(values,id)?values[id]:undefined;if(!field.column)return own(payload?.fields,field.id)!==undefined?own(payload.fields,field.id):own(record.fields,field.id);if(own(payload?.cells,field.id)!==undefined)return own(payload.cells,field.id);return view.kind==="tree"?view.cellOf(record,field.column,view.columns.indexOf(field.column)):own(record.cells,field.id)}
|
|
19
|
-
function recordEmpty(cell,field,fmt){const kind=recordKind(cell);if(kind==="records")return!cell.records.rows?.length&&!cell.records.roots?.length;if(kind)return!Array.isArray(cell[kind])||!cell[kind].length;if(isCellObject(cell)&&(cell.series?.length||cell.badges?.length))return false;return cellText(cell,field,fmt)===""}
|
|
20
|
+
function recordEmpty(cell,field,fmt){const kind=recordKind(cell);if(kind==="records")return!cell.records.rows?.length&&!cell.records.roots?.length;if(kind)return!Array.isArray(cell[kind])||!cell[kind].length;if(isCellObject(cell)&&(cell.series?.length||cell.badges?.length))return false;return cellText(cell,field.column||field,fmt)===""}
|
|
20
21
|
function recordLayout(view,fields){const spec=recordSpec(view),byId=new Map(fields.map(field=>[field.id,field])),placed=new Set(),labels=view.labels;const section=(item,depth)=>({id:item.id,label:item.label,depth,collapsed:!!item.collapsed,renderer:item.renderer||null,fields:(item.fields||[]).map(id=>byId.get(id)).filter(field=>field&&!placed.has(field.id)&&placed.add(field.id)),sections:(item.sections||[]).map(child=>section(child,depth+1))});const sections=(spec.sections||[]).map(item=>section(item,0)),header=new Set([...(spec.header?.facts||[]),spec.header?.status].filter(Boolean));const rest=fields.filter(field=>!placed.has(field.id)&&!(field.primary&&view.view.record)&&!header.has(field.id));if(!spec.sections){const named=new Map();for(const field of rest){const name=field.section||labels.gridDetailsSection;if(!named.has(name))named.set(name,{id:"s"+named.size,label:name,depth:0,fields:[],sections:[]});named.get(name).fields.push(field)}
|
|
21
22
|
sections.push(...named.values())}else if(rest.length)sections.push({id:"other",label:labels.recordOtherFields,depth:0,fields:rest,sections:[]});const known=new Map(sections.map(item=>[item.id,item]));const tabs=(spec.tabs||[]).map(tab=>({id:tab.id,label:tab.label,sections:tab.sections.map(id=>known.get(id)).filter(Boolean)}));if(tabs.length){const used=new Set(tabs.flatMap(tab=>tab.sections));tabs[tabs.length-1].sections.push(...sections.filter(item=>!used.has(item)))}
|
|
22
23
|
return{tabs:tabs.length?tabs:[{id:"all",label:"",sections}],header:spec.header||null,byId,hideEmpty:!!view.view.record&&spec.hideEmpty!==false,jump:spec.jumpList}}
|
|
@@ -36,15 +37,16 @@ const request={protocol:PROTOCOL,type:"gridRecordQuery",view:view.view.id,id,...
|
|
|
36
37
|
function recordEnsure(view,id){const cache=view._recordPayloads||=new Map(),key=recordCacheKey(view,id);let entry=cache.get(key);if(entry)return entry;if(!recordLoader(view))return null;entry={state:"loading"};cache.set(key,entry);if(cache.size>64)cache.delete(cache.keys().next().value);entry.promise=recordFetch(view,id,{}).then(payload=>{entry.state="ready";entry.payload=payload;return payload},error=>{entry.state="error";entry.error=error;if(error.name!=="AbortError")view.emit("error",{error});throw error});entry.promise.catch(()=>{});return entry}
|
|
37
38
|
const RECORD_ICONS={back:'<path d="m14 7-5 5 5 5"/>',print:'<path d="M7 9V4h10v5M7 17H5v-6h14v6h-2M8 14h8v6H8z"/>',link:'<path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/>',more:'<circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/>',open:'<path d="M14 5h5v5M19 5l-8 8M17 14v5H5V7h5"/>',chevron:'<path d="m9 6 6 6-6 6"/>'};function recordIcon(name){return svgIcon(RECORD_ICONS[name])}
|
|
38
39
|
function recordButton(text,run,className,icon){const button=h("button","cx-record-btn" +(className?" "+className:""));button.type="button";if(icon)button.appendChild(recordIcon(icon));if(text)button.appendChild(document.createTextNode(text));button.addEventListener("click",event=>{event.stopPropagation();run(event)});return button}
|
|
39
|
-
const recordCount=(ctx,count)=>formatValue(count,"number",ctx.fmt);const recordRefValid=ref=>!!ref&&typeof ref==="object"&&typeof ref.id==="string"&&!!ref.id&&(ref.view===undefined||typeof ref.view==="string"&&!!ref.view);function recordPlain(ctx,field,cell,element){const text=cellText(cell,field,ctx.fmt),object=isCellObject(cell),span=h("span");applyTone(span,"cx-drawer-text" +(text?"":" p-missing"),toneOf(object?cell.tone:null));setText(span,text||"—");if(object&&cell.title)span.title=cell.title;element.appendChild(span);if(
|
|
40
|
+
const recordCount=(ctx,count)=>formatValue(count,"number",ctx.fmt);const recordRefValid=ref=>!!ref&&typeof ref==="object"&&typeof ref.id==="string"&&!!ref.id&&(ref.view===undefined||typeof ref.view==="string"&&!!ref.view);function recordPlain(ctx,field,cell,element){const text=cellText(cell,field.column||field,ctx.fmt),object=isCellObject(cell),blank=object&&cellValue(cell)==null&&cell.text==="",span=h("span");const column=field.column||field,rule=columnNumericTone(column,cellValue(cell));applyTone(span,"cx-drawer-text" +(text||blank?"":" p-missing"),toneOf(columnValueTone(column,cell)||(object?cell.tone:null)));setText(span,text||blank?text:"—");if(object&&cell.title)span.title=cell.title;element.appendChild(span);if(rule){span.title=rule.label;const label=h("span","p-sub");setText(label,rule.label);element.appendChild(label)}
|
|
41
|
+
if(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge))}
|
|
40
42
|
function recordLink(ctx,cell,field,element,className){const text=cellText(cell,field,ctx.fmt)||cell.ref.id;if(ctx.print||!recordRefValid(cell.ref)){recordPlain(ctx,field,cell,element);return null}
|
|
41
|
-
const link=recordButton(text,()=>ctx.navigate(cell.ref,link),"cx-record-link" +(className?" "+className:""));applyTone(link,link.className,toneOf(cell.tone||null));link.setAttribute("data-cx-origin",field.id+":"+ctx.origins++);if(cell.title)link.title=cell.title;element.appendChild(link);return link}
|
|
43
|
+
const link=recordButton(text,()=>ctx.navigate(cell.ref,link),"cx-record-link" +(className?" "+className:""));applyTone(link,link.className,toneOf(columnValueTone(field.column||field,cell)||cell.tone||null));link.setAttribute("data-cx-origin",field.id+":"+ctx.origins++);if(cell.title)link.title=cell.title;element.appendChild(link);return link}
|
|
42
44
|
function recordScalar(ctx,field,cell,element){const view=ctx.view,grid=recordGridHelpers();if(isCellObject(cell)&&cell.ref){recordLink(ctx,cell,field,element);return}
|
|
43
45
|
if(field.column&&view.paintDrawerValue){if(view.kind==="tree")view.paintDrawerValue(field.column,ctx.node,element,view.columns.indexOf(field.column),ctx);else view.paintDrawerValue(field.column,ctx.row,element,{signal:ctx.signal,width:ctx.width});return}
|
|
44
|
-
if(field.presenter&&
|
|
46
|
+
if((field.presenter||field.wrap)&&view.paintDrawerValue&&view.kind==="grid"){view.paintDrawerValue(field,ctx.row,element,{signal:ctx.signal,width:ctx.width});return}
|
|
45
47
|
recordPlain(ctx,field,cell,element)}
|
|
46
48
|
function recordChip(ctx,field,item){const object=isCellObject(item),text=cellText(item,field,ctx.fmt);if(object&&item.ref&&recordRefValid(item.ref)&&!ctx.print){const holder=h("span");return recordLink(ctx,item,field,holder,"cx-record-chip")}
|
|
47
|
-
const chip=h("span");applyTone(chip,"cx-record-chip",toneOf(object?item.tone:null));setText(chip,text||"—");if(object&&item.title)chip.title=item.title;return chip}
|
|
49
|
+
const chip=h("span");applyTone(chip,"cx-record-chip",toneOf(columnValueTone(field.column||field,item)||(object?item.tone:null)));setText(chip,text||"—");if(object&&item.title)chip.title=item.title;return chip}
|
|
48
50
|
function recordItems(ctx,field,items,element){const list=h("span","cx-record-chips"),limit=ctx.print?items.length:24;for(const item of items.slice(0,limit))list.appendChild(recordChip(ctx,field,item));if(items.length>limit){const more=recordButton(fill(ctx.labels.recordShowAll,{count:recordCount(ctx,items.length)}),()=>{more.remove();for(const item of items.slice(limit))list.appendChild(recordChip(ctx,field,item));list.querySelector(".cx-record-chip:nth-child(" +(limit+1)+ ")")?.focus?.()},"cx-record-more");list.appendChild(more)}
|
|
49
51
|
element.appendChild(list)}
|
|
50
52
|
function recordObject(ctx,field,entries,element,depth){element.classList.add("cx-record-object-value");const list=h("dl","cx-dl cx-record-object");for(const entry of entries){if(!entry||!recordText(entry.name,4096))recordFail("an object field has a name and a value.");const term=h("dt"),value=h("dd");setText(term,entry.name);recordValue(ctx,{id:field.id,title:entry.name,kind:entry.kind||"text",nested:true},entry.value,value,depth+1);list.append(term,value)}
|
|
@@ -161,12 +163,12 @@ if(!items.length)return;const menu=h("div","cx-record-menu"),toggle=recordButton
|
|
|
161
163
|
if(event.key==="Tab"){show(false);return}
|
|
162
164
|
const at=buttons.indexOf(document.activeElement);if(at<0||!["ArrowDown","ArrowUp","Home","End"].includes(event.key))return;event.preventDefault();event.stopPropagation();buttons[{ArrowDown:(at+1)%buttons.length,ArrowUp:(at-1+buttons.length)%buttons.length,Home:0,End:buttons.length-1}[event.key]].focus()});menu.addEventListener("focusout",event=>{if(!menu.contains(event.relatedTarget)&&event.relatedTarget)show(false)});dialog.addEventListener("pointerdown",event=>{if(!menu.contains(event.target))show(false)})}
|
|
163
165
|
async function recordCopy(view,dialog,text){if(!global.navigator.clipboard?.writeText)recordFail("the clipboard is not available.");await global.navigator.clipboard.writeText(text);recordAnnounce(dialog,view.labels.recordCopied)}
|
|
164
|
-
function recordFlat(cell,field,fmt){const kind=recordKind(cell),text=(value,spec=field)=>recordFlat(value,spec,fmt);if(kind==="items")return cell.items.map(item=>text(item)).join(", ");if(kind==="fields")return cell.fields.map(entry=>entry.name+": "+text(entry.value,{kind:entry.kind||"text"})).join("; ");if(kind==="records")return(cell.records.rows||cell.records.roots||[]).map(row=>cell.records.columns.map(column=>text(row.cells?.[column.id]??null,column)).filter(Boolean).join(" · ")).join("\n");if(kind==="events")return cell.events.map(event=>[event.time?formatValue(event.time,"datetime",fmt):"",event.kind,event.actor,event.summary].filter(Boolean).join(" · ")).join("\n");if(kind==="changes")return cell.changes.map(change=>change.name+": "+text(change.before??null)+ " → "+text(change.after??null)).join("\n");return cellText(cell,field,fmt)}
|
|
166
|
+
function recordFlat(cell,field,fmt){const kind=recordKind(cell),text=(value,spec=field)=>recordFlat(value,spec,fmt);if(kind==="items")return cell.items.map(item=>text(item)).join(", ");if(kind==="fields")return cell.fields.map(entry=>entry.name+": "+text(entry.value,{kind:entry.kind||"text"})).join("; ");if(kind==="records")return(cell.records.rows||cell.records.roots||[]).map(row=>cell.records.columns.map(column=>text(row.cells?.[column.id]??null,column)).filter(Boolean).join(" · ")).join("\n");if(kind==="events")return cell.events.map(event=>[event.time?formatValue(event.time,"datetime",fmt):"",event.kind,event.actor,event.summary].filter(Boolean).join(" · ")).join("\n");if(kind==="changes")return cell.changes.map(change=>change.name+": "+text(change.before??null)+ " → "+text(change.after??null)).join("\n");return cellText(cell,field.column||field,fmt)}
|
|
165
167
|
function recordData(view,dialog){const record=dialog._cxRecord,entry=recordEntry(view,record.id),payload=entry?.state==="ready"?entry.payload:null;const fields=recordFields(view),layout=recordLayout(view,fields),items=[],seen=new Set();const walk=(sections,path)=>{for(const section of sections){const name=path?path+" / "+section.label:section.label;for(const field of section.fields)if(!seen.has(field.id)){seen.add(field.id);items.push({section:name,field,cell:recordCell(view,record,payload,field)})}
|
|
166
168
|
walk(section.sections,name)}};walk(layout.tabs.flatMap(tab=>tab.sections),"");for(const field of fields)if(!seen.has(field.id))items.push({section:"",field,cell:recordCell(view,record,payload,field)});return{record,items}}
|
|
167
169
|
function recordExport(view,dialog,format){const{record,items}=recordData(view,dialog),labels=view.labels,title=recordTitle(dialog);if(format==="json")return JSON.stringify({view:view.view.id,id:record.id,title,fields:items.map(item=>
|
|
168
|
-
({id:item.field.id,title:item.field.title,section:item.section,text:recordFlat(item.cell,item.field,view.fmt),value:item.cell===undefined?null:item.cell}))},null,2);const rows=items.map(item=>[item.section,item.field.title,recordFlat(item.cell,item.field,view.fmt)]);if(format==="text")return[title,...rows.map(row=>row[1]+ "\t"+row[2].replace(/\s*\n\s*/g, "; "))].join("\n");
|
|
169
|
-
const quote=value=>{const escaped=gridExportField(
|
|
170
|
+
({id:item.field.id,title:item.field.title,section:item.section,text:recordFlat(item.cell,item.field,view.fmt),value:item.cell===undefined?null:item.cell}))},null,2);const rows=items.map(item=>[item.section,item.field.title,format==="csv"&&item.field.kind==="number"&&typeof cellValue(item.cell)==="number"?cellValue(item.cell):recordFlat(item.cell,item.field,view.fmt)]);if(format==="text")return[title,...rows.map(row=>row[1]+ "\t"+row[2].replace(/\s*\n\s*/g, "; "))].join("\n");
|
|
171
|
+
const quote=value=>{const escaped=gridExportField(value,",");return escaped.startsWith('"')?escaped:'"'+escaped+'"'};return[[labels.recordSection,labels.recordField,labels.recordValue],...rows].map(row=>row.map(quote).join(",")).join("\r\n")}
|
|
170
172
|
function recordDownload(view,dialog,format){const text=recordExport(view,dialog,format),record=dialog._cxRecord;const blob=new Blob([format==="csv"?""+text:text],{type:format==="csv"?"text/csv;charset=utf-8":"application/json"});const link=h("a");link.href=URL.createObjectURL(blob);link.download=(view.view.id+"-"+record.id).replace(/[^\w.-]+/g, "_").slice(0, 100) + "." + format;
|
|
171
173
|
link.hidden=true;document.body.appendChild(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(link.href),10000)}
|
|
172
174
|
let recordPrintDispose;async function recordPrint(view,dialog){if(view.destroyed||!dialog.isConnected)return;recordPrintDispose?.();const record=dialog._cxRecord,entry=recordEntry(view,record.id),payload=entry?.state==="ready"?entry.payload:null;const controller=new AbortController(),signal=AbortSignal.any([controller.signal,view.lifetime.signal]);const sheetOwner=Object.create(dialog,{id:{value:dialog.id+"-print"}});const ctx=recordContext(view,record,sheetOwner,{signal,print:true,index:null},payload);const layout=recordLayout(view,recordFields(view)),showEmpty=RECORD_SHOW_EMPTY||!layout.hideEmpty,sheet=h("div","cx-host cx-record-print"),heading=h("h1");let disposed=false;const changed=()=>{if(dialog._cxRecord!==record)done()};const done=()=>{if(disposed)return;disposed=true;document.documentElement.classList.remove("cx-record-printing");sheet.remove();controller.abort();global.removeEventListener("afterprint",done);dialog.removeEventListener("close",done);dialog.removeEventListener("cx-drawer-paint",changed);signal.removeEventListener("abort",done);if(recordPrintDispose===done)recordPrintDispose=null};recordPrintDispose=done;signal.addEventListener("abort",done,{once:true});dialog.addEventListener("close",done,{once:true});dialog.addEventListener("cx-drawer-paint",changed);sheet.setAttribute("data-cx-theme","light");setText(heading,recordTitle(dialog));sheet.appendChild(heading);const subtitle=dialog.querySelector(".cx-drawer-h p");if(subtitle&&!subtitle.hidden){const line=h("p","cx-record-print-sub");setText(line,subtitle.textContent);sheet.appendChild(line)}
|