@evotecit/canopyx 0.3.16 → 0.3.18
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-board.css +50 -0
- package/CanopyX.Html/Assets/canopyx-board.js +39 -0
- package/CanopyX.Html/Assets/canopyx-buckets.js +15 -0
- package/CanopyX.Html/Assets/canopyx-calculations.css +7 -0
- package/CanopyX.Html/Assets/canopyx-calculations.js +52 -0
- package/CanopyX.Html/Assets/canopyx-calendar-edit.js +3 -3
- package/CanopyX.Html/Assets/canopyx-calendar.css +5 -24
- package/CanopyX.Html/Assets/canopyx-calendar.js +14 -19
- package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
- package/CanopyX.Html/Assets/canopyx-changes.css +6 -24
- package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
- package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
- package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
- package/CanopyX.Html/Assets/canopyx-data.js +3 -3
- package/CanopyX.Html/Assets/canopyx-editing.css +2 -2
- package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
- package/CanopyX.Html/Assets/canopyx-enhance.js +4 -4
- package/CanopyX.Html/Assets/canopyx-export.js +54 -13
- package/CanopyX.Html/Assets/canopyx-facets.css +14 -5
- package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
- package/CanopyX.Html/Assets/canopyx-filter-editor.css +71 -85
- package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
- package/CanopyX.Html/Assets/canopyx-flow-checks.css +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-dialog.css +2 -2
- package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
- package/CanopyX.Html/Assets/canopyx-flow-entry.css +136 -12
- package/CanopyX.Html/Assets/canopyx-flow-entry.js +2 -2
- package/CanopyX.Html/Assets/canopyx-flow-module.mjs +2 -2
- package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
- package/CanopyX.Html/Assets/canopyx-formatting.js +10 -9
- package/CanopyX.Html/Assets/canopyx-grid-module.mjs +182 -128
- package/CanopyX.Html/Assets/canopyx-grid.css +228 -96
- package/CanopyX.Html/Assets/canopyx-grid.js +182 -128
- package/CanopyX.Html/Assets/canopyx-grouping.css +22 -15
- package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
- package/CanopyX.Html/Assets/canopyx-interactive.css +197 -74
- package/CanopyX.Html/Assets/canopyx-interactive.js +38 -45
- package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
- package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
- package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
- package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
- package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
- package/CanopyX.Html/Assets/canopyx-layouts.css +48 -20
- package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
- package/CanopyX.Html/Assets/canopyx-link.js +2 -2
- package/CanopyX.Html/Assets/canopyx-live.css +1 -3
- package/CanopyX.Html/Assets/canopyx-live.js +3 -3
- package/CanopyX.Html/Assets/canopyx-matrix.css +1 -8
- package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
- package/CanopyX.Html/Assets/canopyx-module.mjs +38 -45
- package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
- package/CanopyX.Html/Assets/canopyx-path.css +45 -0
- package/CanopyX.Html/Assets/canopyx-path.js +28 -0
- package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
- package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
- package/CanopyX.Html/Assets/canopyx-plan.css +56 -0
- package/CanopyX.Html/Assets/canopyx-plan.js +67 -0
- package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
- package/CanopyX.Html/Assets/canopyx-record-panel.css +8 -7
- package/CanopyX.Html/Assets/canopyx-record-panel.js +15 -14
- package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +222 -161
- package/CanopyX.Html/Assets/canopyx-reporting.css +240 -107
- package/CanopyX.Html/Assets/canopyx-reporting.js +222 -161
- package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
- package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
- package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
- package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
- package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
- package/CanopyX.Html/Assets/canopyx-tree-tools.css +36 -35
- package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
- package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
- package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
- package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
- package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
- package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
- package/CanopyX.Html/Assets/canopyx-ui-overlays.js +42 -0
- package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
- package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
- package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
- package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
- package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
- package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
- package/CanopyX.Html/Assets/canopyx-values.css +5 -0
- package/CanopyX.Html/Assets/canopyx-values.js +13 -0
- package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
- package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
- package/CanopyX.Html/Assets/canopyx.css +197 -71
- package/CanopyX.Html/Assets/canopyx.js +29 -19
- package/JavaScript/board.d.ts +30 -0
- package/JavaScript/changes.d.ts +4 -1
- package/JavaScript/facets.d.ts +5 -3
- package/JavaScript/grid.d.ts +150 -16
- package/JavaScript/hosts.d.ts +14 -1
- package/JavaScript/index.d.ts +4 -2
- package/JavaScript/locales/de.mjs +177 -9
- package/JavaScript/locales/es.mjs +177 -9
- package/JavaScript/locales/fr.mjs +176 -8
- package/JavaScript/locales/it.mjs +176 -8
- package/JavaScript/locales/pl.mjs +176 -8
- package/JavaScript/matrix.d.ts +4 -1
- package/JavaScript/path.d.ts +33 -0
- package/JavaScript/pivot.d.ts +135 -0
- package/JavaScript/plan.d.ts +23 -0
- package/JavaScript/protocol.d.ts +16 -3
- package/JavaScript/records.d.ts +2 -0
- package/JavaScript/stack.d.ts +28 -0
- package/JavaScript/time-slider.d.ts +58 -0
- package/JavaScript/ui.d.ts +261 -0
- package/JavaScript/view-intents.d.ts +45 -0
- package/README.md +22 -3
- package/ThirdParty/OfficeIMO/LICENSE +21 -0
- package/ThirdParty/OfficeIMO/README.md +13 -0
- package/package.json +76 -3
|
@@ -1,22 +1,63 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"fa85a4b0e8aead4a",requires:["ui-overlays"],install(context){if(installed.has(context.EXPORT_IMPL))return;const{DataGrid,EXPORT_IMPL,h,setText,gridButton,gridOption,fill,numberFormat,gridOperationActive,formatting,gridQuery,validateGridCursorPage,validateGridPage,GRID_REPORTING,gridFreeze,cellValue,cellText,isCellObject,exportTimeout,exportFormat,EXPORT_FORMATS,gridExportField}=context;function printContext(grid,snapshot){const{request,rows}=snapshot,labels=grid.labels,query=request.query,locale=request.locale||grid.lang,scope=labels[request.scope==="all"?"gridAllResults":request.scope==="selected"?"gridSelectedRows":"gridFilteredResults"],parts=[scope,numberFormat(locale).format(rows.length)+ " "+labels.gridRows];if(request.grouping?.levels.length)parts.push(labels.gridGroupedBy+" "+request.grouping.levels.map(level=>level.title).join(", "));if(query?.search)parts.push(labels.searchPlaceholder+": “"+query.search+"”");const filter=item=>{const column=request.columns.find(column=>column.id===item.column),value=item.values??item.value;const operator={eq:"=",ne:"≠",gt:">",ge:"≥",lt:"<",le:"≤",contains:labels.gridContains,startsWith:labels.gridStartsWith,in:labels.gridIn,isNull:labels.gridIsNull,isNotNull:labels.gridIsNotNull}[item.operator]||item.operator;return(column?.title||item.column)+ " "+operator +(value==null?"":" " +(Array.isArray(value)?value.join(", "):String(value)))};const group=value=>"(" +[...(value.filters||[]).map(filter),...(value.groups||[]).map(group)].join(value.operator==="or"?" ∨ ":" ∧ ")+ ")";const filters=[...(query?.filters||[]).map(filter),...(query?.filterGroup?[group(query.filterGroup)]:[])].filter(Boolean);if(filters.length)parts.push(labels.gridFilters+": "+filters.join(" · "));const time=new Date(request.generatedAt||Date.now());parts.push(cellText(time.toISOString(),{kind:"datetime"},formatting(locale,request.timeZone==="local",labels)));return parts.join(" · ")}
|
|
2
|
+
EXPORT_IMPL.snapshot=async function(grid,capture,maxRows,signal,progress=()=>{}){if(!Number.isInteger(maxRows)||maxRows<1||maxRows>10000)throw new Error("CanopyX: print snapshots support 1 to 10000 records.");if(capture.request.recordCount!==null&&capture.request.recordCount>maxRows)
|
|
3
|
+
throw new Error("CanopyX: snapshot exceeds its row bound; use a host export hook.");const rows=[];let size=JSON.stringify(capture.request).length;if(size>4194304)throw new Error("CanopyX: snapshot exceeds its text bound; use a host export hook.");progress("reading",0);for await(const row of grid.exportRows(capture.request,signal)){if(rows.length>=maxRows||(size +=JSON.stringify(row).length+1)>4194304)
|
|
4
|
+
throw new Error("CanopyX: snapshot exceeds its row or text bound; use a host export hook.");rows.push(row);if(rows.length%100===0)progress("reading",rows.length)}
|
|
5
|
+
gridOperationActive(grid,signal);progress("generating",rows.length);return gridFreeze({request:capture.request,rows})};EXPORT_IMPL.printSnapshot=async function(grid,snapshot,signal,layout,templates,projection,cardRoles){gridOperationActive(grid,signal);for(const row of snapshot.rows)if(row.detail!=null){const detail=row.detail;if(detail.type==="html")throw new Error("CanopyX: HTML print details require an onPrint hook or includeDetails: false.");if(detail.type==="table"?!Array.isArray(detail.columns)||!Array.isArray(detail.rows)||
|
|
6
|
+
detail.rows.some(cells=>!Array.isArray(cells)||cells.length!==detail.columns.length):
|
|
7
|
+
detail.type!=="properties"||!Array.isArray(detail.items))throw new Error("CanopyX: invalid static print detail payload.")}
|
|
8
|
+
const frame=document.createElement("iframe");frame.title=grid.labels.gridPrint;frame.style.cssText="position:fixed;width:1px;height:1px;inset:0;border:0;clip-path:inset(100%)";document.body.appendChild(frame);const dispose=()=>frame.remove();signal?.addEventListener("abort",dispose,{once:true});try{const doc=frame.contentDocument,columns=projection?snapshot.request.columns.filter(column=>projection.includes(column.id)):snapshot.request.columns;doc.documentElement.lang=snapshot.request.locale||grid.lang||"en";doc.title=grid.view.label;doc.documentElement.style.colorScheme="light";const theme=getComputedStyle(grid.host);for(const name of theme)if(/^--hfx-(?:font|type|weight)-/.test(name)) doc.documentElement.style.setProperty(name, theme.getPropertyValue(name));
|
|
9
|
+
const add=(tag,parent,text,css)=>{const element=doc.createElement(tag);if(text!==undefined)element.textContent=String(text);if(css)element.style.cssText=css;parent.appendChild(element);return element};add("style",doc.head,"@page{size:A4 " +(layout!=="stacked"&&columns.length>6?"landscape":"portrait")+ ';margin:16mm 14mm;@bottom-right{content:counter(page);font:var(--hfx-type-caption-size,0.75rem) var(--hfx-font-sans,"Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif);color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d))}}' +
|
|
10
|
+
"thead{display:table-header-group}tfoot{display:table-row-group}tr{break-inside:avoid}a{color:inherit;text-decoration:none}" +
|
|
11
|
+
"@media screen{body{padding:40px}main{max-width:1100px;margin:auto}}@media screen and (max-width:600px){body{padding:20px}}" +
|
|
12
|
+
"@media (max-width:600px){body{font-size:10px!important}td,th{padding:6px 4px!important;white-space:normal!important}td.cx-print-number{white-space:nowrap!important}col.cx-print-date{width:80px!important}}" +
|
|
13
|
+
".cx-print-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}" +
|
|
14
|
+
".cx-print-card{break-inside:avoid;min-width:0;border:1px solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-container,var(--hfx-radius-lg,10px));padding:16px}" +
|
|
15
|
+
".cx-print-card-heading{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;margin:0 0 14px}" +
|
|
16
|
+
".cx-print-card h2{flex:1;margin:0;font-size:16px;line-height:1.3;overflow-wrap:anywhere}" +
|
|
17
|
+
".cx-print-card-status{border:1px solid var(--hfx-color-border-strong,light-dark(#cdd0d5,#363a42));border-radius:var(--hfx-radius-pill,999px);padding:2px 7px;font-size:10px}" +
|
|
18
|
+
".cx-print-card dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 16px;margin:0}" +
|
|
19
|
+
".cx-print-card dt{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:10px;margin:0 0 3px}.cx-print-card dd{margin:0;overflow-wrap:anywhere}" +
|
|
20
|
+
".cx-print-card footer{border-top:1px solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));padding-top:10px;margin-top:14px;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d))}" +
|
|
21
|
+
".cx-print-card footer span+span{margin-inline-start:6px}.cx-print-card-wide,.cx-print-cards>h2,.cx-print-cards>[data-cx-print-subtotal],.cx-print-cards>[data-cx-print-total]{grid-column:1/-1}" +
|
|
22
|
+
"@media screen and (min-width:1200px){.cx-print-cards{grid-template-columns:repeat(3,minmax(0,1fr))}}" +
|
|
23
|
+
"@media screen and (max-width:600px){.cx-print-cards{grid-template-columns:minmax(0,1fr)}}" +
|
|
24
|
+
"@media print{body{padding:0}h1{break-after:avoid}header{break-after:avoid}}");doc.body.style.cssText='margin:0;background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));font:11px/1.4 var(--hfx-font-sans,"Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif)';const main=add("main",doc.body),reportHeader=add("header",main,undefined,"margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--hfx-color-border-strong,light-dark(#cdd0d5,#363a42))");add("h1",reportHeader,grid.view.label,"font-size:26px;letter-spacing:-.5px;line-height:1.2;margin:0 0 8px");add("p",reportHeader,printContext(grid,snapshot),"margin:0;max-width:90ch;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:11px;line-height:1.6");const cellStyle="padding:5px 8px;border-bottom:1px solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));text-align:left;vertical-align:top;overflow-wrap:anywhere";const value=(parent,cell)=>{const text=cell&&typeof cell==="object"?cell.text??cell.value??"":cell??"";const link=cell&&typeof cell==="object"&&cell.link?.target;if(typeof link==="string"&&/^(?:https?:|mailto:)/i.test(link)) {
|
|
25
|
+
const anchor=add("a",parent,text,"color:inherit;text-decoration:none");anchor.href=link;if(cell.link.tooltip)anchor.title=cell.link.tooltip}else parent.textContent=String(text)};const detail=(parent,payload)=>{parent.setAttribute("data-cx-print-detail","");if(payload.type==="table"){const table=add("table",parent,undefined,"border-collapse:collapse;width:100%;font:inherit");if(payload.caption)add("caption",table,payload.caption,"text-align:left;font-weight:var(--hfx-weight-semibold,600);margin:4px 0");const headings=add("tr",add("thead",table));for(const column of payload.columns)add("th",headings,column,cellStyle+";overflow-wrap:normal");const body=add("tbody",table);for(const cells of payload.rows){const row=add("tr",body);for(const cell of cells)value(add("td",row,undefined,cellStyle),cell)}}else{const list=add("dl",parent);for(const item of payload.items){add("dt",list,item.name,"font-weight:var(--hfx-weight-semibold,600)");value(add("dd",list,undefined,"margin:0 0 6px;overflow-wrap:anywhere"),item.value)}}};const cell=(row,column)=>{if(!templates||!Object.hasOwn(templates,column.id))return row.cells[column.id];const text=id=>{if(row.templateText&&Object.hasOwn(row.templateText,id))return row.templateText[id];const input=row.cells[id];return input&&typeof input==="object"?input.text??input.value??"":input??""};return{text:typeof templates[column.id]==="string"?templates[column.id].replace(/\{([^{}]+)\}/g, (_, id) => text(id)) : text(column.id) };
|
|
26
|
+
};const grouping=snapshot.request.grouping,starts=new Map(),ends=new Map(),fmt=formatting(snapshot.request.locale||grid.lang,snapshot.request.timeZone==="local",grid.labels);const collect=(groups,depth)=>{for(const group of groups||[]){const headings=starts.get(group.offset)||[];headings.push({text:grouping.levels[depth].title+": "+group.text,depth});starts.set(group.offset,headings);const footers=ends.get(group.offset+group.count)||[];footers.unshift({text:grouping.levels[depth].title+": "+group.text,values:group.aggregates,depth});ends.set(group.offset+group.count,footers);collect(group.groups,depth+1)}};if(grouping)collect(grouping.groups,0);if(layout==="stacked"){const cards=add("div",main);cards.className="cx-print-cards";const summary=(values,label,subtotal)=>{if(!values||!grouping?.aggregates.length)return;const section=add("div",cards,undefined,"break-inside:avoid;padding:8px 10px;margin:0 0 12px;background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));border-top:1px solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));font-weight:var(--hfx-weight-semibold,600)");section.setAttribute(subtotal?"data-cx-print-subtotal":"data-cx-print-total","");add("div",section,label);for(const aggregate of grouping.aggregates){const column=columns.find(column=>column.id===aggregate.column);if(column)add("div",section,(aggregate.label||column.title)+ ": "+cellText(values[aggregate.id],column,fmt))}};for(const[index,row]of snapshot.rows.entries()){for(const heading of starts.get(index)||[])add("h2",cards,heading.text,"font-size:15px;margin:12px 0 6px");const section=add("section",cards);section.className="cx-print-card";section.setAttribute("data-cx-print-record","");const heading=add("div",section);heading.className="cx-print-card-heading";const list=add("dl",section);for(const[index,column]of columns.entries()){const role=cardRoles?.[index]||(index?"field":"title");if(role==="title")value(add("h2",heading),cell(row,column));else if(role==="pill"){const status=add("span",heading);status.className="cx-print-card-status";status.setAttribute("aria-label",column.title);value(status,cell(row,column))}else if(role==="footer"){const footer=add("footer",section);add("span",footer,column.title);value(add("span",footer),cell(row,column))}else{const field=add("div",list);if(role==="wide")field.className="cx-print-card-wide";add("dt",field,column.title);value(add("dd",field),cell(row,column))}}
|
|
27
|
+
if(!list.childNodes.length)list.remove();if(row.detail)detail(add("div",section,undefined,"margin-top:8px"),row.detail);for(const group of ends.get(index+1)||[])summary(group.values,group.text,true)}
|
|
28
|
+
summary(grouping?.totals,grid.labels.gridSummary,false)}else{const table=add("table",main,undefined,"border-collapse:collapse;width:100%;font:inherit"),head=add("thead",table),header=add("tr",head);const widths=add("colgroup",table);table.insertBefore(widths,head);for(const column of columns){const col=add("col",widths,undefined,column.kind==="number"?"width:1%":column.kind==="datetime"?"width:144px":undefined);if(column.kind==="datetime")col.className="cx-print-date";add("th",header,column.title,cellStyle+";overflow-wrap:normal;background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));font-weight:var(--hfx-weight-semibold,600);white-space:nowrap" +(column.kind==="number"?";text-align:right":""))}
|
|
29
|
+
const body=add("tbody",table);const summary=(parent,values,label,subtotal)=>{if(!values||!grouping?.aggregates.length)return;const tr=add("tr",parent);tr.setAttribute(subtotal?"data-cx-print-subtotal":"data-cx-print-total","");for(const[index,column]of columns.entries()){const summaries=grouping.aggregates.filter(aggregate=>aggregate.column===column.id),td=add("td",tr,summaries.length?undefined:index===0?label:"",cellStyle+";font-weight:var(--hfx-weight-semibold,600);background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317))" +
|
|
30
|
+
(column.kind==="number"?";text-align:right":""));for(const aggregate of summaries){const pair=add("div",td);add("span",pair,(aggregate.label||aggregate.operation)+ ": ","display:block;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:9px;font-weight:var(--hfx-weight-regular,400)");add("span",pair,cellText(values[aggregate.id],column,fmt),"display:block;white-space:nowrap")}}};for(const[index,row]of snapshot.rows.entries()){for(const heading of starts.get(index)||[]){const group=add("tr",body),title=add("th",group,heading.text,cellStyle+";background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317))");title.colSpan=columns.length;title.style.paddingInlineStart=(8+heading.depth*12)+ "px"}
|
|
31
|
+
const tr=add("tr",body,undefined,"break-inside:avoid");tr.setAttribute("data-cx-print-record","");for(const column of columns){const td=add("td",tr,undefined,cellStyle);if(column.kind==="number"){td.className="cx-print-number";td.style.textAlign="right";td.style.whiteSpace="nowrap"}
|
|
32
|
+
value(td,cell(row,column))}
|
|
33
|
+
if(row.detail){const next=add("tr",body),holder=add("td",next,undefined,cellStyle);holder.colSpan=columns.length;detail(holder,row.detail)}
|
|
34
|
+
for(const group of ends.get(index+1)||[])summary(body,group.values,group.text,true)}
|
|
35
|
+
summary(add("tfoot",table),grouping?.totals,grid.labels.gridSummary,false)}
|
|
36
|
+
await doc.fonts.ready;await new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)));gridOperationActive(grid,signal);frame.contentWindow.focus();frame.contentWindow.print()}finally{signal?.removeEventListener("abort",dispose);dispose()}};function saveExport(blob,name){const url=URL.createObjectURL(blob),link=h("a");link.href=url;link.download=String(name).replace(/[\\/:*?"<>|\x00-\x1f\x7f\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "_").replace(/^[. ]+|[. ]+$/g, "_");
|
|
2
37
|
document.body.appendChild(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(url),30000)}
|
|
3
|
-
Object.assign(EXPORT_IMPL,{async run(grid,id,options,capture,format){if(!format)throw new Error("CanopyX: export format '"+id+"' is not available.");const total=capture.request.recordCount,onProgress=options.onProgress;if(onProgress!==undefined&&typeof onProgress!=="function"||options.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
38
|
+
Object.assign(EXPORT_IMPL,{async run(grid,id,options,capture,format){if(!format)throw new Error("CanopyX: export format '"+id+"' is not available.");const total=capture.request.recordCount,onProgress=options.onProgress,diagnostics=[];if(onProgress!==undefined&&typeof onProgress!=="function"||options.onDiagnostic!==undefined&&typeof options.onDiagnostic!=="function"||
|
|
39
|
+
options.download!==undefined&&typeof options.download!=="boolean"||options.includeMetadata!==undefined&&typeof options.includeMetadata!=="boolean")
|
|
40
|
+
throw new Error("CanopyX: export callbacks must be functions and download/includeMetadata must be booleans.");const timer=new AbortController(),clock=setTimeout(()=>timer.abort(new DOMException("Export timed out.","TimeoutError")),exportTimeout(grid,options));const signal=AbortSignal.any([grid.lifetime.signal,timer.signal,options.signal].filter(Boolean));const failure=()=>signal.reason?.name==="TimeoutError"?new Error("CanopyX: export timed out."):new DOMException("Export cancelled.","AbortError");const phases=["reading","generating","ready"];let phase=-1,done=0,read=0,inputsComplete=false,finished=false,stop;const report=(name,completed)=>{const next=phases.indexOf(name),count=total===null?completed:Math.min(completed,total);if(signal.aborted||next<phase||!Number.isSafeInteger(completed)||completed<0||next===phase&&count<=done)return;phase=next;done=Math.max(done,count);onProgress?.(Object.freeze({phase:name,completed:done,total}))};const stopped=new Promise((resolve,reject)=>{stop=()=>reject(failure())});signal.addEventListener("abort",stop,{once:true});try{if(signal.aborted)throw failure();const diagnostic=value=>{if(signal.aborted||finished)return;if(!value||typeof value.code!=="string"||!value.code||value.code.length>256||
|
|
41
|
+
[value.columnId,value.rowId].some(id=>id!==undefined&&(typeof id!=="string"||id.length>1024)))
|
|
42
|
+
throw new Error("CanopyX: invalid export diagnostic.");const item=Object.freeze({code:value.code,...(value.columnId===undefined?{}:{columnId:value.columnId}),...(value.rowId===undefined?{}:{rowId:value.rowId})});if(diagnostics.some(known=>known.code===item.code&&known.columnId===item.columnId&&known.rowId===item.rowId))return;if(diagnostics.length>=1000)throw new Error("CanopyX: too many export diagnostics.");diagnostics.push(item);options.onDiagnostic?.(item)};const counted=Object.freeze({request:capture.request,rows:async function*(more){read=0;for await(const row of capture.rows({signal:AbortSignal.any([signal,more?.signal].filter(Boolean))})){if(++read%100===0)report(inputsComplete?"generating":"reading",read);yield row}
|
|
43
|
+
inputsComplete=true;report("generating",read)}});const base=capture.request.fileName||grid.view.id.replace(/[^a-z0-9_-]/gi, "_");
|
|
44
|
+
report("reading",0);let blob=await Promise.race([Promise.resolve().then(()=>format.write(counted,Object.freeze({signal,fileName:base,format:format.id,includeMetadata:options.includeMetadata===true,diagnostic,progress:completed=>report(inputsComplete?"generating":"reading",completed)}))),stopped]).catch(error=>{throw error instanceof Error||error instanceof DOMException?error:new Error("CanopyX: export format '"+id+"' failed: "+String(error))});if(signal.aborted)throw failure();if(blob instanceof ArrayBuffer||ArrayBuffer.isView(blob))blob=new Blob([blob],{type:format.mime});if(!(blob instanceof Blob))throw new Error("CanopyX: export format '"+id+"' must write a Blob.");const fileName=blob.name||base+"."+format.extension;if(options.download!==false)saveExport(blob,fileName);report("generating",read);report("ready",read);return Object.freeze({blob,fileName,format:format.id,diagnostics:Object.freeze(diagnostics.slice())})}finally{finished=true;clearTimeout(clock);signal.removeEventListener("abort",stop)}},async*treeRows(grid,request,rows,signal){const fmt=formatting(request.locale,request.timeZone==="local",grid.labels);const columns=request.columns.map(column=>[column.id,grid.columns.findIndex(item=>item.id===column.id)]);for(const{id,level,path,node}of rows){if(grid.destroyed||signal.aborted)throw new DOMException("Grid cancelled.","AbortError");const cells=Object.create(null);for(const[key,index]of columns){const column=grid.columns[index],cell=grid.cellOf(node,column,index),tone=isCellObject(cell)&&cell.tone;cells[key]=Object.freeze({value:cellValue(cell)??null,text:cellText(cell,column,fmt),...(tone?{tone}:{})})}
|
|
7
45
|
yield Object.freeze({id,level,path:Object.freeze(path),cells:Object.freeze(cells)})}}});function gridWriteClipboard(grid,text,signal){return grid.runGridHook(()=>{const clipboard=global.navigator.clipboard;if(typeof clipboard?.writeText!=="function")throw new Error("CanopyX: clipboard unavailable.");return clipboard.writeText(text)},signal)}
|
|
8
46
|
Object.assign(EXPORT_IMPL,{async*exportRows(request,signal){const{scope}=request;const fmt=formatting(request.locale||this.lang,request.timeZone==="local",this.labels);gridOperationActive(this,signal);const remaining=new Set(request.selection),seen=new Set();if(scope==="selected"&&!remaining.size)return;const expected={revision:request.revision,total:request.total,matched:scope==="filtered"?request.matched:this.cursor?undefined:request.total};const tokens=new Set();let cursor,offset=0;while(this.cursor||offset<expected.matched){gridOperationActive(this,signal);const query=gridQuery(this.view,{...request.query,offset:this.cursor?undefined:offset,cursor});const page=(this.cursor?validateGridCursorPage:validateGridPage)(await this.requestPage(query,signal),this.view,query,expected);if(this.cursor&&(page.offset!==offset||scope!=="filtered"&&page.total!==null&&
|
|
9
47
|
(page.matched!==null&&page.matched!==page.total||page.nextCursor===undefined&&page.offset+page.items.length!==page.total)))
|
|
10
|
-
throw new Error("CanopyX: incomplete cursor export.");expected.matched=page.matched;for(const row of page.items){gridOperationActive(this,signal);if(seen.has(row.id))throw new Error("CanopyX: repeated export row ID.");seen.add(row.id);if(scope!=="selected"||remaining.delete(row.id)){const record=GRID_REPORTING.exportRecord?GRID_REPORTING.exportRecord(this,request,row):gridFreeze({id:row.id,cells:Object.fromEntries(request.columns.map(column=>[column.id,{value:cellValue(row.cells[column.id])??null,text:cellText(row.cells[column.id],column,fmt)}]))});yield GRID_REPORTING.formatRecord?GRID_REPORTING.formatRecord(this,row,record):record}}
|
|
48
|
+
throw new Error("CanopyX: incomplete cursor export.");expected.matched=page.matched;for(const row of page.items){gridOperationActive(this,signal);if(seen.has(row.id))throw new Error("CanopyX: repeated export row ID.");seen.add(row.id);if(scope!=="selected"||remaining.delete(row.id)){const record=GRID_REPORTING.exportRecord?GRID_REPORTING.exportRecord(this,request,row):gridFreeze({id:row.id,cells:Object.fromEntries(request.columns.map(column=>[column.id,{value:cellValue(row.cells[column.id])??null,text:cellText(row.cells[column.id],column,fmt)}]))});yield GRID_REPORTING.formatRecord?GRID_REPORTING.formatRecord(this,row,record,request):record}}
|
|
11
49
|
offset +=this.cursor?page.items.length:request.query.limit;if(this.cursor){cursor=page.nextCursor;if(cursor===undefined)break;if(tokens.has(cursor))throw new Error("CanopyX: cursor export repeated a token.");tokens.add(cursor)}}
|
|
12
50
|
gridOperationActive(this,signal);if(remaining.size)throw new Error("CanopyX: selected IDs absent from revision.")},async exportText(exported,maxRows=50000,delimiter,signal){if(!Number.isInteger(maxRows)||maxRows<1||maxRows>1000000)throw new Error("CanopyX: export row limit is 1 to 1000000.");const request=exported.request;if(request.recordCount>maxRows)throw new Error("CanopyX: client row limit exceeded.");const lines=[request.columns.map(column=>gridExportField(column.title,delimiter)).join(delimiter)];let count=0;for await(const row of exported.rows()){if(++count>maxRows)throw new Error("CanopyX: client row limit exceeded.");lines.push(request.columns.map(column=>{const value=request.values==="raw"?row.cells[column.id]?.value:row.cells[column.id]?.text;return gridExportField(row.level>1&&column.id===this.columns[0].id?" ".repeat(row.level-1)+(value??""):value,delimiter)}).join(delimiter))}
|
|
13
51
|
gridOperationActive(this,signal);return lines.join("\r\n")+ "\r\n"},toCsv(capture,options){return this.exportText(capture,options.maxRows,",",options.signal)},async copy(capture,options){const text=await this.exportText(capture,options.maxRows===undefined?10000:options.maxRows,"\t",options.signal);await gridWriteClipboard(this,text,options.signal);return text},copyFocused(row,cell){if(this.selected.size)return this.copy({scope:"selected"});const columns=this.visibleColumns(),element=this.rendered.get(row),index=cell&&element?this.rowCells(element).indexOf(cell):-1;const text=index>=0?gridExportField(cellText(row.h.cells[columns[index].id],columns[index],this.fmt),"\t"):
|
|
14
52
|
columns.map(column=>gridExportField(cellText(row.h.cells[column.id],column,this.fmt),"\t")).join("\t");return gridWriteClipboard(this,text)},exportToHost(capture,format,options){if(typeof format!=="string"||!format.trim()||typeof this.opts.onExport!=="function")throw new Error("CanopyX: invalid host export.");return this.runGridHook(signal=>this.opts.onExport({format,request:capture.request,capture,signal}),options.signal,exportTimeout(this,options))}});Object.assign(EXPORT_IMPL,{exportFromMenu(action){const{details,panel}=this.exportControl;this.renderGridExport(panel);details.open=true;if(!this.phone&&this.overflow)this.overflow.details.open=false;panel.cxRun(action)}});const exportMenu=function(panel){if(panel.cxRun)return panel.cxFormats();panel.replaceChildren();const reporting=!!this.view.reporting,scope=h("select"),labels=this.labels;const menu=this.opts.exportMenu??{};if(!menu||typeof menu!=="object"||Array.isArray(menu)||
|
|
15
|
-
Object.keys(menu).some(key=>!["csv","copy","values"].includes(key))||
|
|
16
|
-
["csv","copy"].some(key=>menu[key]!==undefined&&typeof menu[key]!=="boolean")||
|
|
53
|
+
Object.keys(menu).some(key=>!["csv","copy","print","values"].includes(key))||
|
|
54
|
+
["csv","copy","print"].some(key=>menu[key]!==undefined&&typeof menu[key]!=="boolean")||
|
|
17
55
|
menu.values!==undefined&&!["raw","display"].includes(menu.values))
|
|
18
|
-
throw new Error("CanopyX: exportMenu supports csv/copy booleans and raw/display values.");scope.setAttribute("aria-label",labels.gridExport);for(const[value,label]of this.exportScopes||[["filtered","gridFilteredResults"],["selected","gridSelectedRows"],["all","gridAllResults"]])
|
|
19
|
-
scope.appendChild(gridOption(value,labels[label]));const
|
|
20
|
-
}));const
|
|
21
|
-
panel.
|
|
22
|
-
|
|
56
|
+
throw new Error("CanopyX: exportMenu supports csv/copy/print booleans and raw/display values.");scope.setAttribute("aria-label",labels.gridExport+": "+labels.gridRows);for(const[value,label]of this.exportScopes||[["filtered","gridFilteredResults"],["selected","gridSelectedRows"],["all","gridAllResults"]])
|
|
57
|
+
scope.appendChild(gridOption(value,labels[label]));panel.classList.add("cx-export-panel");const count=h("p","cx-export-count"),list=h("div","cx-export-formats"),actions=h("div","cx-export-actions");count.setAttribute("role","status");const updateCount=()=>{try{const request=this.prepareExport({scope:scope.value}).request;setText(count,request.recordCount===null?labels.gridUnknownCount:
|
|
58
|
+
numberFormat(this.lang).format(request.recordCount)+ " "+labels.gridRows)}catch{setText(count,scope.selectedOptions[0].textContent)}};scope.addEventListener("change",updateCount);const decorate=(button,title,hint,icon)=>{button.classList.add("cx-export-choice");button.setAttribute("aria-label",title);const symbol=h("span","cx-export-icon");symbol.setAttribute("aria-hidden","true");setText(symbol,icon);const content=h("span","cx-export-choice-text"),name=h("span","cx-export-choice-title");setText(name,title);content.append(name);if(hint){const note=h("span","cx-export-hint");setText(note,hint);content.append(note)}
|
|
59
|
+
button.replaceChildren(symbol,content);return button};const status=h("p","cx-grid-delivery-status");status.setAttribute("role","status");const meter=h("progress");meter.setAttribute("aria-label",labels.gridExport);meter.hidden=true;let operation=null,formats=[];panel.cxExportBusy=()=>operation!==null;const cancel=gridButton(labels.gridCancelExport,()=>operation?.abort());cancel.hidden=true;const progress=value=>{if(this.destroyed||!operation||operation.signal.aborted)return;setText(status,fill(value.total===null?labels.gridExportReading:labels.gridExportProgress,{completed:numberFormat(this.lang).format(value.completed),total:value.total===null?"":numberFormat(this.lang).format(value.total)}));if(value.total===null)meter.removeAttribute("value");else{meter.max=Math.max(1,value.total);meter.value=value.completed}};const canExport=()=>this.view.type!=="grid"||this.defaultExportColumns().length>0;const busy=state=>{scope.disabled=state;cancel.hidden=meter.hidden=!state;for(const button of[csv,...formats,copy,print,this.printButton])if(button)button.disabled=state||!canExport()};const traced=(options,onProgress)=>reporting?{...options,onProgress}:options;panel.cxRun=action=>{if(operation)return;const controller=operation=new AbortController();busy(true);meter.removeAttribute("value");setText(status,labels.loading);Promise.resolve().then(()=>action({scope:scope.value,signal:controller.signal,...(menu.values?{values:menu.values}:{})},progress)).then(()=>{if(!this.destroyed)setText(status,"")},error=>{if(!this.destroyed)setText(status,error.name==="AbortError"?labels.gridExportCancelled:error.message);if(error.name!=="AbortError")this.emit("error",{error})}).finally(()=>{if(operation===controller)operation=null;if(!this.destroyed){const returnFocus=document.activeElement===cancel;busy(false);if(returnFocus)scope.focus()}})};const csv=gridButton(labels.gridDownloadCsv,()=>panel.cxRun(async(options,onProgress)=>{const exported=this.prepareExport(traced(options,onProgress));const text=await this.exportText(exported,50000,",",options.signal);gridOperationActive(this,options.signal);saveExport(new Blob([text],{type:"text/csv;charset=utf-8"}),(exported.request.fileName||this.view.id.replace(/[^a-z0-9_-]/gi, "_")) + ".csv");
|
|
60
|
+
}));decorate(csv,labels.gridDownloadCsv,labels.gridExportCsvHint,"CSV");const copy=this.copy?decorate(gridButton(labels.gridCopy,()=>panel.cxRun((options,onProgress)=>this.copy(traced(options,onProgress)))),labels.gridExportCopy,null,"⧉"):h("span");const print=typeof this.print==="function"?gridButton(labels.gridPrint,()=>panel.cxRun((options,onProgress)=>
|
|
61
|
+
this.print({...options,onProgress}))):h("span");decorate(print,labels.gridPrint,null,"▤");print.hidden=true;this.exportPrintButton=print;csv.hidden=menu.csv===false;copy.hidden=!this.copy||menu.copy===false;panel.cxFormats=()=>{if(operation)return;formats.forEach(button=>button.remove());try{const available=EXPORT_IMPL.formatsOf(this);print.hidden=!(typeof this.print==="function"&&(menu.print??true));formats=available.filter(format=>format.showInMenu&&(!this.pivotState?.active||!["xlsx","pdf"].includes(format.id))).map(format=>Object.assign(decorate(gridButton(format.label,()=>
|
|
62
|
+
panel.cxRun((options,onProgress)=>this.exportAs(format.id,{...options,onProgress}))),format.label,format.id==="xlsx"?labels.gridExportWorkbookHint:format.id==="pdf"?labels.gridExportPdfHint:null,format.extension.toUpperCase()),{value:format.id}))}catch(error){formats=[];this.emit("error",{error})}
|
|
63
|
+
list.replaceChildren(...formats,csv);actions.hidden=copy.hidden&&print.hidden;updateCount();busy(false);if(!canExport())setText(status,labels.gridNoExportColumns);else if(status.textContent===labels.gridNoExportColumns)setText(status,"")};actions.append(copy,print);panel.append(scope,count,meter,status,cancel,list,actions);panel.cxFormats()};DataGrid.prototype.renderGridExport=exportMenu;installed.add(context.EXPORT_IMPL)}};(global.CanopyXParts||=[]).push(["export",part])})(typeof window!=="undefined"?window:globalThis);
|
|
@@ -10,8 +10,7 @@ body.cx-page > .cx-facet-frame[data-cx-position="side"] > .cx-data-grid,body.cx-
|
|
|
10
10
|
.cx-facets[data-cx-position="side"]{flex:none;width:var(--cx-facets-w,260px);align-self:flex-start;display:flex;flex-direction:column;}
|
|
11
11
|
.cx-facets-h{display:flex;align-items:center;gap:var(--cx-size-6px);min-height:var(--cx-size-44px);padding:var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-12px);border-bottom:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
|
|
12
12
|
.cx-facets-title{flex:1;min-width:0;margin:0;font-size:var(--cx-size-14px);font-weight:600;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
13
|
-
.cx-facets .cx-button{
|
|
14
|
-
.cx-facets .cx-button:hover{background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));}
|
|
13
|
+
.cx-facets .cx-button{block-size:var(--hfx-control-height-sm,calc(28px - var(--cx-compact,0) * 4px));min-block-size:var(--hfx-control-height-sm,calc(28px - var(--cx-compact,0) * 4px));padding:0 var(--hfx-space-2,0.5rem);border-color:transparent;background:transparent;color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));}
|
|
15
14
|
.cx-facets .cx-button:focus-visible,.cx-facet-toggle:focus-visible,.cx-facet-val input:focus-visible,.cx-facets .cx-input:focus-visible{outline:var(--hfx-focus-width,2px) solid var(--hfx-color-focus-ring,light-dark(#02726a,#37c9b8));outline-offset:var(--hfx-focus-offset,2px);}
|
|
16
15
|
.cx-facets-toggle{width:var(--cx-size-28px);padding:0;}
|
|
17
16
|
.cx-facets-toggle .cx-ico,.cx-facets-open .cx-ico{width:var(--cx-size-16px);height:var(--cx-size-16px);}
|
|
@@ -33,7 +32,7 @@ body.cx-page > .cx-facet-frame[data-cx-position="side"] > .cx-data-grid,body.cx-
|
|
|
33
32
|
.cx-facet-toggle[aria-expanded="false"]::after{transform:rotate(-45deg);}
|
|
34
33
|
.cx-facet-toggle:hover{background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));}
|
|
35
34
|
.cx-facet-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
36
|
-
.cx-facet-badge{flex:none;min-
|
|
35
|
+
.cx-facet-badge{flex:none;min-inline-size:var(--hfx-badge-height,20px);block-size:var(--hfx-badge-height,20px);padding:0 var(--hfx-space-1-5,6px);border-radius:var(--hfx-radius-pill,999px);background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));color:var(--hfx-color-accent-text,light-dark(#02726a,#37c9b8));font-size:var(--hfx-type-caption-size,0.75rem);font-weight:var(--hfx-weight-semibold,600);line-height:var(--hfx-badge-height,20px);text-align:center;}
|
|
37
36
|
.cx-facet-badge[hidden]{display:none;}
|
|
38
37
|
.cx-facets .cx-facet-clear{position:absolute;top:var(--cx-size-4px);inset-inline-end:var(--cx-size-30px);width:var(--cx-size-28px);min-height:var(--cx-size-28px);padding:0;}
|
|
39
38
|
.cx-facets .cx-facet-clear .cx-ico{width:var(--cx-size-14px);height:var(--cx-size-14px);}
|
|
@@ -58,9 +57,8 @@ body.cx-page > .cx-facet-frame[data-cx-position="side"] > .cx-data-grid,body.cx-
|
|
|
58
57
|
.cx-facet-axis{display:flex;justify-content:space-between;gap:var(--cx-size-8px);margin:0 0 var(--cx-size-6px);color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-size:var(--cx-size-12px);font-variant-numeric:tabular-nums;}
|
|
59
58
|
.cx-facet-range{display:grid;grid-template-columns:1fr 1fr;gap:var(--cx-size-8px);}
|
|
60
59
|
.cx-facet-field{display:flex;flex-direction:column;gap:var(--cx-size-2px);min-width:0;color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));font-size:var(--cx-size-12d5px);}
|
|
61
|
-
.cx-facet-field .cx-input{
|
|
60
|
+
.cx-facet-field .cx-input{inline-size:100%;block-size:var(--hfx-control-height-sm,calc(28px - var(--cx-compact,0) * 4px));padding:0 var(--hfx-space-1-5,6px);color-scheme:inherit;}
|
|
62
61
|
.cx-data-grid .cx-facets-open[hidden]{display:none;}
|
|
63
|
-
.cx-data-grid .cx-facets-open .badge{min-width:var(--cx-size-18px);height:var(--cx-size-18px);padding:0 var(--cx-size-5px);border-radius:var(--hfx-radius-badge,var(--hfx-radius-sm,4px));background:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));color:var(--hfx-color-surface,light-dark(#ffffff,#16181c));font-size:var(--cx-size-11px);line-height:var(--cx-size-18px);}
|
|
64
62
|
.cx-facet-sheet.cx-host{position:fixed;inset:0;width:100%;max-width:none;height:100%;max-height:none;margin:0;padding:0;border:0;border-radius:0;flex-direction:column;}
|
|
65
63
|
.cx-facet-sheet.cx-host[open]{display:flex;}
|
|
66
64
|
.cx-facet-sheet::backdrop{background:var(--hfx-color-overlay,light-dark(rgba(22,24,28,0.42),rgba(0,0,0,0.66)));}
|
|
@@ -84,3 +82,14 @@ body.cx-page > .cx-facet-frame[data-cx-position="side"] > .cx-data-grid,body.cx-
|
|
|
84
82
|
.cx-facet-top{background:Canvas;}
|
|
85
83
|
}
|
|
86
84
|
@media print{.cx-facets,.cx-data-grid .cx-facets-open{display:none;}}
|
|
85
|
+
.cx-facet-frame[data-cx-position="top"]{gap:0;border:var(--hfx-border-width,1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));overflow:hidden;}
|
|
86
|
+
.cx-facet-frame[data-cx-position="top"] > .cx-host{border:0;border-radius:0;}
|
|
87
|
+
.cx-facets[data-cx-position="top"] .cx-facet{max-width:none;}
|
|
88
|
+
.cx-facets[data-cx-position="top"] .cx-facet-values{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,calc(var(--hfx-space-6,2rem)*6)),1fr));}
|
|
89
|
+
.cx-grid-facet > .cx-grid-panel{display:block;max-height:calc(var(--hfx-space-6,2rem) * 15);overflow:auto;}
|
|
90
|
+
.cx-chrome .cx-grid-facet > summary::after{display:block;}
|
|
91
|
+
.cx-grid-facet .cx-facet{border:0;}
|
|
92
|
+
.cx-grid-facet .cx-facet-h{display:none;}
|
|
93
|
+
.cx-grid-facet .cx-facet-top{min-height:var(--hfx-control-height-md,calc(36px - var(--cx-compact,0) * 8px));}
|
|
94
|
+
.cx-grid-facet .cx-facet-top:has(.cx-facet-clear[hidden]){display:none;}
|
|
95
|
+
.cx-grid-facet > summary.cx-facet-active{border-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));color:var(--hfx-color-accent-text,light-dark(#02726a,#37c9b8));}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
(function(global){"use strict";const installed=new WeakSet();const part={version:"
|
|
1
|
+
(function(global){"use strict";const installed=new WeakSet();const part={version:"f1ed74d2447e4f11",install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,h,setText,fill,gridButton,gridIcon,gridQueryStart,gridQueryRows,gridColumnProjection,gridScalar,gridOrder,gridKeyCompare,gridFacetKey,cellText,foldText,numberFormat,gridCellRenderer,gridFreeze,overlayTheme,watchOverlayTheme,GRID_BUCKETS,gridBucketDefinition}=context;function gridColumnGroup(operator,items){const filters=[],groups=[];for(const item of items){if(typeof item==="boolean"){if(item===(operator==="or"))return item;continue}
|
|
2
2
|
if(item.operator===operator){filters.push(...item.filters);groups.push(...item.groups)}
|
|
3
3
|
else(item.groups?groups:filters).push(item)}
|
|
4
4
|
return!filters.length&&!groups.length?operator==="and":!filters.length&&groups.length===1?groups[0]:{operator,filters,groups}}
|
|
5
|
-
function gridColumnClauses(query,id){const clauses=[],has=group=>group.filters.some(item=>item.column===id)||group.groups.some(has),only=group=>group.filters.every(item=>item.column===id)&&group.groups.every(only);const remove=group=>{if(!group)return undefined;if(only(group)){clauses.push(group);return undefined}
|
|
5
|
+
function gridColumnClauses(query,id){if(query.tupleFilters?.some(tuple=>tuple.columns.some(field=>field.column===id)))throw new Error("complex");const clauses=[],has=group=>group.filters.some(item=>item.column===id)||group.groups.some(has),only=group=>group.filters.every(item=>item.column===id)&&group.groups.every(only);const remove=group=>{if(!group)return undefined;if(only(group)){clauses.push(group);return undefined}
|
|
6
6
|
if(group.operator==="or"&&has(group))throw new Error("complex");const filters=group.filters.filter(item=>{if(item.column!==id)return true;clauses.push(item);return false}),groups=group.groups.map(remove).filter(Boolean);if(!filters.length&&!groups.length)return undefined;return gridColumnGroup(group.operator,[...filters,...groups])};const filters=(query.filters||[]).filter(item=>{if(item.column!==id)return true;clauses.push(item);return false}),filterGroup=remove(query.filterGroup);return{clauses,query:{...query,filters,filterGroup}}}
|
|
7
7
|
function gridInstallColumnClause(query,id,clause){const base=gridColumnClauses(query,id).query;if(!clause)return gridQueryStart(base);if(!clause.groups)return gridQueryStart(base,{filters:[...base.filters,clause]});return gridQueryStart(base,{filterGroup:base.filterGroup?gridColumnGroup("and",[base.filterGroup,clause]):clause})}
|
|
8
|
-
const FACET_KEYS=new Set(["columns","position","open","collapsible","width","label","target"]);const FACET_COLUMN_KEYS=new Set(["column","kind","label","limit","bins","sort","collapsed"]);const FACET_VALUES=200;function facetOptions(grid){const read=value=>{if(value===undefined)return{};if(!value||typeof value!=="object"||Array.isArray(value)||Object.keys(value).some(key=>!FACET_KEYS.has(key)))
|
|
8
|
+
const FACET_KEYS=new Set(["columns","position","open","collapsible","width","label","target"]);const FACET_COLUMN_KEYS=new Set(["column","kind","label","limit","bins","sort","collapsed","bucket"]);const FACET_VALUES=200;function facetOptions(grid){const read=value=>{if(value===undefined)return{};if(!value||typeof value!=="object"||Array.isArray(value)||Object.keys(value).some(key=>!FACET_KEYS.has(key)))
|
|
9
9
|
throw new Error("CanopyX: facets takes columns, position, open, collapsible, width, label and target.");return value};const merged={...read(grid.view.facets),...read(grid.opts.facets)},columns=new Map(grid.view.columns.map(column=>[column.id,column]));if(!Array.isArray(merged.columns)||!merged.columns.length||merged.columns.length>24)throw new Error("CanopyX: facets need 1 to 24 columns.");const seen=new Set();const facets=merged.columns.map(entry=>{const facet=typeof entry==="string"?{column:entry}:entry;if(!facet||typeof facet!=="object"||Object.keys(facet).some(key=>!FACET_COLUMN_KEYS.has(key))||!columns.has(facet.column)||seen.has(facet.column)||
|
|
10
10
|
facet.kind!==undefined&&!["list","range"].includes(facet.kind)||facet.label!==undefined&&(typeof facet.label!=="string"||!facet.label.trim()||facet.label.length>256)||
|
|
11
11
|
facet.limit!==undefined&&(!Number.isInteger(facet.limit)||facet.limit<1||facet.limit>FACET_VALUES)||
|
|
12
12
|
facet.bins!==undefined&&(!Number.isInteger(facet.bins)||facet.bins<2||facet.bins>60)||facet.sort!==undefined&&!["count","value"].includes(facet.sort)||
|
|
13
13
|
facet.collapsed!==undefined&&typeof facet.collapsed!=="boolean")
|
|
14
|
-
throw new Error("CanopyX: invalid or duplicate facet column " +(facet&&facet.column));seen.add(facet.column);const
|
|
14
|
+
throw new Error("CanopyX: invalid or duplicate facet column " +(facet&&facet.column));seen.add(facet.column);const sourceDef=columns.get(facet.column),bucket=facet.bucket===undefined?null:gridBucketDefinition(facet.bucket,sourceDef);const column=bucket?{...sourceDef,kind:"number",presenter:undefined,valueOrder:undefined,valueLabels:undefined}:sourceDef,kind=facet.kind||(bucket||column.kind==="text"?"list":"range");if(bucket&&kind!=="list")throw new Error("CanopyX: a bucket facet uses a value list.");if(kind==="range"&&column.kind==="text")throw new Error("CanopyX: range facets need number or date columns.");const order=kind==="list"?facetDeclaredOrder(grid,column):null;return{column:facet.column,def:column,sourceDef,bucket,kind,label:facet.label||column.title,limit:facet.limit||8,bins:facet.bins||16,sort:bucket?"value":facet.sort||(kind==="list"&&!order?"count":"value"),order,collapsed:!!facet.collapsed}});if(merged.position!==undefined&&!["side","top","toolbar"].includes(merged.position)||["open","collapsible"].some(key=>merged[key]!==undefined&&typeof merged[key]!=="boolean")||
|
|
15
15
|
merged.width!==undefined&&(!Number.isInteger(merged.width)||merged.width<180||merged.width>480)||
|
|
16
16
|
merged.label!==undefined&&(typeof merged.label!=="string"||!merged.label.trim()||merged.label.length>256)||
|
|
17
17
|
merged.target!==undefined&&!(merged.target instanceof HTMLElement))
|
|
@@ -20,26 +20,27 @@ throw new Error("CanopyX: a hosted grid's facets must be declared reporting face
|
|
|
20
20
|
function facetDeclaredOrder(grid,column){const presenter=column.presenter,values=column.valueOrder||grid.view.reporting?.ordering?.[column.id]?.categories||
|
|
21
21
|
(presenter&&(presenter.kind==="enum"||presenter.kind==="state")&&presenter.tones?Object.keys(presenter.tones):null);return values&&values.length?new Map(values.map((value,index)=>[gridFacetKey(value,column),index])):null}
|
|
22
22
|
function facetSelection(query,facet){let clauses;try{({clauses}=gridColumnClauses(query,facet.column))}catch(_){return{custom:true,locked:true}}
|
|
23
|
-
if(!clauses.length)return{none:true};if(facet.kind==="list"){const listed=clause=>["in","eq","isNull"].includes(clause.operator)&&!clause.groups;const items=clauses.length!==1?null:clauses[0].groups?clauses[0].operator==="or"&&!clauses[0].groups.length&&clauses[0].filters.every(listed)?clauses[0].filters:null:listed(clauses[0])?clauses:null;return items?{values:items.flatMap(clause=>clause.operator==="isNull"?[null]:clause.values)}:{custom:true}}
|
|
23
|
+
if(!clauses.length)return{none:true};if(facet.kind==="list"){const listed=clause=>["in","eq","isNull"].includes(clause.operator)&&!clause.groups&&JSON.stringify(clause.bucket||null)===JSON.stringify(facet.bucket||null);const items=clauses.length!==1?null:clauses[0].groups?clauses[0].operator==="or"&&!clauses[0].groups.length&&clauses[0].filters.every(listed)?clauses[0].filters:null:listed(clauses[0])?clauses:null;return items?{values:items.flatMap(clause=>clause.operator==="isNull"?[null]:clause.values)}:{custom:true}}
|
|
24
24
|
let low=null,high=null,lowOpen=false,open=false;for(const clause of clauses){if(clause.groups||clauses.length>2)return{custom:true};if((clause.operator==="ge"||clause.operator==="gt")&&low===null){low=clause.values[0];lowOpen=clause.operator==="gt"}
|
|
25
25
|
else if((clause.operator==="le"||clause.operator==="lt")&&high===null){high=clause.values[0];if(clause.operator==="lt")open=true}
|
|
26
26
|
else return{custom:true}}
|
|
27
27
|
return{low,high,lowOpen,open}}
|
|
28
|
-
function facetQuery(query,facet,choice){const predicate=(operator,values=[])=>({column:facet.column,operator,values});try{if(facet.kind==="range"){const base=gridColumnClauses(query,facet.column).query;const bounds=[choice.low!=null&&predicate(choice.lowOpen?"gt":"ge",[choice.low]),choice.high!=null&&predicate(choice.open?"lt":"le",[choice.high])].filter(Boolean);return gridQueryStart(base,{filters:[...base.filters,...bounds]})}
|
|
28
|
+
function facetQuery(query,facet,choice){const predicate=(operator,values=[])=>({column:facet.column,operator,values,...(facet.bucket?{bucket:facet.bucket}:{})});try{if(facet.kind==="range"){const base=gridColumnClauses(query,facet.column).query;const bounds=[choice.low!=null&&predicate(choice.lowOpen?"gt":"ge",[choice.low]),choice.high!=null&&predicate(choice.open?"lt":"le",[choice.high])].filter(Boolean);return gridQueryStart(base,{filters:[...base.filters,...bounds]})}
|
|
29
29
|
const raw=choice.filter(value=>value!==null),empty=raw.length<choice.length;const items=[raw.length&&predicate("in",raw),empty&&predicate("isNull")].filter(Boolean);return gridInstallColumnClause(query,facet.column,!items.length?null:items.length===1?items[0]:{operator:"or",filters:items,groups:[]})}catch(_){return query}}
|
|
30
|
-
const facetShape=query=>query?JSON.stringify([query.search,query.searchMode,query.filters,query.filterGroup,query.revision]):"";const facetKey=gridFacetKey;function facetInlineCounts(grid,facet,query){const projection=gridColumnProjection(query,facet.column),columns=new Map(grid.view.columns.map(column=>[column.id,column]));const rows=gridQueryRows(grid.view,projection,columns,false),column=facet.def;if(facet.kind==="range"){const values=[];for(const row of rows){const value=gridScalar(row.cells[column.id],column);if(value!==null)values.push(value)}
|
|
30
|
+
const facetShape=query=>query?JSON.stringify([query.search,query.searchMode,query.filters,query.filterGroup,query.tupleFilters,query.revision]):"";const facetKey=gridFacetKey;function facetInlineCounts(grid,facet,query){const projection=gridColumnProjection(query,facet.column),columns=new Map(grid.view.columns.map(column=>[column.id,column]));const rows=gridQueryRows(grid.view,projection,columns,false),column=facet.def;if(facet.kind==="range"){const values=[];for(const row of rows){const value=gridScalar(row.cells[column.id],column);if(value!==null)values.push(value)}
|
|
31
31
|
return{matched:rows.length,values,complete:true}}
|
|
32
|
-
const buckets=new Map();for(const row of rows){const raw=gridScalar(row.cells[column.id],
|
|
32
|
+
const buckets=new Map();for(const row of rows){const raw=gridScalar(row.cells[column.id],facet.sourceDef),value=facet.bucket?GRID_BUCKETS.key(facet.bucket,raw):column.kind==="datetime"&&raw!==null?new Date(raw).toISOString():raw,key=facetKey(value,column);const bucket=buckets.get(key);if(bucket){bucket.count++;if(typeof value==="string"&&value<bucket.value)bucket.value=value}else buckets.set(key,{value,count:1})}
|
|
33
33
|
const items=[...buckets.values()];return{matched:rows.length,items,totalValues:items.length,truncated:false}}
|
|
34
|
-
async function facetHostedCounts(grid,facet,search,signal){const page=await grid.getFacets(facet.column,{search:search||"",includeCurrentFilter:false,limit:FACET_VALUES,signal});const column=facet.def;if(facet.kind==="range")
|
|
34
|
+
async function facetHostedCounts(grid,facet,search,signal){const page=await grid.getFacets(facet.column,{search:search||"",includeCurrentFilter:false,limit:FACET_VALUES,signal,...(facet.bucket?{bucket:facet.bucket}:{})});const column=facet.def;if(facet.kind==="range")
|
|
35
35
|
return{matched:page.matched,buckets:page.items.filter(item=>item.value!==null).map(item=>({value:gridScalar(item.value,column),count:item.count})),complete:!page.truncated};return{matched:page.matched,items:page.items.map(item=>({value:item.value,count:item.count})),totalValues:page.totalValues,truncated:page.truncated}}
|
|
36
|
-
const FACET_SEARCH_FROM=12;function facetListBody(panel,facet,body){const grid=panel.grid,search=h("input","cx-input cx-facet-search"),list=h("ul","cx-facet-values"),more=gridButton("",()=>{state.expanded=!state.expanded;draw()});const note=h("p","cx-facet-note"),state={expanded:false,search:"",counts:null,timer:0};search.type="search";search.placeholder=grid.labels.gridFacetSearch;search.setAttribute("aria-label",fill(grid.labels.gridFacetSearch,{})+ ": "+facet.label);search.hidden=true;more.classList.add("cx-facet-more");more.hidden=true;note.hidden=true;list.setAttribute("aria-label",facet.label);body.append(search,list,more,note);search.addEventListener("input",()=>{state.search=search.value;clearTimeout(state.timer);state.timer=setTimeout(()=>facet.hosted?panel.refresh([facet]):draw(),facet.hosted?250:0)});list.addEventListener("keydown",event=>{const boxes=[...list.querySelectorAll("input")],at=boxes.indexOf(document.activeElement);const next={ArrowDown:at+1,ArrowUp:at-1,Home:0,End:boxes.length-1}[event.key];if(at<0||next===undefined||!boxes[next])return;event.preventDefault();boxes.forEach(box=>{box.tabIndex=-1});boxes[next].tabIndex=0;boxes[next].focus()});const choose=(item,checked)=>{const chosen=new Map((state.chosen||[]).map(value=>[facetKey(value,facet.def),value]));if(checked)chosen.set(facetKey(item.value,facet.def),item.value);else chosen.delete(facetKey(item.value,facet.def));state.chosen=[...chosen.values()];panel.apply(facet,state.chosen)};function draw(){const counts=state.counts,selection=panel.selection(facet);if(!counts)return;state.chosen=selection.values||[];const chosen=new Set(state.chosen.map(value=>facetKey(value,facet.def))),focused=list.contains(document.activeElement)?document.activeElement:null;const focusKey=focused?.getAttribute("data-cx-key"),focusPosition=focused?[...list.querySelectorAll("input")].indexOf(focused):0;const needle=facet.hosted?"":foldText(state.search),locked=!!selection.locked;let items=counts.items.filter(item=>!needle||item.value!==null&&foldText(cellText(item.value,facet.def,grid.fmt)).includes(needle));if(!(facet.hosted&&state.search))for(const value of state.chosen)if(!items.some(item=>facetKey(item.value,facet.def)===facetKey(value,facet.def)))items.push({value,count:0});items.sort(facet.sort==="count"?(a,b)=>b.count-a.count||facetValueOrder(a.value,b.value,facet):(a,b)=>facetValueOrder(a.value,b.value,facet));const shown=state.expanded?items.filter((item,index)=>index<FACET_VALUES||chosen.has(facetKey(item.value,facet.def))):items.filter((item,index)=>index<facet.limit||chosen.has(facetKey(item.value,facet.def)));const retainedIndex=shown.findIndex(item=>facetKey(item.value,facet.def)===focusKey);const focusIndex=retainedIndex>=0?retainedIndex:Math.min(Math.max(0,focusPosition),Math.max(0,shown.length-1));const numbers=numberFormat(grid.lang);list.replaceChildren(...shown.map((item,index)=>{const row=h("li"),label=h("label","cx-facet-val"),box=h("input"),text=h("span","cx-facet-text"),count=h("span","cx-facet-n"),key=facetKey(item.value,facet.def);box.type="checkbox";box.checked=chosen.has(key);box.disabled=locked;box.setAttribute("data-cx-key",key);box.tabIndex=index===focusIndex?0:-1;const empty=item.value===null||item.value==="",display=empty?grid.labels.gridFacetEmptyValue:facetValueText(grid,facet,item.value,text);if(empty){setText(text,display);text.classList.add("cx-facet-empty")}
|
|
36
|
+
const FACET_SEARCH_FROM=12;function facetListBody(panel,facet,body){const grid=panel.grid,search=h("input","cx-input cx-facet-search"),list=h("ul","cx-facet-values"),more=gridButton("",()=>{state.expanded=!state.expanded;draw()});const note=h("p","cx-facet-note"),state={expanded:false,search:"",counts:null,timer:0};search.type="search";search.placeholder=grid.labels.gridFacetSearch;search.setAttribute("aria-label",fill(grid.labels.gridFacetSearch,{})+ ": "+facet.label);search.hidden=true;more.classList.add("cx-facet-more");more.hidden=true;note.hidden=true;list.setAttribute("aria-label",facet.label);body.append(search,list,more,note);search.addEventListener("input",()=>{state.search=search.value;clearTimeout(state.timer);state.timer=setTimeout(()=>facet.hosted?panel.refresh([facet]):draw(),facet.hosted?250:0)});list.addEventListener("keydown",event=>{const boxes=[...list.querySelectorAll("input")],at=boxes.indexOf(document.activeElement);const next={ArrowDown:at+1,ArrowUp:at-1,Home:0,End:boxes.length-1}[event.key];if(at<0||next===undefined||!boxes[next])return;event.preventDefault();boxes.forEach(box=>{box.tabIndex=-1});boxes[next].tabIndex=0;boxes[next].focus()});const choose=(item,checked)=>{const chosen=new Map((state.chosen||[]).map(value=>[facetKey(value,facet.def),value]));if(checked)chosen.set(facetKey(item.value,facet.def),item.value);else chosen.delete(facetKey(item.value,facet.def));state.chosen=[...chosen.values()];panel.apply(facet,state.chosen)};function draw(){const counts=state.counts,selection=panel.selection(facet);if(!counts)return;state.chosen=selection.values||[];const chosen=new Set(state.chosen.map(value=>facetKey(value,facet.def))),focused=list.contains(document.activeElement)?document.activeElement:null;const focusKey=focused?.getAttribute("data-cx-key"),focusPosition=focused?[...list.querySelectorAll("input")].indexOf(focused):0;const needle=facet.hosted?"":foldText(state.search),locked=!!selection.locked;let items=counts.items.filter(item=>!needle||item.value!==null&&foldText(facet.bucket?GRID_BUCKETS.label(facet.bucket,item.value,grid.lang):cellText(item.value,facet.def,grid.fmt)).includes(needle));if(!(facet.hosted&&state.search))for(const value of state.chosen)if(!items.some(item=>facetKey(item.value,facet.def)===facetKey(value,facet.def)))items.push({value,count:0});items.sort(facet.sort==="count"?(a,b)=>b.count-a.count||facetValueOrder(a.value,b.value,facet):(a,b)=>facetValueOrder(a.value,b.value,facet));const shown=state.expanded?items.filter((item,index)=>index<FACET_VALUES||chosen.has(facetKey(item.value,facet.def))):items.filter((item,index)=>index<facet.limit||chosen.has(facetKey(item.value,facet.def)));const retainedIndex=shown.findIndex(item=>facetKey(item.value,facet.def)===focusKey);const focusIndex=retainedIndex>=0?retainedIndex:Math.min(Math.max(0,focusPosition),Math.max(0,shown.length-1));const numbers=numberFormat(grid.lang);list.replaceChildren(...shown.map((item,index)=>{const row=h("li"),label=h("label","cx-facet-val"),box=h("input"),text=h("span","cx-facet-text"),count=h("span","cx-facet-n"),key=facetKey(item.value,facet.def);box.type="checkbox";box.checked=chosen.has(key);box.disabled=locked;box.setAttribute("data-cx-key",key);box.tabIndex=index===focusIndex?0:-1;const empty=item.value===null||item.value==="",display=empty?grid.labels.gridFacetEmptyValue:facetValueText(grid,facet,item.value,text);if(empty){setText(text,display);text.classList.add("cx-facet-empty")}
|
|
37
37
|
box.setAttribute("aria-label",fill(grid.labels.gridFacetValueCount,{value:display,count:numbers.format(item.count)}));setText(count,numbers.format(item.count));count.setAttribute("aria-hidden","true");if(!item.count)label.classList.add("cx-facet-zero");box.addEventListener("change",()=>choose(item,box.checked));label.append(box,text,count);row.appendChild(label);return row}));if(focusKey){const target=!locked&&list.querySelector('input[tabindex="0"]')||body.closest(".cx-facet")?.querySelector(".cx-facet-toggle");target?.focus({preventScroll:!locked&&retainedIndex>=0})}
|
|
38
38
|
const hidden=items.length-shown.length,capped=state.expanded&&hidden>0;more.hidden=!hidden&&!state.expanded||items.length<=facet.limit;setText(more,state.expanded?grid.labels.gridFacetShowFewer:fill(grid.labels.gridFacetShowMore,{count:numbers.format(Math.min(hidden,Math.max(1,FACET_VALUES-shown.length)))}));search.hidden=!state.search&&document.activeElement!==search&&counts.totalValues<=FACET_SEARCH_FROM;search.disabled=locked;note.hidden=!counts.truncated&&!capped;if(!note.hidden)setText(note,fill(grid.labels.gridFacetCounts,{count:numbers.format(counts.matched),shown:numbers.format(counts.truncated?counts.items.length:shown.length),total:numbers.format(counts.totalValues)}))}
|
|
39
39
|
return{draw,search:()=>state.search,update(counts){state.counts=counts;draw()}}}
|
|
40
40
|
function facetValueOrder(a,b,facet){const column=facet.def;if(column.valueOrder?.length)return gridKeyCompare(a,b,column,"asc");if(a===null||b===null)return a===b?0:a===null?1:-1;if(facet.order){const at=facet.order.get(facetKey(a,column))??Infinity,bt=facet.order.get(facetKey(b,column))??Infinity;if(at!==bt)return at<bt?-1:1}
|
|
41
41
|
if(column.kind!=="text")return gridOrder(gridScalar(a,column),gridScalar(b,column));if(typeof a!==typeof b)return typeof a==="boolean"?-1:1;return gridOrder(typeof a==="string"?foldText(a):a,typeof b==="string"?foldText(b):b)}
|
|
42
|
-
function facetValueText(grid,facet,value,element){const
|
|
42
|
+
function facetValueText(grid,facet,value,element){if(facet.bucket){const text=GRID_BUCKETS.label(facet.bucket,value,grid.lang);setText(element,text);return text}
|
|
43
|
+
const column=facet.def,options=column.presenter,text=cellText(value,column,grid.fmt)||String(value);if(options&&!["statusStrip","sparklineBars","sparklineLine","change","identifier","longText","list","tags","structured"].includes(options.kind)){try{gridCellRenderer(grid,column,options)({id:"facet",cells:{[column.id]:value}},element);return text}catch(_){element.replaceChildren()}}
|
|
43
44
|
setText(element,text);return text}
|
|
44
45
|
function facetRangeBody(panel,facet,body){const grid=panel.grid,column=facet.def,date=column.kind==="datetime",numbers=numberFormat(grid.lang);const chart=h("div","cx-facet-hist"),axis=h("p","cx-facet-axis"),low=h("span"),high=h("span"),fields=h("div","cx-facet-range"),note=h("p","cx-facet-note");const field=(text,edge)=>{const label=h("label","cx-facet-field"),input=h("input","cx-input");input.type=date?"date":"number";if(!date)input.step="any";label.append(document.createTextNode(text),input);input.addEventListener("change",()=>submit(edge));input.addEventListener("keydown",event=>{if(event.key==="Enter"){event.preventDefault();submit(edge)}});return{label,input}};const from=field(grid.labels.gridFacetFrom,"low"),to=field(grid.labels.gridFacetTo,"high");chart.setAttribute("role","img");chart.setAttribute("aria-label",fill(grid.labels.gridFacetHistogram,{column:facet.label}));axis.append(low,high);axis.setAttribute("aria-hidden","true");fields.append(from.label,to.label);note.hidden=true;note.setAttribute("role","status");body.append(chart,axis,fields,note);const state={counts:null,bins:[]};const toInput=value=>{if(value==null)return "";if(!date)return String(value);const day=new Date(value),pad=part=>String(part).padStart(2,"0");return grid.local?day.getFullYear()+ "-"+pad(day.getMonth()+ 1)+ "-"+pad(day.getDate()):day.toISOString().slice(0,10)};const fromInput=(text,edge)=>{if(text==="")return null;if(!date){const value=Number(text);return Number.isFinite(value)?value:undefined}
|
|
45
46
|
const[year,month,day]=text.split("-").map(Number),end=edge==="high";const time=grid.local?new Date(year,month-1,day,end?23:0,end?59:0,end?59:0,end?999:0).getTime():Date.UTC(year,month-1,day,end?23:0,end?59:0,end?59:0,end?999:0);return Number.isFinite(time)?time:undefined};const wire=value=>value==null?null:date?new Date(value).toISOString():value;const current=(selection=panel.selection(facet))=>{return{low:selection.low==null?null:date?Date.parse(selection.low):selection.low,high:selection.high==null?null:date?Date.parse(selection.high):selection.high,lowOpen:!!selection.lowOpen,open:!!selection.open,locked:!!selection.locked}};const binChoice=index=>{const bin=state.bins[index],last=index===state.bins.length-1;if(date)return{low:Math.ceil(bin.start),high:last?bin.end:Math.ceil(bin.end)- 1,open:false};return{low:bin.start,high:bin.end,open:!last}};function submit(edge){const selection=panel.selection(facet),range=current(selection);const lowChanged=edge==="low"||from.input.value!==toInput(range.low),highChanged=edge==="high"||to.input.value!==toInput(range.high);const low=lowChanged?fromInput(from.input.value,"low"):range.low,high=highChanged?fromInput(to.input.value,"high"):range.high;if(low===undefined||high===undefined){setText(note,grid.labels.gridFacetInvalid);note.hidden=false;return}
|
|
@@ -54,11 +55,14 @@ const place=value=>Math.min(count-1,Math.floor((value-min)/ width));
|
|
|
54
55
|
for(const value of counts.values||[])tallies[place(value)]++;for(const pair of pairs||[])tallies[place(pair.value)]+=pair.count;const highest=Math.max(1,...tallies);const bins=tallies.map((tally,index)=>({start:min+index*width,end:index===count-1?max:min +(index+1)*width,count:tally}));const sameBins=bins.length===state.bins.length&&bins.every((bin,index)=>bin.start===state.bins[index].start&&bin.end===state.bins[index].end);state.bins=bins;const bars=sameBins?Array.from(chart.children):bins.map(()=>h("span","cx-facet-bar"));bins.forEach((bin,index)=>{const last=index===count-1,bar=bars[index];const inside=(range.low==null||(last&&!range.lowOpen?bin.end>=range.low:bin.end>range.low))&&(range.high==null||(range.open?bin.start<range.high:bin.start<=range.high));bar.setAttribute("data-cx-bin",String(index));bar.style.height=Math.max(bin.count?6:0,Math.round(bin.count / highest * 100)) + "%";
|
|
55
56
|
bar.classList.toggle("cx-facet-in",inside&&(range.low!=null||range.high!=null));bar.title=fill(grid.labels.gridFacetBin,{from:label(bin.start),to:label(bin.end),count:numbers.format(bin.count)})});if(!sameBins)chart.replaceChildren(...bars);setText(low,label(min));setText(high,label(max))}
|
|
56
57
|
return{draw,search:()=>"",update(counts){state.counts=counts;draw()}}}
|
|
57
|
-
let facetSeq=0;const FACET_ICON='<path d="M4 6h16M7 12h10M10 18h4"/>';Object.assign(DataGrid.prototype,{startFacets(){if(this.facetPanel)return;const options=this.facetOptions=facetOptions(this),id=this.id+"-facets-" + ++facetSeq,signal=this.lifetime.signal;this.facetColumns=options.facets.map(facet=>Object.assign(facet,{hosted:options.hosted}));this.facetOpen??=options.open;if(this.defaultState)this.defaultState.facets={open:options.open};const panel=this.facetPanel=h("aside","cx-host cx-chrome cx-facets"),head=h("div","cx-facets-h"),title=h("h2","cx-facets-title");const clear=gridButton(this.labels.gridClearAll,()=>this.facetClearAll()),toggle=gridButton("",()=>this.setFacetPanelOpen(!this.facetOpen));const list=h("div","cx-facets-list"),live=this.facetLive=h("p","cx-sr-only");panel.id=id;panel.setAttribute("aria-labelledby",id+"-title");title.id=id+"-title";setText(title,options.label||this.labels.gridFacetPanel);live.setAttribute("aria-live","polite");toggle.classList.add("cx-facets-toggle");toggle.setAttribute("aria-controls",id+"-list");list.id=id+"-list";toggle.appendChild(gridIcon(null,FACET_ICON));clear.classList.add("cx-facets-clear");this.facetClear=clear;toggle.hidden=!options.collapsible;head.append(title,clear,toggle);panel.append(head,list,live);panel.setAttribute("data-cx-position",options.position);panel.style.setProperty("--cx-facets-w",options.width+"px");this.facetSections=this.facetColumns.map(facet=>this.facetSection(facet,list));if(options.target)options.target.appendChild(panel);else{const frame=this.facetFrame=h("div","cx-facet-frame");frame.setAttribute("data-cx-position",options.position);this.host.before(frame);frame.append(panel,this.host)}
|
|
58
|
-
this.facetTheme=watchOverlayTheme(this.host,panel,signal);const sheetButton=this.facetSheetButton=gridButton(this.labels.gridFacetPanel,()=>this.openFacetSheet());sheetButton.classList.add("cx-btn","cx-facets-open");sheetButton.prepend(gridIcon(null,FACET_ICON));sheetButton.hidden=true;sheetButton.setAttribute("aria-haspopup","dialog");const anchor=this.toolbar.querySelector(".cx-grid-filters")||this.toolbar.querySelector(".cx-grid-columns")||this.spacer;if(this.opts.toolbar===false)this.host.prepend(sheetButton);else if(anchor?.parentNode===this.toolbar)anchor.before(sheetButton);else this.toolbar.prepend(sheetButton);
|
|
58
|
+
let facetSeq=0;const FACET_ICON='<path d="M4 6h16M7 12h10M10 18h4"/>';Object.assign(DataGrid.prototype,{startFacets(){if(this.facetPanel)return;const options=this.facetOptions=facetOptions(this),id=this.id+"-facets-" + ++facetSeq,signal=this.lifetime.signal;this.facetColumns=options.facets.map(facet=>Object.assign(facet,{hosted:options.hosted}));this.facetOpen??=options.open;if(this.defaultState)this.defaultState.facets={open:options.open};const panel=this.facetPanel=h("aside","cx-host cx-chrome cx-facets"),head=h("div","cx-facets-h"),title=h("h2","cx-facets-title");const clear=gridButton(this.labels.gridClearAll,()=>this.facetClearAll()),toggle=gridButton("",()=>this.setFacetPanelOpen(!this.facetOpen));const list=h("div","cx-facets-list"),live=this.facetLive=h("p","cx-sr-only");panel.id=id;panel.setAttribute("aria-labelledby",id+"-title");title.id=id+"-title";setText(title,options.label||this.labels.gridFacetPanel);live.setAttribute("aria-live","polite");toggle.classList.add("cx-facets-toggle");toggle.setAttribute("aria-controls",id+"-list");list.id=id+"-list";toggle.appendChild(gridIcon(null,FACET_ICON));clear.classList.add("cx-facets-clear");this.facetClear=clear;toggle.hidden=!options.collapsible;head.append(title,clear,toggle);panel.append(head,list,live);panel.setAttribute("data-cx-position",options.position);panel.style.setProperty("--cx-facets-w",options.width+"px");this.facetSections=this.facetColumns.map(facet=>this.facetSection(facet,list));if(options.position==="toolbar"&&!options.target)this.host.appendChild(panel);else if(options.target)options.target.appendChild(panel);else{const frame=this.facetFrame=h("div","cx-facet-frame");frame.setAttribute("data-cx-position",options.position);this.host.before(frame);frame.append(panel,this.host)}
|
|
59
|
+
this.facetTheme=watchOverlayTheme(this.host,panel,signal);const sheetButton=this.facetSheetButton=gridButton(this.labels.gridFacetPanel,()=>this.openFacetSheet());sheetButton.classList.add("cx-btn","cx-facets-open");sheetButton.prepend(gridIcon(null,FACET_ICON));sheetButton.hidden=true;sheetButton.setAttribute("aria-haspopup","dialog");const anchor=this.toolbar.querySelector(".cx-grid-filters")||this.toolbar.querySelector(".cx-grid-columns")||this.spacer;if(this.opts.toolbar===false)this.host.prepend(sheetButton);else if(anchor?.parentNode===this.toolbar)anchor.before(sheetButton);else this.toolbar.prepend(sheetButton);if(options.position==="toolbar"&&!options.target&&this.opts.toolbar!==false){this.facetToolbarControls=this.facetSections.map(section=>{const control=this.controlPanel(section.facet.label,"cx-grid-facet");control.panel.classList.add("cx-facets");control.panel.appendChild(section.section);section.facet.collapsed=false;section.section.querySelector(".cx-facet-b").hidden=false;section.section.querySelector(".cx-facet-toggle").setAttribute("aria-expanded","true");const summary=control.details.querySelector("summary");summary.classList.remove("ghost");summary.querySelector(".cx-ico")?.remove();if(anchor?.parentNode===this.toolbar)anchor.before(control.details);return{...control,summary,section}})}
|
|
60
|
+
this.facetResize=new ResizeObserver(()=>requestAnimationFrame(()=>this.destroyed||this.facetFit()));this.facetResize.observe(this.facetFrame||this.host);if(this.facetFrame)this.facetResize.observe(this.host);this.host.addEventListener("canopyx:query",()=>{if(facetShape(this.acceptedQuery)!==this.facetCounted)this.facetRefresh()},{signal});this.host.addEventListener("canopyx:rowsChanged",()=>{clearTimeout(this.facetLiveTimer);this.facetLiveTimer=setTimeout(()=>this.facetRefresh(),300)},{signal});signal.addEventListener("abort",()=>this.facetDestroy(),{once:true});this.facetSync();this.facetFit();if(this.acceptedQuery)this.facetRefresh()},facetSection(facet,list){const section=h("section","cx-facet"),head=h("h3","cx-facet-h"),toggle=h("button","cx-facet-toggle"),name=h("span","cx-facet-name"),badge=h("span","cx-facet-badge");const clear=gridButton("",()=>this.facetApply(facet,facet.kind==="list"?[]:{low:null,high:null})),body=h("div","cx-facet-b"),custom=h("p","cx-facet-note cx-facet-custom");const failure=h("p","cx-facet-note cx-facet-error"),spoken=h("span","cx-sr-only");const bodyId=this.facetPanel.id+"-"+facet.column;section.setAttribute("data-cx-facet",facet.column);toggle.type="button";toggle.setAttribute("aria-controls",bodyId);body.id=bodyId;badge.setAttribute("aria-hidden","true");setText(name,facet.label);toggle.append(name,badge,spoken);head.appendChild(toggle);clear.classList.add("cx-facet-clear");clear.appendChild(gridIcon("close"));clear.setAttribute("aria-label",fill(this.labels.gridFacetClear,{column:facet.label}));clear.title=clear.getAttribute("aria-label");custom.hidden=true;custom.setAttribute("role","status");failure.hidden=true;failure.setAttribute("role","status");const facetView={grid:this,selection:target=>facetSelection(this.queryForChange(),target),apply:(target,choice)=>this.facetApply(target,choice),refresh:targets=>this.facetRefresh(targets)};const content=facet.kind==="list"?facetListBody(facetView,facet,body):facetRangeBody(facetView,facet,body);body.prepend(custom,failure);const collapsed=()=>{const closed=facet.collapsed;toggle.setAttribute("aria-expanded",String(!closed));body.hidden=closed;toggle.title=fill(this.labels[closed?"gridFacetExpand":"gridFacetCollapse"],{column:facet.label})};toggle.addEventListener("click",()=>{facet.collapsed=!facet.collapsed;collapsed()});collapsed();const top=h("div","cx-facet-top");top.append(head,clear);section.append(top,body);list.appendChild(section);return{facet,section,badge,spoken,clear,custom,failure,content,generation:0,controller:null}},facetApply(facet,choice){this.facetPending||=new Map();this.facetPending.set(facet.column,{facet,choice});clearTimeout(this.facetTimer);this.facetTimer=setTimeout(()=>this.facetFlush(),150)},facetFlush(){clearTimeout(this.facetTimer);this.facetTimer=0;const pending=this.facetPending;this.facetPending=null;if(!pending||this.destroyed)return Promise.resolve();let query=this.queryForChange(true);for(const{facet,choice}of pending.values())query=facetQuery(query,facet,choice);return this.setQuery(query).then(()=>this.facetAnnounce(),()=>{})},facetClearAll(){clearTimeout(this.facetTimer);this.facetPending=null;let query=this.queryForChange(true);for(const facet of this.facetColumns)query=facetQuery(query,facet,facet.kind==="list"?[]:{low:null,high:null});return this.setQuery(query).then(()=>this.facetAnnounce(),()=>{})},facetAnnounce(){const numbers=numberFormat(this.lang);setText(this.facetLive,"");setText(this.facetLive,fill(this.labels.gridFacetResult,{count:numbers.format(this.snapshot?.matched??0)}))},async facetRefresh(targets){if(!this.facetPanel||!this.acceptedQuery||this.destroyed)return;const query=this.acceptedQuery,run=targets?this.facetRun:this.facetRun=(this.facetRun||0)+ 1;if(!targets)this.facetCounted=facetShape(query);for(const section of this.facetSections){if(targets&&!targets.includes(section.facet))continue;section.controller?.abort();const controller=section.controller=new AbortController(),generation=++section.generation;const current=()=>!this.destroyed&&run===this.facetRun&&generation===section.generation;try{const counts=section.facet.hosted?await facetHostedCounts(this,section.facet,section.content.search(),controller.signal):facetInlineCounts(this,section.facet,query);if(current()){section.failure.hidden=true;section.content.update(counts)}}catch(error){if(current()&&error?.name!=="AbortError"){setText(section.failure,fill(this.labels.queryFailed,{error:error.message}));section.failure.hidden=false}}finally{if(section.controller===controller)section.controller=null;controller.abort()}
|
|
59
61
|
if(!section.facet.hosted)await new Promise(resolve=>setTimeout(resolve,0));if(this.destroyed||run!==this.facetRun)return}},facetSync(){if(!this.facetPanel)return;const query=this.queryForChange(),numbers=numberFormat(this.lang);let active=0;for(const section of this.facetSections||[]){const selection=facetSelection(query,section.facet),count=selection.values?selection.values.length:selection.custom||selection.low!=null||selection.high!=null?1:0;active +=count?1:0;setText(section.badge,selection.values?numbers.format(count):"");section.badge.hidden=!selection.values||!count;setText(section.spoken,section.badge.hidden?"":", "+fill(this.labels.gridFacetSelected,{count:numbers.format(count)}));section.clear.hidden=!count||!!selection.locked;section.section.classList.toggle("cx-facet-active",!!count);if(selection.custom){setText(section.custom,this.labels.gridFacetCustom);section.custom.hidden=false}
|
|
60
62
|
else if(section.custom.textContent===this.labels.gridFacetCustom)section.custom.hidden=true;section.content.draw()}
|
|
61
|
-
this.facetClear.hidden=!active;this.facetActive=active;
|
|
63
|
+
this.facetClear.hidden=!active;this.facetActive=active;for(const control of this.facetToolbarControls||[]){const selection=facetSelection(query,control.section.facet),count=selection.values?.length||0;const value=count===1?cellText(selection.values[0],control.section.facet.def,this.fmt):count?numbers.format(count):"";setText(control.summary,control.section.facet.label +(value?": "+value:""));control.summary.classList.toggle("cx-facet-active",!!count||!!selection.custom||selection.low!=null||selection.high!=null)}
|
|
64
|
+
if(this.facetSheetButton){this.facetSheetButton.querySelector(".badge")?.remove();if(active){const badge=h("span","badge");setText(badge,numbers.format(active));this.facetSheetButton.appendChild(badge)}}},facetFit(){const panel=this.facetPanel,options=this.facetOptions;if(!panel||this.facetSheet)return;if(options.position==="toolbar"&&!options.target){panel.hidden=true;this.facetSheetButton.hidden=this.opts.toolbar!==false;return}
|
|
65
|
+
const width=(this.facetFrame||this.host).clientWidth,fits=options.target?true:options.position==="side"?width>=options.width+480:width>640;this.facetFits=fits;panel.hidden=!fits;this.facetSheetButton.hidden=fits;this.facetFrame?.toggleAttribute("data-cx-sheet",!fits);panel.classList.toggle("cx-facets-closed",!this.facetOpen);panel.style.height=options.position==="side"&&this.facetFrame&&this.facetOpen?Math.max(360,this.host.offsetHeight)+ "px":"";const toggle=panel.querySelector(".cx-facets-toggle");toggle.setAttribute("aria-expanded",String(!!this.facetOpen));toggle.setAttribute("aria-label",this.labels[this.facetOpen?"gridFacetPanelHide":"gridFacetPanelShow"]);toggle.title=toggle.getAttribute("aria-label")},setFacetPanelOpen(open){if(typeof open!=="boolean")return Promise.reject(new Error("CanopyX: the facet panel's open state is a boolean."));if(open!==this.facetOpen){this.facetOpen=open;this.facetFit();this.stateChanged();this.emit("facetPanel",{open})}
|
|
62
66
|
return Promise.resolve(this.getFacetPanel())},getFacetPanel(){if(!this.facetPanel)return gridFreeze({open:this.facetOpen??null,columns:(this.facetColumns||[]).map(facet=>facet.column)});return gridFreeze({open:!!this.facetOpen,columns:this.facetColumns.map(facet=>facet.column),active:this.facetActive||0})},openFacetSheet(){if(this.facetSheet||!this.facetPanel)return;const sheet=this.facetSheet=h("dialog","cx-host cx-chrome cx-grid-overlay cx-facet-sheet"),head=h("div","cx-facet-sheet-h"),title=h("h2"),done=gridButton(this.labels.gridDone,()=>sheet.close());const panel=this.facetPanel,home=panel.parentNode,next=panel.nextSibling,returnFocus=document.activeElement;const disposeTheme=watchOverlayTheme(this.host,sheet,this.lifetime.signal);sheet.addEventListener("close",disposeTheme,{once:true});title.id=this.id+"-facet-sheet";sheet.setAttribute("aria-labelledby",title.id);setText(title,this.facetOptions.label||this.labels.gridFacetPanel);const clear=this.facetClear,clearHome=clear.parentNode,clearNext=clear.nextSibling;done.classList.add("cx-btn");head.append(title,clear,done);sheet.append(head,panel);panel.hidden=false;panel.classList.remove("cx-facets-closed");panel.classList.add("cx-facets-in-sheet");document.body.appendChild(sheet);this.facetTheme.refresh();sheet.addEventListener("close",()=>{if(this.facetPanel!==panel){sheet.remove();return}// The grid was destroyed meanwhile; the panel is gone.
|
|
63
|
-
panel.classList.remove("cx-facets-in-sheet");home?.insertBefore(panel,next);this.facetTheme.refresh();clearHome.insertBefore(clear,clearNext);sheet.remove();this.facetSheet=null;this.facetFit();if(returnFocus?.isConnected)returnFocus.focus({preventScroll:true})},{once:true});sheet.showModal();done.focus()},facetDestroy(){clearTimeout(this.facetTimer);clearTimeout(this.facetLiveTimer);this.facetResize?.disconnect();this.facetTheme?.();this.facetTheme=null;for(const section of this.facetSections||[])section.controller?.abort();const sheet=this.facetSheet;this.facetSheet=null;this.facetPanel?.remove();this.facetSheetButton?.remove();this.facetPanel=null;if(sheet){sheet.close();sheet.remove()}
|
|
67
|
+
panel.classList.remove("cx-facets-in-sheet");home?.insertBefore(panel,next);this.facetTheme.refresh();clearHome.insertBefore(clear,clearNext);sheet.remove();this.facetSheet=null;this.facetFit();if(returnFocus?.isConnected)returnFocus.focus({preventScroll:true})},{once:true});sheet.showModal();done.focus()},facetDestroy(){clearTimeout(this.facetTimer);clearTimeout(this.facetLiveTimer);this.facetResize?.disconnect();this.facetTheme?.();this.facetTheme=null;for(const section of this.facetSections||[])section.controller?.abort();const sheet=this.facetSheet;this.facetSheet=null;this.facetPanel?.remove();this.facetSheetButton?.remove();this.facetPanel=null;for(const control of this.facetToolbarControls||[])control.details.remove();this.facetToolbarControls=null;if(sheet){sheet.close();sheet.remove()}
|
|
64
68
|
if(this.facetFrame){this.facetFrame.replaceWith(this.host);this.facetFrame=null}}});const FACET_SUMMARY=DataGrid.prototype.syncQuerySummary;DataGrid.prototype.syncQuerySummary=function(){FACET_SUMMARY.call(this);if(this.facetPanel)this.facetSync()};const FACET_ZONE=DataGrid.prototype.setTimeZone;DataGrid.prototype.setTimeZone=function(zone){const result=FACET_ZONE.call(this,zone);if(this.facetPanel)this.facetSync();return result};installed.add(context.DataGrid.prototype)}};(global.CanopyXParts||=[]).push(["facets",part])})(typeof window!=="undefined"?window:globalThis);
|