172 lines
5.4 KiB
JavaScript
172 lines
5.4 KiB
JavaScript
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;
|
|
}
|