@evotecit/canopyx 0.3.11 → 0.3.15

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.
Files changed (102) hide show
  1. package/CanopyX.Html/Assets/canopyx-calendar-edit.js +36 -18
  2. package/CanopyX.Html/Assets/canopyx-calendar-ics.js +7 -5
  3. package/CanopyX.Html/Assets/canopyx-calendar.css +124 -116
  4. package/CanopyX.Html/Assets/canopyx-calendar.js +74 -54
  5. package/CanopyX.Html/Assets/canopyx-cell-range.css +8 -8
  6. package/CanopyX.Html/Assets/canopyx-cell-range.js +1 -1
  7. package/CanopyX.Html/Assets/canopyx-changes.css +113 -113
  8. package/CanopyX.Html/Assets/canopyx-changes.js +7 -10
  9. package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -5
  10. package/CanopyX.Html/Assets/canopyx-column-groups.js +1 -1
  11. package/CanopyX.Html/Assets/canopyx-data.js +2 -2
  12. package/CanopyX.Html/Assets/canopyx-detail-rows.css +9 -9
  13. package/CanopyX.Html/Assets/canopyx-detail-rows.js +2 -2
  14. package/CanopyX.Html/Assets/canopyx-editing.css +18 -18
  15. package/CanopyX.Html/Assets/canopyx-editing.js +1 -1
  16. package/CanopyX.Html/Assets/canopyx-enhance.js +2 -2
  17. package/CanopyX.Html/Assets/canopyx-export.js +8 -4
  18. package/CanopyX.Html/Assets/canopyx-facets.css +33 -33
  19. package/CanopyX.Html/Assets/canopyx-facets.js +10 -11
  20. package/CanopyX.Html/Assets/canopyx-filter-editor.css +57 -57
  21. package/CanopyX.Html/Assets/canopyx-filter-editor.js +15 -11
  22. package/CanopyX.Html/Assets/canopyx-flow-checks.css +11 -11
  23. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  24. package/CanopyX.Html/Assets/canopyx-flow-command.css +7 -7
  25. package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
  26. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +7 -7
  27. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  28. package/CanopyX.Html/Assets/canopyx-flow-drafts.css +7 -7
  29. package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
  30. package/CanopyX.Html/Assets/canopyx-flow-entry.css +17 -76
  31. package/CanopyX.Html/Assets/canopyx-flow-entry.js +9 -3
  32. package/CanopyX.Html/Assets/canopyx-flow-host.css +4 -4
  33. package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
  34. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +9 -3
  35. package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
  36. package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
  37. package/CanopyX.Html/Assets/canopyx-flow-preview.css +6 -6
  38. package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
  39. package/CanopyX.Html/Assets/canopyx-flow-records.css +3 -3
  40. package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
  41. package/CanopyX.Html/Assets/canopyx-flow-tasks.css +17 -17
  42. package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
  43. package/CanopyX.Html/Assets/canopyx-flow.css +79 -79
  44. package/CanopyX.Html/Assets/canopyx-flow.js +1 -1
  45. package/CanopyX.Html/Assets/canopyx-format-editor.css +23 -23
  46. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -3
  47. package/CanopyX.Html/Assets/canopyx-formatting.css +17 -17
  48. package/CanopyX.Html/Assets/canopyx-formatting.js +5 -5
  49. package/CanopyX.Html/Assets/canopyx-forms.css +5 -5
  50. package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
  51. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +134 -77
  52. package/CanopyX.Html/Assets/canopyx-grid-options.css +10 -0
  53. package/CanopyX.Html/Assets/canopyx-grid-options.js +47 -0
  54. package/CanopyX.Html/Assets/canopyx-grid.css +199 -261
  55. package/CanopyX.Html/Assets/canopyx-grid.js +134 -77
  56. package/CanopyX.Html/Assets/canopyx-grouping.css +17 -17
  57. package/CanopyX.Html/Assets/canopyx-grouping.js +12 -9
  58. package/CanopyX.Html/Assets/canopyx-highlight.css +14 -14
  59. package/CanopyX.Html/Assets/canopyx-highlight.js +2 -2
  60. package/CanopyX.Html/Assets/canopyx-interactive.css +94 -155
  61. package/CanopyX.Html/Assets/canopyx-interactive.js +58 -24
  62. package/CanopyX.Html/Assets/canopyx-labels-de.js +5 -0
  63. package/CanopyX.Html/Assets/canopyx-labels-es.js +5 -0
  64. package/CanopyX.Html/Assets/canopyx-labels-fr.js +5 -0
  65. package/CanopyX.Html/Assets/canopyx-labels-it.js +5 -0
  66. package/CanopyX.Html/Assets/canopyx-labels-pl.js +5 -0
  67. package/CanopyX.Html/Assets/canopyx-layouts.css +17 -17
  68. package/CanopyX.Html/Assets/canopyx-layouts.js +4 -12
  69. package/CanopyX.Html/Assets/canopyx-link.css +7 -7
  70. package/CanopyX.Html/Assets/canopyx-link.js +1 -1
  71. package/CanopyX.Html/Assets/canopyx-live.css +9 -9
  72. package/CanopyX.Html/Assets/canopyx-live.js +2 -2
  73. package/CanopyX.Html/Assets/canopyx-matrix.css +74 -74
  74. package/CanopyX.Html/Assets/canopyx-matrix.js +3 -4
  75. package/CanopyX.Html/Assets/canopyx-module.mjs +58 -24
  76. package/CanopyX.Html/Assets/canopyx-pager.css +2 -2
  77. package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
  78. package/CanopyX.Html/Assets/canopyx-presenters.js +11 -0
  79. package/CanopyX.Html/Assets/canopyx-record-panel.css +49 -49
  80. package/CanopyX.Html/Assets/canopyx-record-panel.js +13 -11
  81. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +142 -84
  82. package/CanopyX.Html/Assets/canopyx-reporting.css +214 -276
  83. package/CanopyX.Html/Assets/canopyx-reporting.js +142 -84
  84. package/CanopyX.Html/Assets/canopyx-timeline.css +28 -28
  85. package/CanopyX.Html/Assets/canopyx-timeline.js +11 -10
  86. package/CanopyX.Html/Assets/canopyx-tree-tools.css +47 -46
  87. package/CanopyX.Html/Assets/canopyx-tree-tools.js +5 -4
  88. package/CanopyX.Html/Assets/canopyx.css +81 -142
  89. package/CanopyX.Html/Assets/canopyx.js +58 -24
  90. package/JavaScript/calendar.d.ts +15 -0
  91. package/JavaScript/grid.d.ts +29 -4
  92. package/JavaScript/hosts.d.ts +11 -0
  93. package/JavaScript/locales/de.mjs +5 -0
  94. package/JavaScript/locales/es.mjs +5 -0
  95. package/JavaScript/locales/fr.mjs +5 -0
  96. package/JavaScript/locales/it.mjs +5 -0
  97. package/JavaScript/locales/pl.mjs +5 -0
  98. package/JavaScript/plugins.d.ts +4 -0
  99. package/JavaScript/protocol.d.ts +14 -1
  100. package/JavaScript/records.d.ts +2 -0
  101. package/README.md +6 -2
  102. package/package.json +7 -1
@@ -1,11 +1,12 @@
1
- (function(global){"use strict";const installed=new WeakSet();const part={version:"bcc06276c7933af6",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}=context;const RECORD_KINDS=["items","fields","records","events","changes"],RECORD_LINK_KEY=/^[A-Za-z][\w.-]{0,31}$/, RECORD_MAX_STRUCTURE_DEPTH = 8;
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"94adeb844689e329",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.presenter!==undefined&&recordGridHelpers().validatePresenter)recordGridHelpers().validatePresenter(field.presenter,{kind:"text",...field},view.columns);fields.add(field.id)}
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(object)for(const badge of cell.badges||[])element.appendChild(badgeElement(badge))}
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&&grid.gridCellRenderer&&view.kind==="grid"){grid.gridCellRenderer(view,{...field,renderWidth:ctx.width},field.presenter)(ctx.row,element);return}
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)}
@@ -70,7 +72,7 @@ function recordCollection(ctx,field,list,element){if(!list||typeof list!=="objec
70
72
  fill(labels.recordCount,{shown:recordCount(ctx,rows.length),total:recordCount(ctx,total)}));if(total>5||total>rows.length||ctx.print)head.appendChild(count);if(!ctx.print&&list.target?.view){const openAll=recordButton(labels.recordOpenAll,()=>recordOpenAll(ctx,field,list).catch(error=>ctx.view.emit("error",{error})),"cx-record-open-all","open");openAll.disabled=!recordCanOpenAll(list);head.appendChild(openAll)}
71
73
  const body=h("div","cx-record-collection-b");if(head.firstChild)block.appendChild(head);block.appendChild(body);if(ctx.print)recordTable(ctx,list,body);else if(ctx.phone&&!list.roots)recordCards(ctx,field,list,body);else recordNested(ctx,field,list,body);if(!ctx.print&&!list.roots&&rows.length<total&&recordLoader(ctx.view)){const more=recordButton(labels.recordLoadMore,()=>recordMore(ctx,field,list,more),"cx-record-load-more");block.appendChild(more)}
72
74
  element.appendChild(block)}
73
- function recordNested(ctx,field,list,body){const grid=recordGridHelpers(),host=h("div","cx-host cx-record-nested"),rows=list.rows,tree=!!list.roots||!grid.createDataGrid;host.setAttribute("data-cx-theme",ctx.view.host.getAttribute("data-cx-theme")||"auto");const columns=list.columns.map(column=>({kind:"text",sortable:true,...column})),id="cx-record-" + ++recordNestedSeq;const byKey=new Map(rows.map((row,at)=>["r"+String(at).padStart(6,"0"),row]));const open=item=>{const row=byKey.get(item.id)||item,ref=recordRowRef(list,row);if(ref)ctx.navigate(ref,host)};let api;if(tree){const roots=list.roots||rows.map(row=>({id:row.id,label:recordRowTitle(list,row,ctx.fmt),cells:row.cells}));host.classList.add("cx-record-nested-tree");api=createTreeGrid(host,{view:{protocol:PROTOCOL,type:"view",id,label:field.title,columns,source:{kind:"inline"},roots,rowHeight:30},labels:ctx.view.opts.labels,toolbar:false,onDetails:({node})=>open(node)})}else{const length=Math.min(Math.max(list.pageLength||10,1),100),paged=rows.length>length;api=grid.createDataGrid(host,{view:{protocol:PROTOCOL,type:"grid",id,label:field.title,rowHeight:30,pageSize:Math.min(10000,Math.max(rows.length,1)),selection:"none",search:rows.length>8,columns,source:{kind:"inline"},rows:[...byKey].map(([key,row])=>({...row,id:key})),toolbar:{filters:false,columns:false,views:false,export:false,more:false,count:false,columnMenus:false},...(paged?{presentation:"paged",pageLength:length}:{}),rowAction:rows.some(row=>recordRowRef(list,row))?"details":"none"},labels:ctx.view.opts.labels,...(rows.length>8?{}:{toolbar:false}),onDetails:({row})=>open(row)})}
75
+ function recordNested(ctx,field,list,body){const grid=recordGridHelpers(),host=h("div","cx-host cx-record-nested"),rows=list.rows,tree=!!list.roots||!grid.createDataGrid;const columns=list.columns.map(column=>({kind:"text",sortable:true,...column})),id="cx-record-" + ++recordNestedSeq;const byKey=new Map(rows.map((row,at)=>["r"+String(at).padStart(6,"0"),row]));const open=item=>{const row=byKey.get(item.id)||item,ref=recordRowRef(list,row);if(ref)ctx.navigate(ref,host)};let api;if(tree){const roots=list.roots||rows.map(row=>({id:row.id,label:recordRowTitle(list,row,ctx.fmt),cells:row.cells}));host.classList.add("cx-record-nested-tree");api=createTreeGrid(host,{view:{protocol:PROTOCOL,type:"view",id,label:field.title,columns,source:{kind:"inline"},roots,rowHeight:30},labels:ctx.view.opts.labels,toolbar:false,onDetails:({node})=>open(node)})}else{const length=Math.min(Math.max(list.pageLength||10,1),100),paged=rows.length>length;api=grid.createDataGrid(host,{view:{protocol:PROTOCOL,type:"grid",id,label:field.title,rowHeight:30,pageSize:Math.min(10000,Math.max(rows.length,1)),selection:"none",search:rows.length>8,columns,source:{kind:"inline"},rows:[...byKey].map(([key,row])=>({...row,id:key})),toolbar:{filters:false,columns:false,views:false,export:false,more:false,count:false,columnMenus:false},...(paged?{presentation:"paged",pageLength:length}:{}),rowAction:rows.some(row=>recordRowRef(list,row))?"details":"none"},labels:ctx.view.opts.labels,...(rows.length>8?{}:{toolbar:false}),onDetails:({row})=>open(row)})}
74
76
  host.style.setProperty("--cx-record-rows",String(Math.min(tree?(list.roots||rows).length:Math.min(rows.length,list.pageLength||10),12)));body.appendChild(host);recordOnDispose(ctx.signal,()=>api.destroy());api.ready?.catch(error=>{if(!ctx.signal.aborted)ctx.view.emit("error",{error})})}
75
77
  function recordCards(ctx,field,list,body){const holder=h("div","cx-record-cards"),rows=list.rows,columns=list.columns,step=10;const card=row=>{const item=h("div","cx-record-card"),title=h("div","cx-record-card-title"),ref=recordRowRef(list,row),text=recordRowTitle(list,row,ctx.fmt);item.setAttribute("role","group");item.setAttribute("aria-label",text);if(ref)recordLink(ctx,{value:text,ref},{id:field.id,kind:"text"},title);else setText(title,text);const fields=h("dl","cx-dl");for(const column of columns.slice(1)){const cell=row.cells?.[column.id],spec={id:column.id,title:column.title,kind:column.kind||"text"};if(recordEmpty(cell,spec,ctx.fmt))continue;const term=h("dt"),value=h("dd");setText(term,column.title);recordValue(ctx,spec,cell,value,1);fields.append(term,value)}
76
78
  item.append(title,fields);return item};for(const row of rows.slice(0,step))holder.appendChild(card(row));body.appendChild(holder);if(rows.length>step){const more=recordButton(fill(ctx.labels.recordShowAll,{count:recordCount(ctx,rows.length)}),()=>{more.remove();for(const row of rows.slice(step))holder.appendChild(card(row));holder.children[step]?.querySelector("button")?.focus()},"cx-record-more");body.appendChild(more)}}
@@ -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(String(value),",");return escaped.startsWith('"')?escaped:'"'+escaped+'"'};return[[labels.recordSection,labels.recordField,labels.recordValue],...rows].map(row=>row.map(quote).join(",")).join("\r\n")}
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)}