@event-calendar/core 5.3.2 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -6
- package/dist/index.css +1 -1
- package/dist/index.js +178 -147
- package/package.json +2 -2
- package/src/Calendar.svelte +1 -1
- package/src/lib/resources.js +5 -5
- package/src/plugins/resource-timeline/Expander.svelte +21 -14
- package/src/plugins/resource-timeline/index.js +53 -38
- package/src/storage/effects.js +16 -2
- package/src/storage/{options.svelte.js → options.js} +44 -49
- package/src/storage/proxy.svelte.js +2 -2
- package/src/storage/state.svelte.js +11 -20
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ See [demo](https://vkurko.github.io/calendar/) and [changelog](CHANGELOG.md).
|
|
|
5
5
|
Full-sized drag & drop JavaScript event calendar with resource & timeline views:
|
|
6
6
|
|
|
7
7
|
* Lightweight (35kb [br](https://en.wikipedia.org/wiki/Brotli) compressed)
|
|
8
|
-
*
|
|
8
|
+
* Feature-rich, performant, and with minimal DOM structure (thanks to [CSS Grid](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout))
|
|
9
9
|
* Zero-dependency (standalone bundle)
|
|
10
10
|
* Used on over 70,000 websites with [Bookly](https://wordpress.org/plugins/bookly-responsive-appointment-booking-tool/)
|
|
11
11
|
|
|
@@ -68,9 +68,9 @@ Inspired by [FullCalendar](https://fullcalendar.io/), it implements similar opti
|
|
|
68
68
|
- [eventDragStart](#eventdragstart)
|
|
69
69
|
- [eventDragStop](#eventdragstop)
|
|
70
70
|
- [eventDrop](#eventdrop)
|
|
71
|
+
- [eventDurationEditable](#eventdurationeditable)
|
|
71
72
|
</td><td>
|
|
72
73
|
|
|
73
|
-
- [eventDurationEditable](#eventdurationeditable)
|
|
74
74
|
- [eventFilter](#eventfilter)
|
|
75
75
|
- [eventLongPressDelay](#eventlongpressdelay)
|
|
76
76
|
- [eventMouseEnter](#eventmouseenter)
|
|
@@ -92,6 +92,7 @@ Inspired by [FullCalendar](https://fullcalendar.io/), it implements similar opti
|
|
|
92
92
|
- [height](#height)
|
|
93
93
|
- [hiddenDays](#hiddendays)
|
|
94
94
|
- [highlightedDates](#highlighteddates)
|
|
95
|
+
- [icons](#icons)
|
|
95
96
|
- [lazyFetching](#lazyfetching)
|
|
96
97
|
- [listDayFormat](#listdayformat)
|
|
97
98
|
- [listDaySideFormat](#listdaysideformat)
|
|
@@ -102,11 +103,12 @@ Inspired by [FullCalendar](https://fullcalendar.io/), it implements similar opti
|
|
|
102
103
|
- [noEventsClick](#noeventsclick)
|
|
103
104
|
- [noEventsContent](#noeventscontent)
|
|
104
105
|
- [nowIndicator](#nowindicator)
|
|
106
|
+
- [pointer](#pointer)
|
|
105
107
|
</td><td>
|
|
106
108
|
|
|
107
|
-
- [pointer](#pointer)
|
|
108
109
|
- [refetchResourcesOnNavigate](#refetchresourcesonnavigate)
|
|
109
110
|
- [resizeConstraint](#resizeconstraint)
|
|
111
|
+
- [resourceExpand](#resourceexpand)
|
|
110
112
|
- [resources](#resources)
|
|
111
113
|
- [resourceLabelContent](#resourcelabelcontent)
|
|
112
114
|
- [resourceLabelDidMount](#resourcelabeldidmount)
|
|
@@ -251,8 +253,8 @@ This bundle contains a version of the calendar that includes all plugins and is
|
|
|
251
253
|
|
|
252
254
|
The first step is to include the following lines of code in the `<head>` section of your page:
|
|
253
255
|
```html
|
|
254
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@event-calendar/build@5.
|
|
255
|
-
<script src="https://cdn.jsdelivr.net/npm/@event-calendar/build@5.
|
|
256
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@event-calendar/build@5.4.0/dist/event-calendar.min.css">
|
|
257
|
+
<script src="https://cdn.jsdelivr.net/npm/@event-calendar/build@5.4.0/dist/event-calendar.min.js"></script>
|
|
256
258
|
```
|
|
257
259
|
|
|
258
260
|
<details>
|
|
@@ -1829,6 +1831,31 @@ Array of dates that need to be highlighted in the calendar.
|
|
|
1829
1831
|
|
|
1830
1832
|
Each date can be either an ISO8601 date string like `'2026-12-31'`, or a JavaScript Date object.
|
|
1831
1833
|
|
|
1834
|
+
### icons
|
|
1835
|
+
- Type `object`
|
|
1836
|
+
- Default `{collapse: {html: '−'}, expand: {html: '+'}}`
|
|
1837
|
+
|
|
1838
|
+
Defines icons used in some buttons, such as those for expanding nested resources in `resourceTimeline` views.
|
|
1839
|
+
|
|
1840
|
+
Each icon is specified as a [Content](#content) value.
|
|
1841
|
+
|
|
1842
|
+
This option can be either a plain object with all necessary properties, or a callback function that receives default icons object and should return a new one:
|
|
1843
|
+
|
|
1844
|
+
```js
|
|
1845
|
+
function (icons) {
|
|
1846
|
+
// return new icons object
|
|
1847
|
+
}
|
|
1848
|
+
```
|
|
1849
|
+
<table>
|
|
1850
|
+
<tr>
|
|
1851
|
+
<td>
|
|
1852
|
+
|
|
1853
|
+
`icons`
|
|
1854
|
+
</td>
|
|
1855
|
+
<td>An object with default icons</td>
|
|
1856
|
+
</tr>
|
|
1857
|
+
</table>
|
|
1858
|
+
|
|
1832
1859
|
### lazyFetching
|
|
1833
1860
|
- Type `boolean`
|
|
1834
1861
|
- Default `true`
|
|
@@ -2029,6 +2056,47 @@ Callback function that limits the date/time range within which the event is allo
|
|
|
2029
2056
|
|
|
2030
2057
|
The function is triggered during resizing for each cursor movement and takes the same parameters as [eventResize](#eventresize). The function should return `true` if the new size is allowed, and `false` otherwise.
|
|
2031
2058
|
|
|
2059
|
+
### resourceExpand
|
|
2060
|
+
- Type `function`
|
|
2061
|
+
- Default `undefined`
|
|
2062
|
+
|
|
2063
|
+
Callback function that is triggered when a resource with nested children is expanded or collapsed in `resourceTimeline` views.
|
|
2064
|
+
|
|
2065
|
+
|
|
2066
|
+
```js
|
|
2067
|
+
function (info) { }
|
|
2068
|
+
```
|
|
2069
|
+
`info` is an object with the following properties:
|
|
2070
|
+
<table>
|
|
2071
|
+
<tr>
|
|
2072
|
+
<td>
|
|
2073
|
+
|
|
2074
|
+
`resource`
|
|
2075
|
+
</td>
|
|
2076
|
+
<td>
|
|
2077
|
+
|
|
2078
|
+
The associated [Resource](#resource-object) object
|
|
2079
|
+
</td>
|
|
2080
|
+
</tr>
|
|
2081
|
+
<tr>
|
|
2082
|
+
<td>
|
|
2083
|
+
|
|
2084
|
+
`jsEvent`
|
|
2085
|
+
</td>
|
|
2086
|
+
<td>JavaScript native event object with low-level information such as click coordinates</td>
|
|
2087
|
+
</tr>
|
|
2088
|
+
<tr>
|
|
2089
|
+
<td>
|
|
2090
|
+
|
|
2091
|
+
`view`
|
|
2092
|
+
</td>
|
|
2093
|
+
<td>
|
|
2094
|
+
|
|
2095
|
+
The current [View](#view-object) object
|
|
2096
|
+
</td>
|
|
2097
|
+
</tr>
|
|
2098
|
+
</table>
|
|
2099
|
+
|
|
2032
2100
|
### resources
|
|
2033
2101
|
- Type `array`, `object` or `function`
|
|
2034
2102
|
- Default `[]`
|
|
@@ -3263,6 +3331,16 @@ The title of the resource. See [Content](#content)
|
|
|
3263
3331
|
<tr>
|
|
3264
3332
|
<td>
|
|
3265
3333
|
|
|
3334
|
+
`expanded`
|
|
3335
|
+
</td>
|
|
3336
|
+
<td>
|
|
3337
|
+
|
|
3338
|
+
A flag indicating whether the resource is expanded or collapsed if it has nested children
|
|
3339
|
+
</td>
|
|
3340
|
+
</tr>
|
|
3341
|
+
<tr>
|
|
3342
|
+
<td>
|
|
3343
|
+
|
|
3266
3344
|
`extendedProps`
|
|
3267
3345
|
</td>
|
|
3268
3346
|
<td>
|
|
@@ -3320,6 +3398,16 @@ Here are all admissible fields for the resource’s input object:
|
|
|
3320
3398
|
<tr>
|
|
3321
3399
|
<td>
|
|
3322
3400
|
|
|
3401
|
+
`expanded`
|
|
3402
|
+
</td>
|
|
3403
|
+
<td>
|
|
3404
|
+
|
|
3405
|
+
`boolean` Specifies whether the resource with nested children will be expanded or collapsed. Default `true`
|
|
3406
|
+
</td>
|
|
3407
|
+
</tr>
|
|
3408
|
+
<tr>
|
|
3409
|
+
<td>
|
|
3410
|
+
|
|
3323
3411
|
`extendedProps`
|
|
3324
3412
|
</td>
|
|
3325
3413
|
<td>
|
|
@@ -3336,7 +3424,7 @@ Here are all admissible fields for the resource’s input object:
|
|
|
3336
3424
|
</tr>
|
|
3337
3425
|
</table>
|
|
3338
3426
|
|
|
3339
|
-
The `
|
|
3427
|
+
The `resourceTimeline` views support displaying nested resources. Nested resources can be collapsed or expanded using an additional button that appears before the parent resource name. To pass nested resources, use the `children` field:
|
|
3340
3428
|
|
|
3341
3429
|
```js
|
|
3342
3430
|
resources: [
|
package/dist/index.css
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* EventCalendar v5.
|
|
2
|
+
* EventCalendar v5.4.0
|
|
3
3
|
* https://github.com/vkurko/calendar
|
|
4
4
|
*/
|
|
5
5
|
import { untrack, tick, getAbortSignal, getContext, setContext, onMount, mount, unmount } from "svelte";
|
|
@@ -679,10 +679,10 @@ function outsideRange(date, range) {
|
|
|
679
679
|
}
|
|
680
680
|
function createResources(input) {
|
|
681
681
|
let result = [];
|
|
682
|
-
_createResources(input, 0, result);
|
|
682
|
+
_createResources(input, 0, false, result);
|
|
683
683
|
return result;
|
|
684
684
|
}
|
|
685
|
-
function _createResources(input, level, flat) {
|
|
685
|
+
function _createResources(input, level, hidden, flat) {
|
|
686
686
|
let result = [];
|
|
687
687
|
for (let item of input) {
|
|
688
688
|
let resource = createResource(item);
|
|
@@ -691,12 +691,11 @@ function _createResources(input, level, flat) {
|
|
|
691
691
|
let payload = {
|
|
692
692
|
level,
|
|
693
693
|
children: [],
|
|
694
|
-
|
|
695
|
-
hidden: false
|
|
694
|
+
hidden
|
|
696
695
|
};
|
|
697
696
|
setPayload(resource, payload);
|
|
698
697
|
if (item.children) {
|
|
699
|
-
payload.children = _createResources(item.children, level + 1, flat);
|
|
698
|
+
payload.children = _createResources(item.children, level + 1, hidden || !resource.expanded, flat);
|
|
700
699
|
}
|
|
701
700
|
}
|
|
702
701
|
return result;
|
|
@@ -707,6 +706,7 @@ function createResource(input) {
|
|
|
707
706
|
title: input.title || "",
|
|
708
707
|
eventBackgroundColor: eventBackgroundColor(input),
|
|
709
708
|
eventTextColor: eventTextColor(input),
|
|
709
|
+
expanded: input.expanded ?? true,
|
|
710
710
|
extendedProps: input.extendedProps ?? {}
|
|
711
711
|
};
|
|
712
712
|
}
|
|
@@ -793,24 +793,32 @@ function proxy(target, setDependency, hasEffect, invokeEffect) {
|
|
|
793
793
|
},
|
|
794
794
|
set(target2, prop, value, receiver) {
|
|
795
795
|
let has = hasEffect(target2[prop], value);
|
|
796
|
-
Reflect.set(target2, prop, value, receiver);
|
|
796
|
+
let result = Reflect.set(target2, prop, value, receiver);
|
|
797
797
|
if (has) {
|
|
798
798
|
invokeEffect(prop);
|
|
799
799
|
}
|
|
800
|
-
return
|
|
800
|
+
return result;
|
|
801
801
|
}
|
|
802
802
|
});
|
|
803
803
|
}
|
|
804
804
|
function createOptions(plugins) {
|
|
805
805
|
let options = {
|
|
806
|
-
buttonText: {
|
|
806
|
+
buttonText: {
|
|
807
|
+
today: "today"
|
|
808
|
+
},
|
|
807
809
|
customButtons: {},
|
|
808
810
|
customScrollbars: false,
|
|
809
811
|
// ec option
|
|
810
812
|
date: /* @__PURE__ */ new Date(),
|
|
811
813
|
datesSet: void 0,
|
|
812
|
-
dayHeaderFormat: {
|
|
813
|
-
|
|
814
|
+
dayHeaderFormat: {
|
|
815
|
+
weekday: "short",
|
|
816
|
+
month: "numeric",
|
|
817
|
+
day: "numeric"
|
|
818
|
+
},
|
|
819
|
+
dayHeaderAriaLabelFormat: {
|
|
820
|
+
dateStyle: "full"
|
|
821
|
+
},
|
|
814
822
|
displayEventEnd: true,
|
|
815
823
|
duration: { weeks: 1 },
|
|
816
824
|
events: [],
|
|
@@ -828,14 +836,23 @@ function createOptions(plugins) {
|
|
|
828
836
|
eventOrder: void 0,
|
|
829
837
|
eventSources: [],
|
|
830
838
|
eventTextColor: void 0,
|
|
831
|
-
eventTimeFormat: {
|
|
839
|
+
eventTimeFormat: {
|
|
840
|
+
hour: "numeric",
|
|
841
|
+
minute: "2-digit"
|
|
842
|
+
},
|
|
832
843
|
filterEventsWithResources: false,
|
|
833
844
|
firstDay: 0,
|
|
834
|
-
headerToolbar: {
|
|
845
|
+
headerToolbar: {
|
|
846
|
+
start: "title",
|
|
847
|
+
center: "",
|
|
848
|
+
end: "today prev,next"
|
|
849
|
+
},
|
|
835
850
|
height: void 0,
|
|
836
851
|
hiddenDays: [],
|
|
837
852
|
highlightedDates: [],
|
|
838
853
|
// ec option
|
|
854
|
+
icons: {},
|
|
855
|
+
// ec option
|
|
839
856
|
lazyFetching: true,
|
|
840
857
|
loading: void 0,
|
|
841
858
|
locale: void 0,
|
|
@@ -874,17 +891,13 @@ function createOptions(plugins) {
|
|
|
874
891
|
title: "ec-title",
|
|
875
892
|
toolbar: "ec-toolbar",
|
|
876
893
|
view: "",
|
|
877
|
-
weekdays: [
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
"ec-fri",
|
|
884
|
-
"ec-sat"
|
|
885
|
-
]
|
|
894
|
+
weekdays: ["ec-sun", "ec-mon", "ec-tue", "ec-wed", "ec-thu", "ec-fri", "ec-sat"]
|
|
895
|
+
},
|
|
896
|
+
titleFormat: {
|
|
897
|
+
year: "numeric",
|
|
898
|
+
month: "short",
|
|
899
|
+
day: "numeric"
|
|
886
900
|
},
|
|
887
|
-
titleFormat: { year: "numeric", month: "short", day: "numeric" },
|
|
888
901
|
validRange: void 0,
|
|
889
902
|
view: void 0,
|
|
890
903
|
viewDidMount: void 0,
|
|
@@ -911,52 +924,48 @@ function createParsers(plugins) {
|
|
|
911
924
|
}
|
|
912
925
|
return parsers;
|
|
913
926
|
}
|
|
914
|
-
const specialOptions = ["buttonText", "customButtons", "theme"];
|
|
915
|
-
function optionsState(
|
|
927
|
+
const specialOptions = ["buttonText", "customButtons", "icons", "theme"];
|
|
928
|
+
function optionsState(plugins, userOptions) {
|
|
916
929
|
let defOptions = createOptions(plugins);
|
|
917
930
|
let parsers = createParsers(plugins);
|
|
918
931
|
defOptions = parseOptions(defOptions, parsers);
|
|
919
932
|
userOptions = parseOptions(userOptions, parsers);
|
|
920
|
-
let
|
|
921
|
-
let
|
|
933
|
+
let defViews = extractOption(defOptions, "views") ?? {};
|
|
934
|
+
let userViews = extractOption(userOptions, "views") ?? {};
|
|
922
935
|
let options = objectProxy({});
|
|
923
936
|
assign(options, defOptions);
|
|
937
|
+
if (userOptions.view) {
|
|
938
|
+
options.view = userOptions.view;
|
|
939
|
+
}
|
|
924
940
|
let setters = {};
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
let
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
if (!setters[key]) {
|
|
939
|
-
setters[key] = [];
|
|
940
|
-
}
|
|
941
|
-
setters[key].push(specialOptions.includes(key) ? (value) => opts[key] = isFunction(value) ? value(defOpts[key]) : value : (value) => opts[key] = value);
|
|
942
|
-
} else {
|
|
943
|
-
delete opts[key];
|
|
941
|
+
let viewOptions = {};
|
|
942
|
+
let viewComponents = {};
|
|
943
|
+
let views = /* @__PURE__ */ new Set([...keys(defViews), ...keys(userViews)]);
|
|
944
|
+
for (let view2 of views) {
|
|
945
|
+
let userViewOptions = userViews[view2] ?? {};
|
|
946
|
+
let defOpts = mergeOpts(defOptions, defViews[view2] ?? defViews[userViewOptions.type] ?? {});
|
|
947
|
+
let opts = mergeOpts(defOpts, userOptions, userViewOptions);
|
|
948
|
+
let component = extractOption(opts, "component");
|
|
949
|
+
delete opts.view;
|
|
950
|
+
for (let key of keys(opts)) {
|
|
951
|
+
if (hasOwn(options, key)) {
|
|
952
|
+
if (!setters[key]) {
|
|
953
|
+
setters[key] = [];
|
|
944
954
|
}
|
|
955
|
+
setters[key].push(
|
|
956
|
+
specialOptions.includes(key) ? (value) => opts[key] = isFunction(value) ? value(defOpts[key]) : value : (value) => opts[key] = value
|
|
957
|
+
);
|
|
958
|
+
} else {
|
|
959
|
+
delete opts[key];
|
|
945
960
|
}
|
|
946
|
-
$.user_pre_effect(() => {
|
|
947
|
-
let newView = options["view"];
|
|
948
|
-
untrack(() => {
|
|
949
|
-
if (newView === view2) {
|
|
950
|
-
mainState.setViewComponent(component);
|
|
951
|
-
assign(options, opts);
|
|
952
|
-
}
|
|
953
|
-
});
|
|
954
|
-
});
|
|
955
961
|
}
|
|
962
|
+
viewOptions[view2] = opts;
|
|
963
|
+
viewComponents[view2] = component;
|
|
956
964
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
965
|
+
assign(options, viewOptions[options.view]);
|
|
966
|
+
return [
|
|
967
|
+
options,
|
|
968
|
+
function setOption(key, value, parsed = true) {
|
|
960
969
|
if (hasOwn(options, key)) {
|
|
961
970
|
if (!parsed) {
|
|
962
971
|
if (key in parsers) {
|
|
@@ -971,8 +980,11 @@ function optionsState(mainState, plugins, userOptions) {
|
|
|
971
980
|
options[key] = value;
|
|
972
981
|
}
|
|
973
982
|
},
|
|
974
|
-
|
|
975
|
-
|
|
983
|
+
function setViewOptions(view2) {
|
|
984
|
+
assign(options, viewOptions[view2]);
|
|
985
|
+
return viewComponents[view2];
|
|
986
|
+
}
|
|
987
|
+
];
|
|
976
988
|
}
|
|
977
989
|
function parseOptions(opts, parsers) {
|
|
978
990
|
let result = { ...opts };
|
|
@@ -1003,7 +1015,11 @@ function mergeOpts(...args) {
|
|
|
1003
1015
|
override[key] = opts[key](result[key]);
|
|
1004
1016
|
}
|
|
1005
1017
|
}
|
|
1006
|
-
result = {
|
|
1018
|
+
result = {
|
|
1019
|
+
...result,
|
|
1020
|
+
...opts,
|
|
1021
|
+
...override
|
|
1022
|
+
};
|
|
1007
1023
|
}
|
|
1008
1024
|
return result;
|
|
1009
1025
|
}
|
|
@@ -1016,6 +1032,17 @@ function diff(options, prevOptions) {
|
|
|
1016
1032
|
}
|
|
1017
1033
|
return diff2;
|
|
1018
1034
|
}
|
|
1035
|
+
function switchView(mainState) {
|
|
1036
|
+
return () => {
|
|
1037
|
+
let { options: { view: view2 } } = mainState;
|
|
1038
|
+
untrack(() => {
|
|
1039
|
+
let initComponent = mainState.setViewOptions(view2);
|
|
1040
|
+
mainState.extensions = {};
|
|
1041
|
+
mainState.features = [];
|
|
1042
|
+
mainState.viewComponent = initComponent(mainState);
|
|
1043
|
+
});
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1019
1046
|
function loadEvents(mainState, loadingInvoker) {
|
|
1020
1047
|
return () => {
|
|
1021
1048
|
let {
|
|
@@ -1120,10 +1147,10 @@ function load(sources, defaultResult, parseResult, applyResult, activeRange2, fe
|
|
|
1120
1147
|
assign(fetchedRange, activeRange2);
|
|
1121
1148
|
}
|
|
1122
1149
|
}
|
|
1123
|
-
function createLoadingInvoker(
|
|
1150
|
+
function createLoadingInvoker(mainState) {
|
|
1124
1151
|
let counter = 0;
|
|
1125
1152
|
function invoke(value) {
|
|
1126
|
-
let { loading } =
|
|
1153
|
+
let { options: { loading } } = mainState;
|
|
1127
1154
|
if (isFunction(loading)) {
|
|
1128
1155
|
loading(value);
|
|
1129
1156
|
}
|
|
@@ -1455,20 +1482,20 @@ class State {
|
|
|
1455
1482
|
set iClass(value) {
|
|
1456
1483
|
$.set(this.#iClass, value, true);
|
|
1457
1484
|
}
|
|
1458
|
-
|
|
1485
|
+
options;
|
|
1486
|
+
setOption;
|
|
1487
|
+
setViewOptions;
|
|
1459
1488
|
constructor(plugins, options) {
|
|
1460
|
-
|
|
1461
|
-
this.options = state;
|
|
1462
|
-
this.#setOption = setOption;
|
|
1489
|
+
[this.options, this.setOption, this.setViewOptions] = optionsState(plugins, options);
|
|
1463
1490
|
this.#auxComponents = $.state($.proxy([]));
|
|
1464
1491
|
this.#currentRange = $.derived(currentRange(this));
|
|
1465
1492
|
this.#activeRange = $.derived(activeRange(this));
|
|
1466
1493
|
this.#fetchedRange = $.state($.proxy({ events: {}, resources: {} }));
|
|
1467
|
-
this.#events = $.state(arrayProxy(
|
|
1494
|
+
this.#events = $.state(arrayProxy(this.options.events));
|
|
1468
1495
|
this.#filteredEvents = $.derived(filteredEvents(this));
|
|
1469
1496
|
this.#mainEl = $.state();
|
|
1470
1497
|
this.#now = $.state($.proxy(createDate()));
|
|
1471
|
-
this.#resources = $.state(arrayProxy(
|
|
1498
|
+
this.#resources = $.state(arrayProxy(this.options.resources));
|
|
1472
1499
|
this.#today = $.state($.proxy(setMidnight(createDate())));
|
|
1473
1500
|
this.#intlEventTime = $.derived(intlRange(this, "eventTimeFormat"));
|
|
1474
1501
|
this.#intlDayHeader = $.derived(intl(this, "dayHeaderFormat"));
|
|
@@ -1487,11 +1514,11 @@ class State {
|
|
|
1487
1514
|
for (let plugin of plugins) {
|
|
1488
1515
|
plugin.initState?.(this);
|
|
1489
1516
|
}
|
|
1490
|
-
initEffects();
|
|
1491
1517
|
this.#initEffects();
|
|
1492
1518
|
}
|
|
1493
1519
|
#initEffects() {
|
|
1494
|
-
let loading = createLoadingInvoker(this
|
|
1520
|
+
let loading = createLoadingInvoker(this);
|
|
1521
|
+
$.user_pre_effect(switchView(this));
|
|
1495
1522
|
$.user_pre_effect(setNowAndToday(this));
|
|
1496
1523
|
$.user_effect(loadEvents(this, loading));
|
|
1497
1524
|
$.user_effect(loadResources(this, loading));
|
|
@@ -1499,14 +1526,6 @@ class State {
|
|
|
1499
1526
|
$.user_effect(runEventAllUpdated(this));
|
|
1500
1527
|
$.user_effect(runViewDidMount(this));
|
|
1501
1528
|
}
|
|
1502
|
-
setViewComponent(component) {
|
|
1503
|
-
this.extensions = {};
|
|
1504
|
-
this.features = [];
|
|
1505
|
-
this.viewComponent = component(this);
|
|
1506
|
-
}
|
|
1507
|
-
setOption(name, value, parsed = true) {
|
|
1508
|
-
this.#setOption(name, value, parsed);
|
|
1509
|
-
}
|
|
1510
1529
|
}
|
|
1511
1530
|
var root_2$5 = $.from_html(`<h2></h2>`);
|
|
1512
1531
|
var root_4$1 = $.from_html(`<button><i></i></button>`);
|
|
@@ -5558,29 +5577,36 @@ function Event($$anchor, $$props) {
|
|
|
5558
5577
|
return $.pop($$exports);
|
|
5559
5578
|
}
|
|
5560
5579
|
var root_1$2 = $.from_html(`<span></span>`);
|
|
5561
|
-
var root_2 = $.from_html(`<button
|
|
5580
|
+
var root_2 = $.from_html(`<button></button>`);
|
|
5562
5581
|
var root = $.from_html(`<!> <span><!></span>`, 1);
|
|
5563
5582
|
function Expander($$anchor, $$props) {
|
|
5564
5583
|
$.push($$props, true);
|
|
5565
|
-
let
|
|
5584
|
+
let resource = $.prop($$props, "resource", 7);
|
|
5585
|
+
let $$d = $.derived(() => getContext("state")), resources = $.derived(() => $.get($$d).resources), view2 = $.derived(() => $.get($$d).view), buttonText = $.derived(() => $.get($$d).options.buttonText), icons = $.derived(() => $.get($$d).options.icons), resourceExpand = $.derived(() => $.get($$d).options.resourceExpand), theme = $.derived(() => $.get($$d).options.theme);
|
|
5566
5586
|
let payload = $.state({});
|
|
5567
|
-
let expanded = $.
|
|
5587
|
+
let expanded = $.derived(() => resource().expanded);
|
|
5588
|
+
let title = $.derived(() => $.get(buttonText)[$.get(expanded) ? "collapse" : "expand"]);
|
|
5568
5589
|
$.user_pre_effect(() => {
|
|
5569
|
-
$.set(payload, getPayload(
|
|
5570
|
-
$.set(expanded, $.get(payload).expanded, true);
|
|
5590
|
+
$.set(payload, getPayload(resource()));
|
|
5571
5591
|
});
|
|
5572
|
-
function onclick() {
|
|
5573
|
-
$.set(expanded, !$.get(expanded));
|
|
5574
|
-
$.get(payload).
|
|
5575
|
-
toggle($.get(payload).children, $.get(expanded));
|
|
5592
|
+
function onclick(jsEvent) {
|
|
5593
|
+
resource().expanded = $.set(expanded, !$.get(expanded));
|
|
5594
|
+
toggle($.get(payload).children);
|
|
5576
5595
|
$.get(resources).length = $.get(resources).length;
|
|
5596
|
+
if (isFunction($.get(resourceExpand))) {
|
|
5597
|
+
$.get(resourceExpand)({
|
|
5598
|
+
resource: resource(),
|
|
5599
|
+
jsEvent,
|
|
5600
|
+
view: toViewWithLocalDates($.get(view2))
|
|
5601
|
+
});
|
|
5602
|
+
}
|
|
5577
5603
|
}
|
|
5578
|
-
function toggle(children
|
|
5604
|
+
function toggle(children) {
|
|
5579
5605
|
for (let child of children) {
|
|
5580
5606
|
let payload2 = getPayload(child);
|
|
5581
|
-
payload2.hidden =
|
|
5582
|
-
if (
|
|
5583
|
-
toggle(payload2.children
|
|
5607
|
+
payload2.hidden = !$.get(expanded);
|
|
5608
|
+
if (child.expanded) {
|
|
5609
|
+
toggle(payload2.children);
|
|
5584
5610
|
}
|
|
5585
5611
|
}
|
|
5586
5612
|
}
|
|
@@ -5594,30 +5620,19 @@ function Expander($$anchor, $$props) {
|
|
|
5594
5620
|
var span_1 = $.sibling(node, 2);
|
|
5595
5621
|
var node_1 = $.child(span_1);
|
|
5596
5622
|
{
|
|
5597
|
-
var
|
|
5623
|
+
var consequent = ($$anchor2) => {
|
|
5598
5624
|
var button = root_2();
|
|
5599
5625
|
button.__click = onclick;
|
|
5600
|
-
|
|
5601
|
-
{
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
var alternate = ($$anchor3) => {
|
|
5607
|
-
var text_1 = $.text("+");
|
|
5608
|
-
$.append($$anchor3, text_1);
|
|
5609
|
-
};
|
|
5610
|
-
$.if(node_2, ($$render) => {
|
|
5611
|
-
if ($.get(expanded)) $$render(consequent);
|
|
5612
|
-
else $$render(alternate, false);
|
|
5613
|
-
});
|
|
5614
|
-
}
|
|
5615
|
-
$.reset(button);
|
|
5616
|
-
$.template_effect(() => $.set_class(button, 1, $.get(theme).button));
|
|
5626
|
+
$.attach(button, () => contentFrom($.get(icons)[$.get(expanded) ? "collapse" : "expand"]));
|
|
5627
|
+
$.template_effect(() => {
|
|
5628
|
+
$.set_class(button, 1, $.get(theme).button);
|
|
5629
|
+
$.set_attribute(button, "aria-label", $.get(title));
|
|
5630
|
+
$.set_attribute(button, "title", $.get(title));
|
|
5631
|
+
});
|
|
5617
5632
|
$.append($$anchor2, button);
|
|
5618
5633
|
};
|
|
5619
5634
|
$.if(node_1, ($$render) => {
|
|
5620
|
-
if ($.get(payload).children?.length) $$render(
|
|
5635
|
+
if ($.get(payload).children?.length) $$render(consequent);
|
|
5621
5636
|
});
|
|
5622
5637
|
}
|
|
5623
5638
|
$.reset(span_1);
|
|
@@ -5949,43 +5964,59 @@ const index$1 = {
|
|
|
5949
5964
|
createOptions(options) {
|
|
5950
5965
|
createTRROptions(options);
|
|
5951
5966
|
createRROptions(options);
|
|
5952
|
-
options
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
options.
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
};
|
|
5969
|
-
options.
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
day: "numeric"
|
|
5967
|
+
assign(options, {
|
|
5968
|
+
resourceExpand: void 0,
|
|
5969
|
+
slotWidth: 32,
|
|
5970
|
+
// Common options
|
|
5971
|
+
view: "resourceTimelineWeek"
|
|
5972
|
+
});
|
|
5973
|
+
assign(options.buttonText, {
|
|
5974
|
+
expand: "Expand",
|
|
5975
|
+
collapse: "Collapse",
|
|
5976
|
+
resourceTimelineDay: "timeline",
|
|
5977
|
+
resourceTimelineWeek: "timeline",
|
|
5978
|
+
resourceTimelineMonth: "timeline"
|
|
5979
|
+
});
|
|
5980
|
+
assign(options.icons, {
|
|
5981
|
+
collapse: { html: "−" },
|
|
5982
|
+
expand: { html: "+" }
|
|
5983
|
+
});
|
|
5984
|
+
assign(options.theme, {
|
|
5985
|
+
expander: "ec-expander",
|
|
5986
|
+
rowHead: "ec-row-head",
|
|
5987
|
+
slots: "ec-slots"
|
|
5988
|
+
});
|
|
5989
|
+
assign(options.views, {
|
|
5990
|
+
resourceTimelineDay: {
|
|
5991
|
+
buttonText: btnTextDay,
|
|
5992
|
+
component: initViewComponent$1,
|
|
5993
|
+
displayEventEnd: false,
|
|
5994
|
+
dayHeaderFormat: { weekday: "long" },
|
|
5995
|
+
duration: { days: 1 },
|
|
5996
|
+
theme: themeView("ec-resource ec-timeline ec-day-view"),
|
|
5997
|
+
titleFormat: { year: "numeric", month: "long", day: "numeric" }
|
|
5983
5998
|
},
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5999
|
+
resourceTimelineWeek: {
|
|
6000
|
+
buttonText: btnTextWeek,
|
|
6001
|
+
component: initViewComponent$1,
|
|
6002
|
+
displayEventEnd: false,
|
|
6003
|
+
duration: { weeks: 1 },
|
|
6004
|
+
theme: themeView("ec-resource ec-timeline ec-week-view")
|
|
6005
|
+
},
|
|
6006
|
+
resourceTimelineMonth: {
|
|
6007
|
+
buttonText: btnTextMonth,
|
|
6008
|
+
component: initMonthViewComponent,
|
|
6009
|
+
displayEventEnd: false,
|
|
6010
|
+
dayHeaderFormat: {
|
|
6011
|
+
weekday: "short",
|
|
6012
|
+
day: "numeric"
|
|
6013
|
+
},
|
|
6014
|
+
duration: { months: 1 },
|
|
6015
|
+
slotDuration: { days: 1 },
|
|
6016
|
+
theme: themeView("ec-resource ec-timeline ec-month-view"),
|
|
6017
|
+
titleFormat: { year: "numeric", month: "long" }
|
|
6018
|
+
}
|
|
6019
|
+
});
|
|
5989
6020
|
},
|
|
5990
6021
|
createParsers(parsers) {
|
|
5991
6022
|
createTRRParsers(parsers);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event-calendar/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"title": "Event Calendar Core package",
|
|
5
5
|
"description": "Full-sized drag & drop event calendar with resource & timeline views",
|
|
6
6
|
"keywords": [
|
|
@@ -32,6 +32,6 @@
|
|
|
32
32
|
"#components": "./src/lib/components/index.js"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"svelte": "^5.
|
|
35
|
+
"svelte": "^5.50.1"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/Calendar.svelte
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
prevDate, toEventWithLocalDates, toLocalDate, toViewWithLocalDates
|
|
7
7
|
} from '#lib';
|
|
8
8
|
import MainState from './storage/state.svelte.js';
|
|
9
|
-
import {diff} from './storage/options.
|
|
9
|
+
import {diff} from './storage/options.js';
|
|
10
10
|
import Toolbar from './Toolbar.svelte';
|
|
11
11
|
|
|
12
12
|
let {plugins = [], options = {}} = $props();
|
package/src/lib/resources.js
CHANGED
|
@@ -3,11 +3,11 @@ import {empty} from './utils.js';
|
|
|
3
3
|
|
|
4
4
|
export function createResources(input) {
|
|
5
5
|
let result = [];
|
|
6
|
-
_createResources(input, 0, result);
|
|
6
|
+
_createResources(input, 0, false, result);
|
|
7
7
|
return result;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
function _createResources(input, level, flat) {
|
|
10
|
+
function _createResources(input, level, hidden, flat) {
|
|
11
11
|
let result = [];
|
|
12
12
|
for (let item of input) {
|
|
13
13
|
let resource = createResource(item);
|
|
@@ -16,12 +16,11 @@ function _createResources(input, level, flat) {
|
|
|
16
16
|
let payload = {
|
|
17
17
|
level,
|
|
18
18
|
children: [],
|
|
19
|
-
|
|
20
|
-
hidden: false
|
|
19
|
+
hidden
|
|
21
20
|
};
|
|
22
21
|
setPayload(resource, payload);
|
|
23
22
|
if (item.children) {
|
|
24
|
-
payload.children = _createResources(item.children, level + 1, flat);
|
|
23
|
+
payload.children = _createResources(item.children, level + 1, hidden || !resource.expanded, flat);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
return result;
|
|
@@ -33,6 +32,7 @@ export function createResource(input) {
|
|
|
33
32
|
title: input.title || '',
|
|
34
33
|
eventBackgroundColor: eventBackgroundColor(input),
|
|
35
34
|
eventTextColor: eventTextColor(input),
|
|
35
|
+
expanded: input.expanded ?? true,
|
|
36
36
|
extendedProps: input.extendedProps ?? {}
|
|
37
37
|
};
|
|
38
38
|
}
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import {getContext} from 'svelte';
|
|
3
|
-
import {getPayload} from '#lib';
|
|
3
|
+
import {contentFrom, getPayload, isFunction, toViewWithLocalDates} from '#lib';
|
|
4
4
|
|
|
5
5
|
let {resource} = $props();
|
|
6
6
|
|
|
7
|
-
let {resources, options: {theme}} = $derived(getContext('state'));
|
|
7
|
+
let {resources, view, options: {buttonText, icons, resourceExpand, theme}} = $derived(getContext('state'));
|
|
8
8
|
|
|
9
9
|
let payload = $state.raw({});
|
|
10
|
-
let expanded = $
|
|
10
|
+
let expanded = $derived(resource.expanded);
|
|
11
|
+
let title = $derived(buttonText[expanded ? 'collapse' : 'expand']);
|
|
11
12
|
|
|
12
13
|
$effect.pre(() => {
|
|
13
14
|
payload = getPayload(resource);
|
|
14
|
-
expanded = payload.expanded;
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
function onclick() {
|
|
18
|
-
expanded = !expanded;
|
|
19
|
-
payload.
|
|
20
|
-
toggle(payload.children, expanded);
|
|
17
|
+
function onclick(jsEvent) {
|
|
18
|
+
resource.expanded = expanded = !expanded;
|
|
19
|
+
toggle(payload.children);
|
|
21
20
|
resources.length = resources.length;
|
|
21
|
+
if (isFunction(resourceExpand)) {
|
|
22
|
+
resourceExpand({resource, jsEvent, view: toViewWithLocalDates(view)});
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
function toggle(children
|
|
26
|
+
function toggle(children) {
|
|
25
27
|
for (let child of children) {
|
|
26
28
|
let payload = getPayload(child);
|
|
27
|
-
payload.hidden = !
|
|
28
|
-
if (
|
|
29
|
-
toggle(payload.children
|
|
29
|
+
payload.hidden = !expanded;
|
|
30
|
+
if (child.expanded) {
|
|
31
|
+
toggle(payload.children);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -38,8 +40,13 @@
|
|
|
38
40
|
|
|
39
41
|
<span class="{theme.expander}">
|
|
40
42
|
{#if payload.children?.length}
|
|
41
|
-
<button
|
|
42
|
-
{
|
|
43
|
+
<button
|
|
44
|
+
class="{theme.button}"
|
|
45
|
+
aria-label="{title}"
|
|
46
|
+
title="{title}"
|
|
47
|
+
{onclick}
|
|
48
|
+
{@attach contentFrom(icons[expanded ? 'collapse' : 'expand'])}
|
|
49
|
+
>
|
|
43
50
|
</button>
|
|
44
51
|
{/if}
|
|
45
52
|
</span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {btnTextDay, btnTextMonth, btnTextWeek, getPayload, themeView} from '#lib';
|
|
1
|
+
import {assign, btnTextDay, btnTextMonth, btnTextWeek, getPayload, themeView} from '#lib';
|
|
2
2
|
import {setExtensions} from '../time-grid/lib.js';
|
|
3
3
|
import {createTRROptions, createTRRParsers} from '../time-grid/options.js';
|
|
4
4
|
import {createRROptions} from '../resource-time-grid/options.js';
|
|
@@ -8,44 +8,59 @@ export default {
|
|
|
8
8
|
createOptions(options) {
|
|
9
9
|
createTRROptions(options);
|
|
10
10
|
createRROptions(options);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
day: 'numeric'
|
|
11
|
+
assign(options, {
|
|
12
|
+
resourceExpand: undefined,
|
|
13
|
+
slotWidth: 32,
|
|
14
|
+
// Common options
|
|
15
|
+
view: 'resourceTimelineWeek'
|
|
16
|
+
});
|
|
17
|
+
assign(options.buttonText, {
|
|
18
|
+
expand: 'Expand',
|
|
19
|
+
collapse: 'Collapse',
|
|
20
|
+
resourceTimelineDay: 'timeline',
|
|
21
|
+
resourceTimelineWeek: 'timeline',
|
|
22
|
+
resourceTimelineMonth: 'timeline'
|
|
23
|
+
});
|
|
24
|
+
assign(options.icons, {
|
|
25
|
+
collapse: {html: '−'},
|
|
26
|
+
expand: {html: '+'}
|
|
27
|
+
});
|
|
28
|
+
assign(options.theme, {
|
|
29
|
+
expander: 'ec-expander',
|
|
30
|
+
rowHead: 'ec-row-head',
|
|
31
|
+
slots: 'ec-slots'
|
|
32
|
+
});
|
|
33
|
+
assign(options.views, {
|
|
34
|
+
resourceTimelineDay: {
|
|
35
|
+
buttonText: btnTextDay,
|
|
36
|
+
component: initViewComponent,
|
|
37
|
+
displayEventEnd: false,
|
|
38
|
+
dayHeaderFormat: {weekday: 'long'},
|
|
39
|
+
duration: {days: 1},
|
|
40
|
+
theme: themeView('ec-resource ec-timeline ec-day-view'),
|
|
41
|
+
titleFormat: {year: 'numeric', month: 'long', day: 'numeric'}
|
|
43
42
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
resourceTimelineWeek: {
|
|
44
|
+
buttonText: btnTextWeek,
|
|
45
|
+
component: initViewComponent,
|
|
46
|
+
displayEventEnd: false,
|
|
47
|
+
duration: {weeks: 1},
|
|
48
|
+
theme: themeView('ec-resource ec-timeline ec-week-view')
|
|
49
|
+
},
|
|
50
|
+
resourceTimelineMonth: {
|
|
51
|
+
buttonText: btnTextMonth,
|
|
52
|
+
component: initMonthViewComponent,
|
|
53
|
+
displayEventEnd: false,
|
|
54
|
+
dayHeaderFormat: {
|
|
55
|
+
weekday: 'short',
|
|
56
|
+
day: 'numeric'
|
|
57
|
+
},
|
|
58
|
+
duration: {months: 1},
|
|
59
|
+
slotDuration: {days: 1},
|
|
60
|
+
theme: themeView('ec-resource ec-timeline ec-month-view'),
|
|
61
|
+
titleFormat: {year: 'numeric', month: 'long'}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
49
64
|
},
|
|
50
65
|
|
|
51
66
|
createParsers(parsers) {
|
package/src/storage/effects.js
CHANGED
|
@@ -5,6 +5,20 @@ import {
|
|
|
5
5
|
} from '#lib';
|
|
6
6
|
import {arrayProxy} from './proxy.svelte.js';
|
|
7
7
|
|
|
8
|
+
export function switchView(mainState) {
|
|
9
|
+
return () => {
|
|
10
|
+
// Dependencies
|
|
11
|
+
let {options: {view}} = mainState;
|
|
12
|
+
|
|
13
|
+
untrack(() => {
|
|
14
|
+
let initComponent = mainState.setViewOptions(view);
|
|
15
|
+
mainState.extensions = {};
|
|
16
|
+
mainState.features = [];
|
|
17
|
+
mainState.viewComponent = initComponent(mainState);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
8
22
|
export function loadEvents(mainState, loadingInvoker) {
|
|
9
23
|
return () => {
|
|
10
24
|
// Dependencies
|
|
@@ -125,10 +139,10 @@ function load(sources, defaultResult, parseResult, applyResult, activeRange, fet
|
|
|
125
139
|
}
|
|
126
140
|
}
|
|
127
141
|
|
|
128
|
-
export function createLoadingInvoker(
|
|
142
|
+
export function createLoadingInvoker(mainState) {
|
|
129
143
|
let counter = 0;
|
|
130
144
|
function invoke(value) {
|
|
131
|
-
let {loading} =
|
|
145
|
+
let {options: {loading}} = mainState;
|
|
132
146
|
if (isFunction(loading)) {
|
|
133
147
|
loading(value);
|
|
134
148
|
}
|
|
@@ -52,6 +52,7 @@ function createOptions(plugins) {
|
|
|
52
52
|
height: undefined,
|
|
53
53
|
hiddenDays: [],
|
|
54
54
|
highlightedDates: [], // ec option
|
|
55
|
+
icons: {}, // ec option
|
|
55
56
|
lazyFetching: true,
|
|
56
57
|
loading: undefined,
|
|
57
58
|
locale: undefined,
|
|
@@ -130,9 +131,9 @@ function createParsers(plugins) {
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
// Options where default value is passed to the function
|
|
133
|
-
const specialOptions = ['buttonText', 'customButtons', 'theme'];
|
|
134
|
+
const specialOptions = ['buttonText', 'customButtons', 'icons', 'theme'];
|
|
134
135
|
|
|
135
|
-
export function optionsState(
|
|
136
|
+
export function optionsState(plugins, userOptions) {
|
|
136
137
|
// Create default options and parsers
|
|
137
138
|
let defOptions = createOptions(plugins);
|
|
138
139
|
let parsers = createParsers(plugins);
|
|
@@ -142,62 +143,53 @@ export function optionsState(mainState, plugins, userOptions) {
|
|
|
142
143
|
userOptions = parseOptions(userOptions, parsers);
|
|
143
144
|
|
|
144
145
|
// Extract view-specific options
|
|
145
|
-
let
|
|
146
|
-
let
|
|
146
|
+
let defViews = extractOption(defOptions, 'views') ?? {};
|
|
147
|
+
let userViews = extractOption(userOptions, 'views') ?? {};
|
|
147
148
|
|
|
148
149
|
// Create options state
|
|
149
150
|
let options = objectProxy({});
|
|
150
151
|
assign(options, defOptions);
|
|
152
|
+
// Set initial view based on input
|
|
153
|
+
if (userOptions.view) {
|
|
154
|
+
options.view = userOptions.view;
|
|
155
|
+
}
|
|
151
156
|
|
|
157
|
+
// Set options for each view
|
|
152
158
|
let setters = {};
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
let
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// Set up option setters and delete unknown options
|
|
169
|
-
for (let key of keys(opts)) {
|
|
170
|
-
if (hasOwn(options, key)) {
|
|
171
|
-
if (!setters[key]) {
|
|
172
|
-
setters[key] = [];
|
|
173
|
-
}
|
|
174
|
-
setters[key].push(
|
|
175
|
-
specialOptions.includes(key)
|
|
176
|
-
? value => opts[key] = isFunction(value) ? value(defOpts[key]) : value
|
|
177
|
-
: value => opts[key] = value
|
|
178
|
-
);
|
|
179
|
-
} else {
|
|
180
|
-
delete opts[key];
|
|
159
|
+
let viewOptions = {};
|
|
160
|
+
let viewComponents = {};
|
|
161
|
+
let views = new Set([...keys(defViews), ...keys(userViews)]);
|
|
162
|
+
for (let view of views) {
|
|
163
|
+
let userViewOptions = userViews[view] ?? {};
|
|
164
|
+
let defOpts = mergeOpts(defOptions, defViews[view] ?? defViews[userViewOptions.type] ?? {});
|
|
165
|
+
let opts = mergeOpts(defOpts, userOptions, userViewOptions);
|
|
166
|
+
let component = extractOption(opts, 'component');
|
|
167
|
+
// View has been set
|
|
168
|
+
delete opts.view;
|
|
169
|
+
// Set up option setters and delete unknown options
|
|
170
|
+
for (let key of keys(opts)) {
|
|
171
|
+
if (hasOwn(options, key)) {
|
|
172
|
+
if (!setters[key]) {
|
|
173
|
+
setters[key] = [];
|
|
181
174
|
}
|
|
175
|
+
setters[key].push(
|
|
176
|
+
specialOptions.includes(key)
|
|
177
|
+
? value => opts[key] = isFunction(value) ? value(defOpts[key]) : value
|
|
178
|
+
: value => opts[key] = value
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
delete opts[key];
|
|
182
182
|
}
|
|
183
|
-
// When view changes...
|
|
184
|
-
$effect.pre(() => {
|
|
185
|
-
let newView = options['view'];
|
|
186
|
-
untrack(() => {
|
|
187
|
-
if (newView === view) {
|
|
188
|
-
// ...switch view component
|
|
189
|
-
mainState.setViewComponent(component);
|
|
190
|
-
// ...and update options
|
|
191
|
-
assign(options, opts);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
183
|
}
|
|
184
|
+
viewOptions[view] = opts;
|
|
185
|
+
viewComponents[view] = component;
|
|
196
186
|
}
|
|
197
187
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
assign(options, viewOptions[options.view]);
|
|
189
|
+
|
|
190
|
+
return [
|
|
191
|
+
options,
|
|
192
|
+
function setOption(key, value, parsed = true) {
|
|
201
193
|
if (hasOwn(options, key)) {
|
|
202
194
|
if (!parsed) {
|
|
203
195
|
if (key in parsers) {
|
|
@@ -213,8 +205,11 @@ export function optionsState(mainState, plugins, userOptions) {
|
|
|
213
205
|
options[key] = value;
|
|
214
206
|
}
|
|
215
207
|
},
|
|
216
|
-
|
|
217
|
-
|
|
208
|
+
function setViewOptions(view) {
|
|
209
|
+
assign(options, viewOptions[view]);
|
|
210
|
+
return viewComponents[view];
|
|
211
|
+
}
|
|
212
|
+
];
|
|
218
213
|
}
|
|
219
214
|
|
|
220
215
|
function parseOptions(opts, parsers) {
|
|
@@ -38,11 +38,11 @@ function proxy(target, setDependency, hasEffect, invokeEffect) {
|
|
|
38
38
|
},
|
|
39
39
|
set(target, prop, value, receiver) {
|
|
40
40
|
let has = hasEffect(target[prop], value);
|
|
41
|
-
Reflect.set(target, prop, value, receiver);
|
|
41
|
+
let result = Reflect.set(target, prop, value, receiver);
|
|
42
42
|
if (has) {
|
|
43
43
|
invokeEffect(prop);
|
|
44
44
|
}
|
|
45
|
-
return
|
|
45
|
+
return result;
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
import {SvelteMap} from 'svelte/reactivity';
|
|
2
2
|
import {createDate, identity, intl, intlRange, setMidnight} from '#lib';
|
|
3
|
-
import {optionsState} from './options.
|
|
3
|
+
import {optionsState} from './options.js';
|
|
4
4
|
import {
|
|
5
|
-
createLoadingInvoker, loadEvents, loadResources, runDatesSet, runEventAllUpdated, runViewDidMount, setNowAndToday
|
|
5
|
+
createLoadingInvoker, loadEvents, loadResources, runDatesSet, runEventAllUpdated, runViewDidMount, setNowAndToday,
|
|
6
|
+
switchView
|
|
6
7
|
} from './effects.js';
|
|
7
8
|
import {activeRange, currentRange, filteredEvents, view, viewDates, viewTitle} from './derived.js';
|
|
8
9
|
import {arrayProxy} from './proxy.svelte.js';
|
|
9
10
|
|
|
10
11
|
export default class State {
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
options;
|
|
14
|
+
setOption;
|
|
15
|
+
setViewOptions;
|
|
13
16
|
|
|
14
17
|
constructor(plugins, options) {
|
|
15
18
|
// Create options state
|
|
16
|
-
|
|
17
|
-
this.options = state;
|
|
18
|
-
this.#setOption = setOption;
|
|
19
|
+
([this.options, this.setOption, this.setViewOptions] = optionsState(plugins, options));
|
|
19
20
|
|
|
20
21
|
// Create other states
|
|
21
22
|
this.auxComponents = $state([]);
|
|
22
23
|
this.currentRange = $derived.by(currentRange(this));
|
|
23
24
|
this.activeRange = $derived.by(activeRange(this));
|
|
24
25
|
this.fetchedRange = $state({events: {}, resources: {}});
|
|
25
|
-
this.events = $state.raw(arrayProxy(
|
|
26
|
+
this.events = $state.raw(arrayProxy(this.options.events));
|
|
26
27
|
this.filteredEvents = $derived.by(filteredEvents(this));
|
|
27
28
|
this.mainEl = $state();
|
|
28
29
|
this.now = $state(createDate());
|
|
29
|
-
this.resources = $state.raw(arrayProxy(
|
|
30
|
+
this.resources = $state.raw(arrayProxy(this.options.resources));
|
|
30
31
|
this.today = $state(setMidnight(createDate()));
|
|
31
32
|
this.intlEventTime = $derived.by(intlRange(this, 'eventTimeFormat'));
|
|
32
33
|
this.intlDayHeader = $derived.by(intl(this, 'dayHeaderFormat'));
|
|
@@ -49,12 +50,12 @@ export default class State {
|
|
|
49
50
|
plugin.initState?.(this);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
initEffects();
|
|
53
53
|
this.#initEffects();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
#initEffects() {
|
|
57
|
-
let loading = createLoadingInvoker(this
|
|
57
|
+
let loading = createLoadingInvoker(this);
|
|
58
|
+
$effect.pre(switchView(this));
|
|
58
59
|
$effect.pre(setNowAndToday(this));
|
|
59
60
|
$effect(loadEvents(this, loading));
|
|
60
61
|
$effect(loadResources(this, loading));
|
|
@@ -62,14 +63,4 @@ export default class State {
|
|
|
62
63
|
$effect(runEventAllUpdated(this));
|
|
63
64
|
$effect(runViewDidMount(this));
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
setViewComponent(component) {
|
|
67
|
-
this.extensions = {};
|
|
68
|
-
this.features = [];
|
|
69
|
-
this.viewComponent = component(this);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
setOption(name, value, parsed = true) {
|
|
73
|
-
this.#setOption(name, value, parsed);
|
|
74
|
-
}
|
|
75
66
|
}
|