var networkIndicator = document.querySelector('.network-indicator');
var activeRequests = 0;
var _fetch = function(url, options) {
activeRequests += 1;
networkIndicator.hidden = false;
var p = fetch(url, options).then(r => r.ok ? r : Promise.reject(r));
p.finally(() => {
activeRequests -= 1;
networkIndicator.hidden = activeRequests === 0;
});
return p;
};
var uuid = function() {
if (crypto.randomUUID) {
return crypto.randomUUID();
}
var rnds = new Uint8Array(16);
crypto.getRandomValues(rnds);
rnds[6] = (rnds[6] & 0x0f) | 0x40;
rnds[8] = (rnds[8] & 0x3f) | 0x80;
var s = '';
for (var i = 0; i < 16; i++) {
s += (rnds[i] + 0x100).toString(16).substr(1);
if (i == 3 || i == 5 || i == 7 || i == 9) {
s += '-';
}
}
return s;
};
var date2idate = function(date, allDay, offset) {
var odate = offset ? new Date(date - offset) : date;
var idate = ICAL.Time.fromJSDate(odate);
if (allDay) {
idate.hour = 0;
idate.minute = 0;
idate.second = 0;
idate.isDate = true;
}
return idate;
};
var formatDate = function(date) {
return date
.toISOString()
.replace(/[-:.]/g, '')
.replace('000Z', 'Z');
};
export var getCalendars = function(url) {
return _fetch(url, {
method: 'PROPFIND',
credentials: 'same-origin',
body: '\n'
+ '\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ '',
}).then(r => r.text()).then(function(xml) {
var parser = new DOMParser();
var dom = parser.parseFromString(xml, 'text/xml');
var calendars = [];
dom.querySelectorAll('response').forEach(response => {
if (response.querySelector('resourcetype calendar')) {
calendars.push({
href: response.querySelector('href').textContent,
name: response.querySelector('displayname').textContent,
color: response.querySelector('calendar-color').textContent,
});
}
});
return calendars;
});
};
export var getEvents = function(href, info) {
return _fetch(href, {
method: 'REPORT',
credentials: 'same-origin',
headers: {depth: '1'},
body: '\n'
+ '\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ` \n`
+ ' \n'
+ ' \n'
+ ' \n'
+ '',
}).then(r => r.text()).then(function(xml) {
var parser = new DOMParser();
var dom = parser.parseFromString(xml, 'text/xml');
var events = [];
dom.querySelectorAll('response').forEach(response => {
// https://github.com/mozilla-comm/ical.js/wiki
var ics = response.querySelector('calendar-data').textContent;
var jcal = ICAL.parse(ics);
var comp = new ICAL.Component(jcal);
var vevent = new ICAL.Event(comp.getFirstSubcomponent('vevent'));
var iter = vevent.iterator();
var start = vevent.startDate.toJSDate();
var end = vevent.endDate.toJSDate();
var i;
while (i = iter.next()) {
var istart = i.toJSDate();
if (istart < info.start) {
continue;
} else if (istart > info.end) {
break;
}
events.push({
groupId: response.querySelector('href').textContent,
title: vevent.summary,
offset: istart - start,
start: istart,
end: new Date(istart - (start - end)),
allDay: vevent.startDate.isDate,
comp: comp,
});
}
});
return events;
});
};
export var createEvent = function(info, source) {
var comp = new ICAL.Component(['vcalendar', [], []]);
var compEvent = new ICAL.Component('vevent');
comp.updatePropertyWithValue('prodid', '-//kub-caldav-client');
comp.addSubcomponent(compEvent);
var vevent = new ICAL.Event(compEvent);
vevent.uid = uuid();
return {
groupId: source.id + vevent.uid + '.ics', // FIXME: assumptions about href structure
title: 'new event',
offset: 0,
start: info.date,
allDay: info.allDay,
comp: comp,
};
};
export var commitEvent = function(data, _changes) {
var comp = data.extendedProps.comp;
var vevent = new ICAL.Event(comp.getFirstSubcomponent('vevent'));
var changes = _changes || {};
var groupId = changes.groupId || data.groupId;
var title = changes.title || data.title;
var start = changes.start || data.start;
var end = changes.end || data.end;
var allDay = changes.allDay || data.allDay;
vevent.summary = title;
vevent.startDate = date2idate(start, allDay, data.extendedProps.offset);
vevent.endDate = date2idate(end || start, allDay, data.extendedProps.offset);
return _fetch(groupId, {
method: 'PUT',
credentials: 'same-origin',
body: comp.toString(),
});
};
export var deleteEvent = function(url) {
return _fetch(url, {
method: 'DELETE',
credentials: 'same-origin',
});
};