@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.
Files changed (114) hide show
  1. package/CanopyX.Html/Assets/canopyx-board.css +50 -0
  2. package/CanopyX.Html/Assets/canopyx-board.js +39 -0
  3. package/CanopyX.Html/Assets/canopyx-buckets.js +15 -0
  4. package/CanopyX.Html/Assets/canopyx-calculations.css +7 -0
  5. package/CanopyX.Html/Assets/canopyx-calculations.js +52 -0
  6. package/CanopyX.Html/Assets/canopyx-calendar-edit.js +3 -3
  7. package/CanopyX.Html/Assets/canopyx-calendar.css +5 -24
  8. package/CanopyX.Html/Assets/canopyx-calendar.js +14 -19
  9. package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
  10. package/CanopyX.Html/Assets/canopyx-changes.css +6 -24
  11. package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
  12. package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
  13. package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
  14. package/CanopyX.Html/Assets/canopyx-data.js +3 -3
  15. package/CanopyX.Html/Assets/canopyx-editing.css +2 -2
  16. package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
  17. package/CanopyX.Html/Assets/canopyx-enhance.js +4 -4
  18. package/CanopyX.Html/Assets/canopyx-export.js +54 -13
  19. package/CanopyX.Html/Assets/canopyx-facets.css +14 -5
  20. package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
  21. package/CanopyX.Html/Assets/canopyx-filter-editor.css +71 -85
  22. package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
  23. package/CanopyX.Html/Assets/canopyx-flow-checks.css +1 -1
  24. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  25. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +2 -2
  26. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  27. package/CanopyX.Html/Assets/canopyx-flow-entry.css +136 -12
  28. package/CanopyX.Html/Assets/canopyx-flow-entry.js +2 -2
  29. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +2 -2
  30. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
  31. package/CanopyX.Html/Assets/canopyx-formatting.js +10 -9
  32. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +182 -128
  33. package/CanopyX.Html/Assets/canopyx-grid.css +228 -96
  34. package/CanopyX.Html/Assets/canopyx-grid.js +182 -128
  35. package/CanopyX.Html/Assets/canopyx-grouping.css +22 -15
  36. package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
  37. package/CanopyX.Html/Assets/canopyx-interactive.css +197 -74
  38. package/CanopyX.Html/Assets/canopyx-interactive.js +38 -45
  39. package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
  40. package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
  41. package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
  42. package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
  43. package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
  44. package/CanopyX.Html/Assets/canopyx-layouts.css +48 -20
  45. package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
  46. package/CanopyX.Html/Assets/canopyx-link.js +2 -2
  47. package/CanopyX.Html/Assets/canopyx-live.css +1 -3
  48. package/CanopyX.Html/Assets/canopyx-live.js +3 -3
  49. package/CanopyX.Html/Assets/canopyx-matrix.css +1 -8
  50. package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
  51. package/CanopyX.Html/Assets/canopyx-module.mjs +38 -45
  52. package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
  53. package/CanopyX.Html/Assets/canopyx-path.css +45 -0
  54. package/CanopyX.Html/Assets/canopyx-path.js +28 -0
  55. package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
  56. package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
  57. package/CanopyX.Html/Assets/canopyx-plan.css +56 -0
  58. package/CanopyX.Html/Assets/canopyx-plan.js +67 -0
  59. package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
  60. package/CanopyX.Html/Assets/canopyx-record-panel.css +8 -7
  61. package/CanopyX.Html/Assets/canopyx-record-panel.js +15 -14
  62. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +222 -161
  63. package/CanopyX.Html/Assets/canopyx-reporting.css +240 -107
  64. package/CanopyX.Html/Assets/canopyx-reporting.js +222 -161
  65. package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
  66. package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
  67. package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
  68. package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
  69. package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
  70. package/CanopyX.Html/Assets/canopyx-tree-tools.css +36 -35
  71. package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
  72. package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
  73. package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
  74. package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
  75. package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
  76. package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
  77. package/CanopyX.Html/Assets/canopyx-ui-overlays.js +42 -0
  78. package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
  79. package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
  80. package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
  81. package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
  82. package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
  83. package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
  84. package/CanopyX.Html/Assets/canopyx-values.css +5 -0
  85. package/CanopyX.Html/Assets/canopyx-values.js +13 -0
  86. package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
  87. package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
  88. package/CanopyX.Html/Assets/canopyx.css +197 -71
  89. package/CanopyX.Html/Assets/canopyx.js +29 -19
  90. package/JavaScript/board.d.ts +30 -0
  91. package/JavaScript/changes.d.ts +4 -1
  92. package/JavaScript/facets.d.ts +5 -3
  93. package/JavaScript/grid.d.ts +150 -16
  94. package/JavaScript/hosts.d.ts +14 -1
  95. package/JavaScript/index.d.ts +4 -2
  96. package/JavaScript/locales/de.mjs +177 -9
  97. package/JavaScript/locales/es.mjs +177 -9
  98. package/JavaScript/locales/fr.mjs +176 -8
  99. package/JavaScript/locales/it.mjs +176 -8
  100. package/JavaScript/locales/pl.mjs +176 -8
  101. package/JavaScript/matrix.d.ts +4 -1
  102. package/JavaScript/path.d.ts +33 -0
  103. package/JavaScript/pivot.d.ts +135 -0
  104. package/JavaScript/plan.d.ts +23 -0
  105. package/JavaScript/protocol.d.ts +16 -3
  106. package/JavaScript/records.d.ts +2 -0
  107. package/JavaScript/stack.d.ts +28 -0
  108. package/JavaScript/time-slider.d.ts +58 -0
  109. package/JavaScript/ui.d.ts +261 -0
  110. package/JavaScript/view-intents.d.ts +45 -0
  111. package/README.md +22 -3
  112. package/ThirdParty/OfficeIMO/LICENSE +21 -0
  113. package/ThirdParty/OfficeIMO/README.md +13 -0
  114. package/package.json +76 -3
@@ -1,4 +1,4 @@
1
- (function(global){"use strict";const installed=new WeakSet();const part={version:"463aadb3a2169631",install(context){if(installed.has(context.DataGrid.prototype))return;const{toneVariable,DataGrid,h,setText,fill,plural,gridButton,gridIcon,gridFreeze,cellText,cellValue,isCellObject,gridQuery,gridQueryRows,gridResultShape,gridPresenterTone,validateGridRows,validateGridPage,validateGridCursorPage,validStructuralCount,checkDocument,numberFormat,HostCellContext,disposeHostSlot,loadPart,PROTOCOL}=context;const CALENDAR_LABELS={calendarToday:"Today",calendarPrevious:"Previous period",calendarNext:"Next period",calendarViews:"Calendar view",calendarMonth:"Month",calendarWeek:"Week",calendarDay:"Day",calendarDays:"{count} days",calendarAgenda:"Agenda",calendarYear:"Year",calendarTimeline:"Timeline",calendarGoTo:"Go to date",calendarAllDay:"All day",calendarMore:"+{count} more",calendarMoreLabel:"Show {count} more events on {date}",calendarDayEvents:"Events on {date}",calendarNoEvents:"No events in this period",calendarEvents:"[one]{count} event[other]{count} events",calendarShowing:"{view}, {range}",calendarRepeats:"Repeats",calendarTruncated:"Showing the first {count} events. Narrow the period or the filters to see the rest.",calendarLoading:"Loading events…",calendarLoadError:"Could not load events: {error}",calendarNow:"Now",calendarZoom:"Zoom",calendarZoomHour:"Hours",calendarZoomDay:"Days",calendarZoomWeek:"Weeks",calendarZoomMonth:"Months",calendarZoomQuarter:"Quarters",calendarResources:"Resources",calendarCapacity:"Concurrent events",calendarCapacityAt:"{count} at once",calendarBusy:"{hours} h busy",calendarOverlaps:"[one]{count} overlap[other]{count} overlaps",calendarUnavailable:"Unavailable",calendarOutsideHours:"Outside working hours",calendarConflict:"Overlaps {title}",calendarNotAllowed:"{resource} cannot take this event",calendarMoved:"{title} moved to {time}",calendarResized:"{title} now ends {time}",calendarSeriesMoved:"Every occurrence of {title} moved",calendarSeriesTime:"Only the time of a whole series can be moved here.",calendarMoveHelp:"Arrow keys move, Shift with arrow keys changes the end, Alt with Up or Down changes the resource, Enter saves, Escape cancels.",calendarEdit:"Move or resize {title}",calendarSaveFailed:"{title} was not saved: {error}",calendarExport:"iCalendar (.ics)",calendarTimeRange:"{start} – {end}",calendarSelected:"Selected {range}",calendarLane:"{resource}, {events}",calendarHighlighted:"[one]{count} event highlighted[other]{count} events highlighted",calendarMini:"Mini month",calendarWeekList:"Week list",calendarDayList:"Day list",calendarMonths:"Months",calendarWeekNumber:"Week {number}",calendarWeekShort:"W{number}",calendarNewEvent:"New event",calendarEventTitle:"Title",calendarCreate:"Add",calendarCancel:"Cancel",calendarCreated:"{title} added on {time}",calendarReceived:"{title} scheduled on {time}",calendarOccurrenceTitle:"Change a repeating event",calendarOccurrenceReadOnly:"This part of the series cannot be saved because some values are read-only.",calendarEditOccurrence:"Edit this occurrence",calendarRemoveOccurrence:"Remove this occurrence",calendarOccurrenceScope:"Only {date} changes; other dates of {title} stay as they are.",calendarSharedResources:"{count} {resources}",calendarResourceWindow:"{resources} {start}–{end} of {total}",calendarThisEvent:"This event",calendarThisAndFollowing:"This and following events",calendarAllEvents:"All events",calendarSources:"Calendars",calendarImportFailed:"Could not read {source}: {error}",calendarActions:"Actions for {title}",calendarOpen:"Open",calendarMove:"Move",calendarNewHere:"New event here",calendarOutsideRange:"Outside the dates this calendar shows",calendarClose:"Close",calendarDetailsOf:"Details of {title}"};function calLabelsFor(labels){const out={...CALENDAR_LABELS};for(const name of Object.keys(CALENDAR_LABELS))if(Object.hasOwn(labels,name))out[name]=labels[name];return Object.freeze(out)}
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"4762fd2f9e9d1617",requires:["ui-menu"],install(context){if(installed.has(context.DataGrid.prototype))return;const{toneVariable,bindContextMenu,DataGrid,h,setText,fill,plural,gridButton,gridIcon,gridFreeze,cellText,cellValue,isCellObject,gridQuery,gridQueryRows,gridResultShape,gridPresenterTone,validateGridRows,repairGridCell,validateGridPage,validateGridCursorPage,validStructuralCount,checkDocument,numberFormat,HostCellContext,disposeHostSlot,loadPart,PROTOCOL}=context;const CALENDAR_LABELS={calendarToday:"Today",calendarPrevious:"Previous period",calendarNext:"Next period",calendarViews:"Calendar view",calendarMonth:"Month",calendarWeek:"Week",calendarDay:"Day",calendarDays:"{count} days",calendarAgenda:"Agenda",calendarYear:"Year",calendarTimeline:"Timeline",calendarGoTo:"Go to date",calendarAllDay:"All day",calendarMore:"+{count} more",calendarMoreLabel:"Show {count} more events on {date}",calendarDayEvents:"Events on {date}",calendarNoEvents:"No events in this period",calendarEvents:"[one]{count} event[other]{count} events",calendarShowing:"{view}, {range}",calendarRepeats:"Repeats",calendarTruncated:"Showing the first {count} events. Narrow the period or the filters to see the rest.",calendarLoading:"Loading events…",calendarLoadError:"Could not load events: {error}",calendarNow:"Now",calendarZoom:"Zoom",calendarZoomHour:"Hours",calendarZoomDay:"Days",calendarZoomWeek:"Weeks",calendarZoomMonth:"Months",calendarZoomQuarter:"Quarters",calendarResources:"Resources",calendarCapacity:"Concurrent events",calendarCapacityAt:"{count} at once",calendarBusy:"{hours} h busy",calendarOverlaps:"[one]{count} overlap[other]{count} overlaps",calendarUnavailable:"Unavailable",calendarOutsideHours:"Outside working hours",calendarConflict:"Overlaps {title}",calendarNotAllowed:"{resource} cannot take this event",calendarMoved:"{title} moved to {time}",calendarResized:"{title} now ends {time}",calendarSeriesMoved:"Every occurrence of {title} moved",calendarSeriesTime:"Only the time of a whole series can be moved here.",calendarMoveHelp:"Arrow keys move, Shift with arrow keys changes the end, Alt with Up or Down changes the resource, Enter saves, Escape cancels.",calendarEdit:"Move or resize {title}",calendarSaveFailed:"{title} was not saved: {error}",calendarExport:"iCalendar (.ics)",calendarTimeRange:"{start} – {end}",calendarSelected:"Selected {range}",calendarLane:"{resource}, {events}",calendarHighlighted:"[one]{count} event highlighted[other]{count} events highlighted",calendarMini:"Mini month",calendarWeekList:"Week list",calendarDayList:"Day list",calendarMonths:"Months",calendarWeekNumber:"Week {number}",calendarWeekShort:"W{number}",calendarNewEvent:"New event",calendarEventTitle:"Title",calendarCreate:"Add",calendarCancel:"Cancel",calendarCreated:"{title} added on {time}",calendarReceived:"{title} scheduled on {time}",calendarOccurrenceTitle:"Change a repeating event",calendarOccurrenceReadOnly:"This part of the series cannot be saved because some values are read-only.",calendarEditOccurrence:"Edit this occurrence",calendarRemoveOccurrence:"Remove this occurrence",calendarOccurrenceScope:"Only {date} changes; other dates of {title} stay as they are.",calendarSharedResources:"{count} {resources}",calendarResourceWindow:"{resources} {start}–{end} of {total}",calendarThisEvent:"This event",calendarThisAndFollowing:"This and following events",calendarAllEvents:"All events",calendarSources:"Calendars",calendarImportFailed:"Could not read {source}: {error}",calendarActions:"Actions for {title}",calendarOpen:"Open",calendarMove:"Move",calendarNewHere:"New event here",calendarOutsideRange:"Outside the dates this calendar shows",calendarClose:"Close",calendarDetailsOf:"Details of {title}"};function calLabelsFor(labels){const out={...CALENDAR_LABELS};for(const name of Object.keys(CALENDAR_LABELS))if(Object.hasOwn(labels,name))out[name]=labels[name];return Object.freeze(out)}
2
2
  function calCount(grid,template,count,values){return fill(plural(template,count,grid.lang),{...values,count:numberFormat(grid.lang).format(count)})}
3
3
  const CAL_DAY=86400000,CAL_MINUTE=60000,CAL_HOUR=3600000;const calZones=new Map();function calDayNumber(y,m,d){return Math.floor(Date.UTC(y,m-1,d)/ CAL_DAY); }
4
4
  function calDayParts(day){const date=new Date(day*CAL_DAY);return{y:date.getUTCFullYear(),m:date.getUTCMonth()+ 1,d:date.getUTCDate(),dow:date.getUTCDay()}}
@@ -116,10 +116,10 @@ return calColumns(out)}
116
116
  function calInAllDayRow(event){return event.allDay||event.end-event.start>=CAL_DAY}
117
117
  const CAL_ICONS={previous:"M10 3 5 8l5 5",next:"m6 3 5 5-5 5",calendar:"M3 4h10v9H3zM3 7h10M6 2v3M10 2v3",repeat:"M3 7a4 4 0 0 1 7-3l1 1M13 9a4 4 0 0 1-7 3l-1-1M11 2v3H8M5 14v-3h3",print:"M4 6V2h8v4M4 11H2V6h12v5h-2M4 9h8v5H4z"};function calIcon(name){const svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),path=document.createElementNS("http://www.w3.org/2000/svg","path");svg.setAttribute("viewBox","0 0 16 16");svg.setAttribute("aria-hidden","true");svg.setAttribute("class","cx-cal-ico");path.setAttribute("d",CAL_ICONS[name]);svg.appendChild(path);return svg}
118
118
  Object.assign(DataGrid.prototype,{calBuildBar(){const labels=this.calLabels,bar=this.calBar=h("div","cx-cal-bar"),nav=h("div","cx-cal-nav");nav.setAttribute("role","group");nav.setAttribute("aria-label",this.view.label);const button=(text,icon,run,cls)=>{const item=gridButton(icon?"":text,run);item.classList.add("cx-btn","cx-cal-"+cls);if(icon){item.classList.add("icon","ghost");item.appendChild(calIcon(icon));item.setAttribute("aria-label",text);item.title=text}
119
- return item};this.calPrev=button(labels.calendarPrevious,"previous",()=>this.calendarStep(-1),"prev");this.calTodayButton=button(labels.calendarToday,null,()=>{if(this.calTodayButton.getAttribute("aria-disabled")!=="true")this.calendarToday()},"gotoday");this.calNextButton=button(labels.calendarNext,"next",()=>this.calendarStep(1),"next");nav.append(this.calTodayButton,this.calPrev,this.calNextButton);this.calTitle=h("h2","cx-cal-title");this.calTitle.id=this.id+"-cal-title";const jump=this.calJump=h("input","cx-cal-jump");jump.type="date";jump.setAttribute("aria-label",labels.calendarGoTo);jump.title=labels.calendarGoTo;jump.addEventListener("change",()=>{const day=calParseDay(jump.value);if(Number.isFinite(day))this.setCalendarDate(jump.value)});const jumpBox=h("span","cx-cal-jumpbox");if(typeof HTMLInputElement==="function"&&"showPicker" in HTMLInputElement.prototype){const open=this.calJumpButton=h("button","cx-cal-jumpbtn");open.type="button";jump.tabIndex=-1;jump.setAttribute("aria-hidden","true");jump.classList.add("cx-cal-jump-behind");open.addEventListener("click",()=>{try{jump.showPicker()}
120
- catch{jump.classList.remove("cx-cal-jump-behind");jump.removeAttribute("aria-hidden");jump.removeAttribute("tabindex");open.remove();this.calJumpButton=null;jump.focus()}});jumpBox.append(jump,open)}else jumpBox.append(jump);const views=this.calViewGroup=h("div","cx-cal-views");views.setAttribute("role","group");views.setAttribute("aria-label",labels.calendarViews);this.calViewButtons=new Map();for(const view of this.cal.views){const item=button(this.calViewName(view),null,()=>this.setCalendarView(view),"view");item.setAttribute("aria-pressed","false");item.dataset.cxCalView=view;this.calViewButtons.set(view,item);views.appendChild(item)}
121
- const select=this.calViewSelect=h("select","cx-cal-view-select");select.setAttribute("aria-label",labels.calendarViews);for(const view of this.cal.views){const option=h("option");option.value=view;setText(option,this.calViewName(view));select.appendChild(option)}
122
- select.addEventListener("change",()=>this.setCalendarView(select.value));const zoom=this.calZoomSelect=h("select","cx-cal-zoom");zoom.setAttribute("aria-label",labels.calendarZoom);zoom.title=labels.calendarZoom;for(const level of this.cal.zooms){const option=h("option");option.value=level;setText(option,labels["calendarZoom"+level[0].toUpperCase()+ level.slice(1)]);zoom.appendChild(option)}
119
+ return item};this.calPrev=button(labels.calendarPrevious,"previous",()=>this.calendarStep(-1),"prev");this.calTodayButton=button(labels.calendarToday,null,()=>{if(this.calTodayButton.getAttribute("aria-disabled")!=="true")this.calendarToday()},"gotoday");this.calNextButton=button(labels.calendarNext,"next",()=>this.calendarStep(1),"next");nav.append(this.calTodayButton,this.calPrev,this.calNextButton);this.calTitle=h("h2","cx-cal-title");this.calTitle.id=this.id+"-cal-title";const jump=this.calJump=h("input","cx-input cx-cal-jump");jump.type="date";jump.setAttribute("aria-label",labels.calendarGoTo);jump.title=labels.calendarGoTo;jump.addEventListener("change",()=>{const day=calParseDay(jump.value);if(Number.isFinite(day))this.setCalendarDate(jump.value)});const jumpBox=h("span","cx-cal-jumpbox");if(typeof HTMLInputElement==="function"&&"showPicker" in HTMLInputElement.prototype){const open=this.calJumpButton=h("button","cx-btn cx-cal-jumpbtn");open.type="button";jump.tabIndex=-1;jump.setAttribute("aria-hidden","true");jump.classList.add("cx-cal-jump-behind");open.addEventListener("click",()=>{try{jump.showPicker()}
120
+ catch{jump.classList.remove("cx-cal-jump-behind");jump.removeAttribute("aria-hidden");jump.removeAttribute("tabindex");open.remove();this.calJumpButton=null;jump.focus()}});jumpBox.append(jump,open)}else jumpBox.append(jump);const views=this.calViewGroup=h("div","cx-segmented cx-cal-views");views.setAttribute("role","group");views.setAttribute("aria-label",labels.calendarViews);this.calViewButtons=new Map();for(const view of this.cal.views){const item=button(this.calViewName(view),null,()=>this.setCalendarView(view),"view");item.classList.remove("cx-btn","cx-button");item.setAttribute("aria-pressed","false");item.dataset.cxCalView=view;this.calViewButtons.set(view,item);views.appendChild(item)}
121
+ const select=this.calViewSelect=h("select","cx-select cx-cal-view-select");select.setAttribute("aria-label",labels.calendarViews);for(const view of this.cal.views){const option=h("option");option.value=view;setText(option,this.calViewName(view));select.appendChild(option)}
122
+ select.addEventListener("change",()=>this.setCalendarView(select.value));const zoom=this.calZoomSelect=h("select","cx-select cx-cal-zoom");zoom.setAttribute("aria-label",labels.calendarZoom);zoom.title=labels.calendarZoom;for(const level of this.cal.zooms){const option=h("option");option.value=level;setText(option,labels["calendarZoom"+level[0].toUpperCase()+ level.slice(1)]);zoom.appendChild(option)}
123
123
  zoom.addEventListener("change",()=>this.setCalendarZoom(zoom.value));if(this.cal.views.length<2){views.hidden=true;select.hidden=true}
124
124
  const print=this.cal.print?button(this.labels.gridPrint||"Print","print",()=>global.print(),"print"):null;bar.append(nav,this.calTitle,h("span","cx-spacer"),jumpBox,zoom,views,select,...(print?[print]:[]));return bar},calViewName(view){const labels=this.calLabels;return view==="days"?fill(labels.calendarDays,{count:this.calDaysCount()}):labels["calendar"+view[0].toUpperCase()+ view.slice(1)]},calDaysCount(){return this.calPhone&&this.cal.days>3?3:this.cal.days},calSyncBar(announce){const view=this.calView,range=this.calRange;for(const[name,item]of this.calViewButtons){item.setAttribute("aria-pressed",String(name===view));item.classList.toggle("active",name===view)}
125
125
  this.calViewSelect.value=view;this.calZoomSelect.hidden=view!=="timeline"||this.cal.zooms.length<2;this.calZoomSelect.value=this.calZoom;const title=this.calRangeTitle();setText(this.calTitle,title);this.calJump.value=calDayText(this.calDate);if(this.calJumpButton){setText(this.calJumpButton,this.calFmt.date(this.calDate));this.calJumpButton.setAttribute("aria-label",this.calLabels.calendarGoTo+", "+this.calFmt.date(this.calDate));this.calJumpButton.title=this.calLabels.calendarGoTo}
@@ -147,13 +147,8 @@ return parts},calPlace(panel,anchor){this.calRoot.appendChild(panel);const box=a
147
147
  else if(key.key==="Tab"){key.preventDefault();const stops=[close,...panel.querySelectorAll(".cx-cal-det-desc[tabindex]")],at=stops.indexOf(document.activeElement);stops[(at +(key.shiftKey?stops.length-1:1))%stops.length].focus()}});this.calDetailsOutside=press=>{if(!panel.contains(press.target)&&press.target!==anchor)this.calCloseDetails(false)};document.addEventListener("pointerdown",this.calDetailsOutside,true);close.focus({preventScroll:true});return panel},calCloseDetails(restore){const panel=this.calDetails;if(!panel)return;this.calDetails=null;document.removeEventListener("pointerdown",this.calDetailsOutside,true);panel.remove();if(restore&&panel._calAnchor?.isConnected)panel._calAnchor.focus({preventScroll:true})},calHoverOver(pointer){if(!this.cal.hover||pointer.pointerType==="touch"||this.calDrag||this.calMoving||this.calDetails||this.calMenu)return;const element=pointer.target.closest?.(".cx-cal-ev");if(!element?._calEvent||element===this.calHoverAnchor)return;this.calHideHover();this.calHoverAnchor=element;this.calHoverTimer=setTimeout(()=>{if(this.destroyed||!element.isConnected||this.calDrag||this.calDetails)return;const card=this.calHover=h("div","cx-cal-hover");card.setAttribute("aria-hidden","true");card.append(...this.calDetailsContent(element._calEvent));this.calPlace(card,element)},CAL_HOVER_DELAY)},calHoverOut(pointer){if(this.calHoverAnchor&&!this.calHoverAnchor.contains(pointer.relatedTarget))this.calHideHover()},calHideHover(){clearTimeout(this.calHoverTimer);this.calHoverAnchor=null;this.calHover?.remove();this.calHover=null}});Object.assign(DataGrid.prototype,{calMenuContext(target,x){const element=target.closest?.(".cx-cal-ev"),lane=!element&&x!=null&&target.closest?.(".cx-tl-lane");const cell=lane?[...lane.querySelectorAll(".cx-tl-cell")].find(item=>{const box=item.getBoundingClientRect();return x>=box.left&&x<box.right}):target.closest?.("[data-cx-day]");if(element?._calEvent)return{kind:"event",target:element,event:this.calPublicEvent(element._calEvent),raw:element._calEvent};if(!cell)return null;const minutes=cell.dataset.cxMinutes!==undefined?Number(cell.dataset.cxMinutes):null;return{kind:cell.classList.contains("cx-tl-cell")?"resource":minutes===null?"day":"slot",target:cell,day:calDayText(Number(cell.dataset.cxDay)),minutes,resource:this.calCellResource(cell)}},calMenuItems(context){const labels=this.calLabels,items=[];if(context.kind==="event"){items.push({id:"open",label:labels.calendarOpen,run:()=>this.calOpenEvent(context.raw,true,context.target)});if(context.raw.recurring&&this.cal.editable&&this.cal.series?.editable&&this.cal.recurrenceId?.editable&&this.calCanEdit?.(context.raw,false))
148
148
  items.push({id:"occurrence",label:labels.calendarEditOccurrence,run:()=>this.editCalendarOccurrence(context.raw.id)});if(this.calStartMove&&this.cal.editable&&(this.calCanEdit(context.raw,false)||this.calCanEdit(context.raw,true)))items.push({id:"move",label:labels.calendarMove,run:()=>this.calStartMove(context.target)})}else if(this.cal.create&&this.calCreateFromClick){items.push({id:"new",label:labels.calendarNewHere,run:()=>this.calCreateFromClick(context.target)})}
149
149
  const hook=this.opts.calendar?.menu;if(typeof hook!=="function")return items;const own={kind:context.kind,event:context.event,day:context.day,minutes:context.minutes,resource:context.resource};let result;try{result=hook(Object.freeze(own),items.map(({id,label})=>Object.freeze({id,label})))}catch(error){this.emit("error",{error});return items}
150
- if(result===null||result===false)return[];if(!Array.isArray(result))return items;return result.slice(0,30).map(item=>{const kept=item&&items.find(entry=>entry.id===item.id&&!item.run);if(kept)return kept;return item&&typeof item.label==="string"&&item.label.trim()&&typeof item.run==="function"?{id:item.id??null,label:item.label.slice(0,200),run:()=>item.run(Object.freeze(own)),disabled:item.disabled===true}:null}).filter(Boolean)},calOpenMenu(target,x,y){if(!this.cal.menu)return false;const context=this.calMenuContext(target,x);if(context?.target.classList.contains("cx-cal-invalid"))return false;if(!context)return false;const items=this.calMenuItems(context);if(!items.length)return false;this.calCloseMenu(false);this.calHideHover();const menu=this.calMenu=h("div","cx-cal-menu"),name=context.kind==="event"?context.raw.title:context.kind==="resource"?this.calResourceName?.(context.resource)??"":this.calFmt.longDay(calParseDay(context.day));menu.setAttribute("role","menu");menu.setAttribute("aria-label",fill(this.calLabels.calendarActions,{title:name}));const buttons=items.map(item=>{const button=h("button","cx-cal-menu-item");button.type="button";button.setAttribute("role","menuitem");button.tabIndex=-1;setText(button,item.label);if(item.disabled)button.setAttribute("aria-disabled","true");button.addEventListener("click",()=>{if(item.disabled)return;this.calCloseMenu(true);Promise.resolve().then(()=>item.run()).catch(error=>this.emit("error",{error}))});menu.appendChild(button);return button});menu._calReturn=target;menu.addEventListener("contextmenu",event=>event.preventDefault());this.calRoot.appendChild(menu);const frame=this.calRoot.getBoundingClientRect(),box=target.getBoundingClientRect(),width=menu.offsetWidth,height=menu.offsetHeight;const left=x!=null?x-frame.left:box.left-frame.left+Math.min(box.width,24),top=y!=null?y-frame.top:box.top-frame.top+Math.min(box.height,24);menu.style.left=Math.max(4,Math.min(left,frame.width-width-4))+ "px";menu.style.top=Math.max(4,Math.min(top,frame.height-height-4))+ "px";menu.addEventListener("keydown",key=>{const at=buttons.indexOf(document.activeElement);if(key.key==="Escape"||key.key==="Tab"){key.preventDefault();key.stopPropagation();this.calCloseMenu(true)}
151
- else if(key.key==="ArrowDown"){key.preventDefault();buttons[(at+1)%buttons.length].focus()}
152
- else if(key.key==="ArrowUp"){key.preventDefault();buttons[(at+buttons.length-1)%buttons.length].focus()}
153
- else if(key.key==="Home"){key.preventDefault();buttons[0].focus()}
154
- else if(key.key==="End"){key.preventDefault();buttons[buttons.length-1].focus()}});this.calMenuOutside=press=>{if(!menu.contains(press.target))this.calCloseMenu(false)};document.addEventListener("pointerdown",this.calMenuOutside,true);buttons[0].focus({preventScroll:true});return true},calCloseMenu(restore){const menu=this.calMenu;if(!menu)return;this.calMenu=null;document.removeEventListener("pointerdown",this.calMenuOutside,true);menu.remove();if(restore&&menu._calReturn?.isConnected)menu._calReturn.focus({preventScroll:true})},calMenuStart(){if(!this.cal.menu)return;const body=this.calBody,signal=this.lifetime.signal;let press=null;const cancel=()=>{if(press){clearTimeout(press.timer);press=null;this.calPressTimer=0}};body.addEventListener("contextmenu",event=>{cancel();if(this.calMenu&&Date.now()-(this.calMenuOpenedAt||0)<800){event.preventDefault();return}
155
- if(event.shiftKey||this.calDrag?.started||this.calMoving)return;const keyboard=event.button!==2&&event.clientX===0&&event.clientY===0;if(this.calOpenMenu(event.target,keyboard?null:event.clientX,keyboard?null:event.clientY)){event.preventDefault();this.calMenuOpenedAt=Date.now()}},{signal});body.addEventListener("pointerdown",event=>{cancel();if(this.calPressSuppress){this.calPressSuppress=false;this.calSuppressClick=false}
156
- if(event.pointerType!=="touch")return;press={x:event.clientX,y:event.clientY,target:event.target,timer:setTimeout(()=>{const at=press;press=null;if(at&&!this.calDrag?.started&&Date.now()-(this.calMenuOpenedAt||0)>800&&this.calOpenMenu(at.target,at.x,at.y)){this.calMenuOpenedAt=Date.now();this.calSuppressClick=true;this.calPressSuppress=true}},600)};this.calPressTimer=press.timer},{signal,passive:true});body.addEventListener("pointermove",event=>{if(press&&Math.hypot(event.clientX-press.x,event.clientY-press.y)>8)cancel()},{signal,passive:true});for(const type of["pointerup","pointercancel","scroll"])body.addEventListener(type,cancel,{signal,passive:true,capture:type==="scroll"})},calMenuKey(event){if(!this.cal.menu||!(event.key==="ContextMenu"||event.key==="F10"&&event.shiftKey))return false;if(!this.calOpenMenu(event.target))return false;event.preventDefault();this.calMenuOpenedAt=Date.now();return true}});Object.assign(DataGrid.prototype,{calBuildLegend(){const sources=this.cal.sources;this.calHiddenSources=new Set(sources.filter(source=>source.hidden).map(source=>source.id));if(!sources.length)return null;const legend=this.calLegend=h("div","cx-cal-legend");legend.setAttribute("role","group");legend.setAttribute("aria-label",this.calLabels.calendarSources);for(const source of sources){const button=h("button","cx-cal-src"),swatch=h("i","cx-cal-src-swatch"),text=h("span");button.type="button";button.dataset.cxSource=source.id;button.setAttribute("aria-pressed",String(!this.calHiddenSources.has(source.id)));if(source.tone)button.style.setProperty("--cx-ev",toneVariable(source.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));if(source.color)button.style.setProperty("--cx-ev",source.color);swatch.setAttribute("aria-hidden","true");setText(text,source.label);button.append(swatch,text);button.addEventListener("click",()=>this.calToggleSource(source.id));legend.appendChild(button)}
150
+ if(result===null||result===false)return[];if(!Array.isArray(result))return items;return result.slice(0,30).map(item=>{const kept=item&&items.find(entry=>entry.id===item.id&&!item.run);if(kept)return kept;return item&&typeof item.label==="string"&&item.label.trim()&&typeof item.run==="function"?{id:item.id??null,label:item.label.slice(0,200),run:()=>item.run(Object.freeze(own)),disabled:item.disabled===true}:null}).filter(Boolean)},calMenuStart(){if(!this.cal.menu)return;this.calMenuBinding=bindContextMenu(this.calBody,(event,element)=>{const context=this.calMenuContext(element,event?.clientX);return context?this.calMenuItems(context):[]},{host:this.host,closeOnFocusOutside:true,match:event=>this.calMenuContext(event.target,event.type==="keydown"?null:event.clientX)?.target,beforeOpen:(_event,element)=>{if(this.destroyed||!this.cal.menu||this.calDrag?.started||this.calMoving||element.classList.contains("cx-cal-invalid"))return false;this.calHideHover()},label:(event,element)=>{const context=this.calMenuContext(element,event?.clientX);const name=context.kind==="event"?context.raw.title:context.kind==="resource"?
151
+ this.calResourceName?.(context.resource)??"":this.calFmt.longDay(calParseDay(context.day));return fill(this.calLabels.calendarActions,{title:name})},onOpen:({menu})=>{this.calMenu=menu;document.dispatchEvent(new CustomEvent("canopyx:closemenus",{detail:{source:menu}}))},onClose:({menu})=>{if(this.calMenu===menu)this.calMenu=null},onSelect:item=>{Promise.resolve().then(()=>item.run()).catch(error=>this.emit("error",{error}))}});this.calMenuBinding.ready.catch(error=>{if(!this.destroyed)this.emit("error",{error})})}});Object.assign(DataGrid.prototype,{calBuildLegend(){const sources=this.cal.sources;this.calHiddenSources=new Set(sources.filter(source=>source.hidden).map(source=>source.id));if(!sources.length)return null;const legend=this.calLegend=h("div","cx-cal-legend");legend.setAttribute("role","group");legend.setAttribute("aria-label",this.calLabels.calendarSources);for(const source of sources){const button=h("button","cx-chip cx-cal-src"),swatch=h("i","cx-cal-src-swatch"),text=h("span");button.type="button";button.dataset.cxSource=source.id;button.setAttribute("aria-pressed",String(!this.calHiddenSources.has(source.id)));if(source.tone)button.style.setProperty("--cx-ev",toneVariable(source.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));if(source.color)button.style.setProperty("--cx-ev",source.color);swatch.setAttribute("aria-hidden","true");setText(text,source.label);button.append(swatch,text);button.addEventListener("click",()=>this.calToggleSource(source.id));legend.appendChild(button)}
157
152
  return legend},setCalendarSource(id,visible){return this.calToggleSource(id,visible)},calToggleSource(id,show){const hidden=this.calHiddenSources,source=this.cal.sources.find(item=>item.id===id);if(!source)throw new Error("CanopyX: the calendar has no source "+id+".");const visible=show===undefined?hidden.has(id):!!show;if(visible)hidden.delete(id);else hidden.add(id);this.calLegend?.querySelector('[data-cx-source="'+CSS.escape(id)+ '"]')?.setAttribute("aria-pressed",String(visible));this.calSourceVersion=(this.calSourceVersion||0)+ 1;if(this.calAllEvents){this.calEvents=this.calShownEvents(this.calAllEvents);this.calPaint({keep:true})}
158
153
  this.emit("calendarSource",{id,visible});if(source.url)this.calReload({keep:true});return visible},calShownEvents(events){const hidden=this.calHiddenSources;return hidden?.size?events.filter(event=>!event.base.source||!hidden.has(event.base.source)):events}});Object.assign(DataGrid.prototype,{async calLoadJson(from,to,signal){const rows=[],errors=[],cache=this.calJsonCache||=new Map(),budget={bytes:0,rows:0,limit:this.cal.limit};const sources=this.cal.sources.filter(source=>source.url&&!this.calHiddenSources.has(source.id));let next=0;const load=async source=>{const url=new URL(source.url,location.href);for(const[key,value]of Object.entries(source.fetchParams))url.searchParams.set(key,value);url.searchParams.set("start",calIso(from));url.searchParams.set("end",calIso(to));url.searchParams.set("timeZone",this.calZone.name);const key=source.id+":"+url.href;try{let entry=cache.get(key);if(!entry){if(url.origin!==location.origin||!["http:","https:"].includes(url.protocol)||url.username||url.password)throw new Error("JSON feeds need a same-origin http(s) page.");const response=await fetch(url.href,{signal,credentials:"same-origin",redirect:"error",headers:{Accept:"application/json"}});if(!response.ok)throw new Error("HTTP "+response.status);const body=await calJsonText(response,signal,budget);const items=calJsonRows(JSON.parse(body.text),source.id);calJsonCharge(budget,0,items.length);if(signal.aborted)throw new DOMException("Aborted","AbortError");entry={items,bytes:body.bytes};cache.set(key,entry);while(cache.size>12)cache.delete(cache.keys().next().value)}else calJsonCharge(budget,entry.bytes,entry.items.length);rows.push(...entry.items)}catch(error){if(signal.aborted||error.name==="AbortError")throw error;errors.push(source.label+": "+error.message);this.emit("error",{error,source:source.id})}};await Promise.all(Array.from({length:Math.min(4,sources.length)},async()=>{while(next<sources.length&&!budget.problem)await load(sources[next++])}));return{rows,errors}}});async function calJsonText(response,signal,budget){const max=8000000;if(Number(response.headers.get("content-length"))>max)throw new Error("JSON feed exceeds 8 MB.");if(!response.body?.getReader){const text=await response.text();if(text.length>2000000)throw new Error("JSON feed exceeds 2 million characters.");const bytes=new TextEncoder().encode(text).byteLength;calJsonCharge(budget,bytes,0);return{text,bytes}}
159
154
  const reader=response.body.getReader(),decoder=new TextDecoder();let bytes=0,text="";try{for(;;){if(signal.aborted)throw new DOMException("Aborted","AbortError");const chunk=await reader.read();if(chunk.done)break;bytes +=chunk.value.byteLength;if(bytes>max)throw new Error("JSON feed exceeds 8 MB.");calJsonCharge(budget,chunk.value.byteLength,0);text +=decoder.decode(chunk.value,{stream:true});if(text.length>2000000)throw new Error("JSON feed exceeds 2 million characters.")}
@@ -197,7 +192,7 @@ this.calFocus={day,minutes:this.calFocus?.minutes??null,event:null};if(!inside){
197
192
  if(this.calPhone&&view==="month"){const list=this.calBody.querySelector(".cx-cal-daylist");if(list){this.calDisposeEventRenderers(list);list.replaceWith(this.calDayList(day))}
198
193
  this.calMarkListedDay(day);const count=this.calEventsOn(day).length;this.calAnnounce(this.calFmt.longDay(day)+ ", " +(count?calCount(this,this.calLabels.calendarEvents,count):this.calLabels.calendarNoEvents))}
199
194
  this.calRestoreFocus(true)}});const CAL_DAY_GRIDS=["month","mini","months","weekList","dayList"];function calDayGrid(view){return CAL_DAY_GRIDS.includes(view)}
200
- Object.assign(DataGrid.prototype,{calPaintMini(){const range=this.calRange;this.calCells=new Map();const grid=this.calMonthGrid(range.firstDay,range.lastDay,range.month,{rowHeight:34,dots:true,outside:this.cal.outsideDays,labelledBy:this.calTitle.id,className:"cx-cal-mini"});this.calBody.replaceChildren(grid);this.calGrid=grid},calPaintMonths(){const range=this.calRange,stack=h("div","cx-cal-months");this.calCells=new Map();for(let month=range.month;month<=range.lastDay;month=calAddMonths(month,1)){const section=h("section","cx-cal-mblock"),title=h("h3","cx-cal-mtitle"),last=calAddMonths(month,1)- 1;title.id=this.id+"-cal-m"+month;setText(title,this.calFmt.monthTitle(month));const first=calWeekStart(month,this.cal.firstDay),end=calWeekStart(last,this.cal.firstDay)+ 6;section.append(title,this.calMonthGrid(first,end,month,{rowHeight:92,dots:this.calPhone,outside:false,labelledBy:title.id}));stack.appendChild(section)}
195
+ Object.assign(DataGrid.prototype,{calPaintMini(){const range=this.calRange;this.calCells=new Map();const grid=this.calMonthGrid(range.firstDay,range.lastDay,range.month,{rowHeight:34,dots:true,outside:this.cal.outsideDays,labelledBy:this.calTitle.id,className:"cx-cal-mini"});grid.setAttribute("data-cx-finish-allow","empty-band");this.calBody.replaceChildren(grid);this.calGrid=grid},calPaintMonths(){const range=this.calRange,stack=h("div","cx-cal-months");this.calCells=new Map();for(let month=range.month;month<=range.lastDay;month=calAddMonths(month,1)){const section=h("section","cx-cal-mblock"),title=h("h3","cx-cal-mtitle"),last=calAddMonths(month,1)- 1;title.id=this.id+"-cal-m"+month;setText(title,this.calFmt.monthTitle(month));const first=calWeekStart(month,this.cal.firstDay),end=calWeekStart(last,this.cal.firstDay)+ 6;section.append(title,this.calMonthGrid(first,end,month,{rowHeight:92,dots:this.calPhone,outside:false,labelledBy:title.id}));stack.appendChild(section)}
201
196
  this.calBody.replaceChildren(stack);this.calGrid=stack},calPaintList(){const range=this.calRange,days=this.calShownDays(range.firstDay,range.lastDay),today=this.calZone.day(Date.now()),valid=this.cal.validRange,fmt=this.calFmt;const grid=h("div","cx-cal-list" +(days.length===1?" cx-cal-list-day":"")),row=h("div","cx-cal-lrow");grid.setAttribute("role","grid");grid.setAttribute("aria-labelledby",this.calTitle.id);grid.setAttribute("aria-readonly",String(!this.cal.editable&&!this.cal.create));row.setAttribute("role","row");grid.style.setProperty("--cx-cal-cols",String(days.length));this.calCells=new Map();for(const day of days){const events=this.calEventsOn(day),invalid=valid&&(day<valid.first||day>valid.last);const cell=h("div","cx-cal-day cx-cal-lday" +(day===today?" cx-cal-today":"")+(invalid?" cx-cal-invalid":""));cell.setAttribute("role","gridcell");cell.tabIndex=-1;cell.dataset.cxDay=String(day);if(invalid)cell.setAttribute("aria-disabled","true");if(day===today)cell.setAttribute("aria-current","date");cell.setAttribute("aria-label",this.calDayName(day,events.length,this.calBackgroundsOn(day)));const head=h("div","cx-cal-lhead"),name=h("span","cx-cal-dayname"),number=h("span","cx-cal-num");head.setAttribute("aria-hidden","true");setText(name,fmt.weekday(day,days.length===1?"long":"short"));setText(number,fmt.dayNumber(day));head.append(name,number);if(this.cal.weekNumbers&&day===days[0]){const wk=h("span","cx-cal-wknum");setText(wk,fill(this.calLabels.calendarWeekShort,{number:this.calWeekNumber(day)}));head.appendChild(wk)}
202
197
  cell.appendChild(head);if(!events.length){const empty=h("p","cx-cal-empty");setText(empty,this.calLabels.calendarNoEvents);empty.setAttribute("aria-hidden","true");cell.appendChild(empty)}
203
198
  for(const event of events)cell.appendChild(this.calEventElement(event,"item"));const backgrounds=this.calBackgroundsOn(day);if(backgrounds.length){cell.classList.add("cx-cal-bgday");cell.style.setProperty("--cx-bg-tone",toneVariable(backgrounds[0].tone,false,"var(--hfx-color-status-info-fg,light-dark(#2b5fc0,#74a2f7))"))}
@@ -205,7 +200,7 @@ this.calCells.set(day,cell);row.appendChild(cell)}
205
200
  grid.appendChild(row);this.calBody.replaceChildren(grid);this.calGrid=grid}});const CAL_SLOT_PX=24,CAL_GUTTER=64,CAL_ALLDAY_LANES=3;Object.assign(DataGrid.prototype,{calTimeColumns(days){const all=this.calResourceColumns?.()||null;this.calResourcePages=null;if(!all){this.calTimeWindow=null;return days.map(day=>({day,resource:null}))}
206
201
  const size=this.calPhone&&!this.calPrinting&&all.length>2?(days.length===1?2:1):all.length,pages=Math.ceil(all.length / size);
207
202
  const page=Math.min(Math.floor((this.calResourceFirst||0)/ size), pages - 1);
208
- if(pages>1)this.calResourcePages={all,size,pages,page};const resources=all.slice(page*size,page*size+size);const out=[];for(const day of days)for(const resource of resources)out.push({day,resource:resource.id,label:resource.label,group:resource.group});return this.calWindowTimeColumns(out)},calResourcePicker(){const window=this.calTimeWindow,paging=this.calResourcePages;const total=window?.total??paging.all.length,size=window?.size??paging.size,first=window?.first??paging.page*size;const bar=h("div","cx-cal-rpick"),select=h("select","cx-cal-rpick-select"),maximum=window?total-size:Math.floor((total-1)/ size) * size;
203
+ if(pages>1)this.calResourcePages={all,size,pages,page};const resources=all.slice(page*size,page*size+size);const out=[];for(const day of days)for(const resource of resources)out.push({day,resource:resource.id,label:resource.label,group:resource.group});return this.calWindowTimeColumns(out)},calResourcePicker(){const window=this.calTimeWindow,paging=this.calResourcePages;const total=window?.total??paging.all.length,size=window?.size??paging.size,first=window?.first??paging.page*size;const bar=h("div","cx-cal-rpick"),select=h("select","cx-select cx-cal-rpick-select"),maximum=window?total-size:Math.floor((total-1)/ size) * size;
209
204
  const multiDay=window&&window.columns[0].day!==window.columns.at(-1).day;const caption=column=>this.calFmt.day({weekday:"short",month:"short",day:"numeric"},column.day)+ " "+column.label;const range=at=>multiDay?caption(window.columns[at])+ " – "+caption(window.columns[Math.min(total-1,at+size-1)]):
210
205
  fill(this.calLabels.calendarResourceWindow,{resources:this.calLabels.calendarResources,start:this.calFmt.number(at+1),end:this.calFmt.number(Math.min(total,at+size)),total:this.calFmt.number(total)});const choices=new Set([first,maximum]);for(let at=0;at<total;at +=size)choices.add(Math.min(at,maximum));select.setAttribute("aria-label",range(first));for(const at of[...choices].sort((a,b)=>a-b)){const option=h("option");option.value=String(at);setText(option,range(at));select.appendChild(option)}
211
206
  const show=(at,focus)=>{if(window)this.calTimeFirst=at;else this.calResourceFirst=at;this.calPaint({keep:true});this.calBody.querySelector(focus)?.focus({preventScroll:true})};select.value=String(first);select.addEventListener("change",()=>show(Number(select.value),".cx-cal-rpick-select"));const buttons=[-1,1].map(sign=>{const button=h("button","cx-btn ghost cx-cal-rpick-" +(sign<0?"prev":"next")),at=Math.max(0,Math.min(maximum,first+sign*size));button.type="button";button.disabled=at===first;setText(button,sign<0?"←":"→");button.setAttribute("aria-label",(sign<0?this.calLabels.calendarPrevious:this.calLabels.calendarNext)+ ": "+range(at));button.addEventListener("click",()=>show(at,".cx-cal-rpick-select"));return button});bar.append(buttons[0],select,buttons[1]);return bar},calPaintTime(){const cal=this.cal,range=this.calRange,days=this.calShownDays(range.firstDay,range.lastDay),columns=this.calTimeColumns(days);const today=this.calZone.day(Date.now()),slot=cal.slotMinutes,ppm=CAL_SLOT_PX / slot, labels = this.calLabels, fmt = this.calFmt;
@@ -260,7 +255,7 @@ legend.appendChild(high);this.calBody.replaceChildren(year,legend);this.calGrid=
260
255
  if(events.length>shown.length){const item=h("li","cx-cal-yl-more"),more=gridButton(fill(this.calLabels.calendarMore,{count:numberFormat(this.lang).format(events.length-shown.length)}),()=>{if(this.cal.views.includes("month"))this.calGo(first,"month",true);else if(this.cal.views.includes("agenda"))this.calGo(first,"agenda",true)});more.className="cx-cal-yl-morebtn";item.appendChild(more);list.appendChild(item)}
261
256
  return list},calKeyYear(event,cell){const day=Number(cell.dataset.cxDay),key=event.key,range=this.calRange;if(!this.calAllowsSpan(day*CAL_DAY,(day+1)*CAL_DAY,true))return;let next=null;if(key==="ArrowLeft"||key==="ArrowRight")next=day +(key==="ArrowLeft"?-1:1);else if(key==="ArrowUp"||key==="ArrowDown")next=day +(key==="ArrowUp"?-7:7);else if(key==="Home")next=calMonthStart(day);else if(key==="End")next=calAddMonths(calMonthStart(day),1)- 1;else if(key==="PageUp"||key==="PageDown")next=calAddMonths(day,key==="PageUp"?-12:12);else if(key==="Enter"){event.preventDefault();if(this.cal.views.includes("day"))this.calGo(day,"day",true).then(()=>this.calRestoreFocus(true));else if(this.cal.views.includes("week"))this.calGo(day,"week",true).then(()=>this.calRestoreFocus(true));return}
262
257
  if(next===null)return;event.preventDefault();next=this.calClampDay(next);if(next<range.firstDay||next>range.lastDay){this.calGo(next,"year",next).then(()=>this.calRestoreFocus(true));return}
263
- this.calFocus={day:next,minutes:null,event:null};this.calRestoreFocus(true)}});Object.assign(DataGrid.prototype,{calPaint(options={}){if(!this.calBody||this.destroyed)return;this.calDisposeEventRenderers();const independent=document.activeElement?.closest(".cx-cal-rpick");const resourceControl=independent&&this.calBody.contains(independent)?document.activeElement.classList.contains("cx-cal-rpick-prev")?".cx-cal-rpick-prev":document.activeElement.classList.contains("cx-cal-rpick-next")?".cx-cal-rpick-next":".cx-cal-rpick-select":null;const owned=this.calBody.contains(document.activeElement)&&!this.calMore&&!independent;this.calCloseMore(false);this.calHideHover();const scroll=options.keep?this.calScrollState?.():null;const view=this.calView;this.host.setAttribute("data-cx-calendar-view",view);if(view==="month")this.calPaintMonth();else if(view==="mini")this.calPaintMini();else if(view==="months")this.calPaintMonths();else if(view==="weekList"||view==="dayList")this.calPaintList();else if(view==="week"||view==="day"||view==="days")this.calPaintTime();else if(view==="agenda")this.calPaintAgenda();else if(view==="year")this.calPaintYear();else this.calPaintTimeline(options);const restored=scroll&&!options.resize&&this.calRestoreScroll(scroll);if(!restored&&view==="agenda")this.calScrollAgenda();this.calMarkSelection();this.calRestoreFocus(owned);if(resourceControl){const target=this.calBody.querySelector(resourceControl);(target?.disabled?this.calBody.querySelector(".cx-cal-rpick-select"):target)?.focus({preventScroll:true})}},calEventTarget(id,preferred){const anchor=preferred?.closest?.(".cx-cal-ev");if(anchor?.dataset.cxEvent===id&&this.calBody.contains(anchor))return anchor;const elements=[...this.calBody.querySelectorAll('[data-cx-event="'+CSS.escape(id)+ '"]')],focus=this.calFocus;const assignments=focus?.event===id&&focus.resource!=null?elements.filter(element=>element._calEvent?.resource===focus.resource):elements;return assignments.find(element=>Number(element.closest("[data-cx-day]")?.dataset.cxDay)===focus?.day)||assignments[0]||elements[0]||null},calFocusTarget(){const focus=this.calFocus,body=this.calBody;if(focus?.event){const element=this.calEventTarget(focus.event);if(element)return element}
258
+ this.calFocus={day:next,minutes:null,event:null};this.calRestoreFocus(true)}});Object.assign(DataGrid.prototype,{calPaint(options={}){if(!this.calBody||this.destroyed)return;this.calDisposeEventRenderers();const independent=document.activeElement?.closest(".cx-cal-rpick");const resourceControl=independent&&this.calBody.contains(independent)?document.activeElement.classList.contains("cx-cal-rpick-prev")?".cx-cal-rpick-prev":document.activeElement.classList.contains("cx-cal-rpick-next")?".cx-cal-rpick-next":".cx-cal-rpick-select":null;const owned=(this.calBody.contains(document.activeElement)&&!this.calMore&&!independent)||!!this.calMenu?.contains(document.activeElement);this.calMenuBinding?.close("render",false,true);this.calCloseMore(false);this.calHideHover();const scroll=options.keep?this.calScrollState?.():null;const view=this.calView;this.host.setAttribute("data-cx-calendar-view",view);if(view==="month")this.calPaintMonth();else if(view==="mini")this.calPaintMini();else if(view==="months")this.calPaintMonths();else if(view==="weekList"||view==="dayList")this.calPaintList();else if(view==="week"||view==="day"||view==="days")this.calPaintTime();else if(view==="agenda")this.calPaintAgenda();else if(view==="year")this.calPaintYear();else this.calPaintTimeline(options);const restored=scroll&&!options.resize&&this.calRestoreScroll(scroll);if(!restored&&view==="agenda")this.calScrollAgenda();this.calMarkSelection();this.calRestoreFocus(owned);if(resourceControl){const target=this.calBody.querySelector(resourceControl);(target?.disabled?this.calBody.querySelector(".cx-cal-rpick-select"):target)?.focus({preventScroll:true})}},calEventTarget(id,preferred){const anchor=preferred?.closest?.(".cx-cal-ev");if(anchor?.dataset.cxEvent===id&&this.calBody.contains(anchor))return anchor;const elements=[...this.calBody.querySelectorAll('[data-cx-event="'+CSS.escape(id)+ '"]')],focus=this.calFocus;const assignments=focus?.event===id&&focus.resource!=null?elements.filter(element=>element._calEvent?.resource===focus.resource):elements;return assignments.find(element=>Number(element.closest("[data-cx-day]")?.dataset.cxDay)===focus?.day)||assignments[0]||elements[0]||null},calFocusTarget(){const focus=this.calFocus,body=this.calBody;if(focus?.event){const element=this.calEventTarget(focus.event);if(element)return element}
264
259
  if(focus?.unit!=null&&focus.resource!=null){const element=body.querySelector('.cx-tl-cell[data-cx-unit="'+focus.unit+'"][data-cx-resource="'+CSS.escape(focus.resource)+ '"]');if(element)return element}
265
260
  if(focus?.resource!=null&&this.calView==="timeline"&&this.tlAxis){const unit=this.tlAxis.units.findIndex(item=>item.first<=focus.day&&focus.day<=item.last);const element=body.querySelector('.cx-tl-cell[data-cx-unit="'+Math.max(0,unit)+ '"][data-cx-resource="'+CSS.escape(focus.resource)+ '"]');if(element)return element}
266
261
  if(focus?.agendaRow){const element=body.querySelector('[data-cx-event-row="'+CSS.escape(focus.agendaRow)+ '"]');if(element)return element}
@@ -268,7 +263,7 @@ const resource=focus?.resource!=null?'[data-cx-resource="'+CSS.escape(focus.reso
268
263
  if(focus&&focus.minutes==null){const cell=body.querySelector('.cx-cal-allcell[data-cx-day="'+focus.day+'"]'+resource);if(cell)return cell}
269
264
  if(focus){const day=body.querySelector('.cx-cal-day[data-cx-day="'+focus.day+'"],.cx-cal-yday[data-cx-day="'+focus.day+'"],[data-cx-day="'+focus.day+'"][data-cx-minutes],.cx-cal-arow[data-cx-day="'+focus.day+'"]');if(day)return day}
270
265
  return body.querySelector('.cx-cal-day:not(.cx-cal-out):not(.cx-cal-invalid),.cx-cal-yday:not(.cx-cal-invalid),[data-cx-minutes]:not(.cx-cal-invalid),.cx-cal-arow,.cx-tl-cell:not(.cx-cal-invalid)')||null},calRestoreFocus(force){const target=this.calFocusTarget();for(const element of this.calBody.querySelectorAll('[tabindex="0"]'))if(element!==target&&!element.closest(".cx-cal-ylist,.cx-cal-rpick"))element.tabIndex=-1;if(!target)return;target.tabIndex=0;if(force)target.focus({preventScroll:false})},calFocusIn(event){const element=event.target,eventElement=element.closest(".cx-cal-ev"),cell=element.closest("[data-cx-day]");if(!eventElement&&!cell||element.closest(".cx-cal-ylist"))return;if(eventElement?._calEvent)this.calFocus={day:cell?Number(cell.dataset.cxDay):eventElement._calEvent.sd,minutes:null,event:eventElement._calEvent.id,resource:eventElement._calEvent.resource};else if(cell)this.calFocus={day:Number(cell.dataset.cxDay),minutes:cell.dataset.cxMinutes!==undefined?Number(cell.dataset.cxMinutes):null,event:null,resource:cell.dataset.cxResource,agendaRow:cell.dataset.cxEventRow,unit:cell.dataset.cxUnit!==undefined?Number(cell.dataset.cxUnit):null};for(const other of this.calBody.querySelectorAll('[tabindex="0"]'))if(other!==element&&!other.closest(".cx-cal-ylist,.cx-cal-rpick"))other.tabIndex=-1;if(element.tabIndex<0&&(eventElement||cell))element.tabIndex=0},calKey(event){if(event.defaultPrevented||event.altKey&&!this.calMoving)return;if(this.calRtl&&(event.key==="ArrowLeft"||event.key==="ArrowRight")){const real=event,key=event.key==="ArrowLeft"?"ArrowRight":"ArrowLeft";event=new Proxy(real,{get:(target,name)=>name==="key"?key:typeof target[name]==="function"?target[name].bind(target):target[name]})}
271
- if(this.calEditKey?.(event)||this.calMenuKey(event))return;const target=event.target,eventElement=target.closest(".cx-cal-ev"),more=target.closest(".cx-cal-more-btn");if((event.ctrlKey||event.metaKey)&&(event.key==="z"||event.key==="y"||event.key==="Z")){if(!this.cal.editable)return;event.preventDefault();const done=event.key==="y"||event.shiftKey?this.redo():this.undo();if(done===true&&this.cal.editable.commit==="auto"&&this.hasChanges())this.calCommit(this.getChanges().map(change=>change.id),"");return}
266
+ if(this.calEditKey?.(event))return;const target=event.target,eventElement=target.closest(".cx-cal-ev"),more=target.closest(".cx-cal-more-btn");if((event.ctrlKey||event.metaKey)&&(event.key==="z"||event.key==="y"||event.key==="Z")){if(!this.cal.editable)return;event.preventDefault();const done=event.key==="y"||event.shiftKey?this.redo():this.undo();if(done===true&&this.cal.editable.commit==="auto"&&this.hasChanges())this.calCommit(this.getChanges().map(change=>change.id),"");return}
272
267
  if(eventElement&&(event.key==="Enter"||event.key===" ")){event.preventDefault();this.calOpenEvent(eventElement._calEvent,true,eventElement).catch(error=>this.emit("error",{error}));return}
273
268
  if(more&&(event.key==="Enter"||event.key===" ")){event.preventDefault();this.calOpenMore(Number(more.dataset.cxDay),this.calEventsOn(Number(more.dataset.cxDay)),more);return}
274
269
  const view=this.calView,dayCell=!eventElement&&!more&&target.closest("[data-cx-day]");if(this.cal.drop&&dayCell&&this.calDropFromKey?.(event,dayCell))return;if(this.cal.create&&dayCell&&this.calCreateFromKey?.(event,dayCell))return;if(calDayGrid(view)&&(eventElement||more)&&this.calKeyInDay(event,eventElement||more))return;if(calDayGrid(view)){const cell=target.closest(".cx-cal-day");if(cell)this.calKeyMonth(event,cell);return}
@@ -284,7 +279,7 @@ const cell=target.closest("[data-cx-day]");if(!cell)return;const day=Number(cell
284
279
  if(cell.dataset.cxMinutes!==undefined){const minutes=Number(cell.dataset.cxMinutes);this.calSelectSlots(day,minutes,minutes+this.cal.slotMinutes,cell.dataset.cxResource)}
285
280
  else this.calSelectDays(day,day,this.calCellResource(cell));if(this.calPhone&&this.calView==="month"||this.calView==="mini")this.calFocusDay(day);else if(this.cal.create&&!cell.classList.contains("cx-cal-invalid"))this.calCreateFromClick?.(cell)?.catch?.(error=>this.emit("error",{error}))},calCellResource(cell){return this.tlSolo&&cell.classList.contains("cx-tl-cell")?null:cell.dataset.cxResource??null},calSelectDays(first,last,resource){const zone=this.calZone;if(!this.calAllowsSpan(first*CAL_DAY,(last+1)*CAL_DAY,true))return false;this.calSelection={first,last,from:zone.start(first),to:zone.start(last+1),resource:resource??null};this.calReportSelection(this.calFmt.dayRange(first,last))},calSelectSlots(day,fromMinutes,toMinutes,resource){const zone=this.calZone,from=zone.instant(day,fromMinutes),to=zone.instant(day,toMinutes);if(!this.calAllowsSpan(from,to,false))return false;this.calSelection={first:day,last:day,from,to,fromMinutes,toMinutes,resource:resource??null};this.calReportSelection(this.calFmt.longDay(day)+ " "+fill(this.calLabels.calendarTimeRange,{start:this.calFmt.time(from),end:this.calFmt.time(to)}))},calReportSelection(label){const selection=this.calSelection,events=this.calEvents.filter(event=>{const span=this.calDisplaySpan(event);return!event.background&&calOverlaps(span.start,span.end,selection.from,selection.to)&&(selection.resource==null||this.calHasResource(event,selection.resource))});this.calMarkSelection();this.calAnnounce(fill(this.calLabels.calendarSelected,{range:label}));this.calEmitLink("select",events,label,selection)},calMarkSelection(){const selection=this.calSelection;for(const cell of this.calBody.querySelectorAll('[aria-selected="true"]'))cell.setAttribute("aria-selected","false");if(!selection)return;for(const cell of this.calBody.querySelectorAll("[data-cx-day]")){const day=Number(cell.dataset.cxDay),minutes=cell.dataset.cxMinutes;const inside=day>=selection.first&&day<=selection.last&&(minutes===undefined||selection.fromMinutes===undefined||+minutes>=selection.fromMinutes&&+minutes<selection.toMinutes)&&
286
281
  (selection.resource==null||cell.dataset.cxResource===undefined||cell.dataset.cxResource===selection.resource);if(inside)cell.setAttribute("aria-selected","true")}},clearCalendarSelection(){if(!this.calSelection)return;this.calSelection=null;this.calMarkSelection();this.calEmitLink("clear",[],"",null)},calEmitLink(action,events,label,selection){if(this.opts.linkEvents!==true&&!this.linkWatching)return;const keys=[...new Set(events.filter(event=>!event.base?.external).map(event=>event.key))].slice(0,10000),values=Object.create(null);if(selection?.resource!=null&&this.cal.resource)values[this.cal.resource.id]=[selection.resource];this.emit("linkchange",{view:this.view.id,action,scope:"select",keys,values,label,range:selection?{column:this.cal.start.id,from:calIso(selection.from),to:calIso(selection.to)}:null})}});const CAL_CACHE=12,CAL_FALLBACK_PAGES=10;Object.assign(DataGrid.prototype,{async calRecords(from,to,signal){const query=this.acceptedQuery||gridQuery(this.view,this.view.query||{});if(this.view.source.kind==="inline"&&!this.opts.source){if(this.view.rowData){if(!this.source.decoded)await this.source.query({...query,offset:0,limit:1},{signal});await this.source.decoded}
287
- const rows=this.view.rows,key=gridResultShape(query);if(this.calRowsCache?.rows!==rows||this.calRowsCache.key!==key||this.calRowsCache.source!==this.source||this.calRowsCache.shape!==rows.length+":"+this.calVersion){const plain=!query.search&&!query.filters.length&&!query.filterGroup;this.calRowsCache={rows,key,source:this.source,shape:rows.length+":"+this.calVersion,matched:plain?rows:gridQueryRows(this.view,query,new Map(this.view.columns.map(column=>[column.id,column])),null)}}
282
+ const rows=this.view.rows,key=gridResultShape(query);if(this.calRowsCache?.rows!==rows||this.calRowsCache.key!==key||this.calRowsCache.source!==this.source||this.calRowsCache.shape!==rows.length+":"+this.calVersion){const plain=!query.search&&!query.filters.length&&!query.filterGroup&&!query.tupleFilters?.length;this.calRowsCache={rows,key,source:this.source,shape:rows.length+":"+this.calVersion,matched:plain?rows:gridQueryRows(this.view,query,new Map(this.view.columns.map(column=>[column.id,column])),null)}}
288
283
  const matched=this.calEdited(this.calRowsCache.matched);return{rows:matched,overrides:this.calInlineOverrides(matched,from,to),truncated:false}}
289
284
  if(this.cal.allDay){from -=CAL_DAY;to +=CAL_DAY}
290
285
  if(this.calResourcesReady)await this.calResourcesReady();const resources=this.calResourceWindow?.()||null,key=JSON.stringify([gridResultShape(query),query.revision,this.calVersion,from,to,resources]);this.calWindowKey=JSON.stringify(resources);const cache=this.calCache||=new Map();if(cache.has(key)){const hit=cache.get(key);cache.delete(key);cache.set(key,hit);return{...hit,rows:this.calEdited(hit.rows,true)}}
@@ -293,7 +288,7 @@ catch(error){if(error?.code!=="unsupported")throw error;this.calNoRange=true}}
293
288
  answer||=await this.calFallbackRequest(query,from,to,resources,signal);answer=await this.calHostedOverrides(answer,from,to,signal);cache.set(key,answer);while(cache.size>CAL_CACHE)cache.delete(cache.keys().next().value);return{...answer,rows:this.calEdited(answer.rows,true)}},calEdited(rows,hosted){const changes=this.edit?.changes;if(!changes?.size)return rows;const out=rows.map(row=>changes.get(row.id)?.row||row);if(hosted&&this.edit.inserted?.size){const ids=new Set(rows.map(row=>row.id));for(const[id,row]of this.edit.inserted)if(!ids.has(id))out.push(changes.get(id)?.row??row)}
294
289
  return out},calRangeRequest(query,from,to,resources,signal){const cal=this.cal,request={protocol:PROTOCOL,type:"gridRangeQuery",view:this.view.id,query:{...query,offset:0,limit:Math.min(10000,cal.limit)},from:calIso(from),to:calIso(to),start:cal.start.id,calendarView:this.calView,limit:Math.min(10000,cal.limit)};for(const name of["end","recurrence","seriesEnd","resource"])if(cal[name])request[name]=cal[name].id;if(resources&&cal.resource)request.resources=resources;return this.runGridHook(hook=>this.source.range(gridFreeze(request),{signal:hook}),signal).then(page=>{checkDocument(page,"gridRangePage");if(page.view!==this.view.id||typeof page.revision!=="string"||!page.revision||!Array.isArray(page.items)||!validStructuralCount(page.matched)||page.items.length>request.limit||page.items.length>page.matched||
295
290
  typeof page.truncated!=="boolean"||page.truncated!==page.items.length<page.matched)
296
- throw new Error("CanopyX: the range page does not answer its query.");if(query.revision!==undefined&&page.revision!==query.revision)throw new Error("CanopyX: grid page snapshot changed.");validateGridRows(page.items,this.view.columns);return{rows:page.items,truncated:page.truncated,matched:page.matched,revision:page.revision}})},async calFallbackRequest(query,from,to,resources,signal){const cal=this.cal,iso=value=>calIso(value),groups=[];const plain={operator:"or",filters:[{column:cal.start.id,operator:"ge",values:[iso(from)]}],groups:[]};if(cal.end)plain.filters.push({column:cal.end.id,operator:"gt",values:[iso(from)]});if(cal.recurrence){const series={operator:"and",filters:[{column:cal.recurrence.id,operator:"isNotNull",values:[]},{column:cal.recurrence.id,operator:"ne",values:[""]}],groups:[]};if(cal.seriesEnd)series.groups.push({operator:"or",filters:[{column:cal.seriesEnd.id,operator:"isNull",values:[]},{column:cal.seriesEnd.id,operator:"gt",values:[iso(from)]}],groups:[]});plain.groups.push(series)}
291
+ throw new Error("CanopyX: the range page does not answer its query.");if(query.revision!==undefined&&page.revision!==query.revision)throw new Error("CanopyX: grid page snapshot changed.");return{rows:validateGridRows(page.items,this.view.columns,undefined,repairGridCell),truncated:page.truncated,matched:page.matched,revision:page.revision}})},async calFallbackRequest(query,from,to,resources,signal){const cal=this.cal,iso=value=>calIso(value),groups=[];const plain={operator:"or",filters:[{column:cal.start.id,operator:"ge",values:[iso(from)]}],groups:[]};if(cal.end)plain.filters.push({column:cal.end.id,operator:"gt",values:[iso(from)]});if(cal.recurrence){const series={operator:"and",filters:[{column:cal.recurrence.id,operator:"isNotNull",values:[]},{column:cal.recurrence.id,operator:"ne",values:[""]}],groups:[]};if(cal.seriesEnd)series.groups.push({operator:"or",filters:[{column:cal.seriesEnd.id,operator:"isNull",values:[]},{column:cal.seriesEnd.id,operator:"gt",values:[iso(from)]}],groups:[]});plain.groups.push(series)}
297
292
  groups.push(plain);if(query.filterGroup)groups.push(query.filterGroup);const filters=[{column:cal.start.id,operator:"lt",values:[iso(to)]}];if(resources&&cal.resource)filters.push({column:cal.resource.id,operator:"in",values:resources});const input={...query,cursor:undefined,offset:undefined,sort:cal.start.sortable?[{column:cal.start.id,direction:"asc"}]:[],filterGroup:{operator:"and",filters,groups}};return this.calQueryPages(input,signal,{pages:CAL_FALLBACK_PAGES,rows:cal.limit})},async calReload(options={}){if(this.destroyed||!this.calBody)return;const epoch=++this.calEpoch,range=this.calRange=this.calRangeOf(this.calView,this.calDate);this.calAnswer=null;this.calSyncBar(!!options.announce);const from=this.calZone.start(range.firstDay),to=this.calZone.start(range.lastDay+1);const lifetime=this.calLifetime=new AbortController(),signal=AbortSignal.any?AbortSignal.any([lifetime.signal,this.dataLifetime.signal]):lifetime.signal;this.calPrevLifetime?.abort();this.calPrevLifetime=lifetime;let answer;const slow=setTimeout(()=>{if(epoch===this.calEpoch)this.calNotice(this.calLabels.calendarLoading,false)},200);if(this.cal.sources.some(source=>source.ics)&&!this.calIcsLoad)this.calIcsLoad=this.calLoadPart("calendar-ics").then(()=>this.calLoadIcs()).catch(error=>{this.calIcsLoad=null;throw error});let feeds;try{[answer,feeds]=await Promise.all([this.calRecords(from,to,signal),this.calLoadJson(from,to,signal)]);if(this.calIcsLoad)await this.calIcsLoad}
298
293
  catch(error){clearTimeout(slow);if(epoch!==this.calEpoch||error.name==="AbortError"||this.destroyed)return;this.calNotice(fill(this.calLabels.calendarLoadError,{error:error.message}),true);this.emit("error",{error});return}
299
294
  clearTimeout(slow);if(epoch!==this.calEpoch||signal.aborted||this.destroyed)return;const rows=[...answer.rows,...(this.calIcsRows||[]),...feeds.rows];this.calAnswer={rows,query:this.acceptedQuery,source:this.source,signal,epoch};const events=calOccurrences(this,rows,from,to,answer.overrides);this.calAllEvents=events;this.calEvents=this.calShownEvents(events);this.calRanges=calStaticRanges(this,from,to);const sticky=this.calSticky?.at===this.calStickyKey()?this.calSticky.text:"";const truncated=answer.truncated||events.truncated?fill(this.calLabels.calendarTruncated,{count:numberFormat(this.lang).format(events.length)}):"";const imported=[...(this.calIcsErrors||[]),...feeds.errors].join(" ");setText(this.calNoticeElement,[sticky,truncated,imported].filter(Boolean).join(" "));this.calNoticeElement.hidden=!sticky&&!truncated&&!imported;this.calNoticeElement.classList.toggle("cx-cal-error",!!sticky||!!imported);this.calPaint(options);this.host.setAttribute("data-cx-calendar-ready","true");this.emit("calendar",this.calSnapshot())},calNotice(text,error,sticky){this.calSticky=sticky&&text?{text,at:this.calStickyKey()}:text?this.calSticky:null;setText(this.calNoticeElement,text);this.calNoticeElement.hidden=!text;this.calNoticeElement.classList.toggle("cx-cal-error",!!error)},calStickyKey(){return[this.calView,this.calRange?.firstDay,this.calRange?.lastDay,this.calZoom].join("|")}});Object.assign(DataGrid.prototype,{async calQueryPages(query,signal,budget){const rows=[],ids=new Set(),tokens=new Set(),cursor=this.cursor;let next,revision=query.revision,snapshot=null,matched=0,complete=false;while(budget.pages>0&&budget.rows>0){let input=gridQuery(this.view,{...query,limit:Math.min(10000,this.pageSize,budget.rows),revision,offset:cursor?undefined:rows.length,cursor:cursor?next:undefined});if(input.groupBy?.length)input=gridQuery(this.view,{...input,groupBy:[],sort:query.sort||[]});const raw=await this.runGridHook(hook=>this.source.query(input,{signal:hook}),signal);const page=cursor?validateGridCursorPage(raw,this.view,input,snapshot):validateGridPage(raw,this.view,input,snapshot);if(page.offset!==rows.length)throw new Error("CanopyX: calendar pages do not form one result.");for(const row of page.items){if(ids.has(row.id))throw new Error("CanopyX: calendar pages repeat a record.");ids.add(row.id);rows.push(row)}
@@ -310,7 +305,7 @@ throw new Error("CanopyX: iCalendar export needs all mapped calendar columns; in
310
305
  host.setAttribute("data-cx-event-style",this.cal.eventStyle);const root=this.calRoot=h("div","cx-cal");root.setAttribute("role","region");root.setAttribute("aria-label",this.view.label);this.calNoticeElement=h("div","cx-cal-notice");this.calNoticeElement.hidden=true;this.calNoticeElement.setAttribute("role","status");this.calBody=h("div","cx-cal-body");this.calLive=h("div","cx-live cx-sr-only");this.calLive.setAttribute("aria-live","polite");root.append(...[this.calBuildBar(),this.calBuildLegend(),this.calNoticeElement,this.calBody,this.calLive].filter(Boolean));this.grid.before(root);this.calRtl=getComputedStyle(host).direction==="rtl";host.classList.toggle("cx-cal-rtl",this.calRtl);this.calPhone=host.clientWidth>0&&host.clientWidth<=640;if(this.calPhone&&!this.initialState?.calendar)this.calView=this.cal.phone||(this.cal.views.includes("agenda")?"agenda":this.calView);this.calBody.addEventListener("keydown",event=>this.calKey(event),{signal});this.calBody.addEventListener("click",event=>this.calClick(event),{signal});this.calBody.addEventListener("focusin",event=>this.calFocusIn(event),{signal});this.calBody.addEventListener("pointerover",event=>this.calHoverOver(event),{signal});this.calBody.addEventListener("pointerout",event=>this.calHoverOut(event),{signal});for(const type of["pointerdown","keydown","wheel"])this.calBody.addEventListener(type,()=>this.calHideHover(),{signal,passive:true});this.calMenuStart();host.addEventListener("canopyx:query",()=>{const shape=gridResultShape(this.acceptedQuery||{}),same=this.calQueryShape===shape;this.calQueryShape=shape;this.calCache?.clear();this.calJsonCache?.clear();this.calReload(same?{keep:true}:{})},{signal});host.addEventListener("canopyx:rowsChanged",()=>{this.calCache?.clear();this.calVersion++;this.calReload({keep:true})},{signal});host.addEventListener("canopyx:commit",()=>{this.calCache?.clear();this.calVersion++;this.calReload({keep:true})},{signal});host.addEventListener("canopyx:cellValueChanged",()=>{this.calVersion++;this.calReload({keep:true})},{signal});if(this.cal.editable||this.cal.create||this.cal.drop){host.setAttribute("data-cx-calendar-editable","true");this.calEditStart?.();this.calBody.addEventListener("pointerdown",event=>this.calDragStart(event),{signal});this.calBody.addEventListener("pointermove",event=>this.calDragMove(event),{signal});this.calBody.addEventListener("pointerup",event=>this.calDragEnd(event,false),{signal});this.calBody.addEventListener("pointercancel",event=>this.calDragEnd(event,true),{signal});this.calBody.addEventListener("lostpointercapture",event=>{if(this.calDrag?.id===event.pointerId&&!this.calDrag.started)this.calDrag=null},{signal})}
311
306
  let width=0,height=0,resizeFrame=0;const resize=()=>{resizeFrame=0;if(this.destroyed||!root.clientWidth)return;if(root.querySelector(":active")){resizeFrame=requestAnimationFrame(resize);return}
312
307
  this.updateGridPhone();const phone=host.clientWidth<=640,changed=phone!==this.calPhone||Math.abs(root.clientWidth-width)>1||Math.abs(this.calBody.clientHeight-height)>1;width=root.clientWidth;height=this.calBody.clientHeight;const switched=phone!==this.calPhone;if(switched){this.calPhone=phone;host.classList.toggle("cx-cal-phone",phone);this.calSyncBar(false)}
313
- if(!changed||!this.calRange)return;if(switched||this.calView==="month"||this.calTimeWindow)this.calPaint({keep:true,resize:true});else if(this.calView==="timeline")this.tlPaintLanes?.();else if(this.calScroller?.isConnected)this.calGrid.querySelector(".cx-cal-thead").style.paddingInlineEnd=Math.max(0,this.calScroller.offsetWidth-this.calScroller.clientWidth)+ "px"};const observer=new ResizeObserver(()=>{if(!resizeFrame)resizeFrame=requestAnimationFrame(resize)});observer.observe(root);host.classList.toggle("cx-cal-phone",this.calPhone);const timer=setInterval(()=>{if(!this.destroyed&&this.cal.now)this.calTick?.()},60000);const print=on=>{if(this.destroyed||!this.calRange)return;this.calPrinting=on;host.classList.toggle("cx-cal-printing",on);this.tlPrint?.(on);if(this.calView!=="timeline")this.calPaint({keep:true,resize:true})};global.addEventListener("beforeprint",()=>print(true),{signal});global.addEventListener("afterprint",()=>print(false),{signal});signal.addEventListener("abort",()=>{observer.disconnect();cancelAnimationFrame(resizeFrame);clearInterval(timer);clearTimeout(this.calAnnounceTimer);this.calPrevLifetime?.abort();this.calCancelGesture?.();this.calDragEnd?.(null,true);this.calStopMoving?.();if(this.calDropDrag)this.calDropClear?.();this.calDisposeEventRenderers();root.remove();host.classList.remove("cx-calendar","cx-cal-phone","cx-cal-bare","cx-cal-rtl",...CAL_TOOLBAR.map(item=>"cx-cal-no-"+item));this.calHideHover();this.calCloseDetails(false);this.calCloseMenu(false);this.calCloseCreate?.(false);this.calCloseAsk?.(null);this.calCloseOccurrence?.(false);clearTimeout(this.calPressTimer);host.removeAttribute("data-cx-event-style");host.removeAttribute("data-cx-calendar-ready")},{once:true});calWrapHighlight();const plugin={name:"calendar-export",exportFormats:[this.calExportFormat()]};this.plugins=[...this.plugins,plugin];this.opts={...this.opts,plugins:[...this.opts.plugins||[],plugin]};this.calRange=this.calRangeOf(this.calView,this.calDate);this.calSyncBar(false);if(this.cal.resources||this.calView==="timeline")return this.calLoadTimeline()},calRangeOf(view,date){const cal=this.cal;if(view==="month"||view==="mini"){const month=calMonthStart(date),end=calAddMonths(month,1)- 1,first=calWeekStart(month,cal.firstDay);return{firstDay:first,lastDay:view==="mini"||cal.fixedWeeks?first+41:calWeekStart(end,cal.firstDay)+ 6,month}}
308
+ if(!changed||!this.calRange)return;if(switched||this.calView==="month"||this.calTimeWindow||this.view.plan&&this.calView==="timeline"&&Math.abs((this.planFitWidth||0)-this.tlMain.clientWidth)>1)this.calPaint({keep:true,resize:true});else if(this.calView==="timeline")this.tlPaintLanes?.();else if(this.calScroller?.isConnected)this.calGrid.querySelector(".cx-cal-thead").style.paddingInlineEnd=Math.max(0,this.calScroller.offsetWidth-this.calScroller.clientWidth)+ "px"};const observer=new ResizeObserver(()=>{if(!resizeFrame)resizeFrame=requestAnimationFrame(resize)});observer.observe(root);host.classList.toggle("cx-cal-phone",this.calPhone);const timer=setInterval(()=>{if(!this.destroyed&&this.cal.now)this.calTick?.()},60000);const print=on=>{if(this.destroyed||!this.calRange)return;this.calPrinting=on;host.classList.toggle("cx-cal-printing",on);this.tlPrint?.(on);if(this.calView!=="timeline")this.calPaint({keep:true,resize:true})};global.addEventListener("beforeprint",()=>print(true),{signal});global.addEventListener("afterprint",()=>print(false),{signal});signal.addEventListener("abort",()=>{observer.disconnect();cancelAnimationFrame(resizeFrame);clearInterval(timer);clearTimeout(this.calAnnounceTimer);this.calPrevLifetime?.abort();this.calCancelGesture?.();this.calDragEnd?.(null,true);this.calStopMoving?.();if(this.calDropDrag)this.calDropClear?.();this.calDisposeEventRenderers();this.calMenuBinding?.();this.calMenuBinding=null;root.remove();host.classList.remove("cx-calendar","cx-cal-phone","cx-cal-bare","cx-cal-rtl",...CAL_TOOLBAR.map(item=>"cx-cal-no-"+item));this.calHideHover();this.calCloseDetails(false);this.calCloseCreate?.(false);this.calCloseAsk?.(null);this.calCloseOccurrence?.(false);host.removeAttribute("data-cx-event-style");host.removeAttribute("data-cx-calendar-ready")},{once:true});calWrapHighlight();const plugin={name:"calendar-export",exportFormats:[this.calExportFormat()]};this.plugins=[...this.plugins,plugin];this.opts={...this.opts,plugins:[...this.opts.plugins||[],plugin]};this.calRange=this.calRangeOf(this.calView,this.calDate);this.calSyncBar(false);if(this.cal.resources||this.calView==="timeline")return this.calLoadTimeline()},calRangeOf(view,date){const cal=this.cal;if(view==="month"||view==="mini"){const month=calMonthStart(date),end=calAddMonths(month,1)- 1,first=calWeekStart(month,cal.firstDay);return{firstDay:first,lastDay:view==="mini"||cal.fixedWeeks?first+41:calWeekStart(end,cal.firstDay)+ 6,month}}
314
309
  if(view==="months"){const month=calMonthStart(date);return{firstDay:month,lastDay:calAddMonths(month,cal.months)- 1,month}}
315
310
  if(view==="week"||view==="weekList"){const first=calWeekStart(date,cal.firstDay);return{firstDay:first,lastDay:first+6}}
316
311
  if(view==="day"||view==="dayList")return{firstDay:date,lastDay:date};if(view==="days"){let last=date;for(let shown=0;shown<this.calDaysCount();last++)if(!cal.hidden.has(calDow(last)))shown++;return{firstDay:date,lastDay:last-1}}
@@ -1,4 +1,4 @@
1
- (function(global){"use strict";const installed=new WeakSet();const part={version:"91e39c68baaf1d09",install(context){if(installed.has(context.DataGrid.prototype))return;const{DataGrid,h,setText,fill,columnWidth,foldText,gridButton,gridIcon,gridDecorateButton,cellText,cellValue,isCellObject,numberFormat,gridFreeze,gridMomentFromParts,requireIdentifier,loadGridFilterEditor,CELL_CONTROLS,reachable,gridExportField}=context;const CR_LIMIT=200000;const crBad=problem=>{throw new Error("CanopyX: "+problem+".")};function crOptions(grid){const declared=grid.opts.rangeSelection??grid.view.rangeSelection,clipboard=Object.assign({},grid.view.clipboard,grid.opts.clipboard);const object=declared!==null&&typeof declared==="object"&&!Array.isArray(declared),range=object?declared:{};const flag=value=>value===undefined||typeof value==="boolean";if(declared!==undefined&&typeof declared!=="boolean"&&!object||!flag(range.enabled)||!flag(range.multiple)||!flag(range.fillHandle)||
1
+ (function(global){"use strict";const installed=new WeakSet();const part={version:"53c37a658f4f7afb",requires:["ui-menu"],install(context){if(installed.has(context.DataGrid.prototype))return;const{toneVariable,bindContextMenu,DataGrid,h,setText,fill,columnWidth,foldText,gridButton,gridIcon,gridDecorateButton,cellText,cellValue,isCellObject,numberFormat,gridFreeze,gridMomentFromParts,requireIdentifier,loadGridFilterEditor,CELL_CONTROLS,reachable,gridExportField}=context;const CR_LIMIT=200000;const crBad=problem=>{throw new Error("CanopyX: "+problem+".")};function crOptions(grid){const declared=grid.opts.rangeSelection??grid.view.rangeSelection,clipboard=Object.assign({},grid.view.clipboard,grid.opts.clipboard);const object=declared!==null&&typeof declared==="object"&&!Array.isArray(declared),range=object?declared:{};const flag=value=>value===undefined||typeof value==="boolean";if(declared!==undefined&&typeof declared!=="boolean"&&!object||!flag(range.enabled)||!flag(range.multiple)||!flag(range.fillHandle)||
2
2
  !flag(clipboard.copyHeaders)||!flag(clipboard.paste)||clipboard.copyValues!==undefined&&!["display","raw"].includes(clipboard.copyValues))
3
3
  crBad("rangeSelection takes true or { enabled, multiple, fillHandle }, and clipboard { copyHeaders, copyValues, paste }");return Object.freeze({enabled:declared===true||object&&range.enabled!==false,multiple:range.multiple!==false,fillHandle:!!range.fillHandle,headers:!!clipboard.copyHeaders,values:clipboard.copyValues||"display",paste:clipboard.paste!==false})}
4
4
  const crRows=grid=>grid.rowProjection||grid;function crBounds(grid){if(grid.rowProjection)return{first:0,last:grid.rowProjection.rowCount()- 1};const bounds=grid.rowBounds();return{first:Math.max(0,bounds.first),last:bounds.last}}
@@ -23,13 +23,14 @@ const index=grid.cols.findIndex(item=>item.id===column),cell=index>=0&&grid.head
23
23
  const CR_CONTROLS="a[href],button,input,select,textarea,summary,label,[contenteditable]:not([contenteditable=false]),[role=button],[role=checkbox],.cx-hidden-fields";function crHitAt(grid,x,y){const frame=grid.grid.getBoundingClientRect(),top=frame.top+grid.head.offsetHeight,left=frame.left+grid.grid.clientLeft;const px=Math.max(left+1,Math.min(x,left+grid.grid.clientWidth-2)),py=Math.max(top+1,Math.min(y,frame.top+grid.grid.clientHeight-2));for(const element of document.elementsFromPoint(px,py)){if(element.classList.contains("cx-range-handle")||element.classList.contains("cx-fill-handle"))continue;const hit=crHit(grid,element);if(hit)return hit;if(element===grid.grid)break}
24
24
  return null}
25
25
  function crTrack(grid,event,update,done){const pointer=event.pointerId,x0=event.clientX,y0=event.clientY;let x=x0,y=y0,frame=0,last=null,moved=false;const step=()=>{frame=requestAnimationFrame(step);if(!moved)return;const box=grid.grid.getBoundingClientRect(),top=box.top+grid.head.offsetHeight;const dy=y<top+24?-Math.ceil((top+24-y)/ 2) : y > box.bottom - 24 ? Math.ceil((y - box.bottom + 24) / 2) : 0;
26
- const dx=x<box.left+24?-12:x>box.right-24?12:0;if(dy)grid.setLogicalTop(Math.max(0,grid.logicalTop()+ Math.min(40,Math.max(-40,dy))));if(dx)grid.grid.scrollLeft +=dx;if(dx||dy){grid.render();look()}};const look=()=>{const hit=crHitAt(grid,x,y);if(hit&&(!last||hit.row!==last.row||hit.column!==last.column)){last=hit;update(hit)}};const move=ev=>{if(ev.pointerId!==pointer)return;x=ev.clientX;y=ev.clientY;if(!moved&&Math.hypot(x-x0,y-y0)<4)return;moved=true;look()};const stop=ev=>{if(ev&&ev.pointerId!==undefined&&ev.pointerId!==pointer)return;cancelAnimationFrame(frame);global.removeEventListener("pointermove",move);global.removeEventListener("pointerup",stop);global.removeEventListener("pointercancel",stop);grid.lifetime.signal.removeEventListener("abort",stop);if(grid.cellDrag===stop)grid.cellDrag=null;done(ev?.type==="pointerup")};grid.cellDrag?.();grid.cellDrag=stop;global.addEventListener("pointermove",move);global.addEventListener("pointerup",stop);global.addEventListener("pointercancel",stop);grid.lifetime.signal.addEventListener("abort",stop,{once:true});frame=requestAnimationFrame(step)}
26
+ const dx=x<box.left+24?-12:x>box.right-24?12:0;if(dy)grid.setLogicalTop(Math.max(0,grid.logicalTop()+ Math.min(40,Math.max(-40,dy))));if(dx)grid.grid.scrollLeft +=dx;if(dx||dy){grid.render();look()}};const look=()=>{const hit=crHitAt(grid,x,y);if(hit&&(!last||hit.row!==last.row||hit.column!==last.column)){last=hit;update(hit)}};const move=ev=>{if(ev.pointerId!==pointer)return;x=ev.clientX;y=ev.clientY;if(!moved&&Math.hypot(x-x0,y-y0)<4)return;moved=true;look()};const stop=ev=>{if(ev&&ev.pointerId!==undefined&&ev.pointerId!==pointer)return;cancelAnimationFrame(frame);global.removeEventListener("pointermove",move);global.removeEventListener("pointerup",stop);global.removeEventListener("pointercancel",stop);grid.lifetime.signal.removeEventListener("abort",stop);if(grid.cellDrag===stop)grid.cellDrag=null;done(ev?.type==="pointerup",ev)};grid.cellDrag?.();grid.cellDrag=stop;global.addEventListener("pointermove",move);global.addEventListener("pointerup",stop);global.addEventListener("pointercancel",stop);grid.lifetime.signal.addEventListener("abort",stop,{once:true});frame=requestAnimationFrame(step)}
27
27
  function crSwallowClick(grid){const swallow=event=>{event.preventDefault();event.stopPropagation()};grid.grid.addEventListener("click",swallow,{capture:true,once:true});setTimeout(()=>grid.grid.removeEventListener("click",swallow,{capture:true}),400)}
28
28
  function crPointerDown(grid,event){if(!grid.cellOptions.enabled||event.target.closest(".cx-range-handle,.cx-fill-handle"))return;if(event.pointerType==="touch"){crTouchStart(grid,event);return}
29
29
  const hit=crHit(grid,event.target);if(event.button!==0||!hit||event.target.closest(CR_CONTROLS))return;event.preventDefault();grid.cellHandles=false;const additive=(event.ctrlKey||event.metaKey)&&grid.cellOptions.multiple,at={row:hit.row,column:hit.column};const before=JSON.stringify(grid.cellRanges);let range;if(event.shiftKey&&grid.cellAnchor){range={anchor:grid.cellAnchor,end:at};grid.cellRanges=additive?[...grid.cellRanges.slice(0,-1),range]:[range]}else{grid.cellAnchor=at;range={anchor:at,end:at};grid.cellRanges=additive?[...grid.cellRanges,range]:[];if(additive)grid.cellRanges=grid.cellRanges.slice(0,1000)}
30
30
  crPaint(grid);let dragged=false;crTrack(grid,event,next=>{if(next.row===range.anchor.row&&next.column===range.anchor.column&&!grid.cellRanges.includes(range))return;range.end={row:next.row,column:next.column};dragged=true;if(!grid.cellRanges.includes(range))grid.cellRanges=[...grid.cellRanges,range];crPaint(grid)},()=>{if(dragged||event.shiftKey||event.ctrlKey||event.metaKey)crSwallowClick(grid);if(JSON.stringify(grid.cellRanges)!==before||event.shiftKey||additive)crChanged(grid);grid.cellFocusAfterClick=!dragged&&!event.shiftKey&&!additive?hit:null;if(dragged||event.shiftKey||additive)crFocus(grid,grid.cellAnchor)})}
31
31
  function crFocus(grid,at){if(!at)return;const row=crRows(grid).rowItem(at.row),index=grid.cols.findIndex(column=>column.id===at.column);if(row&&!row.status&&index>=0&&grid.rendered.get(row))grid.focusCell(row,index,null)}
32
- const CR_PRESS_MS=500;function crTouchStart(grid,event){const hit=crHit(grid,event.target);if(!hit||event.target.closest(CR_CONTROLS))return;const pointer=event.pointerId,x0=event.clientX,y0=event.clientY;crGuard(grid,true);const quit=pressed=>{clearTimeout(timer);grid.lifetime.signal.removeEventListener("abort",quit);global.removeEventListener("pointermove",watch);global.removeEventListener("pointerup",lift);global.removeEventListener("pointercancel",quit);if(pressed!==true)crGuard(grid,false)};const watch=ev=>{if(ev.pointerId===pointer&&Math.hypot(ev.clientX-x0,ev.clientY-y0)>8)quit()};const lift=ev=>{if(ev.pointerId!==pointer)return;quit();if(grid.cellRanges.length){grid.cellRanges=[];grid.cellHandles=false;crChanged(grid)}};const timer=setTimeout(()=>{quit(true);if(grid.destroyed)return;const inside=crRects(grid).some(rect=>hit.row>=rect.top&&hit.row<=rect.bottom&&crIndex(grid,hit.column)>=rect.left&&crIndex(grid,hit.column)<=rect.right);crSwallowClick(grid);if(inside){crGuard(grid,false);crMenu(grid,hit.cell);return}
32
+ const CR_PRESS_MS=500;function crTouchStart(grid,event){const hit=crHit(grid,event.target);if(!hit||event.target.closest(CR_CONTROLS))return;const pointer=event.pointerId,x0=event.clientX,y0=event.clientY,record=hit.element._w;crGuard(grid,true);const quit=pressed=>{clearTimeout(timer);grid.lifetime.signal.removeEventListener("abort",quit);global.removeEventListener("pointermove",watch);global.removeEventListener("pointerup",lift);global.removeEventListener("pointercancel",quit);if(pressed!==true)crGuard(grid,false)};const watch=ev=>{if(ev.pointerId===pointer&&Math.hypot(ev.clientX-x0,ev.clientY-y0)>8)quit()};const lift=ev=>{if(ev.pointerId!==pointer)return;quit();if(grid.cellRanges.length){grid.cellRanges=[];grid.cellHandles=false;crChanged(grid)}};const timer=setTimeout(()=>{quit(true);const live=crHit(grid,hit.cell);if(grid.destroyed||!live||live.row!==hit.row||live.column!==hit.column||live.element._w!==record){crGuard(grid,false);return}
33
+ const inside=crRects(grid).some(rect=>hit.row>=rect.top&&hit.row<=rect.bottom&&crIndex(grid,hit.column)>=rect.left&&crIndex(grid,hit.column)<=rect.right);crSwallowClick(grid);if(inside){crGuard(grid,false);crMenu(grid,hit.cell,event);return}
33
34
  const at={row:hit.row,column:hit.column},range={anchor:at,end:at};grid.cellAnchor=at;grid.cellRanges=[range];grid.cellHandles=true;crTouching(grid,true);crChanged(grid,false);crTrack(grid,event,next=>{range.end={row:next.row,column:next.column};crPaint(grid)},()=>{crTouching(grid,false);crChanged(grid)})},CR_PRESS_MS);grid.lifetime.signal.addEventListener("abort",quit,{once:true});global.addEventListener("pointermove",watch);global.addEventListener("pointerup",lift);global.addEventListener("pointercancel",quit)}
34
35
  function crTouching(grid,on){grid.cellTouching=on;if(!on)crGuard(grid,false)}
35
36
  function crGuard(grid,on){grid.cellTouchGuard||=event=>{if(grid.cellTouching)event.preventDefault()};if(on)grid.grid.addEventListener("touchmove",grid.cellTouchGuard,{passive:false});else grid.grid.removeEventListener("touchmove",grid.cellTouchGuard,{passive:false})}
@@ -38,7 +39,6 @@ const CR_STEPS={ArrowUp:[-1,0],ArrowDown:[1,0],ArrowLeft:[0,-1],ArrowRight:[0,1]
38
39
  if(command&&letter==="a"){consume();grid.selectAllCells();return}
39
40
  if(command&&letter==="d"&&grid.cellOptions.fillHandle&&grid.cellRanges.length===1){consume();crFillDown(grid).catch(error=>grid.emit("error",{error}));return}
40
41
  if(key==="Escape"&&grid.cellRanges.length){consume();grid.clearCellRanges();return}
41
- if((key==="ContextMenu"||key==="F10"&&event.shiftKey)&&hit){consume();crMenu(grid,hit.cell);return}
42
42
  if(!CR_STEPS[key])return;if(!event.shiftKey){if(grid.cellRanges.length&&!command){grid.cellRanges=[];grid.cellHandles=false;crChanged(grid)}return}
43
43
  if(!hit)return;consume();let range=grid.cellRanges[grid.cellRanges.length-1];if(!range||range.anchor.row!==hit.row||range.anchor.column!==hit.column){range={anchor:{row:hit.row,column:hit.column},end:{row:hit.row,column:hit.column}};grid.cellAnchor=range.anchor;grid.cellRanges=[range]}
44
44
  const bounds=crBounds(grid),[dRow,dColumn]=CR_STEPS[key],last=grid.cols.length-1;let row=range.end.row,column=Math.max(0,grid.cols.findIndex(item=>item.id===range.end.column));if(key==="PageUp"||key==="PageDown")row=crRows(grid)===grid?grid.gridPageStep({_ri:row,hpx:grid.rowH},dRow):row+dRow*Math.max(1,Math.floor(grid.viewportHeight / grid.rowH || 10));
@@ -46,7 +46,9 @@ else if(key==="Home"||key==="End"){column=dColumn<0?0:last;if(command)row=dColum
46
46
  else if(command){if(dRow)row=dRow<0?bounds.first:bounds.last;if(dColumn)column=dColumn<0?0:last}
47
47
  else{row +=dRow;column +=dColumn}
48
48
  range.end={row:Math.max(bounds.first,Math.min(bounds.last,row)),column:grid.cols[Math.max(0,Math.min(last,column))].id};crReveal(grid,range.end.row,range.end.column);crChanged(grid)}
49
- function crMenu(grid,cell){loadGridFilterEditor().then(()=>{if(grid.destroyed||!cell.isConnected)return;const labels=grid.labels,panel=grid.openGridPopover(cell,"cx-column-menu cx-cell-menu",labels.gridCellMenu),menu=h("div");grid.gridPopover.controller.signal.addEventListener("abort",()=>queueMicrotask(()=>{cell.removeAttribute("aria-controls");cell.removeAttribute("aria-expanded")}),{once:true});menu.setAttribute("role","menu");menu.setAttribute("aria-label",panel.getAttribute("aria-label"));panel.appendChild(menu);const add=(label,icon,action,disabled)=>{const button=gridButton(label,()=>{grid.closeGridPopover();Promise.resolve().then(action).catch(error=>grid.emit("error",{error}))});const mark=h("span","ico");if(icon)mark.appendChild(gridIcon(icon));button.prepend(mark);button.classList.add("cx-mi");button.setAttribute("role","menuitem");button.tabIndex=-1;button.disabled=!!disabled;menu.appendChild(button)};const copy=headers=>grid.copyCellRanges({headers});add(labels.gridCopyCells,"copy",()=>copy(false));add(labels.gridCopyCellsWithHeaders,null,()=>copy(true));if(grid.cellOptions.paste)add(labels.gridPasteCells,null,()=>global.navigator.clipboard.readText().then(text=>crPaste(grid,text,null,"clipboard")),typeof global.navigator.clipboard?.readText!=="function");menu.appendChild(h("hr","cx-menu-rule"));add(labels.gridSelectAllCells,null,()=>grid.selectAllCells());add(labels.gridClearCellRanges,"close",()=>grid.clearCellRanges(),!grid.cellRanges.length);const first=menu.querySelector('[role="menuitem"]:not(:disabled)');if(first){first.tabIndex=0;first.focus()}}).catch(error=>grid.emit("error",{error}))}
49
+ function crMenuItems(grid){const labels=grid.labels,items=[{id:"copy",label:labels.gridCopyCells,icon:"copy",run:()=>grid.copyCellRanges({headers:false})},{id:"copy-headers",label:labels.gridCopyCellsWithHeaders,run:()=>grid.copyCellRanges({headers:true})}];if(grid.cellOptions.paste)items.push({id:"paste",label:labels.gridPasteCells,disabled:typeof global.navigator.clipboard?.readText!=="function",run:()=>global.navigator.clipboard.readText().then(text=>crPaste(grid,text,null,"clipboard"))});items.push({id:"selection-separator",kind:"separator"},{id:"select-all",label:labels.gridSelectAllCells,run:()=>grid.selectAllCells()},{id:"clear",label:labels.gridClearCellRanges,icon:"close",disabled:!grid.cellRanges.length,run:()=>grid.clearCellRanges()});return items}
50
+ function crMenu(grid,cell,event){const hit=crHit(grid,cell);if(!hit||grid.destroyed)return;hit.record=hit.element._w;Promise.resolve(grid.cellMenuBinding.open(event,cell,{touch:true,hit}))
51
+ .catch(error=>{if(!grid.destroyed)grid.emit("error",{error})})}
50
52
  const crPad=value=>String(value).padStart(2,"0");function crDate(value,local){const date=new Date(value);if(!Number.isFinite(date.getTime()))return String(value);const part=name=>local?date["get"+name]():date["getUTC"+name]();return part("FullYear")+ "-"+crPad(part("Month")+ 1)+ "-"+crPad(part("Date"))+ " "+crPad(part("Hours"))+ ":"+crPad(part("Minutes"))+ ":"+crPad(part("Seconds"))}
51
53
  function crField(value,typed){return gridExportField(value,"\t",typed)}
52
54
  const crHtml=text=>String(text).replace(/[&<>"']/g, character => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]);
@@ -125,17 +127,17 @@ const remaining=cells.filter(cell=>!declined.has(cell));const applied=editing?aw
125
127
  async function crPaste(grid,text,origin,source){if(typeof text!=="string")crBad("pasteCells takes text");const matrix=crParse(text);if(!text)return gridFreeze({applied:0,refused:[],cancelled:false});const{cells,refused}=await crTargets(grid,matrix,origin);return crApply(grid,cells,refused,source)}
126
128
  function crReport(grid,applied,refused,source){const count=value=>numberFormat(grid.lang).format(value);const said=[fill(grid.labels[source==="fill"?"gridCellsFilled":"gridCellsPasted"],{count:count(applied)})];if(refused.length)said.push(fill(grid.labels.gridPasteRefused,{count:count(refused.length)}));setText(grid.live,said.join(". "));grid.pasteReport?.remove();grid.pasteReport=null;if(!refused.length)return;const panel=h("div","cx-paste-report"),summary=h("p"),details=h("details"),title=h("summary"),list=h("ul");panel.setAttribute("role","region");panel.setAttribute("aria-label",grid.labels.gridPasteReport);setText(summary,said.join(". "));setText(title,grid.labels.gridPasteReport);const identity=grid.columns.find(column=>column.rowHeader)||grid.cols[0],rows=crRows(grid);for(const cell of refused.slice(0,200)){const item=h("li"),row=rows.rowItem(cell.row),column=grid.columns.find(entry=>entry.id===cell.column);const name=row&&!row.status?cellText(row.h.cells[identity.id],identity,grid.fmt)||cell.id:String(cell.row+1);setText(item,fill(grid.labels.gridPasteCell,{row:name,column:column?column.title:cell.column,reason:cell.reason}));list.appendChild(item)}
127
129
  const close=gridDecorateButton(gridButton("",()=>{panel.remove();if(grid.pasteReport===panel)grid.pasteReport=null;grid.grid.focus({preventScroll:true})}),"close",true);close.classList.add("icon");close.setAttribute("aria-label",grid.labels.gridDone);details.append(title,list);panel.append(summary,close,details);grid.host.insertBefore(panel,grid.grid);grid.pasteReport=panel}
128
- function crSeries(values,count){const numbers=values.every(value=>typeof value==="number"),dates=!numbers&&values.every(value=>typeof value==="string"&&/^\d{4}-\d\d-\d\dT/.test(value) && Number.isFinite(Date.parse(value)));
129
- if(values.length>1&&(numbers||dates)){const points=values.map(value=>numbers?value:Date.parse(value)),step=points[1]- points[0];if(points.every((point,index)=>!index||Math.abs(point-points[index-1]- step)<1e-9)){const places=value=>{const[digits,power]=String(value).split("e");return Math.max(0,(digits.split(".")[1]||"").length-Number(power||0))};const decimals=numbers?Math.min(20,Math.max(...values.map(places))):0;return Array.from({length:count},(_,index)=>{const next=points[points.length-1]+ step*(index+1);return numbers?Number(next.toFixed(decimals)):new Date(next).toISOString()})}}
130
- return Array.from({length:count},(_,index)=>values[index%values.length])}
131
- async function crFill(grid,rect,top,bottom,sourceRows){const blocks=[{rows:Array.from({length:bottom-rect.top+1},(_,index)=>rect.top+index),left:rect.left,right:rect.right}];const loaded=await crLoad(grid,blocks),cells=[];const targets=blocks[0].rows.filter(position=>position>=top&&position<=bottom&&loaded.has(position));for(let index=rect.left;index<=rect.right;index++){const column=grid.cols[index],values=[];for(let position=rect.top;position<rect.top+sourceRows;position++){const row=loaded.get(position);if(row)values.push(cellValue(row.h.cells[column.id])??null)}
132
- if(!values.length)continue;const series=crSeries(values,targets.length);for(const[index,position]of targets.entries()){const row=loaded.get(position);const value=series[index],previous=cellValue(row.h.cells[column.id]);cells.push({id:row.key,column:column.id,row:position,text:value==null?"":cellText(value,column,grid.fmt),value,previous:previous??null})}}
130
+ function crSeries(values,count,copy=false){if(!values.length)return[];const repeat=()=>Array.from({length:count},(_,index)=>values[index%values.length]);if(copy)return repeat();const numbers=values.every(value=>typeof value==="number"&&Number.isFinite(value)),dates=!numbers&&values.every(value=>typeof value==="string"&&/^\d{4}-\d\d-\d\d(?:T|$)/.test(value) && Number.isFinite(Date.parse(value))),
131
+ items=!numbers&&!dates&&values.map(value=>typeof value==="string"&&/^(.*?)(\d+)$/.exec(value)),
132
+ numbered=items&&items.every(item=>item&&item[1]===items[0][1]&&Number.isSafeInteger(Number(item[2])));if(numbers||dates||numbered){const points=values.map((value,index)=>numbers?value:dates?Date.parse(value):Number(items[index][2])),step=points.length>1?points[1]- points[0]:dates?86400000:1;if(points.every((point,index)=>!index||Math.abs(point-points[index-1]- step)<1e-9)){const places=value=>{const[digits,power]=String(value).split("e");return Math.max(0,(digits.split(".")[1]||"").length-Number(power||0))};const decimals=numbers?Math.min(20,Math.max(...values.map(places))):0,dateOnly=dates&&values.every(value=>value.length===10),padding=numbered&&items.some(item=>item[2].length>1&&item[2][0]==="0")?Math.max(...items.map(item=>item[2].length)):0;const series=Array.from({length:count},(_,index)=>{const next=points[points.length-1]+ step*(index+1);if(numbers)return Number.isFinite(next)?Number(next.toFixed(decimals)):null;if(numbered)return Number.isSafeInteger(next)&&next>=0?items[0][1]+ String(next).padStart(padding,"0"):null;const date=new Date(next);return Number.isFinite(date.getTime())?dateOnly?date.toISOString().slice(0,10):date.toISOString():null});return series.some(value=>value===null)?repeat():series}}
133
+ return repeat()}
134
+ async function crFill(grid,rect,top,bottom,sourceRows,copy=false){const blocks=[{rows:Array.from({length:bottom-rect.top+1},(_,index)=>rect.top+index),left:rect.left,right:rect.right}];const loaded=await crLoad(grid,blocks),cells=[];const targets=blocks[0].rows.filter(position=>position>=top&&position<=bottom&&loaded.has(position));for(let index=rect.left;index<=rect.right;index++){const column=grid.cols[index],values=[];for(let position=rect.top;position<rect.top+sourceRows;position++){const row=loaded.get(position);if(row)values.push(cellValue(row.h.cells[column.id])??null)}
135
+ if(!values.length)continue;const series=crSeries(values,targets.length,copy);for(const[index,position]of targets.entries()){const row=loaded.get(position);const value=series[index],previous=cellValue(row.h.cells[column.id]);cells.push({id:row.key,column:column.id,row:position,text:value==null?"":cellText(value,column,grid.fmt),value,previous:previous??null})}}
133
136
  return crApply(grid,cells,[],"fill")}
134
- function crFillDown(grid){const rect=crRects(grid)[0];if(!rect||rect.bottom===rect.top)return Promise.resolve();const first=crDataBounds(grid,rect.top,rect.bottom).first;return first<0||first===rect.bottom?Promise.resolve():crFill(grid,{...rect,top:first},first+1,rect.bottom,1)}
135
- function crFillDrag(grid,event){const rect=crRects(grid)[0];if(!rect||event.button!==0)return;event.preventDefault();event.stopPropagation();let bottom=rect.bottom;crTrack(grid,event,hit=>{bottom=Math.max(rect.bottom,hit.row);grid.cellFillPreview=bottom>rect.bottom?{top:rect.bottom+1,bottom,left:rect.left,right:rect.right}:null;crPaint(grid)},released=>{grid.cellFillPreview=null;if(released&&bottom>rect.bottom){const range=grid.cellRanges[grid.cellRanges.length-1];range.anchor={row:rect.top,column:grid.cols[rect.left].id};range.end={row:bottom,column:grid.cols[rect.right].id};crFill(grid,rect,rect.bottom+1,bottom,rect.bottom-rect.top+1).catch(error=>grid.emit("error",{error}));crChanged(grid,false);crFocus(grid,range.anchor)}else crPaint(grid);crSwallowClick(grid)})}
137
+ function crFillDown(grid){const rect=crRects(grid)[0];if(!rect||rect.bottom===rect.top)return Promise.resolve();const first=crDataBounds(grid,rect.top,rect.bottom).first;return first<0||first===rect.bottom?Promise.resolve():crFill(grid,{...rect,top:first},first+1,rect.bottom,1,true)}
138
+ function crFillDrag(grid,event){const rect=crRects(grid)[0];if(!rect||event.button!==0)return;event.preventDefault();event.stopPropagation();let bottom=rect.bottom;crTrack(grid,event,hit=>{bottom=Math.max(rect.bottom,hit.row);grid.cellFillPreview=bottom>rect.bottom?{top:rect.bottom+1,bottom,left:rect.left,right:rect.right}:null;crPaint(grid)},(released,pointer)=>{grid.cellFillPreview=null;if(released&&bottom>rect.bottom){const range=grid.cellRanges[grid.cellRanges.length-1];range.anchor={row:rect.top,column:grid.cols[rect.left].id};range.end={row:bottom,column:grid.cols[rect.right].id};crFill(grid,rect,rect.bottom+1,bottom,rect.bottom-rect.top+1,!!(pointer?.ctrlKey||pointer?.metaKey)).catch(error=>grid.emit("error",{error}));crChanged(grid,false);crFocus(grid,range.anchor)}else crPaint(grid);crSwallowClick(grid)})}
136
139
  function crCopyOptions(options){if(!options||typeof options!=="object"||options.headers!==undefined&&typeof options.headers!=="boolean"||
137
140
  options.values!==undefined&&!["display","raw"].includes(options.values))crBad("copy options are headers (boolean) and values (display or raw)")}
138
141
  function crAt(grid,row,column,name){const bounds=crBounds(grid);if(!Number.isInteger(row)||row<bounds.first||row>bounds.last||!grid.cols.some(item=>item.id===column))crBad(name+" needs row positions in the result and visible columns");return{row,column}}
139
- Object.assign(DataGrid.prototype,{startCellRanges(){if(this.cellOptions||this.destroyed)return;const options=this.cellOptions=crOptions(this),signal=this.lifetime.signal,shared=Object.getPrototypeOf(this);this.cellRanges=[];this.cellAnchor=null;this.renderPass=function(...args){const result=shared.renderPass.apply(this,args);crPaint(this);return result};const columns=()=>{const before=this.cellRanges.length;this.cellRanges=this.cellRanges.filter(range=>crRect(this,range));if(before!==this.cellRanges.length)crChanged(this);else crPaint(this)};const shape=(query,revision)=>query&&JSON.stringify([query.search,query.searchMode,query.sort,query.filters,query.filterGroup,query.groupBy,this.paged?query.offset:0,revision]);const clear=()=>{if(this.cellRanges.length){this.cellRanges=[];this.cellAnchor=null;this.cellHandles=false;crChanged(this)}};let accepted=shape(this.getQuery(),this.snapshot?.revision);this.host.addEventListener("canopyx:query",event=>{const next=shape(event.detail.query,event.detail.revision);if(next===accepted)return;accepted=next;clear()},{signal});this.host.addEventListener("canopyx:group",clear,{signal});this.host.addEventListener("canopyx:detail",clear,{signal});this.host.addEventListener("canopyx:state",columns,{signal});document.addEventListener("copy",event=>crCopyEvent(this,event),{signal});if(!options.enabled)return;this.host.classList.add("cx-cell-ranges");signal.addEventListener("abort",()=>{this.host.classList.remove("cx-cell-ranges");crGuard(this,false)},{once:true});if(options.multiple)this.grid.setAttribute("aria-multiselectable","true");this.canvas.addEventListener("pointerdown",event=>{if(event.target.closest(".cx-fill-handle"))crFillDrag(this,event);else if(event.target.closest(".cx-range-handle"))crHandleDown(this,event);else crPointerDown(this,event)},{signal});this.grid.addEventListener("keydown",event=>crKey(this,event),{capture:true,signal});this.grid.addEventListener("click",()=>{const hit=this.cellFocusAfterClick;this.cellFocusAfterClick=null;if(hit&&this.grid.contains(document.activeElement))crFocus(this,hit)},{signal});this.canvas.addEventListener("contextmenu",event=>{const hit=crHit(this,event.target);if(!hit||event.target.closest(CR_CONTROLS))return;event.preventDefault();if(this.cellTouching||event.pointerType==="touch")return;const inside=crRects(this).some(rect=>hit.row>=rect.top&&hit.row<=rect.bottom&&crIndex(this,hit.column)>=rect.left&&crIndex(this,hit.column)<=rect.right);if(!inside){this.cellAnchor={row:hit.row,column:hit.column};if(this.cellRanges.length){this.cellRanges=[];crChanged(this)}}
140
- crMenu(this,hit.cell)},{signal});this.grid.addEventListener("paste",event=>{if(!options.paste||event.target.closest("input,textarea,select,[contenteditable]:not([contenteditable=false])")||!this.canvas.contains(event.target))return;const text=event.clipboardData?.getData("text/plain");if(typeof text!=="string")return;event.preventDefault();crPaste(this,text,null,"clipboard").catch(error=>this.emit("error",{error}))},{signal});if(this.overflow)this.overflow.panel.prepend(gridDecorateButton(gridButton(this.labels.gridCopyCells,()=>
142
+ Object.assign(DataGrid.prototype,{startCellRanges(){if(this.cellOptions||this.destroyed)return;const options=this.cellOptions=crOptions(this),signal=this.lifetime.signal,shared=Object.getPrototypeOf(this);this.cellRanges=[];this.cellAnchor=null;this.renderPass=function(...args){const result=shared.renderPass.apply(this,args);crPaint(this);const prior=this.cellMenuHit,now=prior&&crHit(this,prior.cell);if(prior&&(!now||now.row!==prior.row||now.column!==prior.column||now.element._w!==prior.record))this.cellMenuBinding.close("recycle",false,true);return result};const columnState=()=>JSON.stringify(this.columns.map(column=>[column.id,column.width,!!column.hidden,column.pin,column.priority]));let acceptedColumns=columnState();const columns=()=>{const next=columnState();if(next===acceptedColumns)return;acceptedColumns=next;this.cellMenuBinding?.close("columns",false,true);const before=this.cellRanges.length;this.cellRanges=this.cellRanges.filter(range=>crRect(this,range));if(before!==this.cellRanges.length)crChanged(this);else crPaint(this)};const shape=(query,revision)=>query&&JSON.stringify([query.search,query.searchMode,query.sort,query.filters,query.filterGroup,query.tupleFilters,query.groupBy,this.paged?query.offset:0,revision]);const clear=()=>{this.cellMenuBinding?.close("query",false,true);if(this.cellRanges.length){this.cellRanges=[];this.cellAnchor=null;this.cellHandles=false;crChanged(this)}};let accepted=shape(this.getQuery(),this.snapshot?.revision);this.host.addEventListener("canopyx:query",event=>{const next=shape(event.detail.query,event.detail.revision);if(next===accepted)return;accepted=next;clear()},{signal});this.host.addEventListener("canopyx:group",clear,{signal});this.host.addEventListener("canopyx:detail",clear,{signal});this.host.addEventListener("canopyx:state",columns,{signal});document.addEventListener("copy",event=>crCopyEvent(this,event),{signal});if(!options.enabled)return;this.host.classList.add("cx-cell-ranges");this.cellMenuBinding=bindContextMenu(this.canvas,()=>crMenuItems(this),{host:this.host,label:this.labels.gridCellMenu,renderIcon:name=>gridIcon(name),closeOnFocusOutside:true,match:event=>!event.target.closest(CR_CONTROLS)&&crHit(this,event.target)?.cell,gesture:()=>false,beforeOpen:(event,cell,settings)=>{const hit=crHit(this,cell);if(this.destroyed||this.cellTouching||!hit||!this.cellOptions.enabled)return false;if(settings.hit&&(hit.row!==settings.hit.row||hit.column!==settings.hit.column||hit.element._w!==settings.hit.record))return false;const inside=crRects(this).some(rect=>hit.row>=rect.top&&hit.row<=rect.bottom&&crIndex(this,hit.column)>=rect.left&&crIndex(this,hit.column)<=rect.right);if(settings.touch&&!inside)return false;if(event?.type==="contextmenu"&&!inside){this.cellAnchor={row:hit.row,column:hit.column};if(this.cellRanges.length){this.cellRanges=[];this.cellHandles=false;crChanged(this)}}},onOpen:({menu,element})=>{this.cellMenuPanel=menu;this.cellMenuHit=crHit(this,element);this.cellMenuHit.record=this.cellMenuHit.element._w;document.dispatchEvent(new CustomEvent("canopyx:closemenus",{detail:{source:menu}}))},onClose:()=>{this.cellMenuHit=null;this.cellMenuPanel=null},onSelect:item=>{Promise.resolve().then(()=>item.run()).catch(error=>this.emit("error",{error}))}});this.cellMenuBinding.ready.catch(error=>{if(!this.destroyed)this.emit("error",{error})});signal.addEventListener("abort",()=>this.cellMenuBinding(),{once:true});signal.addEventListener("abort",()=>{this.host.classList.remove("cx-cell-ranges");crGuard(this,false)},{once:true});if(options.multiple)this.grid.setAttribute("aria-multiselectable","true");this.canvas.addEventListener("pointerdown",event=>{if(event.target.closest(".cx-fill-handle"))crFillDrag(this,event);else if(event.target.closest(".cx-range-handle"))crHandleDown(this,event);else crPointerDown(this,event)},{signal});this.grid.addEventListener("keydown",event=>crKey(this,event),{capture:true,signal});this.grid.addEventListener("click",()=>{const hit=this.cellFocusAfterClick;this.cellFocusAfterClick=null;if(hit&&this.grid.contains(document.activeElement))crFocus(this,hit)},{signal});this.grid.addEventListener("paste",event=>{if(!options.paste||event.target.closest("input,textarea,select,[contenteditable]:not([contenteditable=false])")||!this.canvas.contains(event.target))return;const text=event.clipboardData?.getData("text/plain");if(typeof text!=="string")return;event.preventDefault();crPaste(this,text,null,"clipboard").catch(error=>this.emit("error",{error}))},{signal});if(this.overflow)this.overflow.panel.prepend(gridDecorateButton(gridButton(this.labels.gridCopyCells,()=>
141
143
  this.copyCellRanges().catch(error=>this.emit("error",{error}))),"copy",true));signal.addEventListener("abort",()=>{this.cellDrag?.();this.pasteReport?.remove()},{once:true})},getCellRanges(){return gridFreeze((this.cellRanges?crRects(this):[]).map(rect=>({startRow:rect.top,endRow:rect.bottom,startColumn:this.cols[rect.left].id,endColumn:this.cols[rect.right].id})))},setCellRanges(ranges){this.startCellRanges();if(!Array.isArray(ranges)||ranges.length>1000||ranges.length>1&&!this.cellOptions.multiple)crBad("setCellRanges takes up to 1000 ranges, one unless multiple ranges are on");this.cellRanges=ranges.map(range=>({anchor:crAt(this,range?.startRow,range?.startColumn,"setCellRanges"),end:crAt(this,range.endRow??range.startRow,range.endColumn??range.startColumn,"setCellRanges")}));this.cellAnchor=this.cellRanges[0]?.anchor||null;this.cellHandles=false;crChanged(this)},clearCellRanges(){this.startCellRanges();if(!this.cellRanges?.length)return;this.cellRanges=[];this.cellHandles=false;crChanged(this)},selectAllCells(){this.startCellRanges();const bounds=crBounds(this);if(bounds.last<bounds.first||!this.cols?.length)return;this.setCellRanges([{startRow:bounds.first,endRow:bounds.last,startColumn:this.cols[0].id,endColumn:this.cols[this.cols.length-1].id}])},async getCellRangeText(options={}){this.startCellRanges();crCopyOptions(options);const blocks=crBlocks(this,crCopyRects(this));return crContent(this,blocks,await crLoad(this,blocks),options).text},async copyCellRanges(options={}){this.startCellRanges();crCopyOptions(options);const blocks=crBlocks(this,crCopyRects(this));if(!blocks.length)crBad("copying needs a range or a focused cell");const content=crContent(this,blocks,await crLoad(this,blocks),options);await crWrite(this,content);crCopied(this,content);return content.text},pasteCells(text,at){this.startCellRanges();return crPaste(this,text,at===undefined?null:crAt(this,at?.row,at?.column,"pasteCells"),"api")}});installed.add(context.DataGrid.prototype)}};(global.CanopyXParts||=[]).push(["cell-range",part])})(typeof window!=="undefined"?window:globalThis);
@@ -6,10 +6,8 @@
6
6
  .cx-change-host:is([data-cx-height],[style*="height"]) > :is(.cx-diff,.cx-changes,.cx-prop){height:100%;overflow:auto;}
7
7
  :is(.cx-diff,.cx-changes,.cx-prop) [hidden]{display:none !important;}
8
8
  .cx-chg-ico{width:var(--cx-size-16px);height:var(--cx-size-16px);flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;}
9
- .cx-diff-btn,.cx-chg-action,.cx-chg-more{display:inline-flex;align-items:center;justify-content:center;gap:var(--cx-size-6px);box-sizing:border-box;min-width:var(--cx-size-30px);min-height:var(--cx-size-30px);
10
- padding:0 var(--cx-size-8px);font:inherit;font-size:var(--cx-size-13px);color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:var(--cx-size-1px) solid var(--hfx-color-border-control,light-dark(#8a8f98,#6e737c));border-radius:var(--hfx-radius-sm,4px);cursor:pointer;}
11
- :is(.cx-diff-btn,.cx-chg-action,.cx-chg-more,.cx-chg-kind,.cx-chg-toggle,.cx-chg-hashbtn):hover{background:var(--hfx-color-hover,light-dark(#f5f5f5,#232529));}
12
- :is(.cx-diff-btn,.cx-chg-action,.cx-chg-more,.cx-chg-kind,.cx-chg-toggle,.cx-chg-hashbtn,.cx-diff-segbtn,.cx-diff-expand):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);}
9
+ :is(.cx-chg-toggle,.cx-chg-hashbtn):hover{background:var(--hfx-color-hover,light-dark(#f5f5f5,#232529));}
10
+ :is(.cx-chg-toggle,.cx-chg-hashbtn,.cx-diff-expand):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);}
13
11
  .cx-diff-btn.cx-diff-done{border-color:var(--hfx-color-status-good-fg,light-dark(#177345,#4cc78a));color:var(--hfx-color-status-good-fg,light-dark(#177345,#4cc78a));}
14
12
  .cx-diff{position:relative;display:flex;flex-direction:column;gap:var(--cx-size-8px);max-height:100%;}
15
13
  .cx-diff-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--cx-size-8px) var(--cx-size-12px);}
@@ -19,10 +17,6 @@ padding:0 var(--cx-size-8px);font:inherit;font-size:var(--cx-size-13px);color:va
19
17
  .cx-diff-plus{color:var(--hfx-color-status-good-fg,light-dark(#177345,#4cc78a));}
20
18
  .cx-diff-minus{color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
21
19
  .cx-diff-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cx-size-6px);}
22
- .cx-diff-seg{display:inline-flex;border:var(--cx-size-1px) solid var(--hfx-color-border-control,light-dark(#8a8f98,#6e737c));border-radius:var(--hfx-radius-sm,4px);overflow:hidden;}
23
- .cx-diff-segbtn{min-height:var(--cx-size-30px);padding:0 var(--cx-size-10px);font:inherit;font-size:var(--cx-size-13px);color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:0;cursor:pointer;}
24
- .cx-diff-segbtn + .cx-diff-segbtn{border-inline-start:var(--cx-size-1px) solid var(--hfx-color-border-control,light-dark(#8a8f98,#6e737c));}
25
- .cx-diff-segbtn[aria-checked="true"]{background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));color:var(--hfx-color-accent-text,light-dark(#02726a,#37c9b8));font-weight:600;}
26
20
  .cx-diff-notes{display:grid;gap:var(--cx-size-4px);}
27
21
  .cx-diff-note{padding:var(--cx-size-6px) var(--cx-size-10px);font-size:var(--cx-size-13px);color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:var(--hfx-color-hover,light-dark(#f5f5f5,#232529));border-inline-start:var(--cx-size-3px) solid var(--hfx-color-border-strong,light-dark(#cdd0d5,#363a42));border-radius:var(--hfx-radius-sm,4px);}
28
22
  .cx-diff-note:is(.cx-tone-info,.cx-tone-warning,.cx-tone-danger,.cx-tone-success){border-inline-start-color:var(--cx-chg-note);}
@@ -81,12 +75,9 @@ color:color-mix(in srgb,var(--cx-chg-diff) 70%,var(--hfx-color-text,light-dark(#
81
75
  .cx-changes{container-type:inline-size;display:flex;flex-direction:column;gap:var(--cx-size-8px);}
82
76
  .cx-chg-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cx-size-8px) var(--cx-size-12px);}
83
77
  .cx-chg-kinds{display:flex;flex-wrap:wrap;gap:var(--cx-size-6px);}
84
- .cx-chg-kind{display:inline-flex;align-items:center;gap:var(--cx-size-6px);min-height:var(--cx-size-30px);padding:0 var(--cx-size-8px) 0 var(--cx-size-4px);font:inherit;color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));
85
- background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));border:var(--cx-size-1px) solid var(--hfx-color-border-strong,light-dark(#cdd0d5,#363a42));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));cursor:pointer;}
86
- .cx-chg-kind[aria-pressed="true"]{border-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));background:var(--hfx-color-accent-subtle,light-dark(#e7f1f1,#1b3435));}
78
+ .cx-chg-kind{padding-inline-start:var(--hfx-space-1,0.25rem);}
87
79
  .cx-chg-count{font-size:var(--cx-size-13px);font-weight:600;font-variant-numeric:tabular-nums;}
88
80
  .cx-chg-switch{display:inline-flex;align-items:center;gap:var(--cx-size-6px);min-height:var(--cx-size-30px);font-size:var(--cx-size-13px);cursor:pointer;}
89
- .cx-chg-switch input{width:var(--cx-size-16px);height:var(--cx-size-16px);margin:0;accent-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));}
90
81
  .cx-chg-summary{margin-inline-start:auto;font-size:var(--cx-size-13px);color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));font-variant-numeric:tabular-nums;}
91
82
  .cx-chg-printnote{display:none;}
92
83
  .cx-chg-tools{display:flex;flex-wrap:wrap;gap:var(--cx-size-6px);}
@@ -96,23 +87,14 @@ a.cx-chg-action{text-decoration:none;}
96
87
  background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));}
97
88
  .cx-chg-barpanel > .cx-chg-panel{margin:var(--cx-size-8px) 0 0;}
98
89
  .cx-chg-asklabel{font-size:var(--cx-size-13px);font-weight:600;}
99
- .cx-chg-reasonbox{box-sizing:border-box;width:100%;min-height:var(--cx-size-56px);padding:var(--cx-size-6px) var(--cx-size-8px);font:inherit;font-size:var(--cx-size-13px);color:var(--hfx-color-text,light-dark(#16181c,#f2f3f5));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));
100
- border:var(--cx-size-1px) solid var(--hfx-color-border-control,light-dark(#8a8f98,#6e737c));border-radius:var(--hfx-radius-sm,4px);resize:vertical;}
101
- .cx-chg-reasonbox: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);}
90
+ .cx-chg-reasonbox{inline-size:100%;resize:vertical;}
102
91
  .cx-chg-reasonbox[aria-invalid="true"]{border-color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
103
92
  .cx-chg-hint{font-size:var(--cx-size-12px);color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));}
104
93
  .cx-chg-askerror{font-size:var(--cx-size-12px);font-weight:600;color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
105
94
  .cx-chg-askerror:empty{display:none;}
106
95
  .cx-chg-askbtns{display:flex;flex-wrap:wrap;gap:var(--cx-size-6px);}
107
- .cx-chg-action.cx-chg-primary{color:var(--hfx-color-accent-contrast,light-dark(#ffffff,#0c0d10));background:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));border-color:var(--hfx-color-accent,light-dark(#11776f,#37c9b8));}
108
96
  .cx-chg-note{margin:0;font-size:var(--cx-size-13px);}
109
- .cx-chg-badge{display:inline-flex;align-items:center;box-sizing:border-box;max-width:100%;min-height:var(--cx-size-22px);padding:0 var(--cx-size-8px);overflow:hidden;font-size:var(--cx-size-12px);font-weight:600;
110
- white-space:nowrap;text-overflow:ellipsis;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));border:var(--cx-size-1px) solid currentColor;border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));}
111
- .cx-chg-badge.cx-tone-success{color:var(--hfx-color-status-good-fg,light-dark(#177345,#4cc78a));}
112
- .cx-chg-badge.cx-tone-danger{color:var(--hfx-color-status-bad-fg,light-dark(#b8292a,#f47171));}
113
- .cx-chg-badge.cx-tone-info{color:var(--hfx-color-status-info-fg,light-dark(#2b5fc0,#74a2f7));}
114
- .cx-chg-badge.cx-tone-warning{color:var(--hfx-color-status-warn-fg,light-dark(#8c5c05,#eeb640));}
115
- .cx-chg-badge.cx-toned{color:var(--cx-t);}
97
+ .cx-chg-badge{max-width:100%;overflow:hidden;text-overflow:ellipsis;}
116
98
  .cx-chg-list,.cx-chg-sublist,.cx-chg-reasons{list-style:none;margin:0;padding:0;}
117
99
  .cx-chg-list{border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-radius:var(--hfx-radius-control,var(--hfx-radius-md,6px));background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));}
118
100
  .cx-chg-folder{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--cx-size-6px);padding:var(--cx-size-6px) var(--cx-size-12px);background:var(--hfx-color-surface-sunken,light-dark(#f7f8f9,#111317));border-bottom:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));}
@@ -146,7 +128,7 @@ color:var(--cx-chg-flag,var(--hfx-color-text,light-dark(#16181c,#f2f3f5)));backg
146
128
  .cx-chg-hashbtn{padding:var(--cx-size-1px) var(--cx-size-4px);font-family:var(--hfx-font-mono,"Cascadia Mono","Cascadia Code",Consolas,"SFMono-Regular",Menlo,monospace);font-size:var(--cx-size-12px);color:var(--hfx-color-text-secondary,light-dark(#4d525b,#b0b4bc));background:none;border:0;border-radius:var(--hfx-radius-sm,4px);cursor:copy;}
147
129
  .cx-chg-arrow{color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));}
148
130
  .cx-chg-actions{grid-area:actions;display:flex;gap:var(--cx-size-4px);justify-content:flex-end;}
149
- .cx-chg-action:not(.cx-chg-textaction){padding:0;width:var(--cx-size-30px);}
131
+ .cx-chg-action:not(.cx-chg-textaction){padding:0;inline-size:var(--hfx-control-height-sm,calc(28px - var(--cx-compact,0) * 4px));}
150
132
  .cx-chg-detail{display:grid;gap:var(--cx-size-10px);padding:var(--cx-size-4px) var(--cx-size-12px) var(--cx-size-12px) calc(var(--cx-size-30px) + var(--cx-size-16px));}
151
133
  .cx-chg-dhead{font-size:var(--cx-size-12px);font-weight:600;color:var(--hfx-color-text-muted,light-dark(#626770,#8f949d));text-transform:uppercase;letter-spacing:var(--cx-size-d04em);}
152
134
  .cx-chg-reasons{display:grid;gap:var(--cx-size-4px);font-size:var(--cx-size-13px);}