Widget:UPDEvents: Difference between revisions
Appearance
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
<includeonly> | <includeonly> | ||
<div id | <div id="upd-events-widget"> | ||
<div class="upd-events-loading">Loading upcoming events...</div> | |||
<ul class="upd-events-list" style="display:none;"></ul> | |||
</div> | </div> | ||
< | <script> | ||
.upd-events-widget | (function () { | ||
var container = document.getElementById('upd-events-widget'); | |||
if (!container || container.dataset.loaded === '1') return; | |||
container.dataset.loaded = '1'; | |||
.upd-events- | var loading = container.querySelector('.upd-events-loading'); | ||
var list = container.querySelector('.upd-events-list'); | |||
. | var feedUrl = 'https://upd.edu.ph/events-list/?ical=1'; | ||
. | function decodeICS(value) { | ||
return value | |||
} | .replace(/\\n/gi, '\n') | ||
.replace(/\\,/g, ',') | |||
.replace(/\\;/g, ';') | |||
.replace(/\\\\/g, '\\'); | |||
} | |||
function parseDate(value) { | |||
if (!value) return null; | |||
// All-day event: DTSTART;VALUE=DATE:20261106 | |||
if (/^\d{8}$/.test(value)) { | |||
} | return new Date( | ||
Date.UTC( | |||
Number(value.slice(0, 4)), | |||
Number(value.slice(4, 6)) - 1, | |||
Number(value.slice(6, 8)) | |||
) | |||
); | |||
} | |||
. | // UTC date-time ending in Z | ||
. | if (/^\d{8}T\d{6}Z$/.test(value)) { | ||
return new Date( | |||
value.slice(0, 4) + '-' + | |||
} | value.slice(4, 6) + '-' + | ||
value.slice(6, 8) + 'T' + | |||
value.slice(9, 11) + ':' + | |||
value.slice(11, 13) + ':' + | |||
value.slice(13, 15) + 'Z' | |||
); | |||
} | |||
. | // Date-time without Z: interpret as Philippine local time | ||
if (/^\d{8}T\d{6}$/.test(value)) { | |||
return new Date( | |||
} | value.slice(0, 4) + '-' + | ||
value.slice(4, 6) + '-' + | |||
value.slice(6, 8) + 'T' + | |||
value.slice(9, 11) + ':' + | |||
value.slice(11, 13) + ':' + | |||
value.slice(13, 15) + '+08:00' | |||
); | |||
} | |||
return null; | |||
} | |||
} | |||
.upd | function showError() { | ||
loading.textContent = | |||
} | 'Upcoming events could not be loaded. Please visit the UP Diliman Events page.'; | ||
var link = document.createElement('a'); | |||
link.href = 'https://upd.edu.ph/events-list/'; | |||
link.textContent = ' View all events'; | |||
link.target = '_blank'; | |||
link.rel = 'noopener noreferrer'; | |||
loading.appendChild(link); | |||
} | |||
fetch(feedUrl) | |||
(function () { | .then(function (response) { | ||
if (!response.ok) throw new Error('Calendar feed unavailable'); | |||
return response.text(); | |||
}) | |||
.then(function (ics) { | |||
// Join folded iCalendar lines. | |||
ics = ics.replace(/\r?\n[ \t]/g, ''); | |||
var blocks = ics.match(/BEGIN:VEVENT[\s\S]*?END:VEVENT/g) || []; | |||
var now = new Date(); | |||
var events = []; | |||
var seen = {}; | |||
blocks.forEach(function (block) { | |||
var startMatch = block.match(/^DTSTART(?:;[^:]*)?:(.+)$/m); | |||
var titleMatch = block.match(/^SUMMARY(?:;[^:]*)?:(.+)$/m); | |||
var urlMatch = block.match(/^URL(?:;[^:]*)?:(.+)$/m); | |||
if (!startMatch || !titleMatch || !urlMatch) return; | |||
var start = parseDate(startMatch[1].trim()); | |||
var | var title = decodeICS(titleMatch[1].trim()); | ||
var url = urlMatch[1].trim(); | |||
if (!start || start <= now) return; | |||
if (!/^https:\/\/upd\.edu\.ph\/events\//i.test(url)) return; | |||
// Keep only the nearest upcoming occurrence of each event page. | |||
var key = url + '|' + title.toLowerCase(); | |||
if (seen[key]) return; | |||
seen[key] = true; | |||
events.push({ | |||
title: title, | |||
url: url, | |||
start: start | |||
}); | |||
}); | |||
events.sort(function (a, b) { | |||
return a.start - b.start; | |||
}); | |||
events = events.slice(0, 5); | |||
if (!events.length) { | |||
loading.textContent = 'There are no upcoming events at this time.'; | |||
return; | |||
} | |||
events.forEach(function (event) { | |||
var item = document.createElement('li'); | |||
var link = document.createElement('a'); | |||
link.href = event.url; | |||
link.textContent = event.title; | |||
link.target = '_blank'; | |||
link.rel = 'noopener noreferrer'; | |||
item.appendChild(link); | |||
list.appendChild(item); | |||
}); | |||
loading.style.display = 'none'; | |||
list.style.display = 'block'; | |||
}) | |||
.catch(function (error) { | |||
console.error('UP Diliman Events widget:', error); | |||
showError(); | |||
}); | }); | ||
})(); | })(); | ||
</script> | </script> | ||
</includeonly> | </includeonly> | ||