const http = require('http') const ical = require('ical') const MONTH = 30 * 24 * 60 * 60 * 1000 const Accumulator = { init: function (pastLimit, futureLimit) { this.entries = {} this.futureLimit = futureLimit this.pastLimit = pastLimit }, add: function (time, element) { if (!this.entries.hasOwnProperty(time)) { this.entries[time] = [] } this.entries[time].push(element) }, offer: function (time, element) { if (time >= this.pastLimit && time < this.futureLimit) { this.add(time, element) } }, offerEvent: function (event) { const content = document.createElement('p') const element = document.createElement('div') const formatDate = Intl.DateTimeFormat('fr', { dateStyle: 'long', timeStyle: 'short' }).format const header = document.createElement('h3') content.innerHTML = event.location header.textContent = formatDate(event.date) + ' | ' + event.summary element.className = 'event-entry news-entry' element.setAttribute('entry-time', event.date.getTime()) element.appendChild(header) element.appendChild(content) this.offer(event.date.getTime(), element) }, iterate: function (cb) { Object .keys(this.entries) .sort(function (a, b) { return a < b }) .forEach(time => { cb(time, this.entries[time]) }) } } function createLoader (target) { const message = document.createElement('p') const spinner = document.createElement('div') const wrapper = document.createElement('div') wrapper.className = 'loader-wrapper' message.innerHTML = 'Chargement du calendrier...' wrapper.appendChild(spinner) wrapper.appendChild(message) target.insertBefore(wrapper, target.firstChild) } function loadEvents (cb) { const events = [] http.get({ host: 'www.ti-nuage.fr', path: '/donnees/calendrier.php' }, function (response) { let str = '' response.on('data', (chunk) => { str += chunk }) response.on('end', () => { /* Extract the events. */ Object.values(ical.parseICS(str)).forEach(event => { if (event.type === 'VEVENT') { events.push({ date: event.start, location: event.location, summary: event.summary }) } }) cb(events) }) response.on('error', (e) => { console.error(`Error on calendar response: ${e.message}`) cb(events) }) }).on('error', (e) => { console.error(`Could not fetch calendar: ${e.message}`) cb(events) }) } module.exports = { fill: function (target) { const now = Date.now() const accumulator = Object.create(Accumulator) accumulator.init(now - 1 * MONTH, now + 3 * MONTH) createLoader(target) loadEvents(events => { events.forEach(event => { accumulator.offerEvent(event) }) target.innerHTML = '' accumulator.iterate((time, elements) => { elements.forEach(e => { if (time < now) { e.className = e.className + ' event-elapsed' } target.appendChild(e) }) }) }) }, mergeWithNews: function (target) { const now = Date.now() const accumulator = Object.create(Accumulator) const blogElements = target.getElementsByClassName('blog-entry') accumulator.init(now, now + 1 * MONTH) createLoader(target) for (let i = 0; i < blogElements.length; ++i) { const item = blogElements.item(i) accumulator.add(item.getAttribute('entry-time'), item) } loadEvents(events => { events.forEach(event => { accumulator.offerEvent(event) }) target.innerHTML = '' accumulator.iterate((time, elements) => { elements.forEach(e => { target.appendChild(e) }) }) }) } }