diff options
-rw-r--r-- | module/calp/html/vcomponent.scm | 121 | ||||
-rw-r--r-- | module/calp/html/view/calendar/week.scm | 49 | ||||
-rw-r--r-- | static/clock.js | 2 | ||||
-rw-r--r-- | static/globals.js | 96 |
4 files changed, 177 insertions, 91 deletions
diff --git a/module/calp/html/vcomponent.scm b/module/calp/html/vcomponent.scm index 4b3e9ec7..63b3df3b 100644 --- a/module/calp/html/vcomponent.scm +++ b/module/calp/html/vcomponent.scm @@ -206,11 +206,12 @@ (define-public (edit-template) `(div (@ (class " eventtext edit-tab ")) (form (@ (class "edit-form")) + ;; TODO actually have calendar list here, since we are just a template (div (@ (class "dropdown-goes-here"))) (h3 (input (@ (type "text") (placeholder "Sammanfattning") (name "summary") (required) - (class "bind") (data-property "summary") + (class "interactive") (data-property "summary") ; (value ,(prop ev 'SUMMARY)) ))) @@ -218,36 +219,22 @@ ,@(with-label "Starttid" - `(div (@ (class "date-time") - (name "dtstart")) - (input (@ (type "date") - ; (value ,(date->string (as-date start))) - )) - (input (@ (type "time") - ; (value ,(time->string (as-time start) "~H:~M")) - ; ,@(when (date? start) '((disabled))) - )))) - - ;; TODO some way to add an endtime if missing beforehand - ;; TODO, actually proper support for event without end times + '(date-time-input (@ (name "dtstart") + (class "interactive") + (data-property "dtstart") + ))) + ,@(with-label "Sluttid" - `(div (@ (class "date-time") - (name "dtend")) - (input (@ (type "date") - ; (value ,(date->string (as-date end))) - )) - (input (@ (type "time") - ; (value ,(time->string (as-time end) "~H:~M")) - ; ,@(when (date? end) '((disabled))) - )))) + '(date-time-input (@ (name "dtend") + (class "interactive") + (data-property "dtend")))) (div ,@(with-label "Heldag?" `(input (@ (type "checkbox") (name "wholeday") - ; ,@(when (date? start) '((checked))) )))) ) @@ -257,6 +244,7 @@ `(input (@ (placeholder "Plats") (name "location") (type "text") + (class "interactive") (data-property "location") ; (value ,(or (prop ev 'LOCATION) "")) ))) @@ -264,54 +252,55 @@ ,@(with-label "Beskrivning" `(textarea (@ (placeholder "Beskrivning") + (class "interactive") (data-property "description") (name "description")) ; ,(prop ev 'DESCRIPTION) )) - ,@(with-label - "Kategorier" - ;; It would be better if these input-list's worked on the same - ;; class=bind system as the fields above. The problem with that - ;; is however that each input-list requires different search - ;; and join procedures. Currently this is bound in the JS, see - ;; [CATEGORIES_BIND]. - ;; It matches on ".input-list[data-property='categories']". - `(div (@ (class "input-list") - (data-property "categories")) - #; - ,@(awhen (prop ev 'CATEGORIES) - (map (lambda (c) - `(input (@ (size 2) - (class "unit") - (value ,c)))) - it)) - - (input (@ (class "unit final") - (size 2) - (type "text") - )))) - - (hr) - - ;; For custom user fields - ;; TODO these are currently not bound to anything, so entering data - ;; here does nothing. Bigest hurdle to overcome is supporting arbitrary - ;; fields which will come and go in the JavaScript. - ;; TODO also, all (most? maybe not LAST-MODIFIED) remaining properties - ;; should be exposed here. - (div (@ (class "input-list")) - (div (@ (class "unit final newfield")) - (input (@ (type "text") - (list "known-fields") - (placeholder "Nytt fält"))) - (select (@ (name "TYPE")) - (option (@ (value "TEXT")) "Text")) - (span - (input (@ (type "text") - (placeholder "Värde")))))) - - (hr) + ;; ,@(with-label + ;; "Kategorier" + ;; ;; It would be better if these input-list's worked on the same + ;; ;; class=bind system as the fields above. The problem with that + ;; ;; is however that each input-list requires different search + ;; ;; and join procedures. Currently this is bound in the JS, see + ;; ;; [CATEGORIES_BIND]. + ;; ;; It matches on ".input-list[data-property='categories']". + ;; `(div (@ (class "input-list") + ;; (data-property "categories")) + ;; #; + ;; ,@(awhen (prop ev 'CATEGORIES) + ;; (map (lambda (c) + ;; `(input (@ (size 2) + ;; (class "unit") + ;; (value ,c)))) + ;; it)) + + ;; (input (@ (class "unit final") + ;; (size 2) + ;; (type "text") + ;; )))) + + ;; (hr) + + ;; ;; For custom user fields + ;; ;; TODO these are currently not bound to anything, so entering data + ;; ;; here does nothing. Bigest hurdle to overcome is supporting arbitrary + ;; ;; fields which will come and go in the JavaScript. + ;; ;; TODO also, all (most? maybe not LAST-MODIFIED) remaining properties + ;; ;; should be exposed here. + ;; (div (@ (class "input-list")) + ;; (div (@ (class "unit final newfield")) + ;; (input (@ (type "text") + ;; (list "known-fields") + ;; (placeholder "Nytt fält"))) + ;; (select (@ (name "TYPE")) + ;; (option (@ (value "TEXT")) "Text")) + ;; (span + ;; (input (@ (type "text") + ;; (placeholder "Värde")))))) + + ;; (hr) (input (@ (type "submit"))) diff --git a/module/calp/html/view/calendar/week.scm b/module/calp/html/view/calendar/week.scm index 340db7d5..c2165a8e 100644 --- a/module/calp/html/view/calendar/week.scm +++ b/module/calp/html/view/calendar/week.scm @@ -75,46 +75,53 @@ ;; based on the output of fmt-single-event (define (description-template) '(div (@ (class " eventtext summary-tab " ())) - (h3 ((span (@ (class "repeating")) "↺") + (h3 ((span (@ (class "repeating")) ; "↺" + ) (span (@ (class "bind summary") - (data-property "summary")) - "Test"))) + (data-property "summary"))))) (div (div (time (@ (class "bind dtstart") (data-property "dtstart") (data-fmt "~L~H:~M") - (datetime "2021-09-29T19:56:46")) - "19:56") + (datetime ; "2021-09-29T19:56:46" + )) + ; "19:56" + ) "\xa0—\xa0" (time (@ (class "bind dtend") (data-property "dtend") (data-fmt "~L~H:~M") - (datetime "2021-09-29T19:56:46")) - "20:56")) + (datetime ; "2021-09-29T19:56:46" + )) + ; "20:56" + )) (div (@ (class "fields")) (div (b "Plats: ") (div (@ (class "bind location") (data-property "location")) - "Alsättersgatan 13")) + ; "Alsättersgatan 13" + )) (div (@ (class "bind description") (data-property "description")) - ("With a description")) - (div (@ (class "categories")) - (a (@ (class "category") - (href "/search/?" - "q=%28member%20%22test%22%20%28or%20%28prop%20event%20%28quote%20CATEGORIES%29%29%20%28quote%20%28%29%29%29%29")) - test)) - (div (@ (class "rrule")) - "Upprepas " - "varje vecka" - ".") + ; "With a description" + ) + ;; (div (@ (class "categories")) + ;; (a (@ (class "category") + ;; (href "/search/?" + ;; "q=%28member%20%22test%22%20%28or%20%28prop%20event%20%28quote%20CATEGORIES%29%29%20%28quote%20%28%29%29%29%29")) + ;; test)) + ;; (div (@ (class "rrule")) + ;; "Upprepas " + ;; "varje vecka" + ;; ".") (div (@ (class "last-modified")) - "Senast ändrad " - "2021-09-29 19:56"))))) + "Senast ändrad -" + ; "2021-09-29 19:56" + ))))) (define (block-template) `(div (@ ; (id ,(html-id ev)) (data-calendar "unknown") - (class "event CAL_unknown" + (class "event CAL_unknown" ;; ,(when (and (prop ev 'PARTSTAT) ;; (eq? 'TENTATIVE (prop ev 'PARTSTAT))) ;; " tentative") diff --git a/static/clock.js b/static/clock.js index 240041a9..d33d603a 100644 --- a/static/clock.js +++ b/static/clock.js @@ -75,7 +75,7 @@ class ClockElement extends HTMLElement { this.update(new Date) } - static get observerAttributes () { + static get observedAttributes () { return ['timer_id'] } diff --git a/static/globals.js b/static/globals.js index b881c531..4ee3c62a 100644 --- a/static/globals.js +++ b/static/globals.js @@ -35,6 +35,7 @@ class VEvent { e.value = value; } for (let el of this.registered) { + /* TODO update correct fields, allow component to redraw themselves */ el.redraw(this); } } @@ -188,10 +189,13 @@ class ComponentVEvent extends HTMLElement { for (let el of body.getElementsByClassName("bind")) { let p = el.dataset.property; - let d; + let d, fmt; if ((d = data.getProperty(p))) { - /* TODO format */ - el.innerHTML = d; + if ((fmt = el.dataset.fmt)) { + el.innerHTML = d.format(fmt); + } else { + el.innerHTML = d; + } } } @@ -211,10 +215,61 @@ class ComponentEdit extends ComponentVEvent { constructor () { super(); + this.firstTime = true; + } + + connectedCallback() { + /* 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]); + + for (let el of this.getElementsByClassName("interactive")) { + el.addEventListener('input', () => { + vcal_objects[this.dataset.uid].setProperty( + el.dataset.property, + el.value) + }); + } } + + redraw (data) { + // update ourselves from template + + if (! this.template) { + throw "Something"; + } + + let body; + if (this.firstTime) { + body = this.template.content.cloneNode(true).firstElementChild; + } else { + body = this; + } + + for (let el of body.getElementsByClassName("interactive")) { + let p = el.dataset.property; + let d; + if ((d = data.getProperty(p))) { + /* + https://stackoverflow.com/questions/57157830/how-can-i-specify-the-sequence-of-running-nested-web-components-constructors + */ + window.setTimeout (() => { + /* NOTE Some specific types might require special formatting + here. But due to my custom components implementing custom + `.value' procedures, we might not need any special cases + here */ + el.value = d; + }); + } + } + + if (this.firstTime) { + this.replaceChildren(body); + this.firstTime = false; + } + } + } class ComponentBlock extends ComponentVEvent { @@ -255,3 +310,38 @@ window.addEventListener('load', function () { customElements.define('vevent-block', ComponentBlock); }) + + +class DateTimeInput extends HTMLElement { + constructor () { + super(); + this.innerHTML = '<input type="date" /><input type="time" />' + } + + get value () { + let date = this.querySelector("[type='date']").value; + let time = this.querySelector("[type='time']").value; + return parseDate(date + 'T' + time) + } + + set value (new_value) { + let date, time; + if (new_value instanceof Date) { + date = new_value.format("~L~Y-~m-~d"); + time = new_value.format("~L~H:~M:~S"); + } else { + [date, time] = new_value.split('T') + } + this.querySelector("[type='date']").value = date; + this.querySelector("[type='time']").value = time; + } + + addEventListener(type, proc) { + if (type != 'input') throw "Only input supported"; + + this.querySelector("[type='date']").addEventListener(type, proc); + this.querySelector("[type='time']").addEventListener(type, proc); + } +} + +customElements.define('date-time-input', DateTimeInput) |