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/vevent.ts | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 static/vevent.ts (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts new file mode 100644 index 00000000..678f2134 --- /dev/null +++ b/static/vevent.ts @@ -0,0 +1,214 @@ +"use strict"; + +class VEventValue { + constructor (type, value, parameters = {}) { + this.type = type; + this.value = value; + this.parameters = parameters; + } + + to_jcal () { + let value; + let v = this.value; + switch (this.type) { + case 'binary': + /* TOOD */ + break; + case 'date-time': + value = v.format("~Y-~m-~dT~H:~M:~S"); + // TODO TZ + break; + case 'date': + value = v.format("~Y-~m-~d"); + break; + case 'duration': + /* TODO */ + break; + case 'period': + /* TODO */ + break; + case 'utc-offset': + /* TODO */ + break; + case 'recur': + value = v.asJcal(); + break; + + case 'float': + case 'integer': + case 'text': + case 'uri': + case 'cal-address': + case 'boolean': + value = v; + } + return [this.parameters, this.type, value]; + } +} + +/* maybe ... */ +class VEventDuration extends VEventValue { +} + +class VEvent { + constructor (properties = {}, components = []) { + this.properties = properties; + this.components = components; + this.registered = []; + } + + getProperty (key) { + let e = this.properties[key]; + if (! e) return e; + return e.value; + } + + setProperty (key, value) { + let e = this.properties[key]; + if (! e) { + let type = (valid_input_types[key.toUpperCase()] || ['unknown'])[0] + if (typeof type === typeof []) type = type[0]; + e = this.properties[key] = new VEventValue(type, value); + } else { + e.value = value; + } + for (let el of this.registered) { + /* TODO update correct fields, allow component to redraw themselves */ + console.log(el); + el.redraw(this); + } + } + + register (htmlNode) { + this.registered.push(htmlNode); + } + + to_jcal () { + let out_properties = [] + for (let [key, value] of Object.entries(this.properties)) { + let sub = value.to_jcal(); + sub.unshift(key) + out_properties.push(sub); + } + return ['vevent', out_properties, [/* alarms go here*/]] + } +} + +function make_vevent_value (value_tag) { + /* TODO parameters */ + return new VEventValue (value_tag.tagName, make_vevent_value_ (value_tag)); +} + +function make_vevent_value_ (value_tag) { + /* RFC6321 3.6. */ + switch (value_tag.tagName) { + case 'binary': + /* Base64 to binary + Seems to handle inline whitespace, which xCal standard reqires + */ + return atob(value_tag.innerHTML) + break; + + case 'boolean': + switch (value_tag.innerHTML) { + case 'true': return true; + case 'false': return false; + default: + console.warn(`Bad boolean ${value_tag.innerHTML}, defaulting with !!`) + return !! value_tag.innerHTML; + } + break; + + case 'time': + case 'date': + case 'date-time': + return parseDate(value_tag.innerHTML); + break; + + case 'duration': + /* TODO duration parser here 'P1D' */ + return value_tag.innerHTML; + break; + + case 'float': + case 'integer': + return +value_tag.innerHTML; + break; + + case 'period': + /* TODO has sub components, meaning that a string wont do */ + let start = value_tag.getElementsByTagName('start')[0] + parseDate(start.innerHTML); + let other; + if ((other = value_tag.getElementsByTagName('end')[0])) { + return parseDate(other.innerHTML) + } else if ((other = value_tag.getElementsByTagName('duration')[0])) { + /* TODO parse duration */ + return other.innerHTML + } else { + console.warn('Invalid end to period, defaulting to 1H'); + return new Date(3600); + } + + case 'recur': + /* TODO parse */ + return ""; + + case 'utc-offset': + /* TODO parse */ + return ""; + + default: + console.warn(`Unknown type '${value_tag.tagName}', defaulting to string`) + case 'cal-address': + case 'uri': + case 'text': + return value_tag.innerHTML; + } +} + +/* xml dom object -> class VEvent */ +function xml_to_vcal (xml) { + /* xml MUST have a VEVENT (or equivalent) as its root */ + let properties = xml.getElementsByTagName('properties')[0]; + let components = xml.getElementsByTagName('components')[0]; + + let property_map = {} + if (properties) { + for (var i = 0; i < properties.childElementCount; i++) { + let tag = properties.childNodes[i]; + let parameters = {}; + let value = []; + for (var j = 0; j < tag.childElementCount; j++) { + let child = tag.childNodes[j]; + switch (tag.tagName) { + case 'parameters': + parameters = /* handle parameters */ {}; + break; + + /* These can contain multiple value tags, per + RFC6321 3.4.1.1. */ + case 'categories': + case 'resources': + case 'freebusy': + case 'exdate': + case 'rdate': + value.push(make_vevent_value(child)); + break; + default: + value = make_vevent_value(child); + } + } + property_map[tag.tagName] = value; + } + } + + let component_list = [] + if (components) { + for (let child of components.childNodes) { + component_list.push(xml_to_vcal(child)) + } + } + + return new VEvent(property_map, component_list) +} -- 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/vevent.ts | 268 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 146 insertions(+), 122 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 678f2134..72ab28b1 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,46 +1,55 @@ "use strict"; +interface Redrawable extends HTMLElement { + redraw: ((data: VEvent) => void) +} + class VEventValue { - constructor (type, value, parameters = {}) { + + type: ical_type + value: any + parameters: Map + + constructor(type: ical_type, value: any, parameters = new Map()) { this.type = type; this.value = value; this.parameters = parameters; } - to_jcal () { + to_jcal(): [Map, ical_type, any] { let value; let v = this.value; switch (this.type) { - case 'binary': - /* TOOD */ - break; - case 'date-time': - value = v.format("~Y-~m-~dT~H:~M:~S"); - // TODO TZ - break; - case 'date': - value = v.format("~Y-~m-~d"); - break; - case 'duration': - /* TODO */ - break; - case 'period': - /* TODO */ - break; - case 'utc-offset': - /* TODO */ - break; - case 'recur': - value = v.asJcal(); - break; - - case 'float': - case 'integer': - case 'text': - case 'uri': - case 'cal-address': - case 'boolean': - value = v; + case 'binary': + /* TOOD */ + break; + case 'date-time': + value = v.format("~Y-~m-~dT~H:~M:~S"); + // TODO TZ + break; + case 'date': + value = v.format("~Y-~m-~d"); + break; + case 'duration': + /* TODO */ + break; + case 'period': + /* TODO */ + break; + case 'utc-offset': + /* TODO */ + break; + case 'recur': + value = v.asJcal(); + break; + + case 'float': + case 'integer': + case 'text': + case 'uri': + case 'cal-address': + case 'boolean': + value = v; } return [this.parameters, this.type, value]; } @@ -51,24 +60,38 @@ class VEventDuration extends VEventValue { } class VEvent { - constructor (properties = {}, components = []) { + + properties: Map + components: VEvent[] + registered: Redrawable[] + + constructor(properties: Map = new Map(), components: VEvent[] = []) { this.properties = properties; this.components = components; this.registered = []; } - getProperty (key) { - let e = this.properties[key]; - if (! e) return e; + getProperty(key: string): any | undefined { + let e = this.properties.get(key); + if (!e) return e; return e.value; } - setProperty (key, value) { - let e = this.properties[key]; - if (! e) { - let type = (valid_input_types[key.toUpperCase()] || ['unknown'])[0] - if (typeof type === typeof []) type = type[0]; - e = this.properties[key] = new VEventValue(type, value); + setProperty(key: string, value: any) { + let e = this.properties.get(key); + if (!e) { + key = key.toUpperCase() + let type: ical_type + let type_ = valid_input_types.get(key) + if (type_ === undefined) { + type = 'unknown' + } else if (type_ instanceof Array) { + type = type_[0] + } else { + type = type_ + } + e = new VEventValue(type, value) + this.properties.set(key, e); } else { e.value = value; } @@ -79,11 +102,11 @@ class VEvent { } } - register (htmlNode) { + register(htmlNode: Redrawable) { this.registered.push(htmlNode); } - to_jcal () { + to_jcal(): JCal { let out_properties = [] for (let [key, value] of Object.entries(this.properties)) { let sub = value.to_jcal(); @@ -94,118 +117,119 @@ class VEvent { } } -function make_vevent_value (value_tag) { +function make_vevent_value(value_tag: Element) { /* TODO parameters */ - return new VEventValue (value_tag.tagName, make_vevent_value_ (value_tag)); + return new VEventValue( + /* TODO error on invalid type? */ + value_tag.tagName as ical_type, + make_vevent_value_(value_tag)); } -function make_vevent_value_ (value_tag) { +function make_vevent_value_(value_tag: Element) { /* RFC6321 3.6. */ switch (value_tag.tagName) { - case 'binary': - /* Base64 to binary - Seems to handle inline whitespace, which xCal standard reqires - */ - return atob(value_tag.innerHTML) - break; - - case 'boolean': - switch (value_tag.innerHTML) { - case 'true': return true; - case 'false': return false; - default: - console.warn(`Bad boolean ${value_tag.innerHTML}, defaulting with !!`) - return !! value_tag.innerHTML; - } - break; - - case 'time': - case 'date': - case 'date-time': - return parseDate(value_tag.innerHTML); - break; - - case 'duration': - /* TODO duration parser here 'P1D' */ - return value_tag.innerHTML; - break; - - case 'float': - case 'integer': - return +value_tag.innerHTML; - break; - - case 'period': - /* TODO has sub components, meaning that a string wont do */ - let start = value_tag.getElementsByTagName('start')[0] - parseDate(start.innerHTML); - let other; - if ((other = value_tag.getElementsByTagName('end')[0])) { - return parseDate(other.innerHTML) - } else if ((other = value_tag.getElementsByTagName('duration')[0])) { - /* TODO parse duration */ - return other.innerHTML - } else { - console.warn('Invalid end to period, defaulting to 1H'); - return new Date(3600); - } + case 'binary': + /* Base64 to binary + Seems to handle inline whitespace, which xCal standard reqires + */ + return atob(value_tag.innerHTML) + + case 'boolean': + switch (value_tag.innerHTML) { + case 'true': return true; + case 'false': return false; + default: + console.warn(`Bad boolean ${value_tag.innerHTML}, defaulting with !!`) + return !!value_tag.innerHTML; + } + + case 'time': + case 'date': + case 'date-time': + return parseDate(value_tag.innerHTML); + + case 'duration': + /* TODO duration parser here 'P1D' */ + return value_tag.innerHTML; + + case 'float': + case 'integer': + return +value_tag.innerHTML; + + case 'period': + /* TODO has sub components, meaning that a string wont do */ + let start = value_tag.getElementsByTagName('start')[0] + parseDate(start.innerHTML); + let other; + if ((other = value_tag.getElementsByTagName('end')[0])) { + return parseDate(other.innerHTML) + } else if ((other = value_tag.getElementsByTagName('duration')[0])) { + /* TODO parse duration */ + return other.innerHTML + } else { + console.warn('Invalid end to period, defaulting to 1H'); + return new Date(3600); + } - case 'recur': - /* TODO parse */ - return ""; + case 'recur': + /* TODO parse */ + return ""; - case 'utc-offset': - /* TODO parse */ - return ""; + case 'utc-offset': + /* TODO parse */ + return ""; - default: - console.warn(`Unknown type '${value_tag.tagName}', defaulting to string`) - case 'cal-address': - case 'uri': - case 'text': - return value_tag.innerHTML; + default: + console.warn(`Unknown type '${value_tag.tagName}', defaulting to string`) + case 'cal-address': + case 'uri': + case 'text': + return value_tag.innerHTML; } } /* xml dom object -> class VEvent */ -function xml_to_vcal (xml) { +function xml_to_vcal(xml: Element): VEvent { /* xml MUST have a VEVENT (or equivalent) as its root */ let properties = xml.getElementsByTagName('properties')[0]; let components = xml.getElementsByTagName('components')[0]; - let property_map = {} + let property_map = new Map() if (properties) { for (var i = 0; i < properties.childElementCount; i++) { let tag = properties.childNodes[i]; + if (!(tag instanceof Element)) continue; let parameters = {}; - let value = []; + let value: VEventValue | VEventValue[] = []; for (var j = 0; j < tag.childElementCount; j++) { let child = tag.childNodes[j]; + if (!(child instanceof Element)) continue; switch (tag.tagName) { - case 'parameters': - parameters = /* handle parameters */ {}; - break; + case 'parameters': + parameters = /* TODO handle parameters */ {}; + break; /* These can contain multiple value tags, per RFC6321 3.4.1.1. */ - case 'categories': - case 'resources': - case 'freebusy': - case 'exdate': - case 'rdate': - value.push(make_vevent_value(child)); - break; - default: - value = make_vevent_value(child); + case 'categories': + case 'resources': + case 'freebusy': + case 'exdate': + case 'rdate': + (value as VEventValue[]).push(make_vevent_value(child)); + break; + default: + value = make_vevent_value(child); } } - property_map[tag.tagName] = value; + property_map.set(tag.tagName, value); } } let component_list = [] if (components) { for (let child of components.childNodes) { + if (!(child instanceof Element)) continue; component_list.push(xml_to_vcal(child)) } } -- cgit v1.2.3 From 4f499ccbf71d0ae662159515bb568826e72678a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Wed, 6 Oct 2021 04:32:11 +0200 Subject: Drive popup tabs through javascript. --- static/vevent.ts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 9d6cec88..ade5d222 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -77,6 +77,10 @@ class VEvent { return e.value; } + get boundProperties(): IterableIterator { + return this.properties.keys() + } + setProperty(key: string, value: any) { let e = this.properties.get(key); if (!e) { -- 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/vevent.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index ade5d222..20b668ee 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -82,6 +82,7 @@ class VEvent { } setProperty(key: string, value: any) { + console.log(key, value); let e = this.properties.get(key); if (!e) { key = key.toUpperCase() -- 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/vevent.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 20b668ee..f25c5341 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,3 +1,6 @@ +import { ical_type, valid_input_types, JCal } from './types' +export { VEvent, xml_to_vcal } + "use strict"; interface Redrawable extends HTMLElement { -- 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/vevent.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index f25c5341..0fef9685 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,4 +1,5 @@ import { ical_type, valid_input_types, JCal } from './types' +import { uid, parseDate } from './lib' export { VEvent, xml_to_vcal } "use strict"; -- cgit v1.2.3 From 3afc7d26dcca96925be2e4230b4194a9b335af2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 5 Nov 2021 21:50:18 +0100 Subject: doc updates. --- static/vevent.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 0fef9685..377cb6ae 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,9 +1,11 @@ import { ical_type, valid_input_types, JCal } from './types' import { uid, parseDate } from './lib' + export { VEvent, xml_to_vcal } "use strict"; +/* Something which can be redrawn */ interface Redrawable extends HTMLElement { redraw: ((data: VEvent) => void) } @@ -63,10 +65,21 @@ class VEventValue { class VEventDuration extends VEventValue { } +/* + Abstract representation of a calendar event (or similar). +All "live" calendar data in the frontend should live in an object of this type. + */ class VEvent { + /* Calendar properties */ properties: Map + + /* Children (such as alarms for events) */ components: VEvent[] + + /* HTMLElements which wants to be redrawn when this object changes. + Elements can be registered with the @code{register} method. + */ registered: Redrawable[] constructor(properties: Map = new Map(), components: VEvent[] = []) { @@ -197,7 +210,6 @@ function make_vevent_value_(value_tag: Element) { } } -/* xml dom object -> class VEvent */ function xml_to_vcal(xml: Element): VEvent { /* xml MUST have a VEVENT (or equivalent) as its root */ let properties = xml.getElementsByTagName('properties')[0]; -- cgit v1.2.3 From 724828b505eb1744e3616990528547e883481f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 8 Nov 2021 18:29:35 +0100 Subject: JS normalize all vevent property keys to upper case. --- static/vevent.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 377cb6ae..50c3e1a9 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -82,13 +82,21 @@ class VEvent { */ registered: Redrawable[] - constructor(properties: Map = new Map(), components: VEvent[] = []) { - this.properties = properties; + constructor(properties: Map = new Map(), components: VEvent[] = []) { this.components = components; this.registered = []; + /* Re-normalize all given keys to upper case. We could require + * that beforehand, this is much more reliable, for only a + * marginal performance hit. + */ + this.properties = new Map; + for (const [key, value] of properties) { + this.properties.set(key.toUpperCase(), value); + } } getProperty(key: string): any | undefined { + key = key.toUpperCase() let e = this.properties.get(key); if (!e) return e; return e.value; @@ -99,10 +107,9 @@ class VEvent { } setProperty(key: string, value: any) { - console.log(key, value); + key = key.toUpperCase(); let e = this.properties.get(key); if (!e) { - key = key.toUpperCase() let type: ical_type let type_ = valid_input_types.get(key) if (type_ === undefined) { @@ -118,8 +125,6 @@ class VEvent { e.value = value; } for (let el of this.registered) { - /* TODO update correct fields, allow component to redraw themselves */ - console.log(el); el.redraw(this); } } -- 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/vevent.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 50c3e1a9..e0424ad7 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -3,8 +3,6 @@ import { uid, parseDate } from './lib' export { VEvent, xml_to_vcal } -"use strict"; - /* Something which can be redrawn */ interface Redrawable extends HTMLElement { redraw: ((data: VEvent) => void) @@ -85,10 +83,10 @@ class VEvent { constructor(properties: Map = new Map(), components: VEvent[] = []) { this.components = components; this.registered = []; - /* Re-normalize all given keys to upper case. We could require - * that beforehand, this is much more reliable, for only a - * marginal performance hit. - */ + /* Re-normalize all given keys to upper case. We could require + * that beforehand, this is much more reliable, for only a + * marginal performance hit. + */ this.properties = new Map; for (const [key, value] of properties) { this.properties.set(key.toUpperCase(), value); -- cgit v1.2.3 From ca99de5d4a913a5dada84c22b8b3eaf7d3740e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Wed, 10 Nov 2021 00:15:28 +0100 Subject: Handle calendar change through dropdown. --- static/vevent.ts | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index e0424ad7..c9068106 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -80,6 +80,8 @@ class VEvent { */ registered: Redrawable[] + _calendar: string | null = null; + constructor(properties: Map = new Map(), components: VEvent[] = []) { this.components = components; this.registered = []; @@ -127,6 +129,13 @@ class VEvent { } } + setCalendar(calendar: string) { + this._calendar = calendar; + for (let el of this.registered) { + el.redraw(this); + } + } + register(htmlNode: Redrawable) { this.registered.push(htmlNode); } -- cgit v1.2.3 From c60a60422f69e29628b6c946a15be271e90015aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Wed, 10 Nov 2021 00:47:10 +0100 Subject: Basic event modification works again. --- static/vevent.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index c9068106..d8ef58ce 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,4 +1,4 @@ -import { ical_type, valid_input_types, JCal } from './types' +import { ical_type, valid_input_types, JCal, JCalProperty } from './types' import { uid, parseDate } from './lib' export { VEvent, xml_to_vcal } @@ -141,11 +141,14 @@ class VEvent { } to_jcal(): JCal { - let out_properties = [] - for (let [key, value] of Object.entries(this.properties)) { - let sub = value.to_jcal(); - sub.unshift(key) - out_properties.push(sub); + let out_properties: JCalProperty[] = [] + console.log(this.properties); + for (let [key, value] of this.properties) { + let prop: JCalProperty = [ + key.toLowerCase(), + ...value.to_jcal(), + ] + out_properties.push(prop); } return ['vevent', out_properties, [/* alarms go here*/]] } -- 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/vevent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index d8ef58ce..ddabb507 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,5 +1,5 @@ -import { ical_type, valid_input_types, JCal, JCalProperty } from './types' -import { uid, parseDate } from './lib' +import { uid, ical_type, valid_input_types, JCal, JCalProperty } from './types' +import { parseDate } from './lib' export { VEvent, xml_to_vcal } -- cgit v1.2.3 From ecdb4b7eeb42dc859cfd6aa31634b423b72c50bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 15 Nov 2021 00:47:13 +0100 Subject: Rework some drawing and how calendar is accessed. --- static/vevent.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index ddabb507..4f47f8e3 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -129,13 +129,17 @@ class VEvent { } } - setCalendar(calendar: string) { + set calendar(calendar: string | null) { this._calendar = calendar; for (let el of this.registered) { el.redraw(this); } } + get calendar(): string | null { + return this._calendar; + } + register(htmlNode: Redrawable) { this.registered.push(htmlNode); } -- cgit v1.2.3 From b0170d8cbb14a05d791ae5560c6e15da3fabfd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 15 Nov 2021 00:47:37 +0100 Subject: cleanup --- static/vevent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 4f47f8e3..307c572f 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -236,7 +236,8 @@ function xml_to_vcal(xml: Element): VEvent { let property_map = new Map() if (properties) { - property_loop: for (var i = 0; i < properties.childElementCount; i++) { + property_loop: + for (var i = 0; i < properties.childElementCount; i++) { let tag = properties.childNodes[i]; if (!(tag instanceof Element)) continue; let parameters = {}; -- cgit v1.2.3 From e5d682702f6954ebab946ca0eb67ab22f465f6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 18 Nov 2021 21:40:19 +0100 Subject: Add setProperties, add type info to setProperty. --- static/vevent.ts | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 307c572f..0c262208 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -106,11 +106,15 @@ class VEvent { return this.properties.keys() } - setProperty(key: string, value: any) { + __setPropertyInternal(key: string, value: any, type?: ical_type) { key = key.toUpperCase(); let e = this.properties.get(key); - if (!e) { - let type: ical_type + if (e) { + if (type) { e.type = type; } + e.value = value; + return; + } + if (!type) { let type_ = valid_input_types.get(key) if (type_ === undefined) { type = 'unknown' @@ -119,16 +123,28 @@ class VEvent { } else { type = type_ } - e = new VEventValue(type, value) - this.properties.set(key, e); - } else { - e.value = value; + } + e = new VEventValue(type, value) + this.properties.set(key, e); + } + + setProperty(key: string, value: any, type?: ical_type) { + this.__setPropertyInternal(key, value, type); + for (let el of this.registered) { + el.redraw(this); + } + } + + setProperties(pairs: [string, any, ical_type?][]) { + for (let pair of pairs) { + this.__setPropertyInternal(...pair); } for (let el of this.registered) { el.redraw(this); } } + set calendar(calendar: string | null) { this._calendar = calendar; for (let el of this.registered) { -- cgit v1.2.3 From 1caf04eca708a148e76aab04ece25e0bffe335a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 19 Nov 2021 01:33:15 +0100 Subject: Parse RRULE:s. --- static/vevent.ts | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 3 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 0c262208..dd75d362 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,7 +1,10 @@ import { uid, ical_type, valid_input_types, JCal, JCalProperty } from './types' import { parseDate } from './lib' -export { VEvent, xml_to_vcal } +export { + VEvent, xml_to_vcal, + RecurrenceRule +} /* Something which can be redrawn */ interface Redrawable extends HTMLElement { @@ -182,6 +185,140 @@ function make_vevent_value(value_tag: Element) { make_vevent_value_(value_tag)); } + +// + + + +type freqType = 'SECONDLY' | 'MINUTELY' | 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY' +type weekday = 'MO' | 'TU' | 'WE' | 'TH' | 'FR' | 'SA' | 'SU' + +class RecurrenceRule { + freq?: freqType + until?: Date + count?: number + interval?: number + bysecond?: number[] + byminute?: number[] + byhour?: number[] + byday?: (weekday | [number, weekday])[] + bymonthday?: number[] + byyearday?: number[] + byweekno?: number[] + bymonth?: number[] + bysetpos?: number[] + wkst?: weekday + + to_jcal() { + let obj: any = {} + if (this.freq) obj['freq'] = this.freq; + if (this.until) obj['until'] = this.until.format(this.until.dateonly + ? '~Y-~M~D' + : '~Y-~M~DT~H:~M:~S'); + if (this.count) obj['count'] = this.count; + if (this.interval) obj['interval'] = this.interval; + if (this.bysecond) obj['bysecond'] = this.bysecond; + if (this.byminute) obj['byminute'] = this.byminute; + if (this.byhour) obj['byhour'] = this.byhour; + if (this.bymonthday) obj['bymonthday'] = this.bymonthday; + if (this.byyearday) obj['byyearday'] = this.byyearday; + if (this.byweekno) obj['byweekno'] = this.byweekno; + if (this.bymonth) obj['bymonth'] = this.bymonth; + if (this.bysetpos) obj['bysetpos'] = this.bysetpos; + + if (this.byday) { + let outarr: string[] = [] + for (let byday of this.byday) { + if (byday instanceof Array) { + let [num, day] = byday; + outarr.push(`${num}${day}`) + } else { + outarr.push(byday) + } + } + obj['byday'] = outarr + } + + if (this.wkst) obj['wkst'] = this.wkst; + + return obj; + } +} + +function xml_to_recurrence_rule(xml: Element): RecurrenceRule { + let rr = new RecurrenceRule; + + if (xml.tagName.toLowerCase() !== 'recur') { + throw new TypeError(); + } + let by = new Map([ + ['bysecond', []], + ['byminute', []], + ['byhour', []], + ['bymonthday', []], + ['byyearday', []], + ['byweekno', []], + ['bymonth', []], + ['bysetpos', []], + ['byday', []], + ]); + + + for (let child of xml.children) { + /* see appendix a 3.3.10 RECUR of RFC 6321 */ + let t = child.innerHTML; + let tn = child.tagName.toLowerCase() + + switch (tn) { + case 'freq': + rr.freq = t as freqType + break; + + case 'until': + rr.until = parseDate(t); + break; + + case 'count': + case 'interval': + rr.count = Number(t) + break; + + case 'bysecond': + case 'byminute': + case 'byhour': + case 'bymonthday': + case 'byyearday': + case 'byweekno': + case 'bymonth': + case 'bysetpos': + by.get(tn)!.push(Number(t)); + break; + + case 'byday': + // xsd:integer? type-weekday + let m = t.match(/([+-]?[0-9]*)([A-Z]{2})/) + if (m == null) throw new TypeError() + else if (m[1] === '') by.get('byday')!.push(m[2] as weekday) + else by.get('byday')!.push([Number(m[1]), m[2] as weekday]) + break; + + case 'wkst': + rr.wkst = t as weekday + break; + } + } + + for (let [key, value] of by) { + if (!value || value.length == 0) continue; + (rr as any)[key] = value; + } + + return rr; +} + +// + + function make_vevent_value_(value_tag: Element) { /* RFC6321 3.6. */ switch (value_tag.tagName) { @@ -229,8 +366,7 @@ function make_vevent_value_(value_tag: Element) { } case 'recur': - /* TODO parse */ - return ""; + return xml_to_recurrence_rule(value_tag); case 'utc-offset': /* TODO parse */ -- cgit v1.2.3 From b3d72678192902252613e654c3fada1e57250ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 22 Nov 2021 01:09:04 +0100 Subject: Change innerHTML to textContent. Also changed some innerText to textContent --- static/vevent.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index dd75d362..9bfd8dcf 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -266,7 +266,7 @@ function xml_to_recurrence_rule(xml: Element): RecurrenceRule { for (let child of xml.children) { /* see appendix a 3.3.10 RECUR of RFC 6321 */ - let t = child.innerHTML; + let t = child.textContent || ''; let tn = child.tagName.toLowerCase() switch (tn) { @@ -326,40 +326,40 @@ function make_vevent_value_(value_tag: Element) { /* Base64 to binary Seems to handle inline whitespace, which xCal standard reqires */ - return atob(value_tag.innerHTML) + return atob(value_tag.textContent || '') case 'boolean': - switch (value_tag.innerHTML) { + switch (value_tag.textContent) { case 'true': return true; case 'false': return false; default: - console.warn(`Bad boolean ${value_tag.innerHTML}, defaulting with !!`) - return !!value_tag.innerHTML; + console.warn(`Bad boolean ${value_tag.textContent}, defaulting with !!`) + return !!value_tag.textContent; } case 'time': case 'date': case 'date-time': - return parseDate(value_tag.innerHTML); + return parseDate(value_tag.textContent || ''); case 'duration': /* TODO duration parser here 'P1D' */ - return value_tag.innerHTML; + return value_tag.textContent; case 'float': case 'integer': - return +value_tag.innerHTML; + return Number(value_tag.textContent); case 'period': /* TODO has sub components, meaning that a string wont do */ let start = value_tag.getElementsByTagName('start')[0] - parseDate(start.innerHTML); + parseDate(start.textContent || ''); let other; if ((other = value_tag.getElementsByTagName('end')[0])) { - return parseDate(other.innerHTML) + return parseDate(other.textContent || '') } else if ((other = value_tag.getElementsByTagName('duration')[0])) { /* TODO parse duration */ - return other.innerHTML + return other.textContent } else { console.warn('Invalid end to period, defaulting to 1H'); return new Date(3600); @@ -377,7 +377,7 @@ function make_vevent_value_(value_tag: Element) { case 'cal-address': case 'uri': case 'text': - return value_tag.innerHTML; + return value_tag.textContent; } } -- cgit v1.2.3 From 1df15b2ceaef09b48a39aa6046b577da11ea2f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 26 Nov 2021 15:32:41 +0100 Subject: Got categories working. --- static/vevent.ts | 114 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 26 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 9bfd8dcf..12d8267f 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -14,6 +14,9 @@ interface Redrawable extends HTMLElement { class VEventValue { type: ical_type + + /* value should NEVER be a list, since multi-valued properties should + be split into multiple VEventValue objects! */ value: any parameters: Map @@ -23,12 +26,13 @@ class VEventValue { this.parameters = parameters; } - to_jcal(): [Map, ical_type, any] { + to_jcal(): [Record, ical_type, any] { let value; let v = this.value; switch (this.type) { case 'binary': /* TOOD */ + value = 'BINARY DATA GOES HERE'; break; case 'date-time': value = v.format("~Y-~m-~dT~H:~M:~S"); @@ -39,12 +43,15 @@ class VEventValue { break; case 'duration': /* TODO */ + value = 'DURATION GOES HERE'; break; case 'period': /* TODO */ + value = 'PERIOD GOES HERE'; break; case 'utc-offset': /* TODO */ + value = 'UTC-OFFSET GOES HERE'; break; case 'recur': value = v.asJcal(); @@ -58,7 +65,8 @@ class VEventValue { case 'boolean': value = v; } - return [this.parameters, this.type, value]; + + return [this.parameters, this.type, value] } } @@ -66,6 +74,10 @@ class VEventValue { class VEventDuration extends VEventValue { } +type list_values + = 'categories' | 'resources' | 'freebusy' | 'exdate' | 'rdate' + | 'CATEGORIES' | 'RESOURCES' | 'FREEBUSY' | 'EXDATE' | 'RDATE'; + /* Abstract representation of a calendar event (or similar). All "live" calendar data in the frontend should live in an object of this type. @@ -73,7 +85,7 @@ All "live" calendar data in the frontend should live in an object of this type. class VEvent { /* Calendar properties */ - properties: Map + properties: Map /* Children (such as alarms for events) */ components: VEvent[] @@ -85,7 +97,10 @@ class VEvent { _calendar: string | null = null; - constructor(properties: Map = new Map(), components: VEvent[] = []) { + constructor( + properties: Map = new Map(), + components: VEvent[] = [] + ) { this.components = components; this.registered = []; /* Re-normalize all given keys to upper case. We could require @@ -98,10 +113,18 @@ class VEvent { } } - getProperty(key: string): any | undefined { + getProperty(key: list_values): any[] | undefined; + getProperty(key: string): any | undefined; + + // getProperty(key: 'categories'): string[] | undefined + + getProperty(key: string): any | any[] | undefined { key = key.toUpperCase() let e = this.properties.get(key); if (!e) return e; + if (Array.isArray(e)) { + return e.map(ee => ee.value) + } return e.value; } @@ -110,29 +133,52 @@ class VEvent { } __setPropertyInternal(key: string, value: any, type?: ical_type) { + function resolve_type(key: string, type?: ical_type): ical_type { + if (type) { + return type; + } else { + let type_options = valid_input_types.get(key) + if (type_options === undefined) { + type = 'unknown' + } else if (type_options.length == 0) { + type = 'unknown' + } else { + if (Array.isArray(type_options[0])) { + type = type_options[0][0] + } else { + type = type_options[0] + } + } + return type; + } + } + key = key.toUpperCase(); - let e = this.properties.get(key); - if (e) { - if (type) { e.type = type; } - e.value = value; + if (Array.isArray(value)) { + this.properties.set(key, + value.map(el => new VEventValue(resolve_type(key, type), el))) return; } - if (!type) { - let type_ = valid_input_types.get(key) - if (type_ === undefined) { - type = 'unknown' - } else if (type_ instanceof Array) { - type = type_[0] + let current = this.properties.get(key); + if (current) { + if (Array.isArray(current)) { } else { - type = type_ + if (type) { current.type = type; } + current.value = value; + return; } } - e = new VEventValue(type, value) - this.properties.set(key, e); + type = resolve_type(key, type); + let new_value = new VEventValue(type, value) + this.properties.set(key, new_value); } + setProperty(key: list_values, value: any[], type?: ical_type): void; + setProperty(key: string, value: any, type?: ical_type): void; + setProperty(key: string, value: any, type?: ical_type) { this.__setPropertyInternal(key, value, type); + for (let el of this.registered) { el.redraw(this); } @@ -167,12 +213,27 @@ class VEvent { let out_properties: JCalProperty[] = [] console.log(this.properties); for (let [key, value] of this.properties) { - let prop: JCalProperty = [ - key.toLowerCase(), - ...value.to_jcal(), - ] - out_properties.push(prop); + console.log("key = ", key, ", value = ", value); + if (Array.isArray(value)) { + if (value.length == 0) continue; + let mostly = value.map(v => v.to_jcal()) + let values = mostly.map(x => x[2]) + console.log("mostly", mostly) + out_properties.push([ + key.toLowerCase(), + mostly[0][0], + mostly[0][1], + ...values + ]) + } else { + let prop: JCalProperty = [ + key.toLowerCase(), + ...value.to_jcal(), + ] + out_properties.push(prop); + } } + return ['vevent', out_properties, [/* alarms go here*/]] } } @@ -209,7 +270,7 @@ class RecurrenceRule { bysetpos?: number[] wkst?: weekday - to_jcal() { + to_jcal(): Record { let obj: any = {} if (this.freq) obj['freq'] = this.freq; if (this.until) obj['until'] = this.until.format(this.until.dateonly @@ -386,7 +447,7 @@ function xml_to_vcal(xml: Element): VEvent { let properties = xml.getElementsByTagName('properties')[0]; let components = xml.getElementsByTagName('components')[0]; - let property_map = new Map() + let property_map: Map = new Map; if (properties) { property_loop: for (var i = 0; i < properties.childElementCount; i++) { @@ -394,7 +455,8 @@ function xml_to_vcal(xml: Element): VEvent { if (!(tag instanceof Element)) continue; let parameters = {}; let value: VEventValue | VEventValue[] = []; - value_loop: for (var j = 0; j < tag.childElementCount; j++) { + value_loop: + for (var j = 0; j < tag.childElementCount; j++) { let child = tag.childNodes[j]; if (!(child instanceof Element)) continue; if (child.tagName == 'parameters') { -- cgit v1.2.3 From 8ff65041995e3a1e046ba37b46a8f53454cea7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 26 Nov 2021 17:13:13 +0100 Subject: Minor cleanup. --- static/vevent.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 12d8267f..e35c469f 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -139,17 +139,16 @@ class VEvent { } else { let type_options = valid_input_types.get(key) if (type_options === undefined) { - type = 'unknown' + return 'unknown' } else if (type_options.length == 0) { - type = 'unknown' + return 'unknown' } else { if (Array.isArray(type_options[0])) { - type = type_options[0][0] + return type_options[0][0] } else { - type = type_options[0] + return type_options[0] } } - return type; } } @@ -162,6 +161,7 @@ class VEvent { let current = this.properties.get(key); if (current) { if (Array.isArray(current)) { + /* TODO something here? */ } else { if (type) { current.type = type; } current.value = value; @@ -238,7 +238,7 @@ class VEvent { } } -function make_vevent_value(value_tag: Element) { +function make_vevent_value(value_tag: Element): VEventValue { /* TODO parameters */ return new VEventValue( /* TODO error on invalid type? */ @@ -380,7 +380,7 @@ function xml_to_recurrence_rule(xml: Element): RecurrenceRule { // -function make_vevent_value_(value_tag: Element) { +function make_vevent_value_(value_tag: Element): string | boolean | Date | number | RecurrenceRule { /* RFC6321 3.6. */ switch (value_tag.tagName) { case 'binary': @@ -405,7 +405,7 @@ function make_vevent_value_(value_tag: Element) { case 'duration': /* TODO duration parser here 'P1D' */ - return value_tag.textContent; + return value_tag.textContent || ''; case 'float': case 'integer': @@ -420,7 +420,7 @@ function make_vevent_value_(value_tag: Element) { return parseDate(other.textContent || '') } else if ((other = value_tag.getElementsByTagName('duration')[0])) { /* TODO parse duration */ - return other.textContent + return other.textContent || '' } else { console.warn('Invalid end to period, defaulting to 1H'); return new Date(3600); @@ -438,7 +438,7 @@ function make_vevent_value_(value_tag: Element) { case 'cal-address': case 'uri': case 'text': - return value_tag.textContent; + return value_tag.textContent || ''; } } -- 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/vevent.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index e35c469f..4b6d44c6 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -3,7 +3,8 @@ import { parseDate } from './lib' export { VEvent, xml_to_vcal, - RecurrenceRule + RecurrenceRule, + isRedrawable, } /* Something which can be redrawn */ @@ -11,6 +12,11 @@ interface Redrawable extends HTMLElement { redraw: ((data: VEvent) => void) } +function isRedrawable(x: HTMLElement): x is Redrawable { + return 'redraw' in x +} + + class VEventValue { type: ical_type @@ -209,6 +215,10 @@ class VEvent { this.registered.push(htmlNode); } + unregister(htmlNode: Redrawable) { + this.registered = this.registered.filter(node => node !== htmlNode) + } + to_jcal(): JCal { let out_properties: JCalProperty[] = [] console.log(this.properties); -- cgit v1.2.3 From 6c537f3f60aaac8ae850f8ecaefc2a0d04a8431e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 2 Dec 2021 01:51:28 +0100 Subject: Add basic changelog view --- static/vevent.ts | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 4b6d44c6..c7dcd406 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,4 +1,4 @@ -import { uid, ical_type, valid_input_types, JCal, JCalProperty } from './types' +import { uid, ical_type, valid_input_types, JCal, JCalProperty, ChangeLogEntry } from './types' import { parseDate } from './lib' export { @@ -103,6 +103,32 @@ class VEvent { _calendar: string | null = null; + _changelog: ChangeLogEntry[] = [] + + addlog(entry: ChangeLogEntry) { + let len = this._changelog.length + let last = this._changelog[len - 1] + + // console.log('entry = ', entry, ', last = ', last); + + if (!last) { + // console.log('Adding new entry', entry, this.getProperty('uid')); + this._changelog.push(entry); + return; + } + + if (entry.type === last.type + && entry.name === last.name + && entry.from === last.to) { + this._changelog.pop(); + entry.from = last.from + // console.log('Changing old entry', entry, this.getProperty('uid')); + this._changelog.push(entry) + } else { + this._changelog.push(entry) + } + } + constructor( properties: Map = new Map(), components: VEvent[] = [] @@ -159,6 +185,20 @@ class VEvent { } key = key.toUpperCase(); + + /* + To is mostly for the user. From is to allow an undo button + */ + let entry: ChangeLogEntry = { + type: 'property', + name: key, + from: this.getProperty(key), // TODO what happens if getProperty returns a weird type + to: '' + value, + } + // console.log('Logging ', entry); + this.addlog(entry); + + if (Array.isArray(value)) { this.properties.set(key, value.map(el => new VEventValue(resolve_type(key, type), el))) @@ -201,6 +241,12 @@ class VEvent { set calendar(calendar: string | null) { + this.addlog({ + type: 'calendar', + name: '', + from: this._calendar, + to: calendar, + }); this._calendar = calendar; for (let el of this.registered) { el.redraw(this); -- cgit v1.2.3 From 15e50471776e702333920b188932f03ee1f8573b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 9 Dec 2021 19:17:46 +0100 Subject: Propagate recurring events to frontend. This handles each instance of a recurring event as its own unique event, which allows us to properly send it to the frontend. It's currently not possible to submit the repeating events back, but that is probably a underlying problem. --- static/vevent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index c7dcd406..994c9425 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -60,7 +60,7 @@ class VEventValue { value = 'UTC-OFFSET GOES HERE'; break; case 'recur': - value = v.asJcal(); + value = v.to_jcal(); break; case 'float': -- cgit v1.2.3 From 457ab3301782e4e91334961208c5e4bbde95987d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 10 Dec 2021 03:04:34 +0100 Subject: Add various type specifiers. --- static/vevent.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'static/vevent.ts') diff --git a/static/vevent.ts b/static/vevent.ts index 994c9425..cee26727 100644 --- a/static/vevent.ts +++ b/static/vevent.ts @@ -1,4 +1,4 @@ -import { uid, ical_type, valid_input_types, JCal, JCalProperty, ChangeLogEntry } from './types' +import { ical_type, valid_input_types, JCal, JCalProperty, ChangeLogEntry } from './types' import { parseDate } from './lib' export { @@ -91,7 +91,7 @@ All "live" calendar data in the frontend should live in an object of this type. class VEvent { /* Calendar properties */ - properties: Map + private properties: Map /* Children (such as alarms for events) */ components: VEvent[] @@ -164,7 +164,7 @@ class VEvent { return this.properties.keys() } - __setPropertyInternal(key: string, value: any, type?: ical_type) { + private setPropertyInternal(key: string, value: any, type?: ical_type) { function resolve_type(key: string, type?: ical_type): ical_type { if (type) { return type; @@ -223,7 +223,7 @@ class VEvent { setProperty(key: string, value: any, type?: ical_type): void; setProperty(key: string, value: any, type?: ical_type) { - this.__setPropertyInternal(key, value, type); + this.setPropertyInternal(key, value, type); for (let el of this.registered) { el.redraw(this); @@ -232,7 +232,7 @@ class VEvent { setProperties(pairs: [string, any, ical_type?][]) { for (let pair of pairs) { - this.__setPropertyInternal(...pair); + this.setPropertyInternal(...pair); } for (let el of this.registered) { el.redraw(this); -- cgit v1.2.3