function getCalendarEvents(calendarId, callback) { if (typeof dummyCalendarData !== 'undefined') { callback(dummyCalendarData); return; } const calendarURL = 'https://calendar.shrt1.eu/' + calendarId; fetch(calendarURL).catch(e => { }).then(response => response.json()).then(response => { callback(response); }); } // function getUserLocale() { // if (typeof navigator.languages !== 'undefined') // return navigator.languages[0]; // return navigator.language; // } function toTitleCaseFirstWord(s) { if (s.length < 2) { return s.toUpperCase(); } return s.substring(0, 1).toUpperCase() + s.substring(1); } function renderCalendar() { class PerDayView { constructor(parent) { this.parent = parent; this.data = parent.querySelector('.data'); this.when = false; this.list = false; } hideWhenEmpty() { if (this.when) { this.parent.classList.remove('hidden'); } } update(when) { if (this.when === when) { return this.list; } this.data.appendChild(createElement('H3', when)); const list = createElement('UL'); this.data.appendChild(list); this.when = when; this.list = list; return this.list; } }; class Rehearsal { constructor(who, what, where, when, until, why) { this.who = who; this.what = what; this.where = where; this.when = when; this.until = until; this.why = why; } static parse(event) { const name = event.name; const no = name.match(/GEEN repetitie\s+(?:(\w+(?: \w+)*)\s*)?(?:\((\w+(?: \w+)*)\))?/i); if (no) { console.log(no); if (no[1].length == 0) { return new Rehearsal(no[2], 'canceled', false, event.start, event.end, false); } return new Rehearsal(no[1], 'canceled', false, event.start, event.end, no[2]); } const standard = name.match(/[\w ]*repetitie\s+([\w ]+[Oo]rkest)(\s+[\w ]+)?\s+\(([\w\- ]+)\)/i); if (standard) { const what = event.start.getUTCDay() === 5 ? 'rehearsal' : 'extra'; return new Rehearsal(standard[1], what, standard[3], event.start, event.end, false); } const extra = name.match(/(?:extra|parti[ëe]le) repetitie[ \-]+(\w+) (?:\((\w+)\))?/i); if (extra) { return new Rehearsal(extra[1], 'extra', extra[2], event.start, event.end, false); } const extraOther = name.match(/(?:extra) ([\w ]+) \((\w+)\)?/i); if (extraOther) { return new Rehearsal("Groot Orkest", `extra:${extraOther[1]}`, extraOther[2], event.start, event.end, false); } return false; } }; const createElement = (tagName, content, classes) => { const element = document.createElement(tagName); if (content) { element.innerHTML = content; } if (classes) { element.classList.add(...classes); } return element; }; const parseISODate = date => { if (date.dateTime) { return new Date(date.dateTime); } if (date.date) { return new Date(date.date); } console.log("couldn't parse date", date); return false; }; const formatWhen = when => { const locale = 'nl-BE'; if (when.getFullYear() !== new Date().getFullYear()) { return when.toLocaleString(locale, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } return when.toLocaleString(locale, { weekday: 'long', month: 'long', day: 'numeric' }); }; const formatWhenTime = when => when.toLocaleString('nl-BE', { hour: 'numeric', minute: 'numeric' }).replace(':', 'h').replace('h00', 'h'); class Dates { static addSeconds(date, seconds) { let added = new Date(date.getTime()); added.setSeconds(added.getSeconds() + seconds); return added; } static areSameDay(a, b) { return a.getUTCDate() === b.getUTCDate() && a.getUTCMonth() === b.getUTCMonth() && a.getUTCFullYear() === b.getUTCFullYear() } }; const isOneDayEvent = event => Dates.areSameDay(event.start, Dates.addSeconds(event.end, -1)) && (event.end - event.start) === 86400000; const isMultipleDayEvent = event => !Dates.areSameDay(event.start, Dates.addSeconds(event.end, -1)); getCalendarEvents('d47tods9jipcdrb5qo6ieoliau3br1ga@import.calendar.google.com', response => { console.log("last update: " + response.updated); const events = response.items.map(item => { return { start: parseISODate(item.start), end: parseISODate(item.end), name: item.summary, }; }); events.sort((a, b) => { return a.start.getTime() - b.start.getTime() }); const [rehearsals, other] = (() => { let rehearsals = []; let other = []; for (const event of events) { if (event.name.toLowerCase().indexOf('repetitie') === -1) { other.push(event); } else { const rehearsal = Rehearsal.parse(event); if (rehearsal) { rehearsals.push(rehearsal); } } } return [rehearsals, other]; })(); let shown = { 'instaporkest': false, 'groot orkest': false, }; const calendarElement = document.getElementById('calendar'); const createEvent = (content, classes) => createElement('LI', content, classes); let nextRehearsalsView = new PerDayView(calendarElement.querySelector('.next-rehearsals')); let noRehearsalsView = new PerDayView(calendarElement.querySelector('.no-rehearsals')); let extraRehearsalsView = new PerDayView(calendarElement.querySelector('.extra-rehearsals')); for (const rehearsal of rehearsals) { const whoLowerCase = rehearsal.who.toLowerCase(); const when = toTitleCaseFirstWord(formatWhen(rehearsal.when)); if (rehearsal.what === 'canceled') { const why = rehearsal.why ? ` (${rehearsal.why})` : ``; noRehearsalsView.update(when).appendChild(createEvent(`Geen repetitie ${rehearsal.who}${why}`, ['rehearsal', 'no-rehearsal'])); } else if (rehearsal.what.startsWith('extra')) { const what = rehearsal.what === 'extra' ? "Repetitie" : toTitleCaseFirstWord(rehearsal.what.substring(6)); extraRehearsalsView.update(when).appendChild(createEvent(`${what} ${rehearsal.who} van ${formatWhenTime(rehearsal.when)} tot ${formatWhenTime(rehearsal.until)} (${rehearsal.where})`, ['rehearsal', 'no-rehearsal'])); } if (shown[whoLowerCase] || typeof shown[whoLowerCase] === 'undefined') { continue; } const nextRehearsalsList = nextRehearsalsView.update(when); if (rehearsal.what === 'canceled') { const why = rehearsal.why ? ` (${rehearsal.why})` : ``; nextRehearsalsList.appendChild(createEvent(`Geen repetitie ${rehearsal.who}${why}`, ['rehearsal', 'no-rehearsal'])); } else if (rehearsal.what === 'rehearsal' || rehearsal.what === 'extra') { let classes = ['rehearsal']; if (rehearsal.where.toLowerCase().indexOf('vlierbeekzaal') === -1) { classes.push('changed-location'); } nextRehearsalsList.appendChild(createEvent(`Repetitie ${rehearsal.who} (${rehearsal.where})`, classes)); shown[whoLowerCase] = true; } else { //? } } noRehearsalsView.hideWhenEmpty(); extraRehearsalsView.hideWhenEmpty(); let otherDataView = new PerDayView(calendarElement.querySelector('.other-data')); for (const event of other) { if (isMultipleDayEvent(event)) { const when = `${toTitleCaseFirstWord(formatWhen(event.start))} t/m ${formatWhen(event.end)}`; otherDataView.update(when).appendChild(createElement('LI', event.name)); } else if (isOneDayEvent(event)) { const when = toTitleCaseFirstWord(formatWhen(event.start)); otherDataView.update(when).appendChild(createElement('LI', event.name)); } else { const when = toTitleCaseFirstWord(formatWhen(event.start)); otherDataView.update(when).appendChild(createElement('LI', `${event.name} van ${formatWhenTime(event.start)} tot ${formatWhenTime(event.end)}`)); } } }); }