import { QUICK_LINKS } from './config.js'; globalThis.browser ??= chrome; const dateTimeFormat = Intl.DateTimeFormat([], { dateStyle: 'medium', timeStyle: 'short' }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', async () => { await init(); }); } else { await init(); } async function init() { setL10n(); setLinks(); /** * @type {import("../types").Storage} */ const { calendar, spaceApi } = await browser.storage.session.get(['calendar', 'spaceApi']); if (calendar) { updateNextEvent(calendar); } if (spaceApi) { updateSpaceApiJson(spaceApi); updateState(spaceApi); } } function setL10n() { document.querySelector('html').setAttribute('lang', browser.i18n.getUILanguage()); const loadingText = browser.i18n.getMessage('loading'); document.querySelector('#state').textContent = loadingText; document.querySelector('#calendar').textContent = loadingText; document.querySelector('#space-api > code').textContent = loadingText; document.querySelector('#currentState').textContent = browser.i18n.getMessage('currentState'); document.querySelector('#links').textContent = browser.i18n.getMessage('links'); document.querySelector('#nextEvent').textContent = browser.i18n.getMessage('nextEvent'); document.querySelector('#spaceApiJson').textContent = browser.i18n.getMessage('spaceApiJson'); } function setLinks() { const listElement = document.querySelector('#link-list'); for (const quickLink of QUICK_LINKS) { const template = getCleanTemplateById('template-link-item'); const linkElement = template.querySelector('.link'); linkElement.dataset.url = quickLink.url; linkElement.addEventListener('click', linkElementClickListener); const svgIcon = getCleanTemplateById(quickLink.iconTemplateId); svgIcon.querySelector('svg').setAttribute('aria-label', quickLink.text); template.querySelector('.icon').append(svgIcon); template.querySelector('.text').textContent = quickLink.text; listElement.append(template); } } /** * @param {Event} event */ async function linkElementClickListener(event) { try { await browser.tabs.create({ url: event.currentTarget.dataset.url }); } catch (error) { console.error(error); } } /** * @param {import("../types").Calendar} nextEvents */ function updateNextEvent(nextEvents) { const calendarElement = document.querySelector('#calendar'); calendarElement.textContent = ''; if (nextEvents.length === 0) { const strongElement = document.createElement('strong'); strongElement.textContent = browser.i18n.getMessage('noEventsInNext4Weeks'); calendarElement.append(strongElement); } else { const nextEventDate = nextEvents[0].begin.slice(0, 10); const nextEventDateEvents = nextEvents.filter((nextEvent) => (nextEvent.begin.startsWith(nextEventDate))); for (const nextEventDateEvent of nextEventDateEvents) { calendarElement.append(buildCalendarEntryElement(nextEventDateEvent)); } } } /** * @param {import("../types").CalendarEntry} nextEventDateEvent * @returns {DocumentFragment} */ function buildCalendarEntryElement(nextEventDateEvent) { const calendarEntryElement = getCleanTemplateById('template-calendar-entry'); calendarEntryElement.querySelector('svg').setAttribute('aria-label', browser.i18n.getMessage('event')); calendarEntryElement.querySelector('strong').textContent = nextEventDateEvent.name; const timeElement = calendarEntryElement.querySelector('time'); const beginDate = new Date(nextEventDateEvent.begin); timeElement.dateTime = beginDate.toISOString(); timeElement.textContent = dateTimeFormat.format(beginDate); if (nextEventDateEvent.location) { const locationElement = getCleanTemplateById('template-calendar-entry-location'); locationElement.querySelector('address').textContent = nextEventDateEvent.location; calendarEntryElement.querySelector('.calendar-entry > div').append(locationElement); } return calendarEntryElement; } /** * @param {import("../types").SpaceApi} spaceApi */ function updateSpaceApiJson(spaceApi) { const spaceApiElement = document.querySelector('#space-api > code'); spaceApiElement.textContent = JSON.stringify(spaceApi, null, 2); } /** * @param {import("../types").SpaceApi} spaceApi */ function updateState(spaceApi) { const state = spaceApi.state.open ? 'open' : 'closed'; const stateElements = getCleanTemplateById('template-state'); const svgIconState = getCleanTemplateById(`template-icon-${state}`); svgIconState.querySelector('svg').setAttribute('aria-label', browser.i18n.getMessage(state)); stateElements.querySelector('svg').replaceWith(svgIconState); stateElements.querySelector('span').textContent = browser.i18n.getMessage(spaceApi.state.open ? 'openSince' : 'closedSince'); const timeElement = stateElements.querySelector('time'); const since = new Date(spaceApi.state.lastchange * 1000); timeElement.dateTime = since.toISOString(); timeElement.textContent = dateTimeFormat.format(since); const stateElement = document.querySelector('#state'); stateElement.textContent = ''; stateElement.append(stateElements); } /** * @param {string} templateId * @returns {DocumentFragment} */ function getCleanTemplateById(templateId) { const template = document.querySelector(`#${templateId}`).content.cloneNode(true); if (template.hasChildNodes()) { for (const childNode of template.childNodes) { if (childNode.nodeType !== Node.ELEMENT_NODE) { childNode.remove(); } } } return template; }