From c6c65f9e8273a5bc1b2ac1155d66003d2b98591c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 4 Oct 2021 17:40:59 +0200 Subject: {.js => .ts} on relavant files. --- static/lib.ts | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 static/lib.ts (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts new file mode 100644 index 00000000..100f4161 --- /dev/null +++ b/static/lib.ts @@ -0,0 +1,205 @@ +'use strict'; +/* + General procedures which in theory could be used anywhere. + */ + +HTMLElement.prototype._addEventListener = HTMLElement.prototype.addEventListener; +HTMLElement.prototype.addEventListener = function (name, proc) { + if (! this.listeners) this.listeners = {}; + if (! this.listeners[name]) this.listeners[name] = []; + this.listeners[name].push(proc); + return this._addEventListener(name, proc); +}; + + + +/* list of lists -> list of tuples */ +function zip(...args) { + // console.log(args); + if (args === []) return []; + return [...Array(Math.min(...args.map(x => x.length))).keys()] + .map((_, i) => args.map(lst => lst[i])); +} + + +/* ----- Date Extensions ---------------------------- */ + +/* + Extensions to Javascript's Date to allow representing times + with different timezones. Currently only UTC and local time + are supported, but more should be able to be added. + + NOTE that only the raw `get' (and NOT the `getUTC') methods + should be used on these objects, and that the reported timezone + is quite often wrong. + + TODO The years between 0 and 100 (inclusive) gives dates in the twentieth + century, due to how javascript works (...). + */ + +function parseDate(str) { + let year, month, day, hour=false, minute, second=0, utc; + + let end = str.length - 1; + if (str[end] == 'Z') { + utc = true; + str = str.substring(0, end); + }; + + switch (str.length) { + case '2020-01-01T13:37:00'.length: + second = str.substr(17,2); + case '2020-01-01T13:37'.length: + hour = str.substr(11,2); + minute = str.substr(14,2); + case '2020-01-01'.length: + year = str.substr(0,4); + month = str.substr(5,2) - 1; + day = str.substr(8,2); + break; + default: + throw 'Bad argument'; + } + + let date; + if (hour) { + date = new Date(year, month, day, hour, minute, second); + date.utc = utc; + date.dateonly = false; + } else { + date = new Date(year, month, day); + date.dateonly = true; + } + return date; +} + +function copyDate(date) { + let d = new Date(date); + d.utc = date.utc; + d.dateonly = date.dateonly; + return d; +} + +function to_local(date) { + if (! date.utc) return date; + + return new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000); +} + +/* -------------------------------------------------- */ + +function makeElement (name, attr={}) { + let element = document.createElement(name); + for (let [key, value] of Object.entries(attr)) { + element[key] = value; + } + return element; +} + +function round_time (time, fraction) { + let scale = 1 / fraction; + return Math.round (time * scale) / scale; +} + +/* only used by the bar. + Events use the start and end time of their container, but since the bar + is moving between containers that is clumsy. + Just doing (new Date()/(86400*1000)) would be nice, but there's no good + way to get the time in the current day. + */ +function date_to_percent (date) { + return (date.getHours() + (date.getMinutes() / 60)) * 100/24; +} + +/* if only there was such a thing as a let to wrap around my lambda... */ +/* js infix to not collide with stuff generated backend */ +const gensym = (counter => (prefix="gensym") => prefix + "js" + ++counter)(0) + +function setVar(str, val) { + document.documentElement.style.setProperty("--" + str, val); +} + + +function asList(thing) { + if (thing instanceof Array) { + return thing; + } else { + return [thing]; + } +} + + +function boolean (value) { + switch (typeof value) { + case 'string': + switch (value) { + case 'true': return true; + case 'false': return false; + case '': return false; + default: return true; + } + case 'boolean': + return value; + default: + return !! value; + } +} + + + +/* internal */ +function datepad(thing, width=2) { + return (thing + "").padStart(width, "0"); +} + +function format_date(date, str) { + let fmtmode = false; + let outstr = ""; + for (var i = 0; i < str.length; i++) { + if (fmtmode) { + switch (str[i]) { + /* Moves the date into local time. */ + case 'L': date = to_local(date); break; + case 'Y': outstr += datepad(date.getFullYear(), 4); break; + case 'm': outstr += datepad(date.getMonth() + 1); break; + case 'd': outstr += datepad(date.getDate()); break; + case 'H': outstr += datepad(date.getHours()); break; + case 'M': outstr += datepad(date.getMinutes()); break; + case 'S': outstr += datepad(date.getSeconds()); break; + case 'Z': if (date.utc) outstr += 'Z'; break; + } + fmtmode = false; + } else if (str[i] == '~') { + fmtmode = true; + } else { + outstr += str[i]; + } + } + return outstr; +} + +Object.prototype.format = function (/* any number of arguments */) { return "" + this; } +Date.prototype.format = function (str) { return format_date (this, str); } + +/* + * Finds the first element of the DOMTokenList whichs value matches + * the supplied regexp. Returns a pair of the index and the value. + */ +DOMTokenList.prototype.find = function (regexp) { + let entries = this.entries(); + let entry; + while (! (entry = entries.next()).done) { + if (entry.value[1].match(regexp)) { + return entry.value; + } + } +} + +/* HTMLCollection is the result of a querySelectorAll */ +HTMLCollection.prototype.forEach = function (proc) { + for (let el of this) { + proc(el); + } +} + +const xcal = "urn:ietf:params:xml:ns:icalendar-2.0"; -- cgit v1.2.3 From 8ec2f441d40ab89b40cc3158f65c914eff497cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 4 Oct 2021 23:18:24 +0200 Subject: Major typescript work. --- static/lib.ts | 154 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 95 insertions(+), 59 deletions(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index 100f4161..35b6f867 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -3,10 +3,39 @@ General procedures which in theory could be used anywhere. */ +interface Object { + format: (fmt: string) => string +} + +interface HTMLElement { + _addEventListener: (name: string, proc: (e: Event) => void) => void + listeners: Record void)[]> +} + +interface Date { + dateonly: boolean + utc: boolean + type: 'date' | 'date-time' +} + +interface DOMTokenList { + find: (regex: string) => [number, string] | undefined +} + +interface HTMLCollection { + forEach: (proc: ((el: Element) => void)) => void +} + +interface HTMLCollectionOf { + forEach: (proc: ((el: T) => void)) => void +} + +type uid = string + HTMLElement.prototype._addEventListener = HTMLElement.prototype.addEventListener; -HTMLElement.prototype.addEventListener = function (name, proc) { - if (! this.listeners) this.listeners = {}; - if (! this.listeners[name]) this.listeners[name] = []; +HTMLElement.prototype.addEventListener = function(name: string, proc: (e: Event) => void) { + if (!this.listeners) this.listeners = {}; + if (!this.listeners[name]) this.listeners[name] = []; this.listeners[name].push(proc); return this._addEventListener(name, proc); }; @@ -14,7 +43,8 @@ HTMLElement.prototype.addEventListener = function (name, proc) { /* list of lists -> list of tuples */ -function zip(...args) { +/* TODO figure out how to type this correctly */ +function zip(...args: any[]) { // console.log(args); if (args === []) return []; return [...Array(Math.min(...args.map(x => x.length))).keys()] @@ -37,8 +67,14 @@ function zip(...args) { century, due to how javascript works (...). */ -function parseDate(str) { - let year, month, day, hour=false, minute, second=0, utc; +function parseDate(str: string): Date { + let year: number; + let month: number; + let day: number; + let hour: number | false = false; + let minute: number = 0; + let second: number = 0; + let utc: boolean = false; let end = str.length - 1; if (str[end] == 'Z') { @@ -47,18 +83,18 @@ function parseDate(str) { }; switch (str.length) { - case '2020-01-01T13:37:00'.length: - second = str.substr(17,2); - case '2020-01-01T13:37'.length: - hour = str.substr(11,2); - minute = str.substr(14,2); - case '2020-01-01'.length: - year = str.substr(0,4); - month = str.substr(5,2) - 1; - day = str.substr(8,2); - break; - default: - throw 'Bad argument'; + case '2020-01-01T13:37:00'.length: + second = +str.substr(17, 2); + case '2020-01-01T13:37'.length: + hour = +str.substr(11, 2); + minute = +str.substr(14, 2); + case '2020-01-01'.length: + year = +str.substr(0, 4); + month = +str.substr(5, 2) - 1; + day = +str.substr(8, 2); + break; + default: + throw 'Bad argument'; } let date; @@ -73,32 +109,32 @@ function parseDate(str) { return date; } -function copyDate(date) { +function copyDate(date: Date): Date { let d = new Date(date); d.utc = date.utc; d.dateonly = date.dateonly; return d; } -function to_local(date) { - if (! date.utc) return date; +function to_local(date: Date): Date { + if (!date.utc) return date; return new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000); } /* -------------------------------------------------- */ -function makeElement (name, attr={}) { - let element = document.createElement(name); +function makeElement(name: string, attr = {}): HTMLElement { + let element: HTMLElement = document.createElement(name); for (let [key, value] of Object.entries(attr)) { - element[key] = value; + (element as any)[key] = value; } return element; } -function round_time (time, fraction) { +function round_time(time: number, fraction: number): number { let scale = 1 / fraction; - return Math.round (time * scale) / scale; + return Math.round(time * scale) / scale; } /* only used by the bar. @@ -107,20 +143,20 @@ function round_time (time, fraction) { Just doing (new Date()/(86400*1000)) would be nice, but there's no good way to get the time in the current day. */ -function date_to_percent (date) { - return (date.getHours() + (date.getMinutes() / 60)) * 100/24; +function date_to_percent(date: Date): number /* in 0, 100 */ { + return (date.getHours() + (date.getMinutes() / 60)) * 100 / 24; } /* if only there was such a thing as a let to wrap around my lambda... */ /* js infix to not collide with stuff generated backend */ -const gensym = (counter => (prefix="gensym") => prefix + "js" + ++counter)(0) +const gensym = (counter => (prefix = "gensym") => prefix + "js" + ++counter)(0) -function setVar(str, val) { - document.documentElement.style.setProperty("--" + str, val); +function setVar(str: string, val: any) { + document.documentElement.style.setProperty("--" + str, val); } -function asList(thing) { +function asList(thing: Array | T): Array { if (thing instanceof Array) { return thing; } else { @@ -129,44 +165,44 @@ function asList(thing) { } -function boolean (value) { +function boolean(value: any): boolean { switch (typeof value) { - case 'string': - switch (value) { - case 'true': return true; - case 'false': return false; - case '': return false; - default: return true; - } - case 'boolean': - return value; - default: - return !! value; + case 'string': + switch (value) { + case 'true': return true; + case 'false': return false; + case '': return false; + default: return true; + } + case 'boolean': + return value; + default: + return !!value; } } /* internal */ -function datepad(thing, width=2) { +function datepad(thing: number | string, width = 2): string { return (thing + "").padStart(width, "0"); } -function format_date(date, str) { +function format_date(date: Date, str: string): string { let fmtmode = false; let outstr = ""; for (var i = 0; i < str.length; i++) { if (fmtmode) { switch (str[i]) { /* Moves the date into local time. */ - case 'L': date = to_local(date); break; - case 'Y': outstr += datepad(date.getFullYear(), 4); break; - case 'm': outstr += datepad(date.getMonth() + 1); break; - case 'd': outstr += datepad(date.getDate()); break; - case 'H': outstr += datepad(date.getHours()); break; - case 'M': outstr += datepad(date.getMinutes()); break; - case 'S': outstr += datepad(date.getSeconds()); break; - case 'Z': if (date.utc) outstr += 'Z'; break; + case 'L': date = to_local(date); break; + case 'Y': outstr += datepad(date.getFullYear(), 4); break; + case 'm': outstr += datepad(date.getMonth() + 1); break; + case 'd': outstr += datepad(date.getDate()); break; + case 'H': outstr += datepad(date.getHours()); break; + case 'M': outstr += datepad(date.getMinutes()); break; + case 'S': outstr += datepad(date.getSeconds()); break; + case 'Z': if (date.utc) outstr += 'Z'; break; } fmtmode = false; } else if (str[i] == '~') { @@ -178,17 +214,17 @@ function format_date(date, str) { return outstr; } -Object.prototype.format = function (/* any number of arguments */) { return "" + this; } -Date.prototype.format = function (str) { return format_date (this, str); } +Object.prototype.format = function(/* any number of arguments */) { return "" + this; } +Date.prototype.format = function(str) { return format_date(this, str); } /* * Finds the first element of the DOMTokenList whichs value matches * the supplied regexp. Returns a pair of the index and the value. */ -DOMTokenList.prototype.find = function (regexp) { +DOMTokenList.prototype.find = function(regexp) { let entries = this.entries(); let entry; - while (! (entry = entries.next()).done) { + while (!(entry = entries.next()).done) { if (entry.value[1].match(regexp)) { return entry.value; } @@ -196,7 +232,7 @@ DOMTokenList.prototype.find = function (regexp) { } /* HTMLCollection is the result of a querySelectorAll */ -HTMLCollection.prototype.forEach = function (proc) { +HTMLCollection.prototype.forEach = function(proc) { for (let el of this) { proc(el); } -- cgit v1.2.3 From 200c0bc92203f2103805f1d09602b02800a8593a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 10 Oct 2021 15:13:46 +0200 Subject: Mostly fix datetime values in frontend. --- static/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index 35b6f867..26735bd1 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -94,7 +94,7 @@ function parseDate(str: string): Date { day = +str.substr(8, 2); break; default: - throw 'Bad argument'; + throw `"${str}" doesn't look like a date/-time string` } let date; -- cgit v1.2.3 From 2d0ec2b162e3e2851fef7f280aab21c9f00cd171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 31 Oct 2021 20:48:23 +0100 Subject: Everything but lib. --- static/lib.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index 26735bd1..e3d99007 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -1,3 +1,4 @@ + 'use strict'; /* General procedures which in theory could be used anywhere. -- cgit v1.2.3 From 0712c416259e4860ff1910c4a5bcd7b37da6b237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 31 Oct 2021 21:18:37 +0100 Subject: lib. --- static/lib.ts | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index e3d99007..fe5ef1bd 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -1,34 +1,42 @@ +export { + makeElement, date_to_percent, uid, + parseDate, gensym, to_local, boolean, + xcal, asList, round_time +} 'use strict'; /* General procedures which in theory could be used anywhere. */ -interface Object { - format: (fmt: string) => string -} +declare global { + interface Object { + format: (fmt: string) => string + } -interface HTMLElement { - _addEventListener: (name: string, proc: (e: Event) => void) => void - listeners: Record void)[]> -} + interface HTMLElement { + _addEventListener: (name: string, proc: (e: Event) => void) => void + listeners: Record void)[]> + } -interface Date { - dateonly: boolean - utc: boolean - type: 'date' | 'date-time' -} + interface Date { + format: (fmt: string) => string + dateonly: boolean + utc: boolean + type: 'date' | 'date-time' + } -interface DOMTokenList { - find: (regex: string) => [number, string] | undefined -} + interface DOMTokenList { + find: (regex: string) => [number, string] | undefined + } -interface HTMLCollection { - forEach: (proc: ((el: Element) => void)) => void -} + interface HTMLCollection { + forEach: (proc: ((el: Element) => void)) => void + } -interface HTMLCollectionOf { - forEach: (proc: ((el: T) => void)) => void + interface HTMLCollectionOf { + forEach: (proc: ((el: T) => void)) => void + } } type uid = string -- cgit v1.2.3 From 44f8ae5ba2b6b4954d6562aff2f4e704cfa1a966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 1 Nov 2021 16:17:46 +0100 Subject: Limit exports to those used by imports. This gives a clearer picture of what is dead code and what isn't. --- static/lib.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index fe5ef1bd..d8e881ac 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -9,6 +9,9 @@ export { General procedures which in theory could be used anywhere. */ +/* + * https://www.typescriptlang.org/docs/handbook/declaration-merging.html + */ declare global { interface Object { format: (fmt: string) => string -- cgit v1.2.3 From ae3142da0cf31696f4ab4ad258c5483b7c5490b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 8 Nov 2021 19:38:42 +0100 Subject: Major work on event creation. --- static/lib.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index d8e881ac..ee8046aa 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -4,7 +4,6 @@ export { xcal, asList, round_time } -'use strict'; /* General procedures which in theory could be used anywhere. */ -- cgit v1.2.3 From 410404cfdd54c083b6609fd52334e02d320145d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Wed, 10 Nov 2021 01:40:22 +0100 Subject: Re-modularize javascript. This moves almost everything out of globals.ts, into sepparate files. Things are still slightly to tightly coupled. But that is worked on. --- static/lib.ts | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index ee8046aa..1dfd83f4 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -1,7 +1,7 @@ export { - makeElement, date_to_percent, uid, - parseDate, gensym, to_local, boolean, - xcal, asList, round_time + makeElement, date_to_percent, + parseDate, gensym, to_local, to_boolean, + asList, round_time } /* @@ -41,8 +41,6 @@ declare global { } } -type uid = string - HTMLElement.prototype._addEventListener = HTMLElement.prototype.addEventListener; HTMLElement.prototype.addEventListener = function(name: string, proc: (e: Event) => void) { if (!this.listeners) this.listeners = {}; @@ -52,17 +50,6 @@ HTMLElement.prototype.addEventListener = function(name: string, proc: (e: Event) }; - -/* list of lists -> list of tuples */ -/* TODO figure out how to type this correctly */ -function zip(...args: any[]) { - // console.log(args); - if (args === []) return []; - return [...Array(Math.min(...args.map(x => x.length))).keys()] - .map((_, i) => args.map(lst => lst[i])); -} - - /* ----- Date Extensions ---------------------------- */ /* @@ -120,13 +107,6 @@ function parseDate(str: string): Date { return date; } -function copyDate(date: Date): Date { - let d = new Date(date); - d.utc = date.utc; - d.dateonly = date.dateonly; - return d; -} - function to_local(date: Date): Date { if (!date.utc) return date; @@ -162,11 +142,6 @@ function date_to_percent(date: Date): number /* in 0, 100 */ { /* js infix to not collide with stuff generated backend */ const gensym = (counter => (prefix = "gensym") => prefix + "js" + ++counter)(0) -function setVar(str: string, val: any) { - document.documentElement.style.setProperty("--" + str, val); -} - - function asList(thing: Array | T): Array { if (thing instanceof Array) { return thing; @@ -176,7 +151,7 @@ function asList(thing: Array | T): Array { } -function boolean(value: any): boolean { +function to_boolean(value: any): boolean { switch (typeof value) { case 'string': switch (value) { @@ -248,5 +223,3 @@ HTMLCollection.prototype.forEach = function(proc) { proc(el); } } - -const xcal = "urn:ietf:params:xml:ns:icalendar-2.0"; -- cgit v1.2.3 From 1205d555835772da4e43e0dc8bd60ac449c74ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 15 Nov 2021 00:50:44 +0100 Subject: Add HTMLElement.getListeners. --- static/lib.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index 1dfd83f4..8845f37b 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -18,7 +18,8 @@ declare global { interface HTMLElement { _addEventListener: (name: string, proc: (e: Event) => void) => void - listeners: Record void)[]> + listeners: Map void)[]> + getListeners: () => Map void)[]> } interface Date { @@ -43,11 +44,15 @@ declare global { HTMLElement.prototype._addEventListener = HTMLElement.prototype.addEventListener; HTMLElement.prototype.addEventListener = function(name: string, proc: (e: Event) => void) { - if (!this.listeners) this.listeners = {}; - if (!this.listeners[name]) this.listeners[name] = []; - this.listeners[name].push(proc); + if (!this.listeners) this.listeners = new Map + if (!this.listeners.get(name)) this.listeners.set(name, []); + /* Force since we ensure a value just above */ + this.listeners.get(name)!.push(proc); return this._addEventListener(name, proc); }; +HTMLElement.prototype.getListeners = function() { + return this.listeners; +} /* ----- Date Extensions ---------------------------- */ -- cgit v1.2.3 From d35e5c90fb164f3650b4f273f7abc7c2afad84be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 26 Nov 2021 17:12:54 +0100 Subject: Fix datetime becomming dateonly when hitting midnight. --- static/lib.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index 8845f37b..bc072545 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -24,9 +24,9 @@ declare global { interface Date { format: (fmt: string) => string - dateonly: boolean utc: boolean - type: 'date' | 'date-time' + dateonly: boolean + // type: 'date' | 'date-time' } interface DOMTokenList { -- cgit v1.2.3 From e71f0c20adc4dc2f49bca99a859241fdadf376d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 30 Nov 2021 01:09:53 +0100 Subject: Rework tab system. This sepparates popup-elements from their tabbed contents, allowing clearer sepparations of concerns, along with easier adding and removing of tabs to the tabset! --- static/lib.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'static/lib.ts') diff --git a/static/lib.ts b/static/lib.ts index bc072545..2ef5b596 100644 --- a/static/lib.ts +++ b/static/lib.ts @@ -120,11 +120,14 @@ function to_local(date: Date): Date { /* -------------------------------------------------- */ -function makeElement(name: string, attr = {}): HTMLElement { +function makeElement(name: string, attr = {}, actualAttr = {}): HTMLElement { let element: HTMLElement = document.createElement(name); for (let [key, value] of Object.entries(attr)) { (element as any)[key] = value; } + for (let [key, value] of Object.entries(actualAttr)) { + element.setAttribute(key, '' + value); + } return element; } -- cgit v1.2.3