@event-calendar/core 5.2.4 → 5.3.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 +133 -14
- package/dist/index.css +1 -1
- package/dist/index.js +278 -181
- package/package.json +2 -2
- package/src/Calendar.svelte +6 -1
- package/src/lib/chunks.js +6 -3
- package/src/lib/components/BaseEvent.svelte +11 -5
- package/src/lib/dom.js +9 -0
- package/src/lib/resources.js +9 -8
- package/src/lib/utils.js +8 -9
- package/src/plugins/day-grid/View.svelte +5 -5
- package/src/plugins/list/View.svelte +2 -2
- package/src/plugins/resource-time-grid/View.svelte +10 -10
- package/src/plugins/resource-time-grid/derived.js +1 -1
- package/src/plugins/resource-timeline/View.svelte +9 -7
- package/src/plugins/resource-timeline/derived.js +1 -1
- package/src/plugins/resource-timeline/lib.js +7 -4
- package/src/plugins/time-grid/View.svelte +7 -7
- package/src/plugins/time-grid/lib.js +1 -0
- package/src/storage/derived.js +4 -3
- package/src/storage/effects.js +126 -77
- package/src/storage/options.svelte.js +6 -5
- package/src/storage/state.svelte.js +8 -3
package/src/storage/effects.js
CHANGED
|
@@ -1,91 +1,140 @@
|
|
|
1
1
|
import {getAbortSignal, tick, untrack} from 'svelte';
|
|
2
2
|
import {
|
|
3
|
-
assign, cloneDate, createDate, createEvents, datesEqual,
|
|
4
|
-
toViewWithLocalDates
|
|
3
|
+
assign, cloneDate, createDate, createEvents, createResources, datesEqual, empty, isArray, isFunction, setMidnight,
|
|
4
|
+
toISOString, toLocalDate, toViewWithLocalDates
|
|
5
5
|
} from '#lib';
|
|
6
6
|
|
|
7
|
-
export function loadEvents(mainState) {
|
|
8
|
-
let fetching = 0;
|
|
7
|
+
export function loadEvents(mainState, loadingInvoker) {
|
|
9
8
|
return () => {
|
|
10
9
|
// Dependencies
|
|
11
|
-
let {activeRange, fetchedRange
|
|
10
|
+
let {activeRange, fetchedRange: {events: fetchedRange}, viewDates,
|
|
11
|
+
options: {events, eventSources, lazyFetching}} = mainState;
|
|
12
12
|
|
|
13
13
|
untrack(() => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mainState.events =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
load(
|
|
15
|
+
eventSources.map(source => isFunction(source.events) ? source.events : source),
|
|
16
|
+
events,
|
|
17
|
+
createEvents,
|
|
18
|
+
result => mainState.events = result,
|
|
19
|
+
activeRange,
|
|
20
|
+
fetchedRange,
|
|
21
|
+
viewDates,
|
|
22
|
+
true,
|
|
23
|
+
lazyFetching,
|
|
24
|
+
loadingInvoker
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function loadResources(mainState, loadingInvoker) {
|
|
31
|
+
return () => {
|
|
32
|
+
// Dependencies
|
|
33
|
+
let {activeRange, fetchedRange: {resources: fetchedRange}, viewDates,
|
|
34
|
+
options: {lazyFetching, refetchResourcesOnNavigate, resources}} = mainState;
|
|
35
|
+
|
|
36
|
+
untrack(() => {
|
|
37
|
+
load(
|
|
38
|
+
isArray(resources) ? [] : [resources],
|
|
39
|
+
resources,
|
|
40
|
+
createResources,
|
|
41
|
+
result => mainState.resources = result,
|
|
42
|
+
activeRange,
|
|
43
|
+
fetchedRange,
|
|
44
|
+
viewDates,
|
|
45
|
+
refetchResourcesOnNavigate,
|
|
46
|
+
lazyFetching,
|
|
47
|
+
loadingInvoker
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function load(sources, defaultResult, parseResult, applyResult, activeRange, fetchedRange, viewDates, refetchOnNavigate, lazyFetching, loading) {
|
|
54
|
+
if (empty(viewDates)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (empty(sources)) {
|
|
58
|
+
applyResult(defaultResult);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Do not fetch if new range is within the previous one
|
|
62
|
+
if (
|
|
63
|
+
(refetchOnNavigate || !fetchedRange.start) &&
|
|
64
|
+
(
|
|
65
|
+
!lazyFetching ||
|
|
66
|
+
!fetchedRange.start ||
|
|
67
|
+
fetchedRange.start > activeRange.start ||
|
|
68
|
+
fetchedRange.end < activeRange.end
|
|
69
|
+
)
|
|
70
|
+
) {
|
|
71
|
+
let result = [];
|
|
72
|
+
// Prepare handlers
|
|
73
|
+
let failure = e => loading.stop();
|
|
74
|
+
let success = data => {
|
|
75
|
+
result = result.concat(parseResult(data));
|
|
76
|
+
applyResult(result);
|
|
77
|
+
loading.stop();
|
|
78
|
+
};
|
|
79
|
+
// Prepare other stuff
|
|
80
|
+
let startStr = toISOString(activeRange.start)
|
|
81
|
+
let endStr = toISOString(activeRange.end);
|
|
82
|
+
// Loop over event sources
|
|
83
|
+
for (let source of sources) {
|
|
84
|
+
loading.start();
|
|
85
|
+
if (isFunction(source)) {
|
|
86
|
+
// Source as a function
|
|
87
|
+
let result = source(refetchOnNavigate ? {
|
|
88
|
+
start: toLocalDate(activeRange.start),
|
|
89
|
+
end: toLocalDate(activeRange.end),
|
|
90
|
+
startStr,
|
|
91
|
+
endStr
|
|
92
|
+
} : {}, success, failure);
|
|
93
|
+
if (result !== undefined) {
|
|
94
|
+
Promise.resolve(result).then(success, failure);
|
|
30
95
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let failure = e => stopLoading();
|
|
39
|
-
let success = data => {
|
|
40
|
-
events = events.concat(createEvents(data));
|
|
41
|
-
mainState.events = events;
|
|
42
|
-
stopLoading();
|
|
43
|
-
};
|
|
44
|
-
// Prepare other stuff
|
|
45
|
-
let startStr = toISOString(activeRange.start)
|
|
46
|
-
let endStr = toISOString(activeRange.end);
|
|
47
|
-
// Loop over event sources
|
|
48
|
-
for (let source of eventSources) {
|
|
49
|
-
if (isFunction(source.events)) {
|
|
50
|
-
// Events as a function
|
|
51
|
-
let result = source.events({
|
|
52
|
-
start: toLocalDate(activeRange.start),
|
|
53
|
-
end: toLocalDate(activeRange.end),
|
|
54
|
-
startStr,
|
|
55
|
-
endStr
|
|
56
|
-
}, success, failure);
|
|
57
|
-
if (result !== undefined) {
|
|
58
|
-
Promise.resolve(result).then(success, failure);
|
|
59
|
-
}
|
|
60
|
-
} else {
|
|
61
|
-
// Events as a JSON feed
|
|
62
|
-
// Prepare params
|
|
63
|
-
let params = isFunction(source.extraParams) ? source.extraParams() : assign({}, source.extraParams);
|
|
64
|
-
params.start = startStr;
|
|
65
|
-
params.end = endStr;
|
|
66
|
-
params = new URLSearchParams(params);
|
|
67
|
-
// Prepare fetch
|
|
68
|
-
let url = source.url, headers = {}, body;
|
|
69
|
-
if (['GET', 'HEAD'].includes(source.method)) {
|
|
70
|
-
url += (url.includes('?') ? '&' : '?') + params;
|
|
71
|
-
} else {
|
|
72
|
-
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
73
|
-
body = String(params); // Safari 10.1 doesn't convert to string automatically
|
|
74
|
-
}
|
|
75
|
-
// Do the fetch
|
|
76
|
-
fetch(url, {
|
|
77
|
-
method: source.method, headers, body, signal: getAbortSignal(), credentials: 'same-origin'
|
|
78
|
-
})
|
|
79
|
-
.then(response => response.json())
|
|
80
|
-
.then(success)
|
|
81
|
-
.catch(failure);
|
|
82
|
-
}
|
|
83
|
-
++fetching;
|
|
96
|
+
} else {
|
|
97
|
+
// Source as a JSON feed
|
|
98
|
+
// Prepare params
|
|
99
|
+
let params = isFunction(source.extraParams) ? source.extraParams() : assign({}, source.extraParams);
|
|
100
|
+
if (refetchOnNavigate) {
|
|
101
|
+
params.start = startStr;
|
|
102
|
+
params.end = endStr;
|
|
84
103
|
}
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
params = new URLSearchParams(params);
|
|
105
|
+
// Prepare fetch
|
|
106
|
+
let url = source.url, headers = {}, body;
|
|
107
|
+
if (['GET', 'HEAD'].includes(source.method)) {
|
|
108
|
+
url += (url.includes('?') ? '&' : '?') + params;
|
|
109
|
+
} else {
|
|
110
|
+
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
111
|
+
body = String(params); // Safari 10.1 doesn't convert to string automatically
|
|
112
|
+
}
|
|
113
|
+
// Do the fetch
|
|
114
|
+
fetch(url, {
|
|
115
|
+
method: source.method, headers, body, signal: getAbortSignal(), credentials: 'same-origin'
|
|
116
|
+
})
|
|
117
|
+
.then(response => response.json())
|
|
118
|
+
.then(success)
|
|
119
|
+
.catch(failure);
|
|
87
120
|
}
|
|
88
|
-
}
|
|
121
|
+
}
|
|
122
|
+
// Save current range for future requests
|
|
123
|
+
assign(fetchedRange, activeRange);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function createLoadingInvoker(options) {
|
|
128
|
+
let counter = 0;
|
|
129
|
+
function invoke(value) {
|
|
130
|
+
let {loading} = options;
|
|
131
|
+
if (isFunction(loading)) {
|
|
132
|
+
loading(value);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
start: () => ++counter === 1 && invoke(true),
|
|
137
|
+
stop: () => --counter === 0 && invoke(false)
|
|
89
138
|
};
|
|
90
139
|
}
|
|
91
140
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {untrack} from 'svelte';
|
|
2
2
|
import {
|
|
3
|
-
createDate, createDateRange, createDuration, createEvents, createEventSources, createResources, entries,
|
|
3
|
+
createDate, createDateRange, createDuration, createEvents, createEventSources, createResources, entries, isArray,
|
|
4
4
|
isFunction, keys, setMidnight
|
|
5
5
|
} from '#lib';
|
|
6
6
|
import {SvelteMap} from "svelte/reactivity";
|
|
@@ -55,6 +55,7 @@ function createOptions(plugins) {
|
|
|
55
55
|
lazyFetching: true,
|
|
56
56
|
loading: undefined,
|
|
57
57
|
locale: undefined,
|
|
58
|
+
refetchResourcesOnNavigate: false,
|
|
58
59
|
resources: [],
|
|
59
60
|
selectable: false,
|
|
60
61
|
theme: {
|
|
@@ -110,13 +111,13 @@ function createOptions(plugins) {
|
|
|
110
111
|
|
|
111
112
|
function createParsers(plugins) {
|
|
112
113
|
let parsers = {
|
|
113
|
-
date:
|
|
114
|
+
date: input => setMidnight(createDate(input)),
|
|
114
115
|
duration: createDuration,
|
|
115
116
|
events: createEvents,
|
|
116
117
|
eventSources: createEventSources,
|
|
117
|
-
hiddenDays:
|
|
118
|
-
highlightedDates:
|
|
119
|
-
resources: createResources,
|
|
118
|
+
hiddenDays: input => [...new Set(input)],
|
|
119
|
+
highlightedDates: input => input.map(item => setMidnight(createDate(item))),
|
|
120
|
+
resources: input => isArray(input) ? createResources(input) : input,
|
|
120
121
|
validRange: createDateRange
|
|
121
122
|
};
|
|
122
123
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {SvelteMap} from 'svelte/reactivity';
|
|
2
2
|
import {createDate, identity, intl, intlRange, setMidnight} from '#lib';
|
|
3
3
|
import {optionsState} from './options.svelte.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createLoadingInvoker, loadEvents, loadResources, runDatesSet, runEventAllUpdated, runViewDidMount, setNowAndToday
|
|
6
|
+
} from './effects.js';
|
|
5
7
|
import {activeRange, currentRange, filteredEvents, view, viewDates, viewTitle} from './derived.js';
|
|
6
8
|
|
|
7
9
|
export default class State {
|
|
@@ -18,11 +20,12 @@ export default class State {
|
|
|
18
20
|
this.auxComponents = $state([]);
|
|
19
21
|
this.currentRange = $derived.by(currentRange(this));
|
|
20
22
|
this.activeRange = $derived.by(activeRange(this));
|
|
21
|
-
this.fetchedRange = $state
|
|
23
|
+
this.fetchedRange = $state({events: {}, resources: {}});
|
|
22
24
|
this.events = $state.raw([]);
|
|
23
25
|
this.filteredEvents = $derived.by(filteredEvents(this));
|
|
24
26
|
this.mainEl = $state();
|
|
25
27
|
this.now = $state(createDate());
|
|
28
|
+
this.resources = $state.raw([]);
|
|
26
29
|
this.today = $state(setMidnight(createDate()));
|
|
27
30
|
this.intlEventTime = $derived.by(intlRange(this, 'eventTimeFormat'));
|
|
28
31
|
this.intlDayHeader = $derived.by(intl(this, 'dayHeaderFormat'));
|
|
@@ -50,8 +53,10 @@ export default class State {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
#initEffects() {
|
|
56
|
+
let loading = createLoadingInvoker(this.options);
|
|
53
57
|
$effect.pre(setNowAndToday(this));
|
|
54
|
-
$effect(loadEvents(this));
|
|
58
|
+
$effect(loadEvents(this, loading));
|
|
59
|
+
$effect(loadResources(this, loading));
|
|
55
60
|
$effect(runDatesSet(this));
|
|
56
61
|
$effect(runEventAllUpdated(this));
|
|
57
62
|
$effect(runViewDidMount(this));
|