/**
* Components for working with things which depend on the current time.
*
* Also introduces two web components:
*
* ```html
*
*
* ```
*
* TODO shouldn't these be defined with the rest of the components?
*
* TODO why isn't Timebar and SmallCellHighlight also Web Components?
*
* @module
*/
export {
SmallcalCellHighlight, Timebar,
initialize_clock_components
}
import { makeElement, date_to_percent } from './lib'
/**
* Interface for `things` which wants to get updated on a human timescale.
*/
export abstract class Clock {
/** Called every now and then
* @param now Called with the current time
*/
abstract update(now: Date): void;
}
/** The (blue) vertical line which show the current time in the current day. */
class Timebar extends Clock {
// start_time: Date
// end_time: Date
/** The bar to update */
bar_object: HTMLElement | null
constructor(/*start_time: Date, end_time: Date*/) {
super();
// this.start_time = start_time;
// this.end_time = end_time;
this.bar_object = null
}
update(now: Date) {
// if (! (this.start_time <= now.getTime() && now.getTime() < this.end_time))
// return;
var event_area = document.getElementById(now.format("~Y-~m-~d"))
if (event_area) {
if (this.bar_object !== null && this.bar_object.parentNode !== null) {
this.bar_object.parentNode.removeChild(this.bar_object)
} else {
this.bar_object = makeElement('div', {
id: 'bar',
className: 'eventlike current-time',
});
}
this.bar_object.style.top = date_to_percent(now) + "%";
event_area.append(this.bar_object)
}
}
}
/**
* Highlights the current date in the small calendar to the side.
* Currently directly sets a border
*
* @TODO{but should preferably set a class instead}.
*/
class SmallcalCellHighlight extends Clock {
/** The calendar which a cell should be highlighted in */
small_cal: HTMLElement
/**
The currently highlighted cell, or `null` if no cell should be
should be highlighted (such as if a non-current month is selected
*/
current_cell: HTMLElement | null
/**
* @param small_cal the DOM-node of the calendar widget. It must support
* querySelector.
*/
constructor(small_cal: HTMLElement) {
super();
this.small_cal = small_cal;
this.current_cell = null
}
update(now: Date) {
if (this.current_cell) {
this.current_cell.style.border = "";
}
/* This is expeced to fail if the current date is not
currently on screen. */
this.current_cell = this.small_cal.querySelector(
"time[datetime='" + now.format("~Y-~m-~d") + "']");
if (this.current_cell) {
this.current_cell.style.border = "1px solid black";
}
}
}
/* -------------------------------------------------- */
/**
Base class for custom HTML elements which wants to be updated for a human
timescale.
When creating, the attribute `interval` can be given, which specifies (in
seconds) how often the component should be updated.
*/
class ClockElement extends HTMLElement {
/** Javascript timer id. Used if the timer needs to be canceled */
timer_id: number
constructor() {
super();
this.timer_id = 0
}
connectedCallback() {
let interval = this.hasAttribute('interval')
? +(this.getAttribute('interval') as string)
: 60;
interval *= 1000 /* ms */
this.timer_id = window.setInterval(() => this.update(new Date), interval)
this.update(new Date)
}
/**
Method which is called each "tick" (see interval)
@param date
The current timestamp when the function is called.
*/
update(_: Date) { /* noop */ }
}
/**
A "button" which always points to the link "~Y-~m-~d.html".
This class is bound to the web component
In the backend code, a `/today` endpoint exists. That however requires that
we ask the server for the correct URL, and follow a 300 (series) redirect.
Since the URL:s are stable, it's possible to jump directly to the given page.
*/
class TodayButton extends ClockElement {
a: HTMLAnchorElement;
constructor() {
super();
this.a = document.createElement('a');
this.a.textContent = 'Idag';
this.a.classList.add('btn');
}
connectedCallback() {
super.connectedCallback();
this.replaceChildren(this.a);
}
update(now: Date) {
this.a.href = now.format("~Y-~m-~d.html")
}
}
/**
A component which displays the current time
This class is bound to the web component
It currently is hard-coded to display time on the format ~H:~M:~S.
*/
class CurrentTime extends ClockElement {
update(now: Date) {
this.textContent = now.format('~H:~M:~S')
}
}
/**
Create Web Components mentioned on this page.
MUST be called early on in the execution.
TODO this should be merged with other web component declarations.
*/
function initialize_clock_components() {
customElements.define('today-button', TodayButton)
customElements.define('current-time', CurrentTime)
}