aboutsummaryrefslogtreecommitdiff
path: root/static/globals.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/globals.js')
-rw-r--r--static/globals.js309
1 files changed, 91 insertions, 218 deletions
diff --git a/static/globals.js b/static/globals.js
index 6efba94f..41472264 100644
--- a/static/globals.js
+++ b/static/globals.js
@@ -1,218 +1,5 @@
"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 */
- 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 'uc-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)
-}
-
const vcal_objects = {};
class ComponentVEvent extends HTMLElement {
@@ -226,6 +13,13 @@ class ComponentVEvent extends HTMLElement {
should take care of that some other way */
}
+ connectedCallback () {
+ let uid;
+ if ((uid = this.dataset.uid)) {
+ this.redraw (vcal_objects[uid]);
+ }
+ }
+
redraw (data) {
// update ourselves from template
@@ -270,7 +64,14 @@ class ComponentEdit extends ComponentVEvent {
/* Edit tab is rendered here. It's left blank server-side, since
it only makes sense to have something here if we have javascript */
- this.redraw(vcal_objects[this.dataset.uid]);
+
+ let data = vcal_objects[this.dataset.uid]
+
+ if (! data) {
+ throw `Data missing for uid ${this.dataset.uid}.`
+ }
+
+ this.redraw(data);
for (let el of this.getElementsByClassName("interactive")) {
el.addEventListener('input', () => {
@@ -320,9 +121,31 @@ class ComponentEdit extends ComponentVEvent {
}
+function find_popup (uid) {
+ for (let el of vcal_objects[uid].registered) {
+ if (el.tagName === 'popup-element') {
+ return el;
+ }
+ }
+ throw 'Popup not fonud';
+}
+
+function find_block (uid) {
+ for (let el of vcal_objects[uid].registered) {
+ if (el.tagName === 'vevent-block') {
+ return el;
+ }
+ }
+ throw 'Popup not fonud';
+}
+
class ComponentBlock extends ComponentVEvent {
constructor () {
super();
+
+ this.addEventListener('click', () => {
+ toggle_popup(find_popup(this.dataset.uid));
+ });
}
redraw (data) {
@@ -330,13 +153,13 @@ class ComponentBlock extends ComponentVEvent {
let p;
if ((p = data.getProperty('dtstart'))) {
- this.style.top = date_to_percent(p, 1) + "%";
- console.log('dtstart', p);
+ this.style.top = date_to_percent(to_local(p), 1) + "%";
+ // console.log('dtstart', p);
}
if ((p = data.getProperty('dtend'))) {
this.style.height = 'unset';
- console.log('dtend', p);
- this.style.bottom = (100 - date_to_percent(p, 1)) + "%";
+ // console.log('dtend', p);
+ this.style.bottom = (100 - date_to_percent(to_local(p), 1)) + "%";
}
}
}
@@ -439,6 +262,56 @@ class DateTimeInput extends HTMLElement {
customElements.define('date-time-input', DateTimeInput)
+class PopupElement extends HTMLElement {
+ constructor () {
+ super();
+
+ /* TODO populate remaining */
+ // this.id = 'popup' + this.dataset.uid
+ }
+
+ redraw () {
+ console.log('IMPLEMENT ME');
+ }
+
+ connectedCallback() {
+ let body = document.getElementById('popup-template').content.cloneNode(true).firstElementChild;
+
+ let uid = this.dataset.uid
+ // console.log(uid);
+
+ body.getElementsByClassName('populate-with-uid')
+ .forEach((e) => e.setAttribute('data-uid', uid));
+
+ /* tabs */
+ let tabgroup_id = gensym();
+ for (let tab of body.querySelectorAll(".tabgroup .tab")) {
+ let new_id = gensym();
+ let input = tab.querySelector("input");
+ input.id = new_id;
+ input.name = tabgroup_id;
+ tab.querySelector("label").setAttribute('for', new_id);
+ }
+ /* end tabs */
+
+ /* nav bar */
+ let nav = body.getElementsByClassName("popup-control")[0];
+ bind_popup_control(nav);
+
+ let btn = body.querySelector('.popup-control .close-tooltip')
+ btn.addEventListener('click', () => {
+ close_popup(this);
+ });
+ /* end nav bar */
+
+ this.replaceChildren(body);
+ }
+}
+
+window.addEventListener('load', function () {
+ customElements.define('popup-element', PopupElement)
+});
+
function wholeday_checkbox (box) {
box.closest('.timeinput')
.getElementsByTagName('date-time-input')