From b52a9bfccbe11fedb646f41e0eae281b74c8a1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 28 Jan 2021 13:37:57 +0100 Subject: Look at mapping in vcal types to js types. --- static/script.js | 67 +++++++++++++++++++++++++++++++++++++++++++----- static/server_connect.js | 1 + static/types.js | 12 ++++----- 3 files changed, 68 insertions(+), 12 deletions(-) (limited to 'static') diff --git a/static/script.js b/static/script.js index 6b7ddcd9..68773231 100644 --- a/static/script.js +++ b/static/script.js @@ -542,19 +542,74 @@ function bind_properties (el, wide_event=false) { /* Bind vcomponent fields for this event */ for (let s of el.querySelectorAll(`${field} > :not(parameters)`)) { + /* s ≡ ... */ /* Binds value from XML-tree to javascript object [parsedate] TODO capture xcal type here, to enable us to output it to jcal later. */ - switch (field) { - case 'rrule': - el.properties['_value_rrule'] = recur_xml_to_rrule(s); + let parsedValue; + let type = s.tagName.toLowerCase(); + switch (type) { + case 'float': + case 'integer': + parsedValue = new Number(s.innerHTML); + parsedValue.type = type; break; + + case 'date-time': + case 'date': + parsedValue = parseDate(s.innerHTML); + break; + + /* TODO */ + case 'duration': + let start = s.getElementsByTagName('start'); + let end = s.getElementsByTagName('end, duration'); + if (end.tagName === 'period') { + parsePeriod(end.innerHTML); + } + break; + /* TODO */ + case 'period': + parsePeriod(s.innerHTML); + break; + /* TODO */ + case 'utc-offset': + break; + + case 'recur': + parsedValue = recur_xml_to_rrule(s); + break; + + case 'boolean': + switch (s.innerHTML) { + case 'true': parsedValue = true; break; + case 'false': parsedValue = false; break; + default: throw "Value error" + } + break; + + + case 'binary': + /* Binary is going to be BASE64 decoded, allowing us to ignore + it and handle it as a string for the time being */ + case 'cal-address': + case 'text': + case 'uri': + /* TODO Attributes on strings doesn't work + They do however work on String:s + */ + parsedValue = s.innerHTML; + // parsedValue.type = type; + break; + default: - el.properties["_value_" + field] = s.innerHTML; + parsedValue.type = 'unknown'; + parsedValue = s.innerHTML; } + el.properties['_value_rrule'] = parsedValue; } } @@ -569,7 +624,7 @@ function bind_properties (el, wide_event=false) { if (el.properties.dtstart) { /* [parsedate] */ - el.properties.dtstart = parseDate(el.properties.dtstart); + // el.properties.dtstart = parseDate(el.properties.dtstart); get_property(el, 'dtstart').push( [el.style, (s, v) => s[wide_event?'left':'top'] = 100 * (to_local(v) - start)/(end - start) + "%"]); @@ -577,7 +632,7 @@ function bind_properties (el, wide_event=false) { if (el.properties.dtend) { - el.properties.dtend = parseDate(el.properties.dtend); + // el.properties.dtend = parseDate(el.properties.dtend); get_property(el, 'dtend').push( // TODO right and bottom only works if used from the start. However, // events from the backend instead use top/left and width/height. diff --git a/static/server_connect.js b/static/server_connect.js index a50128ae..252d79eb 100644 --- a/static/server_connect.js +++ b/static/server_connect.js @@ -52,6 +52,7 @@ function event_to_jcal (event) { type = 'recur'; value = v.asJcal(); } + /* TODO period */ else { /* text types */ diff --git a/static/types.js b/static/types.js index 9a4aa01c..02ae2261 100644 --- a/static/types.js +++ b/static/types.js @@ -3,16 +3,16 @@ let all_types = [ 'text', 'uri', 'binary', - 'float', - 'integer', - 'date-time', - 'date', + 'float', /* Number.type = 'float' */ + 'integer', /* Number.type = 'integer' */ + 'date-time', /* Date */ + 'date', /* Date.dateonly = true */ 'duration', 'period', 'utc-offset', 'cal-address', - 'recur', - 'boolean', + 'recur', /* RRule */ + 'boolean', /* boolean */ ] let property_names = [ -- cgit v1.2.3 From cbe3c46a898822b6ee0f10366e561c6a8055a1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 2 Mar 2021 23:34:14 +0100 Subject: Start moving vcal stuff to own class. --- static/binders.js | 8 +- static/script.js | 307 ++---------------------------------------- static/server_connect.js | 47 +------ static/vcal.js | 343 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 362 insertions(+), 343 deletions(-) create mode 100644 static/vcal.js (limited to 'static') diff --git a/static/binders.js b/static/binders.js index 197fb368..729866f3 100644 --- a/static/binders.js +++ b/static/binders.js @@ -7,7 +7,7 @@ function bind_recur(el, e) { /* todo bind default slots of rrule */ - let p = get_property(el, 'rrule'); + let p = el.properties.get('rrule'); // let rrule = el.rrule; /* add listeners to bind-rr tags */ @@ -62,7 +62,7 @@ function bind_recur(el, e) { } function bind_edit(el, e) { - let p = get_property(el, e.dataset.property); + let p = el.properties.get(e.dataset.property); e.addEventListener('input', function () { el.properties[e.dataset.property] = this.value; }); @@ -89,8 +89,8 @@ function bind_edit(el, e) { } function bind_view(el, e) { - let f = (s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt); - get_property(el, e.dataset.property).push([e, f]); + let f = (s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt); + el.properties.get(e.dataset.property).push([e, f]); } diff --git a/static/script.js b/static/script.js index 68773231..d809cc25 100644 --- a/static/script.js +++ b/static/script.js @@ -19,6 +19,8 @@ class EventCreator { let popup = document.getElementById("popup-template") .firstChild.cloneNode(true); + /* TODO shouldn't this use transferListeners (or similar)? + See input_list.js:transferListeners */ popup.getElementsByClassName("edit-form")[0].onsubmit = function () { create_event(event); return false; /* stop default */ @@ -113,7 +115,10 @@ class EventCreator { this.appendChild(event); /* requires that event is child of an '.event-container'. */ - bind_properties(event, wide_element); + event.properties = new VComponent( + event, + wide_element=wide_element); + // bind_properties(event, wide_element); /* requires that dtstart and dtend properties are initialized */ @@ -159,6 +164,8 @@ class EventCreator { let d1 = new Date(container_start.getTime() + start_in_duration) let d2 = new Date(container_start.getTime() + end_in_duration) + // console.log(that.event); + console.log(d1, d2); that.event.properties.dtstart = d1; that.event.properties.dtend = d2; } @@ -187,6 +194,8 @@ class EventCreator { } } + + /* This incarnation of this function only adds the calendar switcher dropdown. All events are already editable by switching to that tab. @@ -227,6 +236,8 @@ function place_in_edit_mode (event) { tab.querySelector("input[name='summary']").focus(); } + + window.onload = function () { // let start_time = document.querySelector("meta[name='start-time']").content; // let end_time = document.querySelector("meta[name='end-time']").content; @@ -309,9 +320,9 @@ window.onload = function () { /* Bind all vcomponent properties into javascript. */ if (el.closest(".longevents")) { - bind_properties(el, true); + el.properties = new VComponent(el, true); } else { - bind_properties(el, false); + el.properties = new VComponent(el, true); } } @@ -373,293 +384,3 @@ window.onload = function () { } - -/* - Returns the _value_ slot of given field in event, creating it if needed . - el - the event to work on - field - name of the field - default_value - default value when creating - bind_to_ical - should this property be added to the icalendar subtree? -*/ -function get_property(el, field, default_value) { - if (! el.properties) { - /* TODO only have construction once */ - el.properties = {}; - el.properties.ical_properties = new Set() - } - - if (! el.properties["_slot_" + field]) { - el.properties["_slot_" + field] = []; - el.properties["_value_" + field] = default_value; - - Object.defineProperty( - el.properties, field, - { - get: function () { - return this["_value_" + field]; - }, - set: function (value) { - this["_value_" + field] = value; - for (let [slot,updater] of el.properties["_slot_" + field]) { - updater(slot, value); - } - } - }); - } - - return el.properties["_slot_" + field]; -} - - - -/* - Properties are icalendar properties. - - p['name'] to get and set value (also updates any connected slots) - - p['_value_name'] for raw value - p['_slot_name'] for connected slots, Vector of pairs, where the - car should be a reference to the slot, and the - cdr a procedure which takes a slot and a value - and binds the value to the slot. - */ -function bind_properties (el, wide_event=false) { - - el.properties = {} - el.properties.ical_properties = new Set() - let popup = popup_from_event(el); - // let children = el.getElementsByTagName("properties")[0].children; - - /* actual component (not popup) */ - /* - for (let e of el.querySelectorAll(".bind")) { - } - */ - - /* bind_recur */ - - /* primary display tab */ - - let p; - let lst = [...popup.querySelectorAll(".bind"), - ...el.querySelectorAll('.bind')]; - for (let e of lst) { - if ((p = e.closest('[data-bindby]'))) { - // console.log(p.dataset.bindby); - eval(p.dataset.bindby)(el, e); - } else { - let f = ((s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt)); - get_property(el, e.dataset.property).push([e, f]); - } - } - - // for (let e of popup.querySelectorAll(".summary-tab .bind")) { - // /* bind_view - // let f = (s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt); - // get_property(el, e.dataset.property).push([e, f]); - // */ - // } - - /* edit tab */ - // for (let e of popup.querySelectorAll(".edit-tab .bind")) { - // /* bind-edit - // let p = get_property(el, e.dataset.property); - // e.addEventListener('input', function () { - // el.properties[e.dataset.property] = this.value; - // }); - // let f; - // switch (e.tagName) { - // case 'input': - // switch (e.type) { - // case 'time': f = (s, v) => s.value = v.format("~H:~M"); break; - // case 'date': f = (s, v) => s.value = v.format("~Y-~m-~d"); break; - // // TODO remaining types cases - // default: f = (s, v) => s.value = v; - // } - // p.push([e, f]) - // break; - // case 'textarea': - // f = (s, v) => s.innerHTML = v; - // p.push([e, f]) - // break; - // default: - // alert("How did you get here??? " + e.tagName) - // break; - // } - // */ - // } - - /* checkbox for whole day */ - - for (let field of ['dtstart', 'dtend']) { - - get_property(el, `--${field}-time`).push( - [el, (el, v) => { let date = el.properties[field]; - if (v == '') return; - let [h,m,s] = v.split(':') - date.setHours(Number(h)); - date.setMinutes(Number(m)); - date.setSeconds(0); - el.properties[field] = date; }]) - get_property(el, `--${field}-date`).push( - [el, (el, v) => { let date = el.properties[field]; - if (v == '') return; - let [y,m,d] = v.split('-') - date.setYear(Number(y)/* - 1900*/); - date.setMonth(Number(m) - 1); - date.setDate(d); - el.properties[field] = date; }]) - - - /* Manual fetch of the fields instead of the general method, - to avoid an infinite loop of dtstart setting --dtstart-time, - and vice versa. - NOTE if many more fields require special treatment then a - general solution is required. - */ - get_property(el, field).push( - [el, (el, v) => { popup - .querySelector(`.edit-tab input[name='${field}-time']`) - .value = v.format("~H:~M"); - popup - .querySelector(`.edit-tab input[name='${field}-date']`) - .value = v.format("~Y-~m-~d"); - }]); - } - - for (let property of property_names) { - el.properties.ical_properties.add(property) - } - - /* icalendar properties */ - for (let child of el.querySelector("vevent > properties").children) { - /* child ≡ ... */ - - let field = child.tagName; - let lst = get_property(el, field); - - el.properties.ical_properties.add(field) - - /* Bind vcomponent fields for this event */ - for (let s of el.querySelectorAll(`${field} > :not(parameters)`)) { - /* s ≡ ... */ - - /* Binds value from XML-tree to javascript object - [parsedate] - - TODO capture xcal type here, to enable us to output it to jcal later. - */ - let parsedValue; - let type = s.tagName.toLowerCase(); - switch (type) { - case 'float': - case 'integer': - parsedValue = new Number(s.innerHTML); - parsedValue.type = type; - break; - - case 'date-time': - case 'date': - parsedValue = parseDate(s.innerHTML); - break; - - /* TODO */ - case 'duration': - let start = s.getElementsByTagName('start'); - let end = s.getElementsByTagName('end, duration'); - if (end.tagName === 'period') { - parsePeriod(end.innerHTML); - } - break; - /* TODO */ - case 'period': - parsePeriod(s.innerHTML); - break; - /* TODO */ - case 'utc-offset': - break; - - case 'recur': - parsedValue = recur_xml_to_rrule(s); - break; - - case 'boolean': - switch (s.innerHTML) { - case 'true': parsedValue = true; break; - case 'false': parsedValue = false; break; - default: throw "Value error" - } - break; - - - case 'binary': - /* Binary is going to be BASE64 decoded, allowing us to ignore - it and handle it as a string for the time being */ - case 'cal-address': - case 'text': - case 'uri': - /* TODO Attributes on strings doesn't work - They do however work on String:s - */ - parsedValue = s.innerHTML; - // parsedValue.type = type; - break; - - default: - parsedValue.type = 'unknown'; - parsedValue = s.innerHTML; - } - el.properties['_value_rrule'] = parsedValue; - } - } - - /* set up graphical display changes */ - let container = el.closest(".event-container"); - if (container === null) { - console.log("No enclosing event container for", el); - return; - } - let start = parseDate(container.dataset.start); - let end = parseDate(container.dataset.end); - - if (el.properties.dtstart) { - /* [parsedate] */ - // el.properties.dtstart = parseDate(el.properties.dtstart); - get_property(el, 'dtstart').push( - [el.style, (s, v) => - s[wide_event?'left':'top'] = 100 * (to_local(v) - start)/(end - start) + "%"]); - } - - - if (el.properties.dtend) { - // el.properties.dtend = parseDate(el.properties.dtend); - get_property(el, 'dtend').push( - // TODO right and bottom only works if used from the start. However, - // events from the backend instead use top/left and width/height. - // Normalize so all use the same, or find a way to convert between. - [el.style, - (s, v) => s[wide_event?'right':'bottom'] = 100 * (1 - (to_local(v)-start)/(end-start)) + "%"]); - } - - - /* ---------- Calendar ------------------------------ */ - - if (! el.dataset.calendar) { - el.dataset.calendar = "Unknown"; - } - - let calprop = get_property(el, 'calendar', el.dataset.calendar); - - const rplcs = (s, v) => { - let [_, calclass] = s.classList.find(/^CAL_/); - s.classList.replace(calclass, "CAL_" + v); - } - - calprop.push([popup, rplcs]); - calprop.push([el, rplcs]); - calprop.push([el, (s, v) => s.dataset.calendar = v]); - - - - /* ---------- Calendar ------------------------------ */ -} diff --git a/static/server_connect.js b/static/server_connect.js index 252d79eb..90bf819d 100644 --- a/static/server_connect.js +++ b/static/server_connect.js @@ -21,51 +21,6 @@ async function remove_event (element) { } } -function event_to_jcal (event) { - let properties = []; - - for (let prop of event.properties.ical_properties) { - let v = event.properties[prop]; - if (v !== undefined) { - - let type = 'text'; - let value; - - if (v instanceof Array) { - } else if (v instanceof Date) { - if (v.isWholeDay) { - type = 'date'; - value = v.format("~Y-~m-~d"); - } else { - type = 'date-time'; - /* TODO TZ */ - value = v.format("~Y-~m-~dT~H:~M:~S"); - } - } else if (v === true || v === false) { - type = 'boolean'; - value = v; - } else if (typeof(v) == 'number') { - /* TODO float or integer */ - type = 'integer'; - value = v; - } else if (v instanceof RRule) { - type = 'recur'; - value = v.asJcal(); - } - - /* TODO period */ - else { - /* text types */ - value = v; - } - - properties.push([prop, {}, type, value]); - } - } - - return ['vevent', properties, [/* alarms go here */]] -} - async function create_event (event) { // let xml = event.getElementsByTagName("icalendar")[0].outerHTML @@ -91,7 +46,7 @@ async function create_event (event) { ], [ /* vtimezone goes here */ - event_to_jcal(event), + event.properties.to_jcal() ] ]; diff --git a/static/vcal.js b/static/vcal.js new file mode 100644 index 00000000..f43de0b7 --- /dev/null +++ b/static/vcal.js @@ -0,0 +1,343 @@ +/* + Properties are icalendar properties. + + p['name'] to get and set value (also updates any connected slots) + + p['_value_name'] for raw value + p['_slot_name'] for connected slots, Vector of pairs, where the + car should be a reference to the slot, and the + cdr a procedure which takes a slot and a value + and binds the value to the slot. + */ +class VComponent { + + constructor(el, wide_event=false) { + el.properties = this; + this.html_element = el; + + this._slots = {} + this._values = {} + + this.ical_properties = new Set(); + + let popup = popup_from_event(el); + // let children = el.getElementsByTagName("properties")[0].children; + + /* actual component (not popup) */ + /* + for (let e of el.querySelectorAll(".bind")) { + } + */ + + /* bind_recur */ + + /* primary display tab */ + + let p; + let lst = [...popup.querySelectorAll(".bind"), + ...el.querySelectorAll('.bind')]; + for (let e of lst) { + if (e.classList.contains('summary')) { + console.log(e, e.closest('[data-bindby]')); + } + if ((p = e.closest('[data-bindby]'))) { + // console.log(p); + // console.log(p.dataset.bindby); + eval(p.dataset.bindby)(el, e); + } else { + if (e.classList.contains('summary')) { + console.log (this.get(e.dataset.property)); + } + let f = (s, v) => { + console.log(s, v); + s.innerHTML = v.format(s.dataset && s.dataset.fmt); + }; + this.get(e.dataset.property).push([e, f]); + if (e.classList.contains('summary')) { + console.log (this.get(e.dataset.property)); + } + // console.log("registreing", e, e.dataset.property, this); + } + } + + /* checkbox for whole day */ + + for (let field of ['dtstart', 'dtend']) { + + this.get(`--${field}-time`).push( + [el, (el, v) => { let date = this[field]; + if (v == '') return; + let [h,m,s] = v.split(':') + date.setHours(Number(h)); + date.setMinutes(Number(m)); + date.setSeconds(0); + this[field] = date; }]) + this.get(`--${field}-date`).push( + [el, (el, v) => { let date = this[field]; + if (v == '') return; + let [y,m,d] = v.split('-') + date.setYear(Number(y)/* - 1900*/); + date.setMonth(Number(m) - 1); + date.setDate(d); + this[field] = date; }]) + + + /* Manual fetch of the fields instead of the general method, + to avoid an infinite loop of dtstart setting --dtstart-time, + and vice versa. + NOTE if many more fields require special treatment then a + general solution is required. + */ + this.get(field).push( + [el, (el, v) => { popup + .querySelector(`.edit-tab input[name='${field}-time']`) + .value = v.format("~H:~M"); + popup + .querySelector(`.edit-tab input[name='${field}-date']`) + .value = v.format("~Y-~m-~d"); + }]); + } + + for (let property of property_names) { + this.ical_properties.add(property) + // console.log("prop", property) + Object.defineProperty( + this, property, + { + get: function() { + return this._values[property].value; + }, + set: function (value) { + console.log("set", property, value); + this._values[property].value = value; + console.log(this._slots[property]); + for (let [slot,updater] of this._slots[property]) { + console.log(updater, slot); + updater(slot, value); + } + }, + }); + } + + /* icalendar properties */ + for (let child of el.querySelector("vevent > properties").children) { + /* child ≡ ... */ + + let field = child.tagName; + // // let lst = get_property(el, field); + // let lst = this.get(field); + + this.ical_properties.add(field) + + /* Bind vcomponent fields for this event */ + for (let s of el.querySelectorAll(`${field} > :not(parameters)`)) { + /* s ≡ ... */ + + /* Binds value from XML-tree to javascript object + [parsedate] + + TODO capture xcal type here, to enable us to output it to jcal later. + */ + let parsedValue; + let type = s.tagName.toLowerCase(); + switch (type) { + case 'float': + case 'integer': + parsedValue = Number(s.innerHTML); + break; + + case 'date-time': + case 'date': + parsedValue = parseDate(s.innerHTML); + break; + + /* TODO */ + case 'duration': + let start = s.getElementsByTagName('start'); + let end = s.getElementsByTagName('end, duration'); + if (end.tagName === 'period') { + parsePeriod(end.innerHTML); + } + break; + /* TODO */ + case 'period': + parsedValue = parsePeriod(s.innerHTML); + break; + /* TODO */ + case 'utc-offset': + break; + + case 'recur': + parsedValue = recur_xml_to_rrule(s); + break; + + case 'boolean': + switch (s.innerHTML) { + case 'true': parsedValue = true; break; + case 'false': parsedValue = false; break; + default: throw "Value error" + } + break; + + + case 'binary': + /* Binary is going to be BASE64 decoded, allowing us to ignore + it and handle it as a string for the time being */ + case 'cal-address': + case 'text': + case 'uri': + parsedValue = s.innerHTML; + // parsedValue.type = type; + break; + + default: + parsedValue = s.innerHTML; + } + + + // this['_value_rrule'] = new VCalParameter(type, parsedValue); + // console.log("set", field, type, parsedValue); + this._values[field] = new VCalParameter(type, parsedValue); + this._slots[field] = []; + } + } + + /* set up graphical display changes */ + let container = el.closest(".event-container"); + if (container === null) { + console.log("No enclosing event container for", el); + return; + } + let start = parseDate(container.dataset.start); + let end = parseDate(container.dataset.end); + + if (this.dtstart) { + /* [parsedate] */ + // el.properties.dtstart = parseDate(el.properties.dtstart); + this.get('dtstart').push( + [el.style, (s, v) => + s[wide_event?'left':'top'] = 100 * (to_local(v.value) - start)/(end - start) + "%"]); + } + + + if (this.dtend) { + // el.properties.dtend = parseDate(el.properties.dtend); + this.get('dtend').push( + // TODO right and bottom only works if used from the start. However, + // events from the backend instead use top/left and width/height. + // Normalize so all use the same, or find a way to convert between. + [el.style, + (s, v) => s[wide_event?'right':'bottom'] = 100 * (1 - (to_local(v.value)-start)/(end-start)) + "%"]); + } + + + /* ---------- Calendar ------------------------------ */ + + if (! el.dataset.calendar) { + el.dataset.calendar = "Unknown"; + } + + // let calprop = get_property(el, 'calendar', el.dataset.calendar); + let calprop = this.get('calendar', el.dataset.calendar); + + const rplcs = (s, v) => { + let [_, calclass] = s.classList.find(/^CAL_/); + s.classList.replace(calclass, "CAL_" + v); + } + + calprop.push([popup, rplcs]); + calprop.push([el, rplcs]); + calprop.push([el, (s, v) => s.dataset.calendar = v]); + + + + /* ---------- Calendar ------------------------------ */ + } + + + /* + Returns the _value_ slot of given field in event, creating it if needed . + el - the event to work on + field - name of the field + default_value - default value when creating + bind_to_ical - should this property be added to the icalendar subtree? + */ + get(field, default_value) { + // let el = this.html_element; + if (! this._slots[field]) { + this._slots[field] = []; + this._values[field] = default_value; + } + + // console.log("get", field); + return this._slots[field]; + } + + to_jcal() { + let properties = []; + + /* ??? */ + // for (let prop of event.properties.ical_properties) { + for (let prop of this.ical_properties) { + let v = this[prop]; + if (v !== undefined) { + properties.push([prop] + v.to_jcal()); + } + } + + return ['vevent', properties, [/* alarms go here */]] + } +} + +class VCalParameter { + constructor (type, value, properties={}) { + this.type = type; + this._value = value; + this.properties = properties; + } + + get value() { + return this._value; + } + + set value(v) { + this._value = v; + } + + to_jcal() { + let 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.properties, this.type, value]; + } +} -- cgit v1.2.3 From 55632aa8d889d3aa01d7e6f682bbb655914cc94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sat, 15 May 2021 23:56:03 +0200 Subject: General fixup of vcal stuff. --- static/server_connect.js | 33 +++++++++++++++++--------------- static/vcal.js | 49 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 19 deletions(-) (limited to 'static') diff --git a/static/server_connect.js b/static/server_connect.js index 90bf819d..45d5db2d 100644 --- a/static/server_connect.js +++ b/static/server_connect.js @@ -21,6 +21,23 @@ async function remove_event (element) { } } +function event_to_jcal (event) { + /* encapsulate event in a shim calendar, to ensure that + we always send correct stuff */ + return ['vcalendar', + [ + /* + 'prodid' and 'version' are technically both required (RFC 5545, + 3.6 Calendar Components). + */ + ], + [ + /* vtimezone goes here */ + event.properties.to_jcal() + ] + ]; +} + async function create_event (event) { // let xml = event.getElementsByTagName("icalendar")[0].outerHTML @@ -34,23 +51,9 @@ async function create_event (event) { console.log(event); + let jcal = event_to_jcal(event); - let jcal = - ['vcalendar', - [ - /* - 'prodid' and 'version' are technically both required (RFC 5545, - 3.6 Calendar Components). - */ - ], - [ - /* vtimezone goes here */ - event.properties.to_jcal() - ] - ]; - - console.log(jcal); let doc = jcal_to_xcal(jcal); console.log(doc); diff --git a/static/vcal.js b/static/vcal.js index f43de0b7..18b47547 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -15,9 +15,26 @@ class VComponent { el.properties = this; this.html_element = el; + /* + List of field listeners, which are all notified whenever + the listened for field is updated. + - keys are field names + - values MUST be a pair of + + a javascript object to update + + a prodecude taking that object, and the new value + */ this._slots = {} + + /* VCalParameter objects */ this._values = {} + /* + All properties on this object which are part of the vcomponent. + Ideally simply looping through all javascript fields would be nice, + but we only want to export some. + + Popuplated by iCalendars built in types per default, and extended + */ this.ical_properties = new Set(); let popup = popup_from_event(el); @@ -46,6 +63,7 @@ class VComponent { eval(p.dataset.bindby)(el, e); } else { if (e.classList.contains('summary')) { + /* TODO transfer data from backend to frontend in a better manner */ console.log (this.get(e.dataset.property)); } let f = (s, v) => { @@ -98,6 +116,7 @@ class VComponent { }]); } + /* Popuplate default types, see types.js for property_names */ for (let property of property_names) { this.ical_properties.add(property) // console.log("prop", property) @@ -105,12 +124,14 @@ class VComponent { this, property, { get: function() { - return this._values[property].value; + return this._values[property]; }, set: function (value) { console.log("set", property, value); this._values[property].value = value; console.log(this._slots[property]); + /* TODO validate type */ + /* See valid_input_types and all_types */ for (let [slot,updater] of this._slots[property]) { console.log(updater, slot); updater(slot, value); @@ -215,8 +236,10 @@ class VComponent { /* [parsedate] */ // el.properties.dtstart = parseDate(el.properties.dtstart); this.get('dtstart').push( - [el.style, (s, v) => - s[wide_event?'left':'top'] = 100 * (to_local(v.value) - start)/(end - start) + "%"]); + [el.style, (s, v) => { + console.log(v); + s[wide_event?'left':'top'] = 100 * (to_local(v.value) - start)/(end - start) + "%"; + } ]); } @@ -279,9 +302,12 @@ class VComponent { /* ??? */ // for (let prop of event.properties.ical_properties) { for (let prop of this.ical_properties) { + console.log(prop); let v = this[prop]; if (v !== undefined) { - properties.push([prop] + v.to_jcal()); + let sub = v.to_jcal(); + sub.unshift(prop); + properties.push(sub); } } @@ -289,6 +315,20 @@ class VComponent { } } + + +/* "Body" of a vcomponent field. + For example, given the JCal + ["dtstamp", {}, "date-time", "2006-02-06T00:11:21Z"], + this class would have + VCalParameter { + type = "date-time", + properties = {}, + _value = new Date(2006,1,6,0,11,21) + } + And returns [{}, "date-time", "2006-02-06T00:11:21Z"] + when serialized + */ class VCalParameter { constructor (type, value, properties={}) { this.type = type; @@ -306,6 +346,7 @@ class VCalParameter { to_jcal() { let value; + let v = this._value; switch (this.type) { case 'binary': /* TOOD */ -- cgit v1.2.3 From 54b1a64807dccbe370682522c3cfbf71b5744d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 16 May 2021 00:07:47 +0200 Subject: s/get/get_callback_list/ --- static/binders.js | 6 +++--- static/vcal.js | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'static') diff --git a/static/binders.js b/static/binders.js index 729866f3..f6c306bd 100644 --- a/static/binders.js +++ b/static/binders.js @@ -7,7 +7,7 @@ function bind_recur(el, e) { /* todo bind default slots of rrule */ - let p = el.properties.get('rrule'); + let p = el.properties.get_callback_list('rrule'); // let rrule = el.rrule; /* add listeners to bind-rr tags */ @@ -62,7 +62,7 @@ function bind_recur(el, e) { } function bind_edit(el, e) { - let p = el.properties.get(e.dataset.property); + let p = el.properties.get_callback_list(e.dataset.property); e.addEventListener('input', function () { el.properties[e.dataset.property] = this.value; }); @@ -90,7 +90,7 @@ function bind_edit(el, e) { function bind_view(el, e) { let f = (s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt); - el.properties.get(e.dataset.property).push([e, f]); + el.properties.get_callback_list(e.dataset.property).push([e, f]); } diff --git a/static/vcal.js b/static/vcal.js index 18b47547..0589606e 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -64,15 +64,15 @@ class VComponent { } else { if (e.classList.contains('summary')) { /* TODO transfer data from backend to frontend in a better manner */ - console.log (this.get(e.dataset.property)); + console.log (this.get_callback_list(e.dataset.property)); } let f = (s, v) => { console.log(s, v); s.innerHTML = v.format(s.dataset && s.dataset.fmt); }; - this.get(e.dataset.property).push([e, f]); + this.get_callback_list(e.dataset.property).push([e, f]); if (e.classList.contains('summary')) { - console.log (this.get(e.dataset.property)); + console.log (this.get_callback_list(e.dataset.property)); } // console.log("registreing", e, e.dataset.property, this); } @@ -82,7 +82,7 @@ class VComponent { for (let field of ['dtstart', 'dtend']) { - this.get(`--${field}-time`).push( + this.get_callback_list(`--${field}-time`).push( [el, (el, v) => { let date = this[field]; if (v == '') return; let [h,m,s] = v.split(':') @@ -90,7 +90,7 @@ class VComponent { date.setMinutes(Number(m)); date.setSeconds(0); this[field] = date; }]) - this.get(`--${field}-date`).push( + this.get_callback_list(`--${field}-date`).push( [el, (el, v) => { let date = this[field]; if (v == '') return; let [y,m,d] = v.split('-') @@ -106,7 +106,7 @@ class VComponent { NOTE if many more fields require special treatment then a general solution is required. */ - this.get(field).push( + this.get_callback_list(field).push( [el, (el, v) => { popup .querySelector(`.edit-tab input[name='${field}-time']`) .value = v.format("~H:~M"); @@ -235,7 +235,7 @@ class VComponent { if (this.dtstart) { /* [parsedate] */ // el.properties.dtstart = parseDate(el.properties.dtstart); - this.get('dtstart').push( + this.get_callback_list('dtstart').push( [el.style, (s, v) => { console.log(v); s[wide_event?'left':'top'] = 100 * (to_local(v.value) - start)/(end - start) + "%"; @@ -245,7 +245,7 @@ class VComponent { if (this.dtend) { // el.properties.dtend = parseDate(el.properties.dtend); - this.get('dtend').push( + this.get_callback_list('dtend').push( // TODO right and bottom only works if used from the start. However, // events from the backend instead use top/left and width/height. // Normalize so all use the same, or find a way to convert between. @@ -261,7 +261,7 @@ class VComponent { } // let calprop = get_property(el, 'calendar', el.dataset.calendar); - let calprop = this.get('calendar', el.dataset.calendar); + let calprop = this.get_callback_list('calendar', el.dataset.calendar); const rplcs = (s, v) => { let [_, calclass] = s.classList.find(/^CAL_/); @@ -285,7 +285,7 @@ class VComponent { default_value - default value when creating bind_to_ical - should this property be added to the icalendar subtree? */ - get(field, default_value) { + get_callback_list(field, default_value) { // let el = this.html_element; if (! this._slots[field]) { this._slots[field] = []; -- cgit v1.2.3 From 356cf51a924a7ba0cbf23529abd9d0a7c0cadd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 16 May 2021 21:57:57 +0200 Subject: Generall callbacks works again. --- static/script.js | 6 +++--- static/server_connect.js | 2 +- static/vcal.js | 46 +++++++++++++++++++++++++++++----------------- 3 files changed, 33 insertions(+), 21 deletions(-) (limited to 'static') diff --git a/static/script.js b/static/script.js index d809cc25..6a561757 100644 --- a/static/script.js +++ b/static/script.js @@ -115,7 +115,7 @@ class EventCreator { this.appendChild(event); /* requires that event is child of an '.event-container'. */ - event.properties = new VComponent( + new VComponent( event, wide_element=wide_element); // bind_properties(event, wide_element); @@ -320,9 +320,9 @@ window.onload = function () { /* Bind all vcomponent properties into javascript. */ if (el.closest(".longevents")) { - el.properties = new VComponent(el, true); + new VComponent(el, true); } else { - el.properties = new VComponent(el, true); + new VComponent(el, true); } } diff --git a/static/server_connect.js b/static/server_connect.js index 45d5db2d..24bf254b 100644 --- a/static/server_connect.js +++ b/static/server_connect.js @@ -43,7 +43,7 @@ async function create_event (event) { // let xml = event.getElementsByTagName("icalendar")[0].outerHTML let calendar = event.properties.calendar; - console.log(calendar/*, xml*/); + console.log('calendar=', calendar/*, xml*/); let data = new URLSearchParams(); data.append("cal", calendar); diff --git a/static/vcal.js b/static/vcal.js index 0589606e..b8c48f90 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -54,26 +54,26 @@ class VComponent { let lst = [...popup.querySelectorAll(".bind"), ...el.querySelectorAll('.bind')]; for (let e of lst) { - if (e.classList.contains('summary')) { - console.log(e, e.closest('[data-bindby]')); - } + // if (e.classList.contains('summary')) { + // console.log(e, e.closest('[data-bindby]')); + // } if ((p = e.closest('[data-bindby]'))) { // console.log(p); // console.log(p.dataset.bindby); eval(p.dataset.bindby)(el, e); } else { - if (e.classList.contains('summary')) { - /* TODO transfer data from backend to frontend in a better manner */ - console.log (this.get_callback_list(e.dataset.property)); - } + // if (e.classList.contains('summary')) { + // /* TODO transfer data from backend to frontend in a better manner */ + // console.log (this.get_callback_list(e.dataset.property)); + // } let f = (s, v) => { console.log(s, v); s.innerHTML = v.format(s.dataset && s.dataset.fmt); }; this.get_callback_list(e.dataset.property).push([e, f]); - if (e.classList.contains('summary')) { - console.log (this.get_callback_list(e.dataset.property)); - } + // if (e.classList.contains('summary')) { + // console.log (this.get_callback_list(e.dataset.property)); + // } // console.log("registreing", e, e.dataset.property, this); } } @@ -106,7 +106,9 @@ class VComponent { NOTE if many more fields require special treatment then a general solution is required. */ - this.get_callback_list(field).push( + let l = this.get_callback_list(field); + console.log(l); + l.push( [el, (el, v) => { popup .querySelector(`.edit-tab input[name='${field}-time']`) .value = v.format("~H:~M"); @@ -114,6 +116,7 @@ class VComponent { .querySelector(`.edit-tab input[name='${field}-date']`) .value = v.format("~Y-~m-~d"); }]); + console.log(l); } /* Popuplate default types, see types.js for property_names */ @@ -129,11 +132,12 @@ class VComponent { set: function (value) { console.log("set", property, value); this._values[property].value = value; - console.log(this._slots[property]); + console.log(this._slots[property].length, + this._slots[property]); /* TODO validate type */ /* See valid_input_types and all_types */ for (let [slot,updater] of this._slots[property]) { - console.log(updater, slot); + // console.log(updater, slot); updater(slot, value); } }, @@ -219,7 +223,9 @@ class VComponent { // this['_value_rrule'] = new VCalParameter(type, parsedValue); // console.log("set", field, type, parsedValue); this._values[field] = new VCalParameter(type, parsedValue); - this._slots[field] = []; + if (! this._slots[field]) { + this._slots[field] = []; + } } } @@ -238,7 +244,7 @@ class VComponent { this.get_callback_list('dtstart').push( [el.style, (s, v) => { console.log(v); - s[wide_event?'left':'top'] = 100 * (to_local(v.value) - start)/(end - start) + "%"; + s[wide_event?'left':'top'] = 100 * (to_local(v) - start)/(end - start) + "%"; } ]); } @@ -250,7 +256,7 @@ class VComponent { // events from the backend instead use top/left and width/height. // Normalize so all use the same, or find a way to convert between. [el.style, - (s, v) => s[wide_event?'right':'bottom'] = 100 * (1 - (to_local(v.value)-start)/(end-start)) + "%"]); + (s, v) => s[wide_event?'right':'bottom'] = 100 * (1 - (to_local(v)-start)/(end-start)) + "%"]); } @@ -261,6 +267,12 @@ class VComponent { } // let calprop = get_property(el, 'calendar', el.dataset.calendar); + /* + TODO this is the only location where default_value of + get_callback_list is used. The option should be removed, + since we lack type information now that everything is encapsulated + in VCalParameter objects. + */ let calprop = this.get_callback_list('calendar', el.dataset.calendar); const rplcs = (s, v) => { @@ -302,7 +314,7 @@ class VComponent { /* ??? */ // for (let prop of event.properties.ical_properties) { for (let prop of this.ical_properties) { - console.log(prop); + // console.log(prop); let v = this[prop]; if (v !== undefined) { let sub = v.to_jcal(); -- cgit v1.2.3 From 1da3c63f34ea30ca35e50cead9edd3bd107bebb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 16 May 2021 22:06:28 +0200 Subject: Calendar setting working again! --- static/server_connect.js | 2 +- static/vcal.js | 61 ++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 31 deletions(-) (limited to 'static') diff --git a/static/server_connect.js b/static/server_connect.js index 24bf254b..f3fbac1b 100644 --- a/static/server_connect.js +++ b/static/server_connect.js @@ -41,7 +41,7 @@ function event_to_jcal (event) { async function create_event (event) { // let xml = event.getElementsByTagName("icalendar")[0].outerHTML - let calendar = event.properties.calendar; + let calendar = event.properties.calendar.value; console.log('calendar=', calendar/*, xml*/); diff --git a/static/vcal.js b/static/vcal.js index b8c48f90..366b879a 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -123,25 +123,8 @@ class VComponent { for (let property of property_names) { this.ical_properties.add(property) // console.log("prop", property) - Object.defineProperty( - this, property, - { - get: function() { - return this._values[property]; - }, - set: function (value) { - console.log("set", property, value); - this._values[property].value = value; - console.log(this._slots[property].length, - this._slots[property]); - /* TODO validate type */ - /* See valid_input_types and all_types */ - for (let [slot,updater] of this._slots[property]) { - // console.log(updater, slot); - updater(slot, value); - } - }, - }); + + this.create_property(property); } /* icalendar properties */ @@ -266,14 +249,10 @@ class VComponent { el.dataset.calendar = "Unknown"; } - // let calprop = get_property(el, 'calendar', el.dataset.calendar); - /* - TODO this is the only location where default_value of - get_callback_list is used. The option should be removed, - since we lack type information now that everything is encapsulated - in VCalParameter objects. - */ - let calprop = this.get_callback_list('calendar', el.dataset.calendar); + let calprop = this.get_callback_list('calendar'); + this.create_property('calendar'); + this._values['calendar'] = + new VCalParameter('INVALID', el.dataset.calendar); const rplcs = (s, v) => { let [_, calclass] = s.classList.find(/^CAL_/); @@ -286,7 +265,7 @@ class VComponent { - /* ---------- Calendar ------------------------------ */ + /* ---------- /Calendar ------------------------------ */ } @@ -297,11 +276,10 @@ class VComponent { default_value - default value when creating bind_to_ical - should this property be added to the icalendar subtree? */ - get_callback_list(field, default_value) { + get_callback_list(field) { // let el = this.html_element; if (! this._slots[field]) { this._slots[field] = []; - this._values[field] = default_value; } // console.log("get", field); @@ -325,6 +303,29 @@ class VComponent { return ['vevent', properties, [/* alarms go here */]] } + + create_property(property_name) { + Object.defineProperty( + this, property_name, + { + get: function() { + return this._values[property_name]; + }, + set: function (value) { + console.log("set", property_name, value); + this._values[property_name].value = value; + console.log(this._slots[property_name].length, + this._slots[property_name]); + /* TODO validate type */ + /* See valid_input_types and all_types */ + for (let [slot,updater] of this._slots[property_name]) { + // console.log(updater, slot); + updater(slot, value); + } + }, + }); + } + } -- cgit v1.2.3 From 24e06a13894f885bbb75b79beaa43d1c6fdfbae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 17 May 2021 00:53:51 +0200 Subject: Rework date-time input to be cleaner + work again. --- static/binders.js | 34 +++++++++++++++++++++++++++++++++ static/date_time.js | 54 +++++++++++++++++++++++++++++------------------------ static/script.js | 26 +++++++++++++++++++++----- static/style.scss | 28 --------------------------- static/vcal.js | 39 -------------------------------------- 5 files changed, 85 insertions(+), 96 deletions(-) (limited to 'static') diff --git a/static/binders.js b/static/binders.js index f6c306bd..72550191 100644 --- a/static/binders.js +++ b/static/binders.js @@ -110,3 +110,37 @@ function bind_wholeday(el, e) { } }); } + + +/* used for dtstart and dtend input boxes + init_date_time MUST be called beforehand +*/ +function bind_date_time(el, e) { + e.addEventListener('input', function () { + let dt = el.properties[e.name].value; + if (e.value == '') return; + let y, m, d, h, s; + switch (this.type) { + case 'date': + [y,m,d] = this.value.split('-') + dt.setYear(Number(y)/* - 1900 */); + dt.setMonth(Number(m) - 1); + dt.setDate(d); + break; + case 'time': + [h,m,s] = this.value.split(':') + dt.setHours(Number(h)); + dt.setMinutes(Number(m)); + dt.setSeconds(0); + break; + default: + console.log("How did you get here??? ", e); + } + + el.properties[e.name] = dt; + }); + + el.properties.get_callback_list(e.name).push( + [e, (s, v) => s.value = v.format("~Y-~m-~dT~H:~M")]); + +} diff --git a/static/date_time.js b/static/date_time.js index 274d476f..8b7249dd 100644 --- a/static/date_time.js +++ b/static/date_time.js @@ -1,30 +1,36 @@ -function init_date_time() { - for (let dt of document.getElementsByClassName("date-time")) { - dt.time = dt.querySelector('[type=time]'); - dt.date = dt.querySelector('[type=date]'); +function init_date_time_single(dt) { + dt.time = dt.querySelector('[type=time]'); + dt.date = dt.querySelector('[type=date]'); - Object.defineProperty(dt, 'value', { - get: () => (dt.date.value && dt.time.value) - // TODO wrapping tag - ? dt.date.value + "T" + dt.time.value - : "", - set: (v) => [dt.date.value, dt.time.value] = v.split("T"), - }); + Object.defineProperty(dt, 'value', { + get: () => (dt.date.value && dt.time.value) + // TODO wrapping tag + ? dt.date.value + "T" + dt.time.value + : "", + set: (v) => [dt.date.value, dt.time.value] = v.split("T"), + }); - Object.defineProperty(dt, 'name', { - get: () => dt.attributes.name.value - }); + Object.defineProperty(dt, 'name', { + get: () => dt.attributes.name.value + }); - dt._addEventListener = dt.addEventListener; - dt.addEventListener = function (field, proc) { - switch (field) { - case 'input': - dt.time.addEventListener(field, proc); - dt.date.addEventListener(field, proc); - break; - default: - dt._addEventListener(field, proc); - } + dt._addEventListener = dt.addEventListener; + dt.addEventListener = function (field, proc) { + /* input events are propagated to children + other events target ourselves */ + switch (field) { + case 'input': + dt.time.addEventListener(field, proc); + dt.date.addEventListener(field, proc); + break; + default: + dt._addEventListener(field, proc); } } } + +function init_date_time() { + for (let dt of document.getElementsByClassName("date-time")) { + init_date_time_single(dt); + } +} diff --git a/static/script.js b/static/script.js index 6a561757..8042c341 100644 --- a/static/script.js +++ b/static/script.js @@ -14,18 +14,30 @@ class EventCreator { } create_empty_event () { + /* TODO this doesn't clone JS attributes */ + let event = document.getElementById("event-template") .firstChild.cloneNode(true); let popup = document.getElementById("popup-template") .firstChild.cloneNode(true); - /* TODO shouldn't this use transferListeners (or similar)? + /* -------------------- */ + /* Manually transfer or recreate attributes which we still need */ + /* TODO shouldn't these use transferListeners (or similar)? See input_list.js:transferListeners */ + + for (let dt of popup.getElementsByClassName("date-time")) { + init_date_time_single(dt); + } + popup.getElementsByClassName("edit-form")[0].onsubmit = function () { create_event(event); return false; /* stop default */ } + /* -------------------- */ + /* Fix tabs for newly created popup */ + let id = gensym ("__js_event"); // TODO remove button? @@ -43,8 +55,12 @@ class EventCreator { let nav = popup.getElementsByClassName("popup-control")[0]; bind_popup_control(nav); + /* -------------------- */ + // TODO download links + /* -------------------- */ + event.id = id; popup.id = "popup" + id; @@ -261,6 +277,8 @@ window.onload = function () { sch.update(d); }, 1000 * 60); + init_date_time(); + /* Is event creation active? */ if (EDIT_MODE) { let eventCreator = new EventCreator; @@ -294,7 +312,7 @@ window.onload = function () { let popupElement = document.getElementById("popup" + event.id); open_popup(popupElement); - popupElement.querySelector("input[name='summary']").focus(); + popupElement.querySelector("input[name='summary']").focus(); }); } @@ -311,7 +329,6 @@ window.onload = function () { */ el.parentElement.removeAttribute("href"); - /* TODO this doesn't yet apply to newly created events */ let popup = document.getElementById("popup" + el.id); popup.getElementsByClassName("edit-form")[0].onsubmit = function () { create_event(el); @@ -322,7 +339,7 @@ window.onload = function () { if (el.closest(".longevents")) { new VComponent(el, true); } else { - new VComponent(el, true); + new VComponent(el, false); } } @@ -379,7 +396,6 @@ window.onload = function () { // init_arbitary_kv(); - init_date_time(); init_input_list(); } diff --git a/static/style.scss b/static/style.scss index 202e3a34..052c9a93 100644 --- a/static/style.scss +++ b/static/style.scss @@ -881,34 +881,6 @@ along with their colors. } .timeinput { - - display: grid; - grid-template-columns: 1fr [lbl-start] 1ch 1fr 1ch [lbl-end]; - grid-template-rows: [lbl-start] 0.7fr 1fr 1fr 0.3fr [lbl-end]; - - label { - background-color: rgba(10,20,30,0.7); - color: white; - border-radius: 1em; - - grid-column: lbl-start / lbl-end; - grid-row: lbl-start / lbl-end; - - text-align: center; - - user-select: none; - - z-index: 1; - - } - - input { - z-index: 2; - } - - input:checked ~ input { - z-index: 0; - } } } diff --git a/static/vcal.js b/static/vcal.js index 366b879a..13c489b8 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -80,45 +80,6 @@ class VComponent { /* checkbox for whole day */ - for (let field of ['dtstart', 'dtend']) { - - this.get_callback_list(`--${field}-time`).push( - [el, (el, v) => { let date = this[field]; - if (v == '') return; - let [h,m,s] = v.split(':') - date.setHours(Number(h)); - date.setMinutes(Number(m)); - date.setSeconds(0); - this[field] = date; }]) - this.get_callback_list(`--${field}-date`).push( - [el, (el, v) => { let date = this[field]; - if (v == '') return; - let [y,m,d] = v.split('-') - date.setYear(Number(y)/* - 1900*/); - date.setMonth(Number(m) - 1); - date.setDate(d); - this[field] = date; }]) - - - /* Manual fetch of the fields instead of the general method, - to avoid an infinite loop of dtstart setting --dtstart-time, - and vice versa. - NOTE if many more fields require special treatment then a - general solution is required. - */ - let l = this.get_callback_list(field); - console.log(l); - l.push( - [el, (el, v) => { popup - .querySelector(`.edit-tab input[name='${field}-time']`) - .value = v.format("~H:~M"); - popup - .querySelector(`.edit-tab input[name='${field}-date']`) - .value = v.format("~Y-~m-~d"); - }]); - console.log(l); - } - /* Popuplate default types, see types.js for property_names */ for (let property of property_names) { this.ical_properties.add(property) -- cgit v1.2.3 From 3d3963e53cb0646ded92c871a6ea7636b25714b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 17 May 2021 01:07:09 +0200 Subject: Cleanup + fix for wholeday checkbox. --- static/binders.js | 10 ++++++++-- static/vcal.js | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'static') diff --git a/static/binders.js b/static/binders.js index 72550191..12d968e4 100644 --- a/static/binders.js +++ b/static/binders.js @@ -103,8 +103,14 @@ function bind_wholeday(el, e) { } for (let f of ['dtstart', 'dtend']) { - let d = el.properties[f]; - if (! d) continue; /* dtend optional */ + let param = el.properties[f]; + if (! param) continue; /* dtend optional */ + let d = param.value; + if (wholeday.checked) { + param.type = 'date'; + } else { + param.type = 'date-time'; + } d.isWholeDay = wholeday.checked; el.properties[f] = d; } diff --git a/static/vcal.js b/static/vcal.js index 13c489b8..079b09f8 100644 --- a/static/vcal.js +++ b/static/vcal.js @@ -269,6 +269,10 @@ class VComponent { Object.defineProperty( this, property_name, { + /* TODO there is an assymetry here with .value needing to be called for + get:ed stuff, but set MUST be an unwrapped item. + Fix this. + */ get: function() { return this._values[property_name]; }, -- cgit v1.2.3 From ed0e9a99601bf9c5b8d3267c6c3d1925f3afc2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 17 May 2021 01:10:46 +0200 Subject: Long events now wholeday per default. --- static/script.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'static') diff --git a/static/script.js b/static/script.js index 8042c341..7d3d2c29 100644 --- a/static/script.js +++ b/static/script.js @@ -314,6 +314,12 @@ window.onload = function () { popupElement.querySelector("input[name='summary']").focus(); + /* This assumes that it's unchecked beforehand. + Preferably we would just ensure that it's checked here, + But we also need to make sure that the proper handlers + are run then */ + popupElement.querySelector("input[name='wholeday']").click(); + }); } } -- cgit v1.2.3