@evotecit/canopyx 0.3.16 → 0.3.20

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 (150) 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 +74 -80
  8. package/CanopyX.Html/Assets/canopyx-calendar.js +26 -31
  9. package/CanopyX.Html/Assets/canopyx-cell-range.css +4 -4
  10. package/CanopyX.Html/Assets/canopyx-cell-range.js +16 -14
  11. package/CanopyX.Html/Assets/canopyx-changes.css +61 -79
  12. package/CanopyX.Html/Assets/canopyx-changes.js +18 -15
  13. package/CanopyX.Html/Assets/canopyx-column-groups.css +5 -1
  14. package/CanopyX.Html/Assets/canopyx-column-groups.js +15 -9
  15. package/CanopyX.Html/Assets/canopyx-compare.css +37 -0
  16. package/CanopyX.Html/Assets/canopyx-compare.js +12 -0
  17. package/CanopyX.Html/Assets/canopyx-data.js +3 -3
  18. package/CanopyX.Html/Assets/canopyx-detail-rows.css +4 -4
  19. package/CanopyX.Html/Assets/canopyx-detail-rows.js +1 -1
  20. package/CanopyX.Html/Assets/canopyx-editing.css +5 -5
  21. package/CanopyX.Html/Assets/canopyx-editing.js +2 -2
  22. package/CanopyX.Html/Assets/canopyx-enhance.js +5 -5
  23. package/CanopyX.Html/Assets/canopyx-export.js +54 -13
  24. package/CanopyX.Html/Assets/canopyx-facets.css +32 -22
  25. package/CanopyX.Html/Assets/canopyx-facets.js +19 -15
  26. package/CanopyX.Html/Assets/canopyx-filter-editor.css +75 -89
  27. package/CanopyX.Html/Assets/canopyx-filter-editor.js +20 -16
  28. package/CanopyX.Html/Assets/canopyx-flow-checks.css +3 -3
  29. package/CanopyX.Html/Assets/canopyx-flow-checks.js +1 -1
  30. package/CanopyX.Html/Assets/canopyx-flow-command.css +3 -3
  31. package/CanopyX.Html/Assets/canopyx-flow-command.js +1 -1
  32. package/CanopyX.Html/Assets/canopyx-flow-dialog.css +4 -4
  33. package/CanopyX.Html/Assets/canopyx-flow-dialog.js +1 -1
  34. package/CanopyX.Html/Assets/canopyx-flow-drafts.css +2 -2
  35. package/CanopyX.Html/Assets/canopyx-flow-drafts.js +1 -1
  36. package/CanopyX.Html/Assets/canopyx-flow-entry.css +142 -17
  37. package/CanopyX.Html/Assets/canopyx-flow-entry.js +5 -5
  38. package/CanopyX.Html/Assets/canopyx-flow-host.css +2 -2
  39. package/CanopyX.Html/Assets/canopyx-flow-host.js +1 -1
  40. package/CanopyX.Html/Assets/canopyx-flow-module.mjs +5 -5
  41. package/CanopyX.Html/Assets/canopyx-flow-pick.css +4 -4
  42. package/CanopyX.Html/Assets/canopyx-flow-pick.js +1 -1
  43. package/CanopyX.Html/Assets/canopyx-flow-preview.css +1 -1
  44. package/CanopyX.Html/Assets/canopyx-flow-preview.js +1 -1
  45. package/CanopyX.Html/Assets/canopyx-flow-records.css +2 -2
  46. package/CanopyX.Html/Assets/canopyx-flow-records.js +1 -1
  47. package/CanopyX.Html/Assets/canopyx-flow-tasks.css +4 -4
  48. package/CanopyX.Html/Assets/canopyx-flow-tasks.js +1 -1
  49. package/CanopyX.Html/Assets/canopyx-flow.css +41 -41
  50. package/CanopyX.Html/Assets/canopyx-flow.js +1 -1
  51. package/CanopyX.Html/Assets/canopyx-format-editor.css +9 -9
  52. package/CanopyX.Html/Assets/canopyx-format-editor.js +2 -2
  53. package/CanopyX.Html/Assets/canopyx-formatting.css +13 -13
  54. package/CanopyX.Html/Assets/canopyx-formatting.js +12 -11
  55. package/CanopyX.Html/Assets/canopyx-forms.css +3 -3
  56. package/CanopyX.Html/Assets/canopyx-forms.js +1 -1
  57. package/CanopyX.Html/Assets/canopyx-grid-module.mjs +220 -155
  58. package/CanopyX.Html/Assets/canopyx-grid-options.css +8 -8
  59. package/CanopyX.Html/Assets/canopyx-grid-options.js +9 -2
  60. package/CanopyX.Html/Assets/canopyx-grid.css +285 -150
  61. package/CanopyX.Html/Assets/canopyx-grid.js +220 -155
  62. package/CanopyX.Html/Assets/canopyx-grouping.css +23 -16
  63. package/CanopyX.Html/Assets/canopyx-grouping.js +24 -17
  64. package/CanopyX.Html/Assets/canopyx-highlight.css +10 -10
  65. package/CanopyX.Html/Assets/canopyx-highlight.js +1 -1
  66. package/CanopyX.Html/Assets/canopyx-interactive.css +215 -91
  67. package/CanopyX.Html/Assets/canopyx-interactive.js +47 -52
  68. package/CanopyX.Html/Assets/canopyx-labels-de.js +177 -9
  69. package/CanopyX.Html/Assets/canopyx-labels-es.js +177 -9
  70. package/CanopyX.Html/Assets/canopyx-labels-fr.js +176 -8
  71. package/CanopyX.Html/Assets/canopyx-labels-it.js +176 -8
  72. package/CanopyX.Html/Assets/canopyx-labels-pl.js +176 -8
  73. package/CanopyX.Html/Assets/canopyx-layouts.css +49 -21
  74. package/CanopyX.Html/Assets/canopyx-layouts.js +36 -14
  75. package/CanopyX.Html/Assets/canopyx-link.css +3 -3
  76. package/CanopyX.Html/Assets/canopyx-link.js +4 -4
  77. package/CanopyX.Html/Assets/canopyx-links.js +2 -2
  78. package/CanopyX.Html/Assets/canopyx-live.css +3 -5
  79. package/CanopyX.Html/Assets/canopyx-live.js +3 -3
  80. package/CanopyX.Html/Assets/canopyx-matrix.css +32 -39
  81. package/CanopyX.Html/Assets/canopyx-matrix.js +11 -11
  82. package/CanopyX.Html/Assets/canopyx-module.mjs +47 -52
  83. package/CanopyX.Html/Assets/canopyx-office-export.js +2936 -0
  84. package/CanopyX.Html/Assets/canopyx-pager.css +1 -1
  85. package/CanopyX.Html/Assets/canopyx-pager.js +1 -1
  86. package/CanopyX.Html/Assets/canopyx-path.css +45 -0
  87. package/CanopyX.Html/Assets/canopyx-path.js +28 -0
  88. package/CanopyX.Html/Assets/canopyx-pivot.css +75 -0
  89. package/CanopyX.Html/Assets/canopyx-pivot.js +72 -0
  90. package/CanopyX.Html/Assets/canopyx-plan.css +63 -0
  91. package/CanopyX.Html/Assets/canopyx-plan.js +71 -0
  92. package/CanopyX.Html/Assets/canopyx-presenters.js +2 -2
  93. package/CanopyX.Html/Assets/canopyx-record-panel.css +51 -45
  94. package/CanopyX.Html/Assets/canopyx-record-panel.js +30 -22
  95. package/CanopyX.Html/Assets/canopyx-reporting-module.mjs +262 -197
  96. package/CanopyX.Html/Assets/canopyx-reporting.css +300 -164
  97. package/CanopyX.Html/Assets/canopyx-reporting.js +262 -197
  98. package/CanopyX.Html/Assets/canopyx-stack.css +35 -0
  99. package/CanopyX.Html/Assets/canopyx-stack.js +24 -0
  100. package/CanopyX.Html/Assets/canopyx-time-slider.css +18 -0
  101. package/CanopyX.Html/Assets/canopyx-time-slider.js +27 -0
  102. package/CanopyX.Html/Assets/canopyx-timeline.css +19 -19
  103. package/CanopyX.Html/Assets/canopyx-timeline.js +6 -5
  104. package/CanopyX.Html/Assets/canopyx-tree-tools.css +47 -46
  105. package/CanopyX.Html/Assets/canopyx-tree-tools.js +15 -12
  106. package/CanopyX.Html/Assets/canopyx-ui-menu.css +41 -0
  107. package/CanopyX.Html/Assets/canopyx-ui-menu.js +64 -0
  108. package/CanopyX.Html/Assets/canopyx-ui-navigation.css +73 -0
  109. package/CanopyX.Html/Assets/canopyx-ui-navigation.js +39 -0
  110. package/CanopyX.Html/Assets/canopyx-ui-overlays.css +79 -0
  111. package/CanopyX.Html/Assets/canopyx-ui-overlays.js +45 -0
  112. package/CanopyX.Html/Assets/canopyx-ui-picker.css +12 -0
  113. package/CanopyX.Html/Assets/canopyx-ui-picker.js +6 -0
  114. package/CanopyX.Html/Assets/canopyx-ui-stepper.css +174 -0
  115. package/CanopyX.Html/Assets/canopyx-ui-stepper.js +48 -0
  116. package/CanopyX.Html/Assets/canopyx-ui-tabs.css +153 -0
  117. package/CanopyX.Html/Assets/canopyx-ui-tabs.js +47 -0
  118. package/CanopyX.Html/Assets/canopyx-values.css +5 -0
  119. package/CanopyX.Html/Assets/canopyx-values.js +13 -0
  120. package/CanopyX.Html/Assets/canopyx-view-intents.css +12 -0
  121. package/CanopyX.Html/Assets/canopyx-view-intents.js +56 -0
  122. package/CanopyX.Html/Assets/canopyx.css +212 -85
  123. package/CanopyX.Html/Assets/canopyx.js +38 -26
  124. package/JavaScript/board.d.ts +30 -0
  125. package/JavaScript/changes.d.ts +4 -1
  126. package/JavaScript/column-groups.d.ts +24 -4
  127. package/JavaScript/facets.d.ts +5 -3
  128. package/JavaScript/grid.d.ts +161 -17
  129. package/JavaScript/hosts.d.ts +16 -1
  130. package/JavaScript/index.d.ts +4 -2
  131. package/JavaScript/locales/de.mjs +177 -9
  132. package/JavaScript/locales/es.mjs +177 -9
  133. package/JavaScript/locales/fr.mjs +176 -8
  134. package/JavaScript/locales/it.mjs +176 -8
  135. package/JavaScript/locales/pl.mjs +176 -8
  136. package/JavaScript/matrix.d.ts +4 -1
  137. package/JavaScript/path.d.ts +33 -0
  138. package/JavaScript/pivot.d.ts +135 -0
  139. package/JavaScript/plan.d.ts +23 -0
  140. package/JavaScript/protocol.d.ts +18 -3
  141. package/JavaScript/records.d.ts +4 -0
  142. package/JavaScript/stack.d.ts +28 -0
  143. package/JavaScript/time-slider.d.ts +58 -0
  144. package/JavaScript/ui.d.ts +261 -0
  145. package/JavaScript/view-intents.d.ts +45 -0
  146. package/README.md +76 -187
  147. package/README.nuget.md +63 -87
  148. package/ThirdParty/OfficeIMO/LICENSE +21 -0
  149. package/ThirdParty/OfficeIMO/README.md +13 -0
  150. 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:"e11aad6b723ddf23",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()}}
@@ -30,7 +30,7 @@ const CAL_SUNDAY_REGIONS=/^(?:US|CA|MX|BR|JP|KR|TW|HK|IL|PH|IN|ZA|SA|AR|CO|PE|VE
30
30
  function calFirstDay(lang){try{const locale=new Intl.Locale(lang||"en-US"),info=typeof locale.getWeekInfo==="function"?locale.getWeekInfo():locale.weekInfo;if(info&&Number.isInteger(info.firstDay))return info.firstDay%7;const region=locale.maximize().region;return CAL_SUNDAY_REGIONS.test(region||"")?0:region?1:0}catch(_){return 1}}
31
31
  function calFormats(lang,zone){const cache=new Map(),timeZone=zone.name==="utc"?"UTC":zone.name==="local"?undefined:zone.name;const make=(options,dayFormat)=>{const key=JSON.stringify(options)+(dayFormat?"d":"t");let format=cache.get(key);if(!format){const settings={...options,timeZone:dayFormat?"UTC":timeZone};try{format=new Intl.DateTimeFormat(lang||undefined,settings)}catch(_){format=new Intl.DateTimeFormat(undefined,settings)}
32
32
  cache.set(key,format)}
33
- return format};const day=(options,value)=>make(options,true).format(new Date(value*CAL_DAY));const range=(options,from,to)=>{if(from===to)return day(options,from);const format=make(options,true);try{return format.formatRange(new Date(from*CAL_DAY),new Date(to*CAL_DAY))}catch(_){return format.format(new Date(from*CAL_DAY))+ " – "+format.format(new Date(to*CAL_DAY))}};return{lang,day,range,monthTitle:value=>day({month:"long",year:"numeric"},value),monthName:value=>day({month:"long"},value),monthShort:value=>day({month:"short"},value),weekday:(value,width)=>day({weekday:width||"short"},value),dayNumber:value=>day({day:"numeric"},value),dayHeader:value=>day({weekday:"short",day:"numeric"},value),longDay:value=>day({weekday:"long",day:"numeric",month:"long",year:"numeric"},value),shortDay:value=>day({day:"numeric",month:"short"},value),date:value=>day({day:"numeric",month:"short",year:"numeric"},value),year:value=>day({year:"numeric"},value),dayRange:(from,to)=>range({day:"numeric",month:"short",year:"numeric"},from,to),monthRange:(from,to)=>range({month:"short",year:"numeric"},from,to),time:value=>make({hour:"numeric",minute:"2-digit"}).format(new Date(value)),hour:minutes=>make({hour:"numeric"},true).format(new Date(minutes*CAL_MINUTE)),clock:minutes=>make({hour:"numeric",minute:"2-digit"},true).format(new Date(minutes*CAL_MINUTE)),number:value=>numberFormat(lang).format(value)}}
33
+ return format};const day=(options,value)=>make(options,true).format(new Date(value*CAL_DAY));const range=(options,from,to)=>{if(from===to)return day(options,from);const format=make(options,true);try{return format.formatRange(new Date(from*CAL_DAY),new Date(to*CAL_DAY))}catch(_){return format.format(new Date(from*CAL_DAY))+ " – "+format.format(new Date(to*CAL_DAY))}};return{lang,day,range,monthTitle:value=>day({month:"long",year:"numeric"},value),monthName:value=>day({month:"long"},value),monthShort:value=>day({month:"short"},value),weekday:(value,width)=>day({weekday:width||"short"},value),dayNumber:value=>day({day:"numeric"},value),dayHeader:value=>day({weekday:"short",day:"numeric"},value),longDay:value=>day({weekday:"long",day:"numeric",month:"long",year:"numeric"},value),shortDay:value=>day({day:"numeric",month:"short"},value),date:value=>day({day:"numeric",month:"short",year:"numeric"},value),year:value=>day({year:"numeric"},value),dayRange:(from,to)=>range({day:"numeric",month:"short",year:"numeric"},from,to),monthRange:(from,to)=>range({month:"short",year:"numeric"},from,to),time:value=>make({hour:"numeric",minute:"2-digit"}).format(new Date(value)),timeRange:(from,to)=>make({hour:"numeric",minute:"2-digit"}).formatRange(new Date(from),new Date(to)),hour:minutes=>make({hour:"numeric"},true).format(new Date(minutes*CAL_MINUTE)),clock:minutes=>make({hour:"numeric",minute:"2-digit"},true).format(new Date(minutes*CAL_MINUTE)),number:value=>numberFormat(lang).format(value)}}
34
34
  const CAL_VIEWS=["month","week","day","days","agenda","year","timeline","mini","weekList","dayList","months"],CAL_ZOOMS=["hour","day","week","month","quarter"];const CAL_KEYS=new Set(["start","end","title","subtitle","allDay","resource","resourceIds","status","recurrence","exceptions","series","recurrenceId","display","seriesEnd","view","views","date","days","firstDay","hiddenDays","slotMinutes","minTime","maxTime","scrollTime","workingHours","nowIndicator","eventLimit","eventStyle","timeZone","editable","resources","zoom","zooms","capacity","ranges","availability","limit","phone","toolbar","details","description","tone","source","sources","create","drop","occurrence","weekNumbers","navLinks","validRange","fixedWeeks","outsideDays","span","menu","hover","yearEvents","agendaSpan","months","print"]);const CAL_TONE=/^[a-z][a-z0-9-]{0,31}$/;
35
35
  function calInvalid(message){throw new Error("CanopyX: "+message)}
36
36
  function calDays(list,name){if(!Array.isArray(list)||list.length>7||new Set(list).size!==list.length||list.some(day=>!Number.isInteger(day)||day<0||day>6))calInvalid(name+" lists weekdays 0 to 6.");return new Set(list)}
@@ -116,21 +116,21 @@ 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}
126
126
  const today=this.calZone.day(Date.now());this.calTodayButton.setAttribute("aria-disabled",String(today>=range.firstDay&&today<=range.lastDay||!this.calInValid({firstDay:today,lastDay:today})));if(this.cal.validRange)for(const[button,direction]of[[this.calPrev,-1],[this.calNextButton,1]])button.setAttribute("aria-disabled",String(!this.calInValid(this.calRangeOf(view,this.calStepDate(direction)))));if(announce)this.calAnnounce(fill(this.calLabels.calendarShowing,{view:this.calViewName(view),range:title}))},calRangeTitle(){const fmt=this.calFmt,range=this.calRange;switch(this.calView){case "month":case "mini":return fmt.monthTitle(this.calDate);case "agenda":{const span=this.cal.agendaSpan;return span==="month"?fmt.monthTitle(this.calDate):span==="year"?fmt.year(this.calDate):span==="day"?fmt.longDay(range.firstDay):fmt.dayRange(range.firstDay,range.lastDay)}
127
- case "months":return fmt.monthRange(range.firstDay,range.lastDay);case "year":return fmt.year(this.calDate);case "day":case "dayList":return this.calPhone?fmt.shortDay(range.firstDay)+ ", "+fmt.year(range.firstDay):fmt.longDay(range.firstDay);case "timeline":return this.calTimelineTitle?this.calTimelineTitle():fmt.dayRange(range.firstDay,range.lastDay);default:return fmt.dayRange(range.firstDay,range.lastDay)}},calAnnounce(text){clearTimeout(this.calAnnounceTimer);this.calAnnounceTimer=setTimeout(()=>{if(!this.destroyed)setText(this.calLive,text)},150)}});const CAL_ROW_COPIES=new WeakMap();Object.assign(DataGrid.prototype,{calTimeText(event){if(event.allDay)return this.calLabels.calendarAllDay;const fmt=this.calFmt,labels=this.calLabels;if(event.marker)return fmt.time(event.start);if(event.ed>event.sd)return fill(labels.calendarTimeRange,{start:fmt.shortDay(event.sd)+ " "+fmt.time(event.start),end:fmt.shortDay(event.ed)+ " "+fmt.time(event.end)});return fill(labels.calendarTimeRange,{start:fmt.time(event.start),end:fmt.time(event.end)})},calStatusText(event){const column=this.cal.status;return column?cellText(event.row.cells[column.id],column,this.fmt):""},calEventName(event){const parts=[event.title,event.allDay&&event.ed>event.sd?this.calFmt.dayRange(event.sd,event.ed):this.calTimeText(event)];const status=this.calStatusText(event);if(status)parts.push(status);if(event.subtitle)parts.push(event.subtitle);if(this.calResourceName)parts.push(...this.calEventResources(event).map(id=>this.calResourceName(id)));if(this.calEventResources(event).length>1)parts.push(calCount(this,this.calLabels.calendarSharedResources,this.calEventResources(event).length,{resources:this.calLabels.calendarResources.toLocaleLowerCase(this.lang)}));if(event.recurring)parts.push(this.calLabels.calendarRepeats);return parts.filter(Boolean).join(", ")},calDisposeEventRenderers(container){const slots=this.calHostSlots;if(!container)this.calHostSlots=null;for(const slot of slots||[])if(!container||container.contains(slot.content)){slots.delete(slot);disposeHostSlot(slot)}},calEventElement(event,kind){const element=h("button","cx-cal-ev cx-cal-ev-"+kind +(event.marker?" cx-cal-marker":"")+(event.allDay?" cx-cal-allday":""));element.type="button";element.tabIndex=-1;element.dataset.cxEvent=event.id;element.dataset.cxRecord=event.key;element._calEvent=event;if(event.tone){element.dataset.cxTone=event.tone;element.style.setProperty("--cx-ev",event.tone==="neutral"?"var(--hfx-color-status-neutral-fg,var(--hfx-color-text-muted,light-dark(#626770,#8f949d)))":toneVariable(event.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));element.style.setProperty("--cx-ev-bg",toneVariable(event.tone,true,"color-mix(in srgb,var(--cx-ev) 14%,var(--hfx-color-surface,light-dark(#ffffff,#16181c)))"))}
128
- if(event.color){element.style.setProperty("--cx-ev",event.color);element.style.setProperty("--cx-ev-bg","color-mix(in srgb,var(--cx-ev) 14%,var(--hfx-color-surface,light-dark(#ffffff,#16181c)))")}
127
+ case "months":return fmt.monthRange(range.firstDay,range.lastDay);case "year":return fmt.year(this.calDate);case "day":case "dayList":return this.calPhone?fmt.shortDay(range.firstDay)+ ", "+fmt.year(range.firstDay):fmt.longDay(range.firstDay);case "timeline":return this.calTimelineTitle?this.calTimelineTitle():fmt.dayRange(range.firstDay,range.lastDay);default:return fmt.dayRange(range.firstDay,range.lastDay)}},calAnnounce(text){clearTimeout(this.calAnnounceTimer);this.calAnnounceTimer=setTimeout(()=>{if(!this.destroyed)setText(this.calLive,text)},150)}});const CAL_ROW_COPIES=new WeakMap();Object.assign(DataGrid.prototype,{calTimeText(event,day){if(event.allDay)return this.calLabels.calendarAllDay;const fmt=this.calFmt,labels=this.calLabels;if(event.marker)return fmt.time(event.start);if(day!==undefined&&event.ed>event.sd)return day===event.sd?fmt.time(event.start):day===event.ed?fmt.time(event.end):labels.calendarAllDay;if(event.ed>event.sd)return fill(labels.calendarTimeRange,{start:fmt.shortDay(event.sd)+ " "+fmt.time(event.start),end:fmt.shortDay(event.ed)+ " "+fmt.time(event.end)});if(day!==undefined)return fmt.timeRange(event.start,event.end);return fill(labels.calendarTimeRange,{start:fmt.time(event.start),end:fmt.time(event.end)})},calStatusText(event){const column=this.cal.status;return column?cellText(event.row.cells[column.id],column,this.fmt):""},calEventName(event){const parts=[event.title,event.allDay&&event.ed>event.sd?this.calFmt.dayRange(event.sd,event.ed):this.calTimeText(event)];const status=this.calStatusText(event);if(status)parts.push(status);if(event.subtitle)parts.push(event.subtitle);if(this.calResourceName)parts.push(...this.calEventResources(event).map(id=>this.calResourceName(id)));if(this.calEventResources(event).length>1)parts.push(calCount(this,this.calLabels.calendarSharedResources,this.calEventResources(event).length,{resources:this.calLabels.calendarResources.toLocaleLowerCase(this.lang)}));if(event.recurring)parts.push(this.calLabels.calendarRepeats);return parts.filter(Boolean).join(", ")},calDisposeEventRenderers(container){const slots=this.calHostSlots;if(!container)this.calHostSlots=null;for(const slot of slots||[])if(!container||container.contains(slot.content)){slots.delete(slot);disposeHostSlot(slot)}},calEventElement(event,kind,day){const element=h("button","cx-cal-ev cx-cal-ev-"+kind +(event.marker?" cx-cal-marker":"")+(event.allDay?" cx-cal-allday":""));element.type="button";element.tabIndex=-1;element.dataset.cxEvent=event.id;element.dataset.cxRecord=event.key;element._calEvent=event;if(event.tone){element.dataset.cxTone=event.tone;element.style.setProperty("--cx-ev",event.tone==="neutral"?"var(--hfx-color-status-neutral-fg,var(--hfx-color-text-secondary,var(--hfx-color-text-muted,light-dark(#626770,#8f949d))))":toneVariable(event.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));element.style.setProperty("--cx-ev-bg",toneVariable(event.tone,true,"color-mix(in srgb,var(--cx-ev) 14%,var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c))))"))}
128
+ if(event.color){element.style.setProperty("--cx-ev",event.color);element.style.setProperty("--cx-ev-bg","color-mix(in srgb,var(--cx-ev) 14%,var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c))))")}
129
129
  element.setAttribute("aria-label",this.calEventName(event));const assignments=this.calEventResources(event);if(assignments.length>1){element.title=this.calEventName(event);const mark=(kind,on)=>{this[kind]=on?event.id:this[kind]===event.id?null:this[kind];for(const card of this.calRoot.querySelectorAll(".cx-cal-ev"))card.classList.toggle("cx-cal-shared-active",card.dataset.cxEvent===this.calSharedHover||card.dataset.cxEvent===this.calSharedFocus)};element.addEventListener("pointerenter",()=>mark("calSharedHover",true));element.addEventListener("pointerleave",()=>mark("calSharedHover",false));element.addEventListener("focus",()=>mark("calSharedFocus",true));element.addEventListener("blur",()=>mark("calSharedFocus",false))}
130
130
  if(!event.base?.external&&this.linkHighlight?.has(event.key))element.dataset.cxLinked="true";const template=this.opts.calendar?.render;if(typeof template==="function"){let copy=CAL_ROW_COPIES.get(event.row);if(copy?.version!==this.calVersion){copy={version:this.calVersion,row:gridFreeze(JSON.parse(JSON.stringify(event.row)))};CAL_ROW_COPIES.set(event.row,copy)}
131
131
  const row=copy.row;try{if(template({event:this.calPublicEvent(event),row,element,kind,labels:this.calLabels})===true)return element}
132
132
  catch(error){this.emit("error",{error});element.textContent=""}}
133
- const time=h("span","cx-cal-ev-time"),title=h("span","cx-cal-ev-title");if(!event.allDay&&kind!=="bar"&&kind!=="lane"){setText(time,kind==="item"?this.calTimeText(event):this.calFmt.time(event.start));element.appendChild(time)}
133
+ const time=h("span","cx-cal-ev-time"),title=h("span","cx-cal-ev-title");if(!event.allDay&&kind!=="bar"&&kind!=="lane"){setText(time,kind==="item"?this.calTimeText(event,day):this.calFmt.time(event.start));element.appendChild(time)}
134
134
  setText(title,event.title);element.appendChild(title);if(assignments.length>1){const shared=h("span","cx-cal-shared");setText(shared,calCount(this,this.calLabels.calendarSharedResources,assignments.length,{resources:this.calLabels.calendarResources.toLocaleLowerCase(this.lang)}));shared.setAttribute("aria-hidden","true");element.appendChild(shared)}
135
135
  if(kind==="block"||kind==="item"||kind==="lane"){if(event.subtitle){const subtitle=h("span","cx-cal-ev-sub");setText(subtitle,event.subtitle);element.appendChild(subtitle)}
136
136
  const column=this.cal.status;if(column&&(kind!=="lane")&&cellValue(event.row.cells[column.id])!=null){const statusClass="cx-cal-ev-status" +(event.base?.toneFromStatus?" cx-cal-status-tone":"");let status=h("span",statusClass);let drawn=false;if(column.render){const slot={content:status},context=new HostCellContext(slot,column.id,undefined,undefined,this.columns.indexOf(column));(this.calHostSlots||=new Set()).add(slot);try{drawn=column.render(event.row,status,context)===true}
@@ -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.")}
@@ -163,24 +158,24 @@ budget.rows+rows>budget.limit?"JSON feeds exceed the combined event limit of "+b
163
158
  function calJsonRows(items,source){if(!Array.isArray(items)||items.length>5000)throw new Error("A JSON feed is an array of at most 5,000 events.");const ids=new Set(),identity=id=>"json:"+JSON.stringify([source,id]);return items.map((item,index)=>{if(!item||typeof item!=="object"||Array.isArray(item)||typeof item.title!=="string"||item.title.length>1000||
164
159
  typeof item.start!=="string"||!Number.isFinite(calInstant(item.start.length===10?item.start+"T00:00:00Z":item.start))||
165
160
  item.end!=null&&(typeof item.end!=="string"||!Number.isFinite(calInstant(item.end.length===10?item.end+"T00:00:00Z":item.end))))throw new Error("A JSON event needs a title and ISO start/end values.");const id=item.id??String(index+1);if(typeof id!=="string"||!CAL_ID.test(id)||ids.has(id))throw new Error("JSON event ids must be unique identifiers.");ids.add(id);for(const name of["description","resource","recurrence","exceptions","series","recurrenceId"])if(item[name]!=null&&(typeof item[name]!=="string"||item[name].length>10000))throw new Error("Invalid JSON event "+name+".");if(item.allDay!==undefined&&typeof item.allDay!=="boolean")throw new Error("JSON allDay is a boolean.");const allDay=item.allDay??item.start.length===10,normalize=value=>value?.length===10?value+"T00:00:00Z":value;return{id:identity(id),external:source,cells:{},fields:{title:item.title,start:normalize(item.start),end:normalize(item.end),allDay,description:item.description||"",resource:item.resource||null,resourceIds:calResourceIds(item.resourceIds),recurrence:item.recurrence,exceptions:item.exceptions,series:item.series?identity(item.series):null,recurrenceId:normalize(item.recurrenceId)}}})}
166
- const CAL_LANE=22,CAL_NUMBER=26;const calDayOrder=(a,b)=>(b.allDay-a.allDay)||a.start-b.start||(a.id<b.id?-1:1);Object.assign(DataGrid.prototype,{calWeekdays(){const days=[];for(let i=0;i<7;i++){const dow=(this.cal.firstDay+i)%7;if(!this.cal.hidden.has(dow))days.push(dow)}
161
+ const CAL_LANE=22,CAL_NUMBER=26;function calMonthLanes(items,columns,limit){const bar=item=>calInAllDayRow(item.event)||item.event.ed>item.event.sd;const ordered=items.slice().sort((a,b)=>Number(bar(b))- Number(bar(a))||(bar(a)?(b.to-b.from)-(a.to-a.from):0));const reserved=new Array(columns).fill(false);let visible,counts,busy,changed;do{visible=[];counts=new Array(columns).fill(0);busy=Array.from({length:columns},()=>[]);changed=false;const shown=new Set();for(const item of ordered){const someColumn=predicate=>{for(let col=item.from;col<=item.to;col++)if(predicate(col))return true;return false};let lane=0;while(someColumn(col=>busy[col][lane]))lane++;if(someColumn(col=>lane>=limit-Number(reserved[col])))continue;visible.push({...item,lane});shown.add(item.event);for(let col=item.from;col<=item.to;col++){busy[col][lane]=true;counts[col]++}}
162
+ for(const item of items)for(let col=item.from;col<=item.to;col++){if(!reserved[col]&&!shown.has(item.event)){reserved[col]=true;changed=true}}}while(changed);return{visible,counts,more:busy.map(lanes=>lanes.length)}}
163
+ const calDayOrder=(a,b)=>(b.allDay-a.allDay)||a.start-b.start||(a.id<b.id?-1:1);Object.assign(DataGrid.prototype,{calWeekdays(){const days=[];for(let i=0;i<7;i++){const dow=(this.cal.firstDay+i)%7;if(!this.cal.hidden.has(dow))days.push(dow)}
167
164
  return days},calWeekdayRow(className,corner){const row=h("div",className),fmt=this.calFmt;row.setAttribute("role","row");if(corner){const cell=h("div","cx-cal-corner");cell.setAttribute("role","columnheader");setText(cell,corner===true?"":corner);row.appendChild(cell)}
168
165
  for(const dow of this.calWeekdays()){const cell=h("div","cx-cal-dowc"),day=calDayNumber(2023,1,1)+ dow;cell.setAttribute("role","columnheader");cell.setAttribute("aria-label",fmt.weekday(day,"long"));setText(cell,fmt.weekday(day,this.calPhone?"narrow":"short"));row.appendChild(cell)}
169
166
  return row},calDayName(day,count,ranges){const parts=[this.calFmt.longDay(day)];if(day===this.calZone.day(Date.now()))parts.push(this.calLabels.calendarToday);for(const range of ranges||[])parts.push(range.label);parts.push(count?calCount(this,this.calLabels.calendarEvents,count):this.calLabels.calendarNoEvents);return parts.join(", ")},calBackgroundsOn(day,resource,partial){const out=[];for(const range of this.calRanges)if(range.sd<=day&&range.ed>=day&&(resource===undefined?!range.inverse||range.resource==null:range.resource==null||range.resource===resource)&&
170
167
  (partial||!range.inverse||range.start<=this.calZone.start(day)&&range.end>=this.calZone.start(day+1)))out.push(range);for(const event of this.calEvents)if(event.background&&event.sd<=day&&event.ed>=day&&(resource===undefined||!this.calEventResources(event).length||this.calHasResource(event,resource)))
171
168
  out.push({id:event.id,label:event.title,tone:event.tone||"info",kind:"background",sd:event.sd,ed:event.ed,start:event.start,end:event.end,resource:event.resource});return out},calPaintMonth(){const range=this.calRange,body=this.calBody,weekCount=Math.round((range.lastDay-range.firstDay+1)/ 7);
172
169
  const available=body.clientHeight-CAL_NUMBER-4,rowHeight=this.calPhone?44:Math.max(96,Math.floor(available / weekCount));
173
- this.calCells=new Map();const grid=this.calMonthGrid(range.firstDay,range.lastDay,range.month,{rowHeight,dots:this.calPhone,outside:this.cal.outsideDays,labelledBy:this.calTitle.id});body.replaceChildren(grid);this.calGrid=grid;if(this.calPhone){const day=this.calFocus?.day??this.calDate;body.appendChild(this.calDayList(day));this.calMarkListedDay(day)}},calMonthGrid(first,last,monthStart,options){const weekdays=this.calWeekdays(),today=this.calZone.day(Date.now()),month=calDayParts(monthStart).m,monthEnd=calAddMonths(monthStart,1)- 1;const events=this.calEvents.filter(event=>!event.background),rowHeight=options.rowHeight,valid=this.cal.validRange;const grid=h("div","cx-cal-month" +(options.className?" "+options.className:""));grid.setAttribute("role","grid");if(options.labelledBy)grid.setAttribute("aria-labelledby",options.labelledBy);grid.setAttribute("aria-readonly",String(!this.cal.editable&&!this.cal.create));grid.style.setProperty("--cx-cal-cols",String(weekdays.length));grid.appendChild(this.calWeekdayRow("cx-cal-dow"));const weeks=h("div","cx-cal-weeks");weeks.setAttribute("role","rowgroup");grid.appendChild(weeks);const fit=Math.max(1,Math.floor((rowHeight-CAL_NUMBER-4)/ CAL_LANE));
170
+ this.calCells=new Map();const grid=this.calMonthGrid(range.firstDay,range.lastDay,range.month,{rowHeight,dots:this.calPhone,outside:this.cal.outsideDays,labelledBy:this.calTitle.id});body.replaceChildren(grid);this.calGrid=grid;if(this.calPhone){const day=this.calFocus?.day??this.calDate;body.appendChild(this.calDayList(day));this.calMarkListedDay(day)}},calMonthGrid(first,last,monthStart,options){const weekdays=this.calWeekdays(),today=this.calZone.day(Date.now()),month=calDayParts(monthStart).m,monthEnd=calAddMonths(monthStart,1)- 1;const events=this.calEvents.filter(event=>!event.background),rowHeight=options.rowHeight,valid=this.cal.validRange;const grid=h("div","cx-cal-month" +(options.className?" "+options.className:""));grid.setAttribute("role","grid");if(options.labelledBy)grid.setAttribute("aria-labelledby",options.labelledBy);grid.setAttribute("aria-readonly",String(!this.cal.editable&&!this.cal.create));grid.style.setProperty("--cx-cal-cols",String(weekdays.length));grid.appendChild(this.calWeekdayRow("cx-cal-dow"));const weeks=h("div","cx-cal-weeks");weeks.setAttribute("role","rowgroup");grid.appendChild(weeks);const fit=Math.max(1,Math.floor((rowHeight-CAL_NUMBER)/ CAL_LANE));
174
171
  const limit=this.calPrinting?Infinity:options.dots?0:this.cal.eventLimit==="auto"?fit:Math.min(this.cal.eventLimit,Math.max(fit,1));for(let week=first;week<=last;week +=7){const row=h("div","cx-cal-week"),columns=new Map();row.setAttribute("role","row");row.style.minHeight=rowHeight+"px";if(this.cal.weekNumbers){const number=this.calWeekNumber(week+3);row.setAttribute("aria-label",fill(this.calLabels.calendarWeekNumber,{number}));row.dataset.cxWeek=String(number)}
175
172
  weekdays.forEach((dow,index)=>columns.set(week +(dow-this.cal.firstDay+7)%7,index));const shown=[...columns.keys()].sort((a,b)=>a-b);const outside=day=>day<monthStart||day>monthEnd,pad=day=>!options.outside&&outside(day);const order=new Map(shown.map((day,index)=>[day,index])),cells=[];for(const day of shown){if(pad(day)){const empty=h("div","cx-cal-pad");empty.setAttribute("role","gridcell");empty.style.gridColumn=String(order.get(day)+ 1);cells.push(empty);row.appendChild(empty);continue}
176
173
  const invalid=valid&&(day<valid.first||day>valid.last);const cell=h("div","cx-cal-day" +(calDayParts(day).m!==month?" cx-cal-out":"")+(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");const number=h("span","cx-cal-num");setText(number,this.calFmt.dayNumber(day));number.setAttribute("aria-hidden","true");cell.appendChild(number);if(this.cal.weekNumbers&&cells.every(item=>item.classList.contains("cx-cal-pad"))){const wk=h("span","cx-cal-wknum");setText(wk,fill(this.calLabels.calendarWeekShort,{number:row.dataset.cxWeek}));wk.setAttribute("aria-hidden","true");cell.appendChild(wk)}
177
174
  cell.style.gridColumn=String(order.get(day)+ 1);cells.push(cell);this.calCells.set(day,cell);row.appendChild(cell)}
178
- const weekEvents=events.filter(event=>event.sd<=week+6&&event.ed>=week);const placed=calLanes(weekEvents,week,week+6,day=>order.has(day)&&!pad(day)?order.get(day):-1);if(this.calPrinting)row.style.minHeight=Math.max(rowHeight,CAL_NUMBER+6 +(Math.max(-1,...placed.map(item=>item.lane))+ 1)*CAL_LANE)+ "px";const totals=new Array(shown.length).fill(0);for(const item of placed)for(let col=item.from;col<=item.to;col++)totals[col]++;const dayLimit=totals.map(total=>total>limit?Math.max(0,limit-1):limit),visible=new Array(shown.length).fill(0);for(const item of placed){let run=null;const flush=()=>{if(!run)return;const event=item.event,bar=calInAllDayRow(event)||event.ed>event.sd,element=this.calEventElement(event,bar?"bar":"chip");element.style.setProperty("--c",String(run.from));element.style.setProperty("--s",String(run.to-run.from+1));element.style.setProperty("--l",String(item.lane));if(event.sd<shown[run.from])element.classList.add("cx-cal-cont-start");if(event.ed>shown[run.to])element.classList.add("cx-cal-cont-end");cells[run.from].appendChild(element);run=null};for(let col=item.from;col<=item.to;col++){if(item.lane<dayLimit[col]){visible[col]++;if(run)run.to=col;else run={from:col,to:col}}
179
- else flush()}
180
- flush()}
175
+ const weekEvents=events.filter(event=>event.sd<=week+6&&event.ed>=week);const placed=calLanes(weekEvents,week,week+6,day=>order.has(day)&&!pad(day)?order.get(day):-1);const totals=new Array(shown.length).fill(0);for(const item of placed)for(let col=item.from;col<=item.to;col++)totals[col]++;const layout=calMonthLanes(placed,shown.length,limit);if(this.calPrinting)row.style.minHeight=Math.max(rowHeight,CAL_NUMBER+6 +(Math.max(-1,...layout.visible.map(item=>item.lane))+ 1)*CAL_LANE)+ "px";for(const item of layout.visible){const event=item.event,bar=calInAllDayRow(event)||event.ed>event.sd,element=this.calEventElement(event,bar?"bar":"chip");element.style.setProperty("--c",String(item.from));element.style.setProperty("--s",String(item.to-item.from+1));element.style.setProperty("--l",String(item.lane));if(event.sd<shown[item.from])element.classList.add("cx-cal-cont-start");if(event.ed>shown[item.to])element.classList.add("cx-cal-cont-end");cells[item.from].appendChild(element)}
181
176
  cells.forEach((cell,col)=>{if(cell.classList.contains("cx-cal-pad"))return;const day=shown[col],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))"));if(backgrounds[0].sd===day||col===0){const label=h("span","cx-cal-bglabel");setText(label,backgrounds[0].label);label.setAttribute("aria-hidden","true");cell.appendChild(label)}}
182
- const hidden=totals[col]- visible[col];cell.setAttribute("aria-label",this.calDayName(day,totals[col],backgrounds));if(options.dots&&totals[col]){const dots=h("span","cx-cal-dots");dots.setAttribute("aria-hidden","true");for(const item of placed.filter(entry=>entry.from<=col&&entry.to>=col).slice(0,3)){const dot=h("i");if(item.event.tone)dot.style.setProperty("--cx-ev",toneVariable(item.event.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));dots.appendChild(dot)}
183
- cell.appendChild(dots)}else if(hidden>0){const more=gridButton(fill(this.calLabels.calendarMore,{count:numberFormat(this.lang).format(hidden)}),()=>{});more.className="cx-cal-more-btn";more.tabIndex=-1;more.dataset.cxDay=String(day);more.setAttribute("aria-label",fill(this.calLabels.calendarMoreLabel,{count:numberFormat(this.lang).format(hidden),date:this.calFmt.longDay(day)}));more.style.setProperty("--l",String(dayLimit[col]));more.style.setProperty("--c",String(col));cell.appendChild(more)}});weeks.appendChild(row)}
177
+ const hidden=totals[col]- layout.counts[col];cell.setAttribute("aria-label",this.calDayName(day,totals[col],backgrounds));if(options.dots&&totals[col]){const dots=h("span","cx-cal-dots");dots.setAttribute("aria-hidden","true");for(const item of placed.filter(entry=>entry.from<=col&&entry.to>=col).slice(0,3)){const dot=h("i");if(item.event.tone)dot.style.setProperty("--cx-ev",toneVariable(item.event.tone,false,"var(--hfx-color-accent,light-dark(#11776f,#37c9b8))"));dots.appendChild(dot)}
178
+ cell.appendChild(dots)}else if(hidden>0){const more=gridButton(fill(this.calLabels.calendarMore,{count:numberFormat(this.lang).format(hidden)}),()=>{});more.className="cx-cal-more-btn";more.tabIndex=-1;more.dataset.cxDay=String(day);more.setAttribute("aria-label",fill(this.calLabels.calendarMoreLabel,{count:numberFormat(this.lang).format(hidden),date:this.calFmt.longDay(day)}));more.style.setProperty("--l",String(layout.more[col]));more.style.setProperty("--c",String(col));cell.appendChild(more)}});weeks.appendChild(row)}
184
179
  return grid},calWeekNumber(day){if(this.cal.weekNumbers!=="locale"){const thursday=day -(calDow(day)+ 6)%7+3,year=calDayParts(thursday).y;return Math.floor((thursday-calDayNumber(year,1,1))/ 7) + 1;
185
180
  }
186
181
  let minimal=1;try{const locale=new Intl.Locale(this.lang);minimal=(locale.getWeekInfo?.()||locale.weekInfo)?.minimalDays||1}catch{minimal=1}
@@ -197,15 +192,15 @@ 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;this.calMarkListedDay(this.calDate)},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
- 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))"))}
198
+ for(const event of events)cell.appendChild(this.calEventElement(event,"item",day));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))"))}
204
199
  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}}
@@ -18,14 +18,14 @@ background-position:top,bottom,left,right,0 0;background-repeat:no-repeat;
18
18
  .cx-data-grid .cx-row .cx-cell.cx-range-fill{outline:var(--cx-size-1px) dashed var(--cx-range-edge);outline-offset:calc(-1 * var(--hfx-focus-width,2px));}
19
19
  .cx-data-grid .cx-row .cx-cell:is(.cx-range,.cx-range-fill):not([data-cx-pin]){position:relative;}
20
20
  .cx-data-grid :is(.cx-range-handle,.cx-fill-handle){position:absolute;z-index:6;box-sizing:border-box;background:var(--cx-range-edge);touch-action:none;}
21
- .cx-data-grid .cx-range-handle{width:var(--cx-size-14px);height:var(--cx-size-14px);border:var(--cx-size-2px) solid var(--hfx-color-surface,light-dark(#ffffff,#16181c));border-radius:50%;box-shadow:0 0 0 var(--cx-size-1px) var(--cx-range-edge);}
21
+ .cx-data-grid .cx-range-handle{width:var(--cx-size-14px);height:var(--cx-size-14px);border:var(--cx-size-2px) solid var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c)));border-radius:50%;box-shadow:0 0 0 var(--cx-size-1px) var(--cx-range-edge);}
22
22
  .cx-data-grid .cx-range-handle-start{left:0;top:0;}
23
23
  .cx-data-grid .cx-range-handle-end{right:0;bottom:0;}
24
- .cx-data-grid .cx-fill-handle{right:0;bottom:0;width:var(--cx-size-7px);height:var(--cx-size-7px);border:var(--cx-size-1px) solid var(--hfx-color-surface,light-dark(#ffffff,#16181c));cursor:crosshair;}
24
+ .cx-data-grid .cx-fill-handle{right:0;bottom:0;width:var(--cx-size-7px);height:var(--cx-size-7px);border:var(--cx-size-1px) solid var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c)));cursor:crosshair;}
25
25
  .cx-data-grid .cx-fill-handle::before{content:"";position:absolute;inset:calc(var(--cx-size-6px) * -1);}
26
26
  .cx-data-grid .cx-paste-report{display:grid;grid-template-columns:1fr auto;align-items:center;gap:var(--cx-size-4px) var(--cx-size-8px);margin:0 0 var(--cx-size-6px);
27
- padding:var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-12px);border:var(--cx-size-1px) solid var(--hfx-color-border,light-dark(#e2e4e7,#272a30));border-left:var(--cx-size-3px) solid var(--hfx-color-status-warn-fg,light-dark(#8c5c05,#eeb640));
28
- border-radius:var(--hfx-radius-sm,4px);background:var(--hfx-color-surface,light-dark(#ffffff,#16181c));font-size:var(--cx-size-13px);}
27
+ padding:var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-6px) var(--cx-size-12px);border:var(--cx-size-1px) solid var(--hfx-color-surface-line,var(--hfx-color-border,light-dark(#e2e4e7,#272a30)));border-left:var(--cx-size-3px) solid var(--hfx-color-status-warn-fg,light-dark(#8c5c05,#eeb640));
28
+ border-radius:var(--hfx-radius-sm,4px);background:var(--hfx-color-surface-card,var(--hfx-color-surface,light-dark(#ffffff,#16181c)));font-size:var(--cx-size-13px);}
29
29
  .cx-data-grid .cx-paste-report p{margin:0;}
30
30
  .cx-data-grid .cx-paste-report details{grid-column:1 / -1;}
31
31
  .cx-data-grid .cx-paste-report summary{cursor:pointer;color:var(--hfx-color-accent-text,var(--hfx-color-accent,light-dark(#11776f,#37c9b8)));}
@@ -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:"cb29468954702795",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);